Type check the return statement
This commit is contained in:
191
boot/ast.cc
191
boot/ast.cc
@ -33,14 +33,6 @@ namespace elna::boot
|
||||
return this->source_position;
|
||||
}
|
||||
|
||||
statement::statement()
|
||||
{
|
||||
}
|
||||
|
||||
statement::~statement()
|
||||
{
|
||||
}
|
||||
|
||||
assign_statement *statement::is_assign()
|
||||
{
|
||||
return nullptr;
|
||||
@ -71,14 +63,6 @@ namespace elna::boot
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
expression::expression()
|
||||
{
|
||||
}
|
||||
|
||||
expression::~expression()
|
||||
{
|
||||
}
|
||||
|
||||
cast_expression *expression::is_cast()
|
||||
{
|
||||
return nullptr;
|
||||
@ -114,39 +98,6 @@ namespace elna::boot
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
if (cast_expression *node = is_cast())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (traits_expression *node = is_traits())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (binary_expression *node = is_binary())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (unary_expression *node = is_unary())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (designator_expression *node = is_designator())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (procedure_call *node = is_call_expression())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal_expression *node = is_literal())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
type_expression::type_expression(const struct position position)
|
||||
: node(position)
|
||||
{
|
||||
@ -182,35 +133,6 @@ namespace elna::boot
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void type_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
if (std::shared_ptr<primitive_type_expression> node = is_primitive())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (std::shared_ptr<array_type_expression> node = is_array())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (std::shared_ptr<pointer_type_expression> node = is_pointer())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (std::shared_ptr<record_type_expression> node = is_record())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (std::shared_ptr<union_type_expression> node = is_union())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (std::shared_ptr<procedure_type_expression> node = is_procedure())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
primitive_type_expression::primitive_type_expression(const struct position position, const std::string& name)
|
||||
: type_expression(position), name(name)
|
||||
{
|
||||
@ -301,8 +223,8 @@ namespace elna::boot
|
||||
}
|
||||
|
||||
variable_declaration::variable_declaration(const struct position position, const std::string& identifier,
|
||||
std::shared_ptr<type_expression> type, const bool exported)
|
||||
: definition(position, identifier, exported), m_type(type)
|
||||
std::shared_ptr<type_expression> variable_type, const bool exported)
|
||||
: definition(position, identifier, exported), m_variable_type(variable_type)
|
||||
{
|
||||
}
|
||||
|
||||
@ -313,7 +235,7 @@ namespace elna::boot
|
||||
|
||||
type_expression& variable_declaration::variable_type()
|
||||
{
|
||||
return *m_type;
|
||||
return *m_variable_type;
|
||||
}
|
||||
|
||||
definition::definition(const struct position position, const std::string& identifier, const bool exported)
|
||||
@ -462,47 +384,16 @@ namespace elna::boot
|
||||
return this;
|
||||
}
|
||||
|
||||
void literal_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
if (literal<std::int32_t> *node = is_int())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<std::uint32_t> *node = is_word())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<double> *node = is_float())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<bool> *node = is_bool())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<unsigned char> *node = is_char())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<std::nullptr_t> *node = is_nil())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else if (literal<std::string> *node = is_string())
|
||||
{
|
||||
return node->accept(visitor);
|
||||
}
|
||||
else
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
defer_statement::defer_statement(const struct position position)
|
||||
: node(position)
|
||||
{
|
||||
}
|
||||
|
||||
void defer_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
defer_statement *defer_statement::is_defer()
|
||||
{
|
||||
return this;
|
||||
@ -529,11 +420,37 @@ namespace elna::boot
|
||||
return this;
|
||||
}
|
||||
|
||||
void designator_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
if (variable_expression *node = is_variable())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
else if (array_access_expression *node = is_array_access())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
else if (field_access_expression *node = is_field_access())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
else if (dereference_expression *node = is_dereference())
|
||||
{
|
||||
return visitor->visit(node);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
variable_expression::variable_expression(const struct position position, const std::string& name)
|
||||
: node(position), name(name)
|
||||
{
|
||||
}
|
||||
|
||||
void variable_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
variable_expression *variable_expression::is_variable()
|
||||
{
|
||||
return this;
|
||||
@ -545,6 +462,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void array_access_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
expression& array_access_expression::index()
|
||||
{
|
||||
return *m_index;
|
||||
@ -572,6 +494,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void field_access_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
expression& field_access_expression::base()
|
||||
{
|
||||
return *m_base;
|
||||
@ -598,6 +525,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void dereference_expression::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
expression& dereference_expression::base()
|
||||
{
|
||||
return *m_base;
|
||||
@ -686,6 +618,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void procedure_call::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
procedure_call *procedure_call::is_call_statement()
|
||||
{
|
||||
return this;
|
||||
@ -780,6 +717,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void return_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
return_statement *return_statement::is_return()
|
||||
{
|
||||
return this;
|
||||
@ -801,6 +743,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void assign_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
assign_statement *assign_statement::is_assign()
|
||||
{
|
||||
return this;
|
||||
@ -847,6 +794,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void if_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
if_statement *if_statement::is_if()
|
||||
{
|
||||
return this;
|
||||
@ -877,6 +829,11 @@ namespace elna::boot
|
||||
{
|
||||
}
|
||||
|
||||
void while_statement::accept(parser_visitor *visitor)
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
while_statement *while_statement::is_while()
|
||||
{
|
||||
return this;
|
||||
|
@ -286,10 +286,15 @@ if_statement:
|
||||
$$ = new boot::if_statement(boot::make_position(@1), then, _else);
|
||||
std::swap($5, $$->branches);
|
||||
}
|
||||
return_statement: "return" expression
|
||||
return_statement:
|
||||
"return" expression
|
||||
{
|
||||
$$ = new boot::return_statement(boot::make_position(@1), $2);
|
||||
}
|
||||
| "return"
|
||||
{
|
||||
$$ = new boot::return_statement(boot::make_position(@1));
|
||||
}
|
||||
defer_statement: DEFER statements "end"
|
||||
{
|
||||
$$ = new boot::defer_statement(boot::make_position(@1));
|
||||
@ -472,9 +477,9 @@ statements:
|
||||
field_declaration:
|
||||
IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); }
|
||||
required_fields:
|
||||
field_declaration required_fields
|
||||
field_declaration ";" required_fields
|
||||
{
|
||||
std::swap($$, $2);
|
||||
std::swap($$, $3);
|
||||
$$.emplace($$.cbegin(), $1);
|
||||
}
|
||||
| field_declaration { $$.emplace_back($1); }
|
||||
@ -534,14 +539,14 @@ constant_definition: identifier_definition "=" literal
|
||||
$$ = new boot::constant_definition(boot::make_position(@1), $1.first, $1.second, $3);
|
||||
}
|
||||
constant_definitions:
|
||||
constant_definition constant_definitions
|
||||
constant_definition ";" constant_definitions
|
||||
{
|
||||
std::swap($$, $2);
|
||||
std::swap($$, $3);
|
||||
$$.insert($$.cbegin(), $1);
|
||||
}
|
||||
| /* no constant definitions */ {}
|
||||
constant_part:
|
||||
{}
|
||||
/* no constant definitions */ {}
|
||||
| "const" constant_definitions { std::swap($$, $2); }
|
||||
type_definition: identifier_definition "=" type_expression
|
||||
{
|
||||
@ -553,10 +558,9 @@ type_definitions:
|
||||
std::swap($$, $2);
|
||||
$$.insert($$.cbegin(), $1);
|
||||
}
|
||||
| type_definition { $$.push_back($1); }
|
||||
| /* no type definitions */ {}
|
||||
type_part:
|
||||
/* no type definitions */ {}
|
||||
| "type" {}
|
||||
| "type" type_definitions { std::swap($$, $2); }
|
||||
formal_parameter: IDENTIFIER ":" type_expression
|
||||
{
|
||||
|
179
boot/semantic.cc
179
boot/semantic.cc
@ -65,6 +65,18 @@ namespace elna::boot
|
||||
auto info = std::make_shared<type_info>(type_info(type(unresolved.second)));
|
||||
this->symbols->enter(std::move(unresolved.first), info);
|
||||
}
|
||||
for (variable_declaration *const variable : program->variables)
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
for (procedure_definition *const procedure : program->procedures)
|
||||
{
|
||||
procedure->accept(this);
|
||||
}
|
||||
for (statement *const statement : program->body)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(type_definition *definition)
|
||||
@ -106,142 +118,219 @@ namespace elna::boot
|
||||
this->current_type = type(std::make_shared<array_type>(this->current_type, type_expression->size));
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(record_type_expression *)
|
||||
void declaration_visitor::visit(record_type_expression *type_expression)
|
||||
{
|
||||
this->current_type = type(std::make_shared<record_type>());
|
||||
auto result_type = std::make_shared<record_type>();
|
||||
|
||||
for (auto& field : type_expression->fields)
|
||||
{
|
||||
field.second->accept(this);
|
||||
result_type->fields.push_back(std::make_pair(field.first, this->current_type));
|
||||
}
|
||||
this->current_type = type(result_type);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(union_type_expression *)
|
||||
void declaration_visitor::visit(union_type_expression *type_expression)
|
||||
{
|
||||
this->current_type = type(std::make_shared<union_type>());
|
||||
auto result_type = std::make_shared<union_type>();
|
||||
|
||||
for (auto& field : type_expression->fields)
|
||||
{
|
||||
field.second->accept(this);
|
||||
result_type->fields.push_back(std::make_pair(field.first, this->current_type));
|
||||
}
|
||||
this->current_type = type(result_type);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(procedure_type_expression *)
|
||||
{
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(variable_declaration *)
|
||||
void declaration_visitor::visit(variable_declaration *declaration)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
declaration->variable_type().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(constant_definition *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(procedure_definition *)
|
||||
void declaration_visitor::visit(procedure_definition *definition)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
for (auto heading_parameter : definition->heading().parameters)
|
||||
{
|
||||
heading_parameter->accept(this);
|
||||
}
|
||||
if (definition->heading().return_type.type != nullptr)
|
||||
{
|
||||
definition->heading().return_type.type->accept(this);
|
||||
}
|
||||
if (definition->body != nullptr)
|
||||
{
|
||||
definition->body->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(assign_statement *)
|
||||
void declaration_visitor::visit(assign_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
statement->lvalue().accept(this);
|
||||
statement->rvalue().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(if_statement *)
|
||||
void declaration_visitor::visit(if_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
statement->body().prerequisite().accept(this);
|
||||
for (struct statement *const statement : statement->body().statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
for (const auto branch : statement->branches)
|
||||
{
|
||||
branch->prerequisite().accept(this);
|
||||
|
||||
for (struct statement *const statement : branch->statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
if (statement->alternative() != nullptr)
|
||||
{
|
||||
for (struct statement *const statement : *statement->alternative())
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(while_statement *)
|
||||
void declaration_visitor::visit(while_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
statement->body().prerequisite().accept(this);
|
||||
for (struct statement *const statement : statement->body().statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
for (const auto branch : statement->branches)
|
||||
{
|
||||
branch->prerequisite().accept(this);
|
||||
|
||||
for (struct statement *const statement : branch->statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(return_statement *)
|
||||
void declaration_visitor::visit(return_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
if (statement->return_expression() != nullptr)
|
||||
{
|
||||
statement->return_expression()->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(defer_statement *)
|
||||
void declaration_visitor::visit(defer_statement *statement)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
for (struct statement *const statement : statement->statements)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(procedure_call *)
|
||||
void declaration_visitor::visit(procedure_call *call)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
call->callable().accept(this);
|
||||
for (expression *const argument: call->arguments)
|
||||
{
|
||||
argument->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(block *)
|
||||
void declaration_visitor::visit(block *block)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
for (constant_definition *const constant : block->constants)
|
||||
{
|
||||
constant->accept(this);
|
||||
}
|
||||
for (variable_declaration *const variable : block->variables)
|
||||
{
|
||||
variable->accept(this);
|
||||
}
|
||||
for (statement *const statement : block->body)
|
||||
{
|
||||
statement->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(traits_expression *)
|
||||
void declaration_visitor::visit(traits_expression *trait)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
if (!trait->parameters.empty())
|
||||
{
|
||||
trait->parameters.front()->accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(cast_expression *)
|
||||
void declaration_visitor::visit(cast_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->value().accept(this);
|
||||
expression->target().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(binary_expression *)
|
||||
void declaration_visitor::visit(binary_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->lhs().accept(this);
|
||||
expression->rhs().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(unary_expression *)
|
||||
void declaration_visitor::visit(unary_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->operand().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(variable_expression *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(array_access_expression *)
|
||||
void declaration_visitor::visit(array_access_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->base().accept(this);
|
||||
expression->index().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(field_access_expression *)
|
||||
void declaration_visitor::visit(field_access_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->base().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(dereference_expression *)
|
||||
void declaration_visitor::visit(dereference_expression *expression)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
expression->base().accept(this);
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<std::int32_t> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<std::uint32_t> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<double> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<bool> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<unsigned char> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<std::nullptr_t> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void declaration_visitor::visit(literal<std::string> *)
|
||||
{
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user