From 937895ef59cb30e391379f087800c5bc2789ef42 Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Sun, 7 May 2017 16:45:27 +0000 Subject: [PATCH] added a new method modifier #lenient that applies to a primitive method. when set, it turns soft failure to error return --- moo/kernel/Apex.moo | 26 +++++++-------- moo/kernel/Context.moo | 2 +- moo/kernel/Magnitu.moo | 6 ++-- moo/lib/comp.c | 20 +++++++++-- moo/lib/exec.c | 75 ++++++++++++++++++++++++------------------ moo/lib/gc.c | 6 ++-- moo/lib/moo-prv.h | 1 + moo/lib/moo.h | 17 +++++----- 8 files changed, 90 insertions(+), 63 deletions(-) diff --git a/moo/kernel/Apex.moo b/moo/kernel/Apex.moo index d92f7c7..a983e89 100644 --- a/moo/kernel/Apex.moo +++ b/moo/kernel/Apex.moo @@ -2,7 +2,7 @@ class Apex(nil) { } -class Error(Apex) +class(#limited) Error(Apex) { } @@ -37,12 +37,7 @@ extend Apex ## ------------------------------------------------------- ## ------------------------------------------------------- - method(#class) dump - { - - } - - method dump + method(#dual) dump { } @@ -50,12 +45,7 @@ extend Apex ## ------------------------------------------------------- ## ------------------------------------------------------- - method(#class) yourself - { - ^self. - } - - method yourself + method(#dual) yourself { ^self. } @@ -63,6 +53,15 @@ extend Apex ## ------------------------------------------------------- ## INSTANTIATION & INITIALIZATION ## ------------------------------------------------------- + method(#class,#lenient) _basicNew + { + + } + method(#class,#lenient) _basicNew: size + { + + } + method(#class) basicNew { | perr | @@ -79,6 +78,7 @@ extend Apex { | perr | + ## self primitiveFailed. diff --git a/moo/kernel/Context.moo b/moo/kernel/Context.moo index 5b6796b..603c83b 100644 --- a/moo/kernel/Context.moo +++ b/moo/kernel/Context.moo @@ -339,7 +339,7 @@ class(#pointer) CompiledMethod(Object) method preambleCode { (* TODO: make this a primtive for performance *) - ^(self.preamble bitAnd: 16rFF) bitShift: -3. + ^(self.preamble bitShift: -4) bitAnd: 16r1F. } method owner diff --git a/moo/kernel/Magnitu.moo b/moo/kernel/Magnitu.moo index 67be249..bcc990c 100644 --- a/moo/kernel/Magnitu.moo +++ b/moo/kernel/Magnitu.moo @@ -43,7 +43,7 @@ class Association(Magnitude) } } -class Character(Magnitude) +class(#limited) Character(Magnitude) { ## method basicSize ## { @@ -53,7 +53,7 @@ class Character(Magnitude) method(#primitive) asInteger. } -class Number(Magnitude) +class(#limited) Number(Magnitude) { method + aNumber { @@ -300,7 +300,7 @@ class(#limited) Integer(Number) } } -class SmallInteger(Integer) +class(#limited) SmallInteger(Integer) { ## method basicSize ## { diff --git a/moo/lib/comp.c b/moo/lib/comp.c index 217bf83..4bfe023 100644 --- a/moo/lib/comp.c +++ b/moo/lib/comp.c @@ -111,6 +111,7 @@ static struct voca_t { 10, { '#','i','m','m','u','t','a','b','l','e' } }, { 6, { 'i','m','p','o','r','t' } }, { 8, { '#','i','n','c','l','u','d','e' } }, + { 8, { '#','l','e','n','i','e','n','t' } }, { 8, { '#','l','i','b','e','r','a','l' } }, { 8, { '#','l','i','m','i','t','e','d' } }, { 7, { '#','l','i','w','o','r','d' } }, @@ -170,6 +171,7 @@ enum voca_id_t VOCA_IMMUTABLE_S, VOCA_IMPORT, VOCA_INCLUDE_S, + VOCA_LENIENT_S, VOCA_LIBERAL_S, VOCA_LIMITED_S, VOCA_LIWORD_S, @@ -3725,7 +3727,7 @@ static int compile_method_pragma (moo_t* moo) if (moo->c->mth.tmpr_nargs < pfbase->minargs || moo->c->mth.tmpr_nargs > pfbase->maxargs) { - MOO_DEBUG5 (moo, "Unsupported argument count in primitive method pragma of %.*js - %zd-%zd expected, %zd specified\n", + MOO_DEBUG5 (moo, "Unsupported argument count in primitive method definition of %.*js - %zd-%zd expected, %zd specified\n", tlen, tptr, pfbase->minargs, pfbase->maxargs, moo->c->mth.tmpr_nargs); set_syntax_error (moo, MOO_SYNERR_PFARGDEFINVAL, &moo->c->mth.name_loc, &moo->c->mth.name); return -1; @@ -3749,7 +3751,7 @@ static int compile_method_pragma (moo_t* moo) { if (moo->c->mth.tmpr_nargs < pfbase->minargs || moo->c->mth.tmpr_nargs > pfbase->maxargs) { - MOO_DEBUG5 (moo, "Unsupported argument count in primitive method pragma of %.*js - %zd-%zd expected, %zd specified\n", + MOO_DEBUG5 (moo, "Unsupported argument count in primitive method definition of %.*js - %zd-%zd expected, %zd specified\n", tlen, tptr, pfbase->minargs, pfbase->maxargs, moo->c->mth.tmpr_nargs); set_syntax_error (moo, MOO_SYNERR_PFARGDEFINVAL, &moo->c->mth.name_loc, &moo->c->mth.name); return -1; @@ -6025,6 +6027,7 @@ static int add_compiled_method (moo_t* moo) /*if (moo->c->mth.variadic) */ preamble_flags |= moo->c->mth.variadic; if (moo->c->mth.type == MOO_METHOD_DUAL) preamble_flags |= MOO_METHOD_PREAMBLE_FLAG_DUAL; + if (moo->c->mth.lenient) preamble_flags |= MOO_METHOD_PREAMBLE_FLAG_LENIENT; MOO_ASSERT (moo, MOO_OOI_IN_METHOD_PREAMBLE_INDEX_RANGE(preamble_index)); @@ -6081,6 +6084,7 @@ static int compile_method_definition (moo_t* moo) /* clear data required to compile a method */ moo->c->mth.type = MOO_METHOD_INSTANCE; moo->c->mth.primitive = 0; + moo->c->mth.lenient = 0; moo->c->mth.text.len = 0; moo->c->mth.assignees.len = 0; moo->c->mth.binsels.len = 0; @@ -6143,7 +6147,17 @@ static int compile_method_definition (moo_t* moo) } moo->c->mth.primitive = 1; - + GET_TOKEN (moo); + } + else if (is_token_symbol(moo, VOCA_LENIENT_S)) + { + /* method(#lenient) */ + if (moo->c->mth.lenient) + { + set_syntax_error (moo, MOO_SYNERR_MODIFIERDUPL, TOKEN_LOC(moo), TOKEN_NAME(moo)); + return -1; + } + moo->c->mth.lenient = 1; GET_TOKEN (moo); } else if (is_token_symbol(moo, VOCA_VARIADIC_S) || diff --git a/moo/lib/exec.c b/moo/lib/exec.c index b6c598f..b176548 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -3963,7 +3963,11 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs) moo_pushtmp (moo, (moo_oop_t*)&method); n = pftab[pfnum].pfbase.handler (moo, nargs); moo_poptmp (moo); - if (n <= MOO_PF_HARD_FAILURE) return -1; + if (n <= MOO_PF_HARD_FAILURE) + { + MOO_DEBUG3 (moo, "Hard failure indicated by primitive function %p - %hs - return code %d\n", pftab[pfnum].pfbase.handler, pftab[pfnum].name, n); + return -1; + } if (n >= MOO_PF_SUCCESS) break; MOO_DEBUG2 (moo, "Soft failure indicated by primitive function %p - %hs\n", pftab[pfnum].pfbase.handler, pftab[pfnum].name); @@ -3971,61 +3975,56 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs) else { moo->errnum = MOO_EINVAL; - MOO_DEBUG1 (moo, "Cannot call primitive numbered %zd - invalid number\n", pfnum); + MOO_DEBUG1 (moo, "Cannot call primitive function numbered %zd - invalid number\n", pfnum); } - moo->processor->active->perr = MOO_ERROR_TO_OOP(moo->errnum); goto activate_primitive_method_body; } case MOO_METHOD_PREAMBLE_NAMED_PRIMITIVE: { moo_ooi_t pf_name_index; - moo_oop_t name; moo_pfbase_t* pfbase; + moo_oop_t pfname; moo_oow_t w; stack_base = moo->sp - nargs - 1; /* stack base before receiver and arguments */ - #if !defined(NDEBUG) + /* index to the primitive function identifier in the literal frame */ pf_name_index = MOO_METHOD_GET_PREAMBLE_INDEX(preamble); - LOG_INST_1 (moo, "preamble_named_primitive %zd", pf_name_index); MOO_ASSERT (moo, pf_name_index >= 0); + pfname = method->slot[pf_name_index]; - name = method->slot[pf_name_index]; - MOO_ASSERT (moo, MOO_OBJ_IS_CHAR_POINTER(name)); - MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_EXTRA(name)); - MOO_ASSERT (moo, MOO_CLASSOF(moo,name) == moo->_symbol); + #if !defined(NDEBUG) + LOG_INST_1 (moo, "preamble_named_primitive %zd", pf_name_index); + MOO_ASSERT (moo, MOO_OBJ_IS_CHAR_POINTER(pfname)); + MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_EXTRA(pfname)); + MOO_ASSERT (moo, MOO_CLASSOF(moo,pfname) == moo->_symbol); #endif /* merge two SmallIntegers to get a full pointer from the cached data */ w = (moo_oow_t)MOO_OOP_TO_SMOOI(method->preamble_data[0]) << (MOO_OOW_BITS / 2) | (moo_oow_t)MOO_OOP_TO_SMOOI(method->preamble_data[1]); pfbase = (moo_pfbase_t*)w; - if (pfbase) goto exec_handler; + if (pfbase) goto exec_handler; /* skip moo_querymod() */ - #if defined(NDEBUG) - pf_name_index = MOO_METHOD_GET_PREAMBLE_INDEX(preamble); - name = method->slot[pf_name_index]; - #endif - - pfbase = moo_querymod (moo, MOO_OBJ_GET_CHAR_SLOT(name), MOO_OBJ_GET_SIZE(name)); + pfbase = moo_querymod (moo, MOO_OBJ_GET_CHAR_SLOT(pfname), MOO_OBJ_GET_SIZE(pfname)); if (pfbase) { int n; - if (nargs < pfbase->minargs || nargs > pfbase->maxargs) - { - MOO_DEBUG5 (moo, "Soft failure due to argument count mismatch for primitive function %.*js - %zu-%zu expected, %zu given\n", - MOO_OBJ_GET_SIZE(name), MOO_OBJ_GET_CHAR_SLOT(name), pfbase->minargs, pfbase->maxargs, nargs); - goto activate_primitive_method_body; - } - /* split a pointer to two OOP fields as SmallIntegers for storing/caching. */ method->preamble_data[0] = MOO_SMOOI_TO_OOP((moo_oow_t)pfbase >> (MOO_OOW_BITS / 2)); method->preamble_data[1] = MOO_SMOOI_TO_OOP((moo_oow_t)pfbase & MOO_LBMASK(moo_oow_t, MOO_OOW_BITS / 2)); exec_handler: + if (nargs < pfbase->minargs || nargs > pfbase->maxargs) + { + MOO_DEBUG5 (moo, "Soft failure due to argument count mismatch for primitive function %.*js - %zu-%zu expected, %zu given\n", + MOO_OBJ_GET_SIZE(pfname), MOO_OBJ_GET_CHAR_SLOT(pfname), pfbase->minargs, pfbase->maxargs, nargs); + goto activate_primitive_method_body; + } + moo_pushtmp (moo, (moo_oop_t*)&method); /* the primitive handler is executed without activating the method itself. @@ -4039,21 +4038,31 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs) moo_poptmp (moo); if (n <= MOO_PF_HARD_FAILURE) { - MOO_DEBUG4 (moo, "Hard failure indicated by primitive function %p - %.*js - return code %d\n", pfbase->handler, MOO_OBJ_GET_SIZE(name), ((moo_oop_char_t)name)->slot, n); + MOO_DEBUG4 (moo, "Hard failure indicated by primitive function %p - %.*js - return code %d\n", pfbase->handler, MOO_OBJ_GET_SIZE(pfname), MOO_OBJ_GET_CHAR_SLOT(pfname), n); return -1; /* hard primitive failure */ } if (n >= MOO_PF_SUCCESS) break; /* primitive ok*/ /* soft primitive failure */ - MOO_DEBUG3 (moo, "Soft failure indicated by primitive function %p - %.*js\n", pfbase->handler, MOO_OBJ_GET_SIZE(name), ((moo_oop_char_t)name)->slot); + MOO_DEBUG3 (moo, "Soft failure indicated by primitive function %p - %.*js\n", pfbase->handler, MOO_OBJ_GET_SIZE(pfname), MOO_OBJ_GET_CHAR_SLOT(pfname)); } else { /* no handler found */ - MOO_DEBUG2 (moo, "Soft failure for non-existent primitive function - %.*js\n", MOO_OBJ_GET_SIZE(name), ((moo_oop_char_t)name)->slot); + MOO_DEBUG2 (moo, "Soft failure for non-existent primitive function - %.*js\n", MOO_OBJ_GET_SIZE(pfname), MOO_OBJ_GET_CHAR_SLOT(pfname)); } activate_primitive_method_body: + if (MOO_METHOD_GET_PREAMBLE_FLAGS(preamble) & MOO_METHOD_PREAMBLE_FLAG_LENIENT) + { + /* convert a soft failure to error return */ + moo->sp = stack_base; + MOO_STACK_PUSH (moo, MOO_ERROR_TO_OOP(moo->errnum)); + break; + } + + moo->processor->active->perr = MOO_ERROR_TO_OOP(moo->errnum); + #if defined(MOO_USE_METHOD_TRAILER) MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_TRAILER(method)); if (MOO_METHOD_GET_CODE_SIZE(method) == 0) /* this trailer size field not a small integer */ @@ -4062,17 +4071,19 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs) #endif { /* no byte code to execute - make it a hard failure */ -/* TODO: what is the best tactics? emulate "self primitiveFailed"? or should this be generated by the compiler */ +/* TODO: what is the best tactics? emulate "self primitiveFailed"? or should this be generated by the compiler + * the compiler produces no code for the body of a method(#primitive). so it will reach here if it fails when executed. */ MOO_DEBUG0 (moo, "Empty primitive body\n"); + moo->sp = stack_base; /* force restore stack pointer */ MOO_STACK_PUSH (moo, moo->_nil); + + /* i assume that the failed primitive handler function set the error number. + * so i don't set it here */ return -1; } - else - { - if (activate_new_method (moo, method, nargs) <= -1) return -1; - } + if (activate_new_method (moo, method, nargs) <= -1) return -1; break; } diff --git a/moo/lib/gc.c b/moo/lib/gc.c index 91db74d..f37b06a 100644 --- a/moo/lib/gc.c +++ b/moo/lib/gc.c @@ -204,14 +204,14 @@ static int ignite_1 (moo_t* moo) MOO_CLASS_SELFSPEC_FLAG_FINAL | MOO_CLASS_SELFSPEC_FLAG_LIMITED, 0, MOO_CLASS_SPEC_MAKE(MOO_PROCESS_SCHEDULER_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP)); - moo->_error_class = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); + moo->_error_class = alloc_kernel_class (moo, MOO_CLASS_SELFSPEC_FLAG_LIMITED, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); moo->_true_class = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); moo->_false_class = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); /* TOOD: what is a proper spec for Character and SmallInteger? * If the fixed part is 0, its instance must be an object of 0 payload fields. * Does this make sense? */ - moo->_character = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); - moo->_small_integer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); + moo->_character = alloc_kernel_class (moo, MOO_CLASS_SELFSPEC_FLAG_LIMITED, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); + moo->_small_integer = alloc_kernel_class (moo, MOO_CLASS_SELFSPEC_FLAG_LIMITED, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); moo->_large_positive_integer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, MOO_CLASS_SPEC_FLAG_INDEXED | MOO_CLASS_SPEC_FLAG_IMMUTABLE, MOO_OBJ_TYPE_LIWORD)); moo->_large_negative_integer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, MOO_CLASS_SPEC_FLAG_INDEXED | MOO_CLASS_SPEC_FLAG_IMMUTABLE, MOO_OBJ_TYPE_LIWORD)); diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index c4936d8..062e51e 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -512,6 +512,7 @@ struct moo_compiler_t { moo_method_type_t type; int primitive; /* true if method(#primitive) */ + int lenient; /* method source text */ moo_oocs_t text; diff --git a/moo/lib/moo.h b/moo/lib/moo.h index d4e0528..e3cc941 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -586,7 +586,7 @@ struct moo_method_t #endif /* The preamble field is composed of: - * 3-bit flag + * 4-bit flag * 5-bit code (0 to 31) * 16-bit index * @@ -607,11 +607,11 @@ struct moo_method_t * 13 - ensure block */ -/* NOTE: changing preamble code bit structure requires changes to CompiledMethod>>preambleCode */ -#define MOO_METHOD_MAKE_PREAMBLE(code,index,flags) ((((moo_ooi_t)index) << 8) | ((moo_ooi_t)code << 3) | flags) -#define MOO_METHOD_GET_PREAMBLE_CODE(preamble) ((((moo_ooi_t)preamble) & 0xFF) >> 3) -#define MOO_METHOD_GET_PREAMBLE_INDEX(preamble) (((moo_ooi_t)preamble) >> 8) -#define MOO_METHOD_GET_PREAMBLE_FLAGS(preamble) (((moo_ooi_t)preamble) & 0x7) +/* [NOTE] changing preamble code bit structure requires changes to CompiledMethod>>preambleCode */ +#define MOO_METHOD_MAKE_PREAMBLE(code,index,flags) ((((moo_ooi_t)index) << 9) | ((moo_ooi_t)code << 4) | flags) +#define MOO_METHOD_GET_PREAMBLE_CODE(preamble) ((((moo_ooi_t)preamble) >> 4) & 0x1F) +#define MOO_METHOD_GET_PREAMBLE_INDEX(preamble) (((moo_ooi_t)preamble) >> 9) +#define MOO_METHOD_GET_PREAMBLE_FLAGS(preamble) (((moo_ooi_t)preamble) & 0xF) /* preamble codes */ #define MOO_METHOD_PREAMBLE_NONE 0 @@ -636,9 +636,10 @@ struct moo_method_t #define MOO_OOI_IN_METHOD_PREAMBLE_INDEX_RANGE(num) ((num) >= MOO_METHOD_PREAMBLE_INDEX_MIN && (num) <= MOO_METHOD_PREAMBLE_INDEX_MAX) /* preamble flags */ -#define MOO_METHOD_PREAMBLE_FLAG_VARIADIC (1 << 0) -#define MOO_METHOD_PREAMBLE_FLAG_LIBERAL (1 << 1) +#define MOO_METHOD_PREAMBLE_FLAG_VARIADIC (1 << 0) /* allows variable arguments. but all named paramenters must be passed in */ +#define MOO_METHOD_PREAMBLE_FLAG_LIBERAL (1 << 1) /* not all named parameters need to get passed in */ #define MOO_METHOD_PREAMBLE_FLAG_DUAL (1 << 2) +#define MOO_METHOD_PREAMBLE_FLAG_LENIENT (1 << 3) /* lenient primitive method - no exception upon failure. return an error instead */ /* NOTE: if you change the number of instance variables for moo_context_t, * you need to change the defintion of BlockContext and MethodContext.