History

memory system upgrade (part 1); scope-sensitive cleanup for each return statement; clarified reference counting semantics; function argument release for builtin functions; improved post-function call object cleanup; auto-reference-increment on returned objects from all builtin/imported functions; absyn tree printing for instruction dumping abysn2str(); Machine.refcount() and refcount printing for object references

Ge Wang committed 3 years ago

Commit beef6541 parent 2eec4e717 files · +835 −72Browse files

Unified · Split

17 files
  1. src/core/chuck_emit.cpp +99 −24
  2. src/core/chuck_emit.h +3 −1
  3. src/core/chuck_frame.cpp +7 −2
  4. src/core/chuck_frame.h +1 −1
  5. src/core/chuck_instr.cpp +197 −12
  6. src/core/chuck_instr.h +44 −5
  7. src/core/chuck_lang.cpp +6 −1
  8. src/core/chuck_oo.cpp +11 −2
  9. src/core/chuck_parse.cpp +404 −0
  10. src/core/chuck_parse.h +2 −0
  11. src/core/ulib_machine.cpp +34 −2
  12. src/core/ulib_machine.h +1 −17
  13. src/test/01-Basic/120.ck +20 −0
  14. src/test/01-Basic/120.txt +1 −0
  15. src/test/05-Global/01b.txt +1 −1
  16. src/test/05-Global/102a.txt +3 −3
  17. src/test/test.py +1 −1
src/core/chuck_emit.cpp+99−24
@@ -35,6 +35,7 @@ · 34 unmodified lines
35#include "chuck_errmsg.h"35#include "chuck_errmsg.h"
36#include "chuck_instr.h"36#include "chuck_instr.h"
37#include "chuck_globals.h" // added 1.4.1.037#include "chuck_globals.h" // added 1.4.1.0
38#include "chuck_parse.h" // added 1.4.2.1
38#include <sstream>39#include <sstream>
39#include <iostream>40#include <iostream>
40 41
@@ -73,7 +74,7 @@ t_CKBOOL emit_engine_emit_exp_postfix( Chuck_Emitter * emit, a_Exp_Postfix postf · 32 unmodified lines
73t_CKBOOL emit_engine_emit_exp_dur( Chuck_Emitter * emit, a_Exp_Dur dur );74t_CKBOOL emit_engine_emit_exp_dur( Chuck_Emitter * emit, a_Exp_Dur dur );
74t_CKBOOL emit_engine_emit_exp_array( Chuck_Emitter * emit, a_Exp_Array array );75t_CKBOOL emit_engine_emit_exp_array( Chuck_Emitter * emit, a_Exp_Array array );
75t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, Chuck_Func * func,76t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, Chuck_Func * func,
76 Chuck_Type * type, int linepos, t_CKBOOL spork = FALSE );77 a_Exp args, Chuck_Type * type, int linepos, t_CKBOOL spork = FALSE );
77t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, a_Exp_Func_Call func_call,78t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, a_Exp_Func_Call func_call,
78 t_CKBOOL spork = FALSE );79 t_CKBOOL spork = FALSE );
79t_CKBOOL emit_engine_emit_func_args( Chuck_Emitter * emit, a_Exp_Func_Call func_call );80t_CKBOOL emit_engine_emit_func_args( Chuck_Emitter * emit, a_Exp_Func_Call func_call );
@@ -386,6 +387,10 @@ t_CKBOOL emit_engine_emit_stmt( Chuck_Emitter * emit, a_Stmt stmt, t_CKBOOL pop · 306 unmodified lines
386 ret = emit_engine_emit_exp( emit, stmt->stmt_exp );387 ret = emit_engine_emit_exp( emit, stmt->stmt_exp );
387 if( !ret )388 if( !ret )
388 return FALSE;389 return FALSE;
390
391 // 1.4.2.1
392 // cerr << absyn2str( stmt->stmt_exp ) << endl;
393
389 // need to pop the final value from stack394 // need to pop the final value from stack
390 if( ret && pop && stmt->stmt_exp->type->size > 0 )395 if( ret && pop && stmt->stmt_exp->type->size > 0 )
391 {396 {
@@ -398,17 +403,25 @@ t_CKBOOL emit_engine_emit_stmt( Chuck_Emitter * emit, a_Stmt stmt, t_CKBOOL pop · 6 unmodified lines
398 if( exp->s_type == ae_exp_primary && exp->primary.s_type == ae_primary_hack )403 if( exp->s_type == ae_exp_primary && exp->primary.s_type == ae_primary_hack )
399 exp = exp->primary.exp;404 exp = exp->primary.exp;
400 405
401 // HACK!406 // loop over the expression that is the statement (prior to 1.4.2.1 comment: "HACK" hmmm...)
402 while( exp )407 while( exp )
403 {408 {
404 // if decl, then expect only one word per var409 // if decl, then expect only one word per var
405 // added 1.3.1.0: iskindofint -- since on some 64-bit systems sz_INT == sz_FLOAT410 // added 1.3.1.0: iskindofint -- since on some 64-bit systems sz_INT == sz_FLOAT
406 if( exp->s_type == ae_exp_decl )411 if( exp->s_type == ae_exp_decl )
412 {
407 // (added 1.3.1.0 -- multiply by type size; #64-bit)413 // (added 1.3.1.0 -- multiply by type size; #64-bit)
408 // (fixed 1.3.1.2 -- uh... decl should also be int-sized, so changed to INT/WORD)414 // (fixed 1.3.1.2 -- uh... decl should also be int-sized, so changed to INT/WORD)
409 emit->append( new Chuck_Instr_Reg_Pop_Word4( exp->decl.num_var_decls * sz_INT / sz_WORD ) );415 emit->append( new Chuck_Instr_Reg_Pop_Word4( exp->decl.num_var_decls * sz_INT / sz_WORD ) );
416 }
410 else if( exp->type->size == sz_INT && iskindofint(emit->env, exp->type) ) // ISSUE: 64-bit (fixed 1.3.1.0)417 else if( exp->type->size == sz_INT && iskindofint(emit->env, exp->type) ) // ISSUE: 64-bit (fixed 1.3.1.0)
411 emit->append( new Chuck_Instr_Reg_Pop_Word );418 {
419 // is an object left on the stack for the stmt
420 if( exp->s_type == ae_exp_func_call && isobj(emit->env, exp->type) )
421 { emit->append( new Chuck_Instr_Release_Object3_Pop_Word ); }
422 else // not an object
423 { emit->append( new Chuck_Instr_Reg_Pop_Word ); }
424 }
412 else if( exp->type->size == sz_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)425 else if( exp->type->size == sz_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)
413 emit->append( new Chuck_Instr_Reg_Pop_Word2 );426 emit->append( new Chuck_Instr_Reg_Pop_Word2 );
414 else if( exp->type->size == sz_COMPLEX ) // ISSUE: 64-bit (fixed 1.3.1.0)427 else if( exp->type->size == sz_COMPLEX ) // ISSUE: 64-bit (fixed 1.3.1.0)
@@ -1291,12 +1304,27 @@ t_CKBOOL emit_engine_emit_continue( Chuck_Emitter * emit, a_Stmt_Continue cont ) · 876 unmodified lines
1291//-----------------------------------------------------------------------------1304//-----------------------------------------------------------------------------
1292t_CKBOOL emit_engine_emit_return( Chuck_Emitter * emit, a_Stmt_Return stmt )1305t_CKBOOL emit_engine_emit_return( Chuck_Emitter * emit, a_Stmt_Return stmt )
1293{1306{
1307 // emit the value
1294 if( !emit_engine_emit_exp( emit, stmt->val ) )1308 if( !emit_engine_emit_exp( emit, stmt->val ) )
1295 return FALSE;1309 return FALSE;
1296 1310
1311 // if return is an object type
1312 if( isobj( emit->env, stmt->val->type ) )
1313 {
1314 // add reference (to be released by the function caller)
1315 emit->append( new Chuck_Instr_Reg_AddRef_Object3 );
1316 }
1317
1318 // 1.4.2.1 (ge) | traverse and unwind current scope frames, release object
1319 // references given the current state of the stack frames; every `return`
1320 // statement needs its own scope unwinding; FYI: this does not change the
1321 // scope frames, which is needed to continue compilation for the rest
1322 // of the function; this does emit instructions (e.g., Release_Object2)
1323 // associated with this traversal action (also see 'break' and 'continue')
1324 emit->traverse_scope_on_jump();
1325
1297 // emit return1326 // emit return
1298 // emit->append( new Chuck_Instr_Func_Return );1327 // emit->append( new Chuck_Instr_Func_Return );
1299
1300 // determine where later1328 // determine where later
1301 Chuck_Instr_Goto * instr = new Chuck_Instr_Goto( 0 );1329 Chuck_Instr_Goto * instr = new Chuck_Instr_Goto( 0 );
1302 emit->append( instr );1330 emit->append( instr );
@@ -2537,7 +2565,7 @@ t_CKBOOL emit_engine_emit_op_chuck( Chuck_Emitter * emit, a_Exp lhs, a_Exp rhs, · 1234 unmodified lines
2537 assert( binary->ck_func != NULL );2565 assert( binary->ck_func != NULL );
2538 2566
2539 // emit2567 // emit
2540 return emit_engine_emit_exp_func_call( emit, binary->ck_func, binary->self->type, binary->linepos );2568 return emit_engine_emit_exp_func_call( emit, binary->ck_func, binary->lhs, binary->self->type, binary->linepos );
2541 }2569 }
2542 2570
2543 // assignment or something else2571 // assignment or something else
@@ -3401,6 +3429,7 @@ t_CKBOOL emit_engine_emit_exp_array( Chuck_Emitter * emit, a_Exp_Array array ) · 857 unmodified lines
3401//-----------------------------------------------------------------------------3429//-----------------------------------------------------------------------------
3402t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit,3430t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit,
3403 Chuck_Func * func,3431 Chuck_Func * func,
3432 a_Exp args,
3404 Chuck_Type * type,3433 Chuck_Type * type,
3405 int linepos,3434 int linepos,
3406 t_CKBOOL spork )3435 t_CKBOOL spork )
@@ -3408,13 +3437,6 @@ t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, · 1 unmodified line
3408 // is a member?3437 // is a member?
3409 t_CKBOOL is_member = func->is_member;3438 t_CKBOOL is_member = func->is_member;
3410 3439
3411 // if member
3412 //if( is_member )
3413 //{
3414 // // this
3415 // emit->append( new Chuck_Instr_Reg_Push_This );
3416 //}
3417
3418 // translate to code3440 // translate to code
3419 emit->append( new Chuck_Instr_Func_To_Code );3441 emit->append( new Chuck_Instr_Func_To_Code );
3420 // emit->append( new Chuck_Instr_Reg_Push_Imm( (t_CKUINT)func->code ) );3442 // emit->append( new Chuck_Instr_Reg_Push_Imm( (t_CKUINT)func->code ) );
@@ -3436,9 +3458,9 @@ t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, · 15 unmodified lines
3436 {3458 {
3437 // is member (1.3.1.0: changed to use kind instead of size)3459 // is member (1.3.1.0: changed to use kind instead of size)
3438 if( is_member )3460 if( is_member )
3439 emit->append( instr = new Chuck_Instr_Func_Call_Member( kind ) );3461 emit->append( instr = new Chuck_Instr_Func_Call_Member( kind, func ) );
3440 else3462 else
3441 emit->append( instr = new Chuck_Instr_Func_Call_Static( kind ) );3463 emit->append( instr = new Chuck_Instr_Func_Call_Static( kind, func ) );
3442 }3464 }
3443 else3465 else
3444 {3466 {
@@ -3509,8 +3531,8 @@ t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, · 64 unmodified lines
3509 }3531 }
3510 3532
3511 // the rest3533 // the rest
3512 return emit_engine_emit_exp_func_call( emit, func_call->ck_func, func_call->ret_type,3534 return emit_engine_emit_exp_func_call( emit, func_call->ck_func, func_call->args,
3513 func_call->linepos, spork );3535 func_call->ret_type, func_call->linepos, spork );
3514}3536}
3515 3537
3516 3538
@@ -4126,7 +4148,7 @@ t_CKBOOL emit_engine_emit_exp_decl( Chuck_Emitter * emit, a_Exp_Decl decl, · 609 unmodified lines
4126 is_ref = ( var_decl->array->exp_list == NULL );4148 is_ref = ( var_decl->array->exp_list == NULL );
4127 // ...and only instantiate if NOT empty4149 // ...and only instantiate if NOT empty
4128 // REFACTOR-2017 TODO: do we want to4150 // REFACTOR-2017 TODO: do we want to
4129 // avoid doing this if the array is global?4151 // avoid doing this if the array is global?
4130 if( !is_ref )4152 if( !is_ref )
4131 {4153 {
4132 // set4154 // set
@@ -4795,13 +4817,22 @@ t_CKBOOL emit_engine_emit_spork( Chuck_Emitter * emit, a_Exp_Func_Call exp ) · 662 unmodified lines
4795 emit->append( op );4817 emit->append( op );
4796 4818
4797 // call the func on sporkee shred4819 // call the func on sporkee shred
4798 if( !emit_engine_emit_exp_func_call(4820 if( !emit_engine_emit_exp_func_call( emit,
4799 emit,4821 exp->ck_func,
4800 exp->ck_func,4822 exp->args,
4801 exp->ret_type,4823 exp->ret_type,
4802 exp->linepos,4824 exp->linepos,
4803 TRUE ) )4825 TRUE ) ) return FALSE;
4804 return FALSE;4826
4827 // 1.4.2.1 (ge) | added to pop/release the returned value, which could be an object
4828 if( iskindofint(emit->env, exp->ret_type) )
4829 {
4830 // is an object?
4831 if( isobj( emit->env, exp->ret_type) )
4832 { emit->append( new Chuck_Instr_Release_Object3_Pop_Word ); }
4833 else // not an object
4834 { emit->append( new Chuck_Instr_Reg_Pop_Word ); }
4835 }
4805 4836
4806 // emit the function call, with special flag4837 // emit the function call, with special flag
4807 // if( !emit_engine_emit_exp_func_call( emit, exp, TRUE ) )4838 // if( !emit_engine_emit_exp_func_call( emit, exp, TRUE ) )
@@ -5087,6 +5118,50 @@ void Chuck_Emitter::addref_on_scope() · 279 unmodified lines
5087 5118
5088 5119
5089 5120
5121//-----------------------------------------------------------------------------
5122// name: traverse_scope_on_jump() | 1.4.2.1 (ge) added
5123// desc: traverse the scope and emit instructions on a jump statement:
5124// 'return', 'break', 'continue'
5125// this is done to ensure proper cleanup of objects on scope frames
5126//-----------------------------------------------------------------------------
5127void Chuck_Emitter::traverse_scope_on_jump( )
5128{
5129 // this gotta be the case
5130 assert( code != NULL );
5131
5132 // clear locals
5133 locals.clear();
5134 // get locals (localOnly=false to get all locals at this point in 'code')
5135 code->frame->get_scope( locals, false );
5136
5137 // loop over
5138 for( int i = 0; i < locals.size(); i++ )
5139 {
5140 // get local
5141 Chuck_Local * local = locals[i];
5142 // skip scope boundary (denoted by NULL)
5143 if( !local ) continue;
5144
5145 // CK_STDCERR << "local: " << local->offset << " " << local->is_obj << CK_STDENDL;
5146 // check to see if it's an object
5147 if( local->is_obj )
5148 {
5149 // (REFACTOR-2017: don't release global objects)
5150 if( !local->is_global )
5151 {
5152 // emit instruction to release the object
5153 this->append( new Chuck_Instr_Release_Object2( local->offset ) );
5154 }
5155 }
5156 }
5157
5158 // clear it
5159 locals.clear();
5160}
5161
5162
5163
5164
5090//-----------------------------------------------------------------------------5165//-----------------------------------------------------------------------------
5091// name: pop_scope()5166// name: pop_scope()
5092// desc: ...5167// desc: ...
src/core/chuck_emit.h+3−1
@@ -148,7 +148,9 @@ struct Chuck_Emitter : public Chuck_VM_Object · 147 unmodified lines
148 // add references to locals on current scope (added 1.3.0.0)148 // add references to locals on current scope (added 1.3.0.0)
149 void addref_on_scope();149 void addref_on_scope();
150 // pop scope150 // pop scope
151 void pop_scope( );151 void pop_scope();
152 // traverse scope on jumps such as 'return' 'break' 'continue' | 1.4.2.1 (ge)
153 void traverse_scope_on_jump();
152 154
153 // default durations155 // default durations
154 t_CKBOOL find_dur( const std::string & name, t_CKDUR * out );156 t_CKBOOL find_dur( const std::string & name, t_CKDUR * out );
src/core/chuck_frame.cpp+7−2
@@ -100,7 +100,7 @@ void Chuck_Frame::push_scope( ) · 99 unmodified lines
100// name: get_scope()100// name: get_scope()
101// desc: get current scope (added 1.3.0.0)101// desc: get current scope (added 1.3.0.0)
102//-----------------------------------------------------------------------------102//-----------------------------------------------------------------------------
103void Chuck_Frame::get_scope( vector<Chuck_Local *> & out ) const103void Chuck_Frame::get_scope( vector<Chuck_Local *> & out, bool localOnly ) const
104{104{
105 // sanity105 // sanity
106 assert( this->stack.size() > 0 );106 assert( this->stack.size() > 0 );
@@ -111,8 +111,13 @@ void Chuck_Frame::get_scope( vector<Chuck_Local *> & out ) const · 4 unmodified lines
111 t_CKINT index = this->stack.size() - 1;111 t_CKINT index = this->stack.size() - 1;
112 112
113 // loop113 // loop
114 while( index >= 0 && this->stack[index] != NULL )114 while( index >= 0 )
115 {115 {
116 // did we hit a stack boundary (delineated by NULL)
117 // localOnly option added 1.4.2.1 (ge) -- to get all scope in the frame
118 if( localOnly && this->stack[index] != NULL )
119 break;
120
116 // last thing121 // last thing
117 local = stack[index];122 local = stack[index];
118 // move123 // move
src/core/chuck_frame.h+1−1
@@ -92,7 +92,7 @@ public: · 91 unmodified lines
92 Chuck_Local * alloc_local( t_CKUINT size, const std::string & name,92 Chuck_Local * alloc_local( t_CKUINT size, const std::string & name,
93 t_CKBOOL is_ref, t_CKBOOL is_obj, t_CKBOOL is_global );93 t_CKBOOL is_ref, t_CKBOOL is_obj, t_CKBOOL is_global );
94 // get the current scope (added 1.3.0.0)94 // get the current scope (added 1.3.0.0)
95 void get_scope( std::vector<Chuck_Local *> & out ) const;95 void get_scope( std::vector<Chuck_Local *> & out, bool localOnly = true ) const;
96 // pop scope96 // pop scope
97 void pop_scope( std::vector<Chuck_Local *> & out );97 void pop_scope( std::vector<Chuck_Local *> & out );
98};98};
src/core/chuck_instr.cpp+197−12
@@ -3777,7 +3777,7 @@ error: · 3776 unmodified lines
3777 3777
3778 3778
3779static Chuck_Instr_Func_Call g_func_call;3779static Chuck_Instr_Func_Call g_func_call;
3780static Chuck_Instr_Func_Call_Member g_func_call_member( 0 );3780static Chuck_Instr_Func_Call_Member g_func_call_member( 0, NULL );
3781//-----------------------------------------------------------------------------3781//-----------------------------------------------------------------------------
3782// name: call_pre_constructor()3782// name: call_pre_constructor()
3783// desc: ...3783// desc: ...
@@ -3797,6 +3797,10 @@ inline void call_pre_constructor( Chuck_VM * vm, Chuck_VM_Shred * shred, · 13 unmodified lines
3797 // push the stack offset3797 // push the stack offset
3798 push_( reg_sp, stack_offset );3798 push_( reg_sp, stack_offset );
3799 3799
3800 // NOTE (1.4.2.1): pre-constructors by their nature have no arguments...
3801 // if they did, they would need to clean up argument list, in the built-in/native
3802 // func case, by setting g_func_call_member.m_func_ref with the appropriate func
3803
3800 // call the function3804 // call the function
3801 if( pre_ctor->native_func != 0 )3805 if( pre_ctor->native_func != 0 )
3802 g_func_call_member.execute( vm, shred );3806 g_func_call_member.execute( vm, shred );
@@ -4399,11 +4403,16 @@ void Chuck_Instr_AddRef_Object2::execute( Chuck_VM * vm, Chuck_VM_Shred * shred · 596 unmodified lines
4399 4403
4400//-----------------------------------------------------------------------------4404//-----------------------------------------------------------------------------
4401// name: execute()4405// name: execute()
4402// desc: add one reference on object (added 1.3.0.0)4406// desc: ref-count increment the top of the register stack (added 1.3.0.0)
4407// 1.4.2.1 (ge) additional notes...
4408// this is used to keep objects referenced while on stack;
4409// relevant for cases like `return obj;` where obj may need to
4410// released for the local stack AND need to be kept on the stack
4411// to be return; in this case, we need this additional add_ref();
4412// releasing obj from stack is responsibility of the caller
4403//-----------------------------------------------------------------------------4413//-----------------------------------------------------------------------------
4404void Chuck_Instr_Reg_AddRef_Object3::execute( Chuck_VM * vm, Chuck_VM_Shred * shred )4414void Chuck_Instr_Reg_AddRef_Object3::execute( Chuck_VM * vm, Chuck_VM_Shred * shred )
4405{4415{
4406 // ISSUE: 64-bit?
4407 // NOTE: this pointer is NOT a reference pointer4416 // NOTE: this pointer is NOT a reference pointer
4408 t_CKUINT * reg_sp = (t_CKUINT *&)shred->reg->sp;4417 t_CKUINT * reg_sp = (t_CKUINT *&)shred->reg->sp;
4409 Chuck_VM_Object * obj = NULL;4418 Chuck_VM_Object * obj = NULL;
@@ -4415,7 +4424,7 @@ void Chuck_Instr_Reg_AddRef_Object3::execute( Chuck_VM * vm, Chuck_VM_Shred * sh · 5 unmodified lines
4415 // ge (2012 april): check for NULL (added 1.3.0.0)4424 // ge (2012 april): check for NULL (added 1.3.0.0)
4416 if( obj != NULL )4425 if( obj != NULL )
4417 {4426 {
4418 // release4427 // add reference
4419 obj->add_ref();4428 obj->add_ref();
4420 }4429 }
4421}4430}
@@ -4470,13 +4479,70 @@ void Chuck_Instr_Release_Object2::execute( Chuck_VM * vm, Chuck_VM_Shred * shred · 48 unmodified lines
4470 4479
4471 4480
4472 4481
4482
4483//-----------------------------------------------------------------------------
4484// name: execute()
4485// desc: release object reference + pop from reg stack | 1.4.2.1 (ge) added
4486// the variant assumes object pointer directly on stack (not offset)
4487// used to release returned object pointer after a function call;
4488// FYI the return value is conveyed on the reg stack; this undoes
4489// the addref before the return; see Chuck_Instr_Reg_AddRef_Object3
4490//-----------------------------------------------------------------------------
4491void Chuck_Instr_Release_Object3_Pop_Word::execute( Chuck_VM * vm, Chuck_VM_Shred * shred )
4492{
4493 t_CKUINT *& reg_sp = (t_CKUINT *&)shred->reg->sp;
4494 Chuck_VM_Object * obj = NULL;
4495
4496 // pop
4497 pop_( reg_sp, 1 );
4498 // copy popped value into mem stack
4499 obj = *( (Chuck_VM_Object **)(reg_sp) );
4500 // ge (2012 april): check for NULL (added 1.3.0.0)
4501 if( obj != NULL )
4502 {
4503 // release
4504 obj->release();
4505 }
4506}
4507
4508
4509
4510
4511//-----------------------------------------------------------------------------
4512// name: execute()
4513// desc: release object reference from reg stack | 1.4.2.1 (ge) added
4514// the variant assumes object pointer directly on stack (not offset)
4515// used to release objects on function arguments, specifically for
4516// built-in / imported (chugins) functions; code-defined functions
4517// do their own argument cleanup
4518//-----------------------------------------------------------------------------
4519void Chuck_Instr_Release_Object4::execute( Chuck_VM * vm, Chuck_VM_Shred * shred )
4520{
4521 // NOTE: this pointer is NOT a reference pointer
4522 t_CKBYTE * mem_sp = (t_CKBYTE *&)shred->mem->sp;
4523 Chuck_VM_Object * obj = NULL;
4524
4525 // move it
4526 mem_sp += m_val;
4527 // copy popped value into mem stack
4528 obj = *( (Chuck_VM_Object **)(mem_sp) );
4529 if( obj != NULL )
4530 {
4531 // release
4532 obj->release();
4533 }
4534}
4535
4536
4537
4538
4473#pragma mark === Function Calls ===4539#pragma mark === Function Calls ===
4474 4540
4475 4541
4476 4542
4477//-----------------------------------------------------------------------------4543//-----------------------------------------------------------------------------
4478// name: execute()4544// name: execute()
4479// desc: ...4545// desc: converts, in place on operand stack, a Func to its Code (instructions)
4480//-----------------------------------------------------------------------------4546//-----------------------------------------------------------------------------
4481void Chuck_Instr_Func_To_Code::execute( Chuck_VM * vm, Chuck_VM_Shred * shred )4547void Chuck_Instr_Func_To_Code::execute( Chuck_VM * vm, Chuck_VM_Shred * shred )
4482{4548{
@@ -4494,6 +4560,57 @@ void Chuck_Instr_Func_To_Code::execute( Chuck_VM * vm, Chuck_VM_Shred * shred ) · 11 unmodified lines
4494 4560
4495 4561
4496 4562
4563//-----------------------------------------------------------------------------
4564// name: func_release_args() | 1.4.2.1 (ge) added
4565// desc: helper function to release objects an function arg list
4566// input: VM, args list, mem stack pointer
4567// context: this is designed for builtin/imported functions
4568// functions defined in chuck code do their own arg list cleanup
4569//-----------------------------------------------------------------------------
4570t_CKBOOL func_release_args( Chuck_VM * vm, a_Arg_List args, t_CKUINT * mem_sp )
4571{
4572 // keep track of offset
4573 t_CKUINT offset = 0;
4574 // the type in question
4575 Chuck_Type * type = NULL;
4576 // object pointer
4577 Chuck_VM_Object * object = NULL;
4578
4579 // loop over
4580 while( args )
4581 {
4582 // get the type
4583 type = args->type;
4584 // check we have one!
4585 if( type != NULL )
4586 {
4587 // is an object?
4588 if( isobj( vm->env(), args->type) )
4589 {
4590 // get the object pointer
4591 object = (Chuck_VM_Object *)(*(mem_sp+offset));
4592 // check
4593 if( object != NULL )
4594 {
4595 // release it
4596 object->release();
4597 }
4598 }
4599
4600 // advance offset
4601 offset += args->type->size;
4602 }
4603
4604 // go
4605 args = args->next;
4606 }
4607
4608 return TRUE;
4609}
4610
4611
4612
4613
4497//-----------------------------------------------------------------------------4614//-----------------------------------------------------------------------------
4498// name: execute()4615// name: execute()
4499// desc: ...4616// desc: ...
@@ -4648,6 +4765,16 @@ void Chuck_Instr_Func_Call_Member::execute( Chuck_VM * vm, Chuck_VM_Shred * shre · 148 unmodified lines
4648 // call the function (added 1.3.0.0 -- Chuck_DL_Api::Api::instance())4765 // call the function (added 1.3.0.0 -- Chuck_DL_Api::Api::instance())
4649 f( (Chuck_Object *)(*mem_sp), mem_sp + 1, &retval, vm, shred, Chuck_DL_Api::Api::instance() );4766 f( (Chuck_Object *)(*mem_sp), mem_sp + 1, &retval, vm, shred, Chuck_DL_Api::Api::instance() );
4650 }4767 }
4768
4769 // if we have a func def | 1.4.2.1 (ge) added
4770 if( m_func_ref != NULL )
4771 {
4772 // cleanup / release objects on the arg list
4773 // context: this should be done here for builtin/import functions
4774 // user-defined functions do their own arg list cleanup
4775 func_release_args( vm, m_func_ref->def->arg_list, mem_sp+1 );
4776 }
4777
4651 // pop (TODO: check if this is right)4778 // pop (TODO: check if this is right)
4652 mem_sp -= push;4779 mem_sp -= push;
4653 4780
@@ -4657,6 +4784,25 @@ void Chuck_Instr_Func_Call_Member::execute( Chuck_VM * vm, Chuck_VM_Shred * shre · 3 unmodified lines
4657 {4784 {
4658 // push the return args4785 // push the return args
4659 push_( reg_sp, retval.v_uint );4786 push_( reg_sp, retval.v_uint );
4787
4788 // 1.4.2.1 (ge) | added -- ensure ref count
4789 if( m_func_ref && isobj(vm->env(), m_func_ref->def->ret_type) )
4790 {
4791 Chuck_VM_Object * obj = (Chuck_VM_Object *) retval.v_uint;
4792 if( obj )
4793 {
4794 // check if refcount is 0
4795 if( obj->m_ref_count == 0 )
4796 {
4797 EM_log( CK_LOG_FINE, "%s(...) returned object with refcount==0", S_name(m_func_ref->def->name) );
4798 EM_pushlog();
4799 EM_log( CK_LOG_FINE, "auto-incrementing object refcount to 1..." );
4800 EM_poplog();
4801 }
4802 // always add reference to returned objects (should release outside)
4803 obj->add_ref();
4804 }
4805 }
4660 }4806 }
4661 else if( m_val == kindof_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)4807 else if( m_val == kindof_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)
4662 {4808 {
@@ -4755,7 +4901,15 @@ void Chuck_Instr_Func_Call_Static::execute( Chuck_VM * vm, Chuck_VM_Shred * shre · 92 unmodified lines
4755 // (added 1.3.0.0 -- Chuck_DL_Api::Api::instance())4901 // (added 1.3.0.0 -- Chuck_DL_Api::Api::instance())
4756 // (added 1.4.1.0 -- base_type)4902 // (added 1.4.1.0 -- base_type)
4757 f( (Chuck_Type *)(*mem_sp), mem_sp+1, &retval, vm, shred, Chuck_DL_Api::Api::instance() );4903 f( (Chuck_Type *)(*mem_sp), mem_sp+1, &retval, vm, shred, Chuck_DL_Api::Api::instance() );
4758 // clean up memory stack4904 // if we have a func def | 1.4.2.1 (ge) added
4905 if( m_func_ref != NULL )
4906 {
4907 // cleanup / release objects on the arg list
4908 // context: this should be done here for builtin/import functions
4909 // user-defined functions do their own arg list cleanup
4910 func_release_args( vm, m_func_ref->def->arg_list, mem_sp+1 );
4911 }
4912 // pop memory stack pointer
4759 mem_sp -= push;4913 mem_sp -= push;
4760 4914
4761 // push the return4915 // push the return
@@ -4764,6 +4918,26 @@ void Chuck_Instr_Func_Call_Static::execute( Chuck_VM * vm, Chuck_VM_Shred * shre · 2 unmodified lines
4764 {4918 {
4765 // push the return args4919 // push the return args
4766 push_( reg_sp, retval.v_uint );4920 push_( reg_sp, retval.v_uint );
4921
4922 // 1.4.2.1 (ge) | added -- ensure ref count
4923 if( m_func_ref && isobj(vm->env(), m_func_ref->def->ret_type) )
4924 {
4925 // get as object pointer
4926 Chuck_VM_Object * obj = (Chuck_VM_Object *) retval.v_uint;
4927 if( obj )
4928 {
4929 // check if refcount is 0
4930 if( obj->m_ref_count == 0 )
4931 {
4932 EM_log( CK_LOG_FINE, "%s(...) returned object with refcount==0", S_name(m_func_ref->def->name) );
4933 EM_pushlog();
4934 EM_log( CK_LOG_FINE, "auto-incrementing object refcount to 1..." );
4935 EM_poplog();
4936 }
4937 // always add reference to returned objects (should release outside)
4938 obj->add_ref();
4939 }
4940 }
4767 }4941 }
4768 else if( m_val == kindof_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)4942 else if( m_val == kindof_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)
4769 {4943 {
@@ -7461,17 +7635,27 @@ void Chuck_Instr_Hack::execute( Chuck_VM * vm, Chuck_VM_Shred * shred ) · 2691 unmodified lines
7461 if( m_type_ref->size == sz_INT && iskindofint(vm->env(), m_type_ref) ) // ISSUE: 64-bit (fixed 1.3.1.0)7635 if( m_type_ref->size == sz_INT && iskindofint(vm->env(), m_type_ref) ) // ISSUE: 64-bit (fixed 1.3.1.0)
7462 {7636 {
7463 t_CKINT * sp = (t_CKINT *)shred->reg->sp;7637 t_CKINT * sp = (t_CKINT *)shred->reg->sp;
7464 if( !isa( m_type_ref, vm->env()->t_string ) || *(sp-1) == 0 )7638 Chuck_Object * obj = ((Chuck_Object *)*(sp-1));
7639 if( !isa( m_type_ref, vm->env()->t_string ) || *(sp-1) == 0 )
7465 {7640 {
7466 // print it7641 // print it
7467 if( *(sp-1) == 0 && isa( m_type_ref, vm->env()->t_object ) )7642 if( isa( m_type_ref, vm->env()->t_object ) )
7468 CK_FPRINTF_STDERR( "null :(%s)\n", m_type_ref->c_name() );7643 {
7644 if( obj == NULL )
7645 {
7646 CK_FPRINTF_STDERR( "null :(%s)\n", m_type_ref->c_name() );
7647 }
7648 else
7649 {
7650 CK_FPRINTF_STDERR( "0x%lx :(%s|refcount=%d)\n", *(sp-1), m_type_ref->c_name(), obj->m_ref_count );
7651 }
7652 }
7469 else7653 else
7470 CK_FPRINTF_STDERR( "%ld :(%s)\n", *(sp-1), m_type_ref->c_name() );7654 CK_FPRINTF_STDERR( "%d :(%s)\n", *(sp-1), m_type_ref->c_name() );
7471 }7655 }
7472 else7656 else
7473 {7657 {
7474 CK_FPRINTF_STDERR( "\"%s\" : (%s)\n", ((Chuck_String *)*(sp-1))->str().c_str(), m_type_ref->c_name() );7658 CK_FPRINTF_STDERR( "\"%s\" :(%s)\n", ((Chuck_String *)obj)->str().c_str(), m_type_ref->c_name() );
7475 }7659 }
7476 }7660 }
7477 else if( m_type_ref->size == sz_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)7661 else if( m_type_ref->size == sz_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0)
@@ -7593,11 +7777,12 @@ void Chuck_Instr_Gack::execute( Chuck_VM * vm, Chuck_VM_Shred * shred ) · 115 unmodified lines
7593 {7777 {
7594 if( isa( type, vm->env()->t_object ) )7778 if( isa( type, vm->env()->t_object ) )
7595 {7779 {
7780 Chuck_Object * obj = ((Chuck_Object *)(*sp));
7596 // print it7781 // print it
7597 if( *(sp) == 0 )7782 if( *(sp) == 0 )
7598 CK_FPRINTF_STDERR( "null " );7783 CK_FPRINTF_STDERR( "null " );
7599 else7784 else
7600 CK_FPRINTF_STDERR( "0x%lx ", *(sp) );7785 CK_FPRINTF_STDERR( "0x%lx (refcount=%d)", *(sp), obj->m_ref_count );
7601 }7786 }
7602 else7787 else
7603 {7788 {
src/core/chuck_instr.h+44−5
@@ -2977,6 +2977,7 @@ public: · 2976 unmodified lines
2977//-----------------------------------------------------------------------------2977//-----------------------------------------------------------------------------
2978// name: struct Chuck_Instr_Reg_AddRef_Object32978// name: struct Chuck_Instr_Reg_AddRef_Object3
2979// desc: added 1.3.0.0 -- does the ref add in-place2979// desc: added 1.3.0.0 -- does the ref add in-place
2980// operates on top of the register stack
2980//-----------------------------------------------------------------------------2981//-----------------------------------------------------------------------------
2981struct Chuck_Instr_Reg_AddRef_Object3 : public Chuck_Instr2982struct Chuck_Instr_Reg_AddRef_Object3 : public Chuck_Instr
2982{2983{
@@ -2989,7 +2990,7 @@ public: · 6 unmodified lines
2989 2990
2990//-----------------------------------------------------------------------------2991//-----------------------------------------------------------------------------
2991// name: struct Chuck_Instr_Release_Object2992// name: struct Chuck_Instr_Release_Object
2992// desc: ...2993// desc: release object on stack by its offset
2993//-----------------------------------------------------------------------------2994//-----------------------------------------------------------------------------
2994struct Chuck_Instr_Release_Object : public Chuck_Instr2995struct Chuck_Instr_Release_Object : public Chuck_Instr
2995{2996{
@@ -3018,6 +3019,38 @@ public: · 22 unmodified lines
3018 3019
3019 3020
3020 3021
3022//-----------------------------------------------------------------------------
3023// name: struct Chuck_Instr_Release_Object3_Pop_Word
3024// desc: release object reference + pop from reg stack | 1.4.2.1 (ge) added
3025// the variant assumes object pointer directly on stack (not offset)
3026//-----------------------------------------------------------------------------
3027struct Chuck_Instr_Release_Object3_Pop_Word : public Chuck_Instr
3028{
3029public:
3030 virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred );
3031};
3032
3033
3034
3035
3036//-----------------------------------------------------------------------------
3037// name: struct Chuck_Instr_Release_Object4
3038// desc: release object reference from reg stack (no pop) | 1.4.2.1 (ge) added
3039// the variant assumes object pointer directly on stack (not offset)
3040//-----------------------------------------------------------------------------
3041struct Chuck_Instr_Release_Object4 : public Chuck_Instr_Unary_Op
3042{
3043public:
3044 Chuck_Instr_Release_Object4( t_CKUINT offset )
3045 { this->set( offset ); }
3046
3047public:
3048 virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred );
3049};
3050
3051
3052
3053
3021//-----------------------------------------------------------------------------3054//-----------------------------------------------------------------------------
3022// name: struct Chuck_Instr_Func_To_Code3055// name: struct Chuck_Instr_Func_To_Code
3023// desc: Chuck_Func * to Chuck_VM_Code *3056// desc: Chuck_Func * to Chuck_VM_Code *
@@ -3051,11 +3084,14 @@ public: · 27 unmodified lines
3051struct Chuck_Instr_Func_Call_Member : public Chuck_Instr_Unary_Op3084struct Chuck_Instr_Func_Call_Member : public Chuck_Instr_Unary_Op
3052{3085{
3053public:3086public:
3054 Chuck_Instr_Func_Call_Member( t_CKUINT ret_size )3087 Chuck_Instr_Func_Call_Member( t_CKUINT ret_size, Chuck_Func * func_ref )
3055 { this->set( ret_size ); }3088 { this->set( ret_size ); m_func_ref = func_ref; }
3056 3089
3057public:3090public:
3058 virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred );3091 virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred );
3092
3093public:
3094 Chuck_Func * m_func_ref; // 1.4.2.1 (ge) | added for arg list cleanup
3059};3095};
3060 3096
3061 3097
@@ -3068,11 +3104,14 @@ public: · 6 unmodified lines
3068struct Chuck_Instr_Func_Call_Static : public Chuck_Instr_Unary_Op3104struct Chuck_Instr_Func_Call_Static : public Chuck_Instr_Unary_Op
3069{3105{
3070public:3106public:
3071 Chuck_Instr_Func_Call_Static( t_CKUINT ret_size )3107 Chuck_Instr_Func_Call_Static( t_CKUINT ret_size, Chuck_Func * func_ref )
3072 { this->set( ret_size ); }3108 { this->set( ret_size ); m_func_ref = func_ref; }
3073 3109
3074public:3110public:
3075 virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred );3111 virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred );
3112
3113public:
3114 Chuck_Func * m_func_ref; // 1.4.2.1 (ge) | added for arg list cleanup
3076};3115};
3077 3116
3078 3117
src/core/chuck_lang.cpp+6−1
@@ -1062,13 +1062,18 @@ CK_DLL_MFUN( object_toString ) · 1061 unmodified lines
1062 RETURN->v_object = NULL;1062 RETURN->v_object = NULL;
1063 return;1063 return;
1064 }1064 }
1065 // 1.4.2.1 (ge) assign to object
1066 OBJ_MEMBER_UINT(SELF, Object_offset_string) = (t_CKUINT)str;
1067 // 1.4.2.1 (ge) | add ref
1068 str->add_ref();
1069
1065 // set it1070 // set it
1066 ostringstream strout( ostringstream::out );1071 ostringstream strout( ostringstream::out );
1067 // get the type1072 // get the type
1068 Chuck_Type * type = SELF->type_ref;1073 Chuck_Type * type = SELF->type_ref;
1069 // write1074 // write
1070 strout.setf( ios::hex, ios::basefield );1075 strout.setf( ios::hex, ios::basefield );
1071 strout << ((type != NULL) ? type->c_name() : "[VOID]") << ":" << (t_CKUINT)SELF;1076 strout << ((type != NULL) ? type->c_name() : "[VOID]") << ":" << (t_CKUINT)SELF << " (refcount=" << SELF->m_ref_count << ")";
1072 strout.flush();1077 strout.flush();
1073 1078
1074 // done1079 // done
src/core/chuck_oo.cpp+11−2
@@ -125,8 +125,14 @@ void Chuck_VM_Object::add_ref() · 124 unmodified lines
125//-----------------------------------------------------------------------------125//-----------------------------------------------------------------------------
126void Chuck_VM_Object::release()126void Chuck_VM_Object::release()
127{127{
128 // make sure there is at least one reference128 // check
129 assert( m_ref_count > 0 );129 if( m_ref_count <= 0 )
130 {
131 // print error
132 EM_error3( "[chuck]: internal error: Object.release() refcount == %d", m_ref_count );
133 // make sure there is at least one reference
134 assert( m_ref_count > 0 );
135 }
130 // decrement136 // decrement
131 m_ref_count--;137 m_ref_count--;
132 138
@@ -148,6 +154,9 @@ void Chuck_VM_Object::release() · 15 unmodified lines
148 *(int *)0 = 1;154 *(int *)0 = 1;
149 }155 }
150 156
157 // log | 1.4.2.1 (ge) added
158 EM_log( CK_LOG_FINEST, "reclaiming %s: 0x%08x", typeid(*this).name(), this );
159
151 // tell the object manager to set this free160 // tell the object manager to set this free
152 // Chuck_VM_Alloc::instance()->free_object( this );161 // Chuck_VM_Alloc::instance()->free_object( this );
153 // REFACTOR-2017: doing this for now162 // REFACTOR-2017: doing this for now
src/core/chuck_parse.cpp+404−0
@@ -278,3 +278,407 @@ t_CKBOOL SyntaxQuery::parseLine( const std::string & line, SyntaxTokenList & tok · 277 unmodified lines
278 278
279 return TRUE;279 return TRUE;
280}280}
281
282
283
284
285
286//-----------------------------------------------------------------------------
287// absyn to string functions
288//-----------------------------------------------------------------------------
289#include "chuck_type.h"
290string absyn_exp2str( a_Exp exp, t_CKBOOL iterate = true );
291string absyn_binary2str( a_Exp_Binary binary );
292string absyn_unary2str( a_Exp_Unary unary );
293string absyn_op2str( ae_Operator op );
294string absyn_cast2str( a_Exp_Cast cast );
295string absyn_postfix2str( a_Exp_Postfix postfix );
296string absyn_dur2str( a_Exp_Dur dur );
297string absyn_primary2str( a_Exp_Primary primary );
298string absyn_array2str( a_Exp_Array array );
299string absyn_func_call2str( a_Exp_Func_Call func_call );
300string absyn_dot_member2str( a_Exp_Dot_Member dot_member );
301string absyn_exp_if2str( a_Exp_If exp_if );
302string absyn_decl2str( a_Exp_Decl decl );
303
304
305
306
307//-----------------------------------------------------------------------------
308// name: absyn2str()
309// desc: convert abstract syntax exp to string
310//-----------------------------------------------------------------------------
311string absyn2str( a_Exp exp )
312{
313 return absyn_exp2str( exp ) + ";";
314}
315
316
317
318
319//-----------------------------------------------------------------------------
320// name: absyn_exp2str()
321// desc: convert abstract syntax exp to string
322//-----------------------------------------------------------------------------
323string absyn_exp2str( a_Exp exp, t_CKBOOL iterate )
324{
325 string str = "";
326
327 // loop over
328 while( exp )
329 {
330 switch( exp->s_type )
331 {
332 case ae_exp_binary:
333 str += absyn_binary2str( &exp->binary );
334 break;
335
336 case ae_exp_unary:
337 str += absyn_unary2str( &exp->unary );
338 break;
339
340 case ae_exp_cast:
341 str += absyn_cast2str( &exp->cast );
342 break;
343
344 case ae_exp_postfix:
345 str += absyn_postfix2str( &exp->postfix );
346 break;
347
348 case ae_exp_dur:
349 str += absyn_dur2str( &exp->dur );
350 break;
351
352 case ae_exp_primary:
353 str += absyn_primary2str( &exp->primary );
354 break;
355
356 case ae_exp_array:
357 str += absyn_array2str( &exp->array );
358 break;
359
360 case ae_exp_func_call:
361 str += absyn_func_call2str( &exp->func_call );
362 break;
363
364 case ae_exp_dot_member:
365 str += absyn_dot_member2str( &exp->dot_member );
366 break;
367
368 case ae_exp_if:
369 str += absyn_exp_if2str( &exp->exp_if );
370 break;
371
372 case ae_exp_decl:
373 str += absyn_decl2str( &exp->decl );
374 break;
375
376 default:
377 return "";
378 }
379
380 // implicit cast
381 if( exp->cast_to != NULL )
382 break;
383
384 // break
385 if( !iterate ) break;
386
387 // next
388 exp = exp->next;
389 // if more
390 if( exp ) str += ", ";
391 }
392
393 return str;
394}
395
396
397
398
399//-----------------------------------------------------------------------------
400// name: absyn_op2str()
401// desc: convert abstract syntax operator to string
402//-----------------------------------------------------------------------------
403string absyn_op2str( ae_Operator op )
404{
405 string str;
406 // get operation string
407 switch( op )
408 {
409 case ae_op_plus: str = "+"; break;
410 case ae_op_plus_chuck: str = "+=>"; break;
411 case ae_op_minus: str = "-"; break;
412 case ae_op_minus_chuck: str = "-=>"; break;
413 case ae_op_times: str = "*"; break;
414 case ae_op_times_chuck: str = "*=>"; break;
415 case ae_op_divide: str = "/"; break;
416 case ae_op_divide_chuck: str = "/=>"; break;
417 case ae_op_s_or: str = "|"; break;
418 case ae_op_s_or_chuck: str = "|=>"; break;
419 case ae_op_s_and: str = "&"; break;
420 case ae_op_s_and_chuck: str = "&=>"; break;
421 case ae_op_shift_left: str = "<<"; break;
422 case ae_op_shift_left_chuck: str = "<<=>"; break;
423 case ae_op_shift_right: str = ">>"; break;
424 case ae_op_shift_right_chuck: str = ">>=>"; break;
425 case ae_op_percent: str = "%"; break;
426 case ae_op_percent_chuck: str = "%=>"; break;
427 case ae_op_s_xor: str = "^"; break;
428 case ae_op_s_xor_chuck: str = "^=>"; break;
429 case ae_op_chuck: str = "=>"; break;
430 case ae_op_unchuck: str = "=<"; break;
431 case ae_op_upchuck: str = "=^"; break;
432 case ae_op_at_chuck: str = "@=>"; break;
433 case ae_op_s_chuck: str = ""; break;
434 case ae_op_eq: str = "=="; break;
435 case ae_op_neq: str = "!="; break;
436 case ae_op_lt: str = "<"; break;
437 case ae_op_le: str = "<="; break;
438 case ae_op_gt: str = ">"; break;
439 case ae_op_ge: str = ">="; break;
440 case ae_op_and: str = "&&"; break;
441 case ae_op_or: str = "||"; break;
442 case ae_op_arrow_left: str = "<-"; break;
443 case ae_op_arrow_right: str = "->"; break;
444
445 // unary
446 case ae_op_plusplus: str = "++"; break;
447 case ae_op_minusminus: str = "--"; break;
448 case ae_op_tilda: str = "~"; break;
449 case ae_op_exclamation: str = "!"; break;
450 case ae_op_spork: str = "spork ~"; break;
451 case ae_op_new: str = "new"; break;
452
453 // not used
454 case ae_op_typeof: str = "typeof"; break;
455 case ae_op_sizeof: str = "sizeof"; break;
456 default: str = "[OP]"; break;
457 }
458 return str;
459}
460
461
462
463
464//-----------------------------------------------------------------------------
465// name: absyn_binary2str()
466// desc: convert abstract syntax binary to string
467//-----------------------------------------------------------------------------
468string absyn_binary2str( a_Exp_Binary binary )
469{
470 // (lhs OP rhs)
471 return "(" + absyn_exp2str(binary->lhs)
472 + absyn_op2str(binary->op)
473 + absyn_exp2str(binary->rhs) + ")";
474}
475
476
477
478
479//-----------------------------------------------------------------------------
480// name: absyn_unary2str()
481// desc: convert abstract syntax unary to string
482//-----------------------------------------------------------------------------
483string absyn_unary2str( a_Exp_Unary unary )
484{
485 return absyn_op2str(unary->op) + " " + absyn_exp2str(unary->exp);
486}
487
488
489
490
491//-----------------------------------------------------------------------------
492// name: absyn_cast2str()
493// desc: convert abstract syntax cast to string
494//-----------------------------------------------------------------------------
495string absyn_cast2str( a_Exp_Cast cast )
496{
497 Chuck_Type * to = cast->self->type;
498 return "$ " + to->name;
499}
500
501
502
503
504//-----------------------------------------------------------------------------
505// name: absyn_cast2str()
506// desc: convert abstract syntax cast to string
507//-----------------------------------------------------------------------------
508string absyn_postfix2str( a_Exp_Postfix postfix )
509{
510 return absyn_exp2str( postfix->exp ) + absyn_op2str( postfix->op );
511}
512
513
514
515
516//-----------------------------------------------------------------------------
517// name: absyn_dur2str()
518// desc: convert abstract syntax dur to string
519//-----------------------------------------------------------------------------
520string absyn_dur2str( a_Exp_Dur dur )
521{
522 return absyn_exp2str(dur->base) + "::" + absyn_exp2str(dur->unit);
523}
524
525
526
527
528//-----------------------------------------------------------------------------
529// name: absyn_primary2str()
530// desc: convert abstract syntax primary to string
531//-----------------------------------------------------------------------------
532string absyn_primary2str( a_Exp_Primary primary )
533{
534 string str;
535
536 // find out exp
537 switch( primary->s_type )
538 {
539 case ae_primary_var: str = S_name(primary->var); break;
540 case ae_primary_num: str = to_string(primary->num); break;
541 case ae_primary_float: str = primary->fnum; break;
542 case ae_primary_str: str = primary->str; break;
543 case ae_primary_char: str = primary->chr; break;
544 case ae_primary_array: str = "["+absyn_exp2str(primary->array->exp_list)+"]"; break;
545 case ae_primary_complex: str = "#("+absyn_exp2str(primary->complex->re)+")"; break;
546 case ae_primary_polar: str = "%("+absyn_exp2str(primary->polar->mod)+")"; break;
547 case ae_primary_vec: str = "@("+absyn_exp2str(primary->vec->args)+")"; break;
548 case ae_primary_exp: str = absyn_exp2str(primary->exp); break;
549 case ae_primary_hack: str = "<<< " + absyn_exp2str(primary->exp) + " >>>"; break;
550 case ae_primary_nil: str = "null"; break;
551 default: str ="[PRIMARY]"; break;
552 }
553
554 return str;
555}
556
557
558
559
560//-----------------------------------------------------------------------------
561// name: absyn_array2str()
562// desc: convert abstract syntax array to string
563//-----------------------------------------------------------------------------
564string absyn_array2str( a_Exp_Array array )
565{
566 string str;
567
568 t_CKUINT depth = 0;
569 a_Array_Sub sub = NULL;
570 t_CKBOOL is_str = FALSE;
571
572 // get the sub
573 sub = array->indices;
574 // expressions
575 a_Exp e = sub->exp_list;
576
577 // base of the array
578 str = absyn_exp2str(array->base);
579
580 // loop over
581 while( e )
582 {
583 // each index
584 str += "[" + absyn_exp2str(e,false) + "]";
585 // advance
586 e = e->next;
587 }
588
589 return str;
590}
591
592
593
594
595//-----------------------------------------------------------------------------
596// name: absyn_func_call2str()
597// desc: convert abstract syntax func_call to string
598//-----------------------------------------------------------------------------
599string absyn_func_call2str( a_Exp_Func_Call func_call )
600{
601 string str;
602 // function name
603 str = absyn_exp2str( func_call->func );
604 // args
605 str += "(" + absyn_exp2str( func_call->args ) + ")";
606 // done
607 return str;
608}
609
610
611
612
613//-----------------------------------------------------------------------------
614// name: absyn_dot_member2str()
615// desc: convert abstract syntax dot_member to string
616//-----------------------------------------------------------------------------
617string absyn_dot_member2str( a_Exp_Dot_Member dot_member )
618{
619 return absyn_exp2str(dot_member->base) + "." + S_name(dot_member->xid);
620}
621
622
623
624
625//-----------------------------------------------------------------------------
626// name: absyn_exp_if2str()
627// desc: convert abstract syntax exp_if to string
628//-----------------------------------------------------------------------------
629string absyn_exp_if2str( a_Exp_If exp_if )
630{
631 return "("+absyn_exp2str(exp_if->cond) + "?" + absyn_exp2str(exp_if->if_exp)
632 + ":" + absyn_exp2str(exp_if->else_exp)+")";
633}
634
635
636
637
638//-----------------------------------------------------------------------------
639// name: absyn_decl2str()
640// desc: convert abstract syntax decl to string
641//-----------------------------------------------------------------------------
642string absyn_decl2str( a_Exp_Decl decl )
643{
644 a_Var_Decl_List list = decl->var_decl_list;
645 string str;
646 a_Exp e = NULL;
647
648 if( decl->is_global ) str += "global ";
649 else if( decl->is_static ) str += "static ";
650
651 while( list )
652 {
653 // type
654 str += list->var_decl->value->type->name + " " + (decl->type->ref ? "@" : "") + list->var_decl->value->name;
655 // array?
656 if( list->var_decl->array )
657 {
658 e = list->var_decl->array->exp_list;
659 if( e )
660 {
661 // loop over
662 while( e )
663 {
664 // each index
665 str += "[" + absyn_exp2str(e,false) + "]";
666 // advance
667 e = e->next;
668 }
669 }
670 else
671 {
672 for( t_CKINT i = 0; i < list->var_decl->value->type->array_depth; i++ )
673 {
674 str += "[]";
675 }
676 }
677 }
678
679 list = list->next;
680 if( list ) str += ",";
681 }
682
683 return str;
684}
src/core/chuck_parse.h+2−0
@@ -63,6 +63,8 @@ t_CKBOOL chuck_parse( c_constr fname, FILE * fd = NULL, c_constr code = NULL ); · 62 unmodified lines
63// reset the parser63// reset the parser
64void reset_parse( );64void reset_parse( );
65 65
66// convert abstract syntax expression to string
67std::string absyn2str( a_Exp exp );
66 68
67// syntax highlighting tools69// syntax highlighting tools
68#include <vector>70#include <vector>
src/core/ulib_machine.cpp+34−2
@@ -40,6 +40,25 @@ · 39 unmodified lines
40#include <string>40#include <string>
41using namespace std;41using namespace std;
42 42
43// exports
44CK_DLL_SFUN( machine_crash_impl );
45CK_DLL_SFUN( machine_add_impl );
46CK_DLL_SFUN( machine_spork_impl );
47CK_DLL_SFUN( machine_remove_impl );
48CK_DLL_SFUN( machine_replace_impl );
49CK_DLL_SFUN( machine_status_impl );
50CK_DLL_SFUN( machine_intsize_impl );
51CK_DLL_SFUN( machine_shreds_impl );
52CK_DLL_SFUN( machine_realtime_impl );
53CK_DLL_SFUN( machine_silent_impl );
54CK_DLL_SFUN( machine_eval_impl );
55CK_DLL_SFUN( machine_eval2_impl );
56CK_DLL_SFUN( machine_eval3_impl );
57CK_DLL_SFUN( machine_version_impl );
58CK_DLL_SFUN( machine_setloglevel_impl );
59CK_DLL_SFUN( machine_getloglevel_impl );
60CK_DLL_SFUN( machine_refcount_impl);
61
43 62
44 63
45 64
@@ -154,7 +173,7 @@ DLL_QUERY machine_query( Chuck_DL_Query * QUERY ) · 108 unmodified lines
154 QUERY->add_sfun( QUERY, machine_version_impl, "string", "version" );173 QUERY->add_sfun( QUERY, machine_version_impl, "string", "version" );
155 QUERY->doc_func( QUERY, "return version string" );174 QUERY->doc_func( QUERY, "return version string" );
156 175
157 // get version string176 // get set loglevel
158 QUERY->add_sfun( QUERY, machine_setloglevel_impl, "int", "loglevel" );177 QUERY->add_sfun( QUERY, machine_setloglevel_impl, "int", "loglevel" );
159 QUERY->add_arg( QUERY, "int", "level" );178 QUERY->add_arg( QUERY, "int", "level" );
160 QUERY->doc_func( QUERY, "set log level\n"179 QUERY->doc_func( QUERY, "set log level\n"
@@ -170,10 +189,15 @@ DLL_QUERY machine_query( Chuck_DL_Query * QUERY ) · 9 unmodified lines
170 " |- 9: FINEST\n"189 " |- 9: FINEST\n"
171 " |- 10: ALL" );190 " |- 10: ALL" );
172 191
173 // get version string192 // get log level
174 QUERY->add_sfun( QUERY, machine_getloglevel_impl, "int", "loglevel" );193 QUERY->add_sfun( QUERY, machine_getloglevel_impl, "int", "loglevel" );
175 QUERY->doc_func( QUERY, "get log level." );194 QUERY->doc_func( QUERY, "get log level." );
176 195
196 // get reference count for any object
197 QUERY->add_sfun( QUERY, machine_refcount_impl, "int", "refcount" );
198 QUERY->add_arg( QUERY, "Object", "obj" );
199 QUERY->doc_func( QUERY, "get an object's current internal reference count; this is intended for testing or curiosity; NOTE: this function intentionally does not take into account any reference counting related to the calling of this function (normally all functions increments the reference count for objects passed as arguments and decrements upon returning)" );
200
177 // end class201 // end class
178 QUERY->end_class( QUERY );202 QUERY->end_class( QUERY );
179 203
@@ -399,3 +423,11 @@ CK_DLL_SFUN( machine_getloglevel_impl ) · 219 unmodified lines
399 // return423 // return
400 RETURN->v_int = VM->carrier()->chuck->getLogLevel();424 RETURN->v_int = VM->carrier()->chuck->getLogLevel();
401}425}
426
427CK_DLL_SFUN( machine_refcount_impl )
428{
429 // get the argument
430 Chuck_Object * obj = (Chuck_Object *)GET_NEXT_OBJECT(ARGS);
431 // return (-1 to account for the extra refcount as part of calling this function!)
432 RETURN->v_int = obj != NULL ? obj->m_ref_count-1 : 0;
433}
src/core/ulib_machine.h+1−17
@@ -53,23 +53,7 @@ t_CKBOOL machine_init( Chuck_Compiler * compiler, proc_msg_func func ); · 52 unmodified lines
53// machine exports53// machine exports
54t_CKUINT machine_intsize();54t_CKUINT machine_intsize();
55 55
56// exports56
57CK_DLL_SFUN( machine_crash_impl );
58CK_DLL_SFUN( machine_add_impl );
59CK_DLL_SFUN( machine_spork_impl );
60CK_DLL_SFUN( machine_remove_impl );
61CK_DLL_SFUN( machine_replace_impl );
62CK_DLL_SFUN( machine_status_impl );
63CK_DLL_SFUN( machine_intsize_impl );
64CK_DLL_SFUN( machine_shreds_impl );
65CK_DLL_SFUN( machine_realtime_impl );
66CK_DLL_SFUN( machine_silent_impl );
67CK_DLL_SFUN( machine_eval_impl );
68CK_DLL_SFUN( machine_eval2_impl );
69CK_DLL_SFUN( machine_eval3_impl );
70CK_DLL_SFUN( machine_version_impl );
71CK_DLL_SFUN( machine_setloglevel_impl );
72CK_DLL_SFUN( machine_getloglevel_impl );
73 57
74 58
75#endif59#endif
src/test/01-Basic/120.ck+20−0
@@ -0,0 +1,20 @@
1fun vec3 missingReturn()
2{
3 // missing return
4}
5
6fun vec3 hasReturn()
7{
8 return @(1,0,0);
9}
10
11// missing return statements default to 0 as appropriate
12// for return type; this tests that and that the stack
13// is okay afterwards, even for larger-than-int return types
14// like vec3
15<<< hasReturn(), missingReturn() >>>;
16
17// before the fix in 1.4.2.1, the above would incorrectly print
18// #(0.0000,0.0000,1.0000) #(0.0000,0.0000,0.0000)
19// this implies the stack pointer is off, due to missingReturn
20// not accounting for the size of its return type, vec3
src/test/01-Basic/120.txt+1−0
@@ -0,0 +1 @@
1#(1.0000,0.0000,0.0000) #(0.0000,0.0000,0.0000)
src/test/05-Global/01b.txt+1−1
@@ -1 +1 @@
1"success" : (string)1"success" :(string)
src/test/05-Global/102a.txt+3−3
@@ -1,5 +1,5 @@
1"no i'm foo" : (string)1"no i'm foo" :(string)
2[chuck](VM): sporking incoming shred: 2 (102b.ck)...2[chuck](VM): sporking incoming shred: 2 (102b.ck)...
3"no i'm foo" : (string)3"no i'm foo" :(string)
4"no i'm foo" : (string)4"no i'm foo" :(string)
53 :(int)53 :(int)
src/test/test.py+1−1
@@ -47,7 +47,7 @@ def run_test(exe, path, filename, attempt): · 46 unmodified lines
47 try:47 try:
48 result = subprocess.check_output([exe, "--silent", "%s" % path], stderr=subprocess.STDOUT).decode("utf-8")48 result = subprocess.check_output([exe, "--silent", "%s" % path], stderr=subprocess.STDOUT).decode("utf-8")
49 49
50 if result.strip().endswith(("\"success\" : (string)",)):50 if result.strip().endswith(("\"success\" :(string)",)):
51 successes += 151 successes += 1
52 52
53 else:53 else:

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t