aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-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
6 files changed, 229 insertions, 110 deletions
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);
}