Skip to content

Commit

Permalink
check for constant var RHS; fix class type value emit
Browse files Browse the repository at this point in the history
  • Loading branch information
gewang committed Dec 10, 2024
1 parent 3118d7c commit 5735834
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 37 deletions.
17 changes: 14 additions & 3 deletions VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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
Expand Down
30 changes: 27 additions & 3 deletions examples/class/inline-doc.ck
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) >>>;
25 changes: 23 additions & 2 deletions src/core/chuck_emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand All @@ -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 );
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 )
{
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/core/chuck_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
45 changes: 17 additions & 28 deletions src/core/ulib_doc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -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:
Expand Down
42 changes: 42 additions & 0 deletions src/test/01-Basic/273-doc-describe.ck
Original file line number Diff line number Diff line change
@@ -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 ) >>>;
5 changes: 5 additions & 0 deletions src/test/01-Basic/273-doc-describe.txt
Original file line number Diff line number Diff line change
@@ -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)
20 changes: 20 additions & 0 deletions src/test/01-Basic/274-type-edge-cases.ck
Original file line number Diff line number Diff line change
@@ -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 ) >>>;
4 changes: 4 additions & 0 deletions src/test/01-Basic/274-type-edge-cases.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"a representation of a ChucK type." :(string)
"a sine wave oscillator." :(string)
"a sine wave oscillator." :(string)
"" :(string)
5 changes: 5 additions & 0 deletions src/test/06-Errors/error-assign-to-class.ck
Original file line number Diff line number Diff line change
@@ -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;

3 changes: 3 additions & 0 deletions src/test/06-Errors/error-assign-to-class.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
error-assign-to-class.ck:4:10: error: cannot modify constant variable 'JCRev'
[4] null @=> JCRev;
^

0 comments on commit 5735834

Please sign in to comment.