diff --git a/libgst/comp.c b/libgst/comp.c index 9cc5986..71f2e12 100644 --- a/libgst/comp.c +++ b/libgst/comp.c @@ -171,6 +171,9 @@ static mst_Boolean compile_and_or_statement (OOP selector, static mst_Boolean compile_if_true_false_statement (OOP selector, tree_node expr); +static mst_Boolean compile_if_nil_statement (OOP selector, + tree_node expr); + /* Special case compilation of an infinite loop, given by the parse node in RECEIVER. Returns true if byte codes were emitted, false if not. If the last argument to the message is not a block @@ -252,6 +255,10 @@ static bc_vector compile_sub_expression (tree_node expr); static bc_vector compile_sub_expression_and_jump (tree_node expr, int branchLen); +/* Like compile_sub_expression, POP the value on the stack. */ +static bc_vector compile_pop_sub_expression_and_jump (tree_node expr); + + /* Compile a send with the given RECEIVER (used to check for sends to super), SELECTOR and number of arguments NUMARGS. */ static void compile_send (tree_node receiver, @@ -1287,7 +1294,12 @@ compile_keyword_expr (tree_node expr, compile_expression (expr->v_expr.receiver); - if (selector == _gst_if_true_symbol + if (selector == _gst_if_nil_symbol) + { + if (compile_if_nil_statement (selector, expr->v_expr.expression)) + return; + } + else if (selector == _gst_if_true_symbol || selector == _gst_if_false_symbol) { if (compile_if_statement (selector, expr->v_expr.expression)) @@ -1689,6 +1701,47 @@ compile_if_true_false_statement (OOP selector, return (true); } +bc_vector +compile_pop_sub_expression_and_jump (tree_node expr) +{ + bc_vector current_bytecodes, subExprByteCodes; + + current_bytecodes = _gst_save_bytecode_array (); + + _gst_compile_byte (POP_STACK_TOP, 0); + + compile_statements (expr->v_block.statements, false); + + subExprByteCodes = _gst_get_bytecodes (); + _gst_restore_bytecode_array (current_bytecodes); + + return (subExprByteCodes); +} + + +mst_Boolean +compile_if_nil_statement (OOP selector, + tree_node expr) +{ + bc_vector nilByteCodes; + struct builtin_selector *bs = _gst_lookup_builtin_selector ("isNil", 5); + + if (expr->v_list.value->nodeType != TREE_BLOCK_NODE + || HAS_PARAMS_OR_TEMPS (expr->v_list.value)) + return (false); + + _gst_compile_byte (DUP_STACK_TOP, 0); + INCR_STACK_DEPTH (); + + _gst_compile_byte (bs->bytecode, 0); + + nilByteCodes = compile_pop_sub_expression_and_jump (expr->v_list.value); + compile_jump (_gst_bytecode_length (nilByteCodes), false); + _gst_compile_and_free_bytecodes (nilByteCodes); + + return (true); +} + mst_Boolean compile_if_statement (OOP selector, tree_node expr) diff --git a/libgst/sym.c b/libgst/sym.c index 6c8d1f4..7e323c6 100644 --- a/libgst/sym.c +++ b/libgst/sym.c @@ -126,6 +126,7 @@ OOP _gst_if_false_if_true_symbol = NULL; OOP _gst_if_false_symbol = NULL; OOP _gst_if_true_if_false_symbol = NULL; OOP _gst_if_true_symbol = NULL; +OOP _gst_if_nil_symbol = NULL; OOP _gst_int_symbol = NULL; OOP _gst_long_double_symbol = NULL; OOP _gst_long_symbol = NULL; @@ -284,6 +285,7 @@ static const symbol_info sym_info[] = { {&_gst_if_false_symbol, "ifFalse:"}, {&_gst_if_true_if_false_symbol, "ifTrue:ifFalse:"}, {&_gst_if_true_symbol, "ifTrue:"}, + {&_gst_if_nil_symbol, "ifNil:"}, {&_gst_int_symbol, "int"}, {&_gst_uint_symbol, "uInt"}, {&_gst_long_double_symbol, "longDouble"}, diff --git a/libgst/sym.h b/libgst/sym.h index 87c1f1c..c1b5ef8 100644 --- a/libgst/sym.h +++ b/libgst/sym.h @@ -115,6 +115,7 @@ extern OOP _gst_if_false_if_true_symbol ATTRIBUTE_HIDDEN; extern OOP _gst_if_false_symbol ATTRIBUTE_HIDDEN; extern OOP _gst_if_true_if_false_symbol ATTRIBUTE_HIDDEN; extern OOP _gst_if_true_symbol ATTRIBUTE_HIDDEN; +extern OOP _gst_if_nil_symbol ATTRIBUTE_HIDDEN; extern OOP _gst_int_symbol ATTRIBUTE_HIDDEN; extern OOP _gst_long_double_symbol ATTRIBUTE_HIDDEN; extern OOP _gst_long_symbol ATTRIBUTE_HIDDEN;