aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/ast.cc142
-rw-r--r--boot/driver.cc4
-rw-r--r--boot/parser.yy53
-rw-r--r--boot/result.cc107
-rw-r--r--boot/semantic.cc331
-rw-r--r--boot/symbol.cc48
6 files changed, 502 insertions, 183 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index 2a22d69..37e89ac 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -413,7 +413,7 @@ namespace elna::boot
{
for (const field_initializer& initializer : expression->field_initializers)
{
- initializer.value->accept(this);
+ initializer.value().accept(this);
}
}
@@ -493,8 +493,8 @@ namespace elna::boot
{
}
- node::node(const struct position position)
- : source_position(position)
+ node::node(const source_position position)
+ : m_position(position)
{
}
@@ -502,9 +502,9 @@ namespace elna::boot
{
}
- const struct position& node::position() const
+ const source_position& node::position() const
{
- return this->source_position;
+ return this->m_position;
}
cast_expression *expression::is_cast()
@@ -572,7 +572,7 @@ namespace elna::boot
return nullptr;
}
- array_type_expression::array_type_expression(const struct position position,
+ array_type_expression::array_type_expression(const source_position position,
type_expression *base, const std::uint32_t size)
: node(position), m_base(base), size(size)
{
@@ -598,7 +598,7 @@ namespace elna::boot
return *m_base;
}
- pointer_type_expression::pointer_type_expression(const struct position position,
+ pointer_type_expression::pointer_type_expression(const source_position position,
type_expression *base)
: node(position), m_base(base)
{
@@ -624,15 +624,15 @@ namespace elna::boot
return *m_base;
}
- record_type_expression::record_type_expression(const struct position position,
+ record_type_expression::record_type_expression(const source_position position,
std::vector<field_declaration>&& fields)
: node(position), fields(std::move(fields))
{
}
- record_type_expression::record_type_expression(const struct position position,
- std::vector<field_declaration>&& fields, std::string&& base)
- : node(position), fields(std::move(fields)), base(std::make_optional<std::string>(std::move(base)))
+ record_type_expression::record_type_expression(const source_position position,
+ std::vector<field_declaration>&& fields, identifier&& base)
+ : node(position), fields(std::move(fields)), base(std::make_optional<identifier>(std::move(base)))
{
}
@@ -646,8 +646,48 @@ namespace elna::boot
return this;
}
- record_constructor_expression::record_constructor_expression(const struct position position,
- std::string&& type_name,
+ field_initializer::field_initializer(identifier name, expression *value)
+ : m_name(std::move(name)), m_value(value)
+ {
+ }
+
+ field_initializer::~field_initializer()
+ {
+ delete this->m_value;
+ }
+
+ field_initializer::field_initializer(field_initializer&& other) noexcept
+ : m_name(std::move(other.m_name)), m_value(other.m_value)
+ {
+ other.m_value = nullptr;
+ }
+
+ field_initializer& field_initializer::operator=(field_initializer&& other) noexcept
+ {
+ delete this->m_value;
+ this->m_name = std::move(other.m_name);
+ this->m_value = other.m_value;
+ other.m_value = nullptr;
+ return *this;
+ }
+
+ const std::string& field_initializer::name() const
+ {
+ return this->m_name.name();
+ }
+
+ const identifier& field_initializer::id() const
+ {
+ return this->m_name;
+ }
+
+ expression& field_initializer::value() const
+ {
+ return *this->m_value;
+ }
+
+ record_constructor_expression::record_constructor_expression(const source_position position,
+ identifier&& type_name,
std::vector<field_initializer>&& field_initializers)
: node(position), type_name(std::move(type_name)), field_initializers(std::move(field_initializers))
{
@@ -658,15 +698,7 @@ namespace elna::boot
visitor->visit(this);
}
- record_constructor_expression::~record_constructor_expression()
- {
- for (const field_initializer& initializer : field_initializers)
- {
- delete initializer.value;
- }
- }
-
- array_constructor_expression::array_constructor_expression(const struct position position,
+ array_constructor_expression::array_constructor_expression(const source_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))
@@ -687,14 +719,14 @@ namespace elna::boot
}
}
- variable_declaration::variable_declaration(const struct position position,
+ variable_declaration::variable_declaration(const source_position position,
std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type,
expression *initializer)
: node(position), m_variable_type(variable_type), identifiers(std::move(identifier)), initializer(initializer)
{
}
- variable_declaration::variable_declaration(const struct position position,
+ variable_declaration::variable_declaration(const source_position position,
std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type,
std::monostate)
: node(position), m_variable_type(variable_type), identifiers(std::move(identifier)), is_extern(true)
@@ -716,12 +748,12 @@ namespace elna::boot
return *m_variable_type;
}
- declaration::declaration(const struct position position, identifier_definition identifier)
+ declaration::declaration(const source_position position, identifier_definition identifier)
: node(position), identifier(identifier)
{
}
- constant_declaration::constant_declaration(const struct position position, identifier_definition identifier,
+ constant_declaration::constant_declaration(const source_position position, identifier_definition identifier,
expression *initializer)
: declaration(position, identifier), m_initializer(initializer)
{
@@ -742,7 +774,7 @@ namespace elna::boot
delete m_initializer;
}
- procedure_type_expression::procedure_type_expression(const struct position position,
+ 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))
{
@@ -766,9 +798,9 @@ namespace elna::boot
return this;
}
- enumeration_type_expression::enumeration_type_expression(const struct position position,
- std::vector<std::string>&& members)
- : node(position), members(members)
+ enumeration_type_expression::enumeration_type_expression(const source_position position,
+ std::vector<identifier>&& members)
+ : node(position), members(std::move(members))
{
}
@@ -782,14 +814,14 @@ namespace elna::boot
return this;
}
- procedure_declaration::procedure_declaration(const struct position position, identifier_definition identifier,
+ procedure_declaration::procedure_declaration(const source_position position, identifier_definition identifier,
procedure_type_expression *heading, procedure_body&& body)
: declaration(position, identifier), m_heading(heading),
body(std::make_optional<procedure_body>(std::move(body)))
{
}
- procedure_declaration::procedure_declaration(const struct position position, identifier_definition identifier,
+ procedure_declaration::procedure_declaration(const source_position position, identifier_definition identifier,
procedure_type_expression *heading)
: declaration(position, identifier), m_heading(heading)
{
@@ -810,7 +842,7 @@ namespace elna::boot
delete m_heading;
}
- type_declaration::type_declaration(const struct position position, identifier_definition identifier,
+ type_declaration::type_declaration(const source_position position, identifier_definition identifier,
type_expression *underlying_type)
: declaration(position, identifier), m_underlying_type(underlying_type)
{
@@ -863,13 +895,13 @@ namespace elna::boot
}
}
- unit::unit(const struct position position)
+ unit::unit(const source_position position)
: node(position), procedure_body(std::vector<constant_declaration *>{},
std::vector<variable_declaration *>{}, std::vector<statement *>{}, nullptr)
{
}
- unit::unit(const struct position position,
+ unit::unit(const source_position position,
std::vector<import_declaration *>&& imports,
std::vector<constant_declaration *>&& constants,
std::vector<type_declaration *>&& types,
@@ -913,7 +945,7 @@ namespace elna::boot
return this;
}
- defer_statement::defer_statement(const struct position position, std::vector<statement *>&& statements)
+ defer_statement::defer_statement(const source_position position, std::vector<statement *>&& statements)
: node(position), statements(std::move(statements))
{
}
@@ -936,7 +968,7 @@ namespace elna::boot
visitor->visit(this);
}
- empty_statement::empty_statement(const struct position position)
+ empty_statement::empty_statement(const source_position position)
: node(position)
{
}
@@ -971,7 +1003,7 @@ namespace elna::boot
__builtin_unreachable();
}
- named_expression::named_expression(const struct position position, const std::string& name)
+ named_expression::named_expression(const source_position position, const std::string& name)
: node(position), name(name)
{
}
@@ -986,7 +1018,7 @@ namespace elna::boot
return this;
}
- array_access_expression::array_access_expression(const struct position position,
+ array_access_expression::array_access_expression(const source_position position,
expression *base, expression *index)
: node(position), m_base(base), m_index(index)
{
@@ -1018,9 +1050,9 @@ namespace elna::boot
delete m_base;
}
- field_access_expression::field_access_expression(const struct position position,
- expression *base, const std::string& field)
- : node(position), m_base(base), m_field(field)
+ field_access_expression::field_access_expression(const source_position position,
+ expression *base, identifier&& field)
+ : node(position), m_base(base), m_field(std::move(field))
{
}
@@ -1034,7 +1066,7 @@ namespace elna::boot
return *m_base;
}
- std::string& field_access_expression::field()
+ const identifier& field_access_expression::field()
{
return m_field;
}
@@ -1049,7 +1081,7 @@ namespace elna::boot
delete m_base;
}
- dereference_expression::dereference_expression(const struct position position,
+ dereference_expression::dereference_expression(const source_position position,
expression *base)
: node(position), m_base(base)
{
@@ -1075,7 +1107,7 @@ namespace elna::boot
delete m_base;
}
- binary_expression::binary_expression(const struct position position, expression *lhs,
+ binary_expression::binary_expression(const source_position position, expression *lhs,
expression *rhs, const binary_operator operation)
: node(position), m_lhs(lhs), m_rhs(rhs), m_operator(operation)
{
@@ -1112,7 +1144,7 @@ namespace elna::boot
delete m_rhs;
}
- unary_expression::unary_expression(const struct position position, expression *operand,
+ unary_expression::unary_expression(const source_position position, expression *operand,
const unary_operator operation)
: node(position), m_operand(std::move(operand)), m_operator(operation)
{
@@ -1143,7 +1175,7 @@ namespace elna::boot
delete m_operand;
}
- procedure_call::procedure_call(const struct position position, designator_expression *callable,
+ procedure_call::procedure_call(const source_position position, designator_expression *callable,
std::vector<expression *>&& arguments)
: node(position), m_callable(callable), arguments(std::move(arguments))
{
@@ -1173,7 +1205,7 @@ namespace elna::boot
delete m_callable;
}
- cast_expression::cast_expression(const struct position position, type_expression *target, expression *value)
+ cast_expression::cast_expression(const source_position position, type_expression *target, expression *value)
: node(position), m_target(target), m_value(value)
{
}
@@ -1204,9 +1236,9 @@ namespace elna::boot
delete m_value;
}
- traits_expression::traits_expression(const struct position position, const std::string& name,
+ traits_expression::traits_expression(const source_position position, identifier&& name,
std::vector<type_expression *>&& arguments)
- : node(position), arguments(std::move(arguments)), name(name)
+ : node(position), arguments(std::move(arguments)), name(std::move(name))
{
}
@@ -1247,7 +1279,7 @@ namespace elna::boot
}
}
- case_statement::case_statement(const struct position position,
+ case_statement::case_statement(const source_position position,
expression *condition, std::vector<switch_case>&& cases, std::vector<statement *> *alternative)
: node(position), m_condition(condition), cases(std::move(cases)), alternative(alternative)
{
@@ -1263,7 +1295,7 @@ namespace elna::boot
return *m_condition;
}
- assign_statement::assign_statement(const struct position position, designator_expression *lvalue,
+ assign_statement::assign_statement(const source_position position, designator_expression *lvalue,
expression *rvalue)
: node(position), m_lvalue(lvalue), m_rvalue(rvalue)
{
@@ -1309,7 +1341,7 @@ namespace elna::boot
delete m_rvalue;
}
- if_statement::if_statement(const struct position position, conditional_statements *branch,
+ if_statement::if_statement(const source_position position, conditional_statements *branch,
std::vector<conditional_statements *>&& branches,
std::vector<statement *> *alternative)
: node(position), m_branch(branch), branches(std::move(branches)), alternative(alternative)
@@ -1336,7 +1368,7 @@ namespace elna::boot
delete this->alternative;
}
- import_declaration::import_declaration(const struct position position, std::vector<std::string>&& segments)
+ import_declaration::import_declaration(const source_position position, std::vector<std::string>&& segments)
: node(position), segments(std::move(segments))
{
}
@@ -1346,7 +1378,7 @@ namespace elna::boot
visitor->visit(this);
}
- while_statement::while_statement(const struct position position, conditional_statements *branch,
+ while_statement::while_statement(const source_position position, conditional_statements *branch,
std::vector<conditional_statements *>&& branches)
: node(position), m_branch(branch), branches(std::move(branches))
{
diff --git a/boot/driver.cc b/boot/driver.cc
index b51da32..8dc95f8 100644
--- a/boot/driver.cc
+++ b/boot/driver.cc
@@ -19,14 +19,14 @@ along with GCC; see the file COPYING3. If not see
namespace elna::boot
{
- position make_position(const yy::location& location)
+ source_position make_position(const yy::location& location)
{
auto start_location = boot::location(static_cast<std::size_t>(location.begin.line),
static_cast<std::size_t>(location.begin.column));
auto end_location = boot::location(static_cast<std::size_t>(location.end.line),
static_cast<std::size_t>(location.end.column));
- return position(start_location, end_location);
+ return source_position(start_location, end_location);
}
syntax_error::syntax_error(const std::string& message, const yy::location& location)
diff --git a/boot/parser.yy b/boot/parser.yy
index 9f610ee..c34c905 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -153,14 +153,16 @@ along with GCC; see the file COPYING3. If not see
%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 <elna::boot::field_initializer> field_initializer;
+%type <std::unique_ptr<elna::boot::field_initializer>> field_initializer;
%type <std::vector<elna::boot::field_initializer>> field_initializers;
%type <std::vector<elna::boot::conditional_statements *>> elsif_then_statements elsif_do_statements;
%type <std::vector<elna::boot::statement *> *> else_statements;
%type <elna::boot::cast_expression *> cast_expression;
-%type <elna::boot::identifier_definition> identifier_definition;
+%type <std::unique_ptr<elna::boot::identifier>> identifier;
+%type <std::unique_ptr<elna::boot::identifier_definition>> identifier_definition;
%type <std::vector<elna::boot::identifier_definition>> identifier_definitions;
-%type <std::vector<std::string>> identifiers import_declaration;
+%type <std::vector<std::string>> import_declaration;
+%type <std::vector<elna::boot::identifier>> identifiers;
%type <std::vector<elna::boot::import_declaration *>> import_declarations import_part;
%%
program:
@@ -176,16 +178,18 @@ procedure_body:
statement_part:
/* no statements */ {}
| "begin" statements { $$ = $2; }
+identifier:
+ IDENTIFIER { $$ = std::make_unique<boot::identifier>($1, boot::make_position(@1)); }
identifier_definition:
- IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; }
- | IDENTIFIER { $$ = boot::identifier_definition{ $1, false }; }
+ IDENTIFIER "*" { $$ = std::make_unique<boot::identifier_definition>($1, boot::make_position(@1), true); }
+ | IDENTIFIER { $$ = std::make_unique<boot::identifier_definition>($1, boot::make_position(@1), false); }
identifier_definitions:
identifier_definition "," identifier_definitions
{
$$ = $3;
- $$.emplace($$.cbegin(), $1);
+ $$.emplace($$.cbegin(), std::move(*$1));
}
- | identifier_definition { $$.emplace_back($1); }
+ | identifier_definition { $$.emplace_back(std::move(*$1)); }
return_declaration:
/* proper procedure */ {}
| ":" "!" { $$ = boot::procedure_type_expression::return_t(std::monostate{}); }
@@ -195,11 +199,11 @@ procedure_heading: "(" optional_fields ")" return_declaration
procedure_declaration:
"proc" identifier_definition procedure_heading procedure_body
{
- $$ = new boot::procedure_declaration(boot::make_position(@$), $2, $3, std::move(*$4));
+ $$ = new boot::procedure_declaration(boot::make_position(@$), std::move(*$2), $3, std::move(*$4));
}
| "proc" identifier_definition procedure_heading "extern"
{
- $$ = new boot::procedure_declaration(boot::make_position(@$), $2, $3);
+ $$ = new boot::procedure_declaration(boot::make_position(@$), std::move(*$2), $3);
}
procedure_part:
/* no procedure declarations */ {}
@@ -247,7 +251,8 @@ literal:
traits_expression:
TRAIT "(" type_expressions ")"
{
- $$ = new boot::traits_expression(boot::make_position(@$), $1, $3);
+ $$ = new boot::traits_expression(boot::make_position(@$),
+ boot::identifier($1, boot::make_position(@1)), $3);
}
simple_expression:
literal { $$ = $1; }
@@ -256,9 +261,9 @@ simple_expression:
| cast_expression { $$ = $1; }
| call_expression { $$ = $1; }
| "(" expression ")" { $$ = $2; }
- | IDENTIFIER "{" field_initializers "}"
+ | identifier "{" field_initializers "}"
{
- $$ = new boot::record_constructor_expression(boot::make_position(@$), $1, $3);
+ $$ = new boot::record_constructor_expression(boot::make_position(@$), std::move(*$1), $3);
}
| "[" INTEGER "]" type_expression "{" expressions "}"
{
@@ -365,8 +370,8 @@ type_expressions:
designator_expression:
simple_expression "[" expression "]"
{ $$ = new boot::array_access_expression(boot::make_position(@$), $1, $3); }
- | simple_expression "." IDENTIFIER
- { $$ = new boot::field_access_expression(boot::make_position(@$), $1, $3); }
+ | simple_expression "." identifier
+ { $$ = new boot::field_access_expression(boot::make_position(@$), $1, std::move(*$3)); }
| simple_expression "^"
{ $$ = new boot::dereference_expression(boot::make_position(@$), $1); }
| IDENTIFIER
@@ -426,14 +431,14 @@ optional_fields:
required_fields { $$ = $1; }
| /* no fields */ {}
field_initializer:
- IDENTIFIER ":" expression { $$.name = $1; $$.value = $3; }
+ identifier ":" expression { $$ = std::make_unique<boot::field_initializer>(std::move(*$1), $3); }
field_initializers:
field_initializer "," field_initializers
{
$$ = $3;
- $$.emplace($$.cbegin(), $1);
+ $$.emplace($$.cbegin(), std::move(*$1));
}
- | field_initializer { $$.push_back($1); }
+ | field_initializer { $$.push_back(std::move(*$1)); }
type_expression:
"[" INTEGER "]" type_expression
{
@@ -447,9 +452,9 @@ type_expression:
{
$$ = new boot::record_type_expression(boot::make_position(@$), $2);
}
- | "record" "(" IDENTIFIER ")" optional_fields "end"
+ | "record" "(" identifier ")" optional_fields "end"
{
- $$ = new boot::record_type_expression(boot::make_position(@$), $5, $3);
+ $$ = new boot::record_type_expression(boot::make_position(@$), $5, std::move(*$3));
}
| "proc" procedure_heading
{
@@ -464,12 +469,12 @@ type_expression:
$$ = new boot::named_expression(boot::make_position(@$), $1);
}
identifiers:
- IDENTIFIER "," identifiers
+ identifier "," identifiers
{
$$ = $3;
- $$.emplace($$.cbegin(), $1);
+ $$.emplace($$.cbegin(), std::move(*$1));
}
- | IDENTIFIER { $$.emplace_back($1); }
+ | identifier { $$.emplace_back(std::move(*$1)); }
variable_declaration:
identifier_definitions ":" type_expression
{
@@ -498,7 +503,7 @@ variable_part:
| "var" variable_declarations { $$ = $2; }
constant_declaration: identifier_definition ":=" expression
{
- $$ = new boot::constant_declaration(boot::make_position(@$), $1, $3);
+ $$ = new boot::constant_declaration(boot::make_position(@$), std::move(*$1), $3);
}
constant_declarations:
constant_declaration constant_declarations
@@ -532,7 +537,7 @@ import_part:
| "import" import_declarations { $$ = $2; }
type_declaration: identifier_definition "=" type_expression
{
- $$ = new boot::type_declaration(boot::make_position(@$), $1, $3);
+ $$ = new boot::type_declaration(boot::make_position(@$), std::move(*$1), $3);
}
type_declarations:
type_declaration type_declarations
diff --git a/boot/result.cc b/boot/result.cc
index 90d0ad6..5f3c516 100644
--- a/boot/result.cc
+++ b/boot/result.cc
@@ -19,22 +19,57 @@ along with GCC; see the file COPYING3. If not see
namespace elna::boot
{
- location::location(std::size_t line, std::size_t column)
- : line(line), column(column)
+ location::location(const std::size_t line, const std::size_t column)
+ : m_line(line), m_column(column)
{
}
+ std::size_t location::line() const
+ {
+ return this->m_line;
+ }
+
+ std::size_t location::column() const
+ {
+ return this->m_column;
+ }
+
bool location::available() const
{
- return this->line != 0 || this->column != 0;
+ return this->m_line != 0 || this->m_column != 0;
+ }
+
+ bool location::operator==(const location& that) const
+ {
+ return this->m_line == that.m_line && this->m_column == that.m_column;
+ }
+
+ bool location::operator!=(const location& that) const
+ {
+ return !(*this == that);
}
- position::position(location start, location end)
- : start(start), end(end)
+ source_position::source_position(location start, location end)
+ : m_start(start), m_end(end)
{
}
- error::error(const struct position position)
+ const location& source_position::start() const
+ {
+ return this->m_start;
+ }
+
+ const location& source_position::end() const
+ {
+ return this->m_end;
+ }
+
+ bool source_position::is_span() const
+ {
+ return this->m_start != this->m_end;
+ }
+
+ error::error(const source_position position)
: position(position)
{
}
@@ -49,19 +84,65 @@ namespace elna::boot
return !m_errors.empty();
}
- bool identifier_definition::operator==(const identifier_definition& that) const
+ identifier::identifier(const std::string& name, const source_position& position)
+ : m_name(name), m_position(position)
+ {
+ }
+
+ const std::string& identifier::name() const
+ {
+ return this->m_name;
+ }
+
+ const source_position& identifier::position() const
+ {
+ return this->m_position;
+ }
+
+ bool identifier::operator==(const identifier& that) const
+ {
+ return this->m_name == that.m_name;
+ }
+
+ bool identifier::operator!=(const identifier& that) const
+ {
+ return !(*this == that);
+ }
+
+ bool identifier::operator==(const std::string& that) const
+ {
+ return this->m_name == that;
+ }
+
+ bool identifier::operator!=(const std::string& that) const
+ {
+ return !(*this == that);
+ }
+
+ identifier_definition::identifier_definition(const std::string& name,
+ const source_position& position, const bool exported)
+ : m_identifier(name, position), m_exported(exported)
+ {
+ }
+
+ const std::string& identifier_definition::name() const
+ {
+ return this->m_identifier.name();
+ }
+
+ const identifier& identifier_definition::id() const
{
- return *this == that.name;
+ return this->m_identifier;
}
- bool identifier_definition::operator==(const std::string& that) const
+ bool identifier_definition::exported() const
{
- return this->name == that;
+ return this->m_exported;
}
}
-std::size_t std::hash<elna::boot::identifier_definition>::operator()(
- const elna::boot::identifier_definition& key) const
+std::size_t std::hash<elna::boot::identifier>::operator()(
+ const elna::boot::identifier& key) const
{
- return std::hash<std::string>{}(key.name);
+ return std::hash<std::string>{}(key.name());
}
diff --git a/boot/semantic.cc b/boot/semantic.cc
index dd9022b..031adfc 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -22,8 +22,8 @@ along with GCC; see the file COPYING3. If not see
namespace elna::boot
{
declaration_error::declaration_error(const kind error_kind,
- const std::string& identifier, const struct position position)
- : error(position), identifier(identifier), error_kind(error_kind)
+ const boot::identifier& identifier)
+ : error(identifier.position()), identifier(identifier.name()), error_kind(error_kind)
{
}
@@ -33,8 +33,6 @@ namespace elna::boot
{
case kind::undeclared:
return "Type '" + identifier + "' not declared";
- case kind::already:
- return "Symbol '" + identifier + "' has been already declared";
case kind::local_export:
return "Local symbol '" + this->identifier + "' cannot be exported";
default:
@@ -42,38 +40,107 @@ namespace elna::boot
}
}
- type_expectation_error::type_expectation_error(const kind error_kind, const struct position position)
- : error(position), error_kind(error_kind)
+ redefinition_error::redefinition_error(const boot::identifier& identifier,
+ std::optional<source_position> original)
+ : error(identifier.position()), identifier(identifier.name()), original(original)
{
}
- std::string type_expectation_error::what() const
+ std::string redefinition_error::what() const
{
- switch (this->error_kind)
+ return "Symbol '" + identifier + "' has been already defined";
+ }
+
+ std::optional<std::pair<std::string, source_position>>
+ redefinition_error::note() const
+ {
+ if (original.has_value() && original->start().available())
{
- case kind::assignment:
- return "Assinging an incompatible type";
- case kind::result:
- return "Procedure return type and type of the return expression are not compatible";
- case kind::argument:
- return "Argument type does not match parameter";
- default:
- __builtin_unreachable();
+ return std::make_pair("previously declared here", *original);
+ }
+ return std::nullopt;
+ }
+
+ type_mismatch_error::type_mismatch_error(const source_position position,
+ type expected, type actual)
+ : error(position), expected(expected), actual(actual)
+ {
+ }
+
+ std::string type_mismatch_error::what() const
+ {
+ return "Expected type '" + expected.to_string()
+ + "', but got '" + actual.to_string() + "'";
+ }
+
+ 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)
+ {
+ }
+
+ std::string field_not_found_error::what() const
+ {
+ type resolved = inner_aliased_type(composite_type);
+ bool is_enum = resolved.get<enumeration_type>() != nullptr;
+ bool is_record = resolved.get<record_type>() != nullptr;
+
+ if (is_enum || is_record)
+ {
+ std::string message = is_enum ? "Enumeration" : "Record";
+
+ if (auto alias = composite_type.get<alias_type>())
+ {
+ message += " '" + alias->name + "'";
+ }
+ message += " does not have a ";
+ message += is_enum ? "member" : "field";
+ message += " named '" + field_name + "'";
+ return message;
}
+ return "Type '" + composite_type.to_string()
+ + "' does not have a field named '" + field_name + "'";
}
- field_duplication_error::field_duplication_error(const std::string& field_name, const struct position position)
- : error(position), field_name(field_name)
+ duplicate_member_error::duplicate_member_error(const boot::identifier& member_name,
+ type aggregate, std::optional<source_position> original,
+ std::optional<std::string> base_name)
+ : error(member_name.position()), member_name(member_name.name()), aggregate(aggregate),
+ original(original), base_name(base_name)
{
}
- std::string field_duplication_error::what() const
+ std::string duplicate_member_error::what() const
{
- return "Repeated field name '" + field_name + "'";
+ type resolved = inner_aliased_type(aggregate);
+ bool is_enum = resolved.get<enumeration_type>() != nullptr;
+ std::string kind = is_enum ? "member" : "field";
+ std::string message = is_enum ? "Enumeration" : "Record";
+
+ if (auto alias = aggregate.get<alias_type>())
+ {
+ message += " '" + alias->name + "'";
+ }
+ message += " already has a " + kind + " named '" + member_name + "'";
+
+ if (base_name.has_value())
+ {
+ message += " (defined in base type '" + *base_name + "')";
+ }
+ return message;
+ }
+
+ std::optional<std::pair<std::string, source_position>> duplicate_member_error::note() const
+ {
+ if (original.has_value() && original->start().available())
+ {
+ return std::make_pair("previously declared here", *original);
+ }
+ return std::nullopt;
}
cyclic_declaration_error::cyclic_declaration_error(const std::vector<std::string>& cycle,
- const struct position position)
+ const source_position position)
: error(position), cycle(cycle)
{
}
@@ -91,28 +158,36 @@ namespace elna::boot
return message;
}
- return_error::return_error(const std::string& identifier, const struct position position)
- : error(position), identifier(identifier)
+ return_error::return_error(const std::string& identifier, const source_position position,
+ type return_type)
+ : error(position), identifier(identifier), return_type(return_type)
{
}
std::string return_error::what() const
{
- return "Procedure '" + this->identifier + "' is expected to return, but does not have a return statement";
+ if (!return_type.empty())
+ {
+ return "Procedure '" + this->identifier
+ + "' does not return a value, but return expression has type '"
+ + return_type.to_string() + "'";
+ }
+ 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)
+ base_type_error::base_type_error(type actual, const source_position position)
+ : error(position), actual(actual)
{
}
std::string base_type_error::what() const
{
- return "Record base type '" + this->base + "' is not a record.";
+ return "'" + actual.to_string() + "' is not a record type";
}
argument_count_error::argument_count_error(std::size_t expected, std::size_t actual,
- const struct position position)
+ const source_position position)
: error(position), expected(expected), actual(actual)
{
}
@@ -138,7 +213,7 @@ namespace elna::boot
void type_analysis_visitor::visit(procedure_declaration *declaration)
{
- this->current_procedure = this->bag.lookup(declaration->identifier.name)->is_procedure();
+ this->current_procedure = this->bag.lookup(declaration->identifier.name())->is_procedure();
if (declaration->body.has_value())
{
@@ -157,17 +232,19 @@ namespace elna::boot
{
if (!is_assignable_from(return_type, return_expr->type_decoration))
{
- add_error<type_expectation_error>(type_expectation_error::kind::result, return_expr->position());
+ add_error<type_mismatch_error>(
+ return_expr->position(), return_type, return_expr->type_decoration);
}
}
else
{
- add_error<type_expectation_error>(type_expectation_error::kind::result, return_expr->position());
+ add_error<return_error>(declaration->identifier.name(),
+ return_expr->position(), return_expr->type_decoration);
}
}
else if (declaration->heading().return_type.proper_type != nullptr)
{
- add_error<return_error>(declaration->identifier.name, declaration->position());
+ add_error<return_error>(declaration->identifier.name(), declaration->position());
}
this->bag.leave();
}
@@ -185,7 +262,8 @@ namespace elna::boot
if (!is_assignable_from(statement->lvalue().type_decoration, statement->rvalue().type_decoration))
{
- add_error<type_expectation_error>(type_expectation_error::kind::assignment, statement->position());
+ add_error<type_mismatch_error>(statement->position(),
+ statement->lvalue().type_decoration, statement->rvalue().type_decoration);
}
}
@@ -199,11 +277,12 @@ namespace elna::boot
}
for (const identifier_definition& variable_identifier : declaration->identifiers)
{
- auto variable_symbol = this->bag.lookup(variable_identifier.name)->is_variable();
+ auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable();
if (!is_assignable_from(variable_symbol->symbol, declaration->initializer->type_decoration))
{
- add_error<type_expectation_error>(type_expectation_error::kind::assignment,
- declaration->initializer->position());
+ add_error<type_mismatch_error>(
+ declaration->initializer->position(),
+ variable_symbol->symbol, declaration->initializer->type_decoration);
}
}
}
@@ -219,8 +298,8 @@ namespace elna::boot
{
if (!is_assignable_from(condition_type, case_label->type_decoration))
{
- add_error<type_expectation_error>(type_expectation_error::kind::assignment,
- case_label->position());
+ add_error<type_mismatch_error>(
+ case_label->position(), condition_type, case_label->type_decoration);
}
}
}
@@ -245,7 +324,7 @@ namespace elna::boot
void type_analysis_visitor::visit(type_declaration *declaration)
{
std::vector<std::string> alias_path;
- auto unresolved_type = this->bag.lookup(declaration->identifier.name)->is_type()->symbol.get<alias_type>();
+ auto unresolved_type = this->bag.lookup(declaration->identifier.name())->is_type()->symbol.get<alias_type>();
if (!check_unresolved_symbol(unresolved_type, alias_path))
{
@@ -261,10 +340,10 @@ namespace elna::boot
{
if (expression->base.has_value())
{
- type base_type = inner_aliased_type(this->bag.lookup(expression->base.value())->is_type()->symbol);
+ type base_type = inner_aliased_type(this->bag.lookup(expression->base.value().name())->is_type()->symbol);
if (base_type.get<record_type>() == nullptr)
{
- add_error<base_type_error>(expression->base.value(), expression->position());
+ add_error<base_type_error>(base_type, expression->position());
}
}
walking_visitor::visit(expression);
@@ -285,8 +364,9 @@ namespace elna::boot
(*argument_iterator)->accept(this);
if (!is_assignable_from(*type_iterator, (*argument_iterator)->type_decoration))
{
- add_error<type_expectation_error>(type_expectation_error::kind::argument,
- (*argument_iterator)->position());
+ add_error<type_mismatch_error>(
+ (*argument_iterator)->position(), *type_iterator,
+ (*argument_iterator)->type_decoration);
}
++argument_iterator;
++type_iterator;
@@ -305,19 +385,22 @@ namespace elna::boot
if (record == nullptr)
{
- add_error<type_expectation_error>(type_expectation_error::kind::result, expression->position());
+ add_error<type_mismatch_error>(
+ expression->position(), type(std::make_shared<record_type>()),
+ expression->type_decoration);
return;
}
for (const field_initializer& initializer : expression->field_initializers)
{
for (const type_field& field : record->fields)
{
- if (field.first == initializer.name)
+ if (field.first == initializer.name())
{
- if (!is_assignable_from(field.second, initializer.value->type_decoration))
+ if (!is_assignable_from(field.second, initializer.value().type_decoration))
{
- add_error<type_expectation_error>(type_expectation_error::kind::argument,
- initializer.value->position());
+ add_error<type_mismatch_error>(
+ initializer.value().position(), field.second,
+ initializer.value().type_decoration);
}
break;
}
@@ -331,7 +414,9 @@ namespace elna::boot
if (array == nullptr)
{
- add_error<type_expectation_error>(type_expectation_error::kind::result, expression->position());
+ add_error<type_mismatch_error>(
+ expression->position(), type(std::make_shared<array_type>(type(), 0)),
+ expression->type_decoration);
return;
}
if (expression->elements.size() > array->size)
@@ -344,8 +429,8 @@ namespace elna::boot
{
if (!is_assignable_from(array->base, element->type_decoration))
{
- add_error<type_expectation_error>(type_expectation_error::kind::argument,
- element->position());
+ add_error<type_mismatch_error>(
+ element->position(), array->base, element->type_decoration);
}
}
}
@@ -382,7 +467,7 @@ namespace elna::boot
for (auto& parameter_name : parameter_names)
{
result_type.first.parameters.push_back(this->current_type);
- result_type.second.push_back(parameter_name);
+ result_type.second.push_back(parameter_name.name());
}
}
return result_type;
@@ -468,11 +553,12 @@ namespace elna::boot
void name_analysis_visitor::visit(type_declaration *declaration)
{
walking_visitor::visit(declaration);
- auto resolved = this->bag.resolve(declaration->identifier.name, this->current_type);
+ auto resolved = this->bag.resolve(declaration->identifier.name(), this->current_type);
auto info = std::make_shared<type_info>(type(resolved));
- info->exported = declaration->identifier.exported;
- this->bag.enter(declaration->identifier.name, info);
+ info->exported = declaration->identifier.exported();
+ info->position.emplace(declaration->position());
+ this->bag.enter(declaration->identifier.name(), info);
}
void name_analysis_visitor::visit(pointer_type_expression *expression)
@@ -492,7 +578,8 @@ namespace elna::boot
/**
* Collects field names from a record type recursively, base first.
*/
- static void collect_field_names(const type& composite_type, std::set<std::string>& names)
+ 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>();
if (record == nullptr)
@@ -505,12 +592,14 @@ namespace elna::boot
}
for (auto& field : record->fields)
{
- names.insert(field.first);
+ names.insert({ field.first, field_origin{ std::nullopt, composite_type } });
}
}
std::vector<type_field> name_analysis_visitor::build_composite_type(
- const std::vector<field_declaration>& fields, std::set<std::string>& field_names)
+ const std::vector<field_declaration>& fields,
+ std::map<std::string, field_origin>& field_names,
+ type aggregate)
{
std::vector<type_field> result;
@@ -519,13 +608,27 @@ namespace elna::boot
field.second->accept(this);
for (auto& field_name : field.first)
{
- if (!field_names.insert(field_name).second)
+ auto existing = field_names.find(field_name.name());
+ if (existing != field_names.end())
{
- add_error<field_duplication_error>(field_name, field.second->position());
+ std::optional<std::string> base_name;
+
+ if (!existing->second.declaration.has_value()
+ && !existing->second.base_type.empty())
+ {
+ if (auto alias = existing->second.base_type.get<alias_type>())
+ {
+ base_name = alias->name;
+ }
+ }
+ add_error<duplicate_member_error>(field_name, aggregate,
+ existing->second.declaration, base_name);
}
else
{
- result.push_back(std::make_pair(field_name, this->current_type));
+ field_names.insert({ field_name.name(),
+ field_origin{ field.second->position(), type() } });
+ result.push_back(std::make_pair(field_name.name(), this->current_type));
}
}
}
@@ -537,11 +640,11 @@ namespace elna::boot
std::shared_ptr<record_type> result_type;
if (expression->base.has_value())
{
- if (auto unresolved_alias = this->bag.declared(expression->base.value()))
+ if (auto unresolved_alias = this->bag.declared(expression->base.value().name()))
{
result_type = std::make_shared<record_type>(type(unresolved_alias));
}
- else if (auto base_symbol = this->bag.lookup(expression->base.value()))
+ else if (auto base_symbol = this->bag.lookup(expression->base.value().name()))
{
if (auto base_type_info = base_symbol->is_type())
{
@@ -549,7 +652,17 @@ namespace elna::boot
}
else
{
- add_error<base_type_error>(expression->base.value(), expression->position());
+ type actual;
+
+ if (auto var = base_symbol->is_variable())
+ {
+ actual = var->symbol;
+ }
+ else if (auto proc = base_symbol->is_procedure())
+ {
+ actual = type(std::make_shared<procedure_type>(proc->symbol));
+ }
+ add_error<base_type_error>(actual, expression->position());
this->current_type = type();
return;
}
@@ -557,7 +670,7 @@ namespace elna::boot
else
{
add_error<declaration_error>(declaration_error::kind::undeclared,
- expression->base.value(), expression->position());
+ expression->base.value());
this->current_type = type();
return;
}
@@ -567,30 +680,35 @@ namespace elna::boot
result_type = std::make_shared<record_type>();
}
- std::set<std::string> field_names;
+ std::map<std::string, field_origin> field_names;
collect_field_names(result_type->base, field_names);
- result_type->fields = build_composite_type(expression->fields, field_names);
+ result_type->fields = build_composite_type(expression->fields, field_names, type(result_type));
this->current_type = type(result_type);
}
void name_analysis_visitor::visit(record_constructor_expression *expression)
{
- if (auto type_symbol = this->bag.lookup(expression->type_name))
+ if (auto type_symbol = this->bag.lookup(expression->type_name.name()))
{
if (auto type_info = type_symbol->is_type())
{
expression->type_decoration = type_info->symbol;
}
}
+ else
+ {
+ add_error<declaration_error>(declaration_error::kind::undeclared,
+ expression->type_name);
+ }
for (const field_initializer& initializer : expression->field_initializers)
{
- initializer.value->accept(this);
+ initializer.value().accept(this);
if (!expression->type_decoration.empty()
- && lookup_field(expression->type_decoration, initializer.name).empty())
+ && lookup_field(expression->type_decoration, initializer.name()).empty())
{
add_error<declaration_error>(declaration_error::kind::undeclared,
- initializer.name, expression->position());
+ initializer.id());
}
}
}
@@ -616,19 +734,42 @@ namespace elna::boot
void name_analysis_visitor::visit(enumeration_type_expression *expression)
{
- std::shared_ptr<enumeration_type> result_type = std::make_shared<enumeration_type>(expression->members);
+ std::vector<std::string> member_names;
+ for (auto& member : expression->members)
+ {
+ member_names.emplace_back(member.name());
+ }
+ std::shared_ptr<enumeration_type> result_type = std::make_shared<enumeration_type>(
+ member_names);
+ std::map<std::string, source_position> seen;
+ type aggregate(result_type);
+ for (auto& member : expression->members)
+ {
+ auto existing = seen.find(member.name());
+ if (existing != seen.end())
+ {
+ add_error<duplicate_member_error>(member, aggregate, existing->second);
+ }
+ else
+ {
+ seen.insert({ member.name(), member.position() });
+ }
+ }
this->current_type = type(result_type);
}
std::shared_ptr<variable_info> name_analysis_visitor::register_variable(const std::string& name,
- const bool is_extern, const struct position position)
+ const bool is_extern, const source_position position)
{
auto variable_symbol = std::make_shared<variable_info>(this->current_type, is_extern);
+ variable_symbol->position.emplace(position);
if (!this->bag.enter(name, variable_symbol))
{
- add_error<declaration_error>(declaration_error::kind::already, name, position);
+ auto original = this->bag.lookup(name);
+ add_error<redefinition_error>(boot::identifier(name, position),
+ original->position);
}
return variable_symbol;
}
@@ -644,9 +785,9 @@ namespace elna::boot
}
for (const identifier_definition& variable_identifier : declaration->identifiers)
{
- auto variable_symbol = register_variable(variable_identifier.name, declaration->is_extern,
+ auto variable_symbol = register_variable(variable_identifier.name(), declaration->is_extern,
declaration->position());
- variable_symbol->exported = variable_identifier.exported;
+ variable_symbol->exported = variable_identifier.exported();
}
}
@@ -655,8 +796,9 @@ namespace elna::boot
walking_visitor::visit(declaration);
auto constant_symbol = std::make_shared<constant_info>(this->current_literal);
- constant_symbol->exported = declaration->identifier.exported;
- this->bag.enter(declaration->identifier.name, constant_symbol);
+ 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)
@@ -701,8 +843,9 @@ namespace elna::boot
{
info = std::make_shared<procedure_info>(heading, std::move(parameter_names));
}
- info->exported = declaration->identifier.exported;
- this->bag.enter(declaration->identifier.name, info);
+ info->exported = declaration->identifier.exported();
+ info->position.emplace(declaration->position());
+ this->bag.enter(declaration->identifier.name(), info);
}
void name_analysis_visitor::visit(procedure_call *call)
@@ -775,6 +918,11 @@ namespace elna::boot
{
trait->type_decoration = trait->types.empty() ? type() : trait->types.front();
}
+ else
+ {
+ add_error<declaration_error>(declaration_error::kind::undeclared,
+ trait->name);
+ }
}
void name_analysis_visitor::visit(binary_expression *expression)
@@ -841,13 +989,18 @@ namespace elna::boot
void name_analysis_visitor::visit(field_access_expression *expression)
{
walking_visitor::visit(expression);
- expression->type_decoration = lookup_field(expression->base().type_decoration, expression->field());
+ expression->type_decoration = lookup_field(expression->base().type_decoration, expression->field().name());
auto is_designator = expression->base().is_designator();
if (expression->type_decoration.empty() && is_designator != nullptr && is_designator->is_named() != nullptr)
{
expression->type_decoration = this->current_type;
}
+ if (expression->type_decoration.empty())
+ {
+ add_error<field_not_found_error>(expression->field(),
+ expression->base().type_decoration);
+ }
}
void name_analysis_visitor::visit(dereference_expression *expression)
@@ -896,7 +1049,7 @@ namespace elna::boot
else
{
add_error<declaration_error>(declaration_error::kind::undeclared,
- expression->name, expression->position());
+ boot::identifier(expression->name, expression->position()));
}
}
@@ -969,12 +1122,12 @@ namespace elna::boot
void declaration_visitor::visit(type_declaration *declaration)
{
- const std::string& type_identifier = declaration->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<declaration_error>(declaration_error::kind::already,
- declaration->identifier.name, declaration->position());
+ add_error<redefinition_error>(declaration->identifier.id(),
+ declaration->position());
}
}
@@ -998,20 +1151,20 @@ namespace elna::boot
{
for (const identifier_definition& variable_identifier : declaration->identifiers)
{
- if (variable_identifier.exported)
+ if (variable_identifier.exported())
{
add_error<declaration_error>(declaration_error::kind::local_export,
- variable_identifier.name, declaration->position());
+ variable_identifier.id());
}
}
}
void declaration_visitor::visit(constant_declaration *declaration)
{
- if (declaration->identifier.exported)
+ if (declaration->identifier.exported())
{
add_error<declaration_error>(declaration_error::kind::local_export,
- declaration->identifier.name, declaration->position());
+ declaration->identifier.id());
}
}
diff --git a/boot/symbol.cc b/boot/symbol.cc
index d7ceacb..a3a36c1 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -270,6 +270,54 @@ namespace elna::boot
return tag == type_tag::empty;
}
+ std::string type::to_string() const
+ {
+ switch (tag)
+ {
+ case type_tag::empty:
+ return "<empty>";
+ case type_tag::alias:
+ return alias.lock()->name;
+ case type_tag::primitive:
+ return primitive->identifier;
+ case type_tag::pointer:
+ return "^" + pointer->base.to_string();
+ case type_tag::array:
+ return "[" + std::to_string(array->size) + "]" + array->base.to_string();
+ case type_tag::record:
+ if (record->base.empty())
+ {
+ return "record ... end";
+ }
+ else
+ {
+ return "record(" + record->base.to_string() + ") ... end";
+ }
+ case type_tag::procedure:
+ {
+ std::string result = "proc(";
+ for (std::size_t i = 0; i < procedure->parameters.size(); ++i)
+ {
+ if (i > 0) result += ", ";
+ result += procedure->parameters[i].to_string();
+ }
+ result += ")";
+ if (procedure->return_type.no_return)
+ {
+ result += ": !";
+ }
+ else if (!procedure->return_type.proper_type.empty())
+ {
+ result += ": " + procedure->return_type.proper_type.to_string();
+ }
+ return result;
+ }
+ case type_tag::enumeration:
+ return "(enumeration)";
+ }
+ __builtin_unreachable();
+ }
+
alias_type::alias_type(const std::string& name)
: name(name), reference()
{