Skip to content

Commit

Permalink
vec2/3/4 member function call from literal values
Browse files Browse the repository at this point in the history
#special-primitive-member-func-from-literal
  • Loading branch information
gewang committed Nov 17, 2024
1 parent 4db3cb4 commit b011876
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 101 deletions.
6 changes: 6 additions & 0 deletions VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@ ChucK VERSIONS log
various scenarios.
(fixed) long-standing SndBuf issue, especially prevalent on macOS:
"System error : Too many open files." this was due a combination of
(fixed) memory leak involving string operations (e.g., string + string);
internally, string operations now are appropriately handled by the
operator overloading mechanism
(fixed) < <= > >= operators for strings
(fixed) vec2/vec3/vec4 implicit cast logic for +=> and -=> operations
(previously, this would cause a crash in some cases)
(fixed) vec2/vec3/vec4 function call from literal (non-variable) value
(e.g., @(1,0).magnitude(); previously this yielded a compiler error)
(added) vector dot product methods for vec2, vec3, and vec4
float vec2.dot( vec2 rhs )
float vec3.dot( vec3 rhs )
Expand Down
2 changes: 1 addition & 1 deletion src/core/chuck_absyn.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ struct a_Exp_Dur_ { a_Exp base; a_Exp unit; uint32_t line; uint32_t where; a_Exp
struct a_Exp_Array_ { a_Exp base; a_Array_Sub indices; uint32_t line; uint32_t where; a_Exp self; };
struct a_Exp_Func_Call_ { a_Exp func; a_Exp args; t_CKTYPE ret_type;
t_CKFUNC ck_func; t_CKVMCODE ck_vm_code; uint32_t line; uint32_t where; a_Exp self; };
struct a_Exp_Dot_Member_ { a_Exp base; t_CKTYPE t_base; S_Symbol xid; uint32_t line; uint32_t where; a_Exp self; };
struct a_Exp_Dot_Member_ { a_Exp base; t_CKTYPE t_base; S_Symbol xid; t_CKBOOL isSpecialPrimitiveFunc; uint32_t line; uint32_t where; a_Exp self; };
struct a_Exp_If_ { a_Exp cond; a_Exp if_exp; a_Exp else_exp; uint32_t line; uint32_t where; a_Exp self; };
struct a_Exp_Decl_ { a_Type_Decl type; a_Var_Decl_List var_decl_list; int num_var_decls; int is_static; int is_global;
int is_const; t_CKTYPE ck_type; int is_auto; uint32_t line; uint32_t where; a_Exp self; };
Expand Down
215 changes: 136 additions & 79 deletions src/core/chuck_emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@
#include "util_string.h" // added 1.5.0.5
#include <sstream>
#include <iostream>

using namespace std;


// forward references
struct Chuck_FuncCall_Options;


//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -81,7 +82,8 @@ t_CKBOOL emit_engine_emit_exp_dur( Chuck_Emitter * emit, a_Exp_Dur dur );
t_CKBOOL emit_engine_emit_exp_array( Chuck_Emitter * emit, a_Exp_Array array );
t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, Chuck_Func * func,
Chuck_Type * type, t_CKUINT line, t_CKUINT where,
t_CKBOOL spork = FALSE );
t_CKBOOL spork = FALSE,
Chuck_FuncCall_Options * options = NULL );
t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit, a_Exp_Func_Call func_call,
t_CKBOOL spork = FALSE );
t_CKBOOL emit_engine_emit_func_args( Chuck_Emitter * emit, a_Exp_Func_Call func_call );
Expand Down Expand Up @@ -4209,20 +4211,123 @@ t_CKBOOL emit_engine_emit_exp_array( Chuck_Emitter * emit, a_Exp_Array array )


//-----------------------------------------------------------------------------
// name: emit_engine_emit_exp_func_call()
// name: struct Chuck_FuncCall_Options | 1.5.4.2 (ge) added
// desc: a struct containing func call options, usually for specific cases
//-----------------------------------------------------------------------------
struct Chuck_FuncCall_Options
{
// set this to true ONLY for specific cases of...
// 1) a special primitive (e.g., vec2/3/4)...
// 2) calls one of its "member" functions (e.g., magnitude())
// 3) not from a variable but from a literal value (e.g., @(1,2,3).magnitude())
// in these cases, a special Chuck_Instr_Reg_Transmute_Value_To_Pointer
// must have been emitted prior to the member function call
// NOTE: in effect, this option tells the member function call to
// clean up the trasmuted THIS pointer before returning
// NOTE: part of #special-primitive-member-func-from-literal
t_CKBOOL transmutingSpecialPrimitiveForMemberFunc;

// constructor
Chuck_FuncCall_Options( t_CKBOOL transmuting = FALSE )
{
// defaults
transmutingSpecialPrimitiveForMemberFunc = transmuting;
}
};




//-----------------------------------------------------------------------------
// name: emit_engine_emit_func_args()
// desc: ...
//-----------------------------------------------------------------------------
t_CKBOOL emit_engine_emit_func_args( Chuck_Emitter * emit,
a_Exp_Func_Call func_call )
{
// emit the args (TRUE for doAddRef added 1.3.0.0)
if( !emit_engine_emit_exp( emit, func_call->args, TRUE ) )
{
EM_error2( func_call->where,
"(emit): internal error in emitting function call arguments..." );
return FALSE;
}

return TRUE;
}




//-----------------------------------------------------------------------------
// name: emit_engine_emit_exp_func_call()
// desc: emit function call from a_Exp_Func_Call
//-----------------------------------------------------------------------------
t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit,
a_Exp_Func_Call func_call,
t_CKBOOL spork )
{
// note: spork situations are now taken care in exp_spork...
// please look at that one before modifying this one!

// make sure there are args, and not sporking
if( func_call->args && !spork )
{
if( !emit_engine_emit_func_args( emit, func_call ) )
return FALSE;
}

// emit func
if( !emit_engine_emit_exp( emit, func_call->func ) )
{
EM_error2( func_call->where,
"(emit): internal error in evaluating function call..." );
return FALSE;
}

// line and pos
t_CKUINT line = func_call->line;
t_CKUINT where = func_call->where;
// additional func call options | 1.5.4.2 (ge) added
Chuck_FuncCall_Options options;

// in the case of member func calls
if( func_call->func->s_type == ae_exp_dot_member )
{
// if possible, get more accurate code position
line = func_call->func->dot_member.line;
where = func_call->func->dot_member.where;
// set option | 1.5.4.2 (ge) added as part of #special-primitive-member-func-from-literal
// this should only be true for special non-primitive functions *from literal value* e.g., @(1,2,3).magnitude();
options.transmutingSpecialPrimitiveForMemberFunc = func_call->func->dot_member.isSpecialPrimitiveFunc;
}

// the rest
return emit_engine_emit_exp_func_call( emit, func_call->ck_func, func_call->ret_type,
line, where, spork, &options );
}




//-----------------------------------------------------------------------------
// name: emit_engine_emit_exp_func_call()
// desc: emit function call from necessary information
//-----------------------------------------------------------------------------
t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit,
Chuck_Func * func,
Chuck_Type * type,
t_CKUINT line,
t_CKUINT where,
t_CKBOOL spork )
t_CKBOOL spork,
Chuck_FuncCall_Options * options )
{
// is a member?
t_CKBOOL is_member = func->is_member;
// is a static? (within class)
t_CKBOOL is_static = func->is_static;
// whether to enable the #special-primitive-member-func-from-literal option for member func
t_CKBOOL transmuting = options ? options->transmutingSpecialPrimitiveForMemberFunc : FALSE;

// only check dependency violations if we are at a context-top-level
// or class-top-level scope, i.e., not in a function definition
Expand Down Expand Up @@ -4275,7 +4380,7 @@ t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit,
{
// is member (1.3.1.0: changed to use kind instead of size)
if( is_member )
emit->append( instr = new Chuck_Instr_Func_Call_Member( kind, func ) );
emit->append( instr = new Chuck_Instr_Func_Call_Member( kind, func, CK_FUNC_CALL_THIS_IN_BACK, transmuting ) );
else if( is_static )
emit->append( instr = new Chuck_Instr_Func_Call_Static( kind, func ) );
else // 1.5.1.5 (ge & andrew) new planes of existence --> this is in global-scope (not global variable)
Expand All @@ -4302,71 +4407,6 @@ t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit,



//-----------------------------------------------------------------------------
// name: emit_engine_emit_func_args()
// desc: ...
//-----------------------------------------------------------------------------
t_CKBOOL emit_engine_emit_func_args( Chuck_Emitter * emit,
a_Exp_Func_Call func_call )
{
// emit the args (TRUE for doAddRef added 1.3.0.0)
if( !emit_engine_emit_exp( emit, func_call->args, TRUE ) )
{
EM_error2( func_call->where,
"(emit): internal error in emitting function call arguments..." );
return FALSE;
}

return TRUE;
}




//-----------------------------------------------------------------------------
// name: emit_engine_emit_exp_func_call()
// desc: emit function call from a_Exp_Func_Call
//-----------------------------------------------------------------------------
t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit,
a_Exp_Func_Call func_call,
t_CKBOOL spork )
{
// note: spork situations are now taken care in exp_spork...
// please look at that one before modifying this one!

// make sure there are args, and not sporking
if( func_call->args && !spork )
{
if( !emit_engine_emit_func_args( emit, func_call ) )
return FALSE;
}

// emit func
if( !emit_engine_emit_exp( emit, func_call->func ) )
{
EM_error2( func_call->where,
"(emit): internal error in evaluating function call..." );
return FALSE;
}

// line and pos
t_CKUINT line = func_call->line;
t_CKUINT where = func_call->where;
// if possible, get more accurate code position
if( func_call->func->s_type == ae_exp_dot_member )
{
line = func_call->func->dot_member.line;
where = func_call->func->dot_member.where;
}

// the rest
return emit_engine_emit_exp_func_call( emit, func_call->ck_func, func_call->ret_type,
line, where, spork );
}




//-----------------------------------------------------------------------------
// name: emit_engine_emit_dot_member_special()
// desc: emit special dot member: complex, polar, vec2, vec3, vec4
Expand Down Expand Up @@ -4546,23 +4586,40 @@ t_CKBOOL emit_engine_emit_exp_dot_member_special( Chuck_Emitter * emit,
// get the func
value = type_engine_find_value( t_base, member->xid );
func = value->func_ref;
// make sure it's there
assert( func != NULL );
if( !func )
{
// should not get here
EM_error2( member->base->where,
"(emit): internal error in lit_special(): expected function not found in value" );
// done
return FALSE;
}

// NOTE: base already emitted earier in this function (and as var)

// check base; 1.3.5.3
if( member->base->s_meta == ae_meta_value ) // is literal
{
// dup the value as pointer (as faux-'this' pointer)
emit->append( new Chuck_Instr_Reg_Dup_Last_As_Pointer( t_base->size / sz_WORD ) );
}
else // normal object
{
// dup the base pointer ('this' pointer as argument -- special case primitive)
emit->append( new Chuck_Instr_Reg_Dup_Last );
// verify
if( !member->isSpecialPrimitiveFunc )
{
// should not get here
EM_error2( member->base->where,
"(emit): internal error in lit_special(): unexpected specialPrimitiveFunc == FALSE" );
// done
return FALSE;
}

// 1.5.4.2 (ge) #special-primitive-member-func-from-literal
// transmute the value as pointer (as faux-'this' pointer)
emit->append( new Chuck_Instr_Reg_Transmute_Value_To_Pointer( t_base->size ) );
}

// dup the base pointer ('this' pointer as argument -- special case primitive)
// as of 1.5.4.2 this is emitted for both literals and variables
// #special-primitive-member-func-from-literal
emit->append( new Chuck_Instr_Reg_Dup_Last );

// find the offset for virtual table
offset = func->vt_index;
// emit the function
Expand Down
Loading

0 comments on commit b011876

Please sign in to comment.