diff --git a/stix/kernel/Context.st b/stix/kernel/Context.st index 8916581..e790cfc 100644 --- a/stix/kernel/Context.st +++ b/stix/kernel/Context.st @@ -88,19 +88,29 @@ block context... ^self.method } - #method varArgCount + #method vargCount { ^self basicSize - self class specNumInstVars - self.ntmprs } + + #method vargAt: index + { + ^self basicAt: (index + self class specNumInstVars + self.ntmprs) + } } #class(#pointer) BlockContext(Context) { #dcl nargs source home origin. - #method varArgCount + #method vargCount { - ^self.home varArgCount + ^self.home vargCount + } + + #method vargAt: index + { + ^self.home vargAt: index } #method fork diff --git a/stix/kernel/test-014.st b/stix/kernel/test-014.st index 9d24150..d5a2c46 100644 --- a/stix/kernel/test-014.st +++ b/stix/kernel/test-014.st @@ -146,10 +146,36 @@ procecure call is treated as if it is a unary message... 'Beautiful life' dump. ]. - thisContext varArgCount dump. - thisContext varArgCount (10, 20) dump. + self varg_test (10, 20, 30, 40, 50) dump. + self varg_test2 (10, 20, 30, 40, 50) dump. + self varg_test3 (10, 20, 30, 40, 50) dump. + thisContext vargCount dump. + thisContext vargCount dump. } + + #method(#class) varg_test() + { + 0 to: (thisContext vargCount - 1) do: [:k | + (thisContext vargAt: k) dump. + ]. + ^999 + } + #method(#class) varg_test2(a,b,c) + { + 0 to: (thisContext vargCount - 1) do: [:k | + (thisContext vargAt: k) dump. + ]. + ^a + } + #method(#class) varg_test3(a,b,c,d,e,f) + { + 0 to: (thisContext vargCount - 1) do: [:k | + (thisContext vargAt: k) dump. + ]. + ## ^b * 100 + ^f + } } #extend MyObject diff --git a/stix/lib/comp.c b/stix/lib/comp.c index 857a5f6..2c091aa 100644 --- a/stix/lib/comp.c +++ b/stix/lib/comp.c @@ -2573,12 +2573,11 @@ static int compile_unary_method_name (stix_t* stix) /* this is a procedural style method */ STIX_ASSERT (stix->c->mth.tmpr_nargs == 0); - if (TOKEN_TYPE(stix) != STIX_IOTOK_RPAREN) + GET_TOKEN (stix); + if (TOKEN_TYPE(stix) != STIX_IOTOK_RPAREN) { - do + do { - GET_TOKEN (stix); - if (TOKEN_TYPE(stix) != STIX_IOTOK_IDENT) { /* wrong argument name. identifier is expected */ @@ -2594,8 +2593,8 @@ static int compile_unary_method_name (stix_t* stix) if (add_temporary_variable(stix, TOKEN_NAME(stix)) <= -1) return -1; stix->c->mth.tmpr_nargs++; + GET_TOKEN (stix); - GET_TOKEN (stix); if (TOKEN_TYPE(stix) == STIX_IOTOK_RPAREN) break; if (TOKEN_TYPE(stix) != STIX_IOTOK_COMMA) @@ -2604,12 +2603,13 @@ static int compile_unary_method_name (stix_t* stix) return -1; } - } + GET_TOKEN (stix); + } while (1); } /* indicate that the unary method name is followed by a parameter list */ - stix->c->mth.parunary = 1; + stix->c->mth.variadic = 1; GET_TOKEN (stix); } @@ -4490,9 +4490,8 @@ static int add_compiled_method (stix_t* stix) preamble_index = 0; } - - if (stix->c->mth.parunary /*&& stix->c->mth.tmpr_nargs > 0*/) - preamble_flags |= STIX_METHOD_PREAMBLE_FLAG_PARUNARY; + if (stix->c->mth.variadic /*&& stix->c->mth.tmpr_nargs > 0*/) + preamble_flags |= STIX_METHOD_PREAMBLE_FLAG_VARIADIC; STIX_ASSERT (STIX_OOI_IN_METHOD_PREAMBLE_INDEX_RANGE(preamble_index)); @@ -4544,7 +4543,7 @@ static int compile_method_definition (stix_t* stix) stix->c->mth.kwsels.len = 0; stix->c->mth.name.len = 0; STIX_MEMSET (&stix->c->mth.name_loc, 0, STIX_SIZEOF(stix->c->mth.name_loc)); - stix->c->mth.parunary = 0; + stix->c->mth.variadic = 0; stix->c->mth.tmprs.len = 0; stix->c->mth.tmpr_count = 0; stix->c->mth.tmpr_nargs = 0; diff --git a/stix/lib/exec.c b/stix/lib/exec.c index c8ca565..26a014c 100644 --- a/stix/lib/exec.c +++ b/stix/lib/exec.c @@ -887,11 +887,11 @@ static stix_oop_process_t start_initial_process (stix_t* stix, stix_oop_context_ return proc; } -static STIX_INLINE int activate_new_method (stix_t* stix, stix_oop_method_t mth) +static STIX_INLINE int activate_new_method (stix_t* stix, stix_oop_method_t mth, stix_ooi_t actual_nargs) { stix_oop_context_t ctx; - stix_ooi_t i; - stix_ooi_t ntmprs, nargs; + stix_ooi_t i, j; + stix_ooi_t ntmprs, nargs, actual_ntmprs; ntmprs = STIX_OOP_TO_SMOOI(mth->tmpr_count); nargs = STIX_OOP_TO_SMOOI(mth->tmpr_nargs); @@ -899,9 +899,17 @@ static STIX_INLINE int activate_new_method (stix_t* stix, stix_oop_method_t mth) STIX_ASSERT (ntmprs >= 0); STIX_ASSERT (nargs <= ntmprs); + if (actual_nargs > nargs) + { + /* more arguments than the method specification have been passed in. + * it must be a variadic unary method. othewise, the compiler is buggy */ + STIX_ASSERT (STIX_METHOD_GET_PREAMBLE_FLAGS(STIX_OOP_TO_SMOOI(mth->preamble)) & STIX_METHOD_PREAMBLE_FLAG_VARIADIC); + actual_ntmprs = ntmprs + (actual_nargs - nargs); + } + else actual_ntmprs = ntmprs; + stix_pushtmp (stix, (stix_oop_t*)&mth); -/* TODO: check if the method is pused some extra arguments... */ - ctx = (stix_oop_context_t)stix_instantiate (stix, stix->_method_context, STIX_NULL, ntmprs); + ctx = (stix_oop_context_t)stix_instantiate (stix, stix->_method_context, STIX_NULL, actual_ntmprs); stix_poptmp (stix); if (!ctx) return -1; @@ -955,11 +963,30 @@ static STIX_INLINE int activate_new_method (stix_t* stix, stix_oop_method_t mth) * Since the number of arguments is 3, stack[sp - 3] points to * the receiver. When the stack is empty, sp is -1. */ - for (i = nargs; i > 0; ) + if (actual_nargs >= nargs) { - /* copy argument */ - ctx->slot[--i] = STIX_STACK_GETTOP (stix); - STIX_STACK_POP (stix); + for (i = actual_nargs, j = ntmprs + (actual_nargs - nargs); i > nargs; i--) + { + /* place variadic arguments after local temporaries */ + ctx->slot[--j] = STIX_STACK_GETTOP (stix); + STIX_STACK_POP (stix); + } + STIX_ASSERT (i == nargs); + while (i > 0) + { + /* place normal argument before local temporaries */ + ctx->slot[--i] = STIX_STACK_GETTOP (stix); + STIX_STACK_POP (stix); + } + } + else + { + for (i = actual_nargs; i > 0; ) + { + /* place normal argument before local temporaries */ + ctx->slot[--i] = STIX_STACK_GETTOP (stix); + STIX_STACK_POP (stix); + } } /* copy receiver */ ctx->receiver_or_source = STIX_STACK_GETTOP (stix); @@ -1140,7 +1167,7 @@ TODO: overcome this problem STIX_ASSERT (stix->active_context == ctx); /* emulate the message sending */ - return activate_new_method (stix, mth); + return activate_new_method (stix, mth, 0); } /* ------------------------------------------------------------------------- */ @@ -2765,16 +2792,26 @@ static int start_method (stix_t* stix, stix_oop_method_t method, stix_oow_t narg stix_ooi_t fetched_instruction_pointer = 0; /* set it to a fake value */ #endif + preamble = STIX_OOP_TO_SMOOI(method->preamble); + /*STIX_ASSERT (STIX_OOP_TO_SMOOI(method->tmpr_nargs) == nargs);*/ if (nargs != STIX_OOP_TO_SMOOI(method->tmpr_nargs)) { - /* TODO: throw exception??? */ - STIX_DEBUG1 (stix, "Argument count mismatch [%O]\n", method->name); - stix->errnum = STIX_EINVAL; - return -1; + + stix_ooi_t preamble_flags; + + preamble_flags = STIX_METHOD_GET_PREAMBLE_FLAGS(preamble); + if (!(preamble_flags & STIX_METHOD_PREAMBLE_FLAG_VARIADIC)) + { +/* TODO: better to throw a stix exception so that the caller can catch it??? */ + STIX_LOG3 (stix, STIX_LOG_IC | STIX_LOG_FATAL, + "Fatal error - Argument count mismatch for a non-variadic method [%O] - %zd expected, %zu given\n", + method->name, STIX_OOP_TO_SMOOI(method->tmpr_nargs), nargs); + stix->errnum = STIX_EINVAL; + return -1; + } } - preamble = STIX_OOP_TO_SMOOI(method->preamble); preamble_code = STIX_METHOD_GET_PREAMBLE_CODE(preamble); switch (preamble_code) { @@ -2868,7 +2905,7 @@ static int start_method (stix_t* stix, stix_oop_method_t method, stix_oow_t narg } /* soft primitive failure */ - if (activate_new_method (stix, method) <= -1) return -1; + if (activate_new_method (stix, method, nargs) <= -1) return -1; break; } @@ -2914,6 +2951,12 @@ static int start_method (stix_t* stix, stix_oop_method_t method, stix_oow_t narg exec_handler: stix_pushtmp (stix, (stix_oop_t*)&method); + + /* the primitive handler is executed without activating the method itself. + * one major difference between the primitive function and the normal method + * invocation is that the primitive function handler should access arguments + * directly in the stack unlik a normal activated method context where the + * arguments are copied to the back. */ n = handler (stix, nargs); stix_poptmp (stix); @@ -2950,7 +2993,7 @@ static int start_method (stix_t* stix, stix_oop_method_t method, stix_oow_t narg } else { - if (activate_new_method (stix, method) <= -1) return -1; + if (activate_new_method (stix, method, nargs) <= -1) return -1; } break; } @@ -2959,7 +3002,7 @@ static int start_method (stix_t* stix, stix_oop_method_t method, stix_oow_t narg STIX_ASSERT (preamble_code == STIX_METHOD_PREAMBLE_NONE || preamble_code == STIX_METHOD_PREAMBLE_EXCEPTION || preamble_code == STIX_METHOD_PREAMBLE_ENSURE); - if (activate_new_method (stix, method) <= -1) return -1; + if (activate_new_method (stix, method, nargs) <= -1) return -1; break; } diff --git a/stix/lib/stix-prv.h b/stix/lib/stix-prv.h index eb8e6b8..9d6d86f 100644 --- a/stix/lib/stix-prv.h +++ b/stix/lib/stix-prv.h @@ -544,7 +544,7 @@ struct stix_compiler_t stix_ioloc_t name_loc; /* is the unary method followed by parameter list? */ - int parunary; + int variadic; /* single string containing a space separated list of temporaries */ stix_oocs_t tmprs; diff --git a/stix/lib/stix.c b/stix/lib/stix.c index 92bd9d5..2ccda0c 100644 --- a/stix/lib/stix.c +++ b/stix/lib/stix.c @@ -696,7 +696,7 @@ stix_pfimpl_t stix_querymod (stix_t* stix, const stix_ooch_t* pfid, stix_oow_t p /* -------------------------------------------------------------------------- */ /* add a new primitive method */ -int stix_genpfmethod (stix_t* stix, stix_mod_t* mod, stix_oop_t _class, stix_method_type_t type, const stix_ooch_t* mthname, const stix_ooch_t* pfname) +int stix_genpfmethod (stix_t* stix, stix_mod_t* mod, stix_oop_t _class, stix_method_type_t type, const stix_ooch_t* mthname, int variadic, const stix_ooch_t* pfname) { /* NOTE: this function is a subset of add_compiled_method() in comp.c */ @@ -706,6 +706,7 @@ int stix_genpfmethod (stix_t* stix, stix_mod_t* mod, stix_oop_t _class, stix_met stix_oow_t tmp_count = 0, i; stix_ooi_t arg_count = 0; stix_oocs_t cs; + stix_ooi_t preamble_flags = 0; static stix_ooch_t dot[] = { '.', '\0' }; STIX_ASSERT (STIX_CLASSOF(stix, _class) == stix->_class); @@ -718,12 +719,17 @@ int stix_genpfmethod (stix_t* stix, stix_mod_t* mod, stix_oop_t _class, stix_met for (i = 0; mthname[i]; i++) { - if (mthname[i] == ':') arg_count++; + if (mthname[i] == ':') + { + if (variadic) goto oops_inval; + arg_count++; + } } /* TODO: check if name is a valid method name - more checks... */ /* TOOD: if the method name is a binary selector, it can still have an argument.. so the check below is invalid... */ if (arg_count > 0 && mthname[i - 1] != ':') { + oops_inval: STIX_DEBUG2 (stix, "Cannot generate primitive function method [%S] in [%O] - invalid name\n", mthname, cls->name); stix->errnum = STIX_EINVAL; goto oops; @@ -777,15 +783,13 @@ int stix_genpfmethod (stix_t* stix, stix_mod_t* mod, stix_oop_t _class, stix_met /* premable should contain the index to the literal frame which is always 0 */ mth->owner = cls; mth->name = mnsym; -/* TODO: premable flag -> VARIADIC, PARUNARY??? */ - mth->preamble = STIX_SMOOI_TO_OOP(STIX_METHOD_MAKE_PREAMBLE(STIX_METHOD_PREAMBLE_NAMED_PRIMITIVE, 0, 0)); + if (variadic) preamble_flags |= STIX_METHOD_PREAMBLE_FLAG_VARIADIC; + mth->preamble = STIX_SMOOI_TO_OOP(STIX_METHOD_MAKE_PREAMBLE(STIX_METHOD_PREAMBLE_NAMED_PRIMITIVE, 0, preamble_flags)); mth->preamble_data[0] = STIX_SMOOI_TO_OOP(0); mth->preamble_data[1] = STIX_SMOOI_TO_OOP(0); mth->tmpr_count = STIX_SMOOI_TO_OOP(arg_count); mth->tmpr_nargs = STIX_SMOOI_TO_OOP(arg_count); - - /* TODO: emit BCODE_RETURN_NIL ? */ if (!stix_putatdic (stix, cls->mthdic[type], (stix_oop_t)mnsym, (stix_oop_t)mth)) diff --git a/stix/lib/stix.h b/stix/lib/stix.h index 65f814b..0b51d6f 100644 --- a/stix/lib/stix.h +++ b/stix/lib/stix.h @@ -545,8 +545,7 @@ struct stix_method_t #define STIX_OOI_IN_METHOD_PREAMBLE_INDEX_RANGE(num) ((num) >= STIX_METHOD_PREAMBLE_INDEX_MIN && (num) <= STIX_METHOD_PREAMBLE_INDEX_MAX) /* preamble flags */ -#define STIX_METHOD_PREAMBLE_FLAG_PARUNARY (1 << 0) -#define STIX_METHOD_PREAMBLE_FLAG_VARIADIC (1 << 1) +#define STIX_METHOD_PREAMBLE_FLAG_VARIADIC (1 << 0) #define STIX_CONTEXT_NAMED_INSTVARS 8 typedef struct stix_context_t stix_context_t; @@ -1208,6 +1207,7 @@ STIX_EXPORT int stix_genpfmethod ( stix_oop_t _class, stix_method_type_t type, const stix_ooch_t* mthname, + int variadic, const stix_ooch_t* name ); diff --git a/stix/mod/stdio.c b/stix/mod/stdio.c index b51602e..bd04f87 100644 --- a/stix/mod/stdio.c +++ b/stix/mod/stdio.c @@ -126,16 +126,17 @@ struct fnctab_t { const stix_bch_t* mthname; const stix_bch_t* pfname; + int variadic; stix_pfimpl_t handler; }; static fnctab_t fnctab[] = { - { "_newInstSize", STIX_NULL, pf_newinstsize }, - { "close", STIX_NULL, pf_close }, - { "gets", STIX_NULL, pf_gets }, - { "open:for:", STIX_NULL, pf_open }, - { "puts", STIX_NULL, pf_puts } + { "_newInstSize", STIX_NULL, 0, pf_newinstsize }, + { "close", STIX_NULL, 0, pf_close }, + { "gets", STIX_NULL, 0, pf_gets }, + { "open:for:", STIX_NULL, 0, pf_open }, + { "puts", STIX_NULL, 1, pf_puts } }; @@ -149,9 +150,9 @@ static stix_ooch_t voca_newInstSize[] = { '_','n','e','w','I','n','s','t','S','i static int import (stix_t* stix, stix_mod_t* mod, stix_oop_t _class) { stix_pushtmp (stix, &_class); - stix_genpfmethod (stix, mod, _class, STIX_METHOD_CLASS, voca_newInstSize, STIX_NULL); - stix_genpfmethod (stix, mod, _class, STIX_METHOD_INSTANCE, voca_open_for, STIX_NULL); - stix_genpfmethod (stix, mod, _class, STIX_METHOD_INSTANCE, voca_close, voca_close); + stix_genpfmethod (stix, mod, _class, STIX_METHOD_CLASS, voca_newInstSize, 0, STIX_NULL); + stix_genpfmethod (stix, mod, _class, STIX_METHOD_INSTANCE, voca_open_for, 0, STIX_NULL); + stix_genpfmethod (stix, mod, _class, STIX_METHOD_INSTANCE, voca_close, 0, voca_close); stix_poptmp (stix); return 0; }