Unified · Split
| @@ -35,6 +35,7 @@ · 34 unmodified lines | ||
| 35 | 35 | #include "chuck_errmsg.h" |
| 36 | 36 | #include "chuck_instr.h" |
| 37 | 37 | #include "chuck_globals.h" // added 1.4.1.0 |
| 38 | +#include "chuck_parse.h" // added 1.4.2.1 | |
| 38 | 39 | #include <sstream> |
| 39 | 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 | ||
| 73 | 74 | t_CKBOOL emit_engine_emit_exp_dur( Chuck_Emitter * emit, a_Exp_Dur dur ); |
| 74 | 75 | t_CKBOOL emit_engine_emit_exp_array( Chuck_Emitter * emit, a_Exp_Array array ); |
| 75 | 76 | t_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 ); | |
| 77 | 78 | t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, a_Exp_Func_Call func_call, |
| 78 | 79 | t_CKBOOL spork = FALSE ); |
| 79 | 80 | t_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 | 387 | ret = emit_engine_emit_exp( emit, stmt->stmt_exp ); |
| 387 | 388 | if( !ret ) |
| 388 | 389 | return FALSE; |
| 390 | + | |
| 391 | + // 1.4.2.1 | |
| 392 | + // cerr << absyn2str( stmt->stmt_exp ) << endl; | |
| 393 | + | |
| 389 | 394 | // need to pop the final value from stack |
| 390 | 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 | 403 | if( exp->s_type == ae_exp_primary && exp->primary.s_type == ae_primary_hack ) |
| 399 | 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 | 407 | while( exp ) |
| 403 | 408 | { |
| 404 | 409 | // if decl, then expect only one word per var |
| 405 | 410 | // added 1.3.1.0: iskindofint -- since on some 64-bit systems sz_INT == sz_FLOAT |
| 406 | 411 | if( exp->s_type == ae_exp_decl ) |
| 412 | + { | |
| 407 | 413 | // (added 1.3.1.0 -- multiply by type size; #64-bit) |
| 408 | 414 | // (fixed 1.3.1.2 -- uh... decl should also be int-sized, so changed to INT/WORD) |
| 409 | 415 | emit->append( new Chuck_Instr_Reg_Pop_Word4( exp->decl.num_var_decls * sz_INT / sz_WORD ) ); |
| 416 | + } | |
| 410 | 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 | 425 | else if( exp->type->size == sz_FLOAT ) // ISSUE: 64-bit (fixed 1.3.1.0) |
| 413 | 426 | emit->append( new Chuck_Instr_Reg_Pop_Word2 ); |
| 414 | 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 | //----------------------------------------------------------------------------- |
| 1292 | 1305 | t_CKBOOL emit_engine_emit_return( Chuck_Emitter * emit, a_Stmt_Return stmt ) |
| 1293 | 1306 | { |
| 1307 | + // emit the value | |
| 1294 | 1308 | if( !emit_engine_emit_exp( emit, stmt->val ) ) |
| 1295 | 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 | 1326 | // emit return |
| 1298 | 1327 | // emit->append( new Chuck_Instr_Func_Return ); |
| 1299 | − | |
| 1300 | 1328 | // determine where later |
| 1301 | 1329 | Chuck_Instr_Goto * instr = new Chuck_Instr_Goto( 0 ); |
| 1302 | 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 | 2565 | assert( binary->ck_func != NULL ); |
| 2538 | 2566 | |
| 2539 | 2567 | // 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 | 2571 | // 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 | //----------------------------------------------------------------------------- |
| 3402 | 3430 | t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, |
| 3403 | 3431 | Chuck_Func * func, |
| 3432 | + a_Exp args, | |
| 3404 | 3433 | Chuck_Type * type, |
| 3405 | 3434 | int linepos, |
| 3406 | 3435 | t_CKBOOL spork ) |
| @@ -3408,13 +3437,6 @@ t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, · 1 unmodified line | ||
| 3408 | 3437 | // is a member? |
| 3409 | 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 | 3440 | // translate to code |
| 3419 | 3441 | emit->append( new Chuck_Instr_Func_To_Code ); |
| 3420 | 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 | 3459 | // is member (1.3.1.0: changed to use kind instead of size) |
| 3438 | 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 | 3462 | 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 | 3465 | 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 | 3533 | // the rest |
| 3512 | − return emit_engine_emit_exp_func_call( emit, func_call->ck_func, func_call->ret_type, | |
| 3513 | − func_call->linepos, spork ); | |
| 3534 | + return emit_engine_emit_exp_func_call( emit, func_call->ck_func, func_call->args, | |
| 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 | 4148 | is_ref = ( var_decl->array->exp_list == NULL ); |
| 4127 | 4149 | // ...and only instantiate if NOT empty |
| 4128 | 4150 | // 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 | 4152 | if( !is_ref ) |
| 4131 | 4153 | { |
| 4132 | 4154 | // set |
| @@ -4795,13 +4817,22 @@ t_CKBOOL emit_engine_emit_spork( Chuck_Emitter * emit, a_Exp_Func_Call exp ) · 662 unmodified lines | ||
| 4795 | 4817 | emit->append( op ); |
| 4796 | 4818 | |
| 4797 | 4819 | // call the func on sporkee shred |
| 4798 | − if( !emit_engine_emit_exp_func_call( | |
| 4799 | − emit, | |
| 4800 | − exp->ck_func, | |
| 4801 | − exp->ret_type, | |
| 4802 | − exp->linepos, | |
| 4803 | − TRUE ) ) | |
| 4804 | − return FALSE; | |
| 4820 | + if( !emit_engine_emit_exp_func_call( emit, | |
| 4821 | + exp->ck_func, | |
| 4822 | + exp->args, | |
| 4823 | + exp->ret_type, | |
| 4824 | + exp->linepos, | |
| 4825 | + TRUE ) ) 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 | 4837 | // emit the function call, with special flag |
| 4807 | 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 | +//----------------------------------------------------------------------------- | |
| 5127 | +void 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 | 5166 | // name: pop_scope() |
| 5092 | 5167 | // desc: ... |
| @@ -148,7 +148,9 @@ struct Chuck_Emitter : public Chuck_VM_Object · 147 unmodified lines | ||
| 148 | 148 | // add references to locals on current scope (added 1.3.0.0) |
| 149 | 149 | void addref_on_scope(); |
| 150 | 150 | // 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 | 155 | // default durations |
| 154 | 156 | t_CKBOOL find_dur( const std::string & name, t_CKDUR * out ); |
| @@ -100,7 +100,7 @@ void Chuck_Frame::push_scope( ) · 99 unmodified lines | ||
| 100 | 100 | // name: get_scope() |
| 101 | 101 | // desc: get current scope (added 1.3.0.0) |
| 102 | 102 | //----------------------------------------------------------------------------- |
| 103 | −void Chuck_Frame::get_scope( vector<Chuck_Local *> & out ) const | |
| 103 | +void Chuck_Frame::get_scope( vector<Chuck_Local *> & out, bool localOnly ) const | |
| 104 | 104 | { |
| 105 | 105 | // sanity |
| 106 | 106 | assert( this->stack.size() > 0 ); |
| @@ -111,8 +111,13 @@ void Chuck_Frame::get_scope( vector<Chuck_Local *> & out ) const · 4 unmodified lines | ||
| 111 | 111 | t_CKINT index = this->stack.size() - 1; |
| 112 | 112 | |
| 113 | 113 | // 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 | 121 | // last thing |
| 117 | 122 | local = stack[index]; |
| 118 | 123 | // move |
| @@ -92,7 +92,7 @@ public: · 91 unmodified lines | ||
| 92 | 92 | Chuck_Local * alloc_local( t_CKUINT size, const std::string & name, |
| 93 | 93 | t_CKBOOL is_ref, t_CKBOOL is_obj, t_CKBOOL is_global ); |
| 94 | 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 | 96 | // pop scope |
| 97 | 97 | void pop_scope( std::vector<Chuck_Local *> & out ); |
| 98 | 98 | }; |
| @@ -3777,7 +3777,7 @@ error: · 3776 unmodified lines | ||
| 3777 | 3777 | |
| 3778 | 3778 | |
| 3779 | 3779 | static Chuck_Instr_Func_Call g_func_call; |
| 3780 | −static Chuck_Instr_Func_Call_Member g_func_call_member( 0 ); | |
| 3780 | +static Chuck_Instr_Func_Call_Member g_func_call_member( 0, NULL ); | |
| 3781 | 3781 | //----------------------------------------------------------------------------- |
| 3782 | 3782 | // name: call_pre_constructor() |
| 3783 | 3783 | // desc: ... |
| @@ -3797,6 +3797,10 @@ inline void call_pre_constructor( Chuck_VM * vm, Chuck_VM_Shred * shred, · 13 unmodified lines | ||
| 3797 | 3797 | // push the stack offset |
| 3798 | 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 | 3804 | // call the function |
| 3801 | 3805 | if( pre_ctor->native_func != 0 ) |
| 3802 | 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 | 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 | //----------------------------------------------------------------------------- |
| 4404 | 4414 | void Chuck_Instr_Reg_AddRef_Object3::execute( Chuck_VM * vm, Chuck_VM_Shred * shred ) |
| 4405 | 4415 | { |
| 4406 | − // ISSUE: 64-bit? | |
| 4407 | 4416 | // NOTE: this pointer is NOT a reference pointer |
| 4408 | 4417 | t_CKUINT * reg_sp = (t_CKUINT *&)shred->reg->sp; |
| 4409 | 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 | 4424 | // ge (2012 april): check for NULL (added 1.3.0.0) |
| 4416 | 4425 | if( obj != NULL ) |
| 4417 | 4426 | { |
| 4418 | − // release | |
| 4427 | + // add reference | |
| 4419 | 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 | +//----------------------------------------------------------------------------- | |
| 4491 | +void 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 | +//----------------------------------------------------------------------------- | |
| 4519 | +void 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 | 4539 | #pragma mark === Function Calls === |
| 4474 | 4540 | |
| 4475 | 4541 | |
| 4476 | 4542 | |
| 4477 | 4543 | //----------------------------------------------------------------------------- |
| 4478 | 4544 | // name: execute() |
| 4479 | −// desc: ... | |
| 4545 | +// desc: converts, in place on operand stack, a Func to its Code (instructions) | |
| 4480 | 4546 | //----------------------------------------------------------------------------- |
| 4481 | 4547 | void 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 | +//----------------------------------------------------------------------------- | |
| 4570 | +t_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 | 4615 | // name: execute() |
| 4499 | 4616 | // desc: ... |
| @@ -4648,6 +4765,16 @@ void Chuck_Instr_Func_Call_Member::execute( Chuck_VM * vm, Chuck_VM_Shred * shre · 148 unmodified lines | ||
| 4648 | 4765 | // call the function (added 1.3.0.0 -- Chuck_DL_Api::Api::instance()) |
| 4649 | 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 | 4778 | // pop (TODO: check if this is right) |
| 4652 | 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 | 4785 | // push the return args |
| 4659 | 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 | 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 | 4901 | // (added 1.3.0.0 -- Chuck_DL_Api::Api::instance()) |
| 4756 | 4902 | // (added 1.4.1.0 -- base_type) |
| 4757 | 4903 | f( (Chuck_Type *)(*mem_sp), mem_sp+1, &retval, vm, shred, Chuck_DL_Api::Api::instance() ); |
| 4758 | − // clean up memory stack | |
| 4904 | + // 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 | 4913 | mem_sp -= push; |
| 4760 | 4914 | |
| 4761 | 4915 | // 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 | 4919 | // push the return args |
| 4766 | 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 | 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 | 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 | 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 | 7641 | // print it |
| 7467 | − if( *(sp-1) == 0 && isa( m_type_ref, vm->env()->t_object ) ) | |
| 7468 | − CK_FPRINTF_STDERR( "null :(%s)\n", m_type_ref->c_name() ); | |
| 7642 | + if( isa( m_type_ref, vm->env()->t_object ) ) | |
| 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 | 7653 | 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 | 7656 | 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 | 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 | 7778 | if( isa( type, vm->env()->t_object ) ) |
| 7595 | 7779 | { |
| 7780 | + Chuck_Object * obj = ((Chuck_Object *)(*sp)); | |
| 7596 | 7781 | // print it |
| 7597 | 7782 | if( *(sp) == 0 ) |
| 7598 | 7783 | CK_FPRINTF_STDERR( "null " ); |
| 7599 | 7784 | else |
| 7600 | − CK_FPRINTF_STDERR( "0x%lx ", *(sp) ); | |
| 7785 | + CK_FPRINTF_STDERR( "0x%lx (refcount=%d)", *(sp), obj->m_ref_count ); | |
| 7601 | 7786 | } |
| 7602 | 7787 | else |
| 7603 | 7788 | { |
| @@ -2977,6 +2977,7 @@ public: · 2976 unmodified lines | ||
| 2977 | 2977 | //----------------------------------------------------------------------------- |
| 2978 | 2978 | // name: struct Chuck_Instr_Reg_AddRef_Object3 |
| 2979 | 2979 | // desc: added 1.3.0.0 -- does the ref add in-place |
| 2980 | +// operates on top of the register stack | |
| 2980 | 2981 | //----------------------------------------------------------------------------- |
| 2981 | 2982 | struct Chuck_Instr_Reg_AddRef_Object3 : public Chuck_Instr |
| 2982 | 2983 | { |
| @@ -2989,7 +2990,7 @@ public: · 6 unmodified lines | ||
| 2989 | 2990 | |
| 2990 | 2991 | //----------------------------------------------------------------------------- |
| 2991 | 2992 | // name: struct Chuck_Instr_Release_Object |
| 2992 | −// desc: ... | |
| 2993 | +// desc: release object on stack by its offset | |
| 2993 | 2994 | //----------------------------------------------------------------------------- |
| 2994 | 2995 | struct 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 | +//----------------------------------------------------------------------------- | |
| 3027 | +struct Chuck_Instr_Release_Object3_Pop_Word : public Chuck_Instr | |
| 3028 | +{ | |
| 3029 | +public: | |
| 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 | +//----------------------------------------------------------------------------- | |
| 3041 | +struct Chuck_Instr_Release_Object4 : public Chuck_Instr_Unary_Op | |
| 3042 | +{ | |
| 3043 | +public: | |
| 3044 | + Chuck_Instr_Release_Object4( t_CKUINT offset ) | |
| 3045 | + { this->set( offset ); } | |
| 3046 | + | |
| 3047 | +public: | |
| 3048 | + virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred ); | |
| 3049 | +}; | |
| 3050 | + | |
| 3051 | + | |
| 3052 | + | |
| 3053 | + | |
| 3021 | 3054 | //----------------------------------------------------------------------------- |
| 3022 | 3055 | // name: struct Chuck_Instr_Func_To_Code |
| 3023 | 3056 | // desc: Chuck_Func * to Chuck_VM_Code * |
| @@ -3051,11 +3084,14 @@ public: · 27 unmodified lines | ||
| 3051 | 3084 | struct Chuck_Instr_Func_Call_Member : public Chuck_Instr_Unary_Op |
| 3052 | 3085 | { |
| 3053 | 3086 | public: |
| 3054 | − Chuck_Instr_Func_Call_Member( t_CKUINT ret_size ) | |
| 3055 | − { this->set( ret_size ); } | |
| 3087 | + Chuck_Instr_Func_Call_Member( t_CKUINT ret_size, Chuck_Func * func_ref ) | |
| 3088 | + { this->set( ret_size ); m_func_ref = func_ref; } | |
| 3056 | 3089 | |
| 3057 | 3090 | public: |
| 3058 | 3091 | virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred ); |
| 3092 | + | |
| 3093 | +public: | |
| 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 | ||
| 3068 | 3104 | struct Chuck_Instr_Func_Call_Static : public Chuck_Instr_Unary_Op |
| 3069 | 3105 | { |
| 3070 | 3106 | public: |
| 3071 | − Chuck_Instr_Func_Call_Static( t_CKUINT ret_size ) | |
| 3072 | − { this->set( ret_size ); } | |
| 3107 | + Chuck_Instr_Func_Call_Static( t_CKUINT ret_size, Chuck_Func * func_ref ) | |
| 3108 | + { this->set( ret_size ); m_func_ref = func_ref; } | |
| 3073 | 3109 | |
| 3074 | 3110 | public: |
| 3075 | 3111 | virtual void execute( Chuck_VM * vm, Chuck_VM_Shred * shred ); |
| 3112 | + | |
| 3113 | +public: | |
| 3114 | + Chuck_Func * m_func_ref; // 1.4.2.1 (ge) | added for arg list cleanup | |
| 3076 | 3115 | }; |
| 3077 | 3116 | |
| 3078 | 3117 | |
| @@ -1062,13 +1062,18 @@ CK_DLL_MFUN( object_toString ) · 1061 unmodified lines | ||
| 1062 | 1062 | RETURN->v_object = NULL; |
| 1063 | 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 | 1070 | // set it |
| 1066 | 1071 | ostringstream strout( ostringstream::out ); |
| 1067 | 1072 | // get the type |
| 1068 | 1073 | Chuck_Type * type = SELF->type_ref; |
| 1069 | 1074 | // write |
| 1070 | 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 | 1077 | strout.flush(); |
| 1073 | 1078 | |
| 1074 | 1079 | // done |
| @@ -125,8 +125,14 @@ void Chuck_VM_Object::add_ref() · 124 unmodified lines | ||
| 125 | 125 | //----------------------------------------------------------------------------- |
| 126 | 126 | void Chuck_VM_Object::release() |
| 127 | 127 | { |
| 128 | − // make sure there is at least one reference | |
| 129 | − assert( m_ref_count > 0 ); | |
| 128 | + // check | |
| 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 | 136 | // decrement |
| 131 | 137 | m_ref_count--; |
| 132 | 138 | |
| @@ -148,6 +154,9 @@ void Chuck_VM_Object::release() · 15 unmodified lines | ||
| 148 | 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 | 160 | // tell the object manager to set this free |
| 152 | 161 | // Chuck_VM_Alloc::instance()->free_object( this ); |
| 153 | 162 | // REFACTOR-2017: doing this for now |
| @@ -278,3 +278,407 @@ t_CKBOOL SyntaxQuery::parseLine( const std::string & line, SyntaxTokenList & tok · 277 unmodified lines | ||
| 278 | 278 | |
| 279 | 279 | return TRUE; |
| 280 | 280 | } |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | +//----------------------------------------------------------------------------- | |
| 287 | +// absyn to string functions | |
| 288 | +//----------------------------------------------------------------------------- | |
| 289 | +#include "chuck_type.h" | |
| 290 | +string absyn_exp2str( a_Exp exp, t_CKBOOL iterate = true ); | |
| 291 | +string absyn_binary2str( a_Exp_Binary binary ); | |
| 292 | +string absyn_unary2str( a_Exp_Unary unary ); | |
| 293 | +string absyn_op2str( ae_Operator op ); | |
| 294 | +string absyn_cast2str( a_Exp_Cast cast ); | |
| 295 | +string absyn_postfix2str( a_Exp_Postfix postfix ); | |
| 296 | +string absyn_dur2str( a_Exp_Dur dur ); | |
| 297 | +string absyn_primary2str( a_Exp_Primary primary ); | |
| 298 | +string absyn_array2str( a_Exp_Array array ); | |
| 299 | +string absyn_func_call2str( a_Exp_Func_Call func_call ); | |
| 300 | +string absyn_dot_member2str( a_Exp_Dot_Member dot_member ); | |
| 301 | +string absyn_exp_if2str( a_Exp_If exp_if ); | |
| 302 | +string absyn_decl2str( a_Exp_Decl decl ); | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | +//----------------------------------------------------------------------------- | |
| 308 | +// name: absyn2str() | |
| 309 | +// desc: convert abstract syntax exp to string | |
| 310 | +//----------------------------------------------------------------------------- | |
| 311 | +string 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 | +//----------------------------------------------------------------------------- | |
| 323 | +string 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 | +//----------------------------------------------------------------------------- | |
| 403 | +string 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 | +//----------------------------------------------------------------------------- | |
| 468 | +string 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 | +//----------------------------------------------------------------------------- | |
| 483 | +string 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 | +//----------------------------------------------------------------------------- | |
| 495 | +string 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 | +//----------------------------------------------------------------------------- | |
| 508 | +string 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 | +//----------------------------------------------------------------------------- | |
| 520 | +string 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 | +//----------------------------------------------------------------------------- | |
| 532 | +string 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 | +//----------------------------------------------------------------------------- | |
| 564 | +string 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 | +//----------------------------------------------------------------------------- | |
| 599 | +string 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 | +//----------------------------------------------------------------------------- | |
| 617 | +string 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 | +//----------------------------------------------------------------------------- | |
| 629 | +string 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 | +//----------------------------------------------------------------------------- | |
| 642 | +string 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 | +} | |
| @@ -63,6 +63,8 @@ t_CKBOOL chuck_parse( c_constr fname, FILE * fd = NULL, c_constr code = NULL ); · 62 unmodified lines | ||
| 63 | 63 | // reset the parser |
| 64 | 64 | void reset_parse( ); |
| 65 | 65 | |
| 66 | +// convert abstract syntax expression to string | |
| 67 | +std::string absyn2str( a_Exp exp ); | |
| 66 | 68 | |
| 67 | 69 | // syntax highlighting tools |
| 68 | 70 | #include <vector> |
| @@ -40,6 +40,25 @@ · 39 unmodified lines | ||
| 40 | 40 | #include <string> |
| 41 | 41 | using namespace std; |
| 42 | 42 | |
| 43 | +// exports | |
| 44 | +CK_DLL_SFUN( machine_crash_impl ); | |
| 45 | +CK_DLL_SFUN( machine_add_impl ); | |
| 46 | +CK_DLL_SFUN( machine_spork_impl ); | |
| 47 | +CK_DLL_SFUN( machine_remove_impl ); | |
| 48 | +CK_DLL_SFUN( machine_replace_impl ); | |
| 49 | +CK_DLL_SFUN( machine_status_impl ); | |
| 50 | +CK_DLL_SFUN( machine_intsize_impl ); | |
| 51 | +CK_DLL_SFUN( machine_shreds_impl ); | |
| 52 | +CK_DLL_SFUN( machine_realtime_impl ); | |
| 53 | +CK_DLL_SFUN( machine_silent_impl ); | |
| 54 | +CK_DLL_SFUN( machine_eval_impl ); | |
| 55 | +CK_DLL_SFUN( machine_eval2_impl ); | |
| 56 | +CK_DLL_SFUN( machine_eval3_impl ); | |
| 57 | +CK_DLL_SFUN( machine_version_impl ); | |
| 58 | +CK_DLL_SFUN( machine_setloglevel_impl ); | |
| 59 | +CK_DLL_SFUN( machine_getloglevel_impl ); | |
| 60 | +CK_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 | 173 | QUERY->add_sfun( QUERY, machine_version_impl, "string", "version" ); |
| 155 | 174 | QUERY->doc_func( QUERY, "return version string" ); |
| 156 | 175 | |
| 157 | − // get version string | |
| 176 | + // get set loglevel | |
| 158 | 177 | QUERY->add_sfun( QUERY, machine_setloglevel_impl, "int", "loglevel" ); |
| 159 | 178 | QUERY->add_arg( QUERY, "int", "level" ); |
| 160 | 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 | 189 | " |- 9: FINEST\n" |
| 171 | 190 | " |- 10: ALL" ); |
| 172 | 191 | |
| 173 | − // get version string | |
| 192 | + // get log level | |
| 174 | 193 | QUERY->add_sfun( QUERY, machine_getloglevel_impl, "int", "loglevel" ); |
| 175 | 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 | 201 | // end class |
| 178 | 202 | QUERY->end_class( QUERY ); |
| 179 | 203 | |
| @@ -399,3 +423,11 @@ CK_DLL_SFUN( machine_getloglevel_impl ) · 219 unmodified lines | ||
| 399 | 423 | // return |
| 400 | 424 | RETURN->v_int = VM->carrier()->chuck->getLogLevel(); |
| 401 | 425 | } |
| 426 | + | |
| 427 | +CK_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 | +} | |
| @@ -53,23 +53,7 @@ t_CKBOOL machine_init( Chuck_Compiler * compiler, proc_msg_func func ); · 52 unmodified lines | ||
| 53 | 53 | // machine exports |
| 54 | 54 | t_CKUINT machine_intsize(); |
| 55 | 55 | |
| 56 | −// exports | |
| 57 | −CK_DLL_SFUN( machine_crash_impl ); | |
| 58 | −CK_DLL_SFUN( machine_add_impl ); | |
| 59 | −CK_DLL_SFUN( machine_spork_impl ); | |
| 60 | −CK_DLL_SFUN( machine_remove_impl ); | |
| 61 | −CK_DLL_SFUN( machine_replace_impl ); | |
| 62 | −CK_DLL_SFUN( machine_status_impl ); | |
| 63 | −CK_DLL_SFUN( machine_intsize_impl ); | |
| 64 | −CK_DLL_SFUN( machine_shreds_impl ); | |
| 65 | −CK_DLL_SFUN( machine_realtime_impl ); | |
| 66 | −CK_DLL_SFUN( machine_silent_impl ); | |
| 67 | −CK_DLL_SFUN( machine_eval_impl ); | |
| 68 | −CK_DLL_SFUN( machine_eval2_impl ); | |
| 69 | −CK_DLL_SFUN( machine_eval3_impl ); | |
| 70 | −CK_DLL_SFUN( machine_version_impl ); | |
| 71 | −CK_DLL_SFUN( machine_setloglevel_impl ); | |
| 72 | −CK_DLL_SFUN( machine_getloglevel_impl ); | |
| 56 | + | |
| 73 | 57 | |
| 74 | 58 | |
| 75 | 59 | #endif |
| @@ -0,0 +1,20 @@ | ||
| 1 | +fun vec3 missingReturn() | |
| 2 | +{ | |
| 3 | + // missing return | |
| 4 | +} | |
| 5 | + | |
| 6 | +fun 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 | |
| @@ -0,0 +1 @@ | ||
| 1 | +#(1.0000,0.0000,0.0000) #(0.0000,0.0000,0.0000) | |
| @@ -1 +1 @@ | ||
| 1 | −"success" : (string) | |
| 1 | +"success" :(string) | |
| @@ -1,5 +1,5 @@ | ||
| 1 | −"no i'm foo" : (string) | |
| 1 | +"no i'm foo" :(string) | |
| 2 | 2 | [chuck](VM): sporking incoming shred: 2 (102b.ck)... |
| 3 | −"no i'm foo" : (string) | |
| 4 | −"no i'm foo" : (string) | |
| 3 | +"no i'm foo" :(string) | |
| 4 | +"no i'm foo" :(string) | |
| 5 | 5 | 3 :(int) |
| @@ -47,7 +47,7 @@ def run_test(exe, path, filename, attempt): · 46 unmodified lines | ||
| 47 | 47 | try: |
| 48 | 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 | 51 | successes += 1 |
| 52 | 52 | |
| 53 | 53 | else: |