import { expect, describe, test } from 'bun:test' 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`) }) })