Skip to content

Commit

Permalink
fix parent info used before define
Browse files Browse the repository at this point in the history
  • Loading branch information
gewang committed Oct 6, 2023
1 parent d711ed6 commit 4a17fb6
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 61 deletions.
52 changes: 50 additions & 2 deletions src/core/chuck_scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@ t_CKBOOL type_engine_scan2_cast_valid( Chuck_Env * env, t_CKTYPE to, t_CKTYPE fr
t_CKBOOL type_engine_scan2_code_segment( Chuck_Env * env, a_Stmt_Code stmt, t_CKBOOL push = TRUE );
t_CKBOOL type_engine_scan2_func_def( Chuck_Env * env, a_Func_Def func_def );
t_CKBOOL type_engine_scan2_class_def( Chuck_Env * env, a_Class_Def class_def );
t_CKBOOL type_engine_scan2_func_def( Chuck_Env * env, a_Func_Def func_def );
t_CKBOOL type_engine_scan2_class_def( Chuck_Env * env, a_Class_Def class_def );



Expand Down Expand Up @@ -2642,6 +2640,56 @@ t_CKBOOL type_engine_scan2_class_def( Chuck_Env * env, a_Class_Def class_def )
env->curr = env->nspc_stack.back();
env->nspc_stack.pop_back();

// the parent class | 1.5.1.4 (ge) moved from chuck_type module for earlier info
t_CKTYPE t_parent = NULL;

// make sure inheritance
// TODO: sort!
if( class_def->ext )
{
// if extend
if( class_def->ext->extend_id )
{
// find the type
t_parent = type_engine_find_type( env, class_def->ext->extend_id );
if( !t_parent )
{
EM_error2( class_def->ext->extend_id->where,
"undefined super class '%s' in definition of class '%s'",
type_path(class_def->ext->extend_id), S_name(class_def->name->xid) );
return FALSE;
}

// must not be primitive
if( isprim( env, t_parent ) )
{
EM_error2( class_def->ext->extend_id->where,
"cannot extend primitive type '%s'",
t_parent->c_name() );
EM_error2( 0, "...(primitive types: 'int', 'float', 'time', 'dur', etc.)" );
return FALSE;
}
}

// TODO: interface
}

// by default object
if( !t_parent ) t_parent = env->ckt_object;

// check for fun
assert( env->context != NULL );
assert( class_def->type != NULL );
assert( class_def->type->info != NULL );

// retrieve the new type (created in scan_class_def)
the_class = class_def->type;

// set fields not set in scan
the_class->parent = t_parent; CK_SAFE_ADD_REF(t_parent);
// inherit ugen_info data from parent PLD
the_class->ugen_info = t_parent->ugen_info; CK_SAFE_ADD_REF(t_parent->ugen_info);

return ret;
}

Expand Down
75 changes: 16 additions & 59 deletions src/core/chuck_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4705,75 +4705,32 @@ t_CKTYPE type_engine_check_exp_array( Chuck_Env * env, a_Exp_Array array )
t_CKBOOL type_engine_check_class_def( Chuck_Env * env, a_Class_Def class_def )
{
// make new type for class def
t_CKTYPE the_class = NULL;
// the parent class
t_CKTYPE t_parent = NULL;
t_CKTYPE the_class = class_def->type;
// the return type
t_CKBOOL ret = TRUE;
// the class body
a_Class_Body body = class_def->body;

// make sure inheritance
// TODO: sort!
if( class_def->ext )
// check if parent class definition is complete or not
// NOTE this could potentially be remove if class defs can be processed
// out of order they appear in file; potentially a relationship tree?
if( the_class->parent->is_complete == FALSE )
{
// if extend
if( class_def->ext->extend_id )
{
// find the type
t_parent = type_engine_find_type( env, class_def->ext->extend_id );
if( !t_parent )
{
EM_error2( class_def->ext->extend_id->where,
"undefined super class '%s' in definition of class '%s'",
type_path(class_def->ext->extend_id), S_name(class_def->name->xid) );
return FALSE;
}

// must not be primitive
if( isprim( env, t_parent ) )
{
EM_error2( class_def->ext->extend_id->where,
"cannot extend primitive type '%s'",
t_parent->c_name() );
EM_error2( 0, "...(primitive types: 'int', 'float', 'time', 'dur', etc.)" );
return FALSE;
}

// if not complete
if( t_parent->is_complete == FALSE )
{
EM_error2( class_def->ext->where,
"cannot extend incomplete type '%s'",
t_parent->c_name() );
EM_error2( class_def->ext->where,
"...(note: the parent's declaration must precede child's)" );
return FALSE;
}
}

// TODO: interface
EM_error2( class_def->ext->where,
"cannot extend incomplete type '%s'",
the_class->parent->c_name() );
EM_error2( class_def->ext->where,
"...(note: the parent's declaration must precede child's)" );
// done
return FALSE;
}

// by default object
if( !t_parent ) t_parent = env->ckt_object;

// check for fun
assert( env->context != NULL );
assert( class_def->type != NULL );
assert( class_def->type->info != NULL );

// retrieve the new type (created in scan_class_def)
the_class = class_def->type;

// set fields not set in scan
the_class->parent = t_parent;
// inherit ugen_info data from parent PLD
the_class->ugen_info = t_parent->ugen_info;
// NB the following should be done AFTER the parent is completely defined
// --
// set the beginning of data segment to after the parent
the_class->info->offset = t_parent->obj_size;
the_class->info->offset = the_class->parent->obj_size;
// duplicate the parent's virtual table
the_class->info->obj_v_table = t_parent->info->obj_v_table;
the_class->info->obj_v_table = the_class->parent->info->obj_v_table;

// set the new type as current
env->nspc_stack.push_back( env->curr );
Expand Down
26 changes: 26 additions & 0 deletions src/test/01-Basic/215-use-before-extend.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// this verifies that inheritance parent type is recognized if
// use before the class definition in file
// https://github.com/ccrma/chuck/issues/375

// instance of our event
TheEvent e;

// spork a shred to broadcast later
spork ~ timer( 1::samp );

// verify e can be recognized as child of Event,
// before TheEvent definition
e => now;

// if we got here, then done
<<< "success" >>>;

// custom Event class
class TheEvent extends Event { }

// a function to wait a bit and broadcast
fun void timer( dur T )
{
T => now;
e.broadcast();
}
27 changes: 27 additions & 0 deletions src/test/06-Errors/error-class-def-order.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// error case: out of order class definitions; Y extends X, but
// Y is defined ahead of X; certain definitions can appear after
// usage or invocation, but for now this is not permitted


// define Y
class Y extends X
{
public void foo() { }
}

// define X
class X
{
public void foo() { }
int y;
dur z;
}

// instantiate a X
X x;

// instantiate a Y
Y y;

// shouldn't get here...
<<<"shouldn't get here...">>>;
6 changes: 6 additions & 0 deletions src/test/06-Errors/error-class-def-order.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
error-class-def-order.ck:7:9: error: cannot extend incomplete type 'X'
[7] class Y extends X
^
error-class-def-order.ck:7:9: error: ...(note: the parent's declaration must precede child's)
[7] class Y extends X
^

0 comments on commit 4a17fb6

Please sign in to comment.