diff --git a/Rakefile b/Rakefile index d9f08a9..aae04fe 100644 --- a/Rakefile +++ b/Rakefile @@ -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, diff --git a/boot/ast.cc b/boot/ast.cc index 7755998..043de55 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -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 top_type::is_basic() { return nullptr; } - array_type *top_type::is_array() + std::shared_ptr top_type::is_array() { return nullptr; } - record_type *top_type::is_record() + std::shared_ptr top_type::is_record() { return nullptr; } - union_type *top_type::is_union() + std::shared_ptr top_type::is_union() { return nullptr; } - pointer_type *top_type::is_pointer() + std::shared_ptr top_type::is_pointer() + { + return nullptr; + } + + std::shared_ptr 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::is_basic() { - return this; + return std::static_pointer_cast(shared_from_this()); } array_type::array_type(const struct position position, std::shared_ptr 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::is_array() { - return this; + return std::static_pointer_cast(shared_from_this()); } pointer_type::pointer_type(const struct position position, std::shared_ptr 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::is_pointer() { + return std::static_pointer_cast(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::is_record() { - return this; + return std::static_pointer_cast(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::is_union() { - return this; + return std::static_pointer_cast(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 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 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::is_procedure() + { + return std::static_pointer_cast(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 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 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) diff --git a/boot/parser.yy b/boot/parser.yy index f5362e0..3a55b97 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -111,7 +111,8 @@ along with GCC; see the file COPYING3. If not see %type return_statement; %type statement; %type > statements optional_statements; -%type procedure_definition procedure_heading; +%type procedure_definition; +%type > procedure_heading; %type > procedure_definitions procedure_part; %type type_definition; %type > 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::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::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::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::make_position(@1), std::move($2)); } + | PROCEDURE procedure_heading + { + $$ = $2; + } | IDENTIFIER { $$ = std::make_shared(elna::boot::make_position(@1), $1); diff --git a/gcc/elna-diagnostic.cc b/gcc/elna-diagnostic.cc index 7c72832..61cb0ff 100644 --- a/gcc/elna-diagnostic.cc +++ b/gcc/elna-diagnostic.cc @@ -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); diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 092d226..878dafd 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -242,27 +242,17 @@ namespace gcc void generic_visitor::visit(boot::procedure_definition *definition) { - std::vector 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(¶meter_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(¶meter->position()), PARM_DECL, - get_identifier(parameter->identifier.c_str()), parameter_types[i]); + get_identifier(parameter->identifier.c_str()), function_args_iter_cond(¶meter_type)); DECL_CONTEXT(declaration_tree) = fndecl; - DECL_ARG_TYPE(declaration_tree) = parameter_types[i]; + DECL_ARG_TYPE(declaration_tree) = function_args_iter_cond(¶meter_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(¶meter_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 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 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 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 record_type = type.is_record()) { std::set 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 union_type = type.is_union()) { std::set 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 procedure_type = type.is_procedure()) + { + std::vector 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) diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index e569503..6eed4ab 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -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 { 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 is_basic(); + virtual std::shared_ptr is_array(); + virtual std::shared_ptr is_pointer(); + virtual std::shared_ptr is_record(); + virtual std::shared_ptr is_union(); + virtual std::shared_ptr 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 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 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 is_pointer() override; }; using field_t = std::pair>; using fields_t = std::vector; - 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 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 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 return_type; + const bool no_return; + std::vector parameters; + + procedure_type(const struct position position, std::shared_ptr return_type = nullptr); + procedure_type(const struct position position, no_return_t); + + virtual void accept(parser_visitor *visitor) override; + std::shared_ptr is_procedure() override; + + virtual ~procedure_type() override; + }; + /** * Procedure definition. */ class procedure_definition : public definition { - std::shared_ptr m_return_type{ nullptr }; - block *m_body{ nullptr }; + std::shared_ptr m_heading; public: - struct no_return_t - { - }; - const bool no_return{ false }; - std::vector parameters; + block *const body; procedure_definition(const struct position position, const std::string& identifier, - const bool exported, std::shared_ptr 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 heading, block *body = nullptr); virtual void accept(parser_visitor *visitor) override; - std::shared_ptr return_type(); - - block *body(); - procedure_definition *add_body(block *procedure_body); + procedure_type& heading(); virtual ~procedure_definition() override; }; diff --git a/source.elna b/source.elna index 9225a26..ed0b1b2 100644 --- a/source.elna +++ b/source.elna @@ -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.