diff --git a/ast/ast.odin b/ast/ast.odin index ce62b61..ec3b977 100644 --- a/ast/ast.odin +++ b/ast/ast.odin @@ -14,6 +14,7 @@ Expression :: union { Statement :: union { Let_Statement, + Return_Statement, } Identifier :: struct { @@ -25,9 +26,13 @@ Let_Statement :: struct { value: Expression, } +Return_Statement :: struct { + value: Expression, +} + parse :: proc(tokens: []token.Token, allocator := context.allocator) -> (Program, [dynamic]Error) { parser := init_parser(tokens) statements := make([dynamic]Statement, allocator) - for statement in next(&parser, allocator) do append(&statements, statement) + for statement in next(&parser) do append(&statements, statement) return Program{statements = statements}, parser.errors } diff --git a/ast/parser.odin b/ast/parser.odin index 8c33ee3..1bb5799 100644 --- a/ast/parser.odin +++ b/ast/parser.odin @@ -49,30 +49,26 @@ read_token :: proc(p: ^Parser) { p.right += 1 } -next :: proc(p: ^Parser, allocator := context.allocator) -> (statement: Statement, ok: bool) { +next :: proc(p: ^Parser) -> (statement: Statement, ok: bool) { switch p.value { case token.Token{}: ok = false case token.Token{type = .Let}: - statement, ok = parse_let_statement(p, allocator) + statement, ok = parse_let_statement(p) + case token.Token{type = .Return}: + statement, ok = parse_return_statement(p) } read_token(p) return } -parse_let_statement :: proc( - p: ^Parser, - allocator := context.allocator, -) -> ( - statement: Statement, - ok: bool, -) { +parse_let_statement :: proc(p: ^Parser) -> (statement: Statement, ok: bool) { peek_token(p, .Identifier) or_return read_token(p) literal := p.value.literal.(string) or_return - identifier := new(Identifier) + identifier := new(Identifier, p.allocator) identifier.value = literal peek_token(p, .Assignment) or_return @@ -85,3 +81,14 @@ parse_let_statement :: proc( read_token(p) return Let_Statement{name = identifier}, true } + +parse_return_statement :: proc(p: ^Parser) -> (statement: Statement, ok: bool) { + peek_token(p, .Integer) or_return + read_token(p) + literal := p.value.literal.(string) or_return + + peek_token(p, .Semicolon) or_return + read_token(p) + + return Return_Statement{value = Identifier{value = literal}}, true +} diff --git a/tests/ast/ast.odin b/tests/ast/ast.odin index 20ccc6a..e349701 100644 --- a/tests/ast/ast.odin +++ b/tests/ast/ast.odin @@ -91,3 +91,43 @@ let_without_semicolon :: proc(t: ^testing.T) { testing.expect_value(t, len(errors), 1) testing.expect_value(t, errors[0], "expected Semicolon, but got Illegal") } + +@(test) +return_statement :: proc(t: ^testing.T) { + tokens := []token.Token { + {type = .Return}, + {type = .Integer, literal = "5"}, + {type = .Semicolon}, + } + + program, errors := ast.parse(tokens) + defer free_all() + + testing.expect_value(t, len(program.statements), 1) + testing.expect_value(t, len(errors), 0) + statement, ok := program.statements[0].(ast.Return_Statement) + testing.expect(t, ok) + testing.expect_value(t, statement.value, ast.Identifier{value = "5"}) +} + +@(test) +return_without_integer :: proc(t: ^testing.T) { + tokens := []token.Token{{type = .Return}, {type = .Semicolon}} + program, errors := ast.parse(tokens) + defer free_all() + + testing.expect_value(t, len(program.statements), 0) + testing.expect_value(t, len(errors), 1) + testing.expect_value(t, errors[0], "expected Integer, but got Semicolon") +} + +@(test) +return_without_semicolon :: proc(t: ^testing.T) { + tokens := []token.Token{{type = .Return}, {type = .Integer, literal = "5"}} + program, errors := ast.parse(tokens) + defer free_all() + + testing.expect_value(t, len(program.statements), 0) + testing.expect_value(t, len(errors), 1) + testing.expect_value(t, errors[0], "expected Semicolon, but got Illegal") +}