diff options
| -rw-r--r-- | boot/ast.cc | 35 | ||||
| -rw-r--r-- | boot/parser.yy | 4 | ||||
| -rw-r--r-- | boot/semantic.cc | 45 | ||||
| -rw-r--r-- | gcc/gcc/elna-generic.cc | 22 | ||||
| -rw-r--r-- | include/elna/boot/ast.h | 19 | ||||
| -rw-r--r-- | include/elna/boot/semantic.h | 2 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 1 | ||||
| -rw-r--r-- | testsuite/runnable/array_constructor.elna | 12 | ||||
| -rw-r--r-- | testsuite/runnable/record_construction.elna (renamed from testsuite/compilable/record_construction.elna) | 0 |
9 files changed, 138 insertions, 2 deletions
diff --git a/boot/ast.cc b/boot/ast.cc index 36215c1..4af906f 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -119,6 +119,11 @@ namespace elna::boot __builtin_unreachable(); } + void empty_visitor::visit(array_constructor_expression *) + { + __builtin_unreachable(); + } + void empty_visitor::visit(traits_expression *) { __builtin_unreachable(); @@ -416,6 +421,15 @@ namespace elna::boot } } + void walking_visitor::visit(array_constructor_expression *expression) + { + expression->m_element_type->accept(this); + for (auto element : expression->elements) + { + element->accept(this); + } + } + void walking_visitor::visit(traits_expression *trait) { if (!trait->parameters.empty()) @@ -656,6 +670,27 @@ namespace elna::boot } } + array_constructor_expression::array_constructor_expression(const struct position position, + std::uint32_t size, type_expression *element_type, + std::vector<expression *>&& elements) + : node(position), size(size), m_element_type(element_type), elements(std::move(elements)) + { + } + + void array_constructor_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + array_constructor_expression::~array_constructor_expression() + { + delete m_element_type; + for (expression *const element : elements) + { + delete element; + } + } + variable_declaration::variable_declaration(const struct position position, std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type, expression *initializer) diff --git a/boot/parser.yy b/boot/parser.yy index ae2e5a8..4ef2de4 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -265,6 +265,10 @@ simple_expression: { $$ = new boot::record_constructor_expression(boot::make_position(@1), std::move($1), std::move($3)); } + | "[" INTEGER "]" type_expression "{" expressions "}" + { + $$ = new boot::array_constructor_expression(boot::make_position(@1), $2, $4, std::move($6)); + } operand: unary_expression { $$ = $1; } | simple_expression { $$ = $1; } diff --git a/boot/semantic.cc b/boot/semantic.cc index f46dce9..f42b094 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -343,6 +343,31 @@ namespace elna::boot } } + void type_analysis_visitor::visit(array_constructor_expression *expression) + { + auto array = inner_aliased_type(expression->type_decoration).get<array_type>(); + + if (array == nullptr) + { + add_error<type_expectation_error>(type_expectation_error::kind::result, expression->position()); + return; + } + if (expression->elements.size() > array->size) + { + add_error<argument_count_error>(array->size, expression->elements.size(), + expression->position()); + return; + } + for (auto element : expression->elements) + { + if (!is_assignable_from(array->base, element->type_decoration)) + { + add_error<type_expectation_error>(type_expectation_error::kind::argument, + element->position()); + } + } + } + name_analysis_visitor::name_analysis_visitor(symbol_bag bag) : error_container(), bag(bag) { @@ -588,6 +613,17 @@ namespace elna::boot } } + void name_analysis_visitor::visit(array_constructor_expression *expression) + { + expression->m_element_type->accept(this); + auto element_type = this->current_type; + for (auto element : expression->elements) + { + element->accept(this); + } + expression->type_decoration = type(std::make_shared<array_type>(element_type, expression->size)); + } + void name_analysis_visitor::visit(procedure_type_expression *expression) { std::shared_ptr<procedure_type> result_type = @@ -617,8 +653,13 @@ namespace elna::boot void name_analysis_visitor::visit(variable_declaration *declaration) { - walking_visitor::visit(declaration); - + declaration->variable_type().accept(this); + auto variable_type = this->current_type; + if (declaration->initializer != nullptr) + { + declaration->initializer->accept(this); + this->current_type = variable_type; + } for (const identifier_definition& variable_identifier : declaration->identifiers) { auto variable_symbol = register_variable(variable_identifier.name, declaration->is_extern, diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc index 5749bbc..928ca8d 100644 --- a/gcc/gcc/elna-generic.cc +++ b/gcc/gcc/elna-generic.cc @@ -202,6 +202,28 @@ namespace elna::gcc this->current_expression = build_constructor(record_type, tree_arguments); } + void generic_visitor::visit(boot::array_constructor_expression *expression) + { + tree array_type = get_inner_alias(expression->type_decoration, this->symbols); + + if (TREE_CODE(array_type) != ARRAY_TYPE) + { + this->current_expression = error_mark_node; + return; + } + tree domain = TYPE_DOMAIN(array_type); + tree index = TYPE_MIN_VALUE(domain); + vec<constructor_elt, va_gc> *tree_arguments = nullptr; + + for (boot::expression *const element : expression->elements) + { + element->accept(this); + CONSTRUCTOR_APPEND_ELT(tree_arguments, index, this->current_expression); + index = int_const_binop(PLUS_EXPR, index, size_one_node); + } + this->current_expression = build_constructor(array_type, tree_arguments); + } + void generic_visitor::visit(boot::unit *unit) { for (boot::import_declaration *const declaration : unit->imports) diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 67e9fbe..fbe65a4 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -61,6 +61,7 @@ namespace elna::boot class procedure_call; class cast_expression; class record_constructor_expression; + class array_constructor_expression; struct field_initializer; class assign_statement; class if_statement; @@ -100,6 +101,7 @@ namespace elna::boot virtual void visit(procedure_call *) = 0; virtual void visit(cast_expression *) = 0; virtual void visit(record_constructor_expression *) = 0; + virtual void visit(array_constructor_expression *) = 0; virtual void visit(traits_expression *) = 0; virtual void visit(assign_statement *) = 0; virtual void visit(if_statement *) = 0; @@ -156,6 +158,7 @@ namespace elna::boot [[noreturn]] virtual void visit(unit *) override; [[noreturn]] virtual void visit(cast_expression *) override; [[noreturn]] virtual void visit(record_constructor_expression *) override; + [[noreturn]] virtual void visit(array_constructor_expression *) override; [[noreturn]] virtual void visit(traits_expression *) override; [[noreturn]] virtual void visit(binary_expression *) override; [[noreturn]] virtual void visit(unary_expression *) override; @@ -199,6 +202,7 @@ namespace elna::boot virtual void visit(unit *unit) override; virtual void visit(cast_expression *expression) override; virtual void visit(record_constructor_expression *expression) override; + virtual void visit(array_constructor_expression *expression) override; virtual void visit(traits_expression *trait) override; virtual void visit(binary_expression *expression) override; virtual void visit(unary_expression *expression) override; @@ -350,6 +354,21 @@ namespace elna::boot virtual ~record_constructor_expression() override; }; + class array_constructor_expression : public expression + { + public: + const std::uint32_t size; + type_expression *const m_element_type; + const std::vector<expression *> elements; + + array_constructor_expression(const struct position position, + std::uint32_t size, type_expression *element_type, + std::vector<expression *>&& elements); + void accept(parser_visitor *visitor) override; + + virtual ~array_constructor_expression() override; + }; + /** * Enumeration type. */ diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h index 5ef4bc8..4041f33 100644 --- a/include/elna/boot/semantic.h +++ b/include/elna/boot/semantic.h @@ -162,6 +162,7 @@ namespace elna::boot void visit(procedure_call *call) override; void visit(case_statement *statement) override; void visit(record_constructor_expression *expression) override; + void visit(array_constructor_expression *expression) override; }; /** @@ -193,6 +194,7 @@ namespace elna::boot void visit(type_declaration *declaration) override; void visit(record_type_expression *expression) override; void visit(record_constructor_expression *expression) override; + void visit(array_constructor_expression *expression) override; void visit(procedure_type_expression *expression) override; void visit(enumeration_type_expression *expression) override; diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index f30f9d6..23e1738 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -84,6 +84,7 @@ namespace elna::gcc void visit(boot::dereference_expression *expression) override; void visit(boot::unit *unit) override; void visit(boot::record_constructor_expression *expression) override; + void visit(boot::array_constructor_expression *expression) override; void visit(boot::assign_statement *statement) override; void visit(boot::if_statement *statement) override; void visit(boot::import_declaration *) override; diff --git a/testsuite/runnable/array_constructor.elna b/testsuite/runnable/array_constructor.elna new file mode 100644 index 0000000..2ce3578 --- /dev/null +++ b/testsuite/runnable/array_constructor.elna @@ -0,0 +1,12 @@ +var + a: [3]Int := [3]Int{1, 2, 3} + b: [2]Int := [2]Int{4} + +begin + assert(a[1] = 1 & a[2] = 2 & a[3] = 3); + assert(b[1] = 4 & b[2] = 0); + + a := [3]Int{5, 6, 7}; + assert(a[1] = 5 & a[2] = 6 & a[3] = 7) +return 0 +end. diff --git a/testsuite/compilable/record_construction.elna b/testsuite/runnable/record_construction.elna index 00e60db..00e60db 100644 --- a/testsuite/compilable/record_construction.elna +++ b/testsuite/runnable/record_construction.elna |
