(* 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, sys.posix.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.