diff --git a/moo/kernel/Apex.moo b/moo/kernel/Apex.moo index d853c26..d92f7c7 100644 --- a/moo/kernel/Apex.moo +++ b/moo/kernel/Apex.moo @@ -61,23 +61,30 @@ extend Apex } ## ------------------------------------------------------- + ## INSTANTIATION & INITIALIZATION ## ------------------------------------------------------- - - method(#class) __trailer_size - { - ^0 - } - method(#class) basicNew { + | perr | + self primitiveFailed. + + ## perr := thisProcess primError. + ## if (perr == xxxx) { self cannotInstantiate } + ## else { self primitiveFailed }. } method(#class) basicNew: size { + | perr | + self primitiveFailed. + + ## perr := thisProcess primError. + ## if (perr == xxxx) { self cannotInstantiate } + ## else { self primitiveFailed }. } method(#class) ngcNew @@ -183,39 +190,10 @@ extend Apex else { self primitiveFailed } } - (* - method(#class) basicAt: index - { - | perr | - - - perr := thisProcess primError. - if (perr == Error.Code.ERANGE) { self index: index outOfRange: (self basicSize) } - elsif (perr == Error.Code.EPERM) { self messageProhibited: #basicAt:put: } - else { self primitiveFailed } - } - - method(#dual) basicAt: index put: anObject - { - | perr | - - - perr := thisProcess primError. - if (perr == Error.Code.ERANGE) { self index: index outOfRange: (self basicSize) } - elsif (perr == Error.Code.EPERM) { self messageProhibited: #basicAt:put: } - else { self primitiveFailed } - }*) - (* ------------------------------------------------------------------ * HASHING * ------------------------------------------------------------------ *) - method hash - { - - self subclassResponsibility: #hash - } - - method(#class) hash + method(#dual) hash { self subclassResponsibility: #hash @@ -225,7 +203,7 @@ extend Apex * IDENTITY TEST * ------------------------------------------------------------------ *) - method == anObject + method(#dual) == anObject { (* check if the receiver is identical to anObject. * this doesn't compare the contents *) @@ -233,21 +211,7 @@ extend Apex self primitiveFailed. } - method ~~ anObject - { - - ^(self == anObject) not. - } - - method(#class) == anObject - { - (* check if the receiver is identical to anObject. - * this doesn't compare the contents *) - - self primitiveFailed. - } - - method(#class) ~~ anObject + method(#dual) ~~ anObject { ^(self == anObject) not. @@ -256,76 +220,42 @@ extend Apex (* ------------------------------------------------------------------ * EQUALITY TEST * ------------------------------------------------------------------ *) - method = anObject + method(#dual) = anObject { self subclassResponsibility: #= } - method ~= anObject + method(#dual) ~= anObject { ^(self = anObject) not. } - method(#class) = anObject - { - - self subclassResponsibility: #= - } - - method(#class) ~= anObject - { - - ^(self = anObject) not. - } - + (* ------------------------------------------------------------------ * COMMON QUERIES * ------------------------------------------------------------------ *) - method isNil + method(#dual) isNil { "^self == nil." ^false } - method notNil + method(#dual) notNil { "^(self == nil) not" "^self ~= nil." ^true. } - method(#class) isNil - { - "^self == nil." - ^false - } - - method(#class) notNil - { - "^(self == nil) not" - "^self ~= nil." - ^true. - } - - method isError + method(#dual) isError { ^false } - method(#class) isError - { - ^false - } - - method notError - { - ^true - } - - method(#class) notError + method(#dual) notError { ^true } @@ -371,13 +301,7 @@ extend Apex ## ------------------------------------------------------- ## ------------------------------------------------------- - method(#class) respondsTo: selector - { - - self primitiveFailed - } - - method respondsTo: selector + method(#dual) respondsTo: selector { self primitiveFailed @@ -386,61 +310,32 @@ extend Apex ## ------------------------------------------------------- ## ------------------------------------------------------- - method(#class,#variadic) perform(selector) + method(#dual,#variadic) perform(selector) { self primitiveFailed } - method(#variadic) perform(selector) + method(#dual) perform: selector { self primitiveFailed } - method(#class) perform: selector - { - - self primitiveFailed - } - - method perform: selector + + method(#dual) perform: selector with: arg1 { self primitiveFailed } - method(#class) perform: selector with: arg1 + method(#dual) perform: selector with: arg1 with: arg2 { self primitiveFailed } - method perform: selector with: arg1 - { - - self primitiveFailed - } - - method(#class) perform: selector with: arg1 with: arg2 - { - - self primitiveFailed - } - - method perform: selector with: arg1 with: arg2 - { - - self primitiveFailed - } - - method(#class) perform: selector with: arg1 with: arg2 with: arg3 - { - - self primitiveFailed - } - - method perform: selector with: arg1 with: arg2 with: arg3 + method(#dual) perform: selector with: arg1 with: arg2 with: arg3 { self primitiveFailed @@ -458,57 +353,12 @@ extend Apex (* ------------------------------------------------------------------ * COMMON ERROR/EXCEPTION HANDLERS * ------------------------------------------------------------------ *) - method primitiveFailed - { - ^self class primitiveFailed. - } - - method cannotInstantiate - { - ^self class cannotInstantiate - } - - method doesNotUnderstand: messageSymbol - { - ^self class doesNotUnderstand: messageSymbol - } - - method index: index outOfRange: ubound - { - ^self class index: index outOfRange: ubound. - } - - method subclassResponsibility: method_name - { - ^self class subclassResponsibility: method_name - } - - method notImplemented: method_name - { - ^self class notImplemented: method_name - } - - method messageProhibited: method_name - { - ^self class messageProhibited: method_name - } - - method cannotExceptionizeError - { - ^self class cannotExceptionizeError - } - - method(#class) error: msgText + method(#dual) error: msgText { (* TODO: implement this Error signal: msgText. *) msgText dump. } - - method error: aString - { - self class error: aString. - } } class Object(Apex) diff --git a/moo/kernel/Except.moo b/moo/kernel/Except.moo index ddff414..cdf15a2 100644 --- a/moo/kernel/Except.moo +++ b/moo/kernel/Except.moo @@ -33,39 +33,51 @@ class Exception(Apex) ^(self class name) & ' - ' & self.messageText. } + (* TODO: remove this.... method __signal { self.signalContext := thisContext. ((thisContext sender) findExceptionContext) handleException: self. - } + }*) method signal { - | exctx exblk retval actpos | + | exctx exblk retval actpos ctx | self.signalContext := thisContext. exctx := (thisContext sender) findExceptionContext. - [exctx notNil] whileTrue: [ + + ##[exctx notNil] whileTrue: [ + while (exctx notNil) + { exblk := exctx findExceptionHandlerFor: (self class). - (exblk notNil and: - [actpos := exctx basicSize - 1. exctx basicAt: actpos]) ifTrue: [ + if (exblk notNil and: + [actpos := exctx basicSize - 1. exctx basicAt: actpos]) + { self.handlerContext := exctx. exctx basicAt: actpos put: false. - [ retval := exblk value: self ] ensure: [ - exctx basicAt: actpos put: true - ]. - + [ retval := exblk value: self ] ensure: [ exctx basicAt: actpos put: true ]. thisContext unwindTo: (exctx sender) return: nil. Processor return: retval to: (exctx sender). - ]. + }. exctx := (exctx sender) findExceptionContext. - ]. + }. ## ----------------------------------------------------------------- ## FATAL ERROR - no exception handler. ## ----------------------------------------------------------------- ##thisContext unwindTo: nil return: nil. ##thisContext unwindTo: (Processor activeProcess initialContext) return: nil. + +## TOOD: IMPROVE THIS EXPERIMENTAL BACKTRACE... +ctx := thisContext. +while (ctx notNil) +{ + if (ctx class == MethodContext) { (ctx method owner name & '>>' & ctx method name) dump }. + ## TODO: include blockcontext??? + ctx := ctx sender. +}. + thisContext unwindTo: (thisProcess initialContext) return: nil. ('### EXCEPTION NOT HANDLED #### ' & self class name & ' - ' & self messageText) dump. ## TODO: debug the current process???? " @@ -88,31 +100,31 @@ class Exception(Apex) method return: value { - (self.handlerContext notNil) ifTrue: [ - Processor return: value to: self.handlerContext. - ]. + if (self.handlerContext notNil) { Processor return: value to: self.handlerContext } } method retry { ## TODO: verify if return:to: causes unnecessary stack growth. - (self.handlerContext notNil) ifTrue: [ + if (self.handlerContext notNil) + { self.handlerContext pc: 0. Processor return: self to: self.handlerContext. - ]. + } } method resume: value { ## TODO: verify if return:to: causes unnecessary stack growth. ## is this correct??? - (self.signalContext notNil and: [self.handlerContext notNil]) ifTrue: [ - | ctx | + | ctx | + if (self.signalContext notNil and: [self.handlerContext notNil]) + { ctx := self.signalContext sender. self.signalContext := nil. self.handlerContext := nil. Processor return: value to: ctx. - ]. + }. } method resume @@ -143,10 +155,11 @@ extend Context { | ctx | ctx := self. - [ ctx notNil ] whileTrue: [ - (ctx isExceptionContext) ifTrue: [^ctx]. + while (ctx notNil) + { + if (ctx isExceptionContext) { ^ctx }. ctx := ctx sender. - ]. + }. ^nil } @@ -157,26 +170,29 @@ extend Context ## private: called by VM upon unwinding ## ------------------------------------------------------------------- - | ctx stop | + | ctx stop eb pending_pos | ctx := self. stop := false. - [stop] whileFalse: [ - | eb | + until (stop) + { eb := ctx ensureBlock. - (eb notNil) ifTrue: [ - | donepos | - donepos := ctx basicSize - 1. - (ctx basicAt: donepos) ifFalse: [ - ctx basicAt: donepos put: true. + if (eb notNil) + { + (* position of the temporary variable in the ensureBlock that indicates + * if the block has been evaluated *) + pending_pos := ctx basicSize - 1. + if (ctx basicAt: pending_pos) + { + ctx basicAt: pending_pos put: false. eb value. - ]. - ]. + } + }. stop := (ctx == context). ctx := ctx sender. ## stop ifFalse: [ stop := ctx isNil ]. - ]. + }. ^retval } @@ -207,9 +223,7 @@ extend MethodContext * instance variables of the method context. As MethodContex has * 8 instance variables, the ensure block must be at the 9th position * which translates to index 8 *) - - (self.method preambleCode == 13) ifFalse: [^nil]. - ^self basicAt: 8. + ^if (self.method preambleCode == 13) { self basicAt: 8 } else { nil } } @@ -226,9 +240,10 @@ extend MethodContext ## TODO: change 8 to a constant when moo is enhanced to support constant definition ## or calcuate the minimum size using the class information. - (self isExceptionContext) ifTrue: [ - | size exc | - + | size exc | + + if (self isExceptionContext) + { (* NOTE: the following loop scans all parameters to the on:do: method. * if the on:do: method contains local temporary variables, * those must be skipped from scanning. *) @@ -236,9 +251,9 @@ extend MethodContext size := self basicSize. 8 priorTo: size by: 2 do: [ :i | exc := self basicAt: i. - ((exception_class == exc) or: [exception_class inheritsFrom: exc]) ifTrue: [^self basicAt: (i + 1)]. + if ((exception_class == exc) or: [exception_class inheritsFrom: exc]) { ^self basicAt: (i + 1) }. ] - ]. + }. ^nil. } @@ -261,12 +276,13 @@ extend MethodContext actpos := (self basicSize) - 1. excblk := self findExceptionHandlerFor: (exception class). - (excblk isNil or: [(self basicAt: actpos) not]) ifTrue: [ + if (excblk isNil or: [(self basicAt: actpos) not]) + { ## self is an exception context but doesn't have a matching ## exception handler or the exception context is already ## in the middle of evaluation. ^(self.sender findExceptionContext) handleException: exception. - ]. + }. exception handlerContext: self. @@ -324,27 +340,24 @@ thisContext isExceptionContext dump. method ensure: aBlock { - | retval done | + | retval pending | - done := false. + pending := true. retval := self value. - ## the temporary variable 'done' may get changed - ## during evaluation for exception handling. - done ifFalse: [ - done := true. - aBlock value. - ]. + (* the temporary variable 'pending' may get changed + * during evaluation for exception handling. + * it gets chagned in Context>>unwindTo:return: *) + if (pending) { pending := false. aBlock value }. ^retval } method ifCurtailed: aBlock { - | v ok | - - ok := false. - [ v := self value. ok := true. ] ensure: [ ok ifFalse: [aBlock value] ]. + | v pending | + pending := true. + [ v := self value. pending := false. ] ensure: [ if (pending) { aBlock value } ]. ^v. } } @@ -389,55 +402,50 @@ class ProhibitedMessageException(Exception) extend Apex { - method(#class) primitiveFailed + method(#dual) primitiveFailed { - ## TODO: implement this -## experimental backtrace... -| ctx | -ctx := thisContext. -[ctx notNil] whileTrue: [ - (ctx class == MethodContext) - ifTrue: [ (ctx method owner name & '>>' & ctx method name) dump ]. - ## TODO: include blockcontext??? - ctx := ctx sender. -]. -'------ END OF BACKTRACE -----------' dump. PrimitiveFailureException signal: 'PRIMITIVE FAILED'. } - method(#class) cannotInstantiate + method(#dual) cannotInstantiate { -## TOOD: accept a class - InstantiationFailureException signal: 'Cannot instantiate'. + ## TODO: use displayString or something like that instead of name.... + InstantiationFailureException signal: 'Cannot instantiate ' & (self name). } - method(#class) doesNotUnderstand: message_name + method(#dual) doesNotUnderstand: message_name { ## TODO: implement this properly - NoSuchMessageException signal: (message_name & ' not understood by ' & (self name)). + | class_name | + class_name := if (self class == Class) { self name } else { self class name }. + NoSuchMessageException signal: (message_name & ' not understood by ' & class_name). } - method(#class) index: index outOfRange: ubound + method(#dual) index: index outOfRange: ubound { IndexOutOfRangeException signal: 'Out of range'. } - method(#class) subclassResponsibility: method_name + method(#dual) subclassResponsibility: method_name { SubclassResponsibilityException signal: ('Subclass must implement ' & method_name). } - method(#class) notImplemented: method_name + method(#dual) notImplemented: method_name { - NotImplementedException signal: (method_name & ' not implemented by ' & (self name)). + | class_name | + class_name := if (self class == Class) { self name } else { self class name }. + NotImplementedException signal: (method_name & ' not implemented by ' & class_name). } - method(#class) messageProhibited: method_name + method(#dual) messageProhibited: method_name { - ProhibitedMessageException signal: (method_name & ' not allowed for ' & (self name)). + | class_name | + class_name := if (self class == Class) { self name } else { self class name }. + ProhibitedMessageException signal: (method_name & ' not allowed for ' & class_name). } - method(#class) cannotExceptionizeError + method(#dual) cannotExceptionizeError { ## todo: accept the object ErrorExceptionizationFailureException signal: 'Cannot exceptionize an error' diff --git a/moo/kernel/Process.moo b/moo/kernel/Process.moo index c6a841a..6d50d61 100644 --- a/moo/kernel/Process.moo +++ b/moo/kernel/Process.moo @@ -3,10 +3,16 @@ class(#pointer) Process(Object) { var initial_context, current_context, state, sp, prev, next, sem, perr. - method new + method(#class) basicNew { - "instantiation is not allowed" - ^nil. "TODO: raise an exception or return an error" + (* instantiation is not allowed. a process is strictly a VM managed object *) + self cannotInstantiate + } + + method(#class) basicNew: size + { + (* instantiation is not allowed. a process is strictly a VM managed object *) + self cannotInstantiate } method prev { ^self.prev } diff --git a/moo/lib/comp.c b/moo/lib/comp.c index dbc0af3..88f0c74 100644 --- a/moo/lib/comp.c +++ b/moo/lib/comp.c @@ -120,6 +120,7 @@ static struct voca_t { 11, { 't','h','i','s','C','o','n','t','e','x','t' } }, { 11, { 't','h','i','s','P','r','o','c','e','s','s' } }, { 4, { 't','r','u','e' } }, + { 5, { 'u','n','t','i','l' } }, { 3, { 'v','a','r' } }, { 8, { 'v','a','r','i','a','b','l','e' } }, { 9, { '#','v','a','r','i','a','d','i','c' } }, @@ -175,6 +176,7 @@ enum voca_id_t VOCA_THIS_CONTEXT, VOCA_THIS_PROCESS, VOCA_TRUE, + VOCA_UNTIL, VOCA_VAR, VOCA_VARIABLE, VOCA_VARIADIC_S, @@ -318,6 +320,7 @@ static int is_reserved_word (const moo_oocs_t* ucs) VOCA_ELSE, VOCA_ELSIF, VOCA_WHILE, + VOCA_UNTIL, VOCA_DO, VOCA_BREAK, VOCA_CONTINUE @@ -1126,6 +1129,10 @@ static int get_ident (moo_t* moo, moo_ooci_t char_read_ahead) { SET_TOKEN_TYPE (moo, MOO_IOTOK_WHILE); } + else if (is_token_word(moo, VOCA_UNTIL)) + { + SET_TOKEN_TYPE (moo, MOO_IOTOK_UNTIL); + } else if (is_token_word(moo, VOCA_DO)) { SET_TOKEN_TYPE (moo, MOO_IOTOK_DO); @@ -2051,7 +2058,6 @@ static int emit_single_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1 case BCODE_JUMP_FORWARD_0: case BCODE_JUMP_BACKWARD_0: - case BCODE_JUMP_FORWARD_IF_FALSE_0: case BCODE_JUMP_BACKWARD_IF_FALSE_0: case BCODE_JUMP_BACKWARD_IF_TRUE_0: if (param_1 < 4) @@ -2072,11 +2078,24 @@ static int emit_single_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1 goto write_long; } + case BCODE_JUMP_BACKWARD_X: + case BCODE_JUMP_BACKWARD_IF_FALSE_X: + case BCODE_JUMP_BACKWARD_IF_TRUE_X: + case BCODE_JUMP_FORWARD_X: + case BCODE_JUMP_FORWARD_IF_FALSE: + case BCODE_JUMP_FORWARD_IF_TRUE: + if (param_1 > MAX_CODE_JUMP) + { + cmd = cmd + 1; /* convert to a JUMP2 instruction */ + param_1 = param_1 - MAX_CODE_JUMP; + } + /* fall thru */ case BCODE_JUMP2_FORWARD: case BCODE_JUMP2_BACKWARD: - case BCODE_JUMP2_FORWARD_IF_FALSE: case BCODE_JUMP2_BACKWARD_IF_FALSE: case BCODE_JUMP2_BACKWARD_IF_TRUE: + case BCODE_JUMP2_FORWARD_IF_FALSE: + case BCODE_JUMP2_FORWARD_IF_TRUE: case BCODE_PUSH_INTLIT: case BCODE_PUSH_NEGINTLIT: case BCODE_PUSH_CHARLIT: @@ -2237,12 +2256,11 @@ static MOO_INLINE int emit_backward_jump_instruction (moo_t* moo, int cmd, moo_o * instruction, which result in 1, 2, 3 when combined with the length 1 * of the instruction itself */ - adj = (offset < 3)? 1: (MOO_BCODE_LONG_PARAM_SIZE + 1); return emit_single_param_instruction (moo, cmd, offset + adj); } -static int patch_long_forward_jump_instruction (moo_t* moo, moo_oow_t jip, moo_oow_t jt, moo_oob_t jump2_inst, moo_ioloc_t* errloc) +static int patch_long_forward_jump_instruction (moo_t* moo, moo_oow_t jip, moo_oow_t jt, moo_ioloc_t* errloc) { moo_oow_t code_size; moo_oow_t jump_offset; @@ -2261,11 +2279,15 @@ static int patch_long_forward_jump_instruction (moo_t* moo, moo_oow_t jip, moo_o return -1; } + MOO_ASSERT (moo, moo->c->mth.code.ptr[jip] == BCODE_JUMP_FORWARD_X || + moo->c->mth.code.ptr[jip] == BCODE_JUMP_FORWARD_IF_FALSE || + moo->c->mth.code.ptr[jip] == BCODE_JUMP_FORWARD_IF_TRUE); + if (code_size > MAX_CODE_JUMP) { /* switch to JUMP2 instruction to allow a bigger jump offset. * up to twice MAX_CODE_JUMP only */ - moo->c->mth.code.ptr[jip] = jump2_inst; + moo->c->mth.code.ptr[jip]++; /* switch to the JUMP2 instruction */ jump_offset = code_size - MAX_CODE_JUMP; } else @@ -2311,7 +2333,7 @@ static int update_loop_jumps (moo_t* moo, moo_oow_pool_t* pool, moo_oow_t jt) for (j = 0; j < MOO_COUNTOF(pool->static_chunk.buf) && i < pool->count; j++) { if (chunk->buf[j] != INVALID_IP && - patch_long_forward_jump_instruction (moo, chunk->buf[j], jt, BCODE_JUMP2_FORWARD, MOO_NULL) <= -1) return -1; + patch_long_forward_jump_instruction (moo, chunk->buf[j], jt, MOO_NULL) <= -1) return -1; i++; } } @@ -2402,12 +2424,13 @@ static MOO_INLINE int inject_break_to_loop (moo_t* moo) static MOO_INLINE int inject_continue_to_loop (moo_t* moo) { + /* used for a do-while loop. jump forward because the conditional + * is at the end of the do-while loop */ if (add_to_oow_pool (moo, &moo->c->mth.loop->continue_ip_pool, moo->c->mth.code.len) <= -1 || emit_single_param_instruction (moo, BCODE_JUMP_FORWARD_0, MAX_CODE_JUMP) <= -1) return -1; return 0; } - static void eliminate_instructions (moo_t* moo, moo_oow_t start, moo_oow_t end) { moo_oow_t last; @@ -2547,7 +2570,8 @@ static int set_class_level_variable_initv (moo_t* moo, var_type_t var_type, moo_ { if (var_index >= moo->c->cls.var[var_type].initv_capa) { - moo_oow_t newcapa, oldcapa, i; + moo_oow_t newcapa, oldcapa; + /*moo_oow_t i;*/ moo_oop_t* tmp; oldcapa = moo->c->cls.var[var_type].initv_capa; @@ -4151,7 +4175,7 @@ static int compile_block_expression (moo_t* moo) if (emit_byte_instruction(moo, BCODE_RETURN_FROM_BLOCK) <= -1) return -1; - if (patch_long_forward_jump_instruction (moo, jump_inst_pos, moo->c->mth.code.len, BCODE_JUMP2_FORWARD, &block_loc) <= -1) return -1; + if (patch_long_forward_jump_instruction (moo, jump_inst_pos, moo->c->mth.code.len, &block_loc) <= -1) return -1; /* restore the temporary count */ moo->c->mth.tmprs.len = saved_tmprs_len; @@ -5172,7 +5196,7 @@ static int compile_if_expression (moo_t* moo) precondpos = moo->c->mth.code.len; if (jumptonext != INVALID_IP && - patch_long_forward_jump_instruction (moo, jumptonext, precondpos, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; + patch_long_forward_jump_instruction (moo, jumptonext, precondpos, &brace_loc) <= -1) goto oops; if (compile_conditional(moo) <= -1) goto oops; postcondpos = moo->c->mth.code.len; @@ -5197,9 +5221,9 @@ static int compile_if_expression (moo_t* moo) { /* remember position of the jump_forward_if_false instruction to be generated */ jumptonext = moo->c->mth.code.len; - /* specifying MAX_CODE_JUMP causes emit_single_param_instruction() to - * produce the long jump instruction (BCODE_JUMP_FORWARD_X) */ - if (emit_single_param_instruction (moo, BCODE_JUMP_FORWARD_IF_FALSE_0, MAX_CODE_JUMP) <= -1) goto oops; + /* BCODE_JUMP_FORWARD_IF_FALSE is always a long jump instruction. + * just specify MAX_CODE_JUMP for consistency with short jump variants */ + if (emit_single_param_instruction (moo, BCODE_JUMP_FORWARD_IF_FALSE, MAX_CODE_JUMP) <= -1) goto oops; } GET_TOKEN (moo); /* get { */ @@ -5210,7 +5234,7 @@ static int compile_if_expression (moo_t* moo) { if (falseblock) { - /* the conditional was false. elimiate instructions emitted + /* the conditional was false. eliminate instructions emitted * for the block attached to the conditional */ eliminate_instructions (moo, precondpos, moo->c->mth.code.len - 1); postcondpos = precondpos; @@ -5235,7 +5259,7 @@ static int compile_if_expression (moo_t* moo) } while (TOKEN_TYPE(moo) == MOO_IOTOK_ELSIF); if (jumptonext != INVALID_IP && - patch_long_forward_jump_instruction (moo, jumptonext, moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; + patch_long_forward_jump_instruction (moo, jumptonext, moo->c->mth.code.len, &brace_loc) <= -1) goto oops; if (TOKEN_TYPE(moo) == MOO_IOTOK_ELSE) { @@ -5263,7 +5287,7 @@ static int compile_if_expression (moo_t* moo) * call will never flood either. */ for (j = 0; j < MOO_COUNTOF(jumptoend.static_chunk.buf) && i < jumptoend.count; j++) { - if (patch_long_forward_jump_instruction (moo, jumptoend_chunk->buf[j], moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &if_loc) <= -1) goto oops; + if (patch_long_forward_jump_instruction (moo, jumptoend_chunk->buf[j], moo->c->mth.code.len, &if_loc) <= -1) goto oops; i++; } } @@ -5276,13 +5300,15 @@ oops: return -1; } -static int compile_while_expression (moo_t* moo) +static int compile_while_expression (moo_t* moo) /* or compile_until_expression */ { moo_ioloc_t while_loc, brace_loc; moo_oow_t precondpos, postcondpos, prebbpos, postbbpos; - int cond_style = 0, loop_pushed = 0; + int cond_style = 0, loop_pushed = 0, is_until_loop; - MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_WHILE); + MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_WHILE || TOKEN_TYPE(moo) == MOO_IOTOK_UNTIL); + + is_until_loop = (TOKEN_TYPE(moo) == MOO_IOTOK_UNTIL); while_loc = *TOKEN_LOC(moo); GET_TOKEN (moo); /* get (, verification is done inside compile_conditional() */ @@ -5290,32 +5316,32 @@ static int compile_while_expression (moo_t* moo) if (compile_conditional (moo) <= -1) goto oops; postcondpos = moo->c->mth.code.len; -#if 0 if (precondpos + 1 == postcondpos) { /* simple optimization - * if the conditional is known to be true, emit the absolute jump instruction. * if it is known to be false, kill all generated instructions. */ - if (moo->c->mth.code.ptr[precondpos] == BCODE_PUSH_TRUE) + if (moo->c->mth.code.ptr[precondpos] == (is_until_loop? BCODE_PUSH_FALSE: BCODE_PUSH_TRUE)) { - /* the conditional is always true */ + /* the conditional is always true for while, or false for until*/ cond_style = 1; eliminate_instructions (moo, precondpos, moo->c->mth.code.len - 1); postcondpos = precondpos; } - else if (moo->c->mth.code.ptr[precondpos] == BCODE_PUSH_FALSE) + else if (moo->c->mth.code.ptr[precondpos] == (is_until_loop? BCODE_PUSH_TRUE: BCODE_PUSH_FALSE)) { - /* the conditional is always false */ + /* the conditional is always false for while, or false for until */ cond_style = -1; } +/* TODO: at least check for some literals for optimization. + * most literal values must be evaluate to true. */ } -#endif if (cond_style != 1) { - /* specifying MAX_CODE_JUMP causes emit_single_param_instruction() to - * produce the long jump instruction (BCODE_JUMP_FORWARD_X) */ - if (emit_single_param_instruction (moo, BCODE_JUMP_FORWARD_IF_FALSE_0, MAX_CODE_JUMP) <= -1) goto oops; + /* BCODE_JUMP_FORWARD_IF_FALSE is always a long jump instruction. + * just specify MAX_CODE_JUMP for consistency with short jump variants */ + if (emit_single_param_instruction (moo, (is_until_loop? BCODE_JUMP_FORWARD_IF_TRUE: BCODE_JUMP_FORWARD_IF_FALSE), MAX_CODE_JUMP) <= -1) goto oops; } /* remember information about this while loop. */ @@ -5357,7 +5383,7 @@ static int compile_while_expression (moo_t* moo) if (cond_style != 1) { /* patch the jump instruction */ - if (patch_long_forward_jump_instruction (moo, postcondpos, moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; + if (patch_long_forward_jump_instruction (moo, postcondpos, moo->c->mth.code.len, &brace_loc) <= -1) goto oops; } if (cond_style == -1) @@ -5388,7 +5414,7 @@ static int compile_do_while_expression (moo_t* moo) { moo_ioloc_t do_loc; moo_oow_t precondpos, postcondpos, prebbpos, postbbpos; - int jbinst = 0, loop_pushed = 0; + int jbinst = 0, loop_pushed = 0, is_until_loop; moo_loop_t* loop = MOO_NULL; MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_DO); @@ -5405,7 +5431,9 @@ static int compile_do_while_expression (moo_t* moo) if (compile_braced_block(moo) <= -1) goto oops; GET_TOKEN (moo); /* get the next token after } */ - if (TOKEN_TYPE(moo) != MOO_IOTOK_WHILE) + if (TOKEN_TYPE(moo) == MOO_IOTOK_UNTIL) is_until_loop = 1; + else if (TOKEN_TYPE(moo) == MOO_IOTOK_WHILE) is_until_loop = 0; + else { set_syntax_error (moo, MOO_SYNERR_WHILE, TOKEN_LOC(moo), TOKEN_NAME(moo)); goto oops; @@ -5438,20 +5466,20 @@ static int compile_do_while_expression (moo_t* moo) if (compile_conditional (moo) <= -1) goto oops; postcondpos = moo->c->mth.code.len; - jbinst = BCODE_JUMP_BACKWARD_IF_TRUE_0; + jbinst = (is_until_loop? BCODE_JUMP_BACKWARD_IF_FALSE_0: BCODE_JUMP_BACKWARD_IF_TRUE_0); if (precondpos + 1 == postcondpos) { /* simple optimization - * if the conditional is known to be true, emit the absolute jump instruction. * if it is known to be false, kill all generated instructions. */ - if (moo->c->mth.code.ptr[precondpos] == BCODE_PUSH_TRUE) + if (moo->c->mth.code.ptr[precondpos] == (is_until_loop? BCODE_PUSH_FALSE: BCODE_PUSH_TRUE)) { /* the conditional is always true. eliminate PUSH_TRUE and emit an absolute jump */ eliminate_instructions (moo, precondpos, moo->c->mth.code.len - 1); postcondpos = precondpos; jbinst = BCODE_JUMP_BACKWARD_0; } - else if (moo->c->mth.code.ptr[precondpos] == BCODE_PUSH_FALSE) + else if (moo->c->mth.code.ptr[precondpos] == (is_until_loop? BCODE_PUSH_TRUE: BCODE_PUSH_FALSE)) { /* the conditional is always false. eliminate PUSH_FALSE and don't emit jump */ eliminate_instructions (moo, precondpos, moo->c->mth.code.len - 1); @@ -5515,7 +5543,8 @@ static int compile_method_expression (moo_t* moo, int pop) { if (compile_if_expression (moo) <= -1) return -1; } - else if (TOKEN_TYPE(moo) == MOO_IOTOK_WHILE) + else if (TOKEN_TYPE(moo) == MOO_IOTOK_WHILE || + TOKEN_TYPE(moo) == MOO_IOTOK_UNTIL) { if (compile_while_expression (moo) <= -1) return -1; } diff --git a/moo/lib/decode.c b/moo/lib/decode.c index a9b8977..7a132eb 100644 --- a/moo/lib/decode.c +++ b/moo/lib/decode.c @@ -264,17 +264,6 @@ int moo_decode (moo_t* moo, moo_oop_method_t mth, const moo_oocs_t* classfqn) LOG_INST_1 (moo, "jump_backward %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */ break; - case BCODE_JUMP_FORWARD_IF_FALSE_X: - FETCH_PARAM_CODE_TO (moo, b1); - LOG_INST_1 (moo, "jump_forward_if_false %zu", b1); - break; - - case BCODE_JUMP_FORWARD_IF_FALSE_0: - case BCODE_JUMP_FORWARD_IF_FALSE_1: - case BCODE_JUMP_FORWARD_IF_FALSE_2: - case BCODE_JUMP_FORWARD_IF_FALSE_3: - LOG_INST_1 (moo, "jump_forward_if_false %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */ - break; case BCODE_JUMP_BACKWARD_IF_FALSE_X: FETCH_PARAM_CODE_TO (moo, b1); @@ -300,6 +289,16 @@ int moo_decode (moo_t* moo, moo_oop_method_t mth, const moo_oocs_t* classfqn) LOG_INST_1 (moo, "jump_backward_if_true %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */ break; + case BCODE_JUMP_FORWARD_IF_FALSE: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump_forward_if_false %zu", b1); + break; + + case BCODE_JUMP_FORWARD_IF_TRUE: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump_forward_if_true %zu", b1); + break; + case BCODE_JUMP2_FORWARD: FETCH_PARAM_CODE_TO (moo, b1); LOG_INST_1 (moo, "jump2_forward %zu", b1); diff --git a/moo/lib/exec.c b/moo/lib/exec.c index f7ab795..ce8cbaa 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -4480,22 +4480,6 @@ int moo_execute (moo_t* moo) moo->ip -= (bcode & 0x3); /* low 2 bits */ break; - case BCODE_JUMP_FORWARD_IF_FALSE_X: - FETCH_PARAM_CODE_TO (moo, b1); - LOG_INST_1 (moo, "jump_forward_if_false %zu", b1); - if (MOO_STACK_GETTOP(moo) == moo->_false) moo->ip += b1; - MOO_STACK_POP (moo); - break; - - case BCODE_JUMP_FORWARD_IF_FALSE_0: - case BCODE_JUMP_FORWARD_IF_FALSE_1: - case BCODE_JUMP_FORWARD_IF_FALSE_2: - case BCODE_JUMP_FORWARD_IF_FALSE_3: - LOG_INST_1 (moo, "jump_forward_if_false %zu", (moo_oow_t)(bcode & 0x3)); - if (MOO_STACK_GETTOP(moo) == moo->_false) moo->ip += (bcode & 0x3); /* low 2 bits */ - MOO_STACK_POP (moo); - break; - case BCODE_JUMP_BACKWARD_IF_FALSE_X: FETCH_PARAM_CODE_TO (moo, b1); LOG_INST_1 (moo, "jump_backward_if_false %zu", b1); @@ -4530,6 +4514,21 @@ int moo_execute (moo_t* moo) MOO_STACK_POP (moo); break; + case BCODE_JUMP_FORWARD_IF_FALSE: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump_forward_if_false %zu", b1); + if (MOO_STACK_GETTOP(moo) == moo->_false) moo->ip += b1; + MOO_STACK_POP (moo); + break; + + case BCODE_JUMP_FORWARD_IF_TRUE: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump_forward_if_true %zu", b1); + /*if (MOO_STACK_GETTOP(moo) == moo->_true) moo->ip += b1;*/ + if (MOO_STACK_GETTOP(moo) != moo->_false) moo->ip += b1; + MOO_STACK_POP (moo); + break; + case BCODE_JUMP2_FORWARD: FETCH_PARAM_CODE_TO (moo, b1); LOG_INST_1 (moo, "jump2_forward %zu", b1); @@ -4549,6 +4548,14 @@ int moo_execute (moo_t* moo) MOO_STACK_POP (moo); break; + case BCODE_JUMP2_FORWARD_IF_TRUE: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump2_forward_if_true %zu", b1); + /*if (MOO_STACK_GETTOP(moo) == moo->_true) moo->ip += MAX_CODE_JUMP + b1;*/ + if (MOO_STACK_GETTOP(moo) != moo->_false) moo->ip += MAX_CODE_JUMP + b1; + MOO_STACK_POP (moo); + break; + case BCODE_JUMP2_BACKWARD_IF_FALSE: FETCH_PARAM_CODE_TO (moo, b1); LOG_INST_1 (moo, "jump2_backward_if_false %zu", b1); diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index 664d794..c96ec2d 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -334,6 +334,7 @@ struct moo_iotok_t MOO_IOTOK_ELSIF, MOO_IOTOK_WHILE, + MOO_IOTOK_UNTIL, MOO_IOTOK_DO, MOO_IOTOK_BREAK, MOO_IOTOK_CONTINUE @@ -637,10 +638,17 @@ SHORT INSTRUCTION CODE LONG INSTRUCTION C 68-71 0100 01XX JUMP_FORWARD 196 1100 0100 XXXXXXXX JUMP_FORWARD_X + 197 1000 0101 XXXXXXXX JUMP2_FORWARD 72-75 0100 10XX JUMP_BACKWARD 200 1100 1000 XXXXXXXX JUMP_BACKWARD_X + 201 1101 1001 XXXXXXXX JUMP2_BACKWARD 76-79 0100 11XX JUMP_BACKWARD_IF_FALSE 204 1100 1100 XXXXXXXX JUMP_BACKWARD_IF_FALSE_X -80-83 0101 00XX JUMP_FORWARD_IF_FALSE 208 1101 0000 XXXXXXXX JUMP_FORWARD_IF_FALSE_X -84-87 0101 01XX JUMP_FORWARD_IF_TRUE 212 1101 0100 XXXXXXXX JUMP_FORWARD_IF_TRUE_X + 205 1101 1101 XXXXXXXX JUMP2_BACKWARD_IF_FALSE +80-83 0101 00XX JUMP_BACKWARD_IF_TRUE 208 1101 0000 XXXXXXXX JUMP_BACKWARD_IF_TRUE_X + 209 1101 0001 XXXXXXXX JUMP2_FORWARD_IF_TRUE +84-87 0101 01XX UNUSED 212 1101 0100 XXXXXXXX JUMP_FORWARD_IF_FALSE + 213 1101 0101 XXXXXXXX JUMP2_FORWARD_IF_FALSE + 214 1101 0110 XXXXXXXX JUMP_FORWARD_IF_TRUE + 215 1101 0111 XXXXXXXX JUMP2_FORWARD_IF_TRUE vv 88-91 0101 10XX YYYYYYYY STORE_INTO_CTXTEMPVAR 216 1101 1000 XXXXXXXX YYYYYYYY STORE_INTO_CTXTEMPVAR_X (bit 3 on, bit 2 off) @@ -761,25 +769,22 @@ enum moo_bcode_t BCODE_JUMP_FORWARD_2 = 0x46, /* 70 */ BCODE_JUMP_FORWARD_3 = 0x47, /* 71 */ - BCODE_JUMP_BACKWARD_0 = 0x48, - BCODE_JUMP_BACKWARD_1 = 0x49, - BCODE_JUMP_BACKWARD_2 = 0x4A, - BCODE_JUMP_BACKWARD_3 = 0x4B, + BCODE_JUMP_BACKWARD_0 = 0x48, /* 72 */ + BCODE_JUMP_BACKWARD_1 = 0x49, /* 73 */ + BCODE_JUMP_BACKWARD_2 = 0x4A, /* 74 */ + BCODE_JUMP_BACKWARD_3 = 0x4B, /* 75 */ - BCODE_JUMP_FORWARD_IF_FALSE_0 = 0x4C, /* 76 */ - BCODE_JUMP_FORWARD_IF_FALSE_1 = 0x4D, /* 77 */ - BCODE_JUMP_FORWARD_IF_FALSE_2 = 0x4E, /* 78 */ - BCODE_JUMP_FORWARD_IF_FALSE_3 = 0x4F, /* 79 */ + BCODE_JUMP_BACKWARD_IF_FALSE_0 = 0x4C, /* 76 */ + BCODE_JUMP_BACKWARD_IF_FALSE_1 = 0x4D, /* 77 */ + BCODE_JUMP_BACKWARD_IF_FALSE_2 = 0x4E, /* 78 */ + BCODE_JUMP_BACKWARD_IF_FALSE_3 = 0x4F, /* 79 */ - BCODE_JUMP_BACKWARD_IF_FALSE_0 = 0x50, /* 80 */ - BCODE_JUMP_BACKWARD_IF_FALSE_1 = 0x51, /* 81 */ - BCODE_JUMP_BACKWARD_IF_FALSE_2 = 0x52, /* 82 */ - BCODE_JUMP_BACKWARD_IF_FALSE_3 = 0x53, /* 83 */ + BCODE_JUMP_BACKWARD_IF_TRUE_0 = 0x50, /* 80 */ + BCODE_JUMP_BACKWARD_IF_TRUE_1 = 0x51, /* 81 */ + BCODE_JUMP_BACKWARD_IF_TRUE_2 = 0x52, /* 82 */ + BCODE_JUMP_BACKWARD_IF_TRUE_3 = 0x53, /* 83 */ - BCODE_JUMP_BACKWARD_IF_TRUE_0 = 0x54, /* 84 */ - BCODE_JUMP_BACKWARD_IF_TRUE_1 = 0x55, /* 85 */ - BCODE_JUMP_BACKWARD_IF_TRUE_2 = 0x56, /* 86 */ - BCODE_JUMP_BACKWARD_IF_TRUE_3 = 0x57, /* 87 */ + /* UNUSED 0x54 - 0x57 */ BCODE_STORE_INTO_CTXTEMPVAR_0 = 0x58, /* 88 */ BCODE_STORE_INTO_CTXTEMPVAR_1 = 0x59, /* 89 */ @@ -859,12 +864,15 @@ enum moo_bcode_t BCODE_JUMP_BACKWARD_X = 0xC8, /* 200 ## */ BCODE_JUMP2_BACKWARD = 0xC9, /* 201 */ - BCODE_JUMP_FORWARD_IF_FALSE_X = 0xCC, /* 204 ## */ - BCODE_JUMP2_FORWARD_IF_FALSE = 0xCD, /* 205 */ - BCODE_JUMP_BACKWARD_IF_FALSE_X = 0xD0, /* 208 ## */ - BCODE_JUMP2_BACKWARD_IF_FALSE = 0xD1, /* 209 */ - BCODE_JUMP_BACKWARD_IF_TRUE_X = 0xD4, /* 212 ## */ - BCODE_JUMP2_BACKWARD_IF_TRUE = 0xD5, /* 213 */ + BCODE_JUMP_BACKWARD_IF_FALSE_X = 0xCC, /* 204 ## */ + BCODE_JUMP2_BACKWARD_IF_FALSE = 0xCD, /* 205 */ + BCODE_JUMP_BACKWARD_IF_TRUE_X = 0xD0, /* 208 ## */ + BCODE_JUMP2_BACKWARD_IF_TRUE = 0xD1, /* 209 */ + + BCODE_JUMP_FORWARD_IF_FALSE = 0xD4, /* 212 ## */ + BCODE_JUMP2_FORWARD_IF_FALSE = 0xD5, /* 213 */ + BCODE_JUMP_FORWARD_IF_TRUE = 0xD6, /* 214 ## */ + BCODE_JUMP2_FORWARD_IF_TRUE = 0xD7, /* 215 */ BCODE_STORE_INTO_CTXTEMPVAR_X = 0xD8, /* 216 ## */ BCODE_POP_INTO_CTXTEMPVAR_X = 0xDC, /* 220 ## */ @@ -888,7 +896,7 @@ enum moo_bcode_t BCODE_MAKE_ARRAY = 0xF5, /* 245 */ BCODE_POP_INTO_ARRAY = 0xF6, /* 246 */ - BCODE_DUP_STACKTOP = 0xF7, + BCODE_DUP_STACKTOP = 0xF7, /* 247 */ BCODE_POP_STACKTOP = 0xF8, BCODE_RETURN_STACKTOP = 0xF9, /* ^something */ BCODE_RETURN_RECEIVER = 0xFA, /* ^self */