implemented the while expression handling. break and continue yet to be implemented
This commit is contained in:
parent
6209b13410
commit
b7a19a3b14
@ -159,13 +159,21 @@ class MyObject(Object)
|
||||
a := 5.
|
||||
##((a < 20) ifTrue: [ 1. if (a < 20) { ^^50 }. 90. ]) dump.
|
||||
([true] whileTrue: [
|
||||
[
|
||||
'aaa' dump.
|
||||
if (a > 20) { ^^506070 }.
|
||||
a := a + 1.
|
||||
'bbb' dump.
|
||||
] ensure: [('xxxxx' & a asString) dump].
|
||||
[true] whileTrue: [
|
||||
[
|
||||
'aaa' dump.
|
||||
if (a > 20) { ^^506070 }.
|
||||
a := a + 1.
|
||||
'bbb' dump.
|
||||
] ensure: [('xxxxx' & a asString) dump].
|
||||
]
|
||||
]) dump.
|
||||
|
||||
a := 5.
|
||||
while (true) {
|
||||
System logNl: a asString.
|
||||
a := a + 100000000000000.
|
||||
}.
|
||||
|
||||
'---------- END ------------' dump.
|
||||
##Processor sleepFor: 20.
|
||||
|
153
moo/lib/comp.c
153
moo/lib/comp.c
@ -62,7 +62,7 @@ typedef enum var_type_t var_type_t;
|
||||
|
||||
struct var_info_t
|
||||
{
|
||||
var_type_t type;
|
||||
var_type_t type;
|
||||
moo_ooi_t pos; /* not used for VAR_GLOBAL */
|
||||
moo_oop_class_t cls; /* useful if type is VAR_CLASS. note MOO_NULL indicates the self class. */
|
||||
moo_oop_association_t gbl; /* used for VAR_GLOBAL only */
|
||||
@ -74,11 +74,13 @@ static struct voca_t
|
||||
moo_oow_t len;
|
||||
moo_ooch_t str[11];
|
||||
} vocas[] = {
|
||||
{ 5, { 'b','r','e','a','k' } },
|
||||
{ 5, { '#','b','y','t','e' } },
|
||||
{ 10, { '#','c','h','a','r','a','c','t','e','r' } },
|
||||
{ 5, { 'c','l','a','s','s' } },
|
||||
{ 6, { '#','c','l','a','s','s' } },
|
||||
{ 10, { '#','c','l','a','s','s','i','n','s','t' } },
|
||||
{ 8, { 'c','o','n','t','i','n','u','e' } },
|
||||
{ 3, { 'd','c','l' } },
|
||||
{ 7, { 'd','e','c','l','a','r','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','P','r','o','c','e','s','s' } },
|
||||
{ 4, { 't','r','u','e' } },
|
||||
{ 5, { 'w','h','i','l','e' } },
|
||||
{ 5, { '#','w','o','r','d' } },
|
||||
|
||||
{ 1, { '|' } },
|
||||
@ -115,11 +118,13 @@ static struct voca_t
|
||||
|
||||
enum voca_id_t
|
||||
{
|
||||
VOCA_BREAK,
|
||||
VOCA_BYTE_S,
|
||||
VOCA_CHARACTER_S,
|
||||
VOCA_CLASS,
|
||||
VOCA_CLASS_S,
|
||||
VOCA_CLASSINST_S,
|
||||
VOCA_CONTINUE,
|
||||
VOCA_DCL,
|
||||
VOCA_DECLARE,
|
||||
VOCA_ELSE,
|
||||
@ -145,6 +150,7 @@ enum voca_id_t
|
||||
VOCA_THIS_CONTEXT,
|
||||
VOCA_THIS_PROCESS,
|
||||
VOCA_TRUE,
|
||||
VOCA_WHILE,
|
||||
VOCA_WORD_S,
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
@ -2034,6 +2052,17 @@ 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)
|
||||
{
|
||||
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
|
||||
* --------------------------------------------------------------------- */
|
||||
@ -3266,18 +3295,19 @@ static int store_tmpr_count_for_block (moo_t* moo, moo_oow_t tmpr_count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int patch_jump_instruction (moo_t* moo, moo_oow_t jip, moo_oob_t jump2_inst, moo_ioloc_t* errloc)
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
if (code_size > MAX_CODE_JUMP * 2)
|
||||
{
|
||||
/* TODO: accept the location and pass it to set_syntax_error.
|
||||
* change error code or get it as a parameter */
|
||||
/* TODO: change error code or get it as a parameter */
|
||||
set_syntax_error (moo, MOO_SYNERR_BLKFLOOD, errloc, MOO_NULL);
|
||||
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 (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
|
||||
/* 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);
|
||||
@ -4277,6 +4307,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)
|
||||
{
|
||||
@ -4342,7 +4374,6 @@ static int compile_conditional (moo_t* moo)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
typedef struct oow_pool_chunk_t oow_pool_chunk_t;
|
||||
struct oow_pool_chunk_t
|
||||
{
|
||||
@ -4442,7 +4473,7 @@ static int compile_if_expression (moo_t* moo)
|
||||
GET_TOKEN (moo);
|
||||
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 ( */
|
||||
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 } */
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -4480,12 +4511,12 @@ static int compile_if_expression (moo_t* moo)
|
||||
/* patch instructions that jumps to the end of if expression */
|
||||
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
|
||||
* call will never flood either. */
|
||||
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++;
|
||||
}
|
||||
}
|
||||
@ -4498,6 +4529,100 @@ oops:
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@ -4517,6 +4642,10 @@ 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)
|
||||
{
|
||||
if (compile_while_expression (moo) <= -1) return -1;
|
||||
}
|
||||
else if (TOKEN_TYPE(moo) == MOO_IOTOK_IDENT ||
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
SWITCH_ACTIVE_CONTEXT (moo, moo->active_context->origin);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,11 @@ struct moo_iotok_t
|
||||
|
||||
MOO_IOTOK_IF,
|
||||
MOO_IOTOK_ELSE,
|
||||
MOO_IOTOK_ELSIF
|
||||
MOO_IOTOK_ELSIF,
|
||||
|
||||
MOO_IOTOK_WHILE,
|
||||
MOO_IOTOK_BREAK,
|
||||
MOO_IOTOK_CONTINUE
|
||||
} type;
|
||||
|
||||
moo_oocs_t name;
|
||||
|
Loading…
Reference in New Issue
Block a user