diff --git a/src/core/chuck_scan.cpp b/src/core/chuck_scan.cpp index 63b9001b9..37dff0e6a 100644 --- a/src/core/chuck_scan.cpp +++ b/src/core/chuck_scan.cpp @@ -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 ); @@ -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; } diff --git a/src/core/chuck_type.cpp b/src/core/chuck_type.cpp index 85e6fee07..87acb08f2 100644 --- a/src/core/chuck_type.cpp +++ b/src/core/chuck_type.cpp @@ -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 ); diff --git a/src/test/01-Basic/215-use-before-extend.ck b/src/test/01-Basic/215-use-before-extend.ck new file mode 100644 index 000000000..d61e9e138 --- /dev/null +++ b/src/test/01-Basic/215-use-before-extend.ck @@ -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(); +} diff --git a/src/test/06-Errors/error-class-def-order.ck b/src/test/06-Errors/error-class-def-order.ck new file mode 100644 index 000000000..fc65fa708 --- /dev/null +++ b/src/test/06-Errors/error-class-def-order.ck @@ -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...">>>; diff --git a/src/test/06-Errors/error-class-def-order.txt b/src/test/06-Errors/error-class-def-order.txt new file mode 100644 index 000000000..c3a887d2b --- /dev/null +++ b/src/test/06-Errors/error-class-def-order.txt @@ -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 + ^