shrimp/src/parser/tests/literals.test.ts

618 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('can have spaces between equals', () => {
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
`)
})
})