aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/ast.cc4
-rw-r--r--boot/parser.yy6
-rw-r--r--boot/semantic.cc57
-rw-r--r--boot/symbol.cc5
-rw-r--r--gcc/gcc/elna-builtins.cc12
-rw-r--r--include/elna/boot/ast.h4
-rw-r--r--include/elna/boot/semantic.h12
-rw-r--r--include/elna/boot/symbol.h5
-rw-r--r--testsuite/runnable/record_base_assignment.elna22
9 files changed, 111 insertions, 16 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index 5885cff..3599308 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -383,8 +383,8 @@ namespace elna::boot
}
record_type_expression::record_type_expression(const struct position position,
- std::vector<field_declaration>&& fields)
- : node(position), fields(std::move(fields))
+ std::vector<field_declaration>&& fields, std::optional<std::string> base)
+ : node(position), fields(std::move(fields)), base(base)
{
}
diff --git a/boot/parser.yy b/boot/parser.yy
index b05b544..7797dd1 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -460,7 +460,11 @@ type_expression:
}
| "record" optional_fields "end"
{
- $$ = new boot::record_type_expression(boot::make_position(@1), std::move($2));
+ $$ = new boot::record_type_expression(boot::make_position(@1), std::move($2), std::nullopt);
+ }
+ | "record" "(" IDENTIFIER ")" optional_fields "end"
+ {
+ $$ = new boot::record_type_expression(boot::make_position(@1), std::move($5), std::move($3));
}
| "union" required_fields "end"
{
diff --git a/boot/semantic.cc b/boot/semantic.cc
index bc7c2d2..a48226b 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -78,7 +78,17 @@ namespace elna::boot
std::string return_error::what() const
{
- return "Procedure '" + identifier + "' is expected to return, but does not have a return statement";
+ return "Procedure '" + this->identifier + "' is expected to return, but does not have a return statement";
+ }
+
+ base_type_error::base_type_error(const std::string& base, const struct position position)
+ : error(position), base(base)
+ {
+ }
+
+ std::string base_type_error::what() const
+ {
+ return "Record base type '" + this->base + "' is not a record.";
}
type_analysis_visitor::type_analysis_visitor(symbol_bag bag)
@@ -291,8 +301,37 @@ namespace elna::boot
void name_analysis_visitor::visit(record_type_expression *type_expression)
{
- auto result_type = std::make_shared<record_type>();
-
+ std::shared_ptr<record_type> result_type;
+ if (type_expression->base.has_value())
+ {
+ if (auto unresolved_alias = this->bag.declared(type_expression->base.value()))
+ {
+ result_type = std::make_shared<record_type>(type(unresolved_alias));
+ }
+ else if (auto base_symbol = this->bag.lookup(type_expression->base.value()))
+ {
+ if (auto base_type_info = base_symbol->is_type())
+ {
+ result_type = std::make_shared<record_type>(base_type_info->symbol);
+ }
+ else
+ {
+ add_error<base_type_error>(type_expression->base.value(), type_expression->position());
+ this->current_type = type();
+ return;
+ }
+ }
+ else
+ {
+ add_error<undeclared_error>(type_expression->base.value(), type_expression->position());
+ this->current_type = type();
+ return;
+ }
+ }
+ else
+ {
+ result_type = std::make_shared<record_type>();
+ }
result_type->fields = build_composite_type(type_expression->fields);
this->current_type = type(result_type);
@@ -498,7 +537,7 @@ namespace elna::boot
{
call->callable().accept(this);
}
- for (expression *const argument: call->arguments)
+ for (expression *const argument : call->arguments)
{
argument->accept(this);
}
@@ -551,15 +590,13 @@ namespace elna::boot
expression->operand().accept(this);
}
- void name_analysis_visitor::visit(named_expression *type_expression)
+ void name_analysis_visitor::visit(named_expression *expression)
{
- auto unresolved_alias = this->bag.declared(type_expression->name);
-
- if (unresolved_alias != nullptr)
+ if (auto unresolved_alias = this->bag.declared(expression->name))
{
this->current_type = type(unresolved_alias);
}
- else if (auto from_symbol_table = this->bag.lookup(type_expression->name))
+ else if (auto from_symbol_table = this->bag.lookup(expression->name))
{
if (auto type_symbol = from_symbol_table->is_type())
{
@@ -568,7 +605,7 @@ namespace elna::boot
}
else
{
- add_error<undeclared_error>(type_expression->name, type_expression->position());
+ add_error<undeclared_error>(expression->name, expression->position());
this->current_type = type();
}
}
diff --git a/boot/symbol.cc b/boot/symbol.cc
index 902d331..d01eb8e 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -268,6 +268,11 @@ namespace elna::boot
{
}
+ record_type::record_type(type base)
+ : base(base)
+ {
+ }
+
procedure_type::procedure_type(return_t return_type)
: return_type(return_type)
{
diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc
index 7c97027..7817c7e 100644
--- a/gcc/gcc/elna-builtins.cc
+++ b/gcc/gcc/elna-builtins.cc
@@ -124,6 +124,18 @@ namespace elna::gcc
{
tree composite_type_node = make_node(RECORD_TYPE);
+ if (!reference->base.empty())
+ {
+ tree base_type_node = get_inner_alias(reference->base, symbols);
+
+ for (tree base_field = TYPE_FIELDS(base_type_node); base_field != NULL_TREE;
+ base_field = TREE_CHAIN(base_field))
+ {
+ tree cloned_field = build_field(UNKNOWN_LOCATION, composite_type_node,
+ IDENTIFIER_POINTER(DECL_NAME(base_field)), TREE_TYPE(base_field));
+ TYPE_FIELDS(composite_type_node) = chainon(TYPE_FIELDS(composite_type_node), cloned_field);
+ }
+ }
build_composite_type(reference->fields, composite_type_node, symbols);
return composite_type_node;
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 0642d44..6942ca5 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -287,8 +287,10 @@ namespace elna::boot
{
public:
const std::vector<field_declaration> fields;
+ const std::optional<std::string> base;
- record_type_expression(const struct position position, std::vector<field_declaration>&& fields);
+ record_type_expression(const struct position position,
+ std::vector<field_declaration>&& fields, std::optional<std::string> base);
void accept(parser_visitor *visitor) override;
record_type_expression *is_record() override;
diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h
index a0a4a73..6bc7fe0 100644
--- a/include/elna/boot/semantic.h
+++ b/include/elna/boot/semantic.h
@@ -78,6 +78,16 @@ namespace elna::boot
std::string what() const override;
};
+ class base_type_error : public error
+ {
+ const std::string base;
+
+ public:
+ base_type_error(const std::string& base, const struct position position);
+
+ std::string what() const override;
+ };
+
/**
* Checks types.
*/
@@ -153,7 +163,7 @@ namespace elna::boot
void visit(traits_expression *trait) override;
void visit(binary_expression *expression) override;
void visit(unary_expression *expression) override;
- void visit(named_expression *type_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;
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
index 5ef917e..beb44e2 100644
--- a/include/elna/boot/symbol.h
+++ b/include/elna/boot/symbol.h
@@ -129,6 +129,9 @@ namespace elna::boot
struct record_type
{
std::vector<type_field> fields;
+ const type base;
+
+ explicit record_type(type base = type());
};
struct union_type
@@ -143,7 +146,7 @@ namespace elna::boot
std::vector<type> parameters;
const return_t return_type;
- procedure_type(return_t return_type = return_t());
+ explicit procedure_type(return_t return_type = return_t());
};
struct enumeration_type
diff --git a/testsuite/runnable/record_base_assignment.elna b/testsuite/runnable/record_base_assignment.elna
new file mode 100644
index 0000000..c91383d
--- /dev/null
+++ b/testsuite/runnable/record_base_assignment.elna
@@ -0,0 +1,22 @@
+type
+ B = record
+ x: Word
+ end
+ R = record(B)
+ y: Word
+ end
+
+proc f(): Int
+var
+ r: R
+begin
+ r.x := 3u;
+ r.y := 2u;
+
+ assert(r.x = 3u & r.y = 2u);
+
+ return 0
+end
+
+ return f()
+end.