598 lines
11 KiB
TypeScript
598 lines
11 KiB
TypeScript
import { expect, describe, test } from 'bun:test'
|
|
|
|
import '../shrimp.grammar' // Importing this so changes cause it to retest!
|
|
|
|
describe('number literals', () => {
|
|
test('binary numbers', () => {
|
|
expect('0b110').toMatchTree(`
|
|
Number 0b110
|
|
`)
|
|
})
|
|
|
|
test('hex numbers', () => {
|
|
expect('0xdeadbeef').toMatchTree(`
|
|
Number 0xdeadbeef
|
|
`)
|
|
})
|
|
|
|
test('hex numbers uppercase', () => {
|
|
expect('0xFF').toMatchTree(`
|
|
Number 0xFF
|
|
`)
|
|
})
|
|
|
|
test('octal numbers', () => {
|
|
expect('0o644').toMatchTree(`
|
|
Number 0o644
|
|
`)
|
|
|
|
expect('0o055').toMatchTree(`
|
|
Number 0o055
|
|
`)
|
|
})
|
|
|
|
test('decimal numbers still work', () => {
|
|
expect('42').toMatchTree(`
|
|
Number 42
|
|
`)
|
|
})
|
|
|
|
test('negative binary', () => {
|
|
expect('-0b110').toMatchTree(`
|
|
Number -0b110
|
|
`)
|
|
})
|
|
|
|
test('negative hex', () => {
|
|
expect('-0xFF').toMatchTree(`
|
|
Number -0xFF
|
|
`)
|
|
})
|
|
|
|
test('negative octal', () => {
|
|
expect('-0o755').toMatchTree(`
|
|
Number -0o755
|
|
`)
|
|
})
|
|
|
|
test('positive prefix binary', () => {
|
|
expect('+0b110').toMatchTree(`
|
|
Number +0b110
|
|
`)
|
|
})
|
|
|
|
test('positive prefix hex', () => {
|
|
expect('+0xFF').toMatchTree(`
|
|
Number +0xFF
|
|
`)
|
|
})
|
|
|
|
test('positive prefix octal', () => {
|
|
expect('+0o644').toMatchTree(`
|
|
Number +0o644
|
|
`)
|
|
})
|
|
|
|
test('hex, binary, and octal in arrays', () => {
|
|
expect('[0xFF 0b110 0o644 42]').toMatchTree(`
|
|
Array
|
|
Number 0xFF
|
|
Number 0b110
|
|
Number 0o644
|
|
Number 42
|
|
`)
|
|
})
|
|
})
|
|
|
|
describe('array literals', () => {
|
|
test('work with numbers', () => {
|
|
expect('[1 2 3]').toMatchTree(`
|
|
Array
|
|
Number 1
|
|
Number 2
|
|
Number 3
|
|
`)
|
|
})
|
|
|
|
test('work with strings', () => {
|
|
expect("['one' 'two' 'three']").toMatchTree(`
|
|
Array
|
|
String
|
|
StringFragment one
|
|
String
|
|
StringFragment two
|
|
String
|
|
StringFragment three
|
|
`)
|
|
})
|
|
|
|
test('work with identifiers', () => {
|
|
expect('[one two three]').toMatchTree(`
|
|
Array
|
|
Identifier one
|
|
Identifier two
|
|
Identifier three
|
|
`)
|
|
})
|
|
|
|
test('can be nested', () => {
|
|
expect('[one [two [three]]]').toMatchTree(`
|
|
Array
|
|
Identifier one
|
|
Array
|
|
Identifier two
|
|
Array
|
|
Identifier three
|
|
`)
|
|
})
|
|
|
|
test('can span multiple lines', () => {
|
|
expect(`[
|
|
1
|
|
2
|
|
3
|
|
]`).toMatchTree(`
|
|
Array
|
|
Number 1
|
|
Number 2
|
|
Number 3
|
|
`)
|
|
})
|
|
|
|
test('can span multiple w/o calling functions', () => {
|
|
expect(`[
|
|
one
|
|
two
|
|
three
|
|
]`).toMatchTree(`
|
|
Array
|
|
Identifier one
|
|
Identifier two
|
|
Identifier three
|
|
`)
|
|
})
|
|
|
|
test('empty arrays', () => {
|
|
expect('[]').toMatchTree(`
|
|
Array []
|
|
`)
|
|
})
|
|
|
|
test('mixed types', () => {
|
|
expect("[1 'two' three true null]").toMatchTree(`
|
|
Array
|
|
Number 1
|
|
String
|
|
StringFragment two
|
|
Identifier three
|
|
Boolean true
|
|
Null null
|
|
`)
|
|
})
|
|
|
|
test('semicolons as separators', () => {
|
|
expect('[1; 2; 3]').toMatchTree(`
|
|
Array
|
|
Number 1
|
|
Number 2
|
|
Number 3
|
|
`)
|
|
})
|
|
|
|
test('expressions in arrays', () => {
|
|
expect('[(1 + 2) (3 * 4)]').toMatchTree(`
|
|
Array
|
|
ParenExpr
|
|
BinOp
|
|
Number 1
|
|
Plus +
|
|
Number 2
|
|
ParenExpr
|
|
BinOp
|
|
Number 3
|
|
Star *
|
|
Number 4
|
|
`)
|
|
})
|
|
|
|
test('mixed separators - spaces and newlines', () => {
|
|
expect(`[1 2
|
|
3 4]`).toMatchTree(`
|
|
Array
|
|
Number 1
|
|
Number 2
|
|
Number 3
|
|
Number 4
|
|
`)
|
|
})
|
|
|
|
test('mixed separators - spaces and semicolons', () => {
|
|
expect('[1 2; 3 4]').toMatchTree(`
|
|
Array
|
|
Number 1
|
|
Number 2
|
|
Number 3
|
|
Number 4
|
|
`)
|
|
})
|
|
|
|
test('empty lines within arrays', () => {
|
|
expect(`[1
|
|
|
|
2]`).toMatchTree(`
|
|
Array
|
|
Number 1
|
|
Number 2
|
|
`)
|
|
})
|
|
|
|
test('comments within arrays', () => {
|
|
expect(`[ # something...
|
|
1 # first
|
|
2 # second
|
|
]`).toMatchTree(`
|
|
Array
|
|
Comment # something...
|
|
Number 1
|
|
Comment # first
|
|
Number 2
|
|
Comment # second
|
|
`)
|
|
})
|
|
|
|
test('complex nested multiline', () => {
|
|
expect(`[
|
|
[1 2]
|
|
[3 4]
|
|
[5 6]
|
|
]`).toMatchTree(`
|
|
Array
|
|
Array
|
|
Number 1
|
|
Number 2
|
|
Array
|
|
Number 3
|
|
Number 4
|
|
Array
|
|
Number 5
|
|
Number 6
|
|
`)
|
|
})
|
|
|
|
test('boolean and null literals', () => {
|
|
expect('[true false null]').toMatchTree(`
|
|
Array
|
|
Boolean true
|
|
Boolean false
|
|
Null null
|
|
`)
|
|
})
|
|
|
|
test('regex literals', () => {
|
|
expect('[//[0-9]+//]').toMatchTree(`
|
|
Array
|
|
Regex //[0-9]+//
|
|
`)
|
|
})
|
|
|
|
test('trailing newlines', () => {
|
|
expect(`[
|
|
1
|
|
2
|
|
]`).toMatchTree(`
|
|
Array
|
|
Number 1
|
|
Number 2
|
|
`)
|
|
})
|
|
})
|
|
|
|
describe('dict literals', () => {
|
|
test('work with numbers', () => {
|
|
expect('[a=1 b=2 c=3]').toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 2
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 3
|
|
`)
|
|
})
|
|
|
|
test('work with strings', () => {
|
|
expect("[a='one' b='two' c='three']").toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
String
|
|
StringFragment one
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
String
|
|
StringFragment two
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
String
|
|
StringFragment three
|
|
`)
|
|
})
|
|
|
|
test('work with identifiers', () => {
|
|
expect('[a=one b=two c=three]').toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Identifier one
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Identifier two
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Identifier three
|
|
`)
|
|
})
|
|
|
|
test('work with functions', () => {
|
|
expect(`[trap=do x: x end]`).toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix trap=
|
|
FunctionDef
|
|
Do do
|
|
Params
|
|
Identifier x
|
|
colon :
|
|
FunctionCallOrIdentifier
|
|
Identifier x
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test('can be nested', () => {
|
|
expect('[a=one b=[two [c=three]]]').toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Identifier one
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Array
|
|
Identifier two
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Identifier three
|
|
`)
|
|
})
|
|
|
|
test('can span multiple lines', () => {
|
|
expect(`[
|
|
a=1
|
|
b=2
|
|
c=3
|
|
]`).toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 2
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 3
|
|
`)
|
|
})
|
|
test('empty dict', () => {
|
|
expect('[=]').toMatchTree(`
|
|
Dict [=]
|
|
`)
|
|
})
|
|
|
|
test('empty dict w whitespace', () => {
|
|
expect('[ = ]').toMatchTree(`
|
|
Dict [ = ]
|
|
`)
|
|
})
|
|
|
|
test('mixed types', () => {
|
|
expect("[a=1 b='two' c=three d=true e=null]").toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
String
|
|
StringFragment two
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Identifier three
|
|
NamedArg
|
|
NamedArgPrefix d=
|
|
Boolean true
|
|
NamedArg
|
|
NamedArgPrefix e=
|
|
Null null
|
|
`)
|
|
})
|
|
|
|
test('semicolons as separators', () => {
|
|
expect('[a=1; b=2; c=3]').toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 2
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 3
|
|
`)
|
|
})
|
|
|
|
test('expressions in dicts', () => {
|
|
expect('[a=(1 + 2) b=(3 * 4)]').toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
ParenExpr
|
|
BinOp
|
|
Number 1
|
|
Plus +
|
|
Number 2
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
ParenExpr
|
|
BinOp
|
|
Number 3
|
|
Star *
|
|
Number 4
|
|
`)
|
|
})
|
|
|
|
test('mixed separators - spaces and newlines', () => {
|
|
expect(`[a=1 b=2
|
|
c=3]`).toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 2
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 3
|
|
`)
|
|
})
|
|
|
|
test('empty lines within dicts', () => {
|
|
expect(`[a=1
|
|
|
|
b=2
|
|
|
|
c=3]`).toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 2
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 3
|
|
`)
|
|
})
|
|
|
|
test('comments within dicts', () => {
|
|
expect(`[ # something...
|
|
a=1 # first
|
|
b=2 # second
|
|
|
|
c=3
|
|
]`).toMatchTree(`
|
|
Dict
|
|
Comment # something...
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
Comment # first
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 2
|
|
Comment # second
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 3
|
|
`)
|
|
})
|
|
|
|
test('complex nested multiline', () => {
|
|
expect(`[
|
|
a=[a=1 b=2]
|
|
b=[b=3 c=4]
|
|
c=[c=5 d=6]
|
|
]`).toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 2
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 3
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 4
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 5
|
|
NamedArg
|
|
NamedArgPrefix d=
|
|
Number 6
|
|
`)
|
|
})
|
|
|
|
test('boolean and null literals', () => {
|
|
expect('[a=true b=false c=null]').toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Boolean true
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Boolean false
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Null null
|
|
`)
|
|
})
|
|
|
|
test('regex literals', () => {
|
|
expect('[pattern=//[0-9]+//]').toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix pattern=
|
|
Regex //[0-9]+//
|
|
`)
|
|
})
|
|
|
|
test('trailing newlines', () => {
|
|
expect(`[
|
|
a=1
|
|
b=2
|
|
c=3
|
|
|
|
]`).toMatchTree(`
|
|
Dict
|
|
NamedArg
|
|
NamedArgPrefix a=
|
|
Number 1
|
|
NamedArg
|
|
NamedArgPrefix b=
|
|
Number 2
|
|
NamedArg
|
|
NamedArgPrefix c=
|
|
Number 3
|
|
`)
|
|
})
|
|
})
|