aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/elna/boot/ast.h86
-rw-r--r--include/elna/boot/name_analysis.h10
-rw-r--r--include/elna/boot/type_check.h1
-rw-r--r--include/elna/boot/validation.h2
-rw-r--r--include/elna/gcc/elna-generic.h5
5 files changed, 68 insertions, 36 deletions
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 4eea412..52461e6 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -111,6 +111,7 @@ namespace elna::boot
template<typename T>
concept literal_type = requires { literal_type_id<T>::value; };
+ class statement;
class variable_declaration;
class procedure_declaration;
class type_declaration;
@@ -153,6 +154,27 @@ namespace elna::boot
class empty_statement;
/**
+ * Variable declarations and the statements they are visible in.
+ */
+ struct block
+ {
+ std::vector<variable_declaration *> variables;
+ std::vector<statement *> statements;
+ /// Scope containing the variables, entered by the name analysis.
+ std::shared_ptr<symbol_table> symbols;
+
+ block() = default;
+ block(std::vector<variable_declaration *>&& variables, std::vector<statement *>&& statements);
+ block(const block&) = delete;
+ block(block&& that) noexcept = default;
+
+ block& operator=(const block&) = delete;
+ block& operator=(block&& that) noexcept = default;
+
+ ~block();
+ };
+
+ /**
* Interface for AST visitors.
*/
struct parser_visitor
@@ -304,6 +326,8 @@ namespace elna::boot
protected:
/// Passes needing the entry point's scope override this.
virtual void visit_entry_point(unit *unit);
+ /// Passes needing the scope of a block override this.
+ virtual void traverse_block(block& body);
};
/**
@@ -659,21 +683,14 @@ namespace elna::boot
procedure_type_expression *is_procedure() override;
};
- struct procedure_body
+ struct procedure_body : block
{
- const std::vector<variable_declaration *> variables;
- const std::vector<statement *> statements;
- expression *const return_expression{ nullptr };
+ expression *return_expression{ nullptr };
- procedure_body(std::vector<variable_declaration *>&& variables,
- std::vector<statement *>&& entry_point,
- expression *return_expression = nullptr);
- procedure_body(const procedure_body&) = delete;
- procedure_body(procedure_body&& that) noexcept;
+ procedure_body(block&& body, expression *return_expression = nullptr);
+ procedure_body(procedure_body&& that) noexcept = default;
- procedure_body& operator=(const procedure_body&) = delete;
-
- virtual ~procedure_body();
+ virtual ~procedure_body() = default;
};
void traverse_body(parser_visitor *visitor, const procedure_body& body);
@@ -687,7 +704,7 @@ namespace elna::boot
public:
const identifier_definition identifier;
- const std::optional<procedure_body> body;
+ std::optional<procedure_body> body;
/**
* Type parameters bound by this declaration. Empty for a plain
@@ -771,9 +788,9 @@ namespace elna::boot
expression *m_prerequisite;
public:
- const std::vector<statement *> statements;
+ block body;
- conditional_statements(expression *prerequisite, std::vector<statement *>&& statements);
+ conditional_statements(expression *prerequisite, block&& body);
expression& prerequisite();
@@ -783,7 +800,7 @@ namespace elna::boot
struct switch_case
{
std::vector<expression *> labels;
- std::vector<statement *> statements;
+ block body;
};
class case_statement : public statement
@@ -791,13 +808,15 @@ namespace elna::boot
expression *m_condition;
public:
- const std::vector<switch_case> cases;
- const std::vector<statement *> *alternative;
+ std::vector<switch_case> cases;
+ block *alternative;
case_statement(const source_position position, expression *condition,
- std::vector<switch_case>&& cases, std::vector<statement *> *alternative = nullptr);
+ std::vector<switch_case>&& cases, block *alternative = nullptr);
void accept(parser_visitor *visitor) override;
expression& condition();
+
+ ~case_statement() override;
};
class designator_expression : public expression
@@ -965,11 +984,11 @@ namespace elna::boot
public:
const std::vector<conditional_statements *> branches;
- const std::vector<statement *> *alternative;
+ block *alternative;
if_statement(const source_position position, conditional_statements *branch,
std::vector<conditional_statements *>&& branches,
- std::vector<statement *> *alternative = nullptr);
+ block *alternative = nullptr);
void accept(parser_visitor *visitor) override;
conditional_statements& branch();
@@ -1016,9 +1035,9 @@ namespace elna::boot
expression *m_condition;
public:
- const std::vector<statement *> body;
+ block body;
- repeat_statement(const source_position position, std::vector<statement *>&& body,
+ repeat_statement(const source_position position, block&& body,
expression *condition);
~repeat_statement() override;
@@ -1037,11 +1056,11 @@ namespace elna::boot
public:
const identifier control_variable;
identifier *const counter;
- const std::vector<statement *> body;
- std::shared_ptr<symbol_table> symbols;
+ /// The control variable and the counter live in the body's scope.
+ block body;
for_statement(const source_position position, identifier&& control_variable,
- expression *range, std::vector<statement *>&& body, identifier *const counter);
+ expression *range, block&& body, identifier *const counter);
~for_statement() override;
void accept(parser_visitor *visitor) override;
@@ -1057,7 +1076,7 @@ namespace elna::boot
public:
const std::vector<import_declaration *> imports;
const std::vector<declaration *> declarations;
- const std::optional<procedure_body> entry_point;
+ std::optional<procedure_body> entry_point;
const std::vector<identifier> parameters;
const std::optional<source_position> entry_position;
@@ -1104,12 +1123,10 @@ namespace elna::boot
class defer_statement : public statement
{
public:
- const std::vector<statement *> statements;
+ block body;
- defer_statement(const source_position position, std::vector<statement *>&& statements);
+ defer_statement(const source_position position, block&& body);
void accept(parser_visitor *visitor) override;
-
- ~defer_statement() override;
};
/**
@@ -1119,13 +1136,10 @@ namespace elna::boot
{
public:
const identifier name;
- const std::vector<statement *> statements;
+ block body;
- block_statement(const source_position position, identifier&& name,
- std::vector<statement *>&& statements);
+ block_statement(const source_position position, identifier&& name, block&& body);
void accept(parser_visitor *visitor) override;
-
- ~block_statement() override;
};
/**
diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h
index 67cd713..004aeae 100644
--- a/include/elna/boot/name_analysis.h
+++ b/include/elna/boot/name_analysis.h
@@ -298,6 +298,16 @@ namespace elna::boot
std::optional<type> lookup_pointer_like_field(const std::string& field_name,
const type& element_type);
type lookup_field(const type& composite_type, const std::string& field_name);
+ /*
+ * Visits the declarations and the statements of a block in the scope
+ * the caller has opened for it.
+ */
+ void traverse_block(block& body);
+ /*
+ * Opens the scope of a block, remembers it on the block for the later
+ * passes and visits the block in it.
+ */
+ void visit_block(block& body);
public:
void visit(array_type_expression *expression) override;
diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h
index 582b887..94f8961 100644
--- a/include/elna/boot/type_check.h
+++ b/include/elna/boot/type_check.h
@@ -300,6 +300,7 @@ namespace elna::boot
protected:
void visit_entry_point(unit *unit) override;
+ void traverse_block(block& body) override;
public:
explicit type_analysis_visitor(symbol_bag bag, const target_info& target);
diff --git a/include/elna/boot/validation.h b/include/elna/boot/validation.h
index 87e0b18..d3a22d1 100644
--- a/include/elna/boot/validation.h
+++ b/include/elna/boot/validation.h
@@ -49,6 +49,8 @@ namespace elna::boot
evaluator constant_evaluator;
void visit_statements(const std::vector<statement *>& statements);
+ /// Visits the statements of a block in its own scope.
+ void visit_block(const block& body);
public:
validation_visitor(symbol_bag& bag, const target_info& target);
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index b05a8f9..54f320e 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -67,6 +67,11 @@ namespace elna::gcc
void build_volatile_store_builtin(location_t call_location, boot::procedure_call *call);
void visit_statements(const std::vector<boot::statement *>& statements);
+ /*
+ * Declares the variables of a block and generates its statements. The
+ * caller opens the binding level the variables are declared in.
+ */
+ void visit_block(boot::block& body);
void assert_constant();
tree declare_local_variable(const boot::identifier& name,
const boot::variable_info& info, tree initial_value);