diff options
| -rw-r--r-- | boot/ast.cc | 29 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 3 | ||||
| -rw-r--r-- | boot/type_check.cc | 42 | ||||
| -rw-r--r-- | include/elna/boot/ast.h | 4 | ||||
| -rw-r--r-- | include/elna/boot/type_check.h | 6 | ||||
| -rw-r--r-- | source/elna/lexer.elna | 128 | ||||
| -rw-r--r-- | source/main.elna | 4 | ||||
| -rw-r--r-- | source/sys/posix/stdlib.elna | 3 | ||||
| -rw-r--r-- | source/sys/posix/string.elna | 3 |
9 files changed, 152 insertions, 70 deletions
diff --git a/boot/ast.cc b/boot/ast.cc index 15e4928..e712f16 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -243,7 +243,7 @@ namespace elna::boot } if (declaration->body.has_value()) { - traverse_block(this, declaration->body.value()); + boot::traverse_block(this, declaration->body.value()); if (declaration->body.value().return_expression != nullptr) { declaration->body.value().return_expression->accept(this); @@ -257,54 +257,59 @@ namespace elna::boot statement->rvalue().accept(this); } + void walking_visitor::traverse_block(const block& body) + { + boot::traverse_block(this, body); + } + void walking_visitor::visit(if_statement *statement) { statement->branch().prerequisite().accept(this); - traverse_block(this, statement->branch().body); + traverse_block(statement->branch().body); for (conditional_statements& branch : statement->branches) { branch.prerequisite().accept(this); - traverse_block(this, branch.body); + traverse_block(branch.body); } if (statement->alternative != nullptr) { - traverse_block(this, *statement->alternative); + traverse_block(*statement->alternative); } } void walking_visitor::visit(while_statement *statement) { statement->branch().prerequisite().accept(this); - traverse_block(this, statement->branch().body); + traverse_block(statement->branch().body); for (conditional_statements& branch : statement->branches) { branch.prerequisite().accept(this); - traverse_block(this, branch.body); + traverse_block(branch.body); } } void walking_visitor::visit(repeat_statement *statement) { statement->condition().accept(this); - traverse_block(this, statement->body); + traverse_block(statement->body); } void walking_visitor::visit(for_statement *statement) { statement->range().accept(this); - traverse_block(this, statement->body); + traverse_block(statement->body); } void walking_visitor::visit(defer_statement *statement) { - traverse_block(this, statement->body); + traverse_block(statement->body); } void walking_visitor::visit(block_statement *statement) { - traverse_block(this, statement->body); + traverse_block(statement->body); } void walking_visitor::visit(break_statement *) @@ -321,11 +326,11 @@ namespace elna::boot for (const switch_case& case_block : statement->cases) { visit_all(this, case_block.labels); - traverse_block(this, case_block.body); + traverse_block(case_block.body); } if (statement->alternative != nullptr) { - traverse_block(this, *statement->alternative); + traverse_block(*statement->alternative); } } diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 9305cd2..11380db 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -1628,7 +1628,8 @@ namespace elna::boot this->bag.leave(); info_object->parameters = type_parameters; info_object->exported = declaration->identifier.exported(); - info_object->position.emplace(declaration->position()); + info_object->position.emplace(declaration->position().start(), + declaration->heading().position().end()); info_object->file = this->module_file; info_object->noreturn = noreturn; diff --git a/boot/type_check.cc b/boot/type_check.cc index 5a8170a..5033ffd 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -494,9 +494,8 @@ namespace elna::boot return is_assignable_from(left, right) || is_assignable_from(right, left); } - void type_analysis_visitor::visit_and_validate_condition(expression& condition) + void type_analysis_visitor::validate_condition(const expression& condition) { - condition.accept(this); if (!is_primitive_type(condition.type_decoration, "Bool")) { add_error<type_requirement_error>(condition.position(), @@ -824,7 +823,7 @@ namespace elna::boot void type_analysis_visitor::visit(for_statement *statement) { - statement->range().accept(this); + walking_visitor::visit(statement); const type resolved_range = resolve_underlying_type(statement->range().type_decoration); if (!get_range_base_type(resolved_range)) @@ -832,47 +831,40 @@ namespace elna::boot add_error<type_requirement_error>(statement->range().position(), statement->range().type_decoration, type_requirement_error::kind::for_range); } - traverse_block(statement->body); } - void type_analysis_visitor::traverse_block(block& body) + void type_analysis_visitor::traverse_block(const block& body) { this->bag.enter(body.symbols); - boot::traverse_block(this, body); + walking_visitor::traverse_block(body); this->bag.leave(); } void type_analysis_visitor::visit(repeat_statement *statement) { - visit_and_validate_condition(statement->condition()); - traverse_block(statement->body); + walking_visitor::visit(statement); + validate_condition(statement->condition()); } void type_analysis_visitor::visit(while_statement *statement) { - visit_and_validate_condition(statement->branch().prerequisite()); - traverse_block(statement->branch().body); + walking_visitor::visit(statement); + validate_condition(statement->branch().prerequisite()); for (conditional_statements& branch : statement->branches) { - visit_and_validate_condition(branch.prerequisite()); - traverse_block(branch.body); + validate_condition(branch.prerequisite()); } } void type_analysis_visitor::visit(if_statement *statement) { - visit_and_validate_condition(statement->branch().prerequisite()); - traverse_block(statement->branch().body); + walking_visitor::visit(statement); + validate_condition(statement->branch().prerequisite()); for (conditional_statements& branch : statement->branches) { - visit_and_validate_condition(branch.prerequisite()); - traverse_block(branch.body); - } - if (statement->alternative != nullptr) - { - traverse_block(*statement->alternative); + validate_condition(branch.prerequisite()); } } @@ -1462,16 +1454,6 @@ namespace elna::boot } // else callable is not declared, or inference failed and reported. } - - void type_analysis_visitor::visit(defer_statement *statement) - { - traverse_block(statement->body); - } - - void type_analysis_visitor::visit(block_statement *statement) - { - traverse_block(statement->body); - } void type_analysis_visitor::visit(record_constructor_expression *expression) { diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index c12d8e8..cf381fc 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -322,6 +322,10 @@ namespace elna::boot void visit(literal<bool> *) override; void visit(literal<std::uint32_t> *) override; void visit(literal<std::string> *) override; + + protected: + /// Passes needing the scope of a block override this. + virtual void traverse_block(const block& body); }; /** diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h index 98db843..3774311 100644 --- a/include/elna/boot/type_check.h +++ b/include/elna/boot/type_check.h @@ -276,7 +276,7 @@ namespace elna::boot static bool is_assignable_from(const type& assignee, const type& assignment); static bool is_equality_compatible(const type& left, const type& right); - void visit_and_validate_condition(expression& condition); + void validate_condition(const expression& condition); void check_arguments(const named_expression& reference, const std::vector<type>& arguments, const argument_rule rule); void check_parameters_used(const source_position position, const std::string& name, @@ -292,7 +292,7 @@ namespace elna::boot type promote_variadic_argument(const expression& argument); protected: - void traverse_block(block& body); + void traverse_block(const block& body) override; public: explicit type_analysis_visitor(symbol_bag bag, const target_info& target); @@ -309,8 +309,6 @@ namespace elna::boot void visit(repeat_statement *statement) override; void visit(while_statement *statement) override; void visit(if_statement *statement) override; - void visit(defer_statement *statement) override; - void visit(block_statement *statement) override; void visit(record_constructor_expression *expression) override; void visit(array_constructor_expression *expression) override; void visit(traits_expression *trait) override; diff --git a/source/elna/lexer.elna b/source/elna/lexer.elna index 64fcc22..4de178e 100644 --- a/source/elna/lexer.elna +++ b/source/elna/lexer.elna @@ -139,6 +139,26 @@ type trait, (* Token is complete, the last byte eaten. *) stop, + (* One-character token stop. *) + single, + (* Assignment operator stop. *) + assignment, + (* Arrow stop. *) + arrow, + (* Greater or equal stop. *) + greater_equal, + (* Less or equal stop. *) + less_equal, + (* Unequal stop. *) + not_equal, + (* Right shift stop. *) + shift_right, + (* Left shift stop. *) + shift_left, + (* Opening attribute bracket stop. *) + attribute_open, + (* Opening generic brace stop. *) + generic_open, (* Reject the token with an error. *) reject, (* Sentinel signaling end of input. *) @@ -241,6 +261,9 @@ type kind: ElnaLexerTokenKind; position: ElnaSourceSpan end + ElnaLexerIdentifierToken = record(ElnaLexerToken) + identifier: StdString + end var (* Initializes the array with character classes. *) @@ -554,17 +577,17 @@ begin elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.space, ElnaLexerState.skip); elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.new_line, ElnaLexerState.skip); elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.colon, ElnaLexerState.colon); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.equals, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.equals, ElnaLexerState.single); elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.left_paren, ElnaLexerState.left_paren); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.right_paren, ElnaLexerState.stop); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.asterisk, ElnaLexerState.stop); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.single, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.right_paren, ElnaLexerState.single); + elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.asterisk, ElnaLexerState.single); + elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.single, ElnaLexerState.single); elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.backquote, ElnaLexerState.wide); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.brace, ElnaLexerState.stop); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.square, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.brace, ElnaLexerState.single); + elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.square, ElnaLexerState.single); elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.eof, ElnaLexerState.eof); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.dot, ElnaLexerState.stop); - elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.plus, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.dot, ElnaLexerState.single); + elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.plus, ElnaLexerState.single); elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.minus, ElnaLexerState.minus); elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.single_quote, ElnaLexerState.narrow); elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.double_quote, ElnaLexerState.string); @@ -583,23 +606,23 @@ begin elna_lexer_set_transition(ElnaLexerState.skip, ElnaLexerClass.new_line, ElnaLexerState.skip); -- Colon state. - elna_lexer_set_transition(ElnaLexerState.colon, ElnaLexerClass.equals, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.colon, ElnaLexerClass.equals, ElnaLexerState.assignment); -- Left paren state. elna_lexer_set_transition(ElnaLexerState.left_paren, ElnaLexerClass.asterisk, ElnaLexerState.docblock); -- Minus state. - elna_lexer_set_transition(ElnaLexerState.minus, ElnaLexerClass.greater, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.minus, ElnaLexerClass.greater, ElnaLexerState.arrow); elna_lexer_set_transition(ElnaLexerState.minus, ElnaLexerClass.minus, ElnaLexerState.comment); -- Greater state. - elna_lexer_set_transition(ElnaLexerState.greater, ElnaLexerClass.greater, ElnaLexerState.stop); - elna_lexer_set_transition(ElnaLexerState.greater, ElnaLexerClass.equals, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.greater, ElnaLexerClass.greater, ElnaLexerState.shift_right); + elna_lexer_set_transition(ElnaLexerState.greater, ElnaLexerClass.equals, ElnaLexerState.greater_equal); -- Less state. - elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.less, ElnaLexerState.stop); - elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.equals, ElnaLexerState.stop); - elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.greater, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.less, ElnaLexerState.shift_left); + elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.equals, ElnaLexerState.less_equal); + elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.greater, ElnaLexerState.not_equal); -- Numbers prefixed by 0 followed by a character (0b, 0x). elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.zero, ElnaLexerState.integer); @@ -666,8 +689,8 @@ begin -- Attribute, generic parameter or trait marker ('#'). elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.exponent, ElnaLexerState.trait); elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.alpha, ElnaLexerState.trait); - elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.square, ElnaLexerState.stop); - elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.brace, ElnaLexerState.stop); + elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.square, ElnaLexerState.generic_open); + elna_lexer_set_transition(ElnaLexerState.number_sign, ElnaLexerClass.brace, ElnaLexerState.attribute_open); -- Trait identifier. elna_lexer_set_transition(ElnaLexerState.trait, ElnaLexerClass.exponent, ElnaLexerState.trait); @@ -751,16 +774,32 @@ proc elna_lexer_skip_trivia(cursor: ^ElnaLexerCursor) until cursor^.state <> ElnaLexerState.skip return +(* + Creates a token of the given kind. The created token is a simple token without + any payload. +*) proc elna_lexer_token_create(kind: ElnaLexerTokenKind) -> ^ElnaLexerToken var result: ^ElnaLexerToken begin result := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - memset(result, 0i8, #size(ElnaLexerToken)); result^.kind := kind return result --- TODO: Identifier (else) should save a payload with the identifier. +(* + Frees the memory allocated for the token itself and for its internal storage. +*) +proc elna_lexer_token_destroy*(token: ^ElnaLexerToken) + if token^.kind = ElnaLexerTokenKind.identifier then + var + identifier_token := cast(token: ^ElnaLexerIdentifierToken) + begin + free(identifier_token^.identifier.ptr) + end; + + free(token) +return + proc elna_lexer_identify_keyword(start, cursor: ^const Word8) -> ^ElnaLexerToken var result: ^ElnaLexerToken @@ -804,7 +843,43 @@ begin "program": result := elna_lexer_token_create(ElnaLexerTokenKind.program_) | "module": result := elna_lexer_token_create(ElnaLexerTokenKind.module_) else - result := elna_lexer_token_create(ElnaLexerTokenKind.identifier) + var + identifier_token := malloc#[ElnaLexerIdentifierToken](#size(ElnaLexerToken)) + identifier_pointer := malloc#[const Word8](identifier.length) + begin + memcpy(identifier_pointer, identifier.ptr, identifier.length); + + identifier_token^.kind := ElnaLexerTokenKind.identifier; + identifier_token^.identifier := identifier_pointer[1 to identifier.length];; + result := identifier_token + end +return result + +proc elna_lexer_stop_single(start: ^const Word8) -> ^ElnaLexerToken +var + result: ^ElnaLexerToken +begin + case start^ of + '&': result := elna_lexer_token_create(ElnaLexerTokenKind.and) | + '|': result := elna_lexer_token_create(ElnaLexerTokenKind.pipe) | + '~': result := elna_lexer_token_create(ElnaLexerTokenKind.not) | + '/': result := elna_lexer_token_create(ElnaLexerTokenKind.division) | + ')': result := elna_lexer_token_create(ElnaLexerTokenKind.right_paren) | + '[': result := elna_lexer_token_create(ElnaLexerTokenKind.left_square) | + ']': result := elna_lexer_token_create(ElnaLexerTokenKind.right_square) | + '{': result := elna_lexer_token_create(ElnaLexerTokenKind.left_brace) | + '}': result := elna_lexer_token_create(ElnaLexerTokenKind.right_brace) | + '=': result := elna_lexer_token_create(ElnaLexerTokenKind.equals) | + ';': result := elna_lexer_token_create(ElnaLexerTokenKind.semicolon) | + '.': result := elna_lexer_token_create(ElnaLexerTokenKind.dot) | + ',': result := elna_lexer_token_create(ElnaLexerTokenKind.comma) | + '+': result := elna_lexer_token_create(ElnaLexerTokenKind.plus) | + '*': result := elna_lexer_token_create(ElnaLexerTokenKind.multiplication) | + '%': result := elna_lexer_token_create(ElnaLexerTokenKind.remainder) | + '^': result := elna_lexer_token_create(ElnaLexerTokenKind.hat) | + '@': result := elna_lexer_token_create(ElnaLexerTokenKind.at) + else + assert(false) end return result @@ -816,12 +891,21 @@ begin elna_lexer_skip_trivia(cursor); case cursor^.state of - ElnaLexerState.identifier: result := elna_lexer_identify_keyword(cursor^.start, cursor^.cursor) + ElnaLexerState.identifier: result := elna_lexer_identify_keyword(cursor^.start, cursor^.cursor) | + ElnaLexerState.single: result := elna_lexer_stop_single(cursor^.start) | + ElnaLexerState.attribute_open: result := elna_lexer_token_create(ElnaLexerTokenKind.attribute_open) | + ElnaLexerState.generic_open: result := elna_lexer_token_create(ElnaLexerTokenKind.generic_open) | + ElnaLexerState.shift_left: result := elna_lexer_token_create(ElnaLexerTokenKind.shift_left) | + ElnaLexerState.shift_right: result := elna_lexer_token_create(ElnaLexerTokenKind.shift_right) | + ElnaLexerState.greater_equal: result := elna_lexer_token_create(ElnaLexerTokenKind.greater_equal) | + ElnaLexerState.less_equal: result := elna_lexer_token_create(ElnaLexerTokenKind.less_equal) | + ElnaLexerState.not_equal: result := elna_lexer_token_create(ElnaLexerTokenKind.not_equal) | + ElnaLexerState.assignment: result := elna_lexer_token_create(ElnaLexerTokenKind.assignment) | + ElnaLexerState.arrow: result := elna_lexer_token_create(ElnaLexerTokenKind.arrow) else result := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); memset(result, 0i8, #size(ElnaLexerToken)) end - return result end. diff --git a/source/main.elna b/source/main.elna index ee4079e..fb58766 100644 --- a/source/main.elna +++ b/source/main.elna @@ -23,6 +23,8 @@ begin printf("Token: %.*s, length: %lu, final state: %i, position: %lu, kind: %i\n\0".ptr, global_cursor.cursor - global_cursor.start, global_cursor.start, global_cursor.cursor - global_cursor.start, global_cursor.state, - global_cursor.position, token^.kind) + global_cursor.position, token^.kind); + + elna_lexer_token_destroy(token) until global_cursor.state = ElnaLexerState.eof end. diff --git a/source/sys/posix/stdlib.elna b/source/sys/posix/stdlib.elna index 0016d9c..66b383a 100644 --- a/source/sys/posix/stdlib.elna +++ b/source/sys/posix/stdlib.elna @@ -6,4 +6,7 @@ module proc malloc#[T]*(size: Word) -> ^T extern +proc free#[T]*(ptr: ^T) +extern + end. diff --git a/source/sys/posix/string.elna b/source/sys/posix/string.elna index 9994679..b699606 100644 --- a/source/sys/posix/string.elna +++ b/source/sys/posix/string.elna @@ -6,4 +6,7 @@ module proc memset#[T]*(b: ^T; c: Int8; len: Word) -> ^T extern +proc memcpy#[T]*(dst: ^T; src: ^const T; n: Word) -> ^T +extern + end. |
