378 lines
7.6 KiB
TypeScript
378 lines
7.6 KiB
TypeScript
import { expect, describe, test } from 'bun:test'
|
|
|
|
import '../shrimp.grammar' // Importing this so changes cause it to retest!
|
|
|
|
describe('if/else if/else', () => {
|
|
test('parses single line if', () => {
|
|
expect(`if y == 1: 'cool' end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
ConditionalOp
|
|
Identifier y
|
|
EqEq ==
|
|
Number 1
|
|
colon :
|
|
Block
|
|
String
|
|
StringFragment cool
|
|
keyword end
|
|
`)
|
|
|
|
expect('a = if x: 2 end').toMatchTree(`
|
|
Assign
|
|
AssignableIdentifier a
|
|
Eq =
|
|
IfExpr
|
|
keyword if
|
|
FunctionCallOrIdentifier
|
|
Identifier x
|
|
colon :
|
|
Block
|
|
Number 2
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test('parses multiline if', () => {
|
|
expect(`
|
|
if x < 9:
|
|
yes
|
|
end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
ConditionalOp
|
|
Identifier x
|
|
Lt <
|
|
Number 9
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier yes
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test('parses multiline if with else', () => {
|
|
expect(`if with-else:
|
|
x
|
|
else:
|
|
y
|
|
end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
FunctionCallOrIdentifier
|
|
Identifier with-else
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier x
|
|
ElseExpr
|
|
keyword else
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier y
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test('parses multiline if with else if', () => {
|
|
expect(`if with-else-if:
|
|
x
|
|
else if another-condition:
|
|
y
|
|
end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
FunctionCallOrIdentifier
|
|
Identifier with-else-if
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier x
|
|
ElseIfExpr
|
|
keyword else
|
|
keyword if
|
|
FunctionCallOrIdentifier
|
|
Identifier another-condition
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier y
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test('parses multiline if with multiple else if and else', () => {
|
|
expect(`if with-else-if-else:
|
|
x
|
|
else if another-condition:
|
|
y
|
|
else if yet-another-condition:
|
|
z
|
|
else:
|
|
oh-no
|
|
end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
FunctionCallOrIdentifier
|
|
Identifier with-else-if-else
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier x
|
|
ElseIfExpr
|
|
keyword else
|
|
keyword if
|
|
FunctionCallOrIdentifier
|
|
Identifier another-condition
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier y
|
|
ElseIfExpr
|
|
keyword else
|
|
keyword if
|
|
FunctionCallOrIdentifier
|
|
Identifier yet-another-condition
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier z
|
|
ElseExpr
|
|
keyword else
|
|
colon :
|
|
Block
|
|
FunctionCallOrIdentifier
|
|
Identifier oh-no
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test('does not parse identifiers that start with if', () => {
|
|
expect('iffy = if true: 2 end').toMatchTree(`
|
|
Assign
|
|
AssignableIdentifier iffy
|
|
Eq =
|
|
IfExpr
|
|
keyword if
|
|
Boolean true
|
|
colon :
|
|
Block
|
|
Number 2
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test('parses function calls in if tests', () => {
|
|
expect(`if var? 'abc': true end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
FunctionCall
|
|
Identifier var?
|
|
PositionalArg
|
|
String
|
|
StringFragment abc
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test("parses paren'd function calls in if tests", () => {
|
|
expect(`if (var? 'abc'): true end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
ParenExpr
|
|
FunctionCall
|
|
Identifier var?
|
|
PositionalArg
|
|
String
|
|
StringFragment abc
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
|
|
test('parses function calls in else-if tests', () => {
|
|
expect(`if false: true else if var? 'abc': true end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
Boolean false
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
ElseIfExpr
|
|
keyword else
|
|
keyword if
|
|
FunctionCall
|
|
Identifier var?
|
|
PositionalArg
|
|
String
|
|
StringFragment abc
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test("parses paren'd function calls in else-if tests", () => {
|
|
expect(`if false: true else if (var? 'abc'): true end`).toMatchTree(`
|
|
IfExpr
|
|
keyword if
|
|
Boolean false
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
ElseIfExpr
|
|
keyword else
|
|
keyword if
|
|
ParenExpr
|
|
FunctionCall
|
|
Identifier var?
|
|
PositionalArg
|
|
String
|
|
StringFragment abc
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end
|
|
`)
|
|
})
|
|
|
|
test('allows if/else in parens', () => {
|
|
expect(`eh? = (if true: true end)`).toMatchTree(`
|
|
Assign
|
|
AssignableIdentifier eh?
|
|
Eq =
|
|
ParenExpr
|
|
IfExpr
|
|
keyword if
|
|
Boolean true
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end
|
|
`)
|
|
})
|
|
})
|
|
|
|
describe('while', () => {
|
|
test('infinite loop', () => {
|
|
expect(`while true: true end`).toMatchTree(`
|
|
WhileExpr
|
|
keyword while
|
|
Boolean true
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end`)
|
|
})
|
|
|
|
test('basic expression', () => {
|
|
expect(`while a > 0: true end`).toMatchTree(`
|
|
WhileExpr
|
|
keyword while
|
|
ConditionalOp
|
|
Identifier a
|
|
Gt >
|
|
Number 0
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end`)
|
|
})
|
|
|
|
|
|
test('compound expression', () => {
|
|
expect(`while a > 0 and b < 100 and c < 1000: true end`).toMatchTree(`
|
|
WhileExpr
|
|
keyword while
|
|
ConditionalOp
|
|
ConditionalOp
|
|
ConditionalOp
|
|
Identifier a
|
|
Gt >
|
|
Number 0
|
|
And and
|
|
ConditionalOp
|
|
Identifier b
|
|
Lt <
|
|
Number 100
|
|
And and
|
|
ConditionalOp
|
|
Identifier c
|
|
Lt <
|
|
Number 1000
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end`)
|
|
})
|
|
|
|
test('multiline infinite loop', () => {
|
|
expect(`
|
|
while true:
|
|
true
|
|
end`).toMatchTree(`
|
|
WhileExpr
|
|
keyword while
|
|
Boolean true
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end`)
|
|
})
|
|
|
|
test('multiline basic expression', () => {
|
|
expect(`
|
|
while a > 0:
|
|
true
|
|
end`).toMatchTree(`
|
|
WhileExpr
|
|
keyword while
|
|
ConditionalOp
|
|
Identifier a
|
|
Gt >
|
|
Number 0
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end`)
|
|
})
|
|
|
|
|
|
test('multiline compound expression', () => {
|
|
expect(`
|
|
while a > 0 and b < 100 and c < 1000:
|
|
true
|
|
end`).toMatchTree(`
|
|
WhileExpr
|
|
keyword while
|
|
ConditionalOp
|
|
ConditionalOp
|
|
ConditionalOp
|
|
Identifier a
|
|
Gt >
|
|
Number 0
|
|
And and
|
|
ConditionalOp
|
|
Identifier b
|
|
Lt <
|
|
Number 100
|
|
And and
|
|
ConditionalOp
|
|
Identifier c
|
|
Lt <
|
|
Number 1000
|
|
colon :
|
|
Block
|
|
Boolean true
|
|
keyword end`)
|
|
})
|
|
}) |