diff options
| -rw-r--r-- | boot/ast.cc | 426 | ||||
| -rw-r--r-- | boot/parser.yy | 25 | ||||
| -rw-r--r-- | boot/semantic.cc | 279 | ||||
| -rw-r--r-- | boot/symbol.cc | 17 | ||||
| -rw-r--r-- | gcc/gcc/elna-generic.cc | 42 | ||||
| -rw-r--r-- | include/elna/boot/ast.h | 107 | ||||
| -rw-r--r-- | include/elna/boot/semantic.h | 62 | ||||
| -rw-r--r-- | include/elna/boot/symbol.h | 11 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 4 |
9 files changed, 559 insertions, 414 deletions
diff --git a/boot/ast.cc b/boot/ast.cc index b6ce4b3..4270a3b 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -24,11 +24,6 @@ namespace elna::boot __builtin_unreachable(); } - void empty_visitor::visit(type_expression *) - { - not_implemented(); - } - void empty_visitor::visit(array_type_expression *) { not_implemented(); @@ -204,6 +199,300 @@ namespace elna::boot not_implemented(); } + void walking_visitor::visit(import_declaration *) + { + } + + void walking_visitor::visit(procedure_declaration *declaration) + { + for (const field_declaration& parameter : declaration->heading().parameters) + { + parameter.second->accept(this); + } + if (declaration->heading().return_type.proper_type != nullptr) + { + declaration->heading().return_type.proper_type->accept(this); + } + if (declaration->body.has_value()) + { + for (constant_declaration *const constant : declaration->body.value().constants()) + { + constant->accept(this); + } + for (variable_declaration *const variable : declaration->body.value().variables()) + { + variable->accept(this); + } + for (statement *const statement : declaration->body.value().statements()) + { + statement->accept(this); + } + } + } + + void walking_visitor::visit(assign_statement *statement) + { + statement->lvalue().accept(this); + statement->rvalue().accept(this); + } + + void walking_visitor::visit(if_statement *statement) + { + statement->branch().prerequisite().accept(this); + for (struct statement *const branch_statement : statement->branch().statements) + { + branch_statement->accept(this); + } + for (conditional_statements *const branch : statement->branches) + { + branch->prerequisite().accept(this); + + for (struct statement *const branch_statement : branch->statements) + { + branch_statement->accept(this); + } + } + if (statement->alternative != nullptr) + { + for (struct statement *const branch_statement : *statement->alternative) + { + branch_statement->accept(this); + } + } + } + + void walking_visitor::visit(while_statement *statement) + { + statement->branch().prerequisite().accept(this); + for (struct statement *const branch_statement : statement->branch().statements) + { + branch_statement->accept(this); + } + for (conditional_statements *const branch : statement->branches) + { + branch->prerequisite().accept(this); + + for (struct statement *const branch_statement : branch->statements) + { + branch_statement->accept(this); + } + } + } + + void walking_visitor::visit(return_statement *statement) + { + statement->return_expression().accept(this); + } + + void walking_visitor::visit(defer_statement *statement) + { + for (struct statement *const block_statement : statement->statements) + { + block_statement->accept(this); + } + } + + void walking_visitor::visit(empty_statement *) + { + } + + void walking_visitor::visit(case_statement *statement) + { + statement->condition().accept(this); + for (const switch_case& case_block : statement->cases) + { + for (expression *const case_label : case_block.labels) + { + case_label->accept(this); + } + for (struct statement *const block_statement : case_block.statements) + { + block_statement->accept(this); + } + } + if (statement->alternative != nullptr) + { + for (struct statement *const block_statement : *statement->alternative) + { + block_statement->accept(this); + } + } + } + + void walking_visitor::visit(procedure_call *call) + { + call->callable().accept(this); + for (expression *const argument : call->arguments) + { + argument->accept(this); + } + } + + void walking_visitor::visit(unit *unit) + { + for (import_declaration *const _import : unit->imports) + { + _import->accept(this); + } + for (type_declaration *const type : unit->types) + { + type->accept(this); + } + for (variable_declaration *const variable : unit->variables) + { + variable->accept(this); + } + for (constant_declaration *const constant : unit->constants) + { + constant->accept(this); + } + for (procedure_declaration *const procedure : unit->procedures) + { + procedure->accept(this); + } + if (unit->entry_point.has_value()) + { + for (statement *const entry_statement : unit->entry_point.value()) + { + entry_statement->accept(this); + } + } + } + + void walking_visitor::visit(type_declaration *declaration) + { + declaration->underlying_type().accept(this); + } + + void walking_visitor::visit(variable_declaration *declaration) + { + declaration->variable_type().accept(this); + if (declaration->initializer != nullptr) + { + declaration->initializer->accept(this); + } + } + + void walking_visitor::visit(constant_declaration *declaration) + { + declaration->initializer().accept(this); + } + + void walking_visitor::visit(array_type_expression *expression) + { + expression->base().accept(this); + } + + void walking_visitor::visit(pointer_type_expression *expression) + { + expression->base().accept(this); + } + + void walking_visitor::visit(record_type_expression *expression) + { + for (const field_declaration& field : expression->fields) + { + field.second->accept(this); + } + } + + void walking_visitor::visit(union_type_expression *expression) + { + for (const field_declaration& field : expression->fields) + { + field.second->accept(this); + } + } + + void walking_visitor::visit(procedure_type_expression *expression) + { + for (const field_declaration& field : expression->parameters) + { + field.second->accept(this); + } + if (expression->return_type.proper_type != nullptr) + { + expression->return_type.proper_type->accept(this); + } + } + + void walking_visitor::visit(enumeration_type_expression *) + { + } + + void walking_visitor::visit(cast_expression *expression) + { + expression->value().accept(this); + expression->target().accept(this); + } + + void walking_visitor::visit(traits_expression *trait) + { + if (!trait->parameters.empty()) + { + trait->parameters.front()->accept(this); + } + } + + void walking_visitor::visit(binary_expression *expression) + { + expression->lhs().accept(this); + expression->rhs().accept(this); + } + + void walking_visitor::visit(unary_expression *expression) + { + expression->operand().accept(this); + } + + void walking_visitor::visit(named_expression *) + { + } + + void walking_visitor::visit(array_access_expression *expression) + { + expression->base().accept(this); + expression->index().accept(this); + } + + void walking_visitor::visit(field_access_expression *expression) + { + expression->base().accept(this); + } + + void walking_visitor::visit(dereference_expression *expression) + { + expression->base().accept(this); + } + + void walking_visitor::visit(literal<std::int32_t> *) + { + } + + void walking_visitor::visit(literal<std::uint32_t> *) + { + } + + void walking_visitor::visit(literal<double> *) + { + } + + void walking_visitor::visit(literal<bool> *) + { + } + + void walking_visitor::visit(literal<unsigned char> *) + { + } + + void walking_visitor::visit(literal<std::nullptr_t> *) + { + } + + void walking_visitor::visit(literal<std::string> *) + { + } + node::node(const struct position position) : source_position(position) { @@ -288,43 +577,6 @@ namespace elna::boot return nullptr; } - void type_expression::accept(parser_visitor *visitor) - { - if (named_expression *node = is_named()) - { - return visitor->visit(node); - } - else if (array_type_expression *node = is_array()) - { - return visitor->visit(node); - } - else if (pointer_type_expression *node = is_pointer()) - { - return visitor->visit(node); - } - else if (record_type_expression *node = is_record()) - { - return visitor->visit(node); - } - else if (union_type_expression *node = is_union()) - { - return visitor->visit(node); - } - else if (procedure_type_expression *node = is_procedure()) - { - return visitor->visit(node); - } - else if (enumeration_type_expression *node = is_enumeration()) - { - return visitor->visit(node); - } - __builtin_unreachable(); - } - - type_expression::~type_expression() - { - } - array_type_expression::array_type_expression(const struct position position, type_expression *base, const std::uint32_t size) : node(position), m_base(base), size(size) @@ -417,8 +669,8 @@ namespace elna::boot variable_declaration::variable_declaration(const struct position position, std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type, - expression *body) - : node(position), m_variable_type(variable_type), identifiers(std::move(identifier)), body(body) + expression *initializer) + : node(position), m_variable_type(variable_type), identifiers(std::move(identifier)), initializer(initializer) { } @@ -436,7 +688,7 @@ namespace elna::boot bool variable_declaration::has_initializer() const { - return this->is_extern || this->body != nullptr; + return this->is_extern || this->initializer != nullptr; } type_expression& variable_declaration::variable_type() @@ -450,8 +702,8 @@ namespace elna::boot } constant_declaration::constant_declaration(const struct position position, identifier_definition identifier, - expression *body) - : declaration(position, identifier), m_body(body) + expression *initializer) + : declaration(position, identifier), m_initializer(initializer) { } @@ -460,14 +712,14 @@ namespace elna::boot visitor->visit(this); } - expression& constant_declaration::body() + expression& constant_declaration::initializer() { - return *m_body; + return *m_initializer; } constant_declaration::~constant_declaration() { - delete m_body; + delete m_initializer; } procedure_type_expression::procedure_type_expression(const struct position position, @@ -511,8 +763,9 @@ namespace elna::boot } procedure_declaration::procedure_declaration(const struct position position, identifier_definition identifier, - procedure_type_expression *heading, block&& body) - : declaration(position, identifier), m_heading(heading), body(std::make_optional<block>(std::move(body))) + procedure_type_expression *heading, procedure_body&& body) + : declaration(position, identifier), m_heading(heading), + body(std::make_optional<procedure_body>(std::move(body))) { } @@ -538,14 +791,14 @@ namespace elna::boot } type_declaration::type_declaration(const struct position position, identifier_definition identifier, - type_expression *body) - : declaration(position, identifier), m_body(body) + type_expression *underlying_type) + : declaration(position, identifier), m_underlying_type(underlying_type) { } type_declaration::~type_declaration() { - delete m_body; + delete m_underlying_type; } void type_declaration::accept(parser_visitor *visitor) @@ -553,55 +806,56 @@ namespace elna::boot visitor->visit(this); } - type_expression& type_declaration::body() + type_expression& type_declaration::underlying_type() { - return *m_body; + return *m_underlying_type; } - block::block(std::vector<constant_declaration *>&& constants, std::vector<variable_declaration *>&& variables, - std::vector<statement *>&& body) - : m_variables(std::move(variables)), m_constants(std::move(constants)), m_body(std::move(body)) + procedure_body::procedure_body(std::vector<constant_declaration *>&& constants, + std::vector<variable_declaration *>&& variables, std::vector<statement *>&& statements) + : m_variables(std::move(variables)), m_constants(std::move(constants)), m_statements(std::move(statements)) { } - block::block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables) - : m_variables(std::move(variables)), m_constants(std::move(constants)) + procedure_body::procedure_body(std::vector<constant_declaration*>&& constants, + std::vector<variable_declaration *>&& variables) + : procedure_body(std::move(constants), std::move(variables), std::vector<statement *>{}) { } - block::block(block&& that) + procedure_body::procedure_body(procedure_body&& that) : m_variables(std::move(that.m_variables)), m_constants(std::move(that.m_constants)), - m_body(std::move(that.m_body)) + m_statements(std::move(that.m_statements)) { } - block& block::operator=(block&& that) + procedure_body& procedure_body::operator=(procedure_body&& that) { std::swap(m_variables, that.m_variables); std::swap(m_constants, that.m_constants); - std::swap(m_body, that.m_body); + std::swap(m_statements, that.m_statements); return *this; } - const std::vector<variable_declaration *>& block::variables() + const std::vector<variable_declaration *>& procedure_body::variables() { return m_variables; } - const std::vector<constant_declaration *>& block::constants() + const std::vector<constant_declaration *>& procedure_body::constants() { return m_constants; } - const std::vector<statement *>& block::body() + const std::vector<statement *>& procedure_body::statements() { - return m_body; + return m_statements; } - block::~block() + procedure_body::~procedure_body() { - for (statement *body_statement : this->body()) + for (statement *body_statement : this->statements()) { delete body_statement; } @@ -620,8 +874,8 @@ namespace elna::boot { } - unit::unit(const struct position position, std::vector<statement *>&& body) - : node(position), body(std::make_optional<std::vector<statement *>>(std::move(body))) + unit::unit(const struct position position, std::vector<statement *>&& entry_point) + : node(position), entry_point(std::make_optional<std::vector<statement *>>(std::move(entry_point))) { } @@ -1073,10 +1327,10 @@ namespace elna::boot delete m_rvalue; } - if_statement::if_statement(const struct position position, conditional_statements *body, + if_statement::if_statement(const struct position position, conditional_statements *branch, std::vector<conditional_statements *>&& branches, std::vector<statement *> *alternative) - : node(position), m_body(body), branches(std::move(branches)), alternative(alternative) + : node(position), m_branch(branch), branches(std::move(branches)), alternative(alternative) { } @@ -1085,15 +1339,15 @@ namespace elna::boot visitor->visit(this); } - conditional_statements& if_statement::body() + conditional_statements& if_statement::branch() { - return *m_body; + return *m_branch; } if_statement::~if_statement() { - delete m_body; - for (const auto branch : branches) + delete m_branch; + for (conditional_statements *const branch : branches) { delete branch; } @@ -1110,9 +1364,9 @@ namespace elna::boot visitor->visit(this); } - while_statement::while_statement(const struct position position, conditional_statements *body, + while_statement::while_statement(const struct position position, conditional_statements *branch, std::vector<conditional_statements *>&& branches) - : node(position), m_body(body), branches(std::move(branches)) + : node(position), m_branch(branch), branches(std::move(branches)) { } @@ -1121,15 +1375,15 @@ namespace elna::boot visitor->visit(this); } - conditional_statements& while_statement::body() + conditional_statements& while_statement::branch() { - return *m_body; + return *m_branch; } while_statement::~while_statement() { - delete m_body; - for (const auto branch : branches) + delete m_branch; + for (conditional_statements *const branch : branches) { delete branch; } diff --git a/boot/parser.yy b/boot/parser.yy index 42840ff..6ada702 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -148,7 +148,7 @@ along with GCC; see the file COPYING3. If not see %type <std::vector<elna::boot::procedure_declaration *>> procedure_part; %type <elna::boot::type_declaration *> type_declaration; %type <std::vector<elna::boot::type_declaration *>> type_declarations type_part; -%type <std::unique_ptr<elna::boot::block>> block; +%type <std::unique_ptr<elna::boot::procedure_body>> procedure_body; %type <elna::boot::field_declaration> field_declaration; %type <std::vector<elna::boot::field_declaration>> optional_fields required_fields; %type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements; @@ -162,32 +162,33 @@ along with GCC; see the file COPYING3. If not see program: import_part constant_part type_part variable_part procedure_part statement_part "end" "." { + boot::unit *tree; if ($6) { - boot::unit *tree = new boot::unit(boot::make_position(@1)); - tree->body = std::make_optional<std::vector<boot::statement *>>(std::move(*$6.release())); - - driver.tree.reset(tree); + tree = new boot::unit(boot::make_position(@1), + std::move(*$6.release())); } else { - driver.tree.reset(new boot::unit(boot::make_position(@1))); + tree = new boot::unit(boot::make_position(@1)); } + driver.tree.reset(tree); + std::swap(driver.tree->imports, $1); std::swap(driver.tree->constants, $2); std::swap(driver.tree->types , $3); std::swap(driver.tree->variables, $4); std::swap(driver.tree->procedures, $5); } -block: constant_part variable_part statement_part "end" +procedure_body: constant_part variable_part statement_part "end" { if ($3) { - $$ = std::make_unique<boot::block>(std::move($1), std::move($2), std::move(*$3.release())); + $$ = std::make_unique<boot::procedure_body>(std::move($1), std::move($2), std::move(*$3.release())); } else { - $$ = std::make_unique<boot::block>(std::move($1), std::move($2)); + $$ = std::make_unique<boot::procedure_body>(std::move($1), std::move($2)); } } statement_part: @@ -221,7 +222,7 @@ procedure_heading: "(" optional_fields ")" return_declaration $$ = new boot::procedure_type_expression(boot::make_position(@1), std::move($2), std::move($4)); } procedure_declaration: - "proc" identifier_definition procedure_heading block + "proc" identifier_definition procedure_heading procedure_body { $$ = new boot::procedure_declaration(boot::make_position(@1), std::move($2), $3, std::move(*$4)); @@ -251,7 +252,7 @@ elsif_do_statements: std::swap($5, $$); $$.emplace($$.begin(), branch); } - | {} + | /* no branches */ {} else_statements: "else" statements { $$ = new std::vector<boot::statement *>(std::move($2)); } | { $$ = nullptr; } @@ -262,7 +263,7 @@ elsif_then_statements: std::swap($5, $$); $$.emplace($$.begin(), branch); } - | {} + | /* no branches */ {} return_statement: "return" expression { $$ = new boot::return_statement(boot::make_position(@1), $2); } literal: diff --git a/boot/semantic.cc b/boot/semantic.cc index 0530448..42b7b3c 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -96,54 +96,26 @@ namespace elna::boot { } - void type_analysis_visitor::visit(procedure_declaration *definition) + void type_analysis_visitor::visit(procedure_declaration *declaration) { - if (definition->body.has_value() && definition->heading().return_type.proper_type != nullptr) + this->returns = false; + walking_visitor::visit(declaration); + + if (declaration->body.has_value()) { - for (statement *const statement : definition->body.value().body()) + if (!this->returns && declaration->heading().return_type.proper_type != nullptr) { - statement->accept(this); - } - if (!this->returns) - { - add_error<return_error>(definition->identifier.name, definition->position()); + add_error<return_error>(declaration->identifier.name, declaration->position()); } } } - void type_analysis_visitor::visit(assign_statement *) - { - } - - void type_analysis_visitor::visit(if_statement *) - { - } - - void type_analysis_visitor::visit(while_statement *) - { - } - - void type_analysis_visitor::visit(return_statement *) + void type_analysis_visitor::visit(return_statement *statement) { + walking_visitor::visit(statement); this->returns = true; } - void type_analysis_visitor::visit(defer_statement *) - { - } - - void type_analysis_visitor::visit(empty_statement *) - { - } - - void type_analysis_visitor::visit(case_statement *) - { - } - - void type_analysis_visitor::visit(procedure_call *) - { - } - bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr<alias_type> alias, std::vector<std::string>& alias_path) { @@ -160,28 +132,32 @@ namespace elna::boot return true; } - void type_analysis_visitor::visit(unit *unit) + void type_analysis_visitor::visit(type_declaration *declaration) { - for (type_declaration *const type : unit->types) + std::vector<std::string> alias_path; + auto unresolved_type = this->bag.lookup(declaration->identifier.name)->is_type()->symbol.get<alias_type>(); + + if (!check_unresolved_symbol(unresolved_type, alias_path)) { - type->accept(this); + add_error<cyclic_declaration_error>(alias_path, declaration->position()); } - for (procedure_declaration *const procedure : unit->procedures) + else { - this->returns = false; - procedure->accept(this); + walking_visitor::visit(declaration); } } - void type_analysis_visitor::visit(type_declaration *definition) + void type_analysis_visitor::visit(record_type_expression *expression) { - std::vector<std::string> alias_path; - auto unresolved_type = this->bag.lookup(definition->identifier.name)->is_type()->symbol.get<alias_type>(); - - if (!check_unresolved_symbol(unresolved_type, alias_path)) + if (expression->base.has_value()) { - add_error<cyclic_declaration_error>(alias_path, definition->position()); + type base_type = inner_aliased_type(this->bag.lookup(expression->base.value())->is_type()->symbol); + if (base_type.get<record_type>() == nullptr) + { + add_error<base_type_error>(expression->base.value(), expression->position()); + } } + walking_visitor::visit(expression); } name_analysis_visitor::name_analysis_visitor(symbol_bag bag) @@ -222,29 +198,25 @@ namespace elna::boot return result_type; } - void name_analysis_visitor::visit(type_declaration *definition) + void name_analysis_visitor::visit(type_declaration *declaration) { - definition->body().accept(this); - auto resolved = this->bag.resolve(definition->identifier.name, this->current_type); + walking_visitor::visit(declaration); + auto resolved = this->bag.resolve(declaration->identifier.name, this->current_type); auto info = std::make_shared<type_info>(type(resolved)); - info->exported = definition->identifier.exported; - this->bag.enter(definition->identifier.name, info); - } - - void name_analysis_visitor::visit(type_expression *) - { + info->exported = declaration->identifier.exported; + this->bag.enter(declaration->identifier.name, info); } void name_analysis_visitor::visit(pointer_type_expression *expression) { - expression->base().accept(this); + walking_visitor::visit(expression); this->current_type = type(std::make_shared<pointer_type>(this->current_type)); } void name_analysis_visitor::visit(array_type_expression *expression) { - expression->base().accept(this); + walking_visitor::visit(expression); auto result_type = std::make_shared<array_type>(this->current_type, expression->size); this->current_type = type(result_type); @@ -350,9 +322,9 @@ namespace elna::boot void name_analysis_visitor::visit(variable_declaration *declaration) { - declaration->variable_type().accept(this); + walking_visitor::visit(declaration); - for (const auto& variable_identifier : declaration->identifiers) + for (const identifier_definition& variable_identifier : declaration->identifiers) { auto variable_symbol = register_variable(variable_identifier.name, declaration->is_extern, declaration->position()); @@ -360,21 +332,21 @@ namespace elna::boot } } - void name_analysis_visitor::visit(constant_declaration *definition) + void name_analysis_visitor::visit(constant_declaration *declaration) { - definition->body().accept(this); + walking_visitor::visit(declaration); auto constant_symbol = std::make_shared<constant_info>(this->current_literal); - constant_symbol->exported = definition->identifier.exported; - this->bag.enter(definition->identifier.name, constant_symbol); + constant_symbol->exported = declaration->identifier.exported; + this->bag.enter(declaration->identifier.name, constant_symbol); } - void name_analysis_visitor::visit(procedure_declaration *definition) + void name_analysis_visitor::visit(procedure_declaration *declaration) { std::shared_ptr<procedure_info> info; - auto [heading, parameter_names] = build_procedure(definition->heading()); + auto [heading, parameter_names] = build_procedure(declaration->heading()); - if (definition->body.has_value()) + if (declaration->body.has_value()) { info = std::make_shared<procedure_info>(heading, std::move(parameter_names), this->bag.enter()); auto name_iterator = std::cbegin(info->names); @@ -383,21 +355,21 @@ namespace elna::boot while (name_iterator != std::cend(info->names) && type_iterator != std::cend(heading.parameters)) { this->current_type = *type_iterator; - auto variable_symbol = register_variable(*name_iterator, false, definition->heading().position()); + auto variable_symbol = register_variable(*name_iterator, false, declaration->heading().position()); variable_symbol->exported = false; ++name_iterator; ++type_iterator; } - for (constant_declaration *const constant : definition->body.value().constants()) + for (constant_declaration *const constant : declaration->body.value().constants()) { constant->accept(this); } - for (variable_declaration *const variable : definition->body.value().variables()) + for (variable_declaration *const variable : declaration->body.value().variables()) { variable->accept(this); } - for (statement *const statement : definition->body.value().body()) + for (statement *const statement : declaration->body.value().statements()) { statement->accept(this); } @@ -407,101 +379,8 @@ namespace elna::boot { info = std::make_shared<procedure_info>(heading, std::move(parameter_names)); } - info->exported = definition->identifier.exported; - this->bag.enter(definition->identifier.name, info); - } - - void name_analysis_visitor::visit(assign_statement *statement) - { - statement->lvalue().accept(this); - statement->rvalue().accept(this); - } - - void name_analysis_visitor::visit(if_statement *statement) - { - statement->body().prerequisite().accept(this); - for (struct statement *const statement : statement->body().statements) - { - statement->accept(this); - } - for (const auto branch : statement->branches) - { - branch->prerequisite().accept(this); - - for (struct statement *const statement : branch->statements) - { - statement->accept(this); - } - } - if (statement->alternative != nullptr) - { - for (struct statement *const statement : *statement->alternative) - { - statement->accept(this); - } - } - } - - void name_analysis_visitor::visit(import_declaration *) - { - } - - void name_analysis_visitor::visit(while_statement *statement) - { - statement->body().prerequisite().accept(this); - for (struct statement *const statement : statement->body().statements) - { - statement->accept(this); - } - for (const auto branch : statement->branches) - { - branch->prerequisite().accept(this); - - for (struct statement *const statement : branch->statements) - { - statement->accept(this); - } - } - } - - void name_analysis_visitor::visit(return_statement *statement) - { - statement->return_expression().accept(this); - } - - void name_analysis_visitor::visit(defer_statement *statement) - { - for (struct statement *const statement : statement->statements) - { - statement->accept(this); - } - } - - void name_analysis_visitor::visit(empty_statement *) - { - } - - void name_analysis_visitor::visit(case_statement *statement) - { - statement->condition().accept(this); - for (const switch_case& case_block : statement->cases) - { - for (expression *const case_label : case_block.labels) - { - case_label->accept(this); - } - for (struct statement *const statement : case_block.statements) - { - statement->accept(this); - } - } - if (statement->alternative != nullptr) - { - for (struct statement *const statement : *statement->alternative) - { - statement->accept(this); - } - } + info->exported = declaration->identifier.exported; + this->bag.enter(declaration->identifier.name, info); } void name_analysis_visitor::visit(procedure_call *call) @@ -536,7 +415,7 @@ namespace elna::boot { procedure->accept(this); } - if (unit->body.has_value()) + if (unit->entry_point.has_value()) { this->bag.enter(); auto variable_type = this->bag.lookup("Int")->is_type()->symbol; @@ -547,7 +426,7 @@ namespace elna::boot variable_type = type(std::make_shared<pointer_type>(variable_type)); this->bag.enter("parameters", std::make_shared<variable_info>(variable_type, false)); - for (statement *const statement : unit->body.value()) + for (statement *const statement : unit->entry_point.value()) { statement->accept(this); } @@ -566,22 +445,10 @@ namespace elna::boot void name_analysis_visitor::visit(cast_expression *expression) { - expression->value().accept(this); - expression->target().accept(this); + walking_visitor::visit(expression); expression->expression_type = this->current_type; } - void name_analysis_visitor::visit(binary_expression *expression) - { - expression->lhs().accept(this); - expression->rhs().accept(this); - } - - void name_analysis_visitor::visit(unary_expression *expression) - { - expression->operand().accept(this); - } - void name_analysis_visitor::visit(named_expression *expression) { if (auto unresolved_alias = this->bag.declared(expression->name)) @@ -602,22 +469,6 @@ namespace elna::boot } } - void name_analysis_visitor::visit(array_access_expression *expression) - { - expression->base().accept(this); - expression->index().accept(this); - } - - void name_analysis_visitor::visit(field_access_expression *expression) - { - expression->base().accept(this); - } - - void name_analysis_visitor::visit(dereference_expression *expression) - { - expression->base().accept(this); - } - void name_analysis_visitor::visit(literal<std::int32_t> *literal) { this->current_literal = literal->value; @@ -672,39 +523,15 @@ namespace elna::boot { type->accept(this); } - for (variable_declaration *const variable : unit->variables) - { - variable->accept(this); - } - for (procedure_declaration *const procedure : unit->procedures) - { - procedure->accept(this); - } } - void declaration_visitor::visit(type_declaration *definition) + void declaration_visitor::visit(type_declaration *declaration) { - const std::string& type_identifier = definition->identifier.name; + const std::string& type_identifier = declaration->identifier.name; if (!this->unresolved.insert({ type_identifier, std::make_shared<alias_type>(type_identifier) }).second) { - add_error<already_declared_error>(definition->identifier.name, definition->position()); - } - } - - void declaration_visitor::visit(variable_declaration *) - { - } - - void declaration_visitor::visit(procedure_declaration *definition) - { - if (!definition->body.has_value()) - { - return; - } - for (variable_declaration *const variable : definition->body.value().variables()) - { - variable->accept(this); + add_error<already_declared_error>(declaration->identifier.name, declaration->position()); } } } diff --git a/boot/symbol.cc b/boot/symbol.cc index d01eb8e..512cf04 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -429,4 +429,21 @@ namespace elna::boot { this->imports.push_front(bag.symbols); } + + type inner_aliased_type(std::shared_ptr<alias_type> alias) + { + return inner_aliased_type(alias->reference); + } + + type inner_aliased_type(type alias) + { + if (auto aliased = alias.get<alias_type>()) + { + return inner_aliased_type(aliased); + } + else + { + return alias; + } + } } diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index a3d022d..9c8990b 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -253,7 +253,7 @@ namespace elna::gcc { procedure->accept(this); } - if (unit->body.has_value()) + if (unit->entry_point.has_value()) { tree declaration_type = build_function_type_list(elna_int_type_node, elna_int_type_node, @@ -282,7 +282,7 @@ namespace elna::gcc DECL_ARGUMENTS(fndecl) = chainon(DECL_ARGUMENTS(fndecl), declaration_tree); parameter_type = TREE_CHAIN(parameter_type); } - visit_statements(unit->body.value()); + visit_statements(unit->entry_point.value()); tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(fndecl), build_int_cst_type(integer_type_node, 0)); tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result); @@ -302,11 +302,11 @@ namespace elna::gcc } } - void generic_visitor::visit(boot::procedure_declaration *definition) + void generic_visitor::visit(boot::procedure_declaration *declaration) { - tree fndecl = this->symbols->lookup(definition->identifier.name); + tree fndecl = this->symbols->lookup(declaration->identifier.name); - if (!definition->body.has_value()) + if (!declaration->body.has_value()) { return; } @@ -314,22 +314,22 @@ namespace elna::gcc DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>(); enter_scope(); - this->bag.enter(this->bag.lookup(definition->identifier.name)->is_procedure()->scope); + this->bag.enter(this->bag.lookup(declaration->identifier.name)->is_procedure()->scope); tree argument_chain = DECL_ARGUMENTS(fndecl); for (; argument_chain != NULL_TREE; argument_chain = TREE_CHAIN(argument_chain)) { this->symbols->enter(IDENTIFIER_POINTER(DECL_NAME(argument_chain)), argument_chain); } - for (boot::constant_declaration *const constant : definition->body.value().constants()) + for (boot::constant_declaration *const constant : declaration->body.value().constants()) { constant->accept(this); } - for (boot::variable_declaration *const variable : definition->body.value().variables()) + for (boot::variable_declaration *const variable : declaration->body.value().variables()) { variable->accept(this); } - visit_statements(definition->body.value().body()); + visit_statements(declaration->body.value().statements()); tree mapping = leave_scope(); this->bag.leave(); @@ -689,10 +689,10 @@ namespace elna::gcc } } - void generic_visitor::visit(boot::constant_declaration *definition) + void generic_visitor::visit(boot::constant_declaration *declaration) { - location_t definition_location = get_location(&definition->position()); - definition->body().accept(this); + location_t definition_location = get_location(&declaration->position()); + declaration->initializer().accept(this); if (assert_constant(definition_location)) { @@ -704,15 +704,15 @@ namespace elna::gcc return; } tree definition_tree = build_decl(definition_location, CONST_DECL, - get_identifier(definition->identifier.name.c_str()), TREE_TYPE(this->current_expression)); - auto result = this->symbols->enter(definition->identifier.name, definition_tree); + get_identifier(declaration->identifier.name.c_str()), TREE_TYPE(this->current_expression)); + auto result = this->symbols->enter(declaration->identifier.name, definition_tree); if (result) { DECL_INITIAL(definition_tree) = this->current_expression; TREE_CONSTANT(definition_tree) = 1; TREE_READONLY(definition_tree) = 1; - TREE_PUBLIC(definition_tree) = definition->identifier.exported; + TREE_PUBLIC(definition_tree) = declaration->identifier.exported; if (!lang_hooks.decls.global_bindings_p()) { @@ -724,7 +724,7 @@ namespace elna::gcc else { error_at(definition_location, "Variable '%s' already declared in this scope", - definition->identifier.name.c_str()); + declaration->identifier.name.c_str()); } this->current_expression = NULL_TREE; } @@ -743,9 +743,9 @@ namespace elna::gcc declaration_tree = declare_variable(variable_identifier.name, *variable_symbol, this->symbols); } // Set initializer if given. - if (declaration->body != nullptr) + if (declaration->initializer != nullptr) { - declaration->body->accept(this); + declaration->initializer->accept(this); if (is_assignable_from(TREE_TYPE(declaration_tree), this->current_expression)) { DECL_INITIAL(declaration_tree) = this->current_expression; @@ -1047,7 +1047,7 @@ namespace elna::gcc tree endif_label_decl = create_artificial_label(UNKNOWN_LOCATION); tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl); - make_if_branch(statement->body(), goto_endif); + make_if_branch(statement->branch(), goto_endif); for (const auto branch : statement->branches) { @@ -1105,7 +1105,7 @@ namespace elna::gcc void generic_visitor::visit(boot::while_statement *statement) { - location_t prerequisite_location = get_location(&statement->body().prerequisite().position()); + location_t prerequisite_location = get_location(&statement->branch().prerequisite().position()); tree prerequisite_label_decl = build_label_decl("while_do", prerequisite_location); auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR, void_type_node, prerequisite_label_decl); @@ -1114,7 +1114,7 @@ namespace elna::gcc tree branch_end_expression = build1_loc(UNKNOWN_LOCATION, LABEL_EXPR, void_type_node, branch_end_declaration); append_statement(prerequisite_label_expr); - make_if_branch(statement->body(), goto_check); + make_if_branch(statement->branch(), goto_check); for (const auto branch : statement->branches) { diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index fe502a4..1c27166 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -111,7 +111,6 @@ namespace elna::boot virtual void visit(unit *) = 0; virtual void visit(binary_expression *) = 0; virtual void visit(unary_expression *) = 0; - virtual void visit(type_expression *) = 0; virtual void visit(array_type_expression *) = 0; virtual void visit(pointer_type_expression *) = 0; virtual void visit(record_type_expression *) = 0; @@ -139,7 +138,6 @@ namespace elna::boot [[noreturn]] void not_implemented(); public: - [[noreturn]] virtual void visit(type_expression *) override; [[noreturn]] virtual void visit(array_type_expression *) override; [[noreturn]] virtual void visit(pointer_type_expression *) override; [[noreturn]] virtual void visit(type_declaration *) override; @@ -179,6 +177,50 @@ namespace elna::boot }; /** + * Abstract visitor that visits all nodes recursively. + */ + class walking_visitor : public parser_visitor + { + public: + virtual void visit(array_type_expression *) override; + virtual void visit(pointer_type_expression *) override; + virtual void visit(type_declaration *) override; + virtual void visit(record_type_expression *) override; + virtual void visit(union_type_expression *) override; + virtual void visit(procedure_type_expression *) override; + virtual void visit(enumeration_type_expression *) override; + + virtual void visit(variable_declaration *) override; + virtual void visit(constant_declaration *) override; + virtual void visit(procedure_declaration *) override; + virtual void visit(assign_statement *) override; + virtual void visit(if_statement *) override; + virtual void visit(import_declaration *) override; + virtual void visit(while_statement *statement) override; + virtual void visit(return_statement *statement) override; + virtual void visit(defer_statement *statement) override; + virtual void visit(empty_statement *) override; + virtual void visit(case_statement *statement) override; + virtual void visit(procedure_call *call) override; + virtual void visit(unit *unit) override; + virtual void visit(cast_expression *expression) override; + virtual void visit(traits_expression *trait) override; + virtual void visit(binary_expression *expression) override; + virtual void visit(unary_expression *expression) override; + virtual void visit(named_expression *) override; + virtual void visit(array_access_expression *expression) override; + virtual void visit(field_access_expression *expression) override; + virtual void visit(dereference_expression *expression) override; + virtual void visit(literal<std::int32_t> *) override; + virtual void visit(literal<std::uint32_t> *) override; + virtual void visit(literal<double> *) override; + virtual void visit(literal<bool> *) override; + virtual void visit(literal<unsigned char> *) override; + virtual void visit(literal<std::nullptr_t> *) override; + virtual void visit(literal<std::string> *) override; + }; + + /** * AST node. */ class node @@ -242,9 +284,6 @@ namespace elna::boot virtual union_type_expression *is_union(); virtual procedure_type_expression *is_procedure(); virtual enumeration_type_expression *is_enumeration(); - - void accept(parser_visitor *visitor) override; - ~type_expression() = 0; }; class array_type_expression : public type_expression @@ -331,7 +370,7 @@ namespace elna::boot public: variable_declaration(const struct position position, std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type, - expression *body = nullptr); + expression *initializer = nullptr); variable_declaration(const struct position position, std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type, std::monostate); @@ -342,7 +381,7 @@ namespace elna::boot const std::vector<identifier_definition> identifiers; type_expression& variable_type(); - expression *const body{ nullptr }; + expression *const initializer{ nullptr }; const bool is_extern{ false }; }; @@ -360,14 +399,14 @@ namespace elna::boot */ class constant_declaration : public declaration { - expression *m_body; + expression *m_initializer; public: constant_declaration(const struct position position, identifier_definition identifier, - expression *body); + expression *initializer); void accept(parser_visitor *visitor) override; - expression& body(); + expression& initializer(); virtual ~constant_declaration() override; }; @@ -391,27 +430,27 @@ namespace elna::boot procedure_type_expression *is_procedure() override; }; - struct block + struct procedure_body { - block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables, - std::vector<statement *>&& body); - block(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables); - block(const block&) = delete; - block(block&& that); + procedure_body(std::vector<constant_declaration*>&& constants, + std::vector<variable_declaration *>&& variables, std::vector<statement *>&& statements); + procedure_body(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables); + procedure_body(const procedure_body&) = delete; + procedure_body(procedure_body&& that); - block& operator=(const block&) = delete; - block& operator=(block&& that); + procedure_body& operator=(const procedure_body&) = delete; + procedure_body& operator=(procedure_body&& that); const std::vector<variable_declaration *>& variables(); const std::vector<constant_declaration *>& constants(); - const std::vector<statement *>& body(); + const std::vector<statement *>& statements(); - virtual ~block(); + virtual ~procedure_body(); private: std::vector<variable_declaration *> m_variables; std::vector<constant_declaration *> m_constants; - std::vector<statement *> m_body; + std::vector<statement *> m_statements; }; @@ -423,10 +462,10 @@ namespace elna::boot procedure_type_expression *m_heading; public: - std::optional<block> body; + std::optional<procedure_body> body; procedure_declaration(const struct position position, identifier_definition identifier, - procedure_type_expression *heading, block&& body); + procedure_type_expression *heading, procedure_body&& body); procedure_declaration(const struct position position, identifier_definition identifier, procedure_type_expression *heading); void accept(parser_visitor *visitor) override; @@ -441,16 +480,16 @@ namespace elna::boot */ class type_declaration : public declaration { - type_expression *m_body; + type_expression *m_underlying_type; public: type_declaration(const struct position position, identifier_definition identifier, type_expression *expression); - ~type_declaration(); + ~type_declaration() override; void accept(parser_visitor *visitor) override; - type_expression& body(); + type_expression& underlying_type(); }; /** @@ -660,18 +699,18 @@ namespace elna::boot */ class if_statement : public statement { - conditional_statements *m_body; + conditional_statements *m_branch; public: const std::vector<conditional_statements *> branches; const std::vector<statement *> *alternative; - if_statement(const struct position position, conditional_statements *body, + if_statement(const struct position position, conditional_statements *branch, std::vector<conditional_statements *>&& branches, std::vector<statement *> *alternative = nullptr); void accept(parser_visitor *visitor) override; - conditional_statements& body(); + conditional_statements& branch(); virtual ~if_statement() override; }; @@ -693,16 +732,16 @@ namespace elna::boot */ class while_statement : public statement { - conditional_statements *m_body; + conditional_statements *m_branch; public: const std::vector<conditional_statements *> branches; - while_statement(const struct position position, conditional_statements *body, + while_statement(const struct position position, conditional_statements *branch, std::vector<conditional_statements *>&& branches); void accept(parser_visitor *visitor) override; - conditional_statements& body(); + conditional_statements& branch(); virtual ~while_statement() override; }; @@ -710,7 +749,7 @@ namespace elna::boot class unit : public node { public: - std::optional<std::vector<statement *>> body; + const std::optional<std::vector<statement *>> entry_point; std::vector<import_declaration *> imports; std::vector<constant_declaration *> constants; @@ -719,7 +758,7 @@ namespace elna::boot std::vector<procedure_declaration *> procedures; unit(const struct position position); - unit(const struct position position, std::vector<statement *>&& body); + unit(const struct position position, std::vector<statement *>&& entry_point); virtual void accept(parser_visitor *visitor) override; virtual ~unit() override; diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h index c6ad19d..9d79b14 100644 --- a/include/elna/boot/semantic.h +++ b/include/elna/boot/semantic.h @@ -28,6 +28,9 @@ along with GCC; see the file COPYING3. If not see namespace elna::boot { + /** + * Undeclared identifier. + */ class undeclared_error : public error { const std::string identifier; @@ -38,6 +41,9 @@ namespace elna::boot std::string what() const override; }; + /** + * A symbol was already declared in this scope. + */ class already_declared_error : public error { const std::string identifier; @@ -48,6 +54,9 @@ namespace elna::boot std::string what() const override; }; + /** + * Field with the same name is already declared in this type. + */ class field_duplication_error : public error { const std::string field_name; @@ -58,6 +67,9 @@ namespace elna::boot std::string what() const override; }; + /** + * Cyclic type declaration. + */ class cyclic_declaration_error : public error { const std::vector<std::string> cycle; @@ -68,6 +80,9 @@ namespace elna::boot std::string what() const override; }; + /** + * Procedure with a return type does not return. + */ class return_error : public error { const std::string identifier; @@ -78,6 +93,9 @@ namespace elna::boot std::string what() const override; }; + /** + * Base type of a record is not a record. + */ class base_type_error : public error { const std::string base; @@ -91,7 +109,7 @@ namespace elna::boot /** * Checks types. */ - class type_analysis_visitor final : public empty_visitor, public error_container + class type_analysis_visitor final : public walking_visitor, public error_container { bool returns; symbol_bag bag; @@ -102,23 +120,16 @@ namespace elna::boot public: explicit type_analysis_visitor(symbol_bag bag); - void visit(procedure_declaration *definition) override; - void visit(assign_statement *) override; - void visit(if_statement *) override; - void visit(while_statement *) override; - void visit(return_statement *) override; - void visit(defer_statement *) override; - void visit(empty_statement *) override; - void visit(case_statement *) override; - void visit(procedure_call *) override; - void visit(unit *unit) override; - void visit(type_declaration *definition) override; + void visit(procedure_declaration *declaration) override; + void visit(return_statement *statement) override; + void visit(type_declaration *declaration) override; + void visit(record_type_expression *expression) override; }; /** * Performs name analysis. */ - class name_analysis_visitor final : public parser_visitor, public error_container + class name_analysis_visitor final : public walking_visitor, public error_container { type current_type; constant_info::variant current_literal; @@ -134,36 +145,23 @@ namespace elna::boot public: name_analysis_visitor(symbol_bag bag); - void visit(type_expression *) override; void visit(array_type_expression *expression) override; void visit(pointer_type_expression *expression) override; - void visit(type_declaration *definition) override; + void visit(type_declaration *declaration) override; void visit(record_type_expression *expression) override; void visit(union_type_expression *expression) override; void visit(procedure_type_expression *expression) override; void visit(enumeration_type_expression *expression) override; void visit(variable_declaration *declaration) override; - void visit(constant_declaration *definition) override; - void visit(procedure_declaration *definition) override; - void visit(assign_statement *statement) override; - void visit(if_statement *statement) override; - void visit(import_declaration *) override; - void visit(while_statement *statement) override; - void visit(return_statement *statement) override; - void visit(defer_statement *) override; - void visit(empty_statement *statement) override; - void visit(case_statement *statement) override; + void visit(constant_declaration *declaration) override; + void visit(procedure_declaration *declaration) override; + void visit(procedure_call *call) override; void visit(unit *unit) override; void visit(cast_expression *expression) override; void visit(traits_expression *trait) override; - void visit(binary_expression *expression) override; - void visit(unary_expression *expression) override; void visit(named_expression *expression) override; - void visit(array_access_expression *expression) override; - void visit(field_access_expression *expression) override; - void visit(dereference_expression *expression) override; void visit(literal<std::int32_t> *literal) override; void visit(literal<std::uint32_t> *literal) override; void visit(literal<double> *literal) override; @@ -185,8 +183,6 @@ namespace elna::boot void visit(import_declaration *) override; void visit(unit *unit) override; - void visit(type_declaration *definition) override; - void visit(variable_declaration *) override; - void visit(procedure_declaration *definition) override; + void visit(type_declaration *declaration) override; }; } diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index beb44e2..6258760 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -457,4 +457,15 @@ namespace elna::boot */ void add_import(const symbol_bag& bag); }; + + /** + * If a type is a declared name for another type, look up recursively + * the declared type. If the given type is not an alias, then this function + * returns its argument. + * + * \param alias The type to lookup the innermost declaration for. + * \return Innermost type declaration. + */ + type inner_aliased_type(type alias); + type inner_aliased_type(std::shared_ptr<alias_type> alias); } diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 7ee251b..28bfe2d 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -65,7 +65,7 @@ namespace elna::gcc public: generic_visitor(std::shared_ptr<symbol_table> symbol_table, elna::boot::symbol_bag bag); - void visit(boot::procedure_declaration *definition) override; + void visit(boot::procedure_declaration *declaration) override; void visit(boot::procedure_call *call) override; void visit(boot::cast_expression *expression) override; void visit(boot::traits_expression *trait) override; @@ -78,7 +78,7 @@ namespace elna::gcc void visit(boot::literal<std::string> *string) override; void visit(boot::binary_expression *expression) override; void visit(boot::unary_expression *expression) override; - void visit(boot::constant_declaration *definition) override; + void visit(boot::constant_declaration *declaration) override; void visit(boot::variable_declaration *declaration) override; void visit(boot::named_expression *expression) override; void visit(boot::array_access_expression *expression) override; |
