Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for constructors and destructors #412

Merged
merged 20 commits into from
Nov 16, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
partial groundwork for language destructors
gewang committed Nov 14, 2023

Verified

This commit was signed with the committer’s verified signature.
Heptazhou Heptazhou
commit 5379ff31fca61b1daea101f1c89fc4f29970f99b
2 changes: 2 additions & 0 deletions src/core/chuck.lex
Original file line number Diff line number Diff line change
@@ -368,6 +368,8 @@ global { adjust(); return GLOBAL; }
"@" { adjust(); return AT_SYM; }
"@@" { adjust(); return ATAT_SYM; }
"@operator" { adjust(); return AT_OP; }
"@construct" { adjust(); return AT_CTOR; }
"@destruct" { adjust(); return AT_DTOR; }
"->" { adjust(); return ARROW_RIGHT; }
"<-" { adjust(); return ARROW_LEFT; }
"-->" { adjust(); return GRUCK_RIGHT; }
9 changes: 8 additions & 1 deletion src/core/chuck.y
Original file line number Diff line number Diff line change
@@ -134,7 +134,8 @@ a_Program g_program = NULL;
UNCHUCK UPCHUCK CLASS INTERFACE EXTENDS IMPLEMENTS
PUBLIC PROTECTED PRIVATE STATIC ABSTRACT CONST
SPORK ARROW_RIGHT ARROW_LEFT L_HACK R_HACK
GRUCK_RIGHT GRUCK_LEFT UNGRUCK_RIGHT UNGRUCK_LEFT AT_OP
GRUCK_RIGHT GRUCK_LEFT UNGRUCK_RIGHT UNGRUCK_LEFT
AT_OP AT_CTOR AT_DTOR


%type <program> program
@@ -266,6 +267,12 @@ function_definition
{ $$ = new_func_def( $1, $2, $3, $4, $6, $8, TRUE, @1.first_line, @1.first_column ); }
| function_decl static_decl type_decl2 ID LPAREN RPAREN code_segment
{ $$ = new_func_def( $1, $2, $3, $4, NULL, $7, TRUE, @1.first_line, @1.first_column ); }
// | function_decl AT_CTOR LPAREN arg_list RPAREN code_segment // 1.5.1.9 (ge) added for constructors
// { $$ = new_func_def( $1, ae_key_instance, NULL, "@construct", $4, $6, TRUE, @1.first_line, @1.first_column ); }
// | function_decl AT_CTOR LPAREN RPAREN code_segment // 1.5.1.9 (ge) added for constructors
// { $$ = new_func_def( $1, ae_key_instance, NULL, "@construct", NULL, $5, TRUE, @1.first_line, @1.first_column ); }
// | function_decl AT_DTOR LPAREN RPAREN code_segment // 1.5.1.9 (ge) added for destructor
// { $$ = new_func_def( $1, ae_key_instance, NULL, "@destruct", NULL, $5, TRUE, @1.first_line, @1.first_column ); }
| function_decl static_decl type_decl2 ID LPAREN arg_list RPAREN SEMICOLON
{ $$ = new_func_def( $1, $2, $3, $4, $6, NULL, TRUE, @1.first_line, @1.first_column ); }
| function_decl static_decl type_decl2 ID LPAREN RPAREN SEMICOLON
1 change: 1 addition & 0 deletions src/core/chuck_absyn.h
Original file line number Diff line number Diff line change
@@ -81,6 +81,7 @@ typedef enum {
ae_key_private, ae_key_static, ae_key_instance, ae_key_abstract
} ae_Keyword;

// key



22 changes: 17 additions & 5 deletions src/core/chuck_oo.cpp
Original file line number Diff line number Diff line change
@@ -290,11 +290,23 @@ Chuck_Object::~Chuck_Object()
// SPENCER TODO: HACK! is there a better way to call the dtor?
if( type->info && type->has_destructor ) // 1.5.0.0 (ge) added type->info check
{
// verify: for now, can only be native func
assert( type->info->dtor && type->info->dtor->native_func );
// REFACTOR-2017: do we know which VM to pass in? (diff main/sub instance?)
// pass in type-associated vm and current shred | 1.5.1.8
((f_dtor)(type->info->dtor->native_func))( this, vm, shred, Chuck_DL_Api::instance() );
// verify
assert( type->info->dtor );
// check origin of dtor
if( type->info->dtor->native_func ) // defined in c++
{
// REFACTOR-2017: do we know which VM to pass in? (diff main/sub instance?)
// pass in type-associated vm and current shred | 1.5.1.8
((f_dtor)(type->info->dtor->native_func))( this, vm, shred, Chuck_DL_Api::instance() );
}
else // defined in chuck
{
// TODO: invoke dtor, if there is one
// should type already have dtorinvoker setup?
// pass in owner shred to invoke()? what about refs?
// what about UGen and GGen that shreds keep track of (and have refs to)?
// or should @destruct disallow accessing context-global variables?
}
}
// go up the inheritance
type = type->parent;
32 changes: 32 additions & 0 deletions src/core/chuck_scan.cpp
Original file line number Diff line number Diff line change
@@ -1407,6 +1407,38 @@ t_CKBOOL type_engine_scan1_func_def( Chuck_Env * env, a_Func_Def f )
{
a_Arg_List arg_list = NULL;
t_CKUINT count = 0;
// substitute for @construct
if( S_name(f->name) == string("@construct") )
{
// make sure we are in a class
if( !env->class_def )
{
EM_error2( f->where, "@construct() can only be used within class definitions..." );
return FALSE;
}

// substitute class name
f->name = insert_symbol( env->class_def->base_name.c_str() );
}
// verify @destruct
if( S_name(f->name) == string("@destruct") )
{
// make sure we are in a class
if( !env->class_def )
{
EM_error2( f->where, "@destruct() can only be used within class definitions..." );
return FALSE;
}
// make sure there are no arguments
if( f->arg_list != NULL )
{
EM_error2( f->where, "@destruct() does not accept arguments..." );
return FALSE;
}
// substitute ~[class name]
f->name = insert_symbol( string("~"+env->class_def->base_name).c_str() );
}
// check if constructor
t_CKBOOL isInCtor = isctor(env,f);

// check if reserved
152 changes: 150 additions & 2 deletions src/core/chuck_vm.cpp
Original file line number Diff line number Diff line change
@@ -3307,8 +3307,10 @@ t_CKBOOL Chuck_VM_MFunInvoker::setup( Chuck_Func * func, t_CKUINT func_vt_offset
instructions.push_back( new Chuck_Instr_Dot_Member_Func(func_vt_offset) );
// func to code
instructions.push_back( new Chuck_Instr_Func_To_Code );
// push stack depth (in bytes)
instructions.push_back( new Chuck_Instr_Reg_Push_Imm(args_size_bytes) );
// frame offset; use 0 since we have no local variables
// was: push stack depth (in bytes)
// was: instructions.push_back( new Chuck_Instr_Reg_Push_Imm(args_size_bytes) );
instructions.push_back( new Chuck_Instr_Reg_Push_Imm(0) );
// func call
instructions.push_back( new Chuck_Instr_Func_Call());

@@ -3581,6 +3583,152 @@ void Chuck_VM_MFunInvoker::cleanup()



//-----------------------------------------------------------------------------
// name: Chuck_VM_DtorInvoker()
// desc: constructor
//-----------------------------------------------------------------------------
Chuck_VM_DtorInvoker::Chuck_VM_DtorInvoker()
{
// zero
invoker_shred = NULL;
instr_pushThis = NULL;
}




//-----------------------------------------------------------------------------
// name: ~Chuck_VM_DtorInvoker()
// desc: destructor
//-----------------------------------------------------------------------------
Chuck_VM_DtorInvoker::~Chuck_VM_DtorInvoker()
{
cleanup();
}




//-----------------------------------------------------------------------------
// name: setup()
// desc: setup the invoker for use
//-----------------------------------------------------------------------------
t_CKBOOL Chuck_VM_DtorInvoker::setup( Chuck_Func * dtor, Chuck_VM * vm, Chuck_VM_Shred * caller )
{
// clean up first
if( invoker_shred ) cleanup();

// a vector of VM instructions
vector<Chuck_Instr *> instructions;

// push this (as func arg) -- will set later
instr_pushThis = new Chuck_Instr_Reg_Push_Imm( 0 );
instructions.push_back( instr_pushThis );
// push destructor VM code
instructions.push_back( new Chuck_Instr_Reg_Push_Code(dtor->code) );
// push stack offset; 0 since this is a dedicated shred for invoking
instructions.push_back( new Chuck_Instr_Reg_Push_Imm(0) );
// func call
instructions.push_back( new Chuck_Instr_Func_Call());
// end of code
instructions.push_back( new Chuck_Instr_EOC);

// create VM code
Chuck_VM_Code * code = new Chuck_VM_Code;
// allocate instruction array
code->instr = new Chuck_Instr*[instructions.size()];
// number of instructions
code->num_instr = instructions.size();
// copy instructions
for( t_CKUINT i = 0; i < instructions.size(); i++ ) code->instr[i] = instructions[i];
// TODO: should this be > 0
code->stack_depth = 0;
// TODO: should this be this true?
code->need_this = FALSE;

// create dedicated shred
invoker_shred = new Chuck_VM_Shred;
// set the VM ref (needed by initialize)
invoker_shred->vm_ref = vm;
// initialize with code + allocate stacks
invoker_shred->initialize( code );
// set name
invoker_shred->name = dtor->signature(FALSE,TRUE);
// enter immediate mode (will throw runtime exception on any time/event ops)
invoker_shred->setImmediateMode( TRUE );

// done
return TRUE;
}




//-----------------------------------------------------------------------------
// name: invoke()
// desc: invoke the dtor
//-----------------------------------------------------------------------------
void Chuck_VM_DtorInvoker::invoke( Chuck_Object * obj, Chuck_VM_Shred * parent_shred )
{
// no shred?
if( !invoker_shred ) return;
// verify
assert( instr_pushThis != NULL );

// set this pointer
instr_pushThis->set( (t_CKUINT)obj );
// reset shred: program counter
invoker_shred->pc = 0;
// next pc
invoker_shred->next_pc = 1;
// set parent
invoker_shred->parent = parent_shred;
// commented out: parent if any should have been set in setup()
// invoker_shred->parent = obj->originShred();

// set parent base_ref; in case mfun is part of a non-public class
// that can access file-global variables outside the class definition
if( invoker_shred->parent ) invoker_shred->base_ref = invoker_shred->parent->base_ref;
else invoker_shred->base_ref = invoker_shred->mem;

// shred in dump (all done)
invoker_shred->is_dumped = FALSE;
// shred done
invoker_shred->is_done = FALSE;
// shred running
invoker_shred->is_running = FALSE;
// shred abort
invoker_shred->is_abort = FALSE;
// set the instr
invoker_shred->instr = invoker_shred->code->instr;
// zero out the id (shred is in immediate mode and cannot be shreduled)
invoker_shred->xid = 0;
// inherit now from vm
invoker_shred->now = invoker_shred->vm_ref->now();
// run shred on VM
invoker_shred->run( invoker_shred->vm_ref );
}




//-----------------------------------------------------------------------------
// name: cleanup()
// desc: clean up
//-----------------------------------------------------------------------------
void Chuck_VM_DtorInvoker::cleanup()
{
// release shred reference
// NB this should also cleanup the code and VM instruction we created in setup
CK_SAFE_RELEASE( invoker_shred );

// zero out
instr_pushThis = NULL;
}




// begin CK_VM_DEBUG implementation
//-----------------------------------------------------------------------------
#if CK_VM_DEBUG_ENABLE
31 changes: 31 additions & 0 deletions src/core/chuck_vm.h
Original file line number Diff line number Diff line change
@@ -862,6 +862,37 @@ struct Chuck_VM_MFunInvoker



//-----------------------------------------------------------------------------
// name: struct Chuck_VM_DtorInvoker | 1.5.1.9 (ge)
// desc: construct for calling chuck-defined @destruct from c++,
// typically called for Object cleanup
//-----------------------------------------------------------------------------
struct Chuck_VM_DtorInvoker
{
public:
// constructor
Chuck_VM_DtorInvoker();
// destructor
~Chuck_VM_DtorInvoker();

public:
// set up the invoker; needed before invoke()
t_CKBOOL setup( Chuck_Func * func, Chuck_VM * vm, Chuck_VM_Shred * caller );
// invoke the member function
void invoke( Chuck_Object * obj, Chuck_VM_Shred * parent_shred );
// clean up
void cleanup();

public:
// dedicated shred to call the dtor on, since this could be running "outside of chuck time"
Chuck_VM_Shred * invoker_shred;
// instruction to update on invoke: pushing this pointer
Chuck_Instr_Reg_Push_Imm * instr_pushThis;
};




//-----------------------------------------------------------------------------
// VM debug macros | 1.5.0.5 (ge) added
// these are governed by the presence of __CHUCK_DEBUG__ (e.g., from makefile)