shrimp/src/parser/tests/functions.test.ts
2025-11-02 14:04:32 -08:00

234 lines
5.0 KiB
TypeScript

import { expect, describe, test } from 'bun:test'
import '../shrimp.grammar' // Importing this so changes cause it to retest!
describe('calling functions', () => {
test('call with no args', () => {
expect('tail').toMatchTree(`
FunctionCallOrIdentifier
Identifier tail
`)
})
test('call with arg', () => {
expect('tail path').toMatchTree(`
FunctionCall
Identifier tail
PositionalArg
Identifier path
`)
})
test('call with arg and named arg', () => {
expect('tail path lines=30').toMatchTree(`
FunctionCall
Identifier tail
PositionalArg
Identifier path
NamedArg
NamedArgPrefix lines=
Number 30
`)
})
test('call with dashed named arg', () => {
expect('tail pre-lines=30 path').toMatchTree(`
FunctionCall
Identifier tail
NamedArg
NamedArgPrefix pre-lines=
Number 30
PositionalArg
Identifier path
`)
})
test('command with arg that is also a command', () => {
expect('tail tail').toMatchTree(`
FunctionCall
Identifier tail
PositionalArg
Identifier tail
`)
expect('tai').toMatchTree(`
FunctionCallOrIdentifier
Identifier tai
`)
})
test('Incomplete namedArg', () => {
expect('tail lines=').toMatchTree(`
FunctionCall
Identifier tail
NamedArg
NamedArgPrefix lines=
`)
})
})
describe('Do', () => {
test('parses function no parameters', () => {
expect('do: 1 end').toMatchTree(`
FunctionDef
Do do
Params
colon :
Number 1
keyword end`)
})
test('parses function with single parameter', () => {
expect('do x: x + 1 end').toMatchTree(`
FunctionDef
Do do
Params
Identifier x
colon :
BinOp
Identifier x
Plus +
Number 1
keyword end`)
})
test('parses function with multiple parameters', () => {
expect('do x y: x * y end').toMatchTree(`
FunctionDef
Do do
Params
Identifier x
Identifier y
colon :
BinOp
Identifier x
Star *
Identifier y
keyword end`)
})
test('parses multiline function with multiple statements', () => {
expect(`do x y:
x * y
x + 9
end`).toMatchTree(`
FunctionDef
Do do
Params
Identifier x
Identifier y
colon :
BinOp
Identifier x
Star *
Identifier y
BinOp
Identifier x
Plus +
Number 9
keyword end`)
})
test('does not parse identifiers that start with fn', () => {
expect('fnnn = do x: x end').toMatchTree(`
Assign
AssignableIdentifier fnnn
Eq =
FunctionDef
Do do
Params
Identifier x
colon :
FunctionCallOrIdentifier
Identifier x
keyword end`)
})
test('does not parse identifiers that start with end', () => {
expect('enddd = do x: x end').toMatchTree(`
Assign
AssignableIdentifier enddd
Eq =
FunctionDef
Do do
Params
Identifier x
colon :
FunctionCallOrIdentifier
Identifier x
keyword end`)
})
test('can call a function returned by a parens expression', () => {
expect('(do x: x end) 5').toMatchTree(`
FunctionCall
ParenExpr
FunctionDef
Do do
Params
Identifier x
colon :
FunctionCallOrIdentifier
Identifier x
keyword end
PositionalArg
Number 5
`)
})
})
describe('default params', () => {
test('parses function with single default parameter', () => {
expect('do x=1: x + 1 end').toMatchTree(`
FunctionDef
Do do
Params
NamedParam
NamedArgPrefix x=
Number 1
colon :
BinOp
Identifier x
Plus +
Number 1
keyword end`)
})
test('parses function with multiple default parameters', () => {
expect(`do x='something' y=true: x * y end`).toMatchTree(`
FunctionDef
Do do
Params
NamedParam
NamedArgPrefix x=
String
StringFragment something
NamedParam
NamedArgPrefix y=
Boolean true
colon :
BinOp
Identifier x
Star *
Identifier y
keyword end`)
})
test('parses function with mixed parameters', () => {
expect('do x y=true: x * y end').toMatchTree(`
FunctionDef
Do do
Params
Identifier x
NamedParam
NamedArgPrefix y=
Boolean true
colon :
BinOp
Identifier x
Star *
Identifier y
keyword end`)
})
})