diff options
Diffstat (limited to 'source/parser.elna')
| -rw-r--r-- | source/parser.elna | 1162 |
1 files changed, 1162 insertions, 0 deletions
diff --git a/source/parser.elna b/source/parser.elna new file mode 100644 index 0000000..30f79f8 --- /dev/null +++ b/source/parser.elna @@ -0,0 +1,1162 @@ +(* This Source Code Form is subject to the terms of the Mozilla Public License, + v. 2.0. If a copy of the MPL was not distributed with this file, You can + obtain one at https://mozilla.org/MPL/2.0/. *) +module +import common, cstdlib, lexer, ast, diagnostic + +proc elna_parser_expect*(cursor: ^ElnaLexerCursor; expected: ElnaLexerKind; error_list: ^ElnaList) -> ^ElnaLexerToken +var + token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken +begin + elna_lexer_skip_empty_lines(cursor); + token := elna_lexer_peek(cursor); + + if token^.kind = expected then + token := elna_lexer_read(cursor) + else + token := nil; + parser_error := elna_error_unexpected_token_create(cursor, 1u); + parser_error^.expected[1] := expected; + elna_list_append(error_list, cast(parser_error: ^ElnaListNode)) + end +return token + +proc elna_parser_escape*(current_position: ^const Word8; result: ^Word8) -> Word +var + parsed_length: Word + next_character: Word8 + pos: ^const Word8 +begin + pos := current_position; + next_character := pos^; + + if next_character = '\\' then + parsed_length := 2u; + pos := pos + 1u; + next_character := pos^; + + if next_character = '\\' then + result^ := 92u8 + elsif next_character = 'n' then + result^ := 10u8 + elsif next_character = 't' then + result^ := 9u8 + elsif next_character = 'f' then + result^ := 12u8 + elsif next_character = 'r' then + result^ := 13u8 + elsif next_character = 'v' then + result^ := 11u8 + elsif next_character = '"' then + result^ := 34u8 + elsif next_character = '\'' then + result^ := 39u8 + elsif next_character = '0' then + result^ := 0u8 + else + result^ := next_character + end + else + parsed_length := 1u; + result^ := next_character + end +return parsed_length + +proc elna_parser_integer_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeIntegerLiteral +var + token: ^ElnaLexerToken + result: ^ElnaTreeIntegerLiteral + i: Word := 1u + val: Word := 0u +begin + result := malloc#[ElnaTreeIntegerLiteral](#size(ElnaTreeIntegerLiteral)); + token := elna_lexer_read(cursor); + result^.kind := ElnaTreeKind.integer_literal; + result^.type_decoration := nil; + result^.position := token^.position; + + while i <= token^.start.length do + val := val * 10u + cast(token^.start[i] - '0': Word); + i := i + 1u + end; + result^.value := val +return result + +proc elna_parser_boolean_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeBooleanLiteral +var + token: ^ElnaLexerToken + result: ^ElnaTreeBooleanLiteral +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeBooleanLiteral](#size(ElnaTreeBooleanLiteral)); + result^.kind := ElnaTreeKind.boolean_literal; + result^.value := token^.start = "true"; + result^.type_decoration := nil; + result^.position := token^.position +return result + +proc elna_parser_nil_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeNilLiteral +var + token: ^ElnaLexerToken + result: ^ElnaTreeNilLiteral +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeNilLiteral](#size(ElnaTreeNilLiteral)); + result^.kind := ElnaTreeKind.null; + result^.type_decoration := nil; + result^.position := token^.position +return result + +proc elna_parser_character_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeCharacterLiteral +var + result: ^ElnaTreeCharacterLiteral + token: ^ElnaLexerToken +begin + result := malloc#[ElnaTreeCharacterLiteral](#size(ElnaTreeCharacterLiteral)); + token := elna_lexer_read(cursor); + result^.kind := ElnaTreeKind.character_literal; + result^.position := token^.position; + result^.type_decoration := nil; + elna_parser_escape(token^.start.ptr + 1u, @result^.value) +return result + +proc elna_parser_variable_expression*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeVariableExpression +var + result: ^ElnaTreeVariableExpression + token: ^ElnaLexerToken +begin + result := malloc#[ElnaTreeVariableExpression](#size(ElnaTreeVariableExpression)); + token := elna_lexer_read(cursor); + result^.kind := ElnaTreeKind.variable_expression; + result^.name := token^.start; + result^.position := token^.position; + result^.type_decoration := nil +return result + +proc elna_parser_string_literal*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeStringLiteral +var + result: ^ElnaTreeStringLiteral + token: ^ElnaLexerToken + current_position: ^const Word8 + parsed_length: Word + parsed_total: Word + target_start, target_position: ^Word8 +begin + result := malloc#[ElnaTreeStringLiteral](#size(ElnaTreeStringLiteral)); + token := elna_lexer_read(cursor); + target_start := malloc#[Word8](token^.start.length); + target_position := target_start; + current_position := token^.start.ptr + 1u; + parsed_total := 2u; + + result^.kind := ElnaTreeKind.string_literal; + result^.position := token^.position; + result^.type_decoration := nil; + + while parsed_total < token^.start.length do + parsed_length := elna_parser_escape(current_position, target_position); + current_position := current_position + parsed_length; + parsed_total := parsed_total + parsed_length; + target_position := target_position + 1u + end; + result^.value := target_start[1 to cast(target_position - target_start: Word)] +return result + +proc elna_parser_trait_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeTraitExpression +var + result: ^ElnaTreeTraitExpression + token: ^ElnaLexerToken +begin + result := malloc#[ElnaTreeTraitExpression](#size(ElnaTreeTraitExpression)); + result^.kind := ElnaTreeKind.trait_expression; + token := elna_lexer_read(cursor); + result^.name := token^.start; + result^.position := token^.position; + + if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) <> nil then + result^.argument := elna_parser_type_expression(cursor, error_list); + if result^.argument = nil then + result := free_and_nil(result) + elsif elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then + result := free_and_nil(result) + end + else + result := free_and_nil(result) + end +return result + +proc elna_parser_cast_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeCastExpression +var + result: ^ElnaTreeCastExpression := nil + token: ^ElnaLexerToken + start_location: ElnaLocation +begin + token := elna_lexer_read(cursor); + start_location := token^.position.start_location; + + if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) <> nil then + result := malloc#[ElnaTreeCastExpression](#size(ElnaTreeCastExpression)); + result^.kind := ElnaTreeKind._cast; + result^.position.start_location := start_location; + result^.type_decoration := nil; + result^.expression := elna_parser_binary_expression(cursor, error_list); + if result^.expression = nil then + result := free_and_nil(result) + elsif elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) = nil then + result := free_and_nil(result) + else + result^.type_expression := elna_parser_type_expression(cursor, error_list); + if result^.type_expression = nil then + result := free_and_nil(result) + else + token := elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list); + if token = nil then + result := free_and_nil(result) + else + result^.position.end_location := token^.position.end_location + end + end + end + end +return result + +proc elna_parser_simple_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeExpression +var + token: ^ElnaLexerToken + result: ^ElnaTreeExpression := nil +begin + token := elna_lexer_peek(cursor); + case token^.kind of + ElnaLexerKind.character: + result := cast(elna_parser_character_literal(cursor): ^ElnaTreeExpression) + | ElnaLexerKind.integer: + result := cast(elna_parser_integer_literal(cursor): ^ElnaTreeExpression) + | ElnaLexerKind.string: + result := cast(elna_parser_string_literal(cursor): ^ElnaTreeExpression) + | ElnaLexerKind.boolean: + result := cast(elna_parser_boolean_literal(cursor): ^ElnaTreeExpression) + | ElnaLexerKind.null: + result := cast(elna_parser_nil_literal(cursor): ^ElnaTreeExpression) + | ElnaLexerKind._cast: + result := cast(elna_parser_cast_expression(cursor, error_list): ^ElnaTreeExpression) + | ElnaLexerKind.trait: + result := cast(elna_parser_trait_expression(cursor, error_list): ^ElnaTreeExpression) + | ElnaLexerKind.identifier: + result := cast(elna_parser_variable_expression(cursor): ^ElnaTreeExpression) + else + end +return result + +proc elna_parser_dereference_expression*(cursor: ^ElnaLexerCursor; + simple_expression: ^ElnaTreeExpression) -> ^ElnaTreeDereferenceExpression +var + result: ^ElnaTreeDereferenceExpression + token: ^ElnaLexerToken +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeDereferenceExpression](#size(ElnaTreeDereferenceExpression)); + result^.kind := ElnaTreeKind.dereference_expression; + result^.pointer := simple_expression; + result^.type_decoration := nil; + result^.position := token^.position +return result + +proc elna_parser_field_access_expression*(cursor: ^ElnaLexerCursor; + aggregate: ^ElnaTreeExpression) -> ^ElnaTreeFieldAccessExpression +var + result: ^ElnaTreeFieldAccessExpression + token: ^ElnaLexerToken +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeFieldAccessExpression](#size(ElnaTreeFieldAccessExpression)); + result^.kind := ElnaTreeKind.field_access_expression; + result^.type_decoration := nil; + result^.aggregate := aggregate; + result^.position.start_location := token^.position.start_location; + + token := elna_lexer_read(cursor); + result^.field := token^.start; + result^.position.end_location := token^.position.end_location +return result + +proc elna_parser_array_access_expression*(cursor: ^ElnaLexerCursor; + array: ^ElnaTreeExpression; error_list: ^ElnaList) -> ^ElnaTreeArrayAccessExpression +var + result: ^ElnaTreeArrayAccessExpression + token: ^ElnaLexerToken +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeArrayAccessExpression](#size(ElnaTreeArrayAccessExpression)); + result^.kind := ElnaTreeKind.array_access_expression; + result^.type_decoration := nil; + result^.array := array; + result^.position.start_location := token^.position.start_location; + + result^.index := elna_parser_binary_expression(cursor, error_list); + if result^.index = nil then + result := free_and_nil(result) + else + token := elna_parser_expect(cursor, ElnaLexerKind.right_square, error_list); + if token = nil then + result := free_and_nil(result) + else + result^.position.end_location := token^.position.end_location + end + end +return result + +proc elna_parser_call*(cursor: ^ElnaLexerCursor; callee: ^ElnaTreeExpression; error_list: ^ElnaList) -> ^ElnaTreeCall +var + result: ^ElnaTreeCall + argument_entry: ^ElnaTreeExpressionList + token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken + reading_args: Bool := true +begin + result := malloc#[ElnaTreeCall](#size(ElnaTreeCall)); + result^.kind := ElnaTreeKind.call; + result^.type_decoration := nil; + result^.arguments := nil; + result^.count := 0u; + result^.callee := cast(callee: ^ElnaTreeVariableExpression); + + token := elna_lexer_read(cursor); + result^.position.start_location := token^.position.start_location; + token := elna_lexer_peek(cursor); + + if token^.kind = ElnaLexerKind.right_paren then + token := elna_lexer_read(cursor); + result^.position.end_location := token^.position.end_location + else + while reading_args do + if result^.arguments = nil then + result^.arguments := malloc#[ElnaTreeExpressionList](#size(ElnaTreeExpressionList)); + argument_entry := result^.arguments + else + argument_entry^.next := malloc#[ElnaTreeExpressionList](#size(ElnaTreeExpressionList)); + argument_entry := argument_entry^.next + end; + argument_entry^.next := nil; + argument_entry^.expression := elna_parser_binary_expression(cursor, error_list); + if argument_entry^.expression = nil then + result := free_and_nil(result); + reading_args := false + else + result^.count := result^.count + 1u; + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.comma then + elna_lexer_read(cursor) + elsif token^.kind = ElnaLexerKind.right_paren then + token := elna_lexer_read(cursor); + result^.position.end_location := token^.position.end_location; + reading_args := false + else + parser_error := elna_error_unexpected_token_create(cursor, 2u); + parser_error^.expected[1] := ElnaLexerKind.comma; + parser_error^.expected[2] := ElnaLexerKind.right_paren; + elna_list_append(error_list, cast(parser_error: ^ElnaListNode)); + result := free_and_nil(result); + reading_args := false + end + end + end + end +return result + +proc elna_parser_designator*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeExpression +var + simple_expression: ^ElnaTreeExpression + token: ^ElnaLexerToken + continue_loop: Bool := true +begin + simple_expression := elna_parser_simple_expression(cursor, error_list); + if simple_expression <> nil then + while continue_loop do + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.hat then + simple_expression := cast(elna_parser_dereference_expression(cursor, simple_expression): ^ElnaTreeExpression) + elsif token^.kind = ElnaLexerKind.dot then + simple_expression := cast(elna_parser_field_access_expression(cursor, simple_expression): ^ElnaTreeExpression) + elsif token^.kind = ElnaLexerKind.left_square then + simple_expression := cast(elna_parser_array_access_expression(cursor, simple_expression, error_list): ^ElnaTreeExpression); + if simple_expression = nil then + continue_loop := false + end + elsif token^.kind = ElnaLexerKind.left_paren then + simple_expression := cast(elna_parser_call(cursor, simple_expression, error_list): ^ElnaTreeExpression); + if simple_expression = nil then + continue_loop := false + end + else + continue_loop := false + end + end + end +return simple_expression + +proc elna_parser_unary_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeExpression +var + unary_result: ^ElnaTreeUnaryExpression + result: ^ElnaTreeExpression + op_kind: ElnaLexerKind + has_op: Bool := false + token: ^ElnaLexerToken +begin + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.at or token^.kind = ElnaLexerKind.minus or token^.kind = ElnaLexerKind.not then + op_kind := token^.kind; + has_op := true; + elna_lexer_read(cursor) + end; + result := elna_parser_designator(cursor, error_list); + if result <> nil & has_op then + unary_result := malloc#[ElnaTreeUnaryExpression](#size(ElnaTreeUnaryExpression)); + unary_result^.kind := ElnaTreeKind.unary_expression; + unary_result^.operand := result; + unary_result^.operator := op_kind; + unary_result^.position := token^.position; + unary_result^.type_decoration := nil; + result := cast(unary_result: ^ElnaTreeExpression) + end +return result + +proc elna_parser_binary_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeExpression +var + lhs_node: ^ElnaTreeExpression + rhs_node: ^ElnaTreeExpression := nil + bin_result: ^ElnaTreeBinaryExpression + token: ^ElnaLexerToken +begin + lhs_node := elna_parser_unary_expression(cursor, error_list); + token := elna_lexer_peek(cursor); + + case token^.kind of + ElnaLexerKind.plus, + ElnaLexerKind.minus, + ElnaLexerKind.multiplication, + ElnaLexerKind.and, + ElnaLexerKind._or, + ElnaLexerKind._xor, + ElnaLexerKind.equals, + ElnaLexerKind.remainder, + ElnaLexerKind.division, + ElnaLexerKind.less_than, + ElnaLexerKind.greater_than, + ElnaLexerKind.less_equal, + ElnaLexerKind.not_equal, + ElnaLexerKind.greater_equal: + elna_lexer_read(cursor); + rhs_node := elna_parser_unary_expression(cursor, error_list) + else + end; + + if rhs_node <> nil then + bin_result := malloc#[ElnaTreeBinaryExpression](#size(ElnaTreeBinaryExpression)); + bin_result^.kind := ElnaTreeKind.binary_expression; + bin_result^.lhs := lhs_node; + bin_result^.rhs := rhs_node; + bin_result^.operator := token^.kind; + bin_result^.position := token^.position; + bin_result^.type_decoration := nil; + lhs_node := cast(bin_result: ^ElnaTreeExpression) + end +return lhs_node + +proc elna_parser_label_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeLabelDeclaration +var + result: ^ElnaTreeLabelDeclaration + token: ^ElnaLexerToken +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeLabelDeclaration](#size(ElnaTreeLabelDeclaration)); + result^.kind := ElnaTreeKind.label_declaration; + result^.next := nil; + result^.position.start_location := token^.position.start_location; + + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token <> nil then + result^.label := token^.start; + result^.position.end_location := token^.position.end_location + else + result := free_and_nil(result) + end +return result + +proc elna_parser_assign_statement*(cursor: ^ElnaLexerCursor; assignee: ^ElnaTreeExpression; error_list: ^ElnaList) -> ^ElnaTreeAssignStatement +var + token: ^ElnaLexerToken + result: ^ElnaTreeAssignStatement +begin + result := malloc#[ElnaTreeAssignStatement](#size(ElnaTreeAssignStatement)); + result^.kind := ElnaTreeKind.assign_statement; + result^.next := nil; + result^.assignee := assignee; + result^.assignment := nil; + + token := elna_parser_expect(cursor, ElnaLexerKind.assignment, error_list); + if token <> nil then + result^.position := token^.position; + result^.assignment := elna_parser_binary_expression(cursor, error_list) + end; + if result^.assignment = nil then + result := free_and_nil(result) + end +return result + +proc elna_parser_return_statement*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeReturnStatement +var + token: ^ElnaLexerToken + result: ^ElnaTreeReturnStatement +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeReturnStatement](#size(ElnaTreeReturnStatement)); + result^.kind := ElnaTreeKind.return_statement; + result^.next := nil; + result^.position := token^.position; + result^.returned := elna_parser_binary_expression(cursor, error_list); + if result^.returned = nil then + result := free_and_nil(result) + end +return result + +proc elna_parser_conditional_statements*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList; + block_keyword: ElnaLexerKind) -> ^ElnaTreeConditionalStatements +var + result: ^ElnaTreeConditionalStatements +begin + result := malloc#[ElnaTreeConditionalStatements](#size(ElnaTreeConditionalStatements)); + elna_lexer_read(cursor); + result^.condition := elna_parser_binary_expression(cursor, error_list); + if result^.condition = nil then + result := free_and_nil(result) + else + if elna_parser_expect(cursor, block_keyword, error_list) <> nil then + result^.statements := elna_parser_statements(cursor, error_list) + end; + if elna_list_empty(error_list) then + result^.next := nil + else + result := free_and_nil(result) + end + end +return result + +proc elna_parser_if_statement*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeIfStatement +var + result: ^ElnaTreeIfStatement + previous_conditional: ^ElnaTreeConditionalStatements + next_conditional: ^ElnaTreeConditionalStatements + token: ^ElnaLexerToken + reading_elsif: Bool := true +begin + token := elna_lexer_peek(cursor); + result := malloc#[ElnaTreeIfStatement](#size(ElnaTreeIfStatement)); + result^.kind := ElnaTreeKind.if_statement; + result^.position := token^.position; + result^.next := nil; + + previous_conditional := elna_parser_conditional_statements(cursor, error_list, ElnaLexerKind._then); + result^.conditionals := previous_conditional; + + while reading_elsif do + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind._elsif then + next_conditional := elna_parser_conditional_statements(cursor, error_list, ElnaLexerKind._then); + previous_conditional^.next := next_conditional; + previous_conditional := next_conditional + elsif token^.kind = ElnaLexerKind._else then + elna_lexer_read(cursor); + result^._else := elna_parser_statements(cursor, error_list); + reading_elsif := false + else + result^._else := nil; + reading_elsif := false + end + end; + elna_parser_expect(cursor, ElnaLexerKind._end, error_list) +return result + +proc elna_parser_statement*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeStatement +var + result: ^ElnaTreeStatement := nil + call_result: ^ElnaTreeCallStatement + designator: ^ElnaTreeExpression + token: ^ElnaLexerToken +begin + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind._if then + result := cast(elna_parser_if_statement(cursor, error_list): ^ElnaTreeStatement) + elsif token^.kind = ElnaLexerKind._return then + result := cast(elna_parser_return_statement(cursor, error_list): ^ElnaTreeStatement) + elsif token^.kind = ElnaLexerKind.dot then + result := cast(elna_parser_label_declaration(cursor, error_list): ^ElnaTreeStatement) + elsif token^.kind = ElnaLexerKind.identifier then + designator := elna_parser_designator(cursor, error_list); + if designator <> nil then + if designator^.kind <> ElnaTreeKind.call then + result := cast(elna_parser_assign_statement(cursor, designator, error_list): ^ElnaTreeStatement) + else + call_result := malloc#[ElnaTreeCallStatement](#size(ElnaTreeCallStatement)); + call_result^.kind := ElnaTreeKind.call_statement; + call_result^.next := nil; + call_result^.call := cast(designator: ^ElnaTreeCall); + call_result^.position := designator^.position; + result := cast(call_result: ^ElnaTreeStatement) + end + end + end +return result + +proc elna_parser_statements*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeStatement +var + previous_statement: ^ElnaTreeStatement + next_statement: ^ElnaTreeStatement + first_statement: ^ElnaTreeStatement + token: ^ElnaLexerToken +begin + elna_lexer_skip_empty_lines(cursor); + first_statement := elna_parser_statement(cursor, error_list); + previous_statement := first_statement; + if previous_statement <> nil then + token := elna_lexer_peek(cursor); + while token^.kind = ElnaLexerKind.semicolon & elna_list_empty(error_list) do + elna_lexer_read(cursor); + elna_lexer_skip_empty_lines(cursor); + next_statement := elna_parser_statement(cursor, error_list); + previous_statement^.next := next_statement; + previous_statement := next_statement; + token := elna_lexer_peek(cursor) + end + end; + elna_lexer_skip_empty_lines(cursor) +return first_statement + +proc elna_parser_named_type_expression*(cursor: ^ElnaLexerCursor) -> ^ElnaTreeNamedTypeExpression +var + result: ^ElnaTreeNamedTypeExpression + token: ^ElnaLexerToken +begin + result := malloc#[ElnaTreeNamedTypeExpression](#size(ElnaTreeNamedTypeExpression)); + token := elna_lexer_read(cursor); + result^.kind := ElnaTreeKind.named_type_expression; + result^.name := token^.start; + result^.position := token^.position +return result + +proc elna_parser_pointer_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreePointerTypeExpression +var + result: ^ElnaTreePointerTypeExpression + token: ^ElnaLexerToken +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreePointerTypeExpression](#size(ElnaTreePointerTypeExpression)); + result^.kind := ElnaTreeKind.pointer_type_expression; + result^.base := elna_parser_type_expression(cursor, error_list); + result^.position := token^.position; + if result^.base = nil then + result := free_and_nil(result) + end +return result + +proc elna_parser_array_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeArrayTypeExpression +var + result: ^ElnaTreeArrayTypeExpression + token: ^ElnaLexerToken +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeArrayTypeExpression](#size(ElnaTreeArrayTypeExpression)); + result^.kind := ElnaTreeKind.array_type_expression; + result^.position.start_location := token^.position.start_location; + + result^.length := elna_parser_binary_expression(cursor, error_list); + if result^.length = nil then + result := free_and_nil(result) + else + token := elna_parser_expect(cursor, ElnaLexerKind.right_square, error_list); + if token = nil then + result := free_and_nil(result) + else + result^.base := elna_parser_type_expression(cursor, error_list); + if result^.base = nil then + result := free_and_nil(result) + else + result^.position.end_location := token^.position.end_location + end + end + end +return result + +proc elna_parser_record_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeRecordTypeExpression +var + entry: ^ElnaTreeField + result: ^ElnaTreeRecordTypeExpression + previous_entry: ^ElnaTreeField + token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken + reading_members: Bool := true +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeRecordTypeExpression](#size(ElnaTreeRecordTypeExpression)); + result^.kind := ElnaTreeKind.record_type_expression; + result^.members := nil; + result^.length := 0u; + result^.position := token^.position; + + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.left_paren then + elna_lexer_read(cursor); + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token = nil then + result := free_and_nil(result); + reading_members := false + else + result^.parent := token^.start; + if elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then + result := free_and_nil(result); + reading_members := false + end + end + end; + + while reading_members & result <> nil do + token := elna_lexer_read(cursor); + if token^.kind = ElnaLexerKind._end then + reading_members := false + elsif token^.kind <> ElnaLexerKind.identifier then + parser_error := elna_error_unexpected_token_create(cursor, 2u); + parser_error^.expected[1] := ElnaLexerKind._end; + parser_error^.expected[2] := ElnaLexerKind.identifier; + elna_list_append(error_list, cast(parser_error: ^ElnaListNode)); + result := free_and_nil(result); + reading_members := false + else + entry := malloc#[ElnaTreeField](#size(ElnaTreeField)); + result^.length := result^.length + 1u; + entry^.name := token^.start; + if elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) = nil then + result := free_and_nil(result); + reading_members := false + else + entry^.type_expression := elna_parser_type_expression(cursor, error_list); + if entry^.type_expression = nil then + result := free_and_nil(result); + reading_members := false + else + entry^.next := nil; + if result^.members = nil then + result^.members := entry + else + previous_entry^.next := entry + end; + previous_entry := entry; + + token := elna_lexer_read(cursor); + if token^.kind = ElnaLexerKind.semicolon then + (* continue *) + elsif token^.kind = ElnaLexerKind._end then + reading_members := false + else + parser_error := elna_error_unexpected_token_create(cursor, 2u); + parser_error^.expected[1] := ElnaLexerKind._end; + parser_error^.expected[2] := ElnaLexerKind.semicolon; + elna_list_append(error_list, cast(parser_error: ^ElnaListNode)); + reading_members := false + end + end + end + end + end +return result + +proc elna_parser_enumeration_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeEnumerationTypeExpression +var + result: ^ElnaTreeEnumerationTypeExpression + entry: ^ElnaTreeEnumeration + previous_entry: ^ElnaTreeEnumeration + token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken + reading_members: Bool := true +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeEnumerationTypeExpression](#size(ElnaTreeEnumerationTypeExpression)); + result^.kind := ElnaTreeKind.enumeration_type_expression; + result^.members := nil; + result^.length := 0u; + result^.position.start_location := token^.position.start_location; + + while reading_members & result <> nil do + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token = nil then + result := free_and_nil(result); + reading_members := false + else + entry := malloc#[ElnaTreeEnumeration](#size(ElnaTreeEnumeration)); + result^.length := result^.length + 1u; + entry^.name := token^.start; + entry^.next := nil; + if result^.members = nil then + result^.members := entry + else + previous_entry^.next := entry + end; + previous_entry := entry; + + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.comma then + elna_lexer_read(cursor) + elsif token^.kind = ElnaLexerKind.right_paren then + token := elna_lexer_read(cursor); + result^.position.end_location := token^.position.end_location; + reading_members := false + else + parser_error := elna_error_unexpected_token_create(cursor, 2u); + parser_error^.expected[1] := ElnaLexerKind.comma; + parser_error^.expected[2] := ElnaLexerKind.right_paren; + elna_list_append(error_list, cast(parser_error: ^ElnaListNode)); + result := free_and_nil(result); + reading_members := false + end + end + end +return result + +proc elna_parser_type_expression*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeTypeExpression +var + result: ^ElnaTreeTypeExpression := nil + token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken +begin + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.identifier then + result := cast(elna_parser_named_type_expression(cursor): ^ElnaTreeTypeExpression) + elsif token^.kind = ElnaLexerKind.left_paren then + result := cast(elna_parser_enumeration_type_expression(cursor, error_list): ^ElnaTreeTypeExpression) + elsif token^.kind = ElnaLexerKind._record then + result := cast(elna_parser_record_type_expression(cursor, error_list): ^ElnaTreeTypeExpression) + elsif token^.kind = ElnaLexerKind.hat then + result := cast(elna_parser_pointer_type_expression(cursor, error_list): ^ElnaTreeTypeExpression) + elsif token^.kind = ElnaLexerKind.left_square then + result := cast(elna_parser_array_type_expression(cursor, error_list): ^ElnaTreeTypeExpression) + else + parser_error := elna_error_unexpected_token_create(cursor, 5u); + parser_error^.expected[1] := ElnaLexerKind.identifier; + parser_error^.expected[2] := ElnaLexerKind.left_paren; + parser_error^.expected[3] := ElnaLexerKind._record; + parser_error^.expected[4] := ElnaLexerKind.hat; + parser_error^.expected[5] := ElnaLexerKind.left_square; + elna_list_append(error_list, cast(parser_error: ^ElnaListNode)) + end +return result + +proc elna_parser_variable_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeVariableDeclaration +var + var_type: ^ElnaTreeTypeExpression + result: ^ElnaTreeVariableDeclaration := nil + token: ^ElnaLexerToken +begin + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token <> nil then + if elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) <> nil then + var_type := elna_parser_type_expression(cursor, error_list); + if var_type <> nil then + result := malloc#[ElnaTreeVariableDeclaration](#size(ElnaTreeVariableDeclaration)); + result^.kind := ElnaTreeKind.variable_declaration; + result^.next := nil; + result^.name := token^.start; + result^.type_expression := var_type; + result^.position := token^.position + end + end + end +return result + +proc elna_parser_parameters*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeVariableDeclaration +var + parameters: ^ElnaTreeVariableDeclaration := nil + token: ^ElnaLexerToken + current_declaration: ^ElnaTreeVariableDeclaration + next_declaration: ^ElnaTreeVariableDeclaration + reading: Bool := true +begin + token := elna_lexer_peek(cursor); + if token^.kind <> ElnaLexerKind.right_paren then + while reading do + next_declaration := elna_parser_variable_declaration(cursor, error_list); + if next_declaration = nil then + parameters := free_and_nil(parameters); + reading := false + else + if parameters = nil then + parameters := next_declaration + else + current_declaration^.next := cast(next_declaration: ^ElnaTreeDeclaration) + end; + current_declaration := next_declaration; + + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.comma or token^.kind = ElnaLexerKind.semicolon then + elna_lexer_read(cursor) + else + reading := false + end + end + end + end +return parameters + +proc elna_parser_procedure_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeProcedureDeclaration +var + result: ^ElnaTreeProcedureDeclaration + token: ^ElnaLexerToken +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeProcedureDeclaration](#size(ElnaTreeProcedureDeclaration)); + result^.kind := ElnaTreeKind.procedure_declaration; + result^.next := nil; + result^.position := token^.position; + + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token = nil then + result := free_and_nil(result) + else + result^.name := token^.start; + + if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) = nil then + result := free_and_nil(result) + else + result^.parameters := elna_parser_parameters(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + elsif elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then + result := free_and_nil(result) + else + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.arrow then + elna_lexer_read(cursor); + result^.return_type := elna_parser_type_expression(cursor, error_list); + if result^.return_type = nil then + result := free_and_nil(result) + end + else + result^.return_type := nil + end; + + if result <> nil then + token := elna_lexer_peek(cursor); + result^.is_extern := token^.kind = ElnaLexerKind._extern; + if result^.is_extern then + elna_lexer_read(cursor); + result^.temporaries := nil; + result^.body := nil + else + result^.temporaries := elna_parser_var_part(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + else + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind._begin then + elna_lexer_read(cursor); + result^.body := elna_parser_statements(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + elsif elna_parser_expect(cursor, ElnaLexerKind._end, error_list) = nil then + result := free_and_nil(result) + end + elsif token^.kind = ElnaLexerKind._return then + result^.body := cast(elna_parser_return_statement(cursor, error_list): ^ElnaTreeStatement); + if result^.body = nil then + result := free_and_nil(result) + end + end + end + end + end + end + end + end +return result + +proc elna_parser_procedures*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeProcedureDeclaration +var + parser_node: ^ElnaTreeProcedureDeclaration + result: ^ElnaTreeProcedureDeclaration := nil + current_declaration: ^ElnaTreeProcedureDeclaration + token: ^ElnaLexerToken + reading: Bool := true +begin + while reading do + elna_lexer_skip_empty_lines(cursor); + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind._proc then + parser_node := elna_parser_procedure_declaration(cursor, error_list); + if parser_node <> nil then + if result = nil then + result := parser_node + else + current_declaration^.next := cast(parser_node: ^ElnaTreeDeclaration) + end; + current_declaration := parser_node + else + reading := false + end + else + reading := false + end + end +return result + +proc elna_parser_type_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeTypeDeclaration +var + result: ^ElnaTreeTypeDeclaration + token: ^ElnaLexerToken +begin + token := elna_lexer_read(cursor); + result := malloc#[ElnaTreeTypeDeclaration](#size(ElnaTreeTypeDeclaration)); + result^.kind := ElnaTreeKind.type_declaration; + result^.next := nil; + result^.name := token^.start; + result^.position := token^.position; + + if elna_parser_expect(cursor, ElnaLexerKind.equals, error_list) <> nil then + result^.type_expression := elna_parser_type_expression(cursor, error_list) + else + result := free_and_nil(result) + end +return result + +proc elna_parser_type_part*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeDeclaration +var + parser_node: ^ElnaTreeDeclaration + result: ^ElnaTreeDeclaration := nil + current_declaration: ^ElnaTreeDeclaration + token: ^ElnaLexerToken + reading: Bool := true +begin + elna_lexer_skip_empty_lines(cursor); + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind._type then + elna_lexer_read(cursor); + while reading do + elna_lexer_skip_empty_lines(cursor); + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.identifier then + parser_node := cast(elna_parser_type_declaration(cursor, error_list): ^ElnaTreeDeclaration); + if parser_node <> nil then + if result = nil then + result := parser_node + else + current_declaration^.next := parser_node + end; + current_declaration := parser_node; + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.semicolon then + elna_lexer_read(cursor) + end + else + reading := false + end + else + reading := false + end + end + end +return result + +proc elna_parser_var_part*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeVariableDeclaration +var + result: ^ElnaTreeVariableDeclaration := nil + variable_node: ^ElnaTreeVariableDeclaration + current_declaration: ^ElnaTreeVariableDeclaration + token: ^ElnaLexerToken + reading: Bool := true +begin + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind._var then + elna_lexer_read(cursor); + while reading do + elna_lexer_skip_empty_lines(cursor); + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.identifier then + variable_node := elna_parser_variable_declaration(cursor, error_list); + if variable_node <> nil then + if result = nil then + result := variable_node + else + current_declaration^.next := cast(variable_node: ^ElnaTreeDeclaration) + end; + current_declaration := variable_node; + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.semicolon then + elna_lexer_read(cursor) + end + else + reading := false + end + else + reading := false + end + end + end +return result + +proc elna_parser_program_body*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeStatement +var + result: ^ElnaTreeStatement := nil + token: ^ElnaLexerToken +begin + elna_lexer_skip_empty_lines(cursor); + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind._begin then + elna_lexer_read(cursor); + result := elna_parser_statements(cursor, error_list); + if elna_parser_expect(cursor, ElnaLexerKind._end, error_list) = nil then + result := free_and_nil(result) + elsif elna_parser_expect(cursor, ElnaLexerKind.dot, error_list) = nil then + result := free_and_nil(result) + end + elsif token^.kind = ElnaLexerKind._end then + elna_lexer_read(cursor); + if elna_parser_expect(cursor, ElnaLexerKind.dot, error_list) = nil then + result := free_and_nil(result) + end + end +return result + +proc elna_parser_module_declaration*(cursor: ^ElnaLexerCursor; error_list: ^ElnaList) -> ^ElnaTreeModuleDeclaration +var + result: ^ElnaTreeModuleDeclaration +begin + result := malloc#[ElnaTreeModuleDeclaration](#size(ElnaTreeModuleDeclaration)); + result^.kind := ElnaTreeKind.module_declaration; + result^.position.start_location := ElnaLocation{ line: 1u, column: 1u }; + result^.position.end_location := result^.position.start_location; + + result^.types := elna_parser_type_part(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + end; + + if result <> nil then + result^.globals := elna_parser_var_part(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + end + end; + + if result <> nil then + result^.procedures := elna_parser_procedures(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + end + end; + + if result <> nil then + result^.body := elna_parser_program_body(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + end + end +return result + +end. |
