Skip to content

Commit

Permalink
support for this() as alternative ctor call
Browse files Browse the repository at this point in the history
  • Loading branch information
gewang committed Dec 7, 2024
1 parent 61a68ed commit 62d25bc
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 78 deletions.
9 changes: 9 additions & 0 deletions src/core/chuck_absyn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,9 @@ void delete_exp( a_Exp e )
{
// TODO: release reference type
// TODO: release reference owner
// 1.5.4.4 (ge) actually -- the above may not be necessary if:
// 1) they are not ref-counted in the first place; e.g., see type_engine_check_exp() which assigned `type`
// AND 2) the AST is cleaned up before types and nspcs etc.

// delete content in this exp
delete_exp_contents( e );
Expand Down Expand Up @@ -1682,7 +1685,13 @@ void delete_exp_decl( a_Exp e )
void delete_exp_from_id( a_Exp_Primary e )
{
// TODO: do we need to anything with the Symbol?
// 1.5.4.4 (ge) symbols are additive but also also unique per string thus growth bounded -- can keep around, in practice
EM_log( CK_LOG_FINEST, "deleting exp (primary ID '%s') [%p]...", S_name(e->var), (void *)e );

// TODO: release reference func_alias #2024-ctor-this
// 1.5.4.4 (ge) actually -- the above may not be necessary if:
// 1) func_alisa not ref-counted in the first place; e.g., see xxx() which assigned `func_alias`
// AND 2) the AST is cleaned up before the func etc.
}

void delete_exp_from_str( a_Exp_Primary e )
Expand Down
2 changes: 2 additions & 0 deletions src/core/chuck_absyn.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ struct a_Exp_Primary_
{
ae_Exp_Primary_Type s_type;
t_CKVALUE value;
// 1.5.4.4 (ge) added to alias a contructor to this() #2024-ctor-this
t_CKFUNC func_alias;

union
{
Expand Down
4 changes: 2 additions & 2 deletions src/core/chuck_compile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2510,8 +2510,6 @@ t_CKBOOL Chuck_Compiler::openFile( Chuck_CompileTarget * target,
return FALSE;
}

// open file
target->fd2parse = fopen( target->absolutePath.c_str(), "rb" );
// check for directory
if( ck_isdir( target->absolutePath ) )
{
Expand All @@ -2521,6 +2519,8 @@ t_CKBOOL Chuck_Compiler::openFile( Chuck_CompileTarget * target,
return FALSE;
}

// open file
target->fd2parse = fopen( target->absolutePath.c_str(), "rb" );
// if still unresolved
if( !target->fd2parse )
{
Expand Down
11 changes: 11 additions & 0 deletions src/core/chuck_emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4369,6 +4369,17 @@ t_CKBOOL emit_engine_emit_exp_func_call( Chuck_Emitter * emit,
return FALSE;
}

// get the function as exp | 1.5.4.4 (ge) added to support calling this() #2024-ctor-this
a_Exp exp_func = func_call->func;
// check if this() -- for calling another constructor from a constructor | 1.5.4.4 (ge) added
if( exp_func->s_type == ae_exp_primary && exp_func->primary.s_type == ae_primary_var && string(S_name(exp_func->primary.var)) == "this" )
{
// NOTE should have already checked that we are within a class if `this` was used
assert( emit->env->class_def != NULL );
// emit the contructor func | (don't need to dup last since we are not resolving from a dot_member
emit->append( new Chuck_Instr_Reg_Push_Imm( (t_CKUINT)exp_func->primary.func_alias ) );
}

// line and pos
t_CKUINT line = func_call->line;
t_CKUINT where = func_call->where;
Expand Down
2 changes: 1 addition & 1 deletion src/core/chuck_instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5329,7 +5329,7 @@ const char * Chuck_Instr_Func_Call::params() const

//-----------------------------------------------------------------------------
// name: execute()
// desc: ...
// desc: general function call for in-language defined functions
//-----------------------------------------------------------------------------
void Chuck_Instr_Func_Call::execute( Chuck_VM * vm, Chuck_VM_Shred * shred )
{
Expand Down
173 changes: 98 additions & 75 deletions src/core/chuck_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4814,99 +4814,122 @@ t_CKTYPE type_engine_check_exp_func_call( Chuck_Env * env, a_Exp exp_func, a_Exp
return NULL;
}

// make sure we have a function
// is exp_func's type a function?
if( !isa( f, env->ckt_function ) )
{
EM_error2( exp_func->where,
"function call using a non-function value" );
// check if f is of type Type | 1.5.2.5 (ge) added
if( equals( f, env->ckt_class ) )
// check if this() -- for calling another constructor from a constructor | 1.5.4.4 (ge) added #2024-ctor-this
if( exp_func->s_type == ae_exp_primary && exp_func->primary.s_type == ae_primary_var && string(S_name(exp_func->primary.var)) == "this" )
{
// NOTE should have already checked that we are within a class if `this` was used
assert( env->class_def != NULL );
// make a temp AST ctor call struct
a_Ctor_Call_ ctor_call;
// populate the args field
ctor_call.args = args;
// match constructor by args
ctor_call.func = type_engine_check_ctor_call( env, env->class_def, &ctor_call, NULL, exp_func->where );
// check for error
if( !ctor_call.func ) return NULL;
// set the function in question
theFunc = ctor_call.func;
// remember it as the func alias for `this`
exp_func->primary.func_alias = theFunc;
}
else // error case
{
// provide hopefully helpful hint
EM_error2( 0, " |- (hint: creating an Object variable with a constructor?)" );
EM_error2( 0, " |- (...if so, try using the form `%s VARNAME(...)` instead)", f->actual_type->name().c_str() );
EM_error2( exp_func->where,
"function call using a non-function value" );
// check if f is of type Type | 1.5.2.5 (ge) added
if( equals( f, env->ckt_class ) )
{
// provide hopefully helpful hint
EM_error2( 0, " |- (hint: creating an Object variable with a constructor?)" );
EM_error2( 0, " |- (...if so, try using the form `%s VARNAME(...)` instead)", f->actual_type->name().c_str() );
}
return NULL;
}
return NULL;
}

// copy the func
up = f->func_bridge;

// check the arguments
if( args )
else // exp_func's type is a function
{
a = type_engine_check_exp( env, args );
if( !a ) return NULL;
}

// look for a match
t_CKBOOL hasError = FALSE;
theFunc = find_func_match( env, up, args, hasError, exp_func->where );
// copy the func
up = f->func_bridge;

// no func
if( !theFunc )
{
// hasError implies an error has already been printed
if( hasError ) return NULL;

// if primary
if( exp_func->s_type == ae_exp_primary && exp_func->primary.s_type == ae_primary_var )
{
EM_error2( exp_func->where,
"argument type(s) do not match...\n...for function '%s(...)'...",
S_name(exp_func->primary.var) );
}
else if( exp_func->s_type == ae_exp_dot_member )
// check the arguments
if( args )
{
EM_error2( exp_func->dot_member.where,
"argument type(s) do not match...\n...for function '%s(...)'...",
type_engine_print_exp_dot_member( env, &exp_func->dot_member ).c_str() );
a = type_engine_check_exp( env, args );
if( !a ) return NULL;
}
else

// look for a match
t_CKBOOL hasError = FALSE;
theFunc = find_func_match( env, up, args, hasError, exp_func->where );

// no func
if( !theFunc )
{
EM_error2( exp_func->where,
"argument type(s) do not match for function..." );
}
// hasError implies an error has already been printed
if( hasError ) return NULL;

EM_error2( 0,
"...(please check the argument types)" );
// if primary
if( exp_func->s_type == ae_exp_primary && exp_func->primary.s_type == ae_primary_var )
{
EM_error2( exp_func->where,
"argument type(s) do not match...\n...for function '%s(...)'...",
S_name(exp_func->primary.var) );
}
else if( exp_func->s_type == ae_exp_dot_member )
{
EM_error2( exp_func->dot_member.where,
"argument type(s) do not match...\n...for function '%s(...)'...",
type_engine_print_exp_dot_member( env, &exp_func->dot_member ).c_str() );
}
else
{
EM_error2( exp_func->where,
"argument type(s) do not match for function..." );
}

return NULL;
}
EM_error2( 0,
"...(please check the argument types)" );

// recheck the type with new name
if( exp_func->s_type == ae_exp_primary && exp_func->primary.s_type == ae_primary_var )
{
// set the new name
// TODO: clear old
exp_func->primary.var = insert_symbol(theFunc->name.c_str());
// make sure the type is still the name
if( *exp_func->type != *type_engine_check_exp( env, exp_func ) )
{
// error
EM_error2( exp_func->where,
"(internal error) function type different on second check" );
return NULL;
}
}
else if( exp_func->s_type == ae_exp_dot_member )
{
// set the new name
// TODO: clear old
exp_func->dot_member.xid = insert_symbol(theFunc->name.c_str());
/*
// TODO: figure if this is necessary - it type checks things twice!
// make sure the type is still the name
if( *exp_func->type != *type_engine_check_exp( env, exp_func ) )

// recheck the type with new name
if( exp_func->s_type == ae_exp_primary && exp_func->primary.s_type == ae_primary_var )
{
// error
EM_error2( exp_func->where,
"(internal error) function type different on second check" );
return NULL;
// set the new name
// TODO: clear old
exp_func->primary.var = insert_symbol(theFunc->name.c_str());
// make sure the type is still the name
if( *exp_func->type != *type_engine_check_exp( env, exp_func ) )
{
// error
EM_error2( exp_func->where,
"(internal error) function type different on second check" );
return NULL;
}
}
*/
else if( exp_func->s_type == ae_exp_dot_member )
{
// set the new name
// TODO: clear old
exp_func->dot_member.xid = insert_symbol(theFunc->name.c_str());
/*
// TODO: figure if this is necessary - it type checks things twice!
// make sure the type is still the name
if( *exp_func->type != *type_engine_check_exp( env, exp_func ) )
{
// error
EM_error2( exp_func->where,
"(internal error) function type different on second check" );
return NULL;
}
*/
}
else assert( FALSE );
}
else assert( FALSE );

// copy ck_func out (return by reference)
ck_func = theFunc;
Expand Down
21 changes: 21 additions & 0 deletions src/test/01-Basic/271-ctor-call-ctor.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Foo
{
int theX;

// a constructor
fun Foo( int x ) { x => theX; }

// another constructor
fun Foo()
{
// call a specific constructor
Foo( 5 );
}
}

// make a foo
Foo foo;

// check
if( foo.theX == 5 ) <<< "success" >>>;

23 changes: 23 additions & 0 deletions src/test/01-Basic/272-this-call-ctor.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// test calling constructor using `this`

class Foo
{
int theX;

// a constructor
fun Foo( int x ) { x => theX; }

// another constructor
fun Foo()
{
// call a specific constructor
this( 5 );
}
}

// make a foo
Foo foo;

// should print 5
if( foo.theX == 5 ) <<< "success" >>>;

0 comments on commit 62d25bc

Please sign in to comment.