shrimp/src/parser/tests/dot-get.test.ts

302 lines
6.9 KiB
TypeScript

import { describe, test, expect } from 'bun:test'
import '../../testSetup'
describe('DotGet', () => {
test('readme.txt is Word when readme not in scope', () => {
expect('readme.txt').toMatchTree(`Word readme.txt`)
})
test('readme.txt is Word when used in function', () => {
expect('echo readme.txt').toMatchTree(`
FunctionCall
Identifier echo
PositionalArg
Word readme.txt`)
})
test('obj.prop is DotGet when obj is assigned', () => {
expect('obj = 5; obj.prop').toMatchTree(`
Assign
AssignableIdentifier obj
Eq =
Number 5
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot obj
Identifier prop
`)
})
test('function parameters are in scope within function body', () => {
expect('do config: config.path end').toMatchTree(`
FunctionDef
Do do
Params
Identifier config
colon :
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot config
Identifier path
keyword end
`)
})
test('parameters out of scope outside function', () => {
expect('do x: x.prop end; x.prop').toMatchTree(`
FunctionDef
Do do
Params
Identifier x
colon :
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot x
Identifier prop
keyword end
Word x.prop
`)
})
test('multiple parameters work correctly', () => {
expect(`do x y:
x.foo
y.bar
end`).toMatchTree(`
FunctionDef
Do do
Params
Identifier x
Identifier y
colon :
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot x
Identifier foo
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot y
Identifier bar
keyword end
`)
})
test('nested functions with scope isolation', () => {
expect(`do x:
x.outer
do y: y.inner end
end`).toMatchTree(`
FunctionDef
Do do
Params
Identifier x
colon :
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot x
Identifier outer
FunctionDef
Do do
Params
Identifier y
colon :
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot y
Identifier inner
keyword end
keyword end
`)
})
test('dot get works as function argument', () => {
expect('config = 42; echo config.path').toMatchTree(`
Assign
AssignableIdentifier config
Eq =
Number 42
FunctionCall
Identifier echo
PositionalArg
DotGet
IdentifierBeforeDot config
Identifier path
`)
})
test('dot get works as bare function', () => {
expect('io = dict print=echo; io.print').toMatchTree(`
Assign
AssignableIdentifier io
Eq =
FunctionCall
Identifier dict
NamedArg
NamedArgPrefix print=
Identifier echo
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot io
Identifier print
`)
})
test('dot get works as function w/ args', () => {
expect('io = dict print=echo; io.print heya').toMatchTree(`
Assign
AssignableIdentifier io
Eq =
FunctionCall
Identifier dict
NamedArg
NamedArgPrefix print=
Identifier echo
FunctionCall
DotGet
IdentifierBeforeDot io
Identifier print
PositionalArg
Identifier heya
`)
})
test('dot get works as function in parens', () => {
expect('io = dict print=echo; (io.print heya)').toMatchTree(`
Assign
AssignableIdentifier io
Eq =
FunctionCall
Identifier dict
NamedArg
NamedArgPrefix print=
Identifier echo
ParenExpr
FunctionCall
DotGet
IdentifierBeforeDot io
Identifier print
PositionalArg
Identifier heya
`)
})
test('mixed file paths and dot get', () => {
expect('config = 42; cat readme.txt; echo config.path').toMatchTree(`
Assign
AssignableIdentifier config
Eq =
Number 42
FunctionCall
Identifier cat
PositionalArg
Word readme.txt
FunctionCall
Identifier echo
PositionalArg
DotGet
IdentifierBeforeDot config
Identifier path
`)
})
test("dot get doesn't work with spaces", () => {
expect('obj . prop').toMatchTree(`
FunctionCall
Identifier obj
PositionalArg
Word .
PositionalArg
Identifier prop`)
})
test('readme.1 is Word when readme not in scope', () => {
expect('readme.1').toMatchTree(`Word readme.1`)
})
test('readme.1 is Word when used in function', () => {
expect('echo readme.1').toMatchTree(`
FunctionCall
Identifier echo
PositionalArg
Word readme.1`)
})
test('obj.1 is DotGet when obj is assigned', () => {
expect('obj = 5; obj.1').toMatchTree(`
Assign
AssignableIdentifier obj
Eq =
Number 5
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot obj
Number 1
`)
})
test('obj.1 arg is DotGet when obj is assigned', () => {
expect('obj = 5; obj.1').toMatchTree(`
Assign
AssignableIdentifier obj
Eq =
Number 5
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot obj
Number 1
`)
})
test('dot get index works as function w/ args', () => {
expect(`io = list (do x: echo x end); io.0 heya`).toMatchTree(`
Assign
AssignableIdentifier io
Eq =
FunctionCall
Identifier list
PositionalArg
ParenExpr
FunctionDef
Do do
Params
Identifier x
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier x
keyword end
FunctionCall
DotGet
IdentifierBeforeDot io
Number 0
PositionalArg
Identifier heya
`)
})
test('can use the result of a parens expression as the property of dot get', () => {
expect('obj = list 1 2 3; obj.(1 + 2)').toMatchTree(`
Assign
AssignableIdentifier obj
Eq =
FunctionCall
Identifier list
PositionalArg
Number 1
PositionalArg
Number 2
PositionalArg
Number 3
FunctionCallOrIdentifier
DotGet
IdentifierBeforeDot obj
ParenExpr
BinOp
Number 1
Plus +
Number 2
`)
})
})