implemented the while expression handling. break and continue yet to be implemented
This commit is contained in:
parent
6209b13410
commit
b7a19a3b14
@ -159,14 +159,22 @@ class MyObject(Object)
|
|||||||
a := 5.
|
a := 5.
|
||||||
##((a < 20) ifTrue: [ 1. if (a < 20) { ^^50 }. 90. ]) dump.
|
##((a < 20) ifTrue: [ 1. if (a < 20) { ^^50 }. 90. ]) dump.
|
||||||
([true] whileTrue: [
|
([true] whileTrue: [
|
||||||
|
[true] whileTrue: [
|
||||||
[
|
[
|
||||||
'aaa' dump.
|
'aaa' dump.
|
||||||
if (a > 20) { ^^506070 }.
|
if (a > 20) { ^^506070 }.
|
||||||
a := a + 1.
|
a := a + 1.
|
||||||
'bbb' dump.
|
'bbb' dump.
|
||||||
] ensure: [('xxxxx' & a asString) dump].
|
] ensure: [('xxxxx' & a asString) dump].
|
||||||
|
]
|
||||||
]) dump.
|
]) dump.
|
||||||
|
|
||||||
|
a := 5.
|
||||||
|
while (true) {
|
||||||
|
System logNl: a asString.
|
||||||
|
a := a + 100000000000000.
|
||||||
|
}.
|
||||||
|
|
||||||
'---------- END ------------' dump.
|
'---------- END ------------' dump.
|
||||||
##Processor sleepFor: 20.
|
##Processor sleepFor: 20.
|
||||||
}
|
}
|
||||||
|
151
moo/lib/comp.c
151
moo/lib/comp.c
@ -74,11 +74,13 @@ static struct voca_t
|
|||||||
moo_oow_t len;
|
moo_oow_t len;
|
||||||
moo_ooch_t str[11];
|
moo_ooch_t str[11];
|
||||||
} vocas[] = {
|
} vocas[] = {
|
||||||
|
{ 5, { 'b','r','e','a','k' } },
|
||||||
{ 5, { '#','b','y','t','e' } },
|
{ 5, { '#','b','y','t','e' } },
|
||||||
{ 10, { '#','c','h','a','r','a','c','t','e','r' } },
|
{ 10, { '#','c','h','a','r','a','c','t','e','r' } },
|
||||||
{ 5, { 'c','l','a','s','s' } },
|
{ 5, { 'c','l','a','s','s' } },
|
||||||
{ 6, { '#','c','l','a','s','s' } },
|
{ 6, { '#','c','l','a','s','s' } },
|
||||||
{ 10, { '#','c','l','a','s','s','i','n','s','t' } },
|
{ 10, { '#','c','l','a','s','s','i','n','s','t' } },
|
||||||
|
{ 8, { 'c','o','n','t','i','n','u','e' } },
|
||||||
{ 3, { 'd','c','l' } },
|
{ 3, { 'd','c','l' } },
|
||||||
{ 7, { 'd','e','c','l','a','r','e' } },
|
{ 7, { 'd','e','c','l','a','r','e' } },
|
||||||
{ 4, { 'e','l','s','e' } },
|
{ 4, { 'e','l','s','e' } },
|
||||||
@ -104,6 +106,7 @@ static struct voca_t
|
|||||||
{ 11, { 't','h','i','s','C','o','n','t','e','x','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' } },
|
{ 11, { 't','h','i','s','P','r','o','c','e','s','s' } },
|
||||||
{ 4, { 't','r','u','e' } },
|
{ 4, { 't','r','u','e' } },
|
||||||
|
{ 5, { 'w','h','i','l','e' } },
|
||||||
{ 5, { '#','w','o','r','d' } },
|
{ 5, { '#','w','o','r','d' } },
|
||||||
|
|
||||||
{ 1, { '|' } },
|
{ 1, { '|' } },
|
||||||
@ -115,11 +118,13 @@ static struct voca_t
|
|||||||
|
|
||||||
enum voca_id_t
|
enum voca_id_t
|
||||||
{
|
{
|
||||||
|
VOCA_BREAK,
|
||||||
VOCA_BYTE_S,
|
VOCA_BYTE_S,
|
||||||
VOCA_CHARACTER_S,
|
VOCA_CHARACTER_S,
|
||||||
VOCA_CLASS,
|
VOCA_CLASS,
|
||||||
VOCA_CLASS_S,
|
VOCA_CLASS_S,
|
||||||
VOCA_CLASSINST_S,
|
VOCA_CLASSINST_S,
|
||||||
|
VOCA_CONTINUE,
|
||||||
VOCA_DCL,
|
VOCA_DCL,
|
||||||
VOCA_DECLARE,
|
VOCA_DECLARE,
|
||||||
VOCA_ELSE,
|
VOCA_ELSE,
|
||||||
@ -145,6 +150,7 @@ enum voca_id_t
|
|||||||
VOCA_THIS_CONTEXT,
|
VOCA_THIS_CONTEXT,
|
||||||
VOCA_THIS_PROCESS,
|
VOCA_THIS_PROCESS,
|
||||||
VOCA_TRUE,
|
VOCA_TRUE,
|
||||||
|
VOCA_WHILE,
|
||||||
VOCA_WORD_S,
|
VOCA_WORD_S,
|
||||||
|
|
||||||
VOCA_VBAR,
|
VOCA_VBAR,
|
||||||
@ -998,6 +1004,18 @@ static int get_ident (moo_t* moo, moo_ooci_t char_read_ahead)
|
|||||||
{
|
{
|
||||||
SET_TOKEN_TYPE (moo, MOO_IOTOK_ELSIF);
|
SET_TOKEN_TYPE (moo, MOO_IOTOK_ELSIF);
|
||||||
}
|
}
|
||||||
|
else if (is_token_word(moo, VOCA_WHILE))
|
||||||
|
{
|
||||||
|
SET_TOKEN_TYPE (moo, MOO_IOTOK_WHILE);
|
||||||
|
}
|
||||||
|
else if (is_token_word(moo, VOCA_BREAK))
|
||||||
|
{
|
||||||
|
SET_TOKEN_TYPE (moo, MOO_IOTOK_BREAK);
|
||||||
|
}
|
||||||
|
else if (is_token_word(moo, VOCA_CONTINUE))
|
||||||
|
{
|
||||||
|
SET_TOKEN_TYPE (moo, MOO_IOTOK_CONTINUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2034,6 +2052,17 @@ static int emit_push_character_literal (moo_t* moo, moo_ooch_t ch)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MOO_INLINE int emit_backward_jump_instruction (moo_t* moo, 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);
|
||||||
|
|
||||||
|
}
|
||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
* Compiler
|
* Compiler
|
||||||
* --------------------------------------------------------------------- */
|
* --------------------------------------------------------------------- */
|
||||||
@ -3266,18 +3295,19 @@ static int store_tmpr_count_for_block (moo_t* moo, moo_oow_t tmpr_count)
|
|||||||
return 0;
|
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)
|
||||||
static int patch_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 code_size;
|
||||||
moo_oow_t jump_offset;
|
moo_oow_t jump_offset;
|
||||||
|
|
||||||
/* MOO_BCODE_LONG_PARAM_SIZE + 1 => size of the long JUMP_FORWARD instruction */
|
/* 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);
|
code_size = moo->c->mth.code.len - jip - (MOO_BCODE_LONG_PARAM_SIZE + 1);
|
||||||
if (code_size > MAX_CODE_JUMP * 2)
|
if (code_size > MAX_CODE_JUMP * 2)
|
||||||
{
|
{
|
||||||
/* TODO: accept the location and pass it to set_syntax_error.
|
/* TODO: change error code or get it as a parameter */
|
||||||
* change error code or get it as a parameter */
|
|
||||||
set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, errloc, MOO_NULL);
|
set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, errloc, MOO_NULL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -3443,7 +3473,7 @@ static int compile_block_expression (moo_t* moo)
|
|||||||
if (emit_byte_instruction(moo, BCODE_RETURN_FROM_BLOCK) <= -1) return -1;
|
if (emit_byte_instruction(moo, BCODE_RETURN_FROM_BLOCK) <= -1) return -1;
|
||||||
|
|
||||||
|
|
||||||
if (patch_jump_instruction (moo, jump_inst_pos, BCODE_JUMP2_FORWARD, &block_loc) <= -1) return -1;
|
if (patch_long_forward_jump_instruction (moo, jump_inst_pos, BCODE_JUMP2_FORWARD, &block_loc) <= -1) return -1;
|
||||||
#if 0
|
#if 0
|
||||||
/* MOO_BCODE_LONG_PARAM_SIZE + 1 => size of the long JUMP_FORWARD instruction */
|
/* MOO_BCODE_LONG_PARAM_SIZE + 1 => size of the long JUMP_FORWARD instruction */
|
||||||
block_code_size = moo->c->mth.code.len - jump_inst_pos - (MOO_BCODE_LONG_PARAM_SIZE + 1);
|
block_code_size = moo->c->mth.code.len - jump_inst_pos - (MOO_BCODE_LONG_PARAM_SIZE + 1);
|
||||||
@ -4277,6 +4307,8 @@ static int compile_braced_block (moo_t* moo)
|
|||||||
{
|
{
|
||||||
/* handle a code block enclosed in { } */
|
/* handle a code block enclosed in { } */
|
||||||
|
|
||||||
|
/*TODO: support local variable declaration inside {} */
|
||||||
|
|
||||||
moo_oow_t code_start;
|
moo_oow_t code_start;
|
||||||
if (TOKEN_TYPE(moo) != MOO_IOTOK_LBRACE)
|
if (TOKEN_TYPE(moo) != MOO_IOTOK_LBRACE)
|
||||||
{
|
{
|
||||||
@ -4342,7 +4374,6 @@ static int compile_conditional (moo_t* moo)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct oow_pool_chunk_t oow_pool_chunk_t;
|
typedef struct oow_pool_chunk_t oow_pool_chunk_t;
|
||||||
struct oow_pool_chunk_t
|
struct oow_pool_chunk_t
|
||||||
{
|
{
|
||||||
@ -4442,7 +4473,7 @@ static int compile_if_expression (moo_t* moo)
|
|||||||
GET_TOKEN (moo);
|
GET_TOKEN (moo);
|
||||||
while (TOKEN_TYPE(moo) == MOO_IOTOK_ELSIF)
|
while (TOKEN_TYPE(moo) == MOO_IOTOK_ELSIF)
|
||||||
{
|
{
|
||||||
if (patch_jump_instruction (moo, jumptonext, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops;
|
if (patch_long_forward_jump_instruction (moo, jumptonext, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops;
|
||||||
|
|
||||||
GET_TOKEN (moo); /* get ( */
|
GET_TOKEN (moo); /* get ( */
|
||||||
if (compile_conditional(moo) <= -1) goto oops;
|
if (compile_conditional(moo) <= -1) goto oops;
|
||||||
@ -4463,7 +4494,7 @@ static int compile_if_expression (moo_t* moo)
|
|||||||
GET_TOKEN (moo); /* get the next token after } */
|
GET_TOKEN (moo); /* get the next token after } */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch_jump_instruction (moo, jumptonext, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops;
|
if (patch_long_forward_jump_instruction (moo, jumptonext, BCODE_JUMP2_FORWARD_IF_FALSE, &brace_loc) <= -1) goto oops;
|
||||||
|
|
||||||
if (TOKEN_TYPE(moo) == MOO_IOTOK_ELSE)
|
if (TOKEN_TYPE(moo) == MOO_IOTOK_ELSE)
|
||||||
{
|
{
|
||||||
@ -4480,12 +4511,12 @@ static int compile_if_expression (moo_t* moo)
|
|||||||
/* patch instructions that jumps to the end of if expression */
|
/* patch instructions that jumps to the end of if expression */
|
||||||
for (jumptoend_chunk = jumptoend.head, i = 0; jumptoend_chunk; jumptoend_chunk = jumptoend_chunk->next)
|
for (jumptoend_chunk = jumptoend.head, i = 0; jumptoend_chunk; jumptoend_chunk = jumptoend_chunk->next)
|
||||||
{
|
{
|
||||||
/* pass if_loc to every call to patch_jump_instruction().
|
/* pass if_loc to every call to patch_long_forward_jump_instruction().
|
||||||
* it's harmless because if the first call doesn't flood, the subseqent
|
* it's harmless because if the first call doesn't flood, the subseqent
|
||||||
* call will never flood either. */
|
* call will never flood either. */
|
||||||
for (j = 0; j < MOO_COUNTOF(jumptoend.static_chunk.buf) && i < jumptoend.count; j++)
|
for (j = 0; j < MOO_COUNTOF(jumptoend.static_chunk.buf) && i < jumptoend.count; j++)
|
||||||
{
|
{
|
||||||
if (patch_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], BCODE_JUMP2_FORWARD_IF_FALSE, &if_loc) <= -1) goto oops;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4498,6 +4529,100 @@ oops:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int compile_while_expression (moo_t* moo)
|
||||||
|
{
|
||||||
|
moo_ioloc_t while_loc, brace_loc;
|
||||||
|
moo_oow_t precondpos, postcondpos, prebbpos, postbbpos;
|
||||||
|
int cond_style = 0;
|
||||||
|
|
||||||
|
MOO_ASSERT (moo, TOKEN_TYPE(moo) == MOO_IOTOK_WHILE);
|
||||||
|
while_loc = *TOKEN_LOC(moo);
|
||||||
|
|
||||||
|
GET_TOKEN (moo); /* get ( */
|
||||||
|
precondpos = moo->c->mth.code.len;
|
||||||
|
if (compile_conditional (moo) <= -1) goto oops;
|
||||||
|
|
||||||
|
postcondpos = moo->c->mth.code.len;
|
||||||
|
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 */
|
||||||
|
cond_style = 1;
|
||||||
|
moo->c->mth.code.len = precondpos;
|
||||||
|
postcondpos = precondpos;
|
||||||
|
}
|
||||||
|
else if (moo->c->mth.code.ptr[precondpos] == BCODE_PUSH_FALSE)
|
||||||
|
{
|
||||||
|
/* the conditional is always false */
|
||||||
|
cond_style = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_TOKEN (moo); /* get { */
|
||||||
|
brace_loc = *TOKEN_LOC(moo);
|
||||||
|
prebbpos = moo->c->mth.code.len;
|
||||||
|
if (compile_braced_block (moo) <= -1) goto oops;
|
||||||
|
GET_TOKEN (moo); /* get the next token after } */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* emit code to jump back to the condition */
|
||||||
|
if (emit_backward_jump_instruction (moo, moo->c->mth.code.len - precondpos) <= -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, &while_loc, MOO_NULL);
|
||||||
|
}
|
||||||
|
goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (cond_style == -1)
|
||||||
|
{
|
||||||
|
/* optimization - get rid of code generated for the while
|
||||||
|
* loop including the conditional */
|
||||||
|
moo->c->mth.code.len = precondpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int compile_method_expression (moo_t* moo, int pop)
|
static int compile_method_expression (moo_t* moo, int pop)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -4517,6 +4642,10 @@ static int compile_method_expression (moo_t* moo, int pop)
|
|||||||
{
|
{
|
||||||
if (compile_if_expression (moo) <= -1) return -1;
|
if (compile_if_expression (moo) <= -1) return -1;
|
||||||
}
|
}
|
||||||
|
else if (TOKEN_TYPE(moo) == MOO_IOTOK_WHILE)
|
||||||
|
{
|
||||||
|
if (compile_while_expression (moo) <= -1) return -1;
|
||||||
|
}
|
||||||
else if (TOKEN_TYPE(moo) == MOO_IOTOK_IDENT ||
|
else if (TOKEN_TYPE(moo) == MOO_IOTOK_IDENT ||
|
||||||
TOKEN_TYPE(moo) == MOO_IOTOK_IDENT_DOTTED)
|
TOKEN_TYPE(moo) == MOO_IOTOK_IDENT_DOTTED)
|
||||||
{
|
{
|
||||||
|
@ -3937,15 +3937,18 @@ int moo_execute (moo_t* moo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* the origin must always be a method context for both an active block context
|
||||||
|
* or an active method context */
|
||||||
MOO_ASSERT (moo, MOO_CLASSOF(moo, moo->active_context->origin) == moo->_method_context);
|
MOO_ASSERT (moo, MOO_CLASSOF(moo, moo->active_context->origin) == moo->_method_context);
|
||||||
|
|
||||||
|
/* restore the stack pointer */
|
||||||
|
moo->sp = MOO_OOP_TO_SMOOI(moo->active_context->origin->sp);
|
||||||
if (bcode == BCODE_LOCAL_RETURN && moo->active_context != moo->active_context->origin)
|
if (bcode == BCODE_LOCAL_RETURN && moo->active_context != moo->active_context->origin)
|
||||||
{
|
{
|
||||||
SWITCH_ACTIVE_CONTEXT (moo, moo->active_context->origin);
|
SWITCH_ACTIVE_CONTEXT (moo, moo->active_context->origin);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* restore the stack pointer */
|
|
||||||
moo->sp = MOO_OOP_TO_SMOOI(moo->active_context->origin->sp);
|
|
||||||
SWITCH_ACTIVE_CONTEXT (moo, moo->active_context->origin->sender);
|
SWITCH_ACTIVE_CONTEXT (moo, moo->active_context->origin->sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +331,11 @@ struct moo_iotok_t
|
|||||||
|
|
||||||
MOO_IOTOK_IF,
|
MOO_IOTOK_IF,
|
||||||
MOO_IOTOK_ELSE,
|
MOO_IOTOK_ELSE,
|
||||||
MOO_IOTOK_ELSIF
|
MOO_IOTOK_ELSIF,
|
||||||
|
|
||||||
|
MOO_IOTOK_WHILE,
|
||||||
|
MOO_IOTOK_BREAK,
|
||||||
|
MOO_IOTOK_CONTINUE
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
moo_oocs_t name;
|
moo_oocs_t name;
|
||||||
|
Loading…
Reference in New Issue
Block a user