added a new method directive #liberal to indicate a method that accept a fully variadic number of arguments.

the directive #liberal allows the caller to omit the named arguments as well.
the directive #variadic requires the caller to provide at least the named arguments
This commit is contained in:
hyunghwan.chung 2017-04-01 06:54:27 +00:00
parent aeb02213b4
commit 2ed62a5edb
4 changed files with 41 additions and 19 deletions

View File

@ -145,6 +145,7 @@ class MyObject(TestObject)
self varg_test (10, 20, 30, 40, 50) dump. self varg_test (10, 20, 30, 40, 50) dump.
self varg_test2 (10, 20, 30, 40, 50) dump. self varg_test2 (10, 20, 30, 40, 50) dump.
self varg_test3 (10, 20, 30, 40, 50) dump. self varg_test3 (10, 20, 30, 40, 50) dump.
self varg_test3 (10, 20, 30, 40, 50, 60, 70, 80, 90, 100) dump.
thisContext vargCount dump. thisContext vargCount dump.
thisContext vargCount dump. thisContext vargCount dump.
@ -204,21 +205,29 @@ class MyObject(TestObject)
} }
method(#class,#variadic) varg_test2(a,b,c) method(#class,#variadic) varg_test2(a,b,c)
{ {
0 to: (thisContext vargCount - 1) do: [:k | 'varg_test2 start .....' dump.
a dump.
b dump.
c dump.
'varg_test2 varg .....' dump.
0 priorTo: (thisContext vargCount) do: [:k |
(thisContext vargAt: k) dump. (thisContext vargAt: k) dump.
]. ].
'varg_test2 end .....' dump.
^a ^a
} }
method(#class,#variadic) varg_test3(a,b,c,d,e,f) method(#class,#liberal) varg_test3(a,b,c,d,e,f)
{ {
0 to: (thisContext vargCount - 1) do: [:k | 'varg_test3 start .....' dump.
0 priorTo: (thisContext vargCount) do: [:k |
(thisContext vargAt: k) dump. (thisContext vargAt: k) dump.
]. ].
'varg_test3 end .....' dump.
## ^b * 100 ## ^b * 100
^f ^f
} }
method(#class,#variadic) t001(a) method(#class,#liberal) t001(a)
{ {
a isNil ifTrue: [^error(10)]. a isNil ifTrue: [^error(10)].
(a = 20) ifTrue: [^error]. (a = 20) ifTrue: [^error].

View File

@ -103,6 +103,7 @@ static struct voca_t
{ 9, { '#','h','a','l','f','w','o','r','d' } }, { 9, { '#','h','a','l','f','w','o','r','d' } },
{ 2, { 'i','f' } }, { 2, { 'i','f' } },
{ 8, { '#','i','n','c','l','u','d','e' } }, { 8, { '#','i','n','c','l','u','d','e' } },
{ 8, { '#','l','i','b','e','r','a','l' } },
{ 7, { '#','l','i','w','o','r','d' } }, { 7, { '#','l','i','w','o','r','d' } },
{ 6, { 'm','e','t','h','o','d' } }, { 6, { 'm','e','t','h','o','d' } },
{ 3, { 'n','i','l' } }, { 3, { 'n','i','l' } },
@ -150,6 +151,7 @@ enum voca_id_t
VOCA_HALFWORD_S, VOCA_HALFWORD_S,
VOCA_IF, VOCA_IF,
VOCA_INCLUDE_S, VOCA_INCLUDE_S,
VOCA_LIBERAL_S,
VOCA_LIWORD_S, VOCA_LIWORD_S,
VOCA_METHOD, VOCA_METHOD,
VOCA_NIL, VOCA_NIL,
@ -5752,8 +5754,8 @@ static int add_compiled_method (moo_t* moo)
preamble_index = 0; preamble_index = 0;
} }
if (moo->c->mth.variadic /*&& moo->c->mth.tmpr_nargs > 0*/) /*if (moo->c->mth.variadic) */
preamble_flags |= MOO_METHOD_PREAMBLE_FLAG_VARIADIC; preamble_flags |= moo->c->mth.variadic;
MOO_ASSERT (moo, MOO_OOI_IN_METHOD_PREAMBLE_INDEX_RANGE(preamble_index)); MOO_ASSERT (moo, MOO_OOI_IN_METHOD_PREAMBLE_INDEX_RANGE(preamble_index));
@ -5853,9 +5855,10 @@ static int compile_method_definition (moo_t* moo)
GET_TOKEN (moo); GET_TOKEN (moo);
} }
else if (is_token_symbol(moo, VOCA_VARIADIC_S)) else if (is_token_symbol(moo, VOCA_VARIADIC_S) ||
is_token_symbol(moo, VOCA_LIBERAL_S))
{ {
/* method(#variadic) */ /* method(#variadic) or method(#liberal) */
if (moo->c->mth.variadic) if (moo->c->mth.variadic)
{ {
/* #variadic duplicate modifier */ /* #variadic duplicate modifier */
@ -5863,7 +5866,10 @@ static int compile_method_definition (moo_t* moo)
return -1; return -1;
} }
moo->c->mth.variadic = 1; if (is_token_symbol(moo, VOCA_LIBERAL_S))
moo->c->mth.variadic = MOO_METHOD_PREAMBLE_FLAG_LIBERAL;
else
moo->c->mth.variadic = MOO_METHOD_PREAMBLE_FLAG_VARIADIC;
GET_TOKEN (moo); GET_TOKEN (moo);
} }
@ -6024,7 +6030,7 @@ static int compile_method_definition (moo_t* moo)
GET_TOKEN (moo); GET_TOKEN (moo);
if (compile_method_temporaries(moo) <= -1 || if (compile_method_temporaries(moo) <= -1 ||
compile_method_progma(moo) <= -1 || compile_method_pragma(moo) <= -1 ||
compile_method_statements(moo) <= -1) return -1; compile_method_statements(moo) <= -1) return -1;
if (TOKEN_TYPE(moo) != MOO_IOTOK_RBRACE) if (TOKEN_TYPE(moo) != MOO_IOTOK_RBRACE)

View File

@ -885,8 +885,8 @@ static MOO_INLINE int activate_new_method (moo_t* moo, moo_oop_method_t mth, moo
if (actual_nargs > nargs) if (actual_nargs > nargs)
{ {
/* more arguments than the method specification have been passed in. /* more arguments than the method specification have been passed in.
* it must be a variadic unary method. othewise, the compiler is buggy */ * it must be a variadic or liberal unary method. othewise, the compiler is buggy */
MOO_ASSERT (moo, MOO_METHOD_GET_PREAMBLE_FLAGS(MOO_OOP_TO_SMOOI(mth->preamble)) & MOO_METHOD_PREAMBLE_FLAG_VARIADIC); MOO_ASSERT (moo, MOO_METHOD_GET_PREAMBLE_FLAGS(MOO_OOP_TO_SMOOI(mth->preamble)) & (MOO_METHOD_PREAMBLE_FLAG_VARIADIC | MOO_METHOD_PREAMBLE_FLAG_LIBERAL));
actual_ntmprs = ntmprs + (actual_nargs - nargs); actual_ntmprs = ntmprs + (actual_nargs - nargs);
} }
else actual_ntmprs = ntmprs; else actual_ntmprs = ntmprs;
@ -3018,7 +3018,7 @@ moo_pfbase_t* moo_getpfnum (moo_t* moo, const moo_ooch_t* ptr, moo_oow_t len, mo
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs) static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs)
{ {
moo_ooi_t preamble, preamble_code; moo_ooi_t preamble, preamble_code, preamble_flags;
moo_ooi_t /*sp,*/ stack_base; moo_ooi_t /*sp,*/ stack_base;
#if defined(MOO_DEBUG_VM_EXEC) #if defined(MOO_DEBUG_VM_EXEC)
@ -3026,16 +3026,22 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs)
#endif #endif
preamble = MOO_OOP_TO_SMOOI(method->preamble); preamble = MOO_OOP_TO_SMOOI(method->preamble);
preamble_flags = MOO_METHOD_GET_PREAMBLE_FLAGS(preamble);
if (preamble_flags & MOO_METHOD_PREAMBLE_FLAG_LIBERAL)
{
/* do nothing - no argument check */
}
else if (preamble_flags & MOO_METHOD_PREAMBLE_FLAG_VARIADIC)
{
if (nargs < MOO_OOP_TO_SMOOI(method->tmpr_nargs)) goto arg_count_mismatch;
}
else
{
if (nargs != MOO_OOP_TO_SMOOI(method->tmpr_nargs)) if (nargs != MOO_OOP_TO_SMOOI(method->tmpr_nargs))
{ {
moo_ooi_t preamble_flags;
preamble_flags = MOO_METHOD_GET_PREAMBLE_FLAGS(preamble);
if (!(preamble_flags & MOO_METHOD_PREAMBLE_FLAG_VARIADIC))
{
/* TODO: better to throw a moo exception so that the caller can catch it??? */ /* TODO: better to throw a moo exception so that the caller can catch it??? */
arg_count_mismatch:
MOO_LOG3 (moo, MOO_LOG_IC | MOO_LOG_FATAL, MOO_LOG3 (moo, MOO_LOG_IC | MOO_LOG_FATAL,
"Fatal error - Argument count mismatch for a non-variadic method [%O] - %zd expected, %zu given\n", "Fatal error - Argument count mismatch for a non-variadic method [%O] - %zd expected, %zu given\n",
method->name, MOO_OOP_TO_SMOOI(method->tmpr_nargs), nargs); method->name, MOO_OOP_TO_SMOOI(method->tmpr_nargs), nargs);

View File

@ -596,6 +596,7 @@ struct moo_method_t
/* preamble flags */ /* preamble flags */
#define MOO_METHOD_PREAMBLE_FLAG_VARIADIC (1 << 0) #define MOO_METHOD_PREAMBLE_FLAG_VARIADIC (1 << 0)
#define MOO_METHOD_PREAMBLE_FLAG_LIBERAL (1 << 1)
/* NOTE: if you change the number of instance variables for moo_context_t, /* NOTE: if you change the number of instance variables for moo_context_t,
* you need to change the defintion of BlockContext and MethodContext. * you need to change the defintion of BlockContext and MethodContext.