diff options
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/ast.cc | 41 | ||||
| -rw-r--r-- | boot/evaluator.cc | 4 | ||||
| -rw-r--r-- | boot/materialization.cc | 17 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 69 | ||||
| -rw-r--r-- | boot/parser.yy | 56 | ||||
| -rw-r--r-- | boot/symbol.cc | 15 | ||||
| -rw-r--r-- | boot/validation.cc | 4 |
7 files changed, 203 insertions, 3 deletions
diff --git a/boot/ast.cc b/boot/ast.cc index edc10a7..15e4928 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -72,6 +72,11 @@ namespace elna::boot __builtin_unreachable(); } + void empty_visitor::visit(constant_declaration *) + { + __builtin_unreachable(); + } + void empty_visitor::visit(procedure_declaration *) { __builtin_unreachable(); @@ -357,6 +362,11 @@ namespace elna::boot } } + void walking_visitor::visit(constant_declaration *declaration) + { + declaration->initializer->accept(this); + } + void walking_visitor::visit(array_type_expression *expression) { expression->base().accept(this); @@ -1007,6 +1017,31 @@ namespace elna::boot return *m_underlying_type; } + constant_declaration::constant_declaration(const source_position position, + identifier_definition identifier, expression *const initializer) + : node(position), identifier(std::move(identifier)), initializer(initializer) + { + } + + constant_declaration::~constant_declaration() + { + delete this->initializer; + } + + void constant_declaration::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + block::block(std::vector<constant_declaration *>&& constants, + std::vector<variable_declaration *>&& variables, + std::vector<statement *>&& statements) + : constants(std::move(constants)), + variables(std::move(variables)), + statements(std::move(statements)) + { + } + block::block(std::vector<variable_declaration *>&& variables, std::vector<statement *>&& statements) : variables(std::move(variables)), statements(std::move(statements)) { @@ -1014,6 +1049,7 @@ namespace elna::boot block& block::operator=(block&& that) noexcept { + std::swap(this->constants, that.constants); std::swap(this->variables, that.variables); std::swap(this->statements, that.statements); std::swap(this->symbols, that.symbols); @@ -1031,6 +1067,10 @@ namespace elna::boot { delete variable; } + for (const constant_declaration *constant : this->constants) + { + delete constant; + } } procedure_body::procedure_body(block&& body, expression *return_expression) @@ -1059,6 +1099,7 @@ namespace elna::boot void traverse_block(parser_visitor *visitor, const block& body) { + visit_all(visitor, body.constants); visit_all(visitor, body.variables); visit_all(visitor, body.statements); } diff --git a/boot/evaluator.cc b/boot/evaluator.cc index 78eb4cd..a96d8ab 100644 --- a/boot/evaluator.cc +++ b/boot/evaluator.cc @@ -295,6 +295,10 @@ namespace elna::boot { return std::nullopt; } + if (const std::shared_ptr<constant_info> constant = symbol->is_constant()) + { + return constant->value; + } const std::shared_ptr<variable_info> variable = symbol->is_variable(); if (variable == nullptr diff --git a/boot/materialization.cc b/boot/materialization.cc index c7296f9..fd2558b 100644 --- a/boot/materialization.cc +++ b/boot/materialization.cc @@ -39,6 +39,8 @@ namespace elna::boot return "Local symbols cannot be extern"; case variable_generic: return "Variables cannot have generic parameters"; + case constant_generic: + return "Constants cannot have generic parameters"; } __builtin_unreachable(); } @@ -91,6 +93,21 @@ namespace elna::boot } } + void materialization_visitor::visit(constant_declaration *declaration) + { + walking_visitor::visit(declaration); + if (!this->in_global_scope && declaration->identifier.exported()) + { + add_error<materialization_error>(declaration->identifier.id().position(), + materialization_error::kind::local_export); + } + if (!declaration->identifier.parameters.empty()) + { + add_error<materialization_error>(declaration->identifier.id().position(), + materialization_error::kind::constant_generic); + } + } + void materialization_visitor::visit(literal<integer_literal> *literal) { switch (literal->wants_signed) diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 9b3dec4..36faee1 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -317,6 +317,10 @@ namespace elna::boot { } + void forward_declaration_visitor::visit(constant_declaration *) + { + } + void forward_declaration_visitor::visit(procedure_declaration *) { } @@ -449,6 +453,26 @@ namespace elna::boot return variable_symbol; } + std::shared_ptr<constant_info> resolving_visitor::register_constant(const std::string& name, + const type& constant_type, const constant_value& value, const source_position position) + { + const std::shared_ptr<constant_info> constant_symbol = + std::make_shared<constant_info>(constant_type, value); + constant_symbol->position.emplace(position); + constant_symbol->file = this->module_file; + + if (!this->bag.enter(name, constant_symbol)) + { + const std::shared_ptr<info> original = this->bag.lookup(name); + symbol_declaration_error::redefinition original_definition{ + .original = original->position, + .file = this->redefinition_file(original) + }; + add_error<symbol_declaration_error>(position, name, original_definition); + } + return constant_symbol; + } + std::optional<type> resolving_visitor::lookup_pointer_like_field( const std::string& field_name, const type& element_type) { @@ -1063,6 +1087,10 @@ namespace elna::boot { expression->type_decoration = variable_symbol->symbol; } + else if (const auto constant_symbol = from_symbol_table->is_constant()) + { + expression->type_decoration = constant_symbol->symbol; + } else if (const auto procedure_symbol = from_symbol_table->is_procedure()) { type procedure = type(std::make_shared<procedure_type>(procedure_symbol->symbol)); @@ -1502,6 +1530,25 @@ namespace elna::boot } } + void declaration_visitor::visit(constant_declaration *declaration) + { + declaration->initializer->accept(this); + const std::optional<constant_value> computed = + this->constant_evaluator.evaluate(*declaration->initializer); + if (!computed.has_value()) + { + const non_constant_expression_error::initializer payload{ { declaration->identifier.id() } }; + add_error<non_constant_expression_error>(declaration->initializer->position(), payload); + return; + } + const type constant_type = declaration->initializer->type_decoration; + const source_position position = declaration->position(); + const std::string name = declaration->identifier.name(); + const std::shared_ptr<constant_info> constant_symbol = + register_constant(name, constant_type, computed.value(), position); + constant_symbol->exported = declaration->identifier.exported(); + } + void declaration_visitor::visit(procedure_declaration *declaration) { // The scope is opened before the heading is built so that the type @@ -1633,6 +1680,28 @@ namespace elna::boot } } + void name_analysis_visitor::visit(constant_declaration *declaration) + { + if (!this->bag.is_global()) + { + declaration->initializer->accept(this); + const std::optional<constant_value> computed = + this->constant_evaluator.evaluate(*declaration->initializer); + if (!computed.has_value()) + { + const non_constant_expression_error::initializer payload{ { declaration->identifier.id() } }; + add_error<non_constant_expression_error>(declaration->initializer->position(), payload); + return; + } + const type constant_type = declaration->initializer->type_decoration; + const source_position position = declaration->position(); + const std::string name = declaration->identifier.name(); + const std::shared_ptr<constant_info> constant_symbol = + register_constant(name, constant_type, computed.value(), position); + constant_symbol->exported = declaration->identifier.exported(); + } + } + void name_analysis_visitor::visit(procedure_declaration *declaration) { if (declaration->body.has_value()) diff --git a/boot/parser.yy b/boot/parser.yy index 9628443..fa701ec 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -132,6 +132,10 @@ along with GCC; see the file COPYING3. If not see %type <std::vector<elna::boot::switch_case>> switch_cases; %type <elna::boot::variable_declaration *> variable_declaration; %type <std::vector<elna::boot::variable_declaration *>> variable_declarations; +%type <elna::boot::constant_declaration *> const_declaration; +%type <std::vector<elna::boot::constant_declaration *>> const_declarations; +%type <std::pair<std::vector<elna::boot::constant_declaration *>, std::vector<elna::boot::variable_declaration *>>> + block_declaration block_declarations; %type <elna::boot::type_expression *> type_expression return_declaration; %type <std::vector<elna::boot::type_expression *>> type_expressions; %type <elna::boot::expression *> expression operand simple_expression procedure_return unary_expression; @@ -201,6 +205,12 @@ section: $$.insert($$.end(), variables.begin(), variables.end()); } + | "const" const_declarations + { + std::vector<boot::constant_declaration *> constants = $2; + + $$.insert($$.end(), constants.begin(), constants.end()); + } | "threadvar" variable_declarations { std::vector<boot::variable_declaration *> variables = $2; @@ -231,11 +241,39 @@ sections: procedure_body: block procedure_return { $$ = std::make_unique<boot::procedure_body>(std::move(*$1), $2); } +block_declaration: + "const" const_declarations + { + $$ = { std::move($2), {} }; + } + | "var" variable_declarations + { + $$ = { {}, std::move($2) }; + } +block_declarations: + block_declaration block_declarations + { + auto [constants, variables] = std::move($1); + auto [more_constants, more_variables] = std::move($2); + + constants.insert(constants.end(), more_constants.begin(), more_constants.end()); + variables.insert(variables.end(), more_variables.begin(), more_variables.end()); + $$ = { std::move(constants), std::move(variables) }; + } + | block_declaration + { + $$ = std::move($1); + } block: - "var" variable_declarations statement_part - { $$ = std::make_unique<boot::block>($2, $3); } + block_declarations statement_part + { + auto [constants, variables] = std::move($1); + $$ = std::make_unique<boot::block>(std::move(constants), std::move(variables), $2); + } | optional_begin_statements - { $$ = std::make_unique<boot::block>(std::vector<boot::variable_declaration *>(), $1); } + { + $$ = std::make_unique<boot::block>(std::vector<boot::variable_declaration *>(), $1); + } statement_part: %empty {} | "begin" statements { $$ = $2; } @@ -749,6 +787,18 @@ variable_declarations: $$ = $2; $$.insert(std::cbegin($$), $1); } +const_declaration: + identifier_definition "=" expression + { + $$ = new boot::constant_declaration(boot::make_position(@$), std::move(*$1), $3); + } +const_declarations: + %empty {} + | const_declaration const_declarations + { + $$ = $2; + $$.insert(std::cbegin($$), $1); + } import_path: IDENTIFIER "." import_path { diff --git a/boot/symbol.cc b/boot/symbol.cc index ffefea4..8feba4a 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -326,6 +326,11 @@ namespace elna::boot return nullptr; } + std::shared_ptr<constant_info> info::is_constant() + { + return nullptr; + } + type_info::type_info(const type& symbol) : symbol(symbol), owner(symbol.get<alias_type>()) { @@ -362,6 +367,16 @@ namespace elna::boot return std::static_pointer_cast<variable_info>(shared_from_this()); } + constant_info::constant_info(const type& symbol, const constant_value& value) + : symbol(symbol), value(value) + { + } + + std::shared_ptr<constant_info> constant_info::is_constant() + { + return std::static_pointer_cast<constant_info>(shared_from_this()); + } + label_info::label_info(std::size_t defer_depth) : defer_depth(defer_depth) { diff --git a/boot/validation.cc b/boot/validation.cc index 4539633..aa47557 100644 --- a/boot/validation.cc +++ b/boot/validation.cc @@ -73,6 +73,10 @@ namespace elna::boot { } + void validation_visitor::visit(constant_declaration *) + { + } + void validation_visitor::visit(procedure_declaration *declaration) { if (declaration->body.has_value()) |
