aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/ast.cc101
-rw-r--r--boot/parser.yy28
-rw-r--r--boot/semantic.cc338
-rw-r--r--boot/symbol.cc91
4 files changed, 285 insertions, 273 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index 37e89ac..3454cce 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -29,6 +29,11 @@ namespace elna::boot
__builtin_unreachable();
}
+ void empty_visitor::visit(constant_type_expression *)
+ {
+ __builtin_unreachable();
+ }
+
void empty_visitor::visit(type_declaration *)
{
__builtin_unreachable();
@@ -54,11 +59,6 @@ namespace elna::boot
__builtin_unreachable();
}
- void empty_visitor::visit(constant_declaration *)
- {
- __builtin_unreachable();
- }
-
void empty_visitor::visit(procedure_declaration *)
{
__builtin_unreachable();
@@ -210,10 +210,6 @@ namespace elna::boot
}
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);
@@ -336,10 +332,6 @@ namespace elna::boot
{
variable->accept(this);
}
- for (constant_declaration *const constant : unit->constants)
- {
- constant->accept(this);
- }
for (procedure_declaration *const procedure : unit->procedures)
{
procedure->accept(this);
@@ -364,17 +356,17 @@ namespace elna::boot
}
}
- void walking_visitor::visit(constant_declaration *declaration)
+ void walking_visitor::visit(array_type_expression *expression)
{
- declaration->initializer().accept(this);
+ expression->base().accept(this);
}
- void walking_visitor::visit(array_type_expression *expression)
+ void walking_visitor::visit(pointer_type_expression *expression)
{
expression->base().accept(this);
}
- void walking_visitor::visit(pointer_type_expression *expression)
+ void walking_visitor::visit(constant_type_expression *expression)
{
expression->base().accept(this);
}
@@ -557,6 +549,11 @@ namespace elna::boot
return nullptr;
}
+ constant_type_expression *type_expression::is_constant()
+ {
+ return nullptr;
+ }
+
record_type_expression *type_expression::is_record()
{
return nullptr;
@@ -624,6 +621,32 @@ namespace elna::boot
return *m_base;
}
+ constant_type_expression::constant_type_expression(const source_position position,
+ type_expression *base)
+ : node(position), m_base(base)
+ {
+ }
+
+ constant_type_expression::~constant_type_expression()
+ {
+ delete m_base;
+ }
+
+ void constant_type_expression::accept(parser_visitor *visitor)
+ {
+ visitor->visit(this);
+ }
+
+ constant_type_expression *constant_type_expression::is_constant()
+ {
+ return this;
+ }
+
+ type_expression& constant_type_expression::base()
+ {
+ return *m_base;
+ }
+
record_type_expression::record_type_expression(const source_position position,
std::vector<field_declaration>&& fields)
: node(position), fields(std::move(fields))
@@ -753,27 +776,6 @@ namespace elna::boot
{
}
- constant_declaration::constant_declaration(const source_position position, identifier_definition identifier,
- expression *initializer)
- : declaration(position, identifier), m_initializer(initializer)
- {
- }
-
- void constant_declaration::accept(parser_visitor *visitor)
- {
- visitor->visit(this);
- }
-
- expression& constant_declaration::initializer()
- {
- return *m_initializer;
- }
-
- constant_declaration::~constant_declaration()
- {
- delete m_initializer;
- }
-
procedure_type_expression::procedure_type_expression(const source_position position,
std::vector<field_declaration>&& parameters, return_t return_type)
: node(position), return_type(return_type), parameters(std::move(parameters))
@@ -863,17 +865,15 @@ namespace elna::boot
return *m_underlying_type;
}
- procedure_body::procedure_body(std::vector<constant_declaration *>&& constants,
- std::vector<variable_declaration *>&& variables, std::vector<statement *>&& entry_point,
- expression *return_expr)
- : constants(std::move(constants)), variables(std::move(variables)),
- entry_point(std::move(entry_point)), return_expression(return_expr)
+ 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)
{
}
procedure_body::procedure_body(procedure_body&& that)
- : constants(std::move(const_cast<std::vector<constant_declaration *>&>(that.constants))),
- variables(std::move(const_cast<std::vector<variable_declaration *>&>(that.variables))),
+ : variables(std::move(const_cast<std::vector<variable_declaration *>&>(that.variables))),
entry_point(std::move(const_cast<std::vector<statement *>&>(that.entry_point))),
return_expression(that.return_expression)
{
@@ -889,27 +889,22 @@ namespace elna::boot
{
delete variable;
}
- for (constant_declaration *constant : this->constants)
- {
- delete constant;
- }
}
unit::unit(const source_position position)
- : node(position), procedure_body(std::vector<constant_declaration *>{},
- std::vector<variable_declaration *>{}, std::vector<statement *>{}, nullptr)
+ : node(position),
+ procedure_body(std::vector<variable_declaration *>{}, std::vector<statement *>{}, nullptr)
{
}
unit::unit(const source_position position,
std::vector<import_declaration *>&& imports,
- std::vector<constant_declaration *>&& constants,
std::vector<type_declaration *>&& types,
std::vector<variable_declaration *>&& variables,
std::vector<procedure_declaration *>&& procedures,
std::vector<statement *>&& entry_point)
: node(position),
- procedure_body(std::move(constants), std::move(variables), std::move(entry_point)),
+ procedure_body(std::move(variables), std::move(entry_point)),
imports(std::move(imports)), types(std::move(types)), procedures(std::move(procedures))
{
}
diff --git a/boot/parser.yy b/boot/parser.yy
index c34c905..1dd42a8 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -129,8 +129,6 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<elna::boot::expression *>> case_labels;
%type <elna::boot::switch_case> switch_case;
%type <std::vector<elna::boot::switch_case>> switch_cases;
-%type <elna::boot::constant_declaration *> constant_declaration;
-%type <std::vector<elna::boot::constant_declaration *>> constant_part constant_declarations;
%type <elna::boot::variable_declaration *> variable_declaration;
%type <std::vector<elna::boot::variable_declaration *>> variable_declarations variable_part;
%type <elna::boot::type_expression *> type_expression;
@@ -166,14 +164,14 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<elna::boot::import_declaration *>> import_declarations import_part;
%%
program:
- import_part constant_part type_part variable_part procedure_part statement_part "end" "."
+ import_part type_part variable_part procedure_part statement_part "end" "."
{
- boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2, $3, $4, $5, $6);
+ boot::unit *tree = new boot::unit(boot::make_position(@$), $1, $2, $3, $4, $5);
driver.tree.reset(tree);
}
procedure_body:
- constant_part variable_part statement_part procedure_return
- { $$ = std::make_unique<boot::procedure_body>($1, $2, $3, $4); }
+ variable_part statement_part procedure_return
+ { $$ = std::make_unique<boot::procedure_body>($1, $2, $3); }
statement_part:
/* no statements */ {}
@@ -444,6 +442,10 @@ type_expression:
{
$$ = new boot::array_type_expression(boot::make_position(@$), $4, $2);
}
+ | "const" type_expression
+ {
+ $$ = new boot::constant_type_expression(boot::make_position(@$), $2);
+ }
| "^" type_expression
{
$$ = new boot::pointer_type_expression(boot::make_position(@$), $2);
@@ -501,20 +503,6 @@ variable_declarations:
variable_part:
/* no variable declarations */ {}
| "var" variable_declarations { $$ = $2; }
-constant_declaration: identifier_definition ":=" expression
- {
- $$ = new boot::constant_declaration(boot::make_position(@$), std::move(*$1), $3);
- }
-constant_declarations:
- constant_declaration constant_declarations
- {
- $$ = $2;
- $$.insert(std::cbegin($$), $1);
- }
- | /* no constant definitions */ {}
-constant_part:
- /* no constant definitions */ {}
- | "const" constant_declarations { $$ = $2; }
import_declaration:
IDENTIFIER "." import_declaration
{
diff --git a/boot/semantic.cc b/boot/semantic.cc
index 9137053..c987cfd 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -73,6 +73,18 @@ namespace elna::boot
+ "', but got '" + actual.to_string() + "'";
}
+ constant_assignment_error::constant_assignment_error(const source_position position,
+ type assignee)
+ : error(position), assignee(assignee)
+ {
+ }
+
+ std::string constant_assignment_error::what() const
+ {
+ return "Cannot assign to a value of type '" + assignee.to_string()
+ + "', because it is constant or contains constant members";
+ }
+
field_not_found_error::field_not_found_error(const identifier& field_name,
type composite_type)
: error(field_name.position()), field_name(field_name.name()), composite_type(composite_type)
@@ -81,7 +93,7 @@ namespace elna::boot
std::string field_not_found_error::what() const
{
- type resolved = inner_aliased_type(composite_type);
+ type resolved = resolve_underlying_type(composite_type);
bool is_enum = resolved.get<enumeration_type>() != nullptr;
bool is_record = resolved.get<record_type>() != nullptr;
@@ -112,7 +124,7 @@ namespace elna::boot
std::string duplicate_member_error::what() const
{
- type resolved = inner_aliased_type(aggregate);
+ type resolved = resolve_underlying_type(aggregate);
bool is_enum = resolved.get<enumeration_type>() != nullptr;
std::string kind = is_enum ? "member" : "field";
std::string message = is_enum ? "Enumeration" : "Record";
@@ -208,7 +220,7 @@ namespace elna::boot
unsupported_trait_type_error::unsupported_trait_type_error(const identifier& trait,
type actual)
- : error(trait.position()), trait_name(trait.name()), actual(actual)
+ : error(trait.position()), actual(actual), trait_name(trait.name())
{
}
@@ -218,6 +230,119 @@ namespace elna::boot
+ "' does not support trait '#" + trait_name + "'";
}
+ // Members of a constant aggregate are constant themselves.
+ static type qualify_member_type(const type& element, const type& aggregate)
+ {
+ if (resolve_aliases(aggregate).get<constant_type>() != nullptr
+ && resolve_aliases(element).get<constant_type>() == nullptr)
+ {
+ return type(std::make_shared<constant_type>(element));
+ }
+ else
+ {
+ return element;
+ }
+ }
+
+ /*
+ * Whether the type itself is constant or has a constant member at any
+ * nesting level, so that values of this type cannot be reassigned as a
+ * whole. Pointers to constants do not make the type itself constant.
+ */
+ static bool contains_constant_member(const type& checked)
+ {
+ auto referent = resolve_aliases(checked);
+
+ if (referent.get<constant_type>() != nullptr)
+ {
+ return true;
+ }
+ else if (auto record = referent.get<record_type>())
+ {
+ for (const type_field& field : record->fields)
+ {
+ if (contains_constant_member(field.second))
+ {
+ return true;
+ }
+ }
+ return !record->base.empty() && contains_constant_member(record->base);
+ }
+ else if (auto array = referent.get<array_type>())
+ {
+ return contains_constant_member(array->base);
+ }
+ return false;
+ }
+
+ bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr<alias_type> alias,
+ std::vector<std::string>& alias_path)
+ {
+ if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path))
+ {
+ return false;
+ }
+ alias_path.push_back(alias->name);
+
+ if (auto another_alias = alias->reference.get<alias_type>())
+ {
+ return check_unresolved_symbol(another_alias, alias_path);
+ }
+ return true;
+ }
+
+ bool type_analysis_visitor::is_base_of(const std::shared_ptr<record_type>& base,
+ const std::shared_ptr<record_type>& derived)
+ {
+ if (derived != nullptr)
+ {
+ if (auto current_record = resolve_underlying_type(derived->base).get<record_type>())
+ {
+ return current_record == base || is_base_of(base, current_record);
+ }
+ }
+ return false;
+ }
+
+ bool type_analysis_visitor::is_assignable_from(const type& assignee, const type& assignment)
+ {
+ type resolved_assignee = resolve_underlying_type(assignee);
+ type resolved_assignment = resolve_underlying_type(assignment);
+
+ if (resolved_assignee == resolved_assignment
+ || (is_primitive_type(resolved_assignee, "Pointer") && is_any_pointer_type(resolved_assignment))
+ || (is_primitive_type(resolved_assignment, "Pointer") && is_any_pointer_type(resolved_assignee)))
+ {
+ return true;
+ }
+ std::shared_ptr<pointer_type> assignee_pointer = resolved_assignee.get<pointer_type>();
+ std::shared_ptr<pointer_type> assignment_pointer = resolved_assignment.get<pointer_type>();
+
+ if (assignee_pointer == nullptr || assignment_pointer == nullptr)
+ {
+ return false;
+ }
+ auto assignee_pointee_const = resolve_aliases(assignee_pointer->base).get<constant_type>();
+ auto assignment_pointee_const = resolve_aliases(assignment_pointer->base).get<constant_type>();
+
+ // Constness can be added at the first indirection level, but not removed.
+ if (assignee_pointee_const != nullptr
+ && assignee_pointee_const->unqualified == assignment_pointer->base)
+ {
+ return true;
+ }
+ if (assignment_pointee_const != nullptr && assignee_pointee_const == nullptr)
+ {
+ return false;
+ }
+ // A pointer to a record can be assigned to a pointer to its base type.
+ std::shared_ptr<record_type> assignee_record =
+ resolve_underlying_type(assignee_pointer->base).get<record_type>();
+
+ return assignee_record != nullptr
+ && is_base_of(assignee_record, resolve_underlying_type(assignment_pointer->base).get<record_type>());
+ }
+
type_analysis_visitor::type_analysis_visitor(symbol_bag bag)
: error_container(), bag(bag)
{
@@ -272,7 +397,12 @@ namespace elna::boot
{
walking_visitor::visit(statement);
- if (!is_assignable_from(statement->lvalue().type_decoration, statement->rvalue().type_decoration))
+ if (contains_constant_member(statement->lvalue().type_decoration))
+ {
+ add_error<constant_assignment_error>(statement->position(),
+ statement->lvalue().type_decoration);
+ }
+ else if (!is_assignable_from(statement->lvalue().type_decoration, statement->rvalue().type_decoration))
{
add_error<type_mismatch_error>(statement->position(),
statement->lvalue().type_decoration, statement->rvalue().type_decoration);
@@ -302,7 +432,7 @@ namespace elna::boot
void type_analysis_visitor::visit(case_statement *statement)
{
walking_visitor::visit(statement);
- type condition_type = inner_aliased_type(statement->condition().type_decoration);
+ type condition_type = resolve_underlying_type(statement->condition().type_decoration);
for (const switch_case& case_block : statement->cases)
{
@@ -317,22 +447,6 @@ namespace elna::boot
}
}
- bool type_analysis_visitor::check_unresolved_symbol(std::shared_ptr<alias_type> alias,
- std::vector<std::string>& alias_path)
- {
- if (std::find(std::cbegin(alias_path), std::cend(alias_path), alias->name) != std::cend(alias_path))
- {
- return false;
- }
- alias_path.push_back(alias->name);
-
- if (auto another_alias = alias->reference.get<alias_type>())
- {
- return check_unresolved_symbol(another_alias, alias_path);
- }
- return true;
- }
-
void type_analysis_visitor::visit(type_declaration *declaration)
{
std::vector<std::string> alias_path;
@@ -352,7 +466,7 @@ namespace elna::boot
{
if (expression->base.has_value())
{
- type base_type = inner_aliased_type(this->bag.lookup(expression->base.value().name())->is_type()->symbol);
+ type base_type = resolve_underlying_type(this->bag.lookup(expression->base.value().name())->is_type()->symbol);
if (base_type.get<record_type>() == nullptr)
{
add_error<base_type_error>(base_type, expression->position());
@@ -393,7 +507,7 @@ namespace elna::boot
void type_analysis_visitor::visit(record_constructor_expression *expression)
{
- auto record = inner_aliased_type(expression->type_decoration).get<record_type>();
+ auto record = resolve_underlying_type(expression->type_decoration).get<record_type>();
if (record == nullptr)
{
@@ -422,7 +536,7 @@ namespace elna::boot
void type_analysis_visitor::visit(array_constructor_expression *expression)
{
- auto array = inner_aliased_type(expression->type_decoration).get<array_type>();
+ auto array = resolve_underlying_type(expression->type_decoration).get<array_type>();
if (array == nullptr)
{
@@ -490,49 +604,9 @@ namespace elna::boot
return this->bag.lookup(name)->is_type()->symbol;
}
- type name_analysis_visitor::type_of_constant(const constant_info::variant& value)
- {
- return std::visit([this](auto&& arg) -> type {
- using T = std::decay_t<decltype(arg)>;
-
- if constexpr (std::is_same_v<T, std::int32_t>)
- {
- return lookup_primitive_type("Int");
- }
- else if constexpr (std::is_same_v<T, std::uint32_t>)
- {
- return lookup_primitive_type("Word");
- }
- else if constexpr (std::is_same_v<T, double>)
- {
- return lookup_primitive_type("Float");
- }
- else if constexpr (std::is_same_v<T, bool>)
- {
- return lookup_primitive_type("Bool");
- }
- else if constexpr (std::is_same_v<T, unsigned char>)
- {
- return lookup_primitive_type("Char");
- }
- else if constexpr (std::is_same_v<T, std::nullptr_t>)
- {
- return lookup_primitive_type("Pointer");
- }
- else if constexpr (std::is_same_v<T, std::string>)
- {
- return lookup_primitive_type("String");
- }
- else
- {
- static_assert(!sizeof(T*), "Unhandled constant type");
- }
- }, value);
- }
-
type name_analysis_visitor::lookup_field(const type& composite_type, const std::string& field_name)
{
- type resolved_type = inner_aliased_type(composite_type);
+ type resolved_type = resolve_underlying_type(composite_type);
if (auto record = resolved_type.get<record_type>())
{
@@ -579,6 +653,12 @@ namespace elna::boot
this->current_type = type(std::make_shared<pointer_type>(this->current_type));
}
+ void name_analysis_visitor::visit(constant_type_expression *expression)
+ {
+ walking_visitor::visit(expression);
+ this->current_type = type(std::make_shared<constant_type>(this->current_type));
+ }
+
void name_analysis_visitor::visit(array_type_expression *expression)
{
walking_visitor::visit(expression);
@@ -593,7 +673,7 @@ namespace elna::boot
static void collect_field_names(const type& composite_type,
std::map<std::string, field_origin>& names)
{
- auto record = inner_aliased_type(composite_type).get<record_type>();
+ auto record = resolve_underlying_type(composite_type).get<record_type>();
if (record == nullptr)
{
return;
@@ -803,15 +883,6 @@ namespace elna::boot
}
}
- void name_analysis_visitor::visit(constant_declaration *declaration)
- {
- walking_visitor::visit(declaration);
- auto constant_symbol = std::make_shared<constant_info>(this->current_literal);
-
- constant_symbol->exported = declaration->identifier.exported();
- constant_symbol->position.emplace(declaration->position());
- this->bag.enter(declaration->identifier.name(), constant_symbol);
- }
void name_analysis_visitor::visit(procedure_declaration *declaration)
{
@@ -833,10 +904,6 @@ namespace elna::boot
++name_iterator;
++type_iterator;
}
- for (constant_declaration *const constant : declaration->body.value().constants)
- {
- constant->accept(this);
- }
for (variable_declaration *const variable : declaration->body.value().variables)
{
variable->accept(this);
@@ -887,10 +954,6 @@ namespace elna::boot
{
variable->accept(this);
}
- for (constant_declaration *const constant : unit->constants)
- {
- constant->accept(this);
- }
for (procedure_declaration *const procedure : unit->procedures)
{
procedure->accept(this);
@@ -932,7 +995,7 @@ namespace elna::boot
if (!trait->type_decoration.empty())
{
- type resolved = inner_aliased_type(trait->type_decoration);
+ type resolved = resolve_underlying_type(trait->type_decoration);
bool is_enum = resolved.get<enumeration_type>() != nullptr;
bool is_integral = false;
@@ -1005,7 +1068,7 @@ namespace elna::boot
void name_analysis_visitor::visit(array_access_expression *expression)
{
walking_visitor::visit(expression);
- auto resolved_base= inner_aliased_type(expression->base().type_decoration);
+ auto resolved_base = resolve_underlying_type(expression->base().type_decoration);
if (auto array = resolved_base.get<array_type>())
{
@@ -1015,6 +1078,13 @@ namespace elna::boot
{
expression->type_decoration = lookup_primitive_type("Char");
}
+ // Elements of a constant array are constant themselves since a static
+ // array is a holistic type.
+ if (!expression->type_decoration.empty())
+ {
+ expression->type_decoration = qualify_member_type(expression->type_decoration,
+ expression->base().type_decoration);
+ }
}
void name_analysis_visitor::visit(field_access_expression *expression)
@@ -1029,7 +1099,11 @@ namespace elna::boot
}
if (expression->type_decoration.empty())
{
- add_error<field_not_found_error>(expression->field(),
+ add_error<field_not_found_error>(expression->field(), expression->base().type_decoration);
+ }
+ else
+ {
+ expression->type_decoration = qualify_member_type(expression->type_decoration,
expression->base().type_decoration);
}
}
@@ -1038,7 +1112,7 @@ namespace elna::boot
{
walking_visitor::visit(expression);
- if (auto pointer = inner_aliased_type(expression->base().type_decoration).get<pointer_type>())
+ if (auto pointer = resolve_underlying_type(expression->base().type_decoration).get<pointer_type>())
{
expression->type_decoration = pointer->base;
}
@@ -1068,10 +1142,6 @@ namespace elna::boot
{
expression->type_decoration = variable_symbol->symbol;
}
- else if (auto constant_symbol = from_symbol_table->is_constant())
- {
- expression->type_decoration = type_of_constant(constant_symbol->symbol);
- }
else if (auto procedure_symbol = from_symbol_table->is_procedure())
{
expression->type_decoration = type(std::make_shared<procedure_type>(procedure_symbol->symbol));
@@ -1086,43 +1156,36 @@ namespace elna::boot
void name_analysis_visitor::visit(literal<std::int32_t> *literal)
{
- this->current_literal = literal->value;
literal->type_decoration = lookup_primitive_type("Int");
}
void name_analysis_visitor::visit(literal<std::uint32_t> *literal)
{
- this->current_literal = literal->value;
literal->type_decoration = lookup_primitive_type("Word");
}
void name_analysis_visitor::visit(literal<double> *literal)
{
- this->current_literal = literal->value;
literal->type_decoration = lookup_primitive_type("Float");
}
void name_analysis_visitor::visit(literal<bool> *literal)
{
- this->current_literal = literal->value;
literal->type_decoration = lookup_primitive_type("Bool");
}
void name_analysis_visitor::visit(literal<unsigned char> *literal)
{
- this->current_literal = literal->value;
literal->type_decoration = lookup_primitive_type("Char");
}
void name_analysis_visitor::visit(literal<std::nullptr_t> *literal)
{
- this->current_literal = literal->value;
literal->type_decoration = lookup_primitive_type("Pointer");
}
void name_analysis_visitor::visit(literal<std::string> *literal)
{
- this->current_literal = literal->value;
literal->type_decoration = lookup_primitive_type("String");
}
@@ -1168,10 +1231,6 @@ namespace elna::boot
{
return;
}
- for (constant_declaration *const constant : declaration->body.value().constants)
- {
- constant->accept(this);
- }
for (variable_declaration *const variable : declaration->body.value().variables)
{
variable->accept(this);
@@ -1189,79 +1248,4 @@ namespace elna::boot
}
}
}
-
- void declaration_visitor::visit(constant_declaration *declaration)
- {
- if (declaration->identifier.exported())
- {
- add_error<declaration_error>(declaration_error::kind::local_export,
- declaration->identifier.id());
- }
- }
-
- bool is_base_of(std::shared_ptr<record_type> base, std::shared_ptr<record_type> derived)
- {
- type current = derived->base;
-
- while (!current.empty())
- {
- auto current_record = inner_aliased_type(current).get<record_type>();
- if (current_record == nullptr)
- {
- return false;
- }
- if (current_record == base)
- {
- return true;
- }
- current = current_record->base;
- }
- return false;
- }
-
- bool are_compatible_pointers(type lhs_type, type rhs_type)
- {
- std::shared_ptr<primitive_type> lhs_primitive = lhs_type.get<primitive_type>();
- std::shared_ptr<primitive_type> rhs_primitive = rhs_type.get<primitive_type>();
-
- bool lhs_is_primitive_pointer = lhs_primitive != nullptr && lhs_primitive->identifier == "Pointer";
- bool rhs_is_primitive_pointer = rhs_primitive != nullptr && rhs_primitive->identifier == "Pointer";
-
- return (lhs_is_primitive_pointer && rhs_type.get<pointer_type>() != nullptr)
- || (rhs_is_primitive_pointer && lhs_type.get<pointer_type>() != nullptr)
- || (lhs_is_primitive_pointer && rhs_type.get<procedure_type>() != nullptr)
- || (rhs_is_primitive_pointer && lhs_type.get<procedure_type>() != nullptr)
- || (lhs_is_primitive_pointer && rhs_is_primitive_pointer);
- }
-
- bool is_assignable_from(const type& assignee, const type& assignment)
- {
- type resolved_assignee = inner_aliased_type(assignee);
- type resolved_assignment = inner_aliased_type(assignment);
-
- if (resolved_assignee == resolved_assignment)
- {
- return true;
- }
- // If the types do not match, only some pointers can be assigned.
- if (are_compatible_pointers(resolved_assignee, resolved_assignment))
- {
- return true;
- }
- std::shared_ptr<pointer_type> assignee_pointer = resolved_assignee.get<pointer_type>();
- std::shared_ptr<pointer_type> assignment_pointer = resolved_assignment.get<pointer_type>();
-
- if (assignee_pointer == nullptr || assignment_pointer == nullptr)
- {
- return false;
- }
- // A pointer to a record can be assigned to a pointer to its base type.
- type assignee_pointee = inner_aliased_type(assignee_pointer->base);
- type assignment_pointee = inner_aliased_type(assignment_pointer->base);
- std::shared_ptr<record_type> assignee_record = assignee_pointee.get<record_type>();
- std::shared_ptr<record_type> assignment_record = assignment_pointee.get<record_type>();
-
- return assignee_record != nullptr && assignment_record != nullptr
- && is_base_of(assignee_record, assignment_record);
- }
}
diff --git a/boot/symbol.cc b/boot/symbol.cc
index a3a36c1..9985489 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -43,6 +43,11 @@ namespace elna::boot
{
}
+ type::type(std::shared_ptr<constant_type> constant)
+ : tag(type_tag::constant), constant(constant)
+ {
+ }
+
type::type(std::shared_ptr<array_type> array)
: tag(type_tag::array), array(array)
{
@@ -76,6 +81,9 @@ namespace elna::boot
case type_tag::pointer:
new (&pointer) std::shared_ptr<pointer_type>(other.pointer);
break;
+ case type_tag::constant:
+ new (&constant) std::shared_ptr<constant_type>(other.constant);
+ break;
case type_tag::array:
new (&array) std::shared_ptr<array_type>(other.array);
break;
@@ -112,6 +120,9 @@ namespace elna::boot
case type_tag::pointer:
new (&pointer) std::shared_ptr<pointer_type>(std::move(other.pointer));
break;
+ case type_tag::constant:
+ new (&constant) std::shared_ptr<constant_type>(std::move(other.constant));
+ break;
case type_tag::array:
new (&array) std::shared_ptr<array_type>(std::move(other.array));
break;
@@ -164,6 +175,9 @@ namespace elna::boot
case type_tag::pointer:
this->pointer.~shared_ptr<pointer_type>();
break;
+ case type_tag::constant:
+ this->constant.~shared_ptr<constant_type>();
+ break;
case type_tag::array:
this->array.~shared_ptr<array_type>();
break;
@@ -207,6 +221,12 @@ namespace elna::boot
}
template<>
+ std::shared_ptr<constant_type> type::get<constant_type>() const
+ {
+ return tag == type_tag::constant ? this->constant : nullptr;
+ }
+
+ template<>
std::shared_ptr<procedure_type> type::get<procedure_type>() const
{
return tag == type_tag::procedure ? this->procedure : nullptr;
@@ -225,8 +245,8 @@ namespace elna::boot
bool type::operator==(const type& other) const
{
- type resolved_this = inner_aliased_type(*this);
- type resolved_that = inner_aliased_type(other);
+ type resolved_this = resolve_aliases(*this);
+ type resolved_that = resolve_aliases(other);
if (auto left_record = resolved_this.get<record_type>())
{
@@ -248,6 +268,12 @@ namespace elna::boot
return right_pointer != nullptr && left_pointer->base == right_pointer->base;
}
+ if (auto left_const = resolved_this.get<constant_type>())
+ {
+ auto right_const = resolved_that.get<constant_type>();
+
+ return right_const != nullptr && left_const->unqualified == right_const->unqualified;
+ }
if (auto left_array = resolved_this.get<array_type>())
{
auto right_array = resolved_that.get<array_type>();
@@ -282,6 +308,8 @@ namespace elna::boot
return primitive->identifier;
case type_tag::pointer:
return "^" + pointer->base.to_string();
+ case type_tag::constant:
+ return "const " + constant->unqualified.to_string();
case type_tag::array:
return "[" + std::to_string(array->size) + "]" + array->base.to_string();
case type_tag::record:
@@ -328,6 +356,11 @@ namespace elna::boot
{
}
+ constant_type::constant_type(type unqualified)
+ : unqualified(unqualified)
+ {
+ }
+
array_type::array_type(type base, std::uint64_t size)
: base(base), size(size)
{
@@ -367,11 +400,6 @@ namespace elna::boot
return nullptr;
}
- std::shared_ptr<constant_info> info::is_constant()
- {
- return nullptr;
- }
-
std::shared_ptr<variable_info> info::is_variable()
{
return nullptr;
@@ -403,16 +431,6 @@ namespace elna::boot
return this->scope == nullptr;
}
- constant_info::constant_info(const variant& symbol)
- : symbol(symbol)
- {
- }
-
- std::shared_ptr<constant_info> constant_info::is_constant()
- {
- return std::static_pointer_cast<constant_info>(shared_from_this());
- }
-
variable_info::variable_info(const type symbol, bool is_extern)
: symbol(symbol), is_extern(is_extern)
{
@@ -524,20 +542,47 @@ namespace elna::boot
return m_exported;
}
- type inner_aliased_type(std::shared_ptr<alias_type> alias)
+ type resolve_underlying_type(std::shared_ptr<alias_type> alias)
{
- return inner_aliased_type(alias->reference);
+ return resolve_underlying_type(alias->reference);
}
- type inner_aliased_type(const type& alias)
+ type resolve_underlying_type(const type& alias)
{
- if (auto aliased = alias.get<alias_type>())
+ type resolved_alias = resolve_aliases(alias);
+
+ if (auto qualified = resolved_alias.get<constant_type>())
{
- return inner_aliased_type(aliased);
+ return resolve_underlying_type(qualified->unqualified);
}
else
{
- return alias;
+ return resolved_alias;
+ }
+ }
+
+ type resolve_aliases(const type& checked)
+ {
+ if (auto alias = checked.get<alias_type>())
+ {
+ return resolve_aliases(alias->reference);
+ }
+ return checked;
+ }
+
+ bool is_primitive_type(const type& checked, const std::string& name)
+ {
+ if (auto primitive_checked = checked.get<primitive_type>())
+ {
+ return primitive_checked->identifier == name;
}
+ return false;
+ }
+
+ bool is_any_pointer_type(const type& checked)
+ {
+ return checked.get<pointer_type>() != nullptr
+ || checked.get<procedure_type>() != nullptr
+ || is_primitive_type(checked, "Pointer");
}
}