diff options
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/ast.cc | 59 | ||||
| -rw-r--r-- | boot/lexer.ll | 3 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 183 | ||||
| -rw-r--r-- | boot/parser.yy | 53 | ||||
| -rw-r--r-- | boot/type_check.cc | 5 | ||||
| -rw-r--r-- | boot/validation.cc | 9 |
6 files changed, 180 insertions, 132 deletions
diff --git a/boot/ast.cc b/boot/ast.cc index d4f015b..b8647f4 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -232,18 +232,7 @@ namespace elna::boot } if (declaration->body.has_value()) { - for (variable_declaration *variable : declaration->body.value().variables) - { - variable->accept(this); - } - for (auto *statement : declaration->body.value().entry_point) - { - statement->accept(this); - } - if (declaration->body.value().return_expression != nullptr) - { - declaration->body.value().return_expression->accept(this); - } + traverse_body(this, declaration->body.value()); } } @@ -376,9 +365,9 @@ namespace elna::boot { procedure->accept(this); } - for (auto *entry_statement : unit->entry_point) + if (unit->entry_point.has_value()) { - entry_statement->accept(this); + traverse_body(this, unit->entry_point.value()); } } @@ -989,20 +978,20 @@ namespace elna::boot procedure_body::procedure_body(std::vector<variable_declaration *>&& variables, std::vector<statement *>&& entry_point, expression *return_expression) : variables(std::move(variables)), - entry_point(std::move(entry_point)), return_expression(return_expression) + statements(std::move(entry_point)), return_expression(return_expression) { } procedure_body::procedure_body(procedure_body&& that) noexcept : variables(std::move(const_cast<std::vector<variable_declaration *>&>(that.variables))), - entry_point(std::move(const_cast<std::vector<statement *>&>(that.entry_point))), + statements(std::move(const_cast<std::vector<statement *>&>(that.statements))), return_expression(that.return_expression) { } procedure_body::~procedure_body() { - for (const statement *body_statement : this->entry_point) + for (const statement *body_statement : this->statements) { delete body_statement; } @@ -1012,9 +1001,30 @@ namespace elna::boot } } - unit::unit(const source_position position) + void traverse_body(parser_visitor *visitor, const procedure_body& body) + { + for (variable_declaration *variable : body.variables) + { + variable->accept(visitor); + } + for (statement *body_statement : body.statements) + { + body_statement->accept(visitor); + } + if (body.return_expression != nullptr) + { + body.return_expression->accept(visitor); + } + } + + unit::unit(const source_position position, + std::vector<import_declaration *>&& imports, + std::vector<type_declaration *>&& types, + std::vector<variable_declaration *>&& variables, + std::vector<procedure_declaration *>&& procedures) : node(position), - procedure_body(std::vector<variable_declaration *>{}, std::vector<statement *>{}, nullptr) + imports(std::move(imports)), types(std::move(types)), procedures(std::move(procedures)), + variables(std::move(variables)) { } @@ -1023,10 +1033,10 @@ namespace elna::boot std::vector<type_declaration *>&& types, std::vector<variable_declaration *>&& variables, std::vector<procedure_declaration *>&& procedures, - std::vector<statement *>&& entry_point) + std::optional<procedure_body>&& body) : node(position), - procedure_body(std::move(variables), std::move(entry_point)), - imports(std::move(imports)), types(std::move(types)), procedures(std::move(procedures)) + imports(std::move(imports)), types(std::move(types)), procedures(std::move(procedures)), + variables(std::move(variables)), entry_point(std::move(body)) { } @@ -1035,11 +1045,6 @@ namespace elna::boot visitor->visit(this); } - bool unit::has_body() const - { - return !this->entry_point.empty(); - } - unit::~unit() { for (const procedure_declaration *procedure : this->procedures) diff --git a/boot/lexer.ll b/boot/lexer.ll index d0493c1..bebfa67 100644 --- a/boot/lexer.ll +++ b/boot/lexer.ll @@ -171,6 +171,9 @@ of { to { return yy::parser::make_TO(this->location); } +program { + return yy::parser::make_PROGRAM(this->location); +} {ID1}{ID2}* { return yy::parser::make_IDENTIFIER(yytext, this->location); } diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 3c4c6f8..77335d1 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -23,12 +23,12 @@ along with GCC; see the file COPYING3. If not see namespace elna::boot { - declaration_error::declaration_error(const source_position position, const std::string& name, payload_type payload) + symbol_declaration_error::symbol_declaration_error(const source_position position, const std::string& name, payload_type payload) : diagnostic(position), name(name), payload(std::move(payload)) { } - std::string declaration_error::what() const + std::string symbol_declaration_error::what() const { return std::visit([this](const auto& payload) -> std::string { using T = std::decay_t<decltype(payload)>; @@ -57,7 +57,7 @@ namespace elna::boot }, this->payload); } - std::optional<diagnostic_note> declaration_error::note() const + std::optional<diagnostic_note> symbol_declaration_error::note() const { if (std::holds_alternative<redefinition>(this->payload)) { @@ -89,12 +89,12 @@ namespace elna::boot return message + " -> " + this->cycle.front(); } - const_qualifier_error::const_qualifier_error(const source_position position, payload_type payload) + declaration_format_error::declaration_format_error(const source_position position, payload_type payload) : diagnostic(position), payload(std::move(payload)) { } - std::string const_qualifier_error::what() const + std::string declaration_format_error::what() const { return std::visit([](const auto& payload) -> std::string { using T = std::decay_t<decltype(payload)>; @@ -112,6 +112,8 @@ namespace elna::boot return "const must be written before the array size, not after"; case duplicate: return "Duplicate 'const' qualifier is not allowed"; + case module_entry: + return "Program entry point should have no or one argument"; default: __builtin_unreachable(); } @@ -119,7 +121,7 @@ namespace elna::boot }, this->payload); } - std::optional<diagnostic_note> const_qualifier_error::note() const + std::optional<diagnostic_note> declaration_format_error::note() const { if (std::holds_alternative<not_initialized>(this->payload)) { @@ -256,9 +258,9 @@ namespace elna::boot if (!this->unresolved.insert({ type_identifier, std::make_shared<alias_type>(type_identifier) }).second) { - add_error<declaration_error>(declaration->identifier.id().position(), + add_error<symbol_declaration_error>(declaration->identifier.id().position(), declaration->identifier.id().name(), - declaration_error::redefinition{ .original = declaration->position(), .file = {} }); + symbol_declaration_error::redefinition{ .original = declaration->position(), .file = {} }); } } @@ -272,24 +274,28 @@ namespace elna::boot { } - std::pair<procedure_type, std::vector<std::string>> resolving_visitor::build_procedure( - procedure_type_expression& expression) + procedure_type::return_t resolving_visitor::build_return_type( + const procedure_type_expression::return_t& return_type) { - procedure_type::return_t result_return; - - if (expression.return_type.no_return) + if (return_type.no_return) { - result_return = procedure_type::return_t(std::monostate{}); + return procedure_type::return_t(std::monostate{}); } - else if (expression.return_type.proper_type != nullptr) + else if (return_type.proper_type != nullptr) { - expression.return_type.proper_type->accept(this); - result_return = procedure_type::return_t(this->current_type); + return_type.proper_type->accept(this); + return procedure_type::return_t(this->current_type); } else { - result_return = procedure_type::return_t(); + return procedure_type::return_t(); } + } + + std::pair<procedure_type, std::vector<std::string>> resolving_visitor::build_procedure( + procedure_type_expression& expression) + { + const procedure_type::return_t result_return = build_return_type(expression.return_type); std::pair<procedure_type, std::vector<std::string>> result_type{ procedure_type(result_return), std::vector<std::string>() }; @@ -361,9 +367,11 @@ namespace elna::boot if (!this->bag.enter(name, variable_symbol)) { auto original = this->bag.lookup(name); - add_error<declaration_error>(position, name, - declaration_error::redefinition{ .original = original->position, - .file = this->redefinition_file(original) }); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error<symbol_declaration_error>(position, name, original_definition); } return variable_symbol; } @@ -424,8 +432,8 @@ namespace elna::boot { auto position_span = source_position(declaration->identifiers.front().id().position().start(), declaration->identifiers.back().id().position().end()); - add_error<const_qualifier_error>(position_span, - const_qualifier_error::not_initialized{ extract_identifiers(declaration->identifiers) }); + add_error<declaration_format_error>(position_span, + declaration_format_error::not_initialized{ extract_identifiers(declaration->identifiers) }); } for (const identifier_definition& variable_identifier : declaration->identifiers) { @@ -443,8 +451,8 @@ namespace elna::boot if (array_base.get<constant_type>() != nullptr) { - add_error<const_qualifier_error>(expression->position(), - const_qualifier_error::kind::array_position); + add_error<declaration_format_error>(expression->position(), + declaration_format_error::kind::array_position); } expression->dimensions().accept(this); if (expression->dimensions().type_decoration.empty()) @@ -483,8 +491,8 @@ namespace elna::boot expression->base().accept(this); if (this->current_type.get<constant_type>() != nullptr) { - add_error<const_qualifier_error>(expression->position(), - const_qualifier_error::kind::duplicate); + add_error<declaration_format_error>(expression->position(), + declaration_format_error::kind::duplicate); } this->current_type = type(std::make_shared<constant_type>(this->current_type)); } @@ -512,8 +520,8 @@ namespace elna::boot } else { - add_error<declaration_error>(expression->base.value().position(), - expression->base.value().name(), declaration_error::kind::undeclared_type); + add_error<symbol_declaration_error>(expression->base.value().position(), + expression->base.value().name(), symbol_declaration_error::kind::undeclared_type); this->current_type = type(); return; } @@ -698,8 +706,8 @@ namespace elna::boot } else { - add_error<declaration_error>(expression->type_name.position(), - expression->type_name.name(), declaration_error::kind::undeclared_type); + add_error<symbol_declaration_error>(expression->type_name.position(), + expression->type_name.name(), symbol_declaration_error::kind::undeclared_type); } for (const field_initializer& initializer : expression->field_initializers) { @@ -766,8 +774,8 @@ namespace elna::boot } else { - add_error<declaration_error>(trait->name.position(), - trait->name.name(), declaration_error::kind::undeclared_trait); + add_error<symbol_declaration_error>(trait->name.position(), + trait->name.name(), symbol_declaration_error::kind::undeclared_trait); } this->current_type = type(); } @@ -847,8 +855,8 @@ namespace elna::boot } else { - add_error<declaration_error>(expression->position(), - expression->name, declaration_error::kind::undeclared_symbol); + add_error<symbol_declaration_error>(expression->position(), + expression->name, symbol_declaration_error::kind::undeclared_symbol); } } @@ -1112,6 +1120,49 @@ namespace elna::boot { procedure->accept(this); } + if (unit->entry_point.has_value()) + { + auto word8_primitive = lookup_primitive_type("Word8"); + const procedure_type::return_t result_return = procedure_type::return_t(word8_primitive); + auto heading = procedure_type(result_return); + std::shared_ptr<procedure_info> info; + + if (unit->parameters.size() > 1) + { + add_error<declaration_format_error>(unit->position(), + declaration_format_error::kind::module_entry); + } + else if (unit->parameters.size() == 1) + { + auto variable_type = type(std::make_shared<pointer_type>(word8_primitive)); + variable_type = type(std::make_shared<slice_type>(variable_type)); + + heading.parameters.push_back(variable_type); + + info = std::make_shared<procedure_info>(heading, + std::vector<std::string>({ unit->parameters.at(0).name() }), this->bag.enter()); + + register_variable(info->names.at(0), variable_type, unit->parameters.at(0).position()); + } + else + { + info = std::make_shared<procedure_info>(heading, std::vector<std::string>{}, this->bag.enter()); + } + this->bag.leave(); + + info->position.emplace(unit->position()); + info->file = this->module_file; + + if (!this->bag.enter("", info)) + { + auto original = this->bag.lookup(""); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error<symbol_declaration_error>(unit->position(), "program", original_definition); + } + } } void declaration_visitor::visit(type_declaration *declaration) @@ -1138,9 +1189,12 @@ namespace elna::boot if (!this->bag.enter(declaration->identifier.name(), info)) { auto original = this->bag.lookup(declaration->identifier.name()); - add_error<declaration_error>(declaration->identifier.id().position(), declaration->identifier.name(), - declaration_error::redefinition{ .original = original->position, - .file = this->redefinition_file(original) }); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error<symbol_declaration_error>(declaration->identifier.id().position(), + declaration->identifier.name(), original_definition); } } @@ -1159,7 +1213,6 @@ namespace elna::boot { auto variable_symbol = register_variable(*name_iterator, *type_iterator, declaration->heading().position()); - variable_symbol->exported = false; ++name_iterator; ++type_iterator; @@ -1176,9 +1229,12 @@ namespace elna::boot if (!this->bag.enter(declaration->identifier.name(), info)) { auto original = this->bag.lookup(declaration->identifier.name()); - add_error<declaration_error>(declaration->identifier.id().position(), declaration->identifier.name(), - declaration_error::redefinition{ .original = original->position, - .file = this->redefinition_file(original) }); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error<symbol_declaration_error>(declaration->identifier.id().position(), + declaration->identifier.name(), original_definition); } } @@ -1199,25 +1255,12 @@ namespace elna::boot { procedure->accept(this); } - if (unit->has_body()) + if (unit->entry_point.has_value()) { - this->bag.enter(); - auto variable_type = lookup_primitive_type("Int"); - auto count_symbol = std::make_shared<variable_info>(variable_type, false); - count_symbol->file = this->module_file; - this->bag.enter("count", count_symbol); - - variable_type = lookup_primitive_type("Word8"); - variable_type = type(std::make_shared<pointer_type>(variable_type)); - variable_type = type(std::make_shared<pointer_type>(variable_type)); - auto parameters_symbol = std::make_shared<variable_info>(variable_type, false); - parameters_symbol->file = this->module_file; - this->bag.enter("parameters", parameters_symbol); + const std::shared_ptr<procedure_info> info = this->bag.lookup("")->is_procedure(); - for (statement *const statement : unit->entry_point) - { - statement->accept(this); - } + this->bag.enter(info->scope); + traverse_body(this, unit->entry_point.value()); this->bag.leave(); } } @@ -1234,31 +1277,21 @@ namespace elna::boot { if (variable_identifier.exported()) { - add_error<declaration_error>(variable_identifier.id().position(), - variable_identifier.id().name(), declaration_error::kind::local_export); + add_error<symbol_declaration_error>(variable_identifier.id().position(), + variable_identifier.id().name(), symbol_declaration_error::kind::local_export); } } } void name_analysis_visitor::visit(procedure_declaration *declaration) { - const std::shared_ptr<procedure_info> info = this->bag.lookup(declaration->identifier.name())->is_procedure(); - if (declaration->body.has_value()) { + const std::shared_ptr<procedure_info> info = + this->bag.lookup(declaration->identifier.name())->is_procedure(); + this->bag.enter(info->scope); - for (variable_declaration *const variable : declaration->body.value().variables) - { - variable->accept(this); - } - for (statement *const statement : declaration->body.value().entry_point) - { - statement->accept(this); - } - if (declaration->body.value().return_expression != nullptr) - { - declaration->body.value().return_expression->accept(this); - } + traverse_body(this, declaration->body.value()); this->bag.leave(); } } diff --git a/boot/parser.yy b/boot/parser.yy index b53a94c..dc1d4e8 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -93,7 +93,7 @@ along with GCC; see the file COPYING3. If not see EXCLAMATION "!" ARROW "->" AT "@" HAT "^" COLON ":" SEMICOLON ";" DOT "." COMMA "," -%token NOT "~" +%token PROGRAM "program" CAST "cast" NIL "nil" CONST "const" @@ -113,7 +113,7 @@ along with GCC; see the file COPYING3. If not see OF "of" TO "to" PIPE "|" -%token OR "or" AND "&" XOR "xor" +%token NOT "~" OR "or" AND "&" XOR "xor" EQUALS "=" NOT_EQUAL "<>" LESS_THAN "<" GREATER_THAN ">" LESS_EQUAL "<=" GREATER_EQUAL ">=" SHIFT_LEFT "<<" SHIFT_RIGHT ">>" PLUS "+" MINUS "-" @@ -125,7 +125,7 @@ along with GCC; see the file COPYING3. If not see %left "+" "-" %left "*" "/" "%" -%type <elna::boot::literal_expression *> literal; +%type <std::unique_ptr<elna::boot::literal_expression>> literal; %type <std::vector<elna::boot::expression *>> case_labels; %type <elna::boot::switch_case> switch_case; %type <std::vector<elna::boot::switch_case>> switch_cases; @@ -162,9 +162,15 @@ along with GCC; see the file COPYING3. If not see %type <std::unique_ptr<elna::boot::array_type_expression>> array_type_expression; %% program: - import_part type_part variable_part procedure_part statement_part "end" "." + import_part type_part variable_part procedure_part "end" "." { - boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2, $3, $4, $5); + boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2, $3, $4); + driver.tree.reset(tree); + } + | import_part type_part variable_part procedure_part "program" "(" ")" statement_part "end" "." + { + boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2, $3, $4, + boot::procedure_body({}, std::move($8))); driver.tree.reset(tree); } procedure_body: @@ -242,91 +248,94 @@ literal: INTEGER { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed, false); } | INTEGER8 { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | INTEGER16 { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | INTEGER32 { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | INTEGER64 { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | WORD { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed, false); } | WORD8 { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | WORD16 { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | WORD32 { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | WORD64 { auto [magnitude, wants_signed] = $1; - $$ = new boot::literal<boot::integer_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::integer_literal>>(boot::make_position(@$), boot::integer_literal::from(magnitude), wants_signed); } | SINGLE { - $$ = new boot::literal<boot::float_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::float_literal>>(boot::make_position(@$), boot::float_literal::from($1), boot::integer_sign::unmarked); } | DOUBLE { - $$ = new boot::literal<boot::float_literal>(boot::make_position(@$), + $$ = std::make_unique<boot::literal<boot::float_literal>>(boot::make_position(@$), boot::float_literal::from($1), boot::integer_sign::unmarked); } | BOOLEAN { - $$ = new boot::literal<bool>(boot::make_position(@$), $1, boot::integer_sign::_unsigned); + $$ = std::make_unique<boot::literal<bool>>(boot::make_position(@$), $1, boot::integer_sign::_unsigned); } | CHARACTER { - $$ = new boot::literal<std::uint32_t>(boot::make_position(@$), $1, boot::integer_sign::_unsigned); + $$ = std::make_unique<boot::literal<std::uint32_t>>(boot::make_position(@$), + $1, boot::integer_sign::_unsigned); } | "nil" { - $$ = new boot::literal<std::nullptr_t>(boot::make_position(@$), nullptr, boot::integer_sign::_unsigned); + $$ = std::make_unique<boot::literal<std::nullptr_t>>(boot::make_position(@$), + nullptr, boot::integer_sign::_unsigned); } | STRING { - $$ = new boot::literal<std::string>(boot::make_position(@$), $1, boot::integer_sign::_unsigned); + $$ = std::make_unique<boot::literal<std::string>>(boot::make_position(@$), + $1, boot::integer_sign::_unsigned); } simple_expression: - literal { $$ = $1; } + literal { $$ = $1.release(); } | designator_expression { $$ = $1; } | TRAIT "(" type_expressions ")" { diff --git a/boot/type_check.cc b/boot/type_check.cc index fd47998..da60a21 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -691,11 +691,6 @@ namespace elna::boot this->current_procedure.reset(); } - void type_analysis_visitor::visit(unit *unit) - { - walking_visitor::visit(unit); - } - void type_analysis_visitor::visit(assign_statement *statement) { walking_visitor::visit(statement); diff --git a/boot/validation.cc b/boot/validation.cc index b046b4e..91dc064 100644 --- a/boot/validation.cc +++ b/boot/validation.cc @@ -79,9 +79,12 @@ namespace elna::boot { procedure->accept(this); } - for (auto *entry_statement : unit->entry_point) + if (unit->entry_point.has_value()) { - entry_statement->accept(this); + for (auto *entry_statement : unit->entry_point->statements) + { + entry_statement->accept(this); + } } } @@ -91,7 +94,7 @@ namespace elna::boot { auto procedure = this->bag.lookup(declaration->identifier.name())->is_procedure(); this->bag.enter(procedure->scope); - for (auto *statement : declaration->body.value().entry_point) + for (auto *statement : declaration->body.value().statements) { statement->accept(this); } |
