aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--gcc/gcc/elna-diagnostic.cc38
-rw-r--r--gcc/gcc/elna-generic.cc45
-rw-r--r--include/elna/boot/ast.h117
-rw-r--r--include/elna/boot/driver.h2
-rw-r--r--include/elna/boot/result.h97
-rw-r--r--include/elna/boot/semantic.h112
-rw-r--r--include/elna/boot/symbol.h7
-rw-r--r--include/elna/gcc/elna-diagnostic.h4
14 files changed, 770 insertions, 337 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()
{
diff --git a/gcc/gcc/elna-diagnostic.cc b/gcc/gcc/elna-diagnostic.cc
index f7b660d..3769ee4 100644
--- a/gcc/gcc/elna-diagnostic.cc
+++ b/gcc/gcc/elna-diagnostic.cc
@@ -38,27 +38,31 @@ namespace elna::gcc
linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
}
- location_t get_location(const boot::position *position)
+ location_t get_location(const boot::source_position *position)
{
- linemap_line_start(line_table, position->start.line, 0);
+ linemap_line_start(line_table, position->start().line(), 0);
- return linemap_position_for_column(line_table, position->start.column);
+ return linemap_position_for_column(line_table, position->start().column());
}
- void fill_range(const boot::position& position, location_t& start, location_t& end)
+ location_t make_range(const boot::source_position& position)
{
- linemap_line_start(line_table, position.start.line, 0);
- start = linemap_position_for_column(line_table, position.start.column);
+ linemap_line_start(line_table, position.start().line(), 0);
+ location_t caret = linemap_position_for_column(line_table, position.start().column());
+ location_t start = caret;
+ location_t end;
- if (position.start.line != position.end.line || position.start.column != position.end.column)
+ if (position.is_span())
{
- linemap_line_start(line_table, position.end.line, 0);
- end = linemap_position_for_column(line_table, position.end.column);
+ linemap_line_start(line_table, position.end().line(), 0);
+ end = linemap_position_for_column(line_table, position.end().column());
}
else
{
end = start;
}
+
+ return make_location(caret, start, end);
}
std::string print_aggregate_name(tree type, const std::string& kind_name)
@@ -174,18 +178,20 @@ namespace elna::gcc
{
for (const auto& error : errors)
{
- if (error->position.start.available())
+ if (error->position.start().available())
{
- location_t start, end;
- fill_range(error->position, start, end);
- rich_location rich_loc(line_table, start);
- rich_loc.add_range(end);
- error_at(&rich_loc, error->what().c_str());
+ location_t loc = make_range(error->position);
+ error_at(loc, "%s", error->what().c_str());
}
else
{
location_t gcc_location{ UNKNOWN_LOCATION };
- error_at(gcc_location, error->what().c_str());
+ error_at(gcc_location, "%s", error->what().c_str());
+ }
+ if (auto note = error->note())
+ {
+ location_t note_loc = make_range(note->second);
+ inform(note_loc, "%s", note->first.c_str());
}
}
}
diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc
index 18d31d6..aace38b 100644
--- a/gcc/gcc/elna-generic.cc
+++ b/gcc/gcc/elna-generic.cc
@@ -180,12 +180,10 @@ namespace elna::gcc
void generic_visitor::visit(boot::record_constructor_expression *expression)
{
- tree type_decl = this->symbols->lookup(expression->type_name);
+ tree type_decl = this->symbols->lookup(expression->type_name.name());
if (type_decl == NULL_TREE)
{
- error_at(get_location(&expression->position()), "Type '%s' not declared",
- expression->type_name.c_str());
this->current_expression = error_mark_node;
return;
}
@@ -195,8 +193,8 @@ namespace elna::gcc
for (const boot::field_initializer& initializer : expression->field_initializers)
{
tree field_decl = find_field_by_name(get_location(&expression->position()),
- record_type, initializer.name);
- initializer.value->accept(this);
+ record_type, initializer.name());
+ initializer.value().accept(this);
CONSTRUCTOR_APPEND_ELT(tree_arguments, field_decl, this->current_expression);
}
this->current_expression = build_constructor(record_type, tree_arguments);
@@ -294,7 +292,7 @@ namespace elna::gcc
void generic_visitor::visit(boot::procedure_declaration *declaration)
{
- tree fndecl = this->symbols->lookup(declaration->identifier.name);
+ tree fndecl = this->symbols->lookup(declaration->identifier.name());
if (!declaration->body.has_value())
{
@@ -304,7 +302,7 @@ namespace elna::gcc
DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
enter_scope();
- this->bag.enter(this->bag.lookup(declaration->identifier.name)->is_procedure()->scope);
+ this->bag.enter(this->bag.lookup(declaration->identifier.name())->is_procedure()->scope);
tree argument_chain = DECL_ARGUMENTS(fndecl);
for (; argument_chain != NULL_TREE; argument_chain = TREE_CHAIN(argument_chain))
@@ -712,15 +710,15 @@ namespace elna::gcc
return;
}
tree definition_tree = build_decl(definition_location, CONST_DECL,
- get_identifier(declaration->identifier.name.c_str()), TREE_TYPE(this->current_expression));
- auto result = this->symbols->enter(declaration->identifier.name, definition_tree);
+ get_identifier(declaration->identifier.name().c_str()), TREE_TYPE(this->current_expression));
+ auto result = this->symbols->enter(declaration->identifier.name(), definition_tree);
if (result)
{
DECL_INITIAL(definition_tree) = this->current_expression;
TREE_CONSTANT(definition_tree) = 1;
TREE_READONLY(definition_tree) = 1;
- TREE_PUBLIC(definition_tree) = declaration->identifier.exported;
+ TREE_PUBLIC(definition_tree) = declaration->identifier.exported();
if (!lang_hooks.decls.global_bindings_p())
{
@@ -729,11 +727,6 @@ namespace elna::gcc
append_statement(declaration_statement);
}
}
- else
- {
- error_at(definition_location, "Variable '%s' already declared in this scope",
- declaration->identifier.name.c_str());
- }
this->current_expression = NULL_TREE;
}
@@ -742,13 +735,13 @@ namespace elna::gcc
for (const auto& variable_identifier : declaration->identifiers)
{
location_t declaration_location = get_location(&declaration->position());
- tree declaration_tree = this->symbols->lookup(variable_identifier.name);
+ tree declaration_tree = this->symbols->lookup(variable_identifier.name());
if (declaration_tree == NULL_TREE)
{
- auto variable_symbol = this->bag.lookup(variable_identifier.name)->is_variable();
+ auto variable_symbol = this->bag.lookup(variable_identifier.name())->is_variable();
- declaration_tree = declare_variable(variable_identifier.name, *variable_symbol, this->symbols);
+ declaration_tree = declare_variable(variable_identifier.name(), *variable_symbol, this->symbols);
}
// Set initializer if given.
if (declaration->initializer != nullptr)
@@ -764,7 +757,7 @@ namespace elna::gcc
if (lang_hooks.decls.global_bindings_p())
{
- TREE_STATIC(declaration_tree) = !variable_identifier.exported && !declaration->is_extern;
+ TREE_STATIC(declaration_tree) = !variable_identifier.exported() && !declaration->is_extern;
varpool_node::get_create(declaration_tree);
varpool_node::finalize_decl(declaration_tree);
}
@@ -786,8 +779,6 @@ namespace elna::gcc
if (symbol == NULL_TREE)
{
- error_at(get_location(&expression->position()), "Symbol '%s' not declared in the current scope",
- expression->name.c_str());
this->current_expression = error_mark_node;
}
else
@@ -843,7 +834,7 @@ namespace elna::gcc
if (trait->arguments.size() != 1)
{
error_at(get_location(&trait->position()), "Trait '%s' expects 1 argument, got %lu",
- trait->name.c_str(), trait->arguments.size());
+ trait->name.name().c_str(), trait->arguments.size());
this->current_expression = error_mark_node;
return false;
}
@@ -861,7 +852,7 @@ namespace elna::gcc
else if (!is_integral_type(this->current_expression) && TREE_CODE(this->current_expression) != ENUMERAL_TYPE)
{
error_at(get_location(&trait->position()), "Type '%s' does not support trait '%s'",
- print_type(this->current_expression).c_str(), trait->name.c_str());
+ print_type(this->current_expression).c_str(), trait->name.name().c_str());
this->current_expression = error_mark_node;
return false;
}
@@ -907,7 +898,7 @@ namespace elna::gcc
if (trait->arguments.size() != 2)
{
error_at(trait_location, "Trait '%s' expects 2 arguments, got %lu",
- trait->name.c_str(), trait->arguments.size());
+ trait->name.name().c_str(), trait->arguments.size());
this->current_expression = error_mark_node;
return;
}
@@ -936,7 +927,6 @@ namespace elna::gcc
}
else
{
- error_at(get_location(&trait->position()), "Trait '%s' is unknown", trait->name.c_str());
this->current_expression = error_mark_node;
}
}
@@ -964,19 +954,18 @@ namespace elna::gcc
for (iterator = TYPE_VALUES(aggregate_type); iterator != NULL_TREE; iterator = TREE_CHAIN(iterator))
{
- if (IDENTIFIER_POINTER(TREE_PURPOSE(iterator)) == expression->field())
+ if (IDENTIFIER_POINTER(TREE_PURPOSE(iterator)) == expression->field().name())
{
this->current_expression = TREE_VALUE(iterator);
return;
}
}
this->current_expression = error_mark_node;
- error_at(expression_location, "Unknown enumeration member '%s'", expression->field().c_str());
}
else
{
tree field_declaration = find_field_by_name(expression_location,
- TREE_TYPE(this->current_expression), expression->field());
+ TREE_TYPE(this->current_expression), expression->field().name());
if (field_declaration != error_mark_node)
{
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 6a5f32d..b6aad70 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -62,7 +62,6 @@ namespace elna::boot
class cast_expression;
class record_constructor_expression;
class array_constructor_expression;
- struct field_initializer;
class assign_statement;
class if_statement;
class import_declaration;
@@ -224,13 +223,13 @@ namespace elna::boot
*/
class node
{
- const struct position source_position;
+ const source_position m_position;
protected:
/**
* \param position Source code position.
*/
- explicit node(const position position);
+ explicit node(const source_position position);
public:
virtual void accept(parser_visitor *visitor) = 0;
@@ -239,7 +238,7 @@ namespace elna::boot
/**
* \return Node position in the source code.
*/
- const struct position& position() const;
+ const source_position& position() const;
};
class statement : public virtual node
@@ -266,7 +265,7 @@ namespace elna::boot
class declaration : public node
{
protected:
- declaration(const struct position position, identifier_definition identifier);
+ declaration(const source_position position, identifier_definition identifier);
public:
const identifier_definition identifier;
@@ -293,7 +292,7 @@ namespace elna::boot
public:
const std::uint32_t size;
- array_type_expression(const struct position position,
+ array_type_expression(const source_position position,
type_expression *base, const std::uint32_t size);
~array_type_expression() override;
@@ -308,7 +307,7 @@ namespace elna::boot
type_expression *m_base;
public:
- pointer_type_expression(const struct position position, type_expression *base);
+ pointer_type_expression(const source_position position, type_expression *base);
~pointer_type_expression() override;
void accept(parser_visitor *visitor) override;
@@ -317,18 +316,18 @@ namespace elna::boot
type_expression& base();
};
- using field_declaration = std::pair<std::vector<std::string>, std::shared_ptr<type_expression>>;
+ using field_declaration = std::pair<std::vector<identifier>, std::shared_ptr<type_expression>>;
class record_type_expression : public type_expression
{
public:
const std::vector<field_declaration> fields;
- const std::optional<std::string> base;
+ const std::optional<identifier> base;
- record_type_expression(const struct position position,
+ record_type_expression(const source_position position,
std::vector<field_declaration>&& fields);
- record_type_expression(const struct position position,
- std::vector<field_declaration>&& fields, std::string&& base);
+ record_type_expression(const source_position position,
+ std::vector<field_declaration>&& fields, identifier&& base);
void accept(parser_visitor *visitor) override;
record_type_expression *is_record() override;
@@ -336,22 +335,34 @@ namespace elna::boot
struct field_initializer
{
- std::string name;
- expression *value;
+ field_initializer(identifier name, expression *value);
+ field_initializer(const field_initializer&) = delete;
+ field_initializer(field_initializer&& other) noexcept;
+
+ field_initializer& operator=(const field_initializer&) = delete;
+ field_initializer& operator=(field_initializer&& other) noexcept;
+
+ ~field_initializer();
+
+ const std::string& name() const;
+ const identifier& id() const;
+ expression& value() const;
+
+ private:
+ identifier m_name;
+ expression *m_value;
};
class record_constructor_expression : public expression
{
public:
- const std::string type_name;
+ const identifier type_name;
const std::vector<field_initializer> field_initializers;
- record_constructor_expression(const struct position position,
- std::string&& type_name,
+ record_constructor_expression(const source_position position,
+ identifier&& type_name,
std::vector<field_initializer>&& field_initializers);
void accept(parser_visitor *visitor) override;
-
- virtual ~record_constructor_expression() override;
};
class array_constructor_expression : public expression
@@ -361,7 +372,7 @@ namespace elna::boot
type_expression *const m_element_type;
const std::vector<expression *> elements;
- array_constructor_expression(const struct position position,
+ array_constructor_expression(const source_position position,
std::uint32_t size, type_expression *element_type,
std::vector<expression *>&& elements);
void accept(parser_visitor *visitor) override;
@@ -375,10 +386,10 @@ namespace elna::boot
class enumeration_type_expression : public type_expression
{
public:
- const std::vector<std::string> members;
+ const std::vector<identifier> members;
- enumeration_type_expression(const struct position,
- std::vector<std::string>&& members);
+ enumeration_type_expression(const source_position,
+ std::vector<identifier>&& members);
void accept(parser_visitor *visitor) override;
enumeration_type_expression *is_enumeration() override;
@@ -392,10 +403,10 @@ namespace elna::boot
std::shared_ptr<type_expression> m_variable_type;
public:
- variable_declaration(const struct position position,
+ variable_declaration(const source_position position,
std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type,
expression *initializer = nullptr);
- variable_declaration(const struct position position,
+ variable_declaration(const source_position position,
std::vector<identifier_definition>&& identifier, std::shared_ptr<type_expression> variable_type,
std::monostate);
@@ -426,7 +437,7 @@ namespace elna::boot
expression *m_initializer;
public:
- constant_declaration(const struct position position, identifier_definition identifier,
+ constant_declaration(const source_position position, identifier_definition identifier,
expression *initializer);
void accept(parser_visitor *visitor) override;
@@ -446,7 +457,7 @@ namespace elna::boot
const return_t return_type;
const std::vector<field_declaration> parameters;
- procedure_type_expression(const struct position position,
+ procedure_type_expression(const source_position position,
std::vector<field_declaration>&& parameters, return_t return_type = return_t());
~procedure_type_expression();
@@ -483,9 +494,9 @@ namespace elna::boot
public:
std::optional<procedure_body> body;
- procedure_declaration(const struct position position, identifier_definition identifier,
+ procedure_declaration(const source_position position, identifier_definition identifier,
procedure_type_expression *heading, procedure_body&& body);
- procedure_declaration(const struct position position, identifier_definition identifier,
+ procedure_declaration(const source_position position, identifier_definition identifier,
procedure_type_expression *heading);
void accept(parser_visitor *visitor) override;
@@ -502,7 +513,7 @@ namespace elna::boot
type_expression *m_underlying_type;
public:
- type_declaration(const struct position position, identifier_definition identifier,
+ type_declaration(const source_position position, identifier_definition identifier,
type_expression *expression);
~type_declaration() override;
@@ -520,7 +531,7 @@ namespace elna::boot
expression *m_value;
public:
- cast_expression(const struct position position, type_expression *target, expression *value);
+ cast_expression(const source_position position, type_expression *target, expression *value);
void accept(parser_visitor *visitor) override;
cast_expression *is_cast() override;
@@ -534,10 +545,10 @@ namespace elna::boot
{
public:
const std::vector<type_expression *> arguments;
- const std::string name;
+ const identifier name;
std::vector<type> types;
- traits_expression(const struct position position, const std::string& name,
+ traits_expression(const source_position position, identifier&& name,
std::vector<type_expression *>&& arguments);
~traits_expression();
@@ -576,7 +587,7 @@ namespace elna::boot
const std::vector<switch_case> cases;
const std::vector<statement *> *alternative;
- case_statement(const struct position position, expression *condition,
+ case_statement(const source_position position, expression *condition,
std::vector<switch_case>&& cases, std::vector<statement *> *alternative = nullptr);
void accept(parser_visitor *visitor) override;
expression& condition();
@@ -603,7 +614,7 @@ namespace elna::boot
public:
const std::string name;
- named_expression(const struct position position, const std::string& name);
+ named_expression(const source_position position, const std::string& name);
void accept(parser_visitor *visitor) override;
named_expression *is_named() override;
@@ -615,7 +626,7 @@ namespace elna::boot
expression *m_index;
public:
- array_access_expression(const struct position position, expression *base, expression *index);
+ array_access_expression(const source_position position, expression *base, expression *index);
void accept(parser_visitor *visitor) override;
expression& base();
@@ -629,15 +640,15 @@ namespace elna::boot
class field_access_expression : public designator_expression
{
expression *m_base;
- std::string m_field;
+ identifier m_field;
public:
- field_access_expression(const struct position position, expression *base,
- const std::string& field);
+ field_access_expression(const source_position position, expression *base,
+ identifier&& field);
void accept(parser_visitor *visitor) override;
expression& base();
- std::string& field();
+ const identifier& field();
field_access_expression *is_field_access() override;
@@ -649,7 +660,7 @@ namespace elna::boot
expression *m_base;
public:
- dereference_expression(const struct position position, expression *base);
+ dereference_expression(const source_position position, expression *base);
void accept(parser_visitor *visitor) override;
expression& base();
@@ -669,7 +680,7 @@ namespace elna::boot
public:
const std::vector<expression *> arguments;
- procedure_call(const struct position position, designator_expression *callable,
+ procedure_call(const source_position position, designator_expression *callable,
std::vector<expression *>&& arguments);
void accept(parser_visitor *visitor) override;
virtual procedure_call *is_call_expression() override;
@@ -690,7 +701,7 @@ namespace elna::boot
* \param lvalue Left-hand side.
* \param rvalue Assigned expression.
*/
- assign_statement(const struct position position, designator_expression *lvalue,
+ assign_statement(const source_position position, designator_expression *lvalue,
expression *rvalue);
void accept(parser_visitor *visitor) override;
@@ -711,7 +722,7 @@ namespace elna::boot
const std::vector<conditional_statements *> branches;
const std::vector<statement *> *alternative;
- if_statement(const struct position position, conditional_statements *branch,
+ if_statement(const source_position position, conditional_statements *branch,
std::vector<conditional_statements *>&& branches,
std::vector<statement *> *alternative = nullptr);
void accept(parser_visitor *visitor) override;
@@ -729,7 +740,7 @@ namespace elna::boot
public:
const std::vector<std::string> segments;
- import_declaration(const struct position position, std::vector<std::string>&& segments);
+ import_declaration(const source_position position, std::vector<std::string>&& segments);
void accept(parser_visitor *visitor) override;
};
@@ -743,7 +754,7 @@ namespace elna::boot
public:
const std::vector<conditional_statements *> branches;
- while_statement(const struct position position, conditional_statements *branch,
+ while_statement(const source_position position, conditional_statements *branch,
std::vector<conditional_statements *>&& branches);
void accept(parser_visitor *visitor) override;
@@ -759,8 +770,8 @@ namespace elna::boot
const std::vector<type_declaration *> types;
const std::vector<procedure_declaration *> procedures;
- unit(const struct position position);
- unit(const struct position position,
+ unit(const source_position position);
+ unit(const source_position position,
std::vector<import_declaration *>&& imports,
std::vector<constant_declaration *>&& constants,
std::vector<type_declaration *>&& types,
@@ -779,7 +790,7 @@ namespace elna::boot
public:
T value;
- literal(const struct position position, const T& value)
+ literal(const source_position position, const T& value)
: node(position), value(value)
{
}
@@ -795,7 +806,7 @@ namespace elna::boot
public:
const std::vector<statement *> statements;
- defer_statement(const struct position position, std::vector<statement *>&& statements);
+ defer_statement(const source_position position, std::vector<statement *>&& statements);
void accept(parser_visitor *visitor) override;
virtual ~defer_statement() override;
@@ -804,7 +815,7 @@ namespace elna::boot
class empty_statement : public statement
{
public:
- empty_statement(const struct position);
+ empty_statement(const source_position);
void accept(parser_visitor *visitor) override;
};
@@ -815,7 +826,7 @@ namespace elna::boot
binary_operator m_operator;
public:
- binary_expression(const struct position position, expression *lhs,
+ binary_expression(const source_position position, expression *lhs,
expression *rhs, const binary_operator operation);
void accept(parser_visitor *visitor) override;
@@ -834,7 +845,7 @@ namespace elna::boot
unary_operator m_operator;
public:
- unary_expression(const struct position position, expression *operand,
+ unary_expression(const source_position position, expression *operand,
const unary_operator operation);
void accept(parser_visitor *visitor) override;
diff --git a/include/elna/boot/driver.h b/include/elna/boot/driver.h
index cd29376..8f93dbd 100644
--- a/include/elna/boot/driver.h
+++ b/include/elna/boot/driver.h
@@ -23,7 +23,7 @@ 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);
class syntax_error final : public error
{
diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h
index 0556dbe..953f701 100644
--- a/include/elna/boot/result.h
+++ b/include/elna/boot/result.h
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#include <string>
#include <deque>
#include <memory>
+#include <optional>
#include <variant>
namespace elna::boot
@@ -30,29 +31,44 @@ namespace elna::boot
*/
struct location
{
- /// Line.
- const std::size_t line;
+ location() = default;
+ location(const std::size_t line, const std::size_t column);
- /// Column.
- const std::size_t column;
+ /// \return Line.
+ std::size_t line() const;
- location(std::size_t line, std::size_t column);
+ /// \return Column.
+ std::size_t column() const;
bool available() const;
+
+ bool operator==(const location& that) const;
+ bool operator!=(const location& that) const;
+
+ private:
+ std::size_t m_line{ 0 };
+ std::size_t m_column{ 0 };
};
/**
* Span in the source text.
*/
- struct position
+ struct source_position
{
- /// Start location.
- const location start;
+ source_position(location start, location end);
+
+ /// \return Start location.
+ const location& start() const;
- /// End location.
- const location end;
+ /// \return End location.
+ const location& end() const;
- position(location start, location end);
+ /// \return Whether this position spans more than one location.
+ bool is_span() const;
+
+ private:
+ location m_start;
+ location m_end;
};
/**
@@ -61,14 +77,25 @@ namespace elna::boot
class error
{
protected:
- error(const struct position position);
+ error(const source_position position);
public:
/// Error position.
- const struct position position;
+ const source_position position;
/// Error text.
virtual std::string what() const = 0;
+
+ /**
+ * Supplementary context shown alongside the primary error,
+ * e.g.\ the location of a previous declaration.
+ *
+ * \return Optional note message and position.
+ */
+ virtual std::optional<std::pair<std::string, source_position>> note() const
+ {
+ return std::nullopt;
+ }
};
using error_list = typename std::deque<std::unique_ptr<error>>;
@@ -111,27 +138,55 @@ namespace elna::boot
{
}
- bool operator==(const return_declaration& other) const
+ bool operator==(const return_declaration& that) const
+ {
+ return this->proper_type == that.proper_type && this->no_return == that.no_return;
+ }
+
+ bool operator!=(const return_declaration& that) const
{
- return this->proper_type == other.proper_type && this->no_return == other.no_return;
+ return !(*this == that);
}
T proper_type{};
bool no_return{ false };
};
- struct identifier_definition
+ struct identifier
{
- std::string name;
- bool exported;
+ identifier(const std::string& name, const source_position& position);
+
+ const std::string& name() const;
+ const source_position& position() const;
+
+ bool operator==(const identifier& that) const;
+ bool operator!=(const identifier& that) const;
- bool operator==(const identifier_definition& that) const;
bool operator==(const std::string& that) const;
+ bool operator!=(const std::string& that) const;
+
+ private:
+ std::string m_name;
+ source_position m_position;
+ };
+
+ struct identifier_definition
+ {
+ identifier_definition(const std::string& name, const source_position& position,
+ const bool exported);
+
+ const std::string& name() const;
+ const identifier& id() const;
+ bool exported() const;
+
+ private:
+ identifier m_identifier;
+ bool m_exported{ false };
};
}
template<>
-struct std::hash<elna::boot::identifier_definition>
+struct std::hash<elna::boot::identifier>
{
- std::size_t operator()(const elna::boot::identifier_definition& key) const noexcept;
+ std::size_t operator()(const elna::boot::identifier& key) const noexcept;
};
diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h
index 4041f33..82ef5f1 100644
--- a/include/elna/boot/semantic.h
+++ b/include/elna/boot/semantic.h
@@ -19,7 +19,7 @@ along with GCC; see the file COPYING3. If not see
#include <string>
#include <memory>
-#include <set>
+#include <map>
#include "elna/boot/ast.h"
#include "elna/boot/result.h"
@@ -32,57 +32,91 @@ namespace elna::boot
*/
class declaration_error : public error
{
- const std::string identifier;
-
public:
enum class kind
{
undeclared,
- already,
local_export
};
+ private:
+ std::string identifier;
+ kind error_kind;
+
+ public:
+
declaration_error(const kind error_kind,
- const std::string& identifier, const struct position position);
+ const boot::identifier& identifier);
std::string what() const override;
-
- private:
- const kind error_kind;
};
/**
- * A symbol was already declared in this scope.
+ * Attempted to redefine a name that is already in use in the
+ * current scope.
*/
- class type_expectation_error : public error
+ class redefinition_error : public error
{
+ std::string identifier;
+ std::optional<source_position> original;
+
public:
- enum class kind
- {
- assignment,
- result,
- argument
- };
+ redefinition_error(const boot::identifier& identifier,
+ std::optional<source_position> original);
- type_expectation_error(const kind error_kind, const struct position position);
+ std::string what() const override;
+
+ std::optional<std::pair<std::string, source_position>> note() const override;
+ };
+
+ /**
+ * Expected type does not match the actual type of an expression.
+ */
+ class type_mismatch_error : public error
+ {
+ type expected;
+ type actual;
+
+ public:
+ type_mismatch_error(const source_position position,
+ type expected, type actual);
std::string what() const override;
+ };
- private:
- const kind error_kind;
+ /**
+ * Attempted to access a field that does not exist on the given type.
+ */
+ class field_not_found_error : public error
+ {
+ std::string field_name;
+ type composite_type;
+
+ public:
+ field_not_found_error(const identifier& field_name,
+ type composite_type);
+
+ std::string what() const override;
};
/**
* Field with the same name is already declared in this type.
*/
- class field_duplication_error : public error
+ class duplicate_member_error : public error
{
- const std::string field_name;
+ std::string member_name;
+ type aggregate;
+ std::optional<source_position> original;
+ std::optional<std::string> base_name;
public:
- field_duplication_error(const std::string& field_name, const struct position position);
+ duplicate_member_error(const boot::identifier& member_name,
+ type aggregate, std::optional<source_position> original = std::nullopt,
+ std::optional<std::string> base_name = std::nullopt);
std::string what() const override;
+
+ std::optional<std::pair<std::string, source_position>> note() const override;
};
/**
@@ -90,10 +124,10 @@ namespace elna::boot
*/
class cyclic_declaration_error : public error
{
- const std::vector<std::string> cycle;
+ std::vector<std::string> cycle;
public:
- cyclic_declaration_error(const std::vector<std::string>& cycle, const struct position position);
+ cyclic_declaration_error(const std::vector<std::string>& cycle, const source_position position);
std::string what() const override;
};
@@ -103,10 +137,12 @@ namespace elna::boot
*/
class return_error : public error
{
- const std::string identifier;
+ std::string identifier;
+ type return_type;
public:
- return_error(const std::string& identifier, const struct position position);
+ return_error(const std::string& identifier, const source_position position,
+ type return_type = type());
std::string what() const override;
};
@@ -116,10 +152,10 @@ namespace elna::boot
*/
class base_type_error : public error
{
- const std::string base;
+ type actual;
public:
- base_type_error(const std::string& base, const struct position position);
+ base_type_error(type actual, const source_position position);
std::string what() const override;
};
@@ -130,12 +166,12 @@ namespace elna::boot
*/
class argument_count_error : public error
{
- const std::size_t expected;
- const std::size_t actual;
+ std::size_t expected;
+ std::size_t actual;
public:
argument_count_error(std::size_t expected, std::size_t actual,
- const struct position position);
+ const source_position position);
std::string what() const override;
};
@@ -166,6 +202,15 @@ namespace elna::boot
};
/**
+ * Origin of a field in a composite type.
+ */
+ struct field_origin
+ {
+ std::optional<source_position> declaration;
+ type base_type;
+ };
+
+ /**
* Performs name analysis.
*/
class name_analysis_visitor final : public walking_visitor, public error_container
@@ -178,9 +223,10 @@ namespace elna::boot
std::pair<procedure_type, std::vector<std::string>> build_procedure(
procedure_type_expression& expression);
std::vector<type_field> build_composite_type(const std::vector<field_declaration>& fields,
- std::set<std::string>& known_names);
+ std::map<std::string, field_origin>& known_names,
+ type aggregate);
std::shared_ptr<variable_info> register_variable(const std::string& name,
- const bool is_extern, const struct position position);
+ const bool is_extern, const source_position position);
type lookup_primitive_type(const std::string& name);
type type_of_constant(const constant_info::variant& value);
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
index e13e842..ec5a051 100644
--- a/include/elna/boot/symbol.h
+++ b/include/elna/boot/symbol.h
@@ -89,6 +89,12 @@ namespace elna::boot
bool operator==(const type& other) const;
bool empty() const;
+
+ /**
+ * \return Human-readable representation of this type suitable for
+ * diagnostics, e.g. \c "Int", \c "^Char", \c "record ... end".
+ */
+ std::string to_string() const;
};
struct alias_type
@@ -157,6 +163,7 @@ namespace elna::boot
{
public:
bool exported{ false };
+ std::optional<source_position> position;
virtual ~info() = 0;
diff --git a/include/elna/gcc/elna-diagnostic.h b/include/elna/gcc/elna-diagnostic.h
index 3957003..31e180e 100644
--- a/include/elna/gcc/elna-diagnostic.h
+++ b/include/elna/gcc/elna-diagnostic.h
@@ -41,8 +41,8 @@ namespace elna::gcc
~linemap_guard();
};
- location_t get_location(const boot::position *position);
- void fill_range(const boot::position& position, location_t& start, location_t& end);
+ location_t get_location(const boot::source_position *position);
+ location_t make_range(const boot::source_position& position);
std::string print_type(tree type);
void report_errors(const std::deque<std::unique_ptr<boot::error>>& errors);
}