aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-24 03:11:32 +0200
committerEugen Wissner <belka@caraus.de>2026-07-24 03:11:32 +0200
commitbb4f474cb2247e0e314beab5d7d72e673ff4e8b6 (patch)
tree4809b414bffa8d422ef8c1b6fe65dcdd4dce65d8 /include
parent275fa4bff6d153019b6914fed7127a7d919ca177 (diff)
downloadelna-bb4f474cb2247e0e314beab5d7d72e673ff4e8b6.tar.gz
Implement a repeat loop
Diffstat (limited to 'include')
-rw-r--r--include/elna/boot/ast.h40
-rw-r--r--include/elna/boot/name_analysis.h20
-rw-r--r--include/elna/boot/symbol.h10
-rw-r--r--include/elna/boot/type_check.h30
-rw-r--r--include/elna/gcc/elna-generic.h5
-rw-r--r--include/elna/gcc/elna-tree.h1
6 files changed, 73 insertions, 33 deletions
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index b50eb75..d6804df 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -75,6 +75,7 @@ namespace elna::boot
class if_statement;
class import_declaration;
class while_statement;
+ class repeat_statement;
class for_statement;
class case_statement;
class traits_expression;
@@ -118,6 +119,7 @@ namespace elna::boot
virtual void visit(if_statement *) = 0;
virtual void visit(import_declaration *) = 0;
virtual void visit(while_statement *) = 0;
+ virtual void visit(repeat_statement *) = 0;
virtual void visit(for_statement *) = 0;
virtual void visit(defer_statement *) = 0;
virtual void visit(case_statement *) = 0;
@@ -146,7 +148,9 @@ namespace elna::boot
};
/**
- * Abstract visitor that doesn't visit any nodes by default.
+ * Abstract visitor that asserts on any node visitation. Child visitors
+ * override only the node types they care about, with the guarantee that
+ * unimplemented nodes are never silently ignored.
*/
class empty_visitor : public parser_visitor
{
@@ -166,6 +170,7 @@ namespace elna::boot
[[noreturn]] void visit(if_statement *) override;
[[noreturn]] void visit(import_declaration *) override;
[[noreturn]] void visit(while_statement *) override;
+ [[noreturn]] void visit(repeat_statement *) override;
[[noreturn]] void visit(for_statement *) override;
[[noreturn]] void visit(defer_statement *) override;
[[noreturn]] void visit(empty_statement *) override;
@@ -213,6 +218,7 @@ namespace elna::boot
void visit(if_statement *) override;
void visit(import_declaration *) override;
void visit(while_statement *statement) override;
+ void visit(repeat_statement *statement) override;
void visit(for_statement *statement) override;
void visit(defer_statement *statement) override;
void visit(empty_statement *) override;
@@ -824,28 +830,44 @@ namespace elna::boot
};
/**
- * for-statement.
+ * for-to-statement.
+ */
+ class repeat_statement : public statement
+ {
+ expression *m_condition;
+
+ public:
+ const std::vector<statement *> body;
+
+ repeat_statement(const source_position position, std::vector<statement *>&& body,
+ expression *condition);
+ ~repeat_statement() override;
+
+ void accept(parser_visitor *visitor) override;
+
+ expression& condition();
+ };
+
+ /**
+ * for-of-statement.
*/
class for_statement : public statement
{
- expression *m_initial_value;
- expression *m_final_value;
+ expression *m_range;
public:
const identifier control_variable;
+ identifier *const counter;
const std::vector<statement *> body;
- expression *const step;
std::shared_ptr<symbol_table> symbols;
for_statement(const source_position position, identifier&& control_variable,
- expression *initial_value, expression *final_value,
- std::vector<statement *>&& body, expression *step = nullptr);
+ expression *range, std::vector<statement *>&& body, identifier *const counter);
~for_statement() override;
void accept(parser_visitor *visitor) override;
- expression& initial_value();
- expression& final_value();
+ expression& range();
};
/**
diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h
index d18b813..68fe6da 100644
--- a/include/elna/boot/name_analysis.h
+++ b/include/elna/boot/name_analysis.h
@@ -33,15 +33,25 @@ namespace elna::boot
* Error declaring or using a symbol (undeclared, redefinition,
* local export).
*/
- class symbol_error : public error
+ class declaration_error : public error
{
public:
- struct undeclared { std::string name; };
- struct local_export { std::string name; };
- struct redefinition { std::string name; std::optional<source_position> original; };
+ struct undeclared
+ {
+ std::string name;
+ };
+ struct local_export
+ {
+ std::string name;
+ };
+ struct redefinition
+ {
+ std::string name;
+ std::optional<source_position> original;
+ };
using payload_type = std::variant<undeclared, local_export, redefinition>;
- symbol_error(const source_position position, payload_type payload);
+ declaration_error(const source_position position, payload_type payload);
std::string what() const override;
std::optional<std::pair<std::string, source_position>> note() const override;
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
index ea418b1..4e97205 100644
--- a/include/elna/boot/symbol.h
+++ b/include/elna/boot/symbol.h
@@ -73,6 +73,7 @@ namespace elna::boot
bool operator==(const std::nullptr_t&) const;
bool operator==(const type& other) const;
+ explicit operator bool() const;
bool empty() const;
@@ -523,4 +524,13 @@ namespace elna::boot
* \return Whether the type is a pointer type.
*/
bool is_any_pointer_type(const type& checked);
+
+ /**
+ * If \a range is an array or a slice gives its base type, otherwise
+ * returns an empty type.
+ *
+ * \param range The type to check.
+ * \return The base type, or an empty type.
+ */
+ type get_range_base_type(const type& range);
}
diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h
index 5fdc5cb..e500007 100644
--- a/include/elna/boot/type_check.h
+++ b/include/elna/boot/type_check.h
@@ -88,16 +88,23 @@ namespace elna::boot
};
/**
- * Base type of a record is not a record.
+ * Unexpected kind of a type at specific position.
*/
- class base_type_error : public error
+ class type_kind_error : public error
{
- type actual;
-
public:
- base_type_error(type actual, const source_position position);
+ enum class kind
+ {
+ record_base,
+ for_loop
+ };
+ type_kind_error(const source_position position, kind type_kind, const type& actual);
std::string what() const override;
+
+ private:
+ kind type_kind;
+ type actual;
};
/**
@@ -165,19 +172,6 @@ namespace elna::boot
};
/**
- * FOR loop variable must be \c Int or \c Word.
- */
- class for_loop_type_error : public error
- {
- type actual;
-
- public:
- for_loop_type_error(const source_position position, type actual);
-
- std::string what() const override;
- };
-
- /**
* Chain of responsibility for type compatibility checks.
*
* Populate \c ctx with pre-resolved types, then call \c run().
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index de95a7e..1ac829f 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -60,6 +60,10 @@ namespace elna::gcc
bool expect_trait_type_only(boot::traits_expression *trait);
void visit_statements(const std::vector<boot::statement *>& statements);
bool assert_constant(location_t expression_location);
+ tree declare_local_variable(const boot::identifier& name,
+ const boot::variable_info& info, tree initial_value);
+ std::pair<tree, tree> build_loop_head(tree control_variable_declaration, tree limit,
+ tree_code comparison, location_t check_location);
public:
generic_visitor(std::shared_ptr<symbol_table> symbol_table,
@@ -89,6 +93,7 @@ namespace elna::gcc
void visit(boot::slicing_expression *expression) override;
void visit(boot::assign_statement *statement) override;
void visit(boot::if_statement *statement) override;
+ void visit(boot::repeat_statement *statement) override;
void visit(boot::for_statement *statement) override;
void visit(boot::while_statement *statement) override;
void visit(boot::defer_statement *statement) override;
diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h
index 1d48b00..ac97e41 100644
--- a/include/elna/gcc/elna-tree.h
+++ b/include/elna/gcc/elna-tree.h
@@ -36,7 +36,6 @@ namespace elna::gcc
using symbol_table = boot::symbol_map<tree, tree, NULL_TREE>;
bool is_integral_type(tree type);
- bool is_numeric_type(tree type);
bool is_unique_type(tree type);
bool is_void_type(tree type);