Skip to content

Commit

Permalink
instantiated_function: Remove zero-ary variadic arguers
Browse files Browse the repository at this point in the history
  • Loading branch information
lhmouse committed Dec 4, 2023
1 parent fd62229 commit 50b5636
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 76 deletions.
4 changes: 1 addition & 3 deletions asteria/runtime/air_optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ create_function(const Source_Location& sloc, stringR name)
}

// Instantiate the function object now.
return ::rocket::make_refcnt<Instantiated_Function>(this->m_params,
::rocket::make_refcnt<Variadic_Arguer>(sloc, ::std::move(func)),
this->m_code);
return ::rocket::make_refcnt<Instantiated_Function>(sloc, func, this->m_params, this->m_code);
}

} // namespace asteria
39 changes: 14 additions & 25 deletions asteria/runtime/executive_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,52 @@
#include "../precompiled.ipp"
#include "executive_context.hpp"
#include "runtime_error.hpp"
#include "../runtime/runtime_error.hpp"
#include "ptc_arguments.hpp"
#include "enums.hpp"
#include "variable.hpp"
#include "instantiated_function.hpp"
#include "../llds/avm_rod.hpp"
#include "../llds/reference_stack.hpp"
#include "../utils.hpp"
namespace asteria {

Executive_Context::
Executive_Context(M_function, Global_Context& global, Reference_Stack& stack,
Reference_Stack& alt_stack, const refcnt_ptr<Variadic_Arguer>& zvarg,
const cow_vector<phsh_string>& params, Reference&& self)
Executive_Context(M_function, Global_Context& xglobal, Reference_Stack& xstack,
Reference_Stack& ystack, const Instantiated_Function& xfunc,
Reference&& xself)
:
m_parent_opt(nullptr), m_global(&global), m_stack(&stack),
m_alt_stack(&alt_stack), m_zvarg(zvarg)
m_parent_opt(nullptr), m_global(&xglobal), m_stack(&xstack), m_alt_stack(&ystack), m_func(&xfunc)
{
// Set the `this` reference, but only if it is a variable or non-null. When
// `this` is null, it is likely that it is never referenced in the function,
// so lazy initialization is performed to avoid the overhead here.
if(!self.is_invalid())
this->do_mut_named_reference(nullptr, sref("__this")) = ::std::move(self);
if(!xself.is_invalid())
this->do_mut_named_reference(nullptr, sref("__this")) = ::std::move(xself);

// Set arguments. Because arguments are evaluated from left to right, the
// reference at the top is the last argument.
uint32_t nargs = stack.size();
uint32_t nargs = this->m_stack->size();
bool has_ellipsis = false;

for(const auto& name : params)
for(const auto& name : this->m_func->params())
if(name != sref("...")) {
// Try popping an argument and assign it.
auto& param = this->do_mut_named_reference(nullptr, name);
if(nargs == 0)
param.set_temporary(nullopt);
else
param = ::std::move(stack.mut_top(--nargs));
param = ::std::move(this->m_stack->mut_top(--nargs));
}
else
has_ellipsis = true;

if(!has_ellipsis && (nargs != 0))
throw Runtime_Error(Runtime_Error::M_format(),
"Too many arguments passed to `$1`", zvarg->func());
"Too many arguments passed to `$1`", this->m_func->func());

// Move all arguments into the variadic argument getter.
while(nargs != 0)
this->m_lazy_args.emplace_back(::std::move(stack.mut_top(--nargs)));
this->m_lazy_args.emplace_back(::std::move(this->m_stack->mut_top(--nargs)));
}

Executive_Context::
Expand All @@ -70,23 +69,13 @@ do_create_lazy_reference_opt(Reference* hint_opt, phsh_stringR name) const

if(name == sref("__func")) {
auto& ref = this->do_mut_named_reference(hint_opt, name);

// Note: This can only happen inside a function context.
ref.set_temporary(this->m_zvarg->func());
ref.set_temporary(this->m_func->func());
return &ref;
}

if(name == sref("__varg")) {
auto& ref = this->do_mut_named_reference(hint_opt, name);

// Use the zero-ary argument getter if there is variadic argument.
// Create a new one otherwise.
auto varg = this->m_zvarg;
if(!this->m_lazy_args.empty())
varg = ::rocket::make_refcnt<Variadic_Arguer>(*varg, this->m_lazy_args);

// Note: This can only happen inside a function context.
ref.set_temporary(::std::move(varg));
ref.set_temporary(::rocket::make_refcnt<Variadic_Arguer>(*(this->m_func), this->m_lazy_args));
return &ref;
}

Expand Down
14 changes: 7 additions & 7 deletions asteria/runtime/executive_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Executive_Context
Reference_Stack* m_alt_stack; // for nested calls

cow_bivector<Source_Location, AVM_Rod> m_defer;
refcnt_ptr<Variadic_Arguer> m_zvarg;
const Instantiated_Function* m_func = nullptr;
cow_vector<Reference> m_lazy_args;

public:
Expand All @@ -41,19 +41,19 @@ class Executive_Context
// contexts of enclosing function will have been destroyed.
ASTERIA_INCOMPLET(AVM_Rod)
explicit
Executive_Context(M_defer, Global_Context& global, Reference_Stack& stack,
Reference_Stack& alt_stack)
Executive_Context(M_defer, Global_Context& xglobal, Reference_Stack& xstack,
Reference_Stack& ystack)
:
m_parent_opt(nullptr), m_global(&global), m_stack(&stack), m_alt_stack(&alt_stack)
m_parent_opt(nullptr), m_global(&xglobal), m_stack(&xstack), m_alt_stack(&ystack)
{ }

// A function context has no parent.
// The caller shall define a global context and evaluation stack, both of which
// shall outlast this context.
explicit
Executive_Context(M_function, Global_Context& global, Reference_Stack& stack,
Reference_Stack& alt_stack, const refcnt_ptr<Variadic_Arguer>& zvarg,
const cow_vector<phsh_string>& params, Reference&& self);
Executive_Context(M_function, Global_Context& xglobal, Reference_Stack& xstack,
Reference_Stack& ystack, const Instantiated_Function& xfunc,
Reference&& xself);

private:
bool
Expand Down
20 changes: 9 additions & 11 deletions asteria/runtime/instantiated_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
namespace asteria {

Instantiated_Function::
Instantiated_Function(const cow_vector<phsh_string>& params, refcnt_ptr<Variadic_Arguer>&& zvarg,
const cow_vector<AIR_Node>& code)
Instantiated_Function(const Source_Location& xsloc, const cow_string& xfunc,
const cow_vector<phsh_string>& xparams, const cow_vector<AIR_Node>& code)
:
m_params(params), m_zvarg(::std::move(zvarg))
m_sloc(xsloc), m_func(xfunc), m_params(xparams)
{
::rocket::for_each(code, [&](const AIR_Node& node) { node.solidify(this->m_rod); });
this->m_rod.finalize();
Expand All @@ -33,7 +33,7 @@ tinyfmt&
Instantiated_Function::
describe(tinyfmt& fmt) const
{
return fmt << "`" << this->m_zvarg->func() << "` at '" << this->m_zvarg->sloc() << "'";
return format(fmt, "`$1` at '$2'", this->m_func, this->m_sloc);
}

void
Expand All @@ -49,10 +49,8 @@ invoke_ptc_aware(Reference& self, Global_Context& global, Reference_Stack&& stac
{
// Create the stack and context for this function.
Reference_Stack alt_stack;
Executive_Context ctx_func(Executive_Context::M_function(), global, stack, alt_stack,
this->m_zvarg, this->m_params, ::std::move(self));

ASTERIA_CALL_GLOBAL_HOOK(global, on_function_enter, ctx_func, *this, this->m_zvarg->sloc());
Executive_Context ctx_func(Executive_Context::M_function(), global, stack, alt_stack, *this, ::std::move(self));
ASTERIA_CALL_GLOBAL_HOOK(global, on_function_enter, ctx_func, *this, this->m_sloc);

// Execute the function body, using `stack` for evaluation.
AIR_Status status;
Expand All @@ -61,8 +59,8 @@ invoke_ptc_aware(Reference& self, Global_Context& global, Reference_Stack&& stac
}
catch(Runtime_Error& except) {
ctx_func.on_scope_exit_exceptional(except);
except.push_frame_function(this->m_zvarg->sloc(), this->m_zvarg->func());
ASTERIA_CALL_GLOBAL_HOOK(global, on_function_except, ctx_func, *this, this->m_zvarg->sloc(), except);
except.push_frame_function(this->m_sloc, this->m_func);
ASTERIA_CALL_GLOBAL_HOOK(global, on_function_except, ctx_func, *this, this->m_sloc, except);
throw;
}
ctx_func.on_scope_exit_normal(status);
Expand Down Expand Up @@ -99,7 +97,7 @@ invoke_ptc_aware(Reference& self, Global_Context& global, Reference_Stack&& stac
ASTERIA_TERMINATE(("Corrupted enumeration `$1`"), status);
}

ASTERIA_CALL_GLOBAL_HOOK(global, on_function_return, ctx_func, *this, this->m_zvarg->sloc(), self);
ASTERIA_CALL_GLOBAL_HOOK(global, on_function_return, ctx_func, *this, this->m_sloc, self);
return self;
}

Expand Down
22 changes: 15 additions & 7 deletions asteria/runtime/instantiated_function.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#define ASTERIA_RUNTIME_INSTANTIATED_FUNCTION_

#include "../fwd.hpp"
#include "variadic_arguer.hpp"
#include "../llds/avm_rod.hpp"
namespace asteria {

Expand All @@ -14,21 +13,30 @@ class Instantiated_Function final
public Abstract_Function
{
private:
Source_Location m_sloc;
cow_string m_func;
cow_vector<phsh_string> m_params;
refcnt_ptr<Variadic_Arguer> m_zvarg;
AVM_Rod m_rod;

public:
explicit
Instantiated_Function(const cow_vector<phsh_string>& params, refcnt_ptr<Variadic_Arguer>&& zvarg,
const cow_vector<AIR_Node>& code);
Instantiated_Function(const Source_Location& xsloc, const cow_string& xfunc,
const cow_vector<phsh_string>& xparams, const cow_vector<AIR_Node>& code);

public:
ASTERIA_NONCOPYABLE_DESTRUCTOR(Instantiated_Function);

const refcnt_ptr<Variadic_Arguer>&
zvarg() const noexcept
{ return this->m_zvarg; }
const Source_Location&
sloc() const noexcept
{ return this->m_sloc; }

const cow_string&
func() const noexcept
{ return this->m_func; }

const cow_vector<phsh_string>&
params() const noexcept
{ return this->m_params; }

tinyfmt&
describe(tinyfmt& fmt) const override;
Expand Down
6 changes: 3 additions & 3 deletions asteria/runtime/reference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ do_use_function_result_slow(Global_Context& global)
// Leave this frame.
if(caller)
ASTERIA_CALL_GLOBAL_HOOK(global, on_function_return, defer_ctx, *caller,
caller->zvarg()->sloc(), *this);
caller->sloc(), *this);
}
}
catch(Runtime_Error& except) {
Expand All @@ -259,7 +259,7 @@ do_use_function_result_slow(Global_Context& global)
except.push_frame_plain(ptcg->sloc(), sref("[proper tail call]"));

if(caller)
except.push_frame_function(caller->zvarg()->sloc(), caller->zvarg()->func());
except.push_frame_function(caller->sloc(), caller->func());

// Evaluate deferred expressions.
defer_ctx.stack() = ::std::move(ptcg->mut_stack());
Expand All @@ -269,7 +269,7 @@ do_use_function_result_slow(Global_Context& global)
// Leave this frame.
if(caller)
ASTERIA_CALL_GLOBAL_HOOK(global, on_function_except, defer_ctx, *caller,
caller->zvarg()->sloc(), except);
caller->sloc(), except);
}

// The exception object has been updated, so rethrow it.
Expand Down
23 changes: 3 additions & 20 deletions asteria/runtime/variadic_arguer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "../fwd.hpp"
#include "reference.hpp"
#include "instantiated_function.hpp"
#include "../source_location.hpp"
namespace asteria {

Expand All @@ -21,34 +22,16 @@ class Variadic_Arguer final

public:
explicit
Variadic_Arguer(const Source_Location& xsloc, stringR xfunc)
Variadic_Arguer(const Instantiated_Function& xfunc, const cow_vector<Reference>& xvargs)
:
m_sloc(xsloc), m_func(xfunc)
{ }

explicit
Variadic_Arguer(const Variadic_Arguer& other, const cow_vector<Reference>& xvargs)
:
m_sloc(other.m_sloc), m_func(other.m_func), m_vargs(xvargs)
m_sloc(xfunc.sloc()), m_func(xfunc.func()), m_vargs(xvargs)
{ }

public:
const Source_Location&
sloc() const noexcept
{ return this->m_sloc; }

const cow_string&
file() const noexcept
{ return this->m_sloc.file(); }

int
line() const noexcept
{ return this->m_sloc.line(); }

int
column() const noexcept
{ return this->m_sloc.column(); }

const cow_string&
func() const noexcept
{ return this->m_func; }
Expand Down

0 comments on commit 50b5636

Please sign in to comment.