diff --git a/moo/kernel/generr.moo b/moo/kernel/generr.moo index 19e8a87..dde3be8 100644 --- a/moo/kernel/generr.moo +++ b/moo/kernel/generr.moo @@ -125,6 +125,7 @@ class MyObject(Object) 'break or continue within a block' 'while expected' 'invalid goto target' + 'label at end' ). f := Stdio open: 'generr.out' for: 'w'. diff --git a/moo/lib/comp.c b/moo/lib/comp.c index 04463cf..91964d5 100644 --- a/moo/lib/comp.c +++ b/moo/lib/comp.c @@ -4952,16 +4952,23 @@ static int compile_block_expression (moo_t* moo) } } } -#else +#elif 0 code_start = cc->mth.code.len; + if (TOKEN_TYPE(moo) != MOO_IOTOK_RBRACK) { moo_oow_t pop_stacktop_pos = 0; - while (TOKEN_TYPE(moo) != MOO_IOTOK_EOF) + do { int n; + if (TOKEN_TYPE(moo) == MOO_IOTOK_EOF) + { + moo_setsynerr (moo, MOO_SYNERR_RBRACK, TOKEN_LOC(moo), TOKEN_NAME(moo)); + return -1; + } + n = compile_block_statement(moo); if (n <= -1) return -1; if (n == 8888) @@ -4975,6 +4982,29 @@ static int compile_block_expression (moo_t* moo) break; } } + else if (n == 7777) + { + /* goto statement - + * the goto statement looks like a normal statement, but it never pushes a value. + * so no pop_stacktop instruction needs to get injected */ + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACK) + { + /* eliminate BCODE_POP_STACKTOP produced in the else block below + * becuase the non-steatemnt item is the last item before the closing bracket */ + if (pop_stacktop_pos > 0) eliminate_instructions (moo, pop_stacktop_pos, cc->mth.code.len - 1); + break; + } + else if (TOKEN_TYPE(moo) == MOO_IOTOK_PERIOD) + { + GET_TOKEN (moo); + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACK) break; + } + else + { + moo_setsynerr (moo, MOO_SYNERR_RBRACK, TOKEN_LOC(moo), TOKEN_NAME(moo)); + return -1; + } + } else { /* a proper statement has been processed in compile_block_statemnt */ @@ -4995,6 +5025,7 @@ static int compile_block_expression (moo_t* moo) } } } + while (1); } if (cc->mth.code.len == code_start) @@ -5002,6 +5033,107 @@ static int compile_block_expression (moo_t* moo) /* the block is empty */ if (emit_byte_instruction(moo, BCODE_PUSH_NIL, TOKEN_LOC(moo)) <= -1) return -1; } +#else +moo_oow_t pop_stacktop_pos = INVALID_IP; /* TODO: move this up */ + + code_start = cc->mth.code.len; + if (emit_byte_instruction(moo, BCODE_PUSH_NIL, TOKEN_LOC(moo)) <= -1) return -1; + pop_stacktop_pos = cc->mth.code.len; + if (emit_byte_instruction(moo, BCODE_POP_STACKTOP, TOKEN_LOC(moo)) <= -1) return -1; + + if (TOKEN_TYPE(moo) != MOO_IOTOK_RBRACK) + { + do + { + int n; + + if (TOKEN_TYPE(moo) == MOO_IOTOK_EOF) + { + moo_setsynerr (moo, MOO_SYNERR_RBRACK, TOKEN_LOC(moo), TOKEN_NAME(moo)); + return -1; + } + + n = compile_block_statement(moo); + if (n <= -1) return -1; + if (n == 8888) + { + /* compile_block_statement() processed non-statement item like a jump label. */ + MOO_ASSERT (moo, cc->mth._label != MOO_NULL); + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACK) + { + /* the last label inside [] must be followed by a valid statement */ + moo_oocs_t labname; + labname.ptr = (moo_ooch_t*)(cc->mth._label + 1); + labname.len = moo_count_oocstr(labname.ptr); + moo_setsynerrbfmt (moo, MOO_SYNERR_LABELATEND, &cc->mth._label->loc, &labname, "label at end of square bracketed block"); + return -1; + } + } + else if (n == 7777) + { + /* goto statement - + * the goto statement looks like a normal statement, but it never pushes a value. + * so no pop_stacktop instruction needs to get injected */ + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACK) + { + /* eliminate BCODE_POP_STACKTOP produced in the else block below + * becuase the non-stetment item is the last item before the closing bracket */ + if (pop_stacktop_pos != INVALID_IP) + { + eliminate_instructions (moo, pop_stacktop_pos, pop_stacktop_pos); + pop_stacktop_pos = INVALID_IP; + } + break; + } + else if (TOKEN_TYPE(moo) == MOO_IOTOK_PERIOD) + { + GET_TOKEN (moo); + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACK) break; + } + else + { + moo_setsynerr (moo, MOO_SYNERR_RBRACK, TOKEN_LOC(moo), TOKEN_NAME(moo)); + return -1; + } + } + else + { + /* a proper statement has been processed in compile_block_statemnt */ + pop_stacktop_pos = cc->mth.code.len; + if (emit_byte_instruction(moo, BCODE_POP_STACKTOP, TOKEN_LOC(moo)) <= -1) return -1; + + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACK) + { + eliminate_instructions(moo, pop_stacktop_pos, pop_stacktop_pos); + pop_stacktop_pos = INVALID_IP; + break; + } + else if (TOKEN_TYPE(moo) == MOO_IOTOK_PERIOD) + { + moo_ioloc_t period_loc = *TOKEN_LOC(moo); + GET_TOKEN (moo); + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACK) + { + eliminate_instructions(moo, pop_stacktop_pos, pop_stacktop_pos); + pop_stacktop_pos = INVALID_IP; + break; + } + } + else + { + moo_setsynerr (moo, MOO_SYNERR_RBRACK, TOKEN_LOC(moo), TOKEN_NAME(moo)); + return -1; + } + } + } + while (1); + } + + /* + if (cc->mth.code.len > 2 && cc->mth.code.len - 2 == code_start) + { + if (cc->mth.code.ptr[code_start] == BCODE_PUSH_NIL + }*/ #endif if (emit_byte_instruction(moo, BCODE_RETURN_FROM_BLOCK, TOKEN_LOC(moo)) <= -1) return -1; @@ -6053,15 +6185,33 @@ static int compile_braced_block (moo_t* moo) if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACE) { /* non-statement followed by the closing brace. - * if there is a statement above the non-statement item, the POP_STACKSTOP is procuced. + * if there is a statement above the non-statement item, the POP_STACKSTOP is produced. * it should be eliminated since the block should return the last evalulated value */ if (pop_stacktop_pos > 0) eliminate_instructions (moo, pop_stacktop_pos, cc->mth.code.len - 1); break; } } + else if (n == 7777) + { + /* goto statement */ + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACE) + { + if (pop_stacktop_pos > 0) eliminate_instructions (moo, pop_stacktop_pos, cc->mth.code.len - 1); + break; + } + else if (TOKEN_TYPE(moo) == MOO_IOTOK_PERIOD) + { + GET_TOKEN (moo); + if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACE) break; + } + else + { + moo_setsynerr (moo, MOO_SYNERR_RBRACE, TOKEN_LOC(moo), TOKEN_NAME(moo)); + return -1; + } + } else { - if (TOKEN_TYPE(moo) == MOO_IOTOK_RBRACE) break; else if (TOKEN_TYPE(moo) == MOO_IOTOK_PERIOD) { @@ -6693,7 +6843,7 @@ static MOO_INLINE int resolve_goto_label (moo_t* moo, moo_goto_t* _goto) } gtname.len = moo_count_oocstr(gtname.ptr); - moo_setsynerrbfmt (moo, MOO_SYNERR_NAMEUNDEF, &_goto->loc, >name, "undefined goto label - %js", gtname); + moo_setsynerrbfmt (moo, MOO_SYNERR_NAMEUNDEF, &_goto->loc, >name, "undefined goto label"); return -1; } @@ -6856,7 +7006,8 @@ static int compile_special_statement (moo_t* moo) else if (TOKEN_TYPE(moo) == MOO_IOTOK_GOTO) { GET_TOKEN (moo); - return compile_goto_statement(moo); + if (compile_goto_statement(moo) <= -1) return -1; + return 7777; /* indicate that a goto statement has been seen and processed */ } return 9999; /* to indicate that no special statement has been seen and processed */ diff --git a/moo/lib/err.c b/moo/lib/err.c index b994683..d5f9e32 100644 --- a/moo/lib/err.c +++ b/moo/lib/err.c @@ -150,6 +150,7 @@ static moo_ooch_t synerrstr_74[] = {'b','r','e','a','k',' ','o','r',' ','c','o', static moo_ooch_t synerrstr_75[] = {'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_76[] = {'w','h','i','l','e',' ','e','x','p','e','c','t','e','d','\0'}; static moo_ooch_t synerrstr_77[] = {'i','n','v','a','l','i','d',' ','g','o','t','o',' ','t','a','r','g','e','t','\0'}; +static moo_ooch_t synerrstr_78[] = {'l','a','b','e','l',' ','a','t',' ','e','n','d','\0'}; static moo_ooch_t* synerrstr[] = { synerrstr_0, synerrstr_1, synerrstr_2, synerrstr_3, synerrstr_4, synerrstr_5, synerrstr_6, synerrstr_7, @@ -161,7 +162,7 @@ static moo_ooch_t* synerrstr[] = synerrstr_48, synerrstr_49, synerrstr_50, synerrstr_51, synerrstr_52, synerrstr_53, synerrstr_54, synerrstr_55, synerrstr_56, synerrstr_57, synerrstr_58, synerrstr_59, synerrstr_60, synerrstr_61, synerrstr_62, synerrstr_63, synerrstr_64, synerrstr_65, synerrstr_66, synerrstr_67, synerrstr_68, synerrstr_69, synerrstr_70, synerrstr_71, - synerrstr_72, synerrstr_73, synerrstr_74, synerrstr_75, synerrstr_76, synerrstr_77 + synerrstr_72, synerrstr_73, synerrstr_74, synerrstr_75, synerrstr_76, synerrstr_77, synerrstr_78 }; #endif /* END: GENERATED WITH generr.moo */ diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 06fc3ae..ed4c5e3 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -1894,7 +1894,8 @@ enum moo_synerrnum_t MOO_SYNERR_NOTINLOOP, /* break or continue not within a loop */ MOO_SYNERR_INBLOCK, /* break or continue within a block */ MOO_SYNERR_WHILE, /* while expected */ - MOO_SYNERR_GOTOTARGETINVAL /* invalid goto target */ + MOO_SYNERR_GOTOTARGETINVAL, /* invalid goto target */ + MOO_SYNERR_LABELATEND /* label at the end without following statement */ }; typedef enum moo_synerrnum_t moo_synerrnum_t; diff --git a/moo/t/m/b-001.txt b/moo/t/m/b-001.txt new file mode 100644 index 0000000..e51adf8 --- /dev/null +++ b/moo/t/m/b-001.txt @@ -0,0 +1,2 @@ +[ X02: 20 ] value dump. +[ X02: 20 ] value dump. // syntax error X02 is a duplicate label. a label must be uniquie method-wide. diff --git a/moo/t/m/b-002.txt b/moo/t/m/b-002.txt new file mode 100644 index 0000000..69627eb --- /dev/null +++ b/moo/t/m/b-002.txt @@ -0,0 +1,2 @@ +[ goto X03. ] value dump. /* Unable to jump out of a block */ +[ goto X02. X01: 9. goto X03. X02: goto X01. X03: 20. ] value dump. diff --git a/moo/t/m/r.awk b/moo/t/m/r.awk new file mode 100644 index 0000000..4bbbf49 --- /dev/null +++ b/moo/t/m/r.awk @@ -0,0 +1,38 @@ +### THIS SCRIPT NEEDS MUCH MORE ENHANCEMENT. +### THE CURRENT CODE IS JUST TEMPORARY. + +BEGIN { + @local pid, workfile, d, f, cmd; + + pid = sys::getpid(); + workfile = "moo-test." pid; + + d = dir::open (".", dir::SORT); + while (dir::read(d, f) > 0) + { + if (f !~ /.txt$/) continue; + + print "#include \"../../kernel/Moo.moo\"." > workfile; + print "class MyObject(Object) {" >> workfile; + print "\tmethod(#class) main" >> workfile; + print "\t{" >> workfile; + + while ((getline x < f) > 0) + { + print x >> workfile; + } + close (f); + + print "\t}" >> workfile; + print "\}" >> workfile; + close (workfile); + + cmd = "/home/hyung-hwan/xxx/bin/moo " workfile; + print "<" f ">"; + ##sys::system ("cat " workfile); + sys::system (cmd); + } + + dir::close(d); + sys::unlink (workfile); +}