Skip to content

Commit

Permalink
Enhance constructor and field definitions: add synthetic flag to fiel…
Browse files Browse the repository at this point in the history
…d, update constructor parameters, and improve invocation logic for constructors
  • Loading branch information
riccardodebenedictis committed Dec 28, 2024
1 parent 09ab3e0 commit 9e2fdd8
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 50 deletions.
18 changes: 5 additions & 13 deletions include/constructor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace riddle
class constructor : public scope
{
public:
constructor(scope &scp, std::vector<std::unique_ptr<field>> &&args = {}, const std::vector<std::unique_ptr<statement>> &body = {}) noexcept;
constructor(scope &scp, std::vector<std::unique_ptr<field>> &&args = {}, const std::vector<std::pair<id_token, std::vector<std::unique_ptr<expression>>>> &inits = {}, const std::vector<std::unique_ptr<statement>> &body = {}) noexcept;

/**
* @brief Retrieves the arguments.
Expand All @@ -19,19 +19,11 @@ namespace riddle
*/
[[nodiscard]] const std::vector<std::string> &get_args() const noexcept { return args; }

/**
* @brief Invokes a function with the provided arguments.
*
* This function takes a vector of shared pointers to `item` objects as arguments
* and returns a shared pointer to an `item` object.
*
* @param args A vector of shared pointers to `item` objects, passed as an rvalue reference.
* @return std::shared_ptr<item> A shared pointer to the resulting `item` object.
*/
[[nodiscard]] std::shared_ptr<item> invoke(std::vector<std::shared_ptr<item>> &&args) const;
void invoke(std::shared_ptr<component> self, std::vector<std::shared_ptr<item>> &&args) const;

private:
std::vector<std::string> args; // The names of the arguments.
const std::vector<std::unique_ptr<statement>> &body; // The body of the constructor.
std::vector<std::string> args; // The names of the arguments.
const std::vector<std::pair<id_token, std::vector<std::unique_ptr<expression>>>> &inits; // The initializations.
const std::vector<std::unique_ptr<statement>> &body; // The body of the constructor.
};
} // namespace riddle
12 changes: 11 additions & 1 deletion include/scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace riddle
class field
{
public:
field(type &tp, std::string &&name, const std::unique_ptr<expression> &expr) noexcept;
field(type &tp, std::string &&name, const std::unique_ptr<expression> &expr, bool synthetic = false) noexcept;

/**
* @brief Retrieves the type of the field.
Expand Down Expand Up @@ -48,10 +48,20 @@ namespace riddle
*/
[[nodiscard]] const std::unique_ptr<expression> &get_expression() const noexcept { return expr; }

/**
* @brief Checks if the field is synthetic.
*
* This function returns a boolean value indicating whether the field is synthetic.
*
* @return true if the field is synthetic, false otherwise.
*/
[[nodiscard]] bool is_synthetic() const noexcept { return synthetic; }

private:
type &tp;
std::string name;
const std::unique_ptr<expression> &expr;
bool synthetic;
};

class scope
Expand Down
1 change: 1 addition & 0 deletions include/type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ namespace riddle
friend class predicate_declaration;
friend class constructor_declaration;
friend class constructor;
friend class constructor_expression;

public:
component_type(scope &scp, std::string &&name) noexcept;
Expand Down
94 changes: 84 additions & 10 deletions src/constructor.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#include "constructor.hpp"
#include "type.hpp"
#include "core.hpp"
#include "exceptions.hpp"
#include <algorithm>

namespace riddle
{
constructor::constructor(scope &scp, std::vector<std::unique_ptr<field>> &&args, const std::vector<std::unique_ptr<statement>> &body) noexcept : scope(scp.get_core(), scp), body(body)
constructor::constructor(scope &scp, std::vector<std::unique_ptr<field>> &&args, const std::vector<std::pair<id_token, std::vector<std::unique_ptr<expression>>>> &inits, const std::vector<std::unique_ptr<statement>> &body) noexcept : scope(scp.get_core(), scp), inits(inits), body(body)
{
for (auto &arg : args)
{
Expand All @@ -12,23 +13,96 @@ namespace riddle
}
}

std::shared_ptr<item> constructor::invoke(std::vector<std::shared_ptr<item>> &&args) const
void constructor::invoke(std::shared_ptr<component> self, std::vector<std::shared_ptr<item>> &&args) const
{
if (args.size() != this->args.size())
throw std::invalid_argument("invalid number of arguments");
for (size_t i = 0; i < args.size(); ++i)
if (!args[i]->get_type().is_assignable_from(get_field(this->args[i]).get_type()))
throw std::invalid_argument("invalid argument type");

auto &tp = static_cast<component_type &>(get_parent()); // the type of the component..
auto instance = std::static_pointer_cast<component>(tp.new_instance()); // the new instance of the component..

env ctx(get_core(), *instance); // the context in which the constructor is invoked..
env ctx(get_core(), *self); // the context in which the constructor is invoked..
for (size_t i = 0; i < args.size(); ++i)
ctx.items.emplace(this->args[i], args[i]);

throw std::runtime_error("not implemented");
// we initialize the instance
for (const auto &init : inits)
if (auto f = fields.find(init.first.id); f != fields.end())
{
if (init.second.empty()) // we initialize the field with a new instance
self->items.emplace(f->first, f->second->get_type().new_instance());
else
{
std::vector<std::shared_ptr<item>> init_args;
std::vector<std::reference_wrapper<const type>> argument_types;

for (const auto &arg : init.second)
init_args.emplace_back(arg->evaluate(*this, ctx));
for (const auto &arg : init_args)
argument_types.emplace_back(arg->get_type());

if (init_args.size() == 1 && argument_types[0].get().is_assignable_from(f->second->get_type()))
self->items.emplace(f->first, init_args[0]); // we assign the argument to the field
else
{ // we invoke the constructor of the field
auto &ctp = static_cast<component_type &>(f->second->get_type());
auto instance = std::dynamic_pointer_cast<component>(ctp.new_instance());
ctp.get_constructor(argument_types).invoke(instance, std::move(init_args));
self->items.emplace(f->first, instance);
}
}
}
else
{
auto &tp = static_cast<component_type &>(get_parent());
if (auto st = std::find_if(tp.get_parents().begin(), tp.get_parents().end(), [&init](const auto &parent)
{ return parent.get().get_name() == init.first.id; });
st != tp.get_parents().end())
{ // we invoke a supertype constructor
std::vector<std::shared_ptr<item>> init_args;
std::vector<std::reference_wrapper<const type>> argument_types;

for (const auto &arg : init.second)
init_args.emplace_back(arg->evaluate(*this, ctx));
for (const auto &arg : init_args)
argument_types.emplace_back(arg->get_type());

st->get().get_constructor(argument_types).invoke(self, std::move(init_args));
}
}

return instance; // return the new instance of the component..
// we initialize the uninitialized fields
for (const auto &[name, f] : fields)
if (!f->is_synthetic() && self->items.find(name) == self->items.end()) // the field is not initialized
{
if (f->get_expression())
{ // initialize with an expression
auto val = f->get_expression()->evaluate(*this, ctx);
if (f->get_type().is_assignable_from(val->get_type()))
self->items.emplace(name, val);
else
throw std::runtime_error("Invalid assignment");
}
else if (f->get_type().is_primitive()) // initialize with a default value
self->items.emplace(name, f->get_type().new_instance());
else if (auto ct = dynamic_cast<component_type *>(&f->get_type()))
switch (ct->get_instances().size())
{
case 0: // no instances
throw inconsistency_exception();
case 1: // only one instance
self->items.emplace(name, *ct->get_instances().begin());
break;
default:
{ // multiple instances
std::vector<std::reference_wrapper<utils::enum_val>> values;
for (auto &inst : ct->get_instances())
values.emplace_back(*inst);
self->items.emplace(name, get_core().new_enum(*ct, std::move(values)));
}
}
else
throw std::runtime_error("Invalid type reference");
}
}
} // namespace riddle
6 changes: 3 additions & 3 deletions src/declaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ namespace riddle
}

auto tp = dynamic_cast<component_type *>(&scp);
tp->add_constructor(std::make_unique<constructor>(*tp, std::move(args), stmts));
tp->add_constructor(std::make_unique<constructor>(*tp, std::move(args), inits, stmts));
}

void method_declaration::refine(scope &scp) const
Expand Down Expand Up @@ -181,9 +181,9 @@ namespace riddle
for (const auto &tp : types)
tp->refine(ct);

// we refine the predicates..
// we declare the predicates..
for (const auto &predicate : predicates)
predicate->refine(ct);
predicate->declare(ct);
}
void class_declaration::refine_predicates(scope &scp) const
{
Expand Down
6 changes: 5 additions & 1 deletion src/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ namespace riddle
argument_types.emplace_back(arg->get_type());

if (auto ct = dynamic_cast<component_type *>(tp))
return ct->get_constructor(argument_types).invoke(std::move(args));
{
auto instance = ct->new_instance();
ct->get_constructor(argument_types).invoke(std::dynamic_pointer_cast<component>(instance), std::move(args));
return instance;
}
else
throw std::runtime_error("Invalid type reference");
}
Expand Down
9 changes: 0 additions & 9 deletions src/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,7 @@ namespace riddle
tokens.push_back(finish_token());
}
else
{
current_state = ID;
text.push_back(c);
}
}
else
text.push_back(c);
Expand Down Expand Up @@ -403,10 +400,7 @@ namespace riddle
tokens.push_back(finish_token());
}
else
{
current_state = ID;
text.push_back(c);
}
}
else
text.push_back(c);
Expand Down Expand Up @@ -503,10 +497,7 @@ namespace riddle
tokens.push_back(finish_token());
}
else
{
current_state = ID;
text.push_back(c);
}
}
else
text.push_back(c);
Expand Down
35 changes: 24 additions & 11 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace riddle
case TIME:
case STRING:
{
pos++;
if (!match(ID))
error("Expected identifier");

Expand All @@ -58,12 +59,12 @@ namespace riddle
error("Expected identifier after `.`");
if (match(LPAREN))
{ // method declaration..
pos = c_pos - 1;
pos = c_pos;
methods.emplace_back(parse_method_declaration());
}
else
{ // statement..
pos = c_pos - 1;
pos = c_pos;
statements.emplace_back(parse_statement());
}
break;
Expand Down Expand Up @@ -224,15 +225,19 @@ namespace riddle
break;
}
case ENUM:
pos--;
types.emplace_back(parse_enum_declaration());
break;
case CLASS:
pos--;
types.emplace_back(parse_class_declaration());
break;
case PREDICATE:
pos--;
predicates.emplace_back(parse_predicate_declaration());
break;
case VOID:
pos--;
methods.emplace_back(parse_method_declaration());
break;
default:
Expand All @@ -242,13 +247,8 @@ namespace riddle
if (!match(SEMICOLON))
error("Expected `;` after class declaration");

if (constructors.empty())
{ // default constructor..
std::vector<std::pair<std::vector<id_token>, id_token>> params;
std::vector<std::pair<id_token, std::vector<std::unique_ptr<expression>>>> inits;
std::vector<std::unique_ptr<statement>> stmts;
constructors.emplace_back(std::make_unique<constructor_declaration>(std::move(params), std::move(inits), std::move(stmts)));
}
if (constructors.empty()) // default constructor..
constructors.emplace_back(std::make_unique<constructor_declaration>(std::vector<std::pair<std::vector<id_token>, id_token>>(), std::vector<std::pair<id_token, std::vector<std::unique_ptr<expression>>>>(), std::vector<std::unique_ptr<statement>>()));

return std::make_unique<class_declaration>(std::move(id), std::move(base_classes), std::move(fields), std::move(constructors), std::move(methods), std::move(predicates), std::move(types));
}
Expand Down Expand Up @@ -928,7 +928,12 @@ namespace riddle
}
default:
pos--;
return std::make_unique<expression_statement>(parse_expression());
auto xpr = parse_expression();

if (!match(SEMICOLON))
error("Expected `;` after expression");

return std::make_unique<expression_statement>(std::move(xpr));
}
}

Expand Down Expand Up @@ -1077,21 +1082,24 @@ namespace riddle
((tokens.at(pos)->sym == LT || tokens.at(pos)->sym == LTEQ || tokens.at(pos)->sym == GTEQ || tokens.at(pos)->sym == GT) && 2 >= precedence) ||
((tokens.at(pos)->sym == PLUS || tokens.at(pos)->sym == MINUS) && 3 >= precedence) ||
((tokens.at(pos)->sym == STAR || tokens.at(pos)->sym == SLASH) && 4 >= precedence))
switch (tokens.at(pos++)->sym)
switch (tokens.at(pos)->sym)
{
case EQEQ:
assert(0 >= precedence);
pos++; // we parse the `==` operator..
expr = std::make_unique<eq_expression>(std::move(expr), parse_expression(1));
break;
case BANGEQ:
assert(0 >= precedence);
pos++; // we parse the `!=` operator..
expr = std::make_unique<not_expression>(std::make_unique<eq_expression>(std::move(expr), parse_expression(1)));
break;
case IMPLICATION:
{
assert(1 >= precedence);
std::vector<std::unique_ptr<expression>> xprs;
xprs.emplace_back(std::make_unique<not_expression>(std::move(expr)));
pos++; // we parse the `=>` operator..
xprs.emplace_back(parse_expression(2));
expr = std::make_unique<or_expression>(std::move(xprs));
break;
Expand Down Expand Up @@ -1128,18 +1136,22 @@ namespace riddle
}
case LT:
assert(2 >= precedence);
pos++; // we parse the `<` operator..
expr = std::make_unique<lt_expression>(std::move(expr), parse_expression(3));
break;
case LTEQ:
assert(2 >= precedence);
pos++; // we parse the `<=` operator..
expr = std::make_unique<le_expression>(std::move(expr), parse_expression(3));
break;
case GTEQ:
assert(2 >= precedence);
pos++; // we parse the `>=` operator..
expr = std::make_unique<ge_expression>(std::move(expr), parse_expression(3));
break;
case GT:
assert(2 >= precedence);
pos++; // we parse the `>` operator..
expr = std::make_unique<gt_expression>(std::move(expr), parse_expression(3));
break;
case PLUS:
Expand All @@ -1164,6 +1176,7 @@ namespace riddle
}
case SLASH:
assert(4 >= precedence);
pos++; // we parse the `/` operator..
expr = std::make_unique<divide_expression>(std::move(expr), parse_expression(5));
break;
default:
Expand Down
2 changes: 1 addition & 1 deletion src/scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace riddle
{
field::field(type &tp, std::string &&name, const std::unique_ptr<expression> &expr) noexcept : tp(tp), name(std::move(name)), expr(expr) {}
field::field(type &tp, std::string &&name, const std::unique_ptr<expression> &expr, bool synthetic) noexcept : tp(tp), name(std::move(name)), expr(expr), synthetic(synthetic) {}

scope::scope(core &c, scope &parent, std::vector<std::unique_ptr<field>> &&args) : cr(c), parent(parent)
{
Expand Down
Loading

0 comments on commit 9e2fdd8

Please sign in to comment.