diff --git a/moo/kernel/Mill.moo b/moo/kernel/Mill.moo index 5302762..95c2793 100644 --- a/moo/kernel/Mill.moo +++ b/moo/kernel/Mill.moo @@ -176,14 +176,29 @@ class MyObject(Object) a := a + 100000000000000. }.*) + (* a := 5. - while (true) + a := while (true) { a := a + 1. - if (a > 20) { break }. + ##if (a > 20) { break if (true) { break. }. }. + if (a > 20) { + ^if (true) { break } else {10}. ## return gets ignored for break. + }. a dump. }. + a dump.*) + a := 5. + do { + a := do { + ('in loop.....' & a asString) dump. + if (a > 5) { break }. + a := a + 1. + } while(a < 10). + } while (false). + a dump. + ## these should be elimited by the compiler. nil. 1. 0. @@ -192,6 +207,8 @@ class MyObject(Object) thisContext. nil. nil. + ## end of elimination. + '---------- END ------------' dump. ##Processor sleepFor: 20. } diff --git a/moo/kernel/generr.moo b/moo/kernel/generr.moo index 0d5bf2c..c0d219f 100644 --- a/moo/kernel/generr.moo +++ b/moo/kernel/generr.moo @@ -100,6 +100,7 @@ class MyObject(Object) 'literal expected' 'break or continue not within a loop' 'break or continue within a block' + 'while expected' ). f := Stdio open: 'generr.out' for: 'w'. diff --git a/moo/lib/comp.c b/moo/lib/comp.c index 954b346..7fe6d09 100644 --- a/moo/lib/comp.c +++ b/moo/lib/comp.c @@ -83,6 +83,7 @@ static struct voca_t { 8, { 'c','o','n','t','i','n','u','e' } }, { 3, { 'd','c','l' } }, { 7, { 'd','e','c','l','a','r','e' } }, + { 2, { 'd','o' } }, { 4, { 'e','l','s','e' } }, { 5, { 'e','l','s','i','f' } }, { 6, { 'e','n','s','u','r','e', } }, @@ -127,6 +128,7 @@ enum voca_id_t VOCA_CONTINUE, VOCA_DCL, VOCA_DECLARE, + VOCA_DO, VOCA_ELSE, VOCA_ELSIF, VOCA_ENSURE, @@ -245,11 +247,13 @@ static MOO_INLINE int is_identchar (moo_ooci_t c) return is_alnumchar(c) || c == '_'; } +#if 0 static MOO_INLINE int is_closing_char (moo_ooci_t c) { switch (c) { case '.': + case '}': case ']': case ')': case ';': @@ -261,6 +265,7 @@ static MOO_INLINE int is_closing_char (moo_ooci_t c) return 0; } } +#endif static MOO_INLINE int is_word (const moo_oocs_t* oocs, voca_id_t id) { @@ -1061,6 +1066,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_DO)) + { + SET_TOKEN_TYPE (moo, MOO_IOTOK_DO); + } else if (is_token_word(moo, VOCA_BREAK)) { SET_TOKEN_TYPE (moo, MOO_IOTOK_BREAK); @@ -1945,10 +1954,6 @@ static int emit_single_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1 case BCODE_PUSH_OBJECT_0: case BCODE_STORE_INTO_OBJECT_0: case BCODE_POP_INTO_OBJECT_0: - case BCODE_JUMP_FORWARD_0: - case BCODE_JUMP_BACKWARD_0: - case BCODE_JUMP_FORWARD_IF_FALSE_0: - case BCODE_JUMP_BACKWARD_IF_FALSE_0: if (param_1 < 4) { /* low 2 bits to hold the parameter */ @@ -1957,13 +1962,40 @@ static int emit_single_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1 } else { - /* convert the code to a long version */ + /* convert the instruction to a long version (_X) */ bc = cmd | 0x80; goto write_long; } + + 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) + { + /* low 2 bits to hold the parameter */ + bc = (moo_oob_t)(cmd & 0xFC) | (moo_oob_t)param_1; + goto write_short; + } + else + { + /* convert the instruction to a long version (_X) */ + bc = cmd | 0x80; + if (param_1 > MAX_CODE_JUMP) + { + cmd = cmd + 1; /* convert to a JUMP2 instruction */ + param_1 = param_1 - MAX_CODE_JUMP; + } + goto write_long; + } + 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_PUSH_INTLIT: case BCODE_PUSH_NEGINTLIT: case BCODE_PUSH_CHARLIT: @@ -1995,7 +2027,6 @@ write_long: return 0; } - static int emit_double_param_instruction (moo_t* moo, int cmd, moo_oow_t param_1, moo_oow_t param_2) { moo_oob_t bc; @@ -2106,15 +2137,64 @@ static int emit_push_character_literal (moo_t* moo, moo_ooch_t ch) return 0; } -static MOO_INLINE int emit_backward_jump_instruction (moo_t* moo, moo_oow_t offset) +static MOO_INLINE int emit_backward_jump_instruction (moo_t* moo, int cmd, moo_oow_t offset) { moo_oow_t adj; - /* BCODE_JUMP_BACKWARD_0 can use low 2 bits to encode the jump offset. - * so it can encode 0, 1, 2, 3. the instruction itself is 1 byte long. - * the 0, 1, 2 can get emitted u*/ - adj = (offset < 3)? 1: (MOO_BCODE_LONG_PARAM_SIZE + 1); - return emit_single_param_instruction (moo, BCODE_JUMP_BACKWARD_0, offset + adj); + MOO_ASSERT (moo, cmd == BCODE_JUMP_BACKWARD_0 || + cmd == BCODE_JUMP_BACKWARD_IF_FALSE_0 || + cmd == BCODE_JUMP_BACKWARD_IF_TRUE_0); + + /* the short BCODE_JUMP_BACKWARD instructions use low 2 bits to encode + * the jump offset. so it can encode 0, 1, 2, 3. the instruction itself + * is 1 byte long. the offset value of 0, 1, 2 can get encoded into the + * 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) +{ + moo_oow_t code_size; + moo_oow_t jump_offset; + + /* jip - jump instruction pointer, jt - jump target * + * + * when this jump instruction is executed, the instruction pointer advances + * to the next instruction. so the actual jump size gets offset by the size + * of this jump instruction. MOO_BCODE_LONG_PARAM_SIZE + 1 is the size of + * the long JUMP_FORWARD instruction */ + code_size = jt - jip - (MOO_BCODE_LONG_PARAM_SIZE + 1); + if (code_size > MAX_CODE_JUMP * 2) + { + /* TODO: change error code or get it as a parameter */ + set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, errloc, MOO_NULL); + return -1; + } + + 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; + jump_offset = code_size - MAX_CODE_JUMP; + } + else + { + jump_offset = code_size; + } + +#if (MOO_BCODE_LONG_PARAM_SIZE == 2) + moo->c->mth.code.ptr[jip + 1] = jump_offset >> 8; + moo->c->mth.code.ptr[jip + 2] = jump_offset & 0xFF; +#else + moo->c->mth.code.ptr[jip + 1] = jump_offset; +#endif + + return 0; } /* --------------------------------------------------------------------- * Compiler @@ -3348,46 +3428,7 @@ static int store_tmpr_count_for_block (moo_t* moo, moo_oow_t tmpr_count) return 0; } -static int patch_long_forward_jump_instruction (moo_t* moo, moo_oow_t jip, moo_oob_t jump2_inst, moo_ioloc_t* errloc) -{ - moo_oow_t code_size; - moo_oow_t jump_offset; - - /* when this jump instruction is executed, the instruction pointer advances - * to the next instruction. so the actual jump size gets offset by the size - * of this jump instruction. MOO_BCODE_LONG_PARAM_SIZE + 1 is the size of - * the long JUMP_FORWARD instruction */ - code_size = moo->c->mth.code.len - jip - (MOO_BCODE_LONG_PARAM_SIZE + 1); - if (code_size > MAX_CODE_JUMP * 2) - { - /* TODO: change error code or get it as a parameter */ - set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, errloc, MOO_NULL); - return -1; - } - - 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; - jump_offset = code_size - MAX_CODE_JUMP; - } - else - { - jump_offset = code_size; - } - -#if (MOO_BCODE_LONG_PARAM_SIZE == 2) - moo->c->mth.code.ptr[jip + 1] = jump_offset >> 8; - moo->c->mth.code.ptr[jip + 2] = jump_offset & 0xFF; -#else - moo->c->mth.code.ptr[jip + 1] = jump_offset; -#endif - - return 0; -} - -static int push_loop (moo_t* moo, moo_oow_t startpos) +static int push_loop (moo_t* moo, moo_loop_type_t type, moo_oow_t startpos) { moo_loop_t* loop; @@ -3395,6 +3436,8 @@ static int push_loop (moo_t* moo, moo_oow_t startpos) if (!loop) return -1; init_oow_pool (moo, &loop->break_ip_pool); + init_oow_pool (moo, &loop->continue_ip_pool); + loop->type = type; loop->startpos = startpos; loop->next = moo->c->mth.loop; moo->c->mth.loop = loop; @@ -3402,37 +3445,56 @@ static int push_loop (moo_t* moo, moo_oow_t startpos) return 0; } -static int pop_loop (moo_t* moo, int patch_break) +static int update_loop_jumps (moo_t* moo, moo_oow_pool_t* pool, moo_oow_t jt) +{ + /* patch the jump instructions emitted for 'break' */ + moo_oow_pool_chunk_t* chunk; + moo_oow_t i, j; + + for (chunk = pool->head, i = 0; chunk; chunk = chunk->next) + { + for (j = 0; j < MOO_COUNTOF(pool->static_chunk.buf) && i < pool->count; j++) + { + if (patch_long_forward_jump_instruction (moo, chunk->buf[j], jt, BCODE_JUMP2_FORWARD, MOO_NULL) <= -1) return -1; + i++; + } + } + + return 0; +} + +static MOO_INLINE int update_loop_breaks (moo_t* moo, moo_oow_t jt) +{ + return update_loop_jumps (moo, &moo->c->mth.loop->break_ip_pool, jt); +} + +static MOO_INLINE int update_loop_continues (moo_t* moo, moo_oow_t jt) +{ + return update_loop_jumps (moo, &moo->c->mth.loop->continue_ip_pool, jt); +} + + +static MOO_INLINE moo_loop_t* unlink_loop (moo_t* moo) { moo_loop_t* loop; - /* this function must be called when moo->c->mth.code.len is pointing - * to the intended target position because patch_long_forward_jump_instruction() - * patches jumps using the current value in moo->c->mth.code.len */ - MOO_ASSERT (moo, moo->c->mth.loop != MOO_NULL); loop = moo->c->mth.loop; moo->c->mth.loop = loop->next; - if (patch_break) - { - /* patch the jump instructions emitted for 'break' */ - moo_oow_pool_chunk_t* chunk; - moo_oow_t i, j; - - for (chunk = loop->break_ip_pool.head, i = 0; chunk; chunk = chunk->next) - { - for (j = 0; j < MOO_COUNTOF(loop->break_ip_pool.static_chunk.buf) && i < loop->break_ip_pool.count; j++) - { - if (patch_long_forward_jump_instruction (moo, chunk->buf[j], BCODE_JUMP2_FORWARD, MOO_NULL) <= -1) return -1; - i++; - } - } - } + return loop; +} +static MOO_INLINE void free_loop (moo_t* moo, moo_loop_t* loop) +{ + fini_oow_pool (moo, &loop->continue_ip_pool); fini_oow_pool (moo, &loop->break_ip_pool); moo_freemem (moo, loop); - return 0; +} + +static MOO_INLINE void pop_loop (moo_t* moo) +{ + free_loop (moo, unlink_loop (moo)); } static MOO_INLINE int inject_break_to_loop (moo_t* moo) @@ -3442,6 +3504,13 @@ static MOO_INLINE int inject_break_to_loop (moo_t* moo) return 0; } +static MOO_INLINE int inject_continue_to_loop (moo_t* moo) +{ + 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 int compile_block_expression (moo_t* moo) { moo_oow_t jump_inst_pos; @@ -3586,7 +3655,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, BCODE_JUMP2_FORWARD, &block_loc) <= -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; /* restore the temporary count */ moo->c->mth.tmprs.len = saved_tmprs_len; @@ -4395,8 +4464,8 @@ static int compile_braced_block (moo_t* moo) /* handle a code block enclosed in { } */ /*TODO: support local variable declaration inside {} */ - moo_oow_t code_start; + if (TOKEN_TYPE(moo) != MOO_IOTOK_LBRACE) { set_syntax_error (moo, MOO_SYNERR_LBRACE, TOKEN_LOC(moo), TOKEN_NAME(moo)); @@ -4496,7 +4565,7 @@ static int compile_if_expression (moo_t* moo) GET_TOKEN (moo); while (TOKEN_TYPE(moo) == MOO_IOTOK_ELSIF) { - if (patch_long_forward_jump_instruction (moo, jumptonext, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; + if (patch_long_forward_jump_instruction (moo, jumptonext, moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; GET_TOKEN (moo); /* get ( */ if (compile_conditional(moo) <= -1) goto oops; @@ -4517,7 +4586,7 @@ static int compile_if_expression (moo_t* moo) GET_TOKEN (moo); /* get the next token after } */ } - if (patch_long_forward_jump_instruction (moo, jumptonext, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; + if (patch_long_forward_jump_instruction (moo, jumptonext, moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; if (TOKEN_TYPE(moo) == MOO_IOTOK_ELSE) { @@ -4539,7 +4608,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], 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, BCODE_JUMP2_FORWARD_IF_FALSE, &if_loc) <= -1) goto oops; i++; } } @@ -4561,7 +4630,7 @@ static int compile_while_expression (moo_t* moo) MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_WHILE); while_loc = *TOKEN_LOC(moo); - GET_TOKEN (moo); /* get ( */ + GET_TOKEN (moo); /* get (, verification is done inside compile_conditional() */ precondpos = moo->c->mth.code.len; if (compile_conditional (moo) <= -1) goto oops; @@ -4593,7 +4662,7 @@ static int compile_while_expression (moo_t* moo) } /* remember information about this while loop. */ - if (push_loop (moo, precondpos) <= -1) goto oops; + if (push_loop (moo, MOO_LOOP_WHILE, precondpos) <= -1) goto oops; loop_pushed = 1; GET_TOKEN (moo); /* get { */ @@ -4617,7 +4686,7 @@ static int compile_while_expression (moo_t* moo) } /* emit code to jump back to the condition */ - if (emit_backward_jump_instruction (moo, moo->c->mth.code.len - precondpos) <= -1) + if (emit_backward_jump_instruction (moo, BCODE_JUMP_BACKWARD_0, moo->c->mth.code.len - precondpos) <= -1) { if (moo->errnum == MOO_ERANGE) { @@ -4631,7 +4700,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, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; + if (patch_long_forward_jump_instruction (moo, postcondpos, moo->c->mth.code.len, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops; } if (cond_style == -1) @@ -4641,8 +4710,12 @@ static int compile_while_expression (moo_t* moo) moo->c->mth.code.len = precondpos; } - /* destroy the loop information stored earlier in this function */ - pop_loop (moo, 1); + /* patch the jump instructions for break */ + if (update_loop_breaks (moo, moo->c->mth.code.len) <= -1) goto oops; + + /* destroy the loop information stored earlier in this function */ + pop_loop (moo); + loop_pushed = 0; /* push nil as a result of the while expression. TODO: is it the best value? anything else? */ if (emit_byte_instruction (moo, BCODE_PUSH_NIL) <= -1) goto oops; @@ -4650,7 +4723,117 @@ static int compile_while_expression (moo_t* moo) return 0; oops: - if (loop_pushed) pop_loop (moo, 0); + if (loop_pushed) pop_loop (moo); + return -1; +} + +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; + moo_loop_t* loop = MOO_NULL; + + MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_DO); + do_loc = *TOKEN_LOC(moo); + + GET_TOKEN (moo); /* get { */ + prebbpos = moo->c->mth.code.len; + + /* remember information about this loop. + * position of the conditional is not known yet.*/ + if (push_loop (moo, MOO_LOOP_DO_WHILE, prebbpos) <= -1) goto oops; + loop_pushed = 1; + + if (compile_braced_block(moo) <= -1) goto oops; + + GET_TOKEN (moo); /* get the next token after } */ + if (TOKEN_TYPE(moo) != MOO_IOTOK_WHILE) + { + set_syntax_error (moo, MOO_SYNERR_WHILE, TOKEN_LOC(moo), TOKEN_NAME(moo)); + goto oops; + } + GET_TOKEN (moo); /* get ( */ + postbbpos = moo->c->mth.code.len; + + if (prebbpos + 1 == postbbpos && moo->c->mth.code.ptr[prebbpos] == BCODE_PUSH_NIL) + { + /* optimization - + * the braced block is kind of empty as it only pushes nil. + * get rid of this push instruction and don't generate the POP_STACKTOP */ + moo->c->mth.code.len = prebbpos; + precondpos = prebbpos; + } + else if (prebbpos < postbbpos) + { + /* emit code to pop the value pushed by the braced block */ + if (emit_byte_instruction (moo, BCODE_POP_STACKTOP) <= -1) goto oops; + } + + precondpos = moo->c->mth.code.len; + + /* update jump instructions emitted for continue */ + if (update_loop_continues (moo, precondpos) <= -1) goto oops; + /* cannnot destroy the loop information because of pending jump updates + * for break. but need to unlink it as the conditional is not really + * part of the loop body */ + loop = unlink_loop (moo); + + if (compile_conditional (moo) <= -1) goto oops; + postcondpos = moo->c->mth.code.len; + jbinst = 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) + { + /* the conditional is always true. eliminate PUSH_TRUE and emit an absolute jump */ + moo->c->mth.code.len = precondpos; + postcondpos = precondpos; + jbinst = BCODE_JUMP_BACKWARD_0; + } + else if (moo->c->mth.code.ptr[precondpos] == BCODE_PUSH_FALSE) + { + /* the conditional is always false. eliminate PUSH_FALSE and don't emit jump */ + moo->c->mth.code.len = precondpos; + postcondpos = precondpos; + goto skip_emitting_jump_backward; + } + } + + if (emit_backward_jump_instruction (moo, jbinst, moo->c->mth.code.len - prebbpos) <= -1) + { + if (moo->errnum == MOO_ERANGE) + { + /* the jump offset is out of the representable range by the offset + * portion of the jump instruction */ + set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, &do_loc, MOO_NULL); + } + goto oops; + } + +skip_emitting_jump_backward: + GET_TOKEN (moo); /* get the next token after ) */ + + /* update jump instructions emitted for break */ + if (update_loop_jumps (moo, &loop->break_ip_pool, moo->c->mth.code.len) <= -1) return -1; + free_loop (moo, loop); + loop = MOO_NULL; + loop_pushed = 0; + + /* push nil as a result of the while expression. TODO: is it the best value? anything else? */ + if (emit_byte_instruction (moo, BCODE_PUSH_NIL) <= -1) goto oops; + + return 0; + +oops: + if (loop_pushed) + { + if (loop) free_loop (moo, loop); + else pop_loop (moo); + } return -1; } @@ -4677,6 +4860,10 @@ static int compile_method_expression (moo_t* moo, int pop) { if (compile_while_expression (moo) <= -1) return -1; } + else if (TOKEN_TYPE(moo) == MOO_IOTOK_DO) + { + if (compile_do_while_expression (moo) <= -1) return -1; + } else if (TOKEN_TYPE(moo) == MOO_IOTOK_IDENT || TOKEN_TYPE(moo) == MOO_IOTOK_IDENT_DOTTED) { @@ -4838,10 +5025,13 @@ static int compile_special_statement (moo_t* moo) } GET_TOKEN (moo); /* read the next token to continue */ - return emit_backward_jump_instruction (moo, moo->c->mth.code.len - moo->c->mth.loop->startpos); + + return (moo->c->mth.loop->type == MOO_LOOP_DO_WHILE)? + inject_continue_to_loop (moo): /* in a do-while loop, the position to the conditional is not known yet */ + emit_backward_jump_instruction (moo, BCODE_JUMP_BACKWARD_0, moo->c->mth.code.len - moo->c->mth.loop->startpos); } - return 9999; /* to indicate that no special stament has been seen and processed */ + return 9999; /* to indicate that no special statement has been seen and processed */ } static int compile_block_statement (moo_t* moo) @@ -4858,7 +5048,6 @@ static int compile_block_statement (moo_t* moo) static int compile_method_statement (moo_t* moo) { - /* * method-statement := method-return-statement | break | continue | method-expression * method-return-statement := "^" method-expression diff --git a/moo/lib/decode.c b/moo/lib/decode.c index 6039fac..d3d4374 100644 --- a/moo/lib/decode.c +++ b/moo/lib/decode.c @@ -280,6 +280,18 @@ int moo_decode (moo_t* moo, moo_oop_method_t mth, const moo_oocs_t* classfqn) LOG_INST_1 (moo, "jump_backward_if_false %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */ break; + case BCODE_JUMP_BACKWARD_IF_TRUE_X: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump_backward_if_true %zu", b1); + break; + + case BCODE_JUMP_BACKWARD_IF_TRUE_0: + case BCODE_JUMP_BACKWARD_IF_TRUE_1: + case BCODE_JUMP_BACKWARD_IF_TRUE_2: + case BCODE_JUMP_BACKWARD_IF_TRUE_3: + LOG_INST_1 (moo, "jump_backward_if_true %zu", (moo_oow_t)(bcode & 0x3)); /* low 2 bits */ + break; + case BCODE_JUMP2_FORWARD: FETCH_PARAM_CODE_TO (moo, b1); LOG_INST_1 (moo, "jump2_forward %zu", b1); @@ -299,6 +311,11 @@ int moo_decode (moo_t* moo, moo_oop_method_t mth, const moo_oocs_t* classfqn) FETCH_PARAM_CODE_TO (moo, b1); LOG_INST_1 (moo, "jump2_backward_if_false %zu", b1); break; + + case BCODE_JUMP2_BACKWARD_IF_TRUE: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump2_backward_if_true %zu", b1); + break; /* -------------------------------------------------------- */ case BCODE_PUSH_CTXTEMPVAR_X: diff --git a/moo/lib/err.c b/moo/lib/err.c index 6906502..1d6754b 100644 --- a/moo/lib/err.c +++ b/moo/lib/err.c @@ -126,6 +126,7 @@ static moo_ooch_t synerrstr_54[] = {'d','u','p','l','i','c','a','t','e',' ','p', static moo_ooch_t synerrstr_55[] = {'l','i','t','e','r','a','l',' ','e','x','p','e','c','t','e','d','\0'}; static moo_ooch_t synerrstr_56[] = {'b','r','e','a','k',' ','o','r',' ','c','o','n','t','i','n','u','e',' ','n','o','t',' ','w','i','t','h','i','n',' ','a',' ','l','o','o','p','\0'}; static moo_ooch_t synerrstr_57[] = {'b','r','e','a','k',' ','o','r',' ','c','o','n','t','i','n','u','e',' ','w','i','t','h','i','n',' ','a',' ','b','l','o','c','k','\0'}; +static moo_ooch_t synerrstr_58[] = {'w','h','i','l','e',' ','e','x','p','e','c','t','e','d','\0'}; static moo_ooch_t* synerrstr[] = { synerrstr_0, synerrstr_1, synerrstr_2, synerrstr_3, synerrstr_4, synerrstr_5, synerrstr_6, synerrstr_7, @@ -135,7 +136,7 @@ static moo_ooch_t* synerrstr[] = synerrstr_32, synerrstr_33, synerrstr_34, synerrstr_35, synerrstr_36, synerrstr_37, synerrstr_38, synerrstr_39, synerrstr_40, synerrstr_41, synerrstr_42, synerrstr_43, synerrstr_44, synerrstr_45, synerrstr_46, synerrstr_47, synerrstr_48, synerrstr_49, synerrstr_50, synerrstr_51, synerrstr_52, synerrstr_53, synerrstr_54, synerrstr_55, - synerrstr_56, synerrstr_57 + synerrstr_56, synerrstr_57, synerrstr_58 }; #endif /* END: GENERATED WITH generr.st */ diff --git a/moo/lib/exec.c b/moo/lib/exec.c index 3936f05..84e5ded 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -3515,6 +3515,22 @@ int moo_execute (moo_t* moo) MOO_STACK_POP (moo); break; + case BCODE_JUMP_BACKWARD_IF_TRUE_X: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump_backward_if_true %zu", b1); + if (MOO_STACK_GETTOP(moo) == moo->_true) moo->ip -= b1; + MOO_STACK_POP (moo); + break; + + case BCODE_JUMP_BACKWARD_IF_TRUE_0: + case BCODE_JUMP_BACKWARD_IF_TRUE_1: + case BCODE_JUMP_BACKWARD_IF_TRUE_2: + case BCODE_JUMP_BACKWARD_IF_TRUE_3: + LOG_INST_1 (moo, "jump_backward_if_true %zu", (moo_oow_t)(bcode & 0x3)); + if (MOO_STACK_GETTOP(moo) == moo->_true) moo->ip -= (bcode & 0x3); /* low 2 bits */ + MOO_STACK_POP (moo); + break; + case BCODE_JUMP2_FORWARD: FETCH_PARAM_CODE_TO (moo, b1); LOG_INST_1 (moo, "jump2_forward %zu", b1); @@ -3541,6 +3557,12 @@ int moo_execute (moo_t* moo) MOO_STACK_POP (moo); break; + case BCODE_JUMP2_BACKWARD_IF_TRUE: + FETCH_PARAM_CODE_TO (moo, b1); + LOG_INST_1 (moo, "jump2_backward_if_true %zu", b1); + if (MOO_STACK_GETTOP(moo) == moo->_true) moo->ip -= MAX_CODE_JUMP + b1; + MOO_STACK_POP (moo); + break; /* -------------------------------------------------------- */ case BCODE_PUSH_CTXTEMPVAR_X: diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index 9c19eb3..7a19cbc 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_DO, MOO_IOTOK_BREAK, MOO_IOTOK_CONTINUE } type; @@ -374,11 +375,20 @@ struct moo_oow_pool_t moo_oow_t count; }; +enum moo_loop_type_t +{ + MOO_LOOP_WHILE, + MOO_LOOP_DO_WHILE +}; +typedef enum moo_loop_type_t moo_loop_type_t; + typedef struct moo_loop_t moo_loop_t; struct moo_loop_t { + moo_loop_type_t type; moo_oow_t startpos; - moo_oow_pool_t break_ip_pool; /* a pool that holds break instruction pointer */ + moo_oow_pool_t break_ip_pool; /* a pool that holds jump instruction pointers for break */ + moo_oow_pool_t continue_ip_pool; /* a pool that hold jump instructino pointers for continue. only for do-while */ moo_oow_t blkcount; /* number of inner blocks enclosed in square brackets */ moo_loop_t* next; }; @@ -611,10 +621,9 @@ SHORT INSTRUCTION CODE LONG INSTRUCTION C 68-71 0100 01XX JUMP_FORWARD 196 1100 0100 XXXXXXXX JUMP_FORWARD_X 72-75 0100 10XX JUMP_BACKWARD 200 1100 1000 XXXXXXXX JUMP_BACKWARD_X -76-79 0100 11XX JUMP_BACKWARD_IF_FALSE 204 1100 1100 XXXXXXXX JUMP_BACKWARD_IF_FALSE_X +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 UNUSED +84-87 0101 01XX JUMP_FORWARD_IF_TRUE 212 1101 0100 XXXXXXXX JUMP_FORWARD_IF_TRUE_X vv 88-91 0101 10XX YYYYYYYY STORE_INTO_CTXTEMPVAR 216 1101 1000 XXXXXXXX YYYYYYYY STORE_INTO_CTXTEMPVAR_X (bit 3 on, bit 2 off) @@ -750,6 +759,11 @@ enum moo_bcode_t BCODE_JUMP_BACKWARD_IF_FALSE_2 = 0x52, /* 82 */ BCODE_JUMP_BACKWARD_IF_FALSE_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 */ + BCODE_STORE_INTO_CTXTEMPVAR_0 = 0x58, /* 88 */ BCODE_STORE_INTO_CTXTEMPVAR_1 = 0x59, /* 89 */ BCODE_STORE_INTO_CTXTEMPVAR_2 = 0x5A, /* 90 */ @@ -832,6 +846,8 @@ enum moo_bcode_t 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_STORE_INTO_CTXTEMPVAR_X = 0xD8, /* 216 ## */ BCODE_POP_INTO_CTXTEMPVAR_X = 0xDC, /* 220 ## */ diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 4360e3c..d8c6c45 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -1148,7 +1148,8 @@ enum moo_synerrnum_t MOO_SYNERR_POOLDICDUP, /* duplicate pool dictionary */ MOO_SYNERR_LITERAL, /* literal expected */ MOO_SYNERR_NOTINLOOP, /* break or continue not within a loop */ - MOO_SYNERR_INBLOCK /* break or continue within a block */ + MOO_SYNERR_INBLOCK, /* break or continue within a block */ + MOO_SYNERR_WHILE /* while expected */ }; typedef enum moo_synerrnum_t moo_synerrnum_t;