diff --git a/VERSIONS b/VERSIONS index ff5002d8a..0cc4912b6 100644 --- a/VERSIONS +++ b/VERSIONS @@ -6,6 +6,8 @@ ChucK VERSIONS log ======= (added) basic @doc functionality for language-defined classes to add inline CKDoc documentation for class definitions and function defintions. +(added) function to retrive CKDoc descriptions for classes and functions: + string CKDoc.describe( Object target ); ---------------------------------------- class Foo { @@ -18,10 +20,19 @@ ChucK VERSIONS log @doc "a function in Foo, bar() likes calling his friends" } } - // can see the above @doc descriptions printed in the class info - // (will also appear in documentation generated by CKDoc) - Foo.help(); + // print class description + CKDoc.describe( Foo ); + // with an instance, can also get info about instanced functions + Foo f; + <<< CKDoc.describe( f ) >>>; + <<< CKDoc.describe( f.bar ) >>>; ---------------------------------------- +(fixed) proper emission of classes by name, e.g., `<<< SinOsc >>>;` +(fixed) attempts to assign to a constant right-hand-side variable + e.g., `null @=> SinOsc;` now results in a compiler error + NOTE: in the above example, SinOsc is a variable of type 'Type' + and is created alongside the SinOsc class/type; such Type variables + associated with class definitions are automatically marked as constant (fixed) crash due to functions / classes references a local variable defined at file-scope; code emission is now internally re-ordered to compile file-scope code segments -> function definitions -> class definitions diff --git a/examples/class/inline-doc.ck b/examples/class/inline-doc.ck index 439da4f4b..0efc4680b 100644 --- a/examples/class/inline-doc.ck +++ b/examples/class/inline-doc.ck @@ -9,15 +9,39 @@ class Foo { // add inline documenation (processed at compile-time) + // (@doc can appear anywhere within the class definition) @doc "this is a description for the class Foo" fun void bar() { + beth(); + kenny(); + // add inline documenation (processed at compile-time) + // (@doc can appear anywhere within the function definition) @doc "a function in Foo, bar() likes calling his friends" } + + fun static void beth() + { + // add inline documenation (processed at compile-time) + @doc "beth() is working on a novel about shared memory" + } + + fun static void kenny() + { + // add inline documenation (processed at compile-time) + @doc "kenny() is fun, and expects nothing in return" + } } -// print runtime info about Foo: -// can see the above @doc descriptions in the class info + +// print runtime info about Foo... // (will also appear in documentation generated by CKDoc) -Foo.help(); +<<< CKDoc.describe( Foo ) >>>; +<<< CKDoc.describe( Foo.beth ) >>>; +<<< CKDoc.describe( Foo.kenny ) >>>; + +// with an instance, can also get info about instanced functions +Foo f; +<<< CKDoc.describe( f ) >>>; +<<< CKDoc.describe( f.bar ) >>>; diff --git a/src/core/chuck_emit.cpp b/src/core/chuck_emit.cpp index bdb2f9c90..caaa76037 100644 --- a/src/core/chuck_emit.cpp +++ b/src/core/chuck_emit.cpp @@ -3441,7 +3441,9 @@ t_CKBOOL emit_engine_emit_op_at_chuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rh if( isa( left, right ) ) { // basic types? - if( type_engine_check_primitive( emit->env, left ) || isa( left, emit->env->ckt_string ) ) + // 1.5.4.4 (ge) updated to isa( right, emit->env->ckt_string ) instead of left + // in case left is null; right can't be null since null should be const + if( type_engine_check_primitive( emit->env, left ) || isa( right, emit->env->ckt_string ) ) { // assigment? if( rhs->s_meta != ae_meta_var ) @@ -3461,7 +3463,9 @@ t_CKBOOL emit_engine_emit_op_at_chuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rh emit->append( instr = new Chuck_Instr_Time_Advance ); instr->set_linepos( lhs->line ); } - else if( isa( left, emit->env->ckt_string ) ) // string + // string | 1.5.4.4 (ge) updated to check right instead of left + // in case left is null; right can't be null since null should be const + else if( isa( right, emit->env->ckt_string ) ) { // assign string emit->append( new Chuck_Instr_Assign_String ); @@ -3500,6 +3504,7 @@ t_CKBOOL emit_engine_emit_op_at_chuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rh } // TODO: deal with const + // 1.5.4.4 (ge) if RHS is a var, now const is checked in // no match EM_error2( lhs->where, @@ -6308,6 +6313,14 @@ t_CKBOOL emit_engine_emit_symbol( Chuck_Emitter * emit, S_Symbol symbol, // var or value if( emit_var ) { + // check for const | 1.5.4.4 (ge) added + if( v->is_const ) + { + EM_error2( exp->where, + "cannot modify constant variable '%s'", S_name( exp->var ) ); + return FALSE; + } + // emit as addr if( v->is_global ) { @@ -6340,6 +6353,14 @@ t_CKBOOL emit_engine_emit_symbol( Chuck_Emitter * emit, S_Symbol symbol, instr->set_linepos( line ); emit->append( instr ); } + else if( isa(v->type, emit->env->ckt_class) && + v->owner->lookup_type( v->name, 0, TRUE ) ) // 1.5.4.4 (ge) if the value is of type Type (e.g., <<< SinOsc >>>;) + { + // look up the type by name in the value's owner namespace, climb==0, stayWithinClassDef==TRUE + Chuck_Type * type = v->owner->lookup_type( v->name, 0, TRUE ); + // append the value pointer directly | 1.5.4.4 (ge) added + emit->append( new Chuck_Instr_Reg_Push_Imm( (t_CKUINT)type ) ); + } // check size // (added 1.3.1.0: iskindofint -- since in some 64-bit systems, sz_INT == sz_FLOAT) else if( v->type->size == sz_INT && iskindofint(emit->env, v->type) ) // ISSUE: 64-bit (fixed 1.3.1.0) diff --git a/src/core/chuck_type.cpp b/src/core/chuck_type.cpp index 0664556a6..1e7321eae 100644 --- a/src/core/chuck_type.cpp +++ b/src/core/chuck_type.cpp @@ -2466,7 +2466,7 @@ t_CKTYPE type_engine_check_op( Chuck_Env * env, ae_Operator op, a_Exp lhs, a_Exp } // mark to emit var instead of value - rhs->emit_var = 1; + rhs->emit_var = TRUE; break; diff --git a/src/core/ulib_doc.cpp b/src/core/ulib_doc.cpp index 5b1cd1aeb..97045725d 100644 --- a/src/core/ulib_doc.cpp +++ b/src/core/ulib_doc.cpp @@ -231,11 +231,11 @@ DLL_QUERY ckdoc_query( Chuck_DL_Query * QUERY ) // func->doc = "Associate a description with `target`, which must be either a Type (i.e., a class) or a function. Returns true on sucess; returns false if target is neither a class nor function, or if describe() was called on a target without sufficient permission to update its description."; // if( !type_engine_import_sfun( env, func ) ) goto error; - // // describe - // func = make_new_sfun( "string", "describe", CKDoc_get_describe ); - // func->add_arg( "Object", "target" ); - // func->doc = "Returns the description associated with `target`, which must be either a Type (i.e., a class) or a function."; - // if( !type_engine_import_sfun( env, func ) ) goto error; + // describe + func = make_new_sfun( "string", "describe", CKDoc_get_describe ); + func->add_arg( "Object", "target" ); + func->doc = "Returns the description associated with `target`, which must be either a Type (i.e., a class) or a function."; + if( !type_engine_import_sfun( env, func ) ) goto error; // end the class import type_engine_import_class_end( env ); @@ -2351,44 +2351,33 @@ CK_DLL_SFUN( CKDoc_get_describe ) { Chuck_Object * target = GET_NEXT_OBJECT(ARGS); // type of object - Chuck_Type * type = target ? target->type_ref : NULL; + Chuck_Type * targetType = NULL; string doc = ""; // check it - if( !target ) - { - CK_FPRINTF_STDERR( "CKDoc.describe(): null target argument; no action taken.\n" ); - goto done; - } - - // check target type - if( !isa(type,VM->env()->ckt_class) && !isa(type,VM->env()->ckt_function) ) - { - CK_FPRINTF_STDERR( "CKDoc.describe(): target type must be either Type (i.e., a class) or a function; no action taken.\n" ); - goto done; - } + if( !target ) goto done; + targetType = target->type_ref; // if a class - if( isa(type,VM->env()->ckt_class) ) + if( isa(targetType,VM->env()->ckt_class) ) { - // target is a type - Chuck_Type * targetType = (Chuck_Type *)target; + // target is a Type type + Chuck_Type * type = (Chuck_Type *)target; // copy the document string - doc = targetType->doc; + doc = type->doc; } // if a func - else if( isa(type,VM->env()->ckt_function) ) + else if( isa(targetType,VM->env()->ckt_function) ) { // target is a function - Chuck_Func * targetFunc = (Chuck_Func *)target; + Chuck_Func * func = (Chuck_Func *)target; // copy the document string - doc = targetFunc->doc; + doc = func->doc; } else { - // should not get here - CK_FPRINTF_STDERR( "CKDoc.describe(): internal error -- unaccounted Object type '%s", target->type_ref->name().c_str() ); - goto done; + // use the target's type and copy the document string + doc = targetType->doc; } done: diff --git a/src/test/01-Basic/273-doc-describe.ck b/src/test/01-Basic/273-doc-describe.ck new file mode 100644 index 000000000..642a90fc5 --- /dev/null +++ b/src/test/01-Basic/273-doc-describe.ck @@ -0,0 +1,42 @@ +// test adding descriptions with classes and functions using @doc +// requires: chuck-1.5.4.4 or higher + +class Foo +{ + // add inline documenation (processed at compile-time) + // (@doc can appear anywhere within the class definition) + @doc "this is a description for the class Foo" + + fun void bar() + { + beth(); + kenny(); + + // add inline documenation (processed at compile-time) + // (@doc can appear anywhere within the function definition) + @doc "a function in Foo, bar() likes calling his friends" + } + + fun static void beth() + { + // add inline documenation (processed at compile-time) + @doc "beth() is working on a novel about shared memory" + } + + fun static void kenny() + { + // add inline documenation (processed at compile-time) + @doc "kenny() is fun, and expects nothing in return" + } +} + +// print runtime info about Foo... +// (will also appear in documentation generated by CKDoc) +<<< CKDoc.describe( Foo ) >>>; +<<< CKDoc.describe( Foo.beth ) >>>; +<<< CKDoc.describe( Foo.kenny ) >>>; + +// with an instance, can also get info about instanced functions +Foo f; +<<< CKDoc.describe( f ) >>>; +<<< CKDoc.describe( f.bar ) >>>; diff --git a/src/test/01-Basic/273-doc-describe.txt b/src/test/01-Basic/273-doc-describe.txt new file mode 100644 index 000000000..1fed9c9c3 --- /dev/null +++ b/src/test/01-Basic/273-doc-describe.txt @@ -0,0 +1,5 @@ +"this is a description for the class Foo" :(string) +"beth() is working on a novel about shared memory" :(string) +"kenny() is fun, and expects nothing in return" :(string) +"this is a description for the class Foo" :(string) +"a function in Foo, bar() likes calling his friends" :(string) diff --git a/src/test/01-Basic/274-type-edge-cases.ck b/src/test/01-Basic/274-type-edge-cases.ck new file mode 100644 index 000000000..085387392 --- /dev/null +++ b/src/test/01-Basic/274-type-edge-cases.ck @@ -0,0 +1,20 @@ +// strange (but valid) edge cases... + +// first, not so strange... +// print info about Type +<<< CKDoc.describe( Type ) >>>; +// print info about SinOsc +<<< CKDoc.describe( SinOsc ) >>>; + +// next, getting strange... +// a local variable whose name shadows an existing type +SinOsc NRev; +// should print out info about SinOsc +<<< CKDoc.describe( NRev ) >>>; + +// really strange (but possible) situation... +// a local Type variable whose name shadows another type +Type JCRev; +// should print "" (and not Type's info) +// since here `JCRev` is an empty Type... +<<< CKDoc.describe( JCRev ) >>>; diff --git a/src/test/01-Basic/274-type-edge-cases.txt b/src/test/01-Basic/274-type-edge-cases.txt new file mode 100644 index 000000000..0b700013b --- /dev/null +++ b/src/test/01-Basic/274-type-edge-cases.txt @@ -0,0 +1,4 @@ +"a representation of a ChucK type." :(string) +"a sine wave oscillator." :(string) +"a sine wave oscillator." :(string) +"" :(string) diff --git a/src/test/06-Errors/error-assign-to-class.ck b/src/test/06-Errors/error-assign-to-class.ck new file mode 100644 index 000000000..930b36d59 --- /dev/null +++ b/src/test/06-Errors/error-assign-to-class.ck @@ -0,0 +1,5 @@ +// added chuck-1.5.4.4 + +// error case: cannot modify; JCRev as a variable here should be marked as const... +null @=> JCRev; + diff --git a/src/test/06-Errors/error-assign-to-class.txt b/src/test/06-Errors/error-assign-to-class.txt new file mode 100644 index 000000000..9984c88de --- /dev/null +++ b/src/test/06-Errors/error-assign-to-class.txt @@ -0,0 +1,3 @@ +error-assign-to-class.ck:4:10: error: cannot modify constant variable 'JCRev' +[4] null @=> JCRev; + ^