Add procedure type expression

This commit is contained in:
Eugen Wissner 2025-02-22 02:43:58 +01:00
parent ff9169a98c
commit 18857e1a88
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
7 changed files with 199 additions and 142 deletions

View File

@ -49,7 +49,7 @@ namespace :boot do
"--build=#{options.build}",
"--host=#{options.build}"
]
flags = '-O2 -fPIC -I/opt/homebrew/Cellar/flex/2.6.4_2/include'
flags = '-O0 -g -fPIC -I/opt/homebrew/Cellar/flex/2.6.4_2/include'
env = {
'CC' => options.gcc,
'CXX' => options.gxx,

View File

@ -32,13 +32,10 @@ namespace boot
void empty_visitor::visit(procedure_definition *definition)
{
for (auto parameter : definition->parameters)
definition->heading().accept(this);
if (definition->body != nullptr)
{
parameter->accept(this);
}
if (definition->body() != nullptr)
{
definition->body()->accept(this);
definition->body->accept(this);
}
}
@ -182,6 +179,18 @@ namespace boot
}
}
void empty_visitor::visit(procedure_type *expression)
{
for (auto parameter : expression->parameters)
{
parameter->accept(this);
}
if (expression->return_type != nullptr)
{
expression->return_type->accept(this);
}
}
void empty_visitor::visit(variable_expression *)
{
}
@ -255,27 +264,32 @@ namespace boot
{
}
basic_type *top_type::is_basic()
std::shared_ptr<basic_type> top_type::is_basic()
{
return nullptr;
}
array_type *top_type::is_array()
std::shared_ptr<array_type> top_type::is_array()
{
return nullptr;
}
record_type *top_type::is_record()
std::shared_ptr<record_type> top_type::is_record()
{
return nullptr;
}
union_type *top_type::is_union()
std::shared_ptr<union_type> top_type::is_union()
{
return nullptr;
}
pointer_type *top_type::is_pointer()
std::shared_ptr<pointer_type> top_type::is_pointer()
{
return nullptr;
}
std::shared_ptr<procedure_type> top_type::is_procedure()
{
return nullptr;
}
@ -295,9 +309,9 @@ namespace boot
return m_name;
}
basic_type *basic_type::is_basic()
std::shared_ptr<basic_type> basic_type::is_basic()
{
return this;
return std::static_pointer_cast<basic_type>(shared_from_this());
}
array_type::array_type(const struct position position, std::shared_ptr<top_type> base, const std::uint32_t size)
@ -315,9 +329,9 @@ namespace boot
return *m_base;
}
array_type*array_type::is_array()
std::shared_ptr<array_type> array_type::is_array()
{
return this;
return std::static_pointer_cast<array_type>(shared_from_this());
}
pointer_type::pointer_type(const struct position position, std::shared_ptr<top_type> base)
@ -335,18 +349,13 @@ namespace boot
return *m_base;
}
pointer_type *pointer_type::is_pointer()
{
return this;
}
composite_type::composite_type(const struct position position, fields_t&& fields)
: top_type(position), fields(std::move(fields))
std::shared_ptr<pointer_type> pointer_type::is_pointer()
{
return std::static_pointer_cast<pointer_type>(shared_from_this());
}
record_type::record_type(const struct position position, fields_t&& fields)
: composite_type(position, std::move(fields))
: top_type(position), fields(std::move(fields))
{
}
@ -355,19 +364,19 @@ namespace boot
visitor->visit(this);
}
record_type *record_type::is_record()
std::shared_ptr<record_type> record_type::is_record()
{
return this;
return std::static_pointer_cast<record_type>(shared_from_this());
}
union_type::union_type(const struct position position, fields_t&& fields)
: composite_type(position, std::move(fields))
: top_type(position), fields(std::move(fields))
{
}
union_type *union_type::is_union()
std::shared_ptr<union_type> union_type::is_union()
{
return this;
return std::static_pointer_cast<union_type>(shared_from_this());
}
void union_type::accept(parser_visitor *visitor)
@ -417,15 +426,37 @@ namespace boot
delete m_body;
}
procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
const bool exported, std::shared_ptr<top_type> return_type)
: definition(position, identifier, exported), m_return_type(return_type), no_return{ false }
procedure_type::procedure_type(const struct position position, std::shared_ptr<top_type> return_type)
: top_type(position), return_type(return_type), no_return(false)
{
}
procedure_type::procedure_type(const struct position position, no_return_t)
: top_type(position), return_type(nullptr), no_return(true)
{
}
void procedure_type::accept(parser_visitor *visitor)
{
visitor->visit(this);
}
std::shared_ptr<procedure_type> procedure_type::is_procedure()
{
return std::static_pointer_cast<procedure_type>(shared_from_this());
}
procedure_type::~procedure_type()
{
for (auto parameter : this->parameters)
{
delete parameter;
}
}
procedure_definition::procedure_definition(const struct position position, const std::string& identifier,
const bool exported, no_return_t)
: definition(position, identifier, exported), m_return_type(nullptr), no_return{ true }
const bool exported, std::shared_ptr<procedure_type> heading, block *body)
: definition(position, identifier, exported), m_heading(heading), body(body)
{
}
@ -434,32 +465,14 @@ namespace boot
visitor->visit(this);
}
block *procedure_definition::body()
procedure_type& procedure_definition::heading()
{
return m_body;
}
procedure_definition *procedure_definition::add_body(block *procedure_body)
{
m_body = procedure_body;
return this;
}
std::shared_ptr<top_type> procedure_definition::return_type()
{
return m_return_type;
return *m_heading;
}
procedure_definition::~procedure_definition()
{
if (m_body != nullptr)
{
delete m_body;
}
for (auto parameter : parameters)
{
delete parameter;
}
delete body;
}
type_definition::type_definition(const struct position position, const std::string& identifier,
@ -846,10 +859,7 @@ namespace boot
return_statement::~return_statement()
{
if (m_return_expression != nullptr)
{
delete m_return_expression;
}
delete m_return_expression;
}
void assign_statement::accept(parser_visitor *visitor)
@ -926,10 +936,7 @@ namespace boot
{
delete branch;
}
if (m_alternative != nullptr)
{
delete m_alternative;
}
delete m_alternative;
}
while_statement::while_statement(const struct position position, conditional_statements *body)

View File

@ -111,7 +111,8 @@ along with GCC; see the file COPYING3. If not see
%type <elna::boot::return_statement *> return_statement;
%type <elna::boot::statement *> statement;
%type <std::vector<elna::boot::statement *>> statements optional_statements;
%type <elna::boot::procedure_definition *> procedure_definition procedure_heading;
%type <elna::boot::procedure_definition *> procedure_definition;
%type <std::shared_ptr<elna::boot::procedure_type>> procedure_heading;
%type <std::vector<elna::boot::procedure_definition *>> procedure_definitions procedure_part;
%type <elna::boot::type_definition *> type_definition;
%type <std::vector<elna::boot::type_definition *>> type_definitions type_part;
@ -162,27 +163,30 @@ identifier_definitions:
}
| identifier_definition { $$.emplace_back(std::move($1)); }
procedure_heading:
PROCEDURE identifier_definition formal_parameter_list SEMICOLON
formal_parameter_list
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2.first, $2.second);
std::swap($3, $$->parameters);
$$ = std::make_shared<elna::boot::procedure_type>(elna::boot::make_position(@1));
std::swap($1, $$->parameters);
}
| PROCEDURE identifier_definition formal_parameter_list ARROW EXCLAMATION SEMICOLON
| formal_parameter_list ARROW EXCLAMATION
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2.first, $2.second, elna::boot::procedure_definition::no_return_t{});
std::swap($3, $$->parameters);
$$ = std::make_shared<elna::boot::procedure_type>(elna::boot::make_position(@1), elna::boot::no_return);
std::swap($1, $$->parameters);
}
| PROCEDURE identifier_definition formal_parameter_list ARROW type_expression SEMICOLON
| formal_parameter_list ARROW type_expression
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1),
$2.first, $2.second, $5);
std::swap($3, $$->parameters);
$$ = std::make_shared<elna::boot::procedure_type>(elna::boot::make_position(@1), $3);
std::swap($1, $$->parameters);
}
procedure_definition:
procedure_heading block { $$ = $1->add_body($2); }
| procedure_heading EXTERN { $$ = $1; }
PROCEDURE identifier_definition procedure_heading SEMICOLON block
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), $2.first, $2.second, $3, $5);
}
| PROCEDURE identifier_definition procedure_heading SEMICOLON EXTERN
{
$$ = new elna::boot::procedure_definition(elna::boot::make_position(@1), $2.first, $2.second, $3);
}
procedure_definitions:
procedure_definition procedure_definitions
{
@ -467,6 +471,10 @@ type_expression:
{
$$ = std::make_shared<elna::boot::union_type>(elna::boot::make_position(@1), std::move($2));
}
| PROCEDURE procedure_heading
{
$$ = $2;
}
| IDENTIFIER
{
$$ = std::make_shared<elna::boot::basic_type>(elna::boot::make_position(@1), $1);

View File

@ -86,7 +86,7 @@ namespace gcc
{
std::string output = "proc(";
tree parameter_type = TYPE_ARG_TYPES(type);
while (parameter_type != NULL_TREE)
while (TREE_VALUE(parameter_type) != void_type_node)
{
output += print_type(TREE_VALUE(parameter_type));
parameter_type = TREE_CHAIN(parameter_type);

View File

@ -242,27 +242,17 @@ namespace gcc
void generic_visitor::visit(boot::procedure_definition *definition)
{
std::vector<tree> parameter_types(definition->parameters.size());
for (std::size_t i = 0; i < definition->parameters.size(); ++i)
{
parameter_types[i] = build_type(definition->parameters.at(i)->variable_type());
}
tree return_type = definition->return_type() == nullptr
? void_type_node
: build_type(*definition->return_type());
tree declaration_type = build_function_type_array(return_type,
definition->parameters.size(), parameter_types.data());
tree declaration_type = build_type(definition->heading());
tree fndecl = build_fn_decl(definition->identifier.c_str(), declaration_type);
this->symbol_map->enter(definition->identifier, fndecl);
if (definition->no_return)
if (definition->heading().no_return)
{
TREE_THIS_VOLATILE(fndecl) = 1;
}
if (definition->body() != nullptr)
if (definition->body != nullptr)
{
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, return_type);
tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, TREE_TYPE(declaration_type));
DECL_CONTEXT(resdecl) = fndecl;
DECL_RESULT(fndecl) = resdecl;
@ -272,27 +262,29 @@ namespace gcc
enter_scope();
}
tree argument_chain = NULL_TREE;
for (std::size_t i = 0; i < definition->parameters.size(); ++i)
function_args_iterator parameter_type;
function_args_iter_init(&parameter_type, declaration_type);
for (const boot::variable_declaration *parameter : definition->heading().parameters)
{
auto parameter = definition->parameters.at(i);
tree declaration_tree = build_decl(get_location(&parameter->position()), PARM_DECL,
get_identifier(parameter->identifier.c_str()), parameter_types[i]);
get_identifier(parameter->identifier.c_str()), function_args_iter_cond(&parameter_type));
DECL_CONTEXT(declaration_tree) = fndecl;
DECL_ARG_TYPE(declaration_tree) = parameter_types[i];
DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(&parameter_type);
if (definition->body() != nullptr)
if (definition->body != nullptr)
{
this->symbol_map->enter(parameter->identifier, declaration_tree);
}
argument_chain = chainon(argument_chain, declaration_tree);
function_args_iter_next(&parameter_type);
}
DECL_ARGUMENTS(fndecl) = argument_chain;
TREE_PUBLIC(fndecl) = definition->exported;
if (definition->body() != nullptr)
if (definition->body != nullptr)
{
definition->body()->accept(this);
definition->body->accept(this);
tree mapping = leave_scope();
BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
@ -749,7 +741,7 @@ namespace gcc
tree generic_visitor::build_type(boot::top_type& type)
{
if (boot::basic_type *basic_type = type.is_basic())
if (std::shared_ptr<boot::basic_type> basic_type = type.is_basic())
{
tree symbol = this->lookup(basic_type->base_name());
@ -762,7 +754,7 @@ namespace gcc
return error_mark_node;
}
else if (boot::array_type *array_type = type.is_array())
else if (std::shared_ptr<boot::array_type> array_type = type.is_array())
{
tree lower_bound = build_int_cst_type(integer_type_node, 0);
tree upper_bound = build_int_cst_type(integer_type_node, array_type->size);
@ -776,7 +768,7 @@ namespace gcc
return build_array_type(base_type, range_type);
}
else if (boot::pointer_type *pointer_type = type.is_pointer())
else if (std::shared_ptr<boot::pointer_type> pointer_type = type.is_pointer())
{
tree base_type = build_type(pointer_type->base());
@ -786,7 +778,7 @@ namespace gcc
}
return build_pointer_type_for_mode(base_type, VOIDmode, true);
}
else if (boot::record_type *record_type = type.is_record())
else if (std::shared_ptr<boot::record_type> record_type = type.is_record())
{
std::set<std::string> field_names;
tree record_type_node = make_node(RECORD_TYPE);
@ -813,7 +805,7 @@ namespace gcc
return record_type_node;
}
else if (boot::union_type *union_type = type.is_union())
else if (std::shared_ptr<boot::union_type> union_type = type.is_union())
{
std::set<std::string> field_names;
tree union_type_node = make_node(UNION_TYPE);
@ -840,6 +832,21 @@ namespace gcc
return union_type_node;
}
else if (std::shared_ptr<boot::procedure_type> procedure_type = type.is_procedure())
{
std::vector<tree> parameter_types(procedure_type->parameters.size());
for (std::size_t i = 0; i < procedure_type->parameters.size(); ++i)
{
parameter_types[i] = build_type(procedure_type->parameters.at(i)->variable_type());
}
tree return_type = procedure_type->return_type == nullptr
? void_type_node
: build_type(*procedure_type->return_type);
return build_function_type_array(return_type,
procedure_type->parameters.size(), parameter_types.data());
}
return NULL_TREE;
}
@ -889,9 +896,15 @@ namespace gcc
"variable '%s' not declared in the current scope",
expression->name().c_str());
this->current_expression = error_mark_node;
return;
}
this->current_expression = symbol;
else if (TREE_CODE(symbol) == FUNCTION_DECL)
{
this->current_expression = build1(ADDR_EXPR, build_pointer_type(TREE_TYPE(symbol)), symbol);
}
else
{
this->current_expression = symbol;
}
}
void generic_visitor::visit(boot::array_access_expression *expression)

View File

@ -75,6 +75,7 @@ namespace boot
class pointer_type;
class record_type;
class union_type;
class procedure_type;
class variable_expression;
class array_access_expression;
class field_access_expression;
@ -110,6 +111,7 @@ namespace boot
virtual void visit(pointer_type *) = 0;
virtual void visit(record_type *) = 0;
virtual void visit(union_type *) = 0;
virtual void visit(procedure_type *) = 0;
virtual void visit(variable_expression *) = 0;
virtual void visit(array_access_expression *) = 0;
virtual void visit(field_access_expression *is_field_access) = 0;
@ -150,6 +152,7 @@ namespace boot
virtual void visit(pointer_type *) override;
virtual void visit(record_type *expression) override;
virtual void visit(union_type *expression) override;
virtual void visit(procedure_type *expression) override;
virtual void visit(variable_expression *) override;
virtual void visit(array_access_expression *expression) override;
virtual void visit(field_access_expression *expression) override;
@ -220,14 +223,15 @@ namespace boot
/**
* Some type expression.
*/
class top_type : public node
class top_type : public node, public std::enable_shared_from_this<top_type>
{
public:
virtual basic_type *is_basic();
virtual array_type *is_array();
virtual pointer_type *is_pointer();
virtual record_type *is_record();
virtual union_type *is_union();
virtual std::shared_ptr<basic_type> is_basic();
virtual std::shared_ptr<array_type> is_array();
virtual std::shared_ptr<pointer_type> is_pointer();
virtual std::shared_ptr<record_type> is_record();
virtual std::shared_ptr<union_type> is_union();
virtual std::shared_ptr<procedure_type> is_procedure();
protected:
top_type(const struct position position);
@ -250,7 +254,7 @@ namespace boot
const std::string& base_name();
basic_type *is_basic() override;
std::shared_ptr<basic_type> is_basic() override;
};
class array_type : public top_type
@ -265,7 +269,7 @@ namespace boot
top_type& base();
array_type *is_array() override;
std::shared_ptr<array_type> is_array() override;
};
class pointer_type : public top_type
@ -278,37 +282,32 @@ namespace boot
top_type& base();
pointer_type *is_pointer() override;
std::shared_ptr<pointer_type> is_pointer() override;
};
using field_t = std::pair<std::string, std::shared_ptr<top_type>>;
using fields_t = std::vector<field_t>;
class composite_type : public top_type
class record_type : public top_type
{
protected:
composite_type(const struct position position, fields_t&& fields);
public:
fields_t fields;
};
class record_type : public composite_type
{
public:
record_type(const struct position position, fields_t&& fields);
virtual void accept(parser_visitor *visitor) override;
record_type *is_record() override;
std::shared_ptr<record_type> is_record() override;
};
class union_type : public composite_type
class union_type : public top_type
{
public:
fields_t fields;
union_type(const struct position position, fields_t&& fields);
virtual void accept(parser_visitor *visitor) override;
union_type *is_union() override;
std::shared_ptr<union_type> is_union() override;
};
/**
@ -357,31 +356,48 @@ namespace boot
virtual ~constant_definition() override;
};
/**
* Tags a procedure type as never returning.
*/
struct no_return_t
{
};
constexpr no_return_t no_return{};
/**
* Procedure type.
*/
class procedure_type : public top_type
{
public:
const std::shared_ptr<top_type> return_type;
const bool no_return;
std::vector<variable_declaration *> parameters;
procedure_type(const struct position position, std::shared_ptr<top_type> return_type = nullptr);
procedure_type(const struct position position, no_return_t);
virtual void accept(parser_visitor *visitor) override;
std::shared_ptr<procedure_type> is_procedure() override;
virtual ~procedure_type() override;
};
/**
* Procedure definition.
*/
class procedure_definition : public definition
{
std::shared_ptr<top_type> m_return_type{ nullptr };
block *m_body{ nullptr };
std::shared_ptr<procedure_type> m_heading;
public:
struct no_return_t
{
};
const bool no_return{ false };
std::vector<variable_declaration *> parameters;
block *const body;
procedure_definition(const struct position position, const std::string& identifier,
const bool exported, std::shared_ptr<top_type> return_type = nullptr);
procedure_definition(const struct position position, const std::string& identifier,
const bool exported, no_return_t);
const bool exported, std::shared_ptr<procedure_type> heading, block *body = nullptr);
virtual void accept(parser_visitor *visitor) override;
std::shared_ptr<top_type> return_type();
block *body();
procedure_definition *add_body(block *procedure_body);
procedure_type& heading();
virtual ~procedure_definition() override;
};

View File

@ -891,6 +891,19 @@ begin
return 0
end
proc f();
begin
write_s("In f\n")
end
proc g();
var x: ^proc()
begin
x := cast(f: ^proc())
(* x() *)
end
begin
g()
exit(process(cast(count: Int), cast(parameters: ^^Char)))
end.