aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-13 18:14:45 +0200
committerEugen Wissner <belka@caraus.de>2026-07-13 18:14:45 +0200
commit500c0676b3f6cd5a2297987d5b0dc7ccf34a28d9 (patch)
treea394c73de9273489e6045f3d252714b5ac69b17c
parent97741a01323021ccec8b0b60c6f8318c88ac373a (diff)
downloadelna-500c0676b3f6cd5a2297987d5b0dc7ccf34a28d9.tar.gz
Make return statement part of the body and not a statement
-rw-r--r--boot/ast.cc128
-rw-r--r--boot/parser.yy62
-rw-r--r--boot/semantic.cc79
-rw-r--r--cl.elna213
-rw-r--r--gcc/gcc/elna-generic.cc56
-rw-r--r--include/elna/boot/ast.h62
-rw-r--r--include/elna/boot/semantic.h5
-rw-r--r--include/elna/gcc/elna-generic.h3
-rw-r--r--source/lexer.elna205
-rw-r--r--source/main.elna1
-rw-r--r--testsuite/compilable/pointer_cast.elna4
-rw-r--r--testsuite/fail_compilation/module_without_return.elna6
12 files changed, 372 insertions, 452 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index fbecf11..118d92c 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -84,11 +84,6 @@ namespace elna::boot
__builtin_unreachable();
}
- void empty_visitor::visit(return_statement *)
- {
- __builtin_unreachable();
- }
-
void empty_visitor::visit(defer_statement *)
{
__builtin_unreachable();
@@ -205,18 +200,22 @@ namespace elna::boot
}
if (declaration->body.has_value())
{
- for (constant_declaration *const constant : declaration->body.value().constants())
+ for (constant_declaration *const constant : declaration->body.value().constants)
{
constant->accept(this);
}
- for (variable_declaration *const variable : declaration->body.value().variables())
+ for (variable_declaration *const variable : declaration->body.value().variables)
{
variable->accept(this);
}
- for (statement *const statement : declaration->body.value().statements())
+ for (statement *const statement : declaration->body.value().entry_point)
{
statement->accept(this);
}
+ if (declaration->body.value().return_expression != nullptr)
+ {
+ declaration->body.value().return_expression->accept(this);
+ }
}
}
@@ -269,11 +268,6 @@ namespace elna::boot
}
}
- void walking_visitor::visit(return_statement *statement)
- {
- statement->return_expression().accept(this);
- }
-
void walking_visitor::visit(defer_statement *statement)
{
for (struct statement *const block_statement : statement->statements)
@@ -340,12 +334,13 @@ namespace elna::boot
{
procedure->accept(this);
}
- if (unit->entry_point.has_value())
+ for (statement *const entry_statement : unit->entry_point)
{
- for (statement *const entry_statement : unit->entry_point.value())
- {
- entry_statement->accept(this);
- }
+ entry_statement->accept(this);
+ }
+ if (unit->return_expression != nullptr)
+ {
+ unit->return_expression->accept(this);
}
}
@@ -773,70 +768,54 @@ namespace elna::boot
}
procedure_body::procedure_body(std::vector<constant_declaration *>&& constants,
- std::vector<variable_declaration *>&& variables, std::vector<statement *>&& statements)
- : m_variables(std::move(variables)), m_constants(std::move(constants)), m_statements(std::move(statements))
- {
- }
-
- procedure_body::procedure_body(std::vector<constant_declaration*>&& constants,
- std::vector<variable_declaration *>&& variables)
- : procedure_body(std::move(constants), std::move(variables), std::vector<statement *>{})
+ std::vector<variable_declaration *>&& variables, std::vector<statement *>&& entry_point,
+ expression *return_expr)
+ : constants(std::move(constants)), variables(std::move(variables)),
+ entry_point(std::move(entry_point)), return_expression(return_expr)
{
}
procedure_body::procedure_body(procedure_body&& that)
- : m_variables(std::move(that.m_variables)), m_constants(std::move(that.m_constants)),
- m_statements(std::move(that.m_statements))
- {
- }
-
- procedure_body& procedure_body::operator=(procedure_body&& that)
- {
- std::swap(m_variables, that.m_variables);
- std::swap(m_constants, that.m_constants);
- std::swap(m_statements, that.m_statements);
-
- return *this;
- }
-
- const std::vector<variable_declaration *>& procedure_body::variables()
- {
- return m_variables;
- }
-
- const std::vector<constant_declaration *>& procedure_body::constants()
- {
- return m_constants;
- }
-
- const std::vector<statement *>& procedure_body::statements()
+ : constants(std::move(const_cast<std::vector<constant_declaration *>&>(that.constants))),
+ variables(std::move(const_cast<std::vector<variable_declaration *>&>(that.variables))),
+ entry_point(std::move(const_cast<std::vector<statement *>&>(that.entry_point))),
+ return_expression(that.return_expression)
{
- return m_statements;
}
procedure_body::~procedure_body()
{
- for (statement *body_statement : this->statements())
+ for (statement *body_statement : this->entry_point)
{
delete body_statement;
}
- for (variable_declaration *variable : this->variables())
+ for (variable_declaration *variable : this->variables)
{
delete variable;
}
- for (constant_declaration *constant : this->constants())
+ for (constant_declaration *constant : this->constants)
{
delete constant;
}
}
unit::unit(const struct position position)
- : node(position)
+ : node(position), procedure_body(std::vector<constant_declaration *>{},
+ std::vector<variable_declaration *>{}, std::vector<statement *>{}, nullptr)
{
}
- unit::unit(const struct position position, std::vector<statement *>&& entry_point)
- : node(position), entry_point(std::make_optional<std::vector<statement *>>(std::move(entry_point)))
+ unit::unit(const struct position position,
+ std::vector<import_declaration *>&& imports,
+ std::vector<constant_declaration *>&& constants,
+ std::vector<type_declaration *>&& types,
+ std::vector<variable_declaration *>&& variables,
+ std::vector<procedure_declaration *>&& procedures,
+ std::vector<statement *>&& entry_point,
+ expression *const return_expression)
+ : node(position),
+ procedure_body(std::move(constants), std::move(variables), std::move(entry_point), return_expression),
+ imports(std::move(imports)), types(std::move(types)), procedures(std::move(procedures))
{
}
@@ -845,24 +824,21 @@ namespace elna::boot
visitor->visit(this);
}
+ bool unit::has_body() const
+ {
+ return !this->entry_point.empty() || this->return_expression != nullptr;
+ }
+
unit::~unit()
{
for (procedure_declaration *procedure : this->procedures)
{
delete procedure;
}
- for (variable_declaration *variable : this->variables)
- {
- delete variable;
- }
for (type_declaration *type : this->types)
{
delete type;
}
- for (constant_declaration *constant : this->constants)
- {
- delete constant;
- }
for (import_declaration *declaration : this->imports)
{
delete declaration;
@@ -1206,26 +1182,6 @@ namespace elna::boot
}
}
- return_statement::return_statement(const struct position position, expression *return_expression)
- : node(position), m_return_expression(return_expression)
- {
- }
-
- void return_statement::accept(parser_visitor *visitor)
- {
- visitor->visit(this);
- }
-
- expression& return_statement::return_expression()
- {
- return *m_return_expression;
- }
-
- return_statement::~return_statement()
- {
- delete m_return_expression;
- }
-
case_statement::case_statement(const struct position position,
expression *condition, std::vector<switch_case>&& cases, std::vector<statement *> *alternative)
: node(position), m_condition(condition), cases(std::move(cases)), alternative(alternative)
diff --git a/boot/parser.yy b/boot/parser.yy
index aace9a1..f1bf915 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -131,16 +131,14 @@ along with GCC; see the file COPYING3. If not see
%type <elna::boot::type_expression *> type_expression;
%type <std::vector<elna::boot::type_expression *>> type_expressions;
%type <elna::boot::traits_expression *> traits_expression;
-%type <elna::boot::expression *> expression operand simple_expression;
+%type <elna::boot::expression *> expression operand simple_expression return_statement;
%type <elna::boot::unary_expression *> unary_expression;
%type <elna::boot::binary_expression *> binary_expression;
%type <std::vector<elna::boot::expression *>> expressions actual_parameter_list;
%type <elna::boot::designator_expression *> designator_expression;
%type <elna::boot::procedure_call*> call_expression;
-%type <elna::boot::return_statement *> return_statement;
%type <elna::boot::statement *> statement;
-%type <std::vector<elna::boot::statement *>> statements;
-%type <std::unique_ptr<std::vector<elna::boot::statement *>>> statement_part;
+%type <std::vector<elna::boot::statement *>> statements statement_part;
%type <elna::boot::procedure_declaration *> procedure_declaration;
%type <elna::boot::procedure_type_expression *> procedure_heading;
%type <elna::boot::procedure_type_expression::return_t> return_declaration;
@@ -159,49 +157,22 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<elna::boot::import_declaration *>> import_declarations import_part;
%%
program:
- import_part constant_part type_part variable_part procedure_part statement_part "end" "."
- {
- boot::unit *tree;
- if ($6)
- {
- tree = new boot::unit(boot::make_position(@1),
- std::move(*$6.release()));
- }
- else
- {
- tree = new boot::unit(boot::make_position(@1));
- }
- driver.tree.reset(tree);
-
- std::swap(driver.tree->imports, $1);
- std::swap(driver.tree->constants, $2);
- std::swap(driver.tree->types , $3);
- std::swap(driver.tree->variables, $4);
- std::swap(driver.tree->procedures, $5);
- }
-procedure_body: constant_part variable_part statement_part "end"
- {
- if ($3)
- {
- $$ = std::make_unique<boot::procedure_body>(std::move($1), std::move($2), std::move(*$3.release()));
- }
- else
- {
- $$ = std::make_unique<boot::procedure_body>(std::move($1), std::move($2));
- }
- }
-statement_part:
- /* no statements */ {}
- | "begin" statements { $$ = std::make_unique<std::vector<boot::statement *>>(std::move($2));; }
- | return_statement
+ import_part constant_part type_part variable_part procedure_part statement_part return_statement "end" "."
{
- $$ = std::make_unique<std::vector<boot::statement *>>(std::vector<boot::statement *>{ $1 });
+ boot::unit *tree = new boot::unit(boot::make_position(@1),
+ std::move($1), std::move($2), std::move($3), std::move($4), std::move($5),
+ std::move($6), $7);
+ driver.tree.reset(tree);
}
- | "begin" statements ";" return_statement
+procedure_body:
+ constant_part variable_part statement_part return_statement "end"
{
- $$ = std::make_unique<std::vector<boot::statement *>>(std::move($2));
- $$->push_back($4);
+ $$ = std::make_unique<boot::procedure_body>(std::move($1), std::move($2), std::move($3), $4);
}
+
+statement_part:
+ /* no statements */ {}
+ | "begin" statements { std::swap($$, $2); }
identifier_definition:
IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; }
| IDENTIFIER { $$ = boot::identifier_definition{ $1, false }; }
@@ -263,8 +234,9 @@ elsif_then_statements:
$$.emplace($$.begin(), branch);
}
| /* no branches */ {}
-return_statement: "return" expression
- { $$ = new boot::return_statement(boot::make_position(@1), $2); }
+return_statement:
+ "return" expression { $$ = $2; }
+ | /* no return statement */ { $$ = nullptr; }
literal:
INTEGER { $$ = new boot::literal<std::int32_t>(boot::make_position(@1), $1); }
| WORD { $$ = new boot::literal<std::uint32_t>(boot::make_position(@1), $1); }
diff --git a/boot/semantic.cc b/boot/semantic.cc
index 3486830..97c316a 100644
--- a/boot/semantic.cc
+++ b/boot/semantic.cc
@@ -139,7 +139,6 @@ namespace elna::boot
void type_analysis_visitor::visit(procedure_declaration *declaration)
{
this->current_procedure = this->bag.lookup(declaration->identifier.name)->is_procedure();
- this->returns = false;
if (declaration->body.has_value())
{
@@ -149,41 +148,53 @@ namespace elna::boot
if (declaration->body.has_value())
{
- this->bag.leave();
- if (!this->returns && declaration->heading().return_type.proper_type != nullptr)
+ if (declaration->body.value().return_expression != nullptr)
+ {
+ expression *return_expr = declaration->body.value().return_expression;
+ type return_type = this->current_procedure->symbol.return_type.proper_type;
+
+ if (!return_type.empty())
+ {
+ if (!is_assignable_from(return_type, return_expr->type_decoration))
+ {
+ add_error<type_expectation_error>(type_expectation_error::kind::result, return_expr->position());
+ }
+ }
+ else
+ {
+ add_error<type_expectation_error>(type_expectation_error::kind::result, return_expr->position());
+ }
+ }
+ else if (declaration->heading().return_type.proper_type != nullptr)
{
add_error<return_error>(declaration->identifier.name, declaration->position());
}
+ this->bag.leave();
}
this->current_procedure.reset();
}
- void type_analysis_visitor::visit(return_statement *statement)
+ void type_analysis_visitor::visit(unit *unit)
{
- walking_visitor::visit(statement);
- type return_type;
+ walking_visitor::visit(unit);
- if (this->current_procedure == nullptr)
+ if (unit->has_body())
{
- // In the main function.
- return_type = this->bag.lookup("Int")->is_type()->symbol;
- }
- else
- {
- return_type = this->current_procedure->symbol.return_type.proper_type;
- }
- if (!return_type.empty())
- {
- if (!is_assignable_from(return_type, statement->return_expression().type_decoration))
+ if (unit->return_expression != nullptr)
{
- add_error<type_expectation_error>(type_expectation_error::kind::result, statement->position());
+ type return_type = this->bag.lookup("Int")->is_type()->symbol;
+
+ if (!is_assignable_from(return_type, unit->return_expression->type_decoration))
+ {
+ add_error<type_expectation_error>(type_expectation_error::kind::result,
+ unit->return_expression->position());
+ }
+ }
+ else
+ {
+ add_error<return_error>("module", unit->position());
}
}
- else
- {
- add_error<type_expectation_error>(type_expectation_error::kind::result, statement->position());
- }
- this->returns = true;
}
void type_analysis_visitor::visit(assign_statement *statement)
@@ -641,18 +652,22 @@ namespace elna::boot
++name_iterator;
++type_iterator;
}
- for (constant_declaration *const constant : declaration->body.value().constants())
+ for (constant_declaration *const constant : declaration->body.value().constants)
{
constant->accept(this);
}
- for (variable_declaration *const variable : declaration->body.value().variables())
+ for (variable_declaration *const variable : declaration->body.value().variables)
{
variable->accept(this);
}
- for (statement *const statement : declaration->body.value().statements())
+ for (statement *const statement : declaration->body.value().entry_point)
{
statement->accept(this);
}
+ if (declaration->body.value().return_expression != nullptr)
+ {
+ declaration->body.value().return_expression->accept(this);
+ }
this->bag.leave();
}
else
@@ -698,7 +713,7 @@ namespace elna::boot
{
procedure->accept(this);
}
- if (unit->entry_point.has_value())
+ if (unit->has_body())
{
this->bag.enter();
auto variable_type = lookup_primitive_type("Int");
@@ -709,10 +724,14 @@ namespace elna::boot
variable_type = type(std::make_shared<pointer_type>(variable_type));
this->bag.enter("parameters", std::make_shared<variable_info>(variable_type, false));
- for (statement *const statement : unit->entry_point.value())
+ for (statement *const statement : unit->entry_point)
{
statement->accept(this);
}
+ if (unit->return_expression != nullptr)
+ {
+ unit->return_expression->accept(this);
+ }
this->bag.leave();
}
}
@@ -942,11 +961,11 @@ namespace elna::boot
{
return;
}
- for (constant_declaration *const constant : declaration->body.value().constants())
+ for (constant_declaration *const constant : declaration->body.value().constants)
{
constant->accept(this);
}
- for (variable_declaration *const variable : declaration->body.value().variables())
+ for (variable_declaration *const variable : declaration->body.value().variables)
{
variable->accept(this);
}
diff --git a/cl.elna b/cl.elna
index f716676..fb076ab 100644
--- a/cl.elna
+++ b/cl.elna
@@ -4728,23 +4728,6 @@ begin
return first_procedure
end
-(**
- * Skips comments.
- *)
-proc elna_lexer_skip_empty_lines(cursor: ^ElnaLexerCursor)
-var
- token: ^ElnaLexerToken
-begin
- .skip_empty_lines_rerun;
-
- token := elna_lexer_peek(cursor);
-
- if token^.kind = ElnaLexerKind.comment then
- elna_lexer_read(cursor);
- goto skip_empty_lines_rerun
- end
-end
-
proc elna_parser_type_declaration(cursor: ^ElnaLexerCursor; error_list: ^ElnaList): ^ElnaTreeTypeDeclaration
var
result: ^ElnaTreeTypeDeclaration
@@ -6163,202 +6146,6 @@ begin
elna_symbol_table_enter(symbol_table_global, "String".ptr, 6, current_info)
end
-(**
- * One time lexer initialization.
- *)
-proc elna_lexer_initialize(cursor: ^ElnaLexerCursor; code_pointer: Word)
-begin
- elna_lexer_classifications();
- elna_lexer_transitions();
-
- cursor^.start := code_pointer;
- cursor^.finish := code_pointer;
- cursor^.token := nil;
- cursor^.position.start_location.line := 1;
- cursor^.position.start_location.column := 1;
- cursor^.position.end_location.line := 1;
- cursor^.position.end_location.column := 1
-end
-
-proc elna_lexer_classify_finalize(start_position: ^Char; position: ^ElnaPosition): ^ElnaLexerToken
-var
- character: Char
- result: ^ElnaLexerToken
-begin
- character := start_position^;
-
- if character = ':' then
- result := elna_lexer_token_create(ElnaLexerKind.colon, position)
- elsif character = '.' then
- result := elna_lexer_token_create(ElnaLexerKind.dot, position)
- elsif character = '(' then
- result := elna_lexer_token_create(ElnaLexerKind.left_paren, position)
- elsif character = '-' then
- result := elna_lexer_token_create(ElnaLexerKind.minus, position)
- elsif character = '<' then
- result := elna_lexer_token_create(ElnaLexerKind.less_than, position)
- elsif character = '>' then
- result := elna_lexer_token_create(ElnaLexerKind.greater_than, position)
- end;
- return result
-end
-
-proc elna_lexer_classify_single(start_position: ^Char; position: ^ElnaPosition): ^ElnaLexerToken
-var
- character: Char
- result: ^ElnaLexerToken
-begin
- result := malloc(#size(ElnaLexerToken));
- character := start_position^;
-
- if character = ';' then
- result := elna_lexer_token_create(ElnaLexerKind.semicolon, position)
- elsif character = ',' then
- result := elna_lexer_token_create(ElnaLexerKind.comma, position)
- elsif character = ')' then
- result := elna_lexer_token_create(ElnaLexerKind.right_paren, position)
- elsif character = '@' then
- result := elna_lexer_token_create(ElnaLexerKind.at, position)
- elsif character = '~' then
- result := elna_lexer_token_create(ElnaLexerKind.not, position)
- elsif character = '&' then
- result := elna_lexer_token_create(ElnaLexerKind.and, position)
- elsif character = '+' then
- result := elna_lexer_token_create(ElnaLexerKind.plus, position)
- elsif character = '*' then
- result := elna_lexer_token_create(ElnaLexerKind.multiplication, position)
- elsif character = '=' then
- result := elna_lexer_token_create(ElnaLexerKind.equals, position)
- elsif character = '%' then
- result := elna_lexer_token_create(ElnaLexerKind.remainder, position)
- elsif character = '/' then
- result := elna_lexer_token_create(ElnaLexerKind.division, position)
- elsif character = '.' then
- result := elna_lexer_token_create(ElnaLexerKind.dot, position)
- elsif character = '^' then
- result := elna_lexer_token_create(ElnaLexerKind.hat, position)
- elsif character = '[' then
- result := elna_lexer_token_create(ElnaLexerKind.left_square, position)
- elsif character = ']' then
- result := elna_lexer_token_create(ElnaLexerKind.right_square, position)
- end;
- return result
-end
-
-proc elna_lexer_classify_composite(start_position, one_before_last: ^Char; position: ^ElnaPosition): ^ElnaLexerToken
-var
- first_character: Char
- last_character: Char
- result: ^ElnaLexerToken
-begin
- first_character := start_position^;
- last_character := one_before_last^;
-
- if first_character = ':' then
- result := elna_lexer_token_create(ElnaLexerKind.assignment, position)
- elsif first_character = '<' then
- if last_character = '=' then
- result := elna_lexer_token_create(ElnaLexerKind.less_equal, position)
- elsif last_character = '>' then
- result := elna_lexer_token_create(ElnaLexerKind.not_equal, position)
- end
- elsif first_character = '>' then
- if last_character = '=' then
- result := elna_lexer_token_create(ElnaLexerKind.greater_equal, position)
- end
- elsif first_character = '-' then
- result := elna_lexer_token_create(ElnaLexerKind.arrow, position)
- end;
- return result
-end
-
-proc elna_lexer_execute_action(cursor: ^ElnaLexerCursor; action_to_perform: Word): ^ElnaLexerToken
-var
- token: ^ElnaLexerToken
-begin
- token := nil;
-
- if action_to_perform = ElnaLexerAction.none then
- elsif action_to_perform = ElnaLexerAction.accumulate then
- elna_lexer_advance(cursor)
- elsif action_to_perform = ElnaLexerAction.skip then
- elna_lexer_classify_space(cursor^.start, @cursor^.position.end_location);
- cursor^.start := cursor^.start + 1;
- cursor^.finish := cursor^.finish + 1
- elsif action_to_perform = ElnaLexerAction.single then
- elna_lexer_advance(cursor);
-
- token := elna_lexer_classify_single(cursor^.start, @cursor^.position)
- elsif action_to_perform = ElnaLexerAction.eof then
- token := malloc(#size(ElnaLexerToken));
- token^.kind := ElnaLexerKind.eof
- elsif action_to_perform = ElnaLexerAction.finalize then
- token := elna_lexer_classify_finalize(cursor^.start, @cursor^.position)
- elsif action_to_perform = ElnaLexerAction.composite then
- token := elna_lexer_classify_composite(cursor^.start, cursor^.finish, @cursor^.position);
-
- elna_lexer_advance(cursor)
- elsif action_to_perform = ElnaLexerAction.key_id then
- token := elna_lexer_classify_keyword(cursor^.start, cursor^.finish, @cursor^.position)
- elsif action_to_perform = ElnaLexerAction.integer then
- token := elna_lexer_classify_integer(cursor^.start, cursor^.finish, @cursor^.position)
- elsif action_to_perform = ElnaLexerAction.delimited then
- elna_lexer_advance(cursor);
-
- token := elna_lexer_classify_delimited(cursor^.start, cursor^.finish, @cursor^.position)
- end;
- return token
-end
-
-proc elna_lexer_execute_transition(cursor: ^ElnaLexerCursor; kind: ^ElnaLexerKind): ^ElnaLexerToken
-var
- next_transition: ^ElnaLexerTransition
- current_character: Char
-begin
- current_character := cursor^.finish^;
- next_transition := elna_lexer_get_transition(cursor^.state, classification[current_character + 1]);
- cursor^.state := next_transition^.next_state;
-
- return elna_lexer_execute_action(cursor, next_transition^.action, kind)
-end
-
-(**
- * Reads the next token and writes its type into the address in the kind parameter.
- * Resets the lexer state for reading the next token.
- *)
-proc elna_lexer_peek(cursor: ^ElnaLexerCursor): ^ElnaLexerToken
-var
- token: ^ElnaLexerToken
-begin
- if cursor^.token = nil then
- cursor^.state := ElnaLexerState.start;
-
- .elna_lexer_peek_loop;
- token := elna_lexer_execute_transition(cursor);
-
- if cursor^.state <> ElnaLexerState.finish then
- goto elna_lexer_peek_loop
- end;
- cursor^.token := token
- end;
- return cursor^.token
-end
-
-(**
- * Reads the token and advance the lexer.
- *)
-proc elna_lexer_read(cursor: ^ElnaLexerCursor): ^ElnaLexerToken
-var
- token: ^ElnaLexerToken
-begin
- token := elna_lexer_peek(cursor);
- cursor^.token := nil;
- cursor^.start := cursor^.finish;
- cursor^.position.start_location := cursor^.position.end_location;
-
- return token
-end
-
proc initialize_global_state()
begin
stdin := fdopen(0, "r\0".ptr);
diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc
index 497bcc6..30dd68b 100644
--- a/gcc/gcc/elna-generic.cc
+++ b/gcc/gcc/elna-generic.cc
@@ -196,7 +196,7 @@ namespace elna::gcc
{
procedure->accept(this);
}
- if (unit->entry_point.has_value())
+ if (unit->has_body())
{
tree declaration_type = build_function_type_list(elna_int_type_node,
elna_int_type_node,
@@ -225,11 +225,13 @@ namespace elna::gcc
DECL_ARGUMENTS(fndecl) = chainon(DECL_ARGUMENTS(fndecl), declaration_tree);
parameter_type = TREE_CHAIN(parameter_type);
}
- visit_statements(unit->entry_point.value());
+ visit_statements(unit->entry_point);
+ unit->return_expression->accept(this);
tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(fndecl),
- build_int_cst_type(integer_type_node, 0));
+ this->current_expression);
tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
append_statement(return_stmt);
+ this->current_expression = NULL_TREE;
tree mapping = leave_scope();
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
@@ -264,15 +266,33 @@ namespace elna::gcc
{
this->symbols->enter(IDENTIFIER_POINTER(DECL_NAME(argument_chain)), argument_chain);
}
- for (boot::constant_declaration *const constant : declaration->body.value().constants())
+ for (boot::constant_declaration *const constant : declaration->body.value().constants)
{
constant->accept(this);
}
- for (boot::variable_declaration *const variable : declaration->body.value().variables())
+ for (boot::variable_declaration *const variable : declaration->body.value().variables)
{
variable->accept(this);
}
- visit_statements(declaration->body.value().statements());
+ visit_statements(declaration->body.value().entry_point);
+
+ if (declaration->body.value().return_expression != nullptr)
+ {
+ location_t position = get_location(&declaration->body.value().return_expression->position());
+ tree set_result{ NULL_TREE };
+
+ if (TREE_THIS_VOLATILE(current_function_decl) != 1)
+ {
+ declaration->body.value().return_expression->accept(this);
+
+ set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(current_function_decl),
+ this->current_expression);
+ }
+ tree return_stmt = build1_loc(position, RETURN_EXPR, void_type_node, set_result);
+ append_statement(return_stmt);
+
+ this->current_expression = NULL_TREE;
+ }
tree mapping = leave_scope();
this->bag.leave();
@@ -1066,30 +1086,6 @@ namespace elna::gcc
}
}
- void generic_visitor::visit(boot::return_statement *statement)
- {
- boot::expression *return_expression = &statement->return_expression();
- location_t statement_position = get_location(&statement->position());
- tree set_result{ NULL_TREE };
-
- if (TREE_THIS_VOLATILE(current_function_decl) == 1)
- {
- error_at(statement_position, "This procedure is not allowed to return");
- return;
- }
- if (return_expression != nullptr)
- {
- return_expression->accept(this);
-
- set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(current_function_decl),
- this->current_expression);
- }
- tree return_stmt = build1_loc(statement_position, RETURN_EXPR, void_type_node, set_result);
- append_statement(return_stmt);
-
- this->current_expression = NULL_TREE;
- }
-
void generic_visitor::visit(boot::defer_statement *statement)
{
enter_scope();
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index d9f3af8..ab79c30 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -64,7 +64,6 @@ namespace elna::boot
class if_statement;
class import_declaration;
class while_statement;
- class return_statement;
class case_statement;
class traits_expression;
class unit;
@@ -103,7 +102,6 @@ namespace elna::boot
virtual void visit(if_statement *) = 0;
virtual void visit(import_declaration *) = 0;
virtual void visit(while_statement *) = 0;
- virtual void visit(return_statement *) = 0;
virtual void visit(defer_statement *) = 0;
virtual void visit(case_statement *) = 0;
virtual void visit(empty_statement *) = 0;
@@ -148,7 +146,6 @@ namespace elna::boot
[[noreturn]] virtual void visit(if_statement *) override;
[[noreturn]] virtual void visit(import_declaration *) override;
[[noreturn]] virtual void visit(while_statement *) override;
- [[noreturn]] virtual void visit(return_statement *) override;
[[noreturn]] virtual void visit(defer_statement *) override;
[[noreturn]] virtual void visit(empty_statement *) override;
[[noreturn]] virtual void visit(case_statement *) override;
@@ -191,7 +188,6 @@ namespace elna::boot
virtual void visit(if_statement *) override;
virtual void visit(import_declaration *) override;
virtual void visit(while_statement *statement) override;
- virtual void visit(return_statement *statement) override;
virtual void visit(defer_statement *statement) override;
virtual void visit(empty_statement *) override;
virtual void visit(case_statement *statement) override;
@@ -416,26 +412,21 @@ namespace elna::boot
struct procedure_body
{
- procedure_body(std::vector<constant_declaration*>&& constants,
- std::vector<variable_declaration *>&& variables, std::vector<statement *>&& statements);
- procedure_body(std::vector<constant_declaration*>&& constants, std::vector<variable_declaration *>&& variables);
+ const std::vector<constant_declaration *> constants;
+ const std::vector<variable_declaration *> variables;
+ const std::vector<statement *> entry_point;
+ expression *const return_expression{ nullptr };
+
+ procedure_body(std::vector<constant_declaration *>&& constants,
+ std::vector<variable_declaration *>&& variables,
+ std::vector<statement *>&& entry_point,
+ expression *return_expr = nullptr);
procedure_body(const procedure_body&) = delete;
procedure_body(procedure_body&& that);
procedure_body& operator=(const procedure_body&) = delete;
- procedure_body& operator=(procedure_body&& that);
-
- const std::vector<variable_declaration *>& variables();
- const std::vector<constant_declaration *>& constants();
- const std::vector<statement *>& statements();
virtual ~procedure_body();
-
- private:
- std::vector<variable_declaration *> m_variables;
- std::vector<constant_declaration *> m_constants;
- std::vector<statement *> m_statements;
-
};
/**
@@ -526,19 +517,6 @@ namespace elna::boot
virtual ~conditional_statements();
};
- class return_statement : public statement
- {
- public:
- expression *m_return_expression;
-
- return_statement(const struct position position, expression *return_expression);
- void accept(parser_visitor *visitor) override;
-
- expression& return_expression();
-
- virtual ~return_statement() override;
- };
-
struct switch_case
{
std::vector<expression *> labels;
@@ -728,19 +706,23 @@ namespace elna::boot
virtual ~while_statement() override;
};
- class unit : public node
+ class unit : public node, public procedure_body
{
public:
- const std::optional<std::vector<statement *>> entry_point;
-
- std::vector<import_declaration *> imports;
- std::vector<constant_declaration *> constants;
- std::vector<type_declaration *> types;
- std::vector<variable_declaration *> variables;
- std::vector<procedure_declaration *> procedures;
+ const std::vector<import_declaration *> imports;
+ const std::vector<type_declaration *> types;
+ const std::vector<procedure_declaration *> procedures;
unit(const struct position position);
- unit(const struct position position, std::vector<statement *>&& entry_point);
+ unit(const struct position position,
+ std::vector<import_declaration *>&& imports,
+ std::vector<constant_declaration *>&& constants,
+ std::vector<type_declaration *>&& types,
+ std::vector<variable_declaration *>&& variables,
+ std::vector<procedure_declaration *>&& procedures,
+ std::vector<statement *>&& entry_point,
+ expression *const return_expression = nullptr);
+ bool has_body() const;
virtual void accept(parser_visitor *visitor) override;
virtual ~unit() override;
diff --git a/include/elna/boot/semantic.h b/include/elna/boot/semantic.h
index b94d269..1e81ebb 100644
--- a/include/elna/boot/semantic.h
+++ b/include/elna/boot/semantic.h
@@ -18,10 +18,8 @@ along with GCC; see the file COPYING3. If not see
#pragma once
#include <string>
-#include <unordered_map>
#include <memory>
#include <set>
-#include <deque>
#include "elna/boot/ast.h"
#include "elna/boot/result.h"
@@ -147,7 +145,6 @@ namespace elna::boot
*/
class type_analysis_visitor final : public walking_visitor, public error_container
{
- bool returns;
symbol_bag bag;
std::shared_ptr<procedure_info> current_procedure;
@@ -161,7 +158,7 @@ namespace elna::boot
explicit type_analysis_visitor(symbol_bag bag);
void visit(procedure_declaration *declaration) override;
- void visit(return_statement *statement) override;
+ void visit(unit *unit) override;
void visit(assign_statement *statement) override;
void visit(variable_declaration *declaration) override;
void visit(type_declaration *declaration) override;
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index 28bfe2d..2fe4d48 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -18,8 +18,6 @@ along with GCC; see the file COPYING3. If not see
#pragma once
#include <string>
-#include <forward_list>
-
#include "elna/boot/ast.h"
#include "elna/boot/symbol.h"
#include "elna/boot/semantic.h"
@@ -89,7 +87,6 @@ namespace elna::gcc
void visit(boot::if_statement *statement) override;
void visit(boot::import_declaration *) override;
void visit(boot::while_statement *statement) override;
- void visit(boot::return_statement *statement) override;
void visit(boot::defer_statement *statement) override;
void visit(boot::empty_statement *) override;
void visit(boot::case_statement *statement) override;
diff --git a/source/lexer.elna b/source/lexer.elna
index 5029ec5..62ad3b1 100644
--- a/source/lexer.elna
+++ b/source/lexer.elna
@@ -622,4 +622,209 @@ begin
return result
end
+proc elna_lexer_classify_finalize(start_position: ^Char; position: ^ElnaPosition): ^ElnaLexerToken
+var
+ character: Char
+ result: ^ElnaLexerToken
+begin
+ character := start_position^;
+
+ if character = ':' then
+ result := elna_lexer_token_create(ElnaLexerKind.colon, position)
+ elsif character = '.' then
+ result := elna_lexer_token_create(ElnaLexerKind.dot, position)
+ elsif character = '(' then
+ result := elna_lexer_token_create(ElnaLexerKind.left_paren, position)
+ elsif character = '-' then
+ result := elna_lexer_token_create(ElnaLexerKind.minus, position)
+ elsif character = '<' then
+ result := elna_lexer_token_create(ElnaLexerKind.less_than, position)
+ elsif character = '>' then
+ result := elna_lexer_token_create(ElnaLexerKind.greater_than, position)
+ end;
+ return result
+end
+
+proc elna_lexer_classify_single(start_position: ^Char; position: ^ElnaPosition): ^ElnaLexerToken
+var
+ character: Char
+ result: ^ElnaLexerToken
+begin
+ result := malloc(#size(ElnaLexerToken));
+ character := start_position^;
+
+ if character = ';' then
+ result := elna_lexer_token_create(ElnaLexerKind.semicolon, position)
+ elsif character = ',' then
+ result := elna_lexer_token_create(ElnaLexerKind.comma, position)
+ elsif character = ')' then
+ result := elna_lexer_token_create(ElnaLexerKind.right_paren, position)
+ elsif character = '@' then
+ result := elna_lexer_token_create(ElnaLexerKind.at, position)
+ elsif character = '~' then
+ result := elna_lexer_token_create(ElnaLexerKind.not, position)
+ elsif character = '&' then
+ result := elna_lexer_token_create(ElnaLexerKind.and, position)
+ elsif character = '+' then
+ result := elna_lexer_token_create(ElnaLexerKind.plus, position)
+ elsif character = '*' then
+ result := elna_lexer_token_create(ElnaLexerKind.multiplication, position)
+ elsif character = '=' then
+ result := elna_lexer_token_create(ElnaLexerKind.equals, position)
+ elsif character = '%' then
+ result := elna_lexer_token_create(ElnaLexerKind.remainder, position)
+ elsif character = '/' then
+ result := elna_lexer_token_create(ElnaLexerKind.division, position)
+ elsif character = '.' then
+ result := elna_lexer_token_create(ElnaLexerKind.dot, position)
+ elsif character = '^' then
+ result := elna_lexer_token_create(ElnaLexerKind.hat, position)
+ elsif character = '[' then
+ result := elna_lexer_token_create(ElnaLexerKind.left_square, position)
+ elsif character = ']' then
+ result := elna_lexer_token_create(ElnaLexerKind.right_square, position)
+ end;
+ return result
+end
+
+proc elna_lexer_classify_composite(start_position, one_before_last: ^Char; position: ^ElnaPosition): ^ElnaLexerToken
+var
+ first_character: Char
+ last_character: Char
+ result: ^ElnaLexerToken
+begin
+ first_character := start_position^;
+ last_character := one_before_last^;
+
+ if first_character = ':' then
+ result := elna_lexer_token_create(ElnaLexerKind.assignment, position)
+ elsif first_character = '<' then
+ if last_character = '=' then
+ result := elna_lexer_token_create(ElnaLexerKind.less_equal, position)
+ elsif last_character = '>' then
+ result := elna_lexer_token_create(ElnaLexerKind.not_equal, position)
+ end
+ elsif first_character = '>' then
+ if last_character = '=' then
+ result := elna_lexer_token_create(ElnaLexerKind.greater_equal, position)
+ end
+ end;
+ return result
+end
+
+proc elna_lexer_execute_action(cursor: ^ElnaLexerCursor; action_to_perform: ElnaLexerAction): ^ElnaLexerToken
+var
+ token: ^ElnaLexerToken
+begin
+ token := nil;
+
+ if action_to_perform = ElnaLexerAction.none then
+ elsif action_to_perform = ElnaLexerAction.accumulate then
+ elna_lexer_advance(cursor)
+ elsif action_to_perform = ElnaLexerAction.skip then
+ elna_lexer_classify_space(cursor^.start, @cursor^.position.end_location);
+ cursor^.start := cursor^.start + 1;
+ cursor^.finish := cursor^.finish + 1
+ elsif action_to_perform = ElnaLexerAction.single then
+ elna_lexer_advance(cursor);
+
+ token := elna_lexer_classify_single(cursor^.start, @cursor^.position)
+ elsif action_to_perform = ElnaLexerAction.eof then
+ token := malloc(#size(ElnaLexerToken));
+ token^.kind := ElnaLexerKind.eof
+ elsif action_to_perform = ElnaLexerAction.finalize then
+ token := elna_lexer_classify_finalize(cursor^.start, @cursor^.position)
+ elsif action_to_perform = ElnaLexerAction.composite then
+ token := elna_lexer_classify_composite(cursor^.start, cursor^.finish, @cursor^.position);
+
+ elna_lexer_advance(cursor)
+ elsif action_to_perform = ElnaLexerAction.key_id then
+ token := elna_lexer_classify_keyword(cursor^.start, cursor^.finish, @cursor^.position)
+ elsif action_to_perform = ElnaLexerAction.integer then
+ token := elna_lexer_classify_integer(cursor^.start, cursor^.finish, @cursor^.position)
+ elsif action_to_perform = ElnaLexerAction.delimited then
+ elna_lexer_advance(cursor);
+
+ token := elna_lexer_classify_delimited(cursor^.start, cursor^.finish, @cursor^.position)
+ end;
+ return token
+end
+
+proc elna_lexer_execute_transition(cursor: ^ElnaLexerCursor): ^ElnaLexerToken
+var
+ next_transition: ^ElnaLexerTransition
+ current_character: Char
+begin
+ current_character := cursor^.finish^;
+ next_transition := elna_lexer_get_transition(cursor^.state,
+ classification[cast(current_character: Word) + 1u]);
+ cursor^.state := next_transition^.next_state;
+
+ return elna_lexer_execute_action(cursor, next_transition^.action)
+end
+
+(**
+ * One time lexer initialization.
+ *)
+proc elna_lexer_initialize(cursor: ^ElnaLexerCursor; code_pointer: ^Char)
+begin
+ elna_lexer_classifications();
+ elna_lexer_transitions();
+
+ cursor^.start := code_pointer;
+ cursor^.finish := code_pointer;
+ cursor^.token := nil;
+ cursor^.position.start_location := ElnaLocation(1u, 1u);
+ cursor^.position.end_location := ElnaLocation(1u, 1u);
+end
+
+(**
+ * Reads the next token and writes its type into the address in the kind parameter.
+ * Resets the lexer state for reading the next token.
+ *)
+proc elna_lexer_peek(cursor: ^ElnaLexerCursor): ^ElnaLexerToken
+var
+ token: ^ElnaLexerToken
+begin
+ if cursor^.token = nil then
+ cursor^.state := ElnaLexerState.start;
+
+ while cursor^.state <> ElnaLexerState.finish do
+ token := elna_lexer_execute_transition(cursor)
+ end;
+ cursor^.token := token
+ end;
+ return cursor^.token
+end
+
+(**
+ * Reads the token and advance the lexer.
+ *)
+proc elna_lexer_read(cursor: ^ElnaLexerCursor): ^ElnaLexerToken
+var
+ token: ^ElnaLexerToken
+begin
+ token := elna_lexer_peek(cursor);
+ cursor^.token := nil;
+ cursor^.start := cursor^.finish;
+ cursor^.position.start_location := cursor^.position.end_location;
+
+ return token
+end
+
+(**
+ * Skips comments.
+ *)
+proc elna_lexer_skip_empty_lines(cursor: ^ElnaLexerCursor)
+var
+ token: ^ElnaLexerToken
+begin
+ token := elna_lexer_peek(cursor);
+
+ while token^.kind = ElnaLexerKind.comment do
+ elna_lexer_read(cursor);
+ token := elna_lexer_peek(cursor)
+ end
+end
+
end.
diff --git a/source/main.elna b/source/main.elna
index 37d0f07..b7ce29c 100644
--- a/source/main.elna
+++ b/source/main.elna
@@ -851,5 +851,6 @@ end
begin
initialize_global_state();
+
return process(count, parameters)
end.
diff --git a/testsuite/compilable/pointer_cast.elna b/testsuite/compilable/pointer_cast.elna
index d10fb23..64b99ca 100644
--- a/testsuite/compilable/pointer_cast.elna
+++ b/testsuite/compilable/pointer_cast.elna
@@ -4,5 +4,7 @@ var
begin
p := c;
- c := p
+ c := p;
+
+ return 0
end.
diff --git a/testsuite/fail_compilation/module_without_return.elna b/testsuite/fail_compilation/module_without_return.elna
new file mode 100644
index 0000000..f2ece07
--- /dev/null
+++ b/testsuite/fail_compilation/module_without_return.elna
@@ -0,0 +1,6 @@
+var (* @Error Procedure 'module' is expected to return, but does not have a return statement *)
+ x: Int
+
+begin
+ x := 42
+end.