Skip to content

Commit

Permalink
add support for destructor
Browse files Browse the repository at this point in the history
  • Loading branch information
gewang committed Nov 15, 2023
1 parent 5379ff3 commit 2137737
Show file tree
Hide file tree
Showing 16 changed files with 327 additions and 79 deletions.
34 changes: 33 additions & 1 deletion VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,40 @@
ChucK VERSIONS log
------------------

1.5.1.9 (November 2023)
1.5.1.9 (November 2023) "Better Late Than Never...constructors"
=======
- (added) language-level, overloadable class constructors
- (added) language-level class destructor
```
class Foo
{
// a member variable
1 => int num;

// constructor "default"
fun void Foo() { 2 => num; }

// another constructor
fun void Foo( int x ) { x => num; }

// yet another constructor
fun void Foo( int x, int y ) { x*y => num; }

// destructor
fun @destruct() { <<< "bye:", this >>>; }
}

// constructor "default"
Foo f1();
// another constructor
Foo f2(15);
// yet another constructor
new Foo(8,9) @=> Foo @ f3;
// print
<<< f1.num, f2.num, f3.num >>>;
```
- (added) examples/class/constructors.ck
- (added) examples/class/destructor.ck
- (added) Shred.parent() and Shred.ancestor()
- (added) chugins runtime API support for creating arrays from chugins
- (fixed) Type.of("int[][]").isArray() now correctly returns true
Expand Down
6 changes: 4 additions & 2 deletions src/core/chuck.y
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,10 @@ function_definition
// { $$ = 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 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 AT_DTOR LPAREN arg_list RPAREN code_segment // 1.5.1.9 (ge) added for constructors
{ $$ = new_func_def( $1, ae_key_instance, NULL, "@destruct", $4, $6, 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
Expand Down
35 changes: 24 additions & 11 deletions src/core/chuck_oo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,26 +288,39 @@ Chuck_Object::~Chuck_Object()
while( type != NULL )
{
// 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
if( type->info && type->info->pre_dtor ) // 1.5.0.0 (ge) added type->info check
{
// verify
assert( type->info->dtor );
// check origin of dtor
if( type->info->dtor->native_func ) // defined in c++
if( type->info->pre_dtor->native_func ) // c++-defined deconstructor
{
// 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() );
((f_dtor)(type->info->pre_dtor->native_func))( this, vm, shred, Chuck_DL_Api::instance() );
}
else // chuck-defined deconstructor
{
// this shouldn't be possible
EM_error3( "(internal error) native_func dtor not found in class '%s'...", type->c_name() );
// keep going for now...
}
}

// chuck-defined destructor | 1.5.1.9 (ge) added
if( type->dtor )
{
// verify
if( !type->dtor_invoker )
{
EM_error3( "(internal error) dtor invoker not found in class '%s'...", type->c_name() );
}
else // defined in chuck
else
{
// 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?
// invoke the dtor
// NOTE @destruct disallows accessing context-global variables/functions
type->dtor_invoker->invoke( this, this->originShred() );
}
}

// go up the inheritance
type = type->parent;
}
Expand Down
83 changes: 58 additions & 25 deletions src/core/chuck_scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1432,14 +1432,16 @@ t_CKBOOL type_engine_scan1_func_def( Chuck_Env * env, a_Func_Def f )
// make sure there are no arguments
if( f->arg_list != NULL )
{
EM_error2( f->where, "@destruct() does not accept arguments..." );
EM_error2( f->where, "@destruct() cannot accept arguments..." );
return FALSE;
}
// substitute ~[class name]
f->name = insert_symbol( string("~"+env->class_def->base_name).c_str() );
// f->name = insert_symbol( string("~"+env->class_def->base_name).c_str() );
}
// check if constructor
t_CKBOOL isInCtor = isctor(env,f);
// check if destructor
t_CKBOOL isInDtor = isdtor(env,f);

// check if reserved
if( type_engine_check_reserved( env, f->name, f->where ) )
Expand Down Expand Up @@ -1467,12 +1469,22 @@ t_CKBOOL type_engine_scan1_func_def( Chuck_Env * env, a_Func_Def f )
// check return type (must be void)
if( !isa(f->ret_type, env->ckt_void) )
{
EM_error2( f->where, "constructor for class '%s' must return void",
EM_error2( f->where, "constructor for class '%s' must return void...",
S_name(f->name) );
goto error;
}
}

if( isInDtor )
{
// check return type (must be void)
if( !isa(f->ret_type, env->ckt_void) )
{
EM_error2( f->where, "destructor must return void..." );
goto error;
}
}

// check if array
if( f->type_decl->array != NULL )
{
Expand Down Expand Up @@ -2768,7 +2780,7 @@ t_CKBOOL type_engine_scan2_class_def( Chuck_Env * env, a_Class_Def class_def )

//-----------------------------------------------------------------------------
// name: type_engine_scan2_func_def()
// desc: ...
// desc: type scan 2 for function definition
//-----------------------------------------------------------------------------
t_CKBOOL type_engine_scan2_func_def( Chuck_Env * env, a_Func_Def f )
{
Expand All @@ -2793,6 +2805,8 @@ t_CKBOOL type_engine_scan2_func_def( Chuck_Env * env, a_Func_Def f )
t_CKBOOL op_overload = ( f->op2overload != ae_op_none );
// is in constructor? | 1.5.1.9
t_CKBOOL isInCtor = isctor(env,f);
// is in destructor? | 1.5.1.9
t_CKBOOL isInDtor = isdtor(env,f);

// see if we are already in a function definition
if( env->func != NULL )
Expand Down Expand Up @@ -2876,25 +2890,6 @@ t_CKBOOL type_engine_scan2_func_def( Chuck_Env * env, a_Func_Def f )
func->code->native_func = (t_CKUINT)func->def()->dl_func_ptr;
}

// constructor | 1.5.1.9 (ge) added
if( isInCtor )
{
// set constructor flag
func->is_ctor = TRUE;
// set in class as constructor; if not NULL, then a ctor is already set, and this is an overloading
if( env->class_def->ctors == NULL )
{
CK_SAFE_REF_ASSIGN( env->class_def->ctors, func );
}
// check if default constructor
func->is_default_ctor = (f->arg_list == NULL);
// if no arguments, then set as base constructor
if( func->is_default_ctor )
{
CK_SAFE_REF_ASSIGN( env->class_def->ctor_default, func );
}
}

// make a new type for the function
type = env->context->new_Chuck_Type( env );
type->xid = te_function;
Expand Down Expand Up @@ -3126,13 +3121,13 @@ t_CKBOOL type_engine_scan2_func_def( Chuck_Env * env, a_Func_Def f )
EM_error2( f->where, "cannot overload functions with identical arguments..." );
if( env->class_def )
{
EM_error3( " |- '%s %s.%s( %s )' already defined elsewhere",
EM_error3( " |- '%s %s.%s(%s)' already defined elsewhere",
func->def()->ret_type->base_name.c_str(), env->class_def->c_name(),
orig_name.c_str(), arglist2string(func->def()->arg_list).c_str() );
}
else
{
EM_error3( " |- '%s %s( %s )' already defined elsewhere",
EM_error3( " |- '%s %s(%s)' already defined elsewhere",
func->def()->ret_type->base_name.c_str(), orig_name.c_str(), arglist2string(func->def()->arg_list).c_str() );
}
goto error;
Expand All @@ -3143,6 +3138,44 @@ t_CKBOOL type_engine_scan2_func_def( Chuck_Env * env, a_Func_Def f )
}
}

// constructor | 1.5.1.9 (ge) added
if( isInCtor )
{
// set constructor flag
func->is_ctor = TRUE;
// set in class as constructor; if not NULL, then a ctor is already set, and this is an overloading
if( env->class_def->ctors == NULL )
{
CK_SAFE_REF_ASSIGN( env->class_def->ctors, func );
}
// check if default constructor
func->is_default_ctor = (f->arg_list == NULL);
// if no arguments, then set as base constructor
if( func->is_default_ctor )
{
CK_SAFE_REF_ASSIGN( env->class_def->ctor_default, func );
}
}

// destructor | 1.5.1.9 (ge) added
if( isInDtor )
{
// verify
if( env->class_def->dtor != NULL )
{
EM_error2( f->where, "(internal error): unexpected destructor found in '%s'...", env->class_def->c_name() );
return FALSE;
}
// set destructor flag
func->is_dtor = TRUE;
// set in class as destructor
CK_SAFE_REF_ASSIGN( env->class_def->dtor, func );
// set invoker
env->class_def->dtor_invoker = new Chuck_VM_DtorInvoker;
// init invoker
env->class_def->dtor_invoker->setup( func, env->vm() );
}

// operator overload | 1.5.1.5 (ge) added
if( op_overload )
{
Expand Down
Loading

0 comments on commit 2137737

Please sign in to comment.