// Rough interface
// Shadows the stack and holds details like named variables, permissions etc.
// Acts as a reverse single-linked-list, allowing the stack to be traversed
struct InvocationContext;
// Holds type details
struct TypeHandle;
// Allocates objects when supplied a type
struct ObjectAllocator;
// Pairs a pointer with a type
struct ObjectHandle
{
// Untyped pointer to the object
void* handle;
// The type of the object
TypeHandle type;
};
// A simple smart pointer type
struct ReturnHandle
{
// The contained object
ObjectHandle object;
// The allocator it was created from
ObjectAllocator* allocator;
~ReturnHandle();
};
// Represents the details of a function invocation
struct Invocation
{
// The context the invocation takes place in
InvocationContext* context;
// The argument to the function
ObjectHandle argument;
// The result of the function
ReturnHandle result;
};
// A function
struct Function
{
// Actual implementation uses function pointers in place of virtual tables, simplified for brevity
virtual void Invoke(Invocation& invocation)=0;
};
// A basic addition function for integers
struct AddIntsFunction : public Function
{
void Invoke(Invocation& invocation) override final {
// Get the context
InvocationContext& context = *invocation.context;
// Try to treat the argument as a tuple and extra two integers from it
auto&& [argA, argB] = ExpandArgumentTuple<int, int>(context, invocation.argument);
// Do our calculation
int result = argA + argB;
// Get the allocator for locals
auto& allocator = context.getLocalAllocator();
// Create an object handle from a lifted int, with the int type
ObectHandle marshalledResult{allocator.Allocate<int>(result), GetType<int>()};
// Set our invocation result
invocation.result = ReturnHandle{marshalledResult, &allocator};
}
};
// Function can be called from c++ like this;
InvocationContext context{/*Construction details omitted*/};
int a = 3, b = 5;
// Create our tuple
Tuple argTuple{GetObjectHandle(a), GetObjectHandle(b)};
// Specify our invocation
Invocation invocation{&context, GetObjectHandle(argTuple), {}};
AddIntsFunction{}.Invoke(invocation);
// Retrieve the result
int result = GetObject<int>(context, invocation.result.object);
// Notes;
// The aforementioned function only works on ints, so in practice a meta function is used which
// deduces the correct add function by inspecting the operands' types before calling it.
// The C++ api is somewhat cumbersome, but a bytecode IL is already underway.