diff options
Diffstat (limited to 'com.c')
-rw-r--r-- | com.c | 43 |
1 files changed, 29 insertions, 14 deletions
@@ -59,12 +59,15 @@ static int stack_effect_of(Op opcode) { case OP_MOD: case OP_ARRAPPEND: return -1; + case OP_SETIDX: + return -2; // these ones depend on their argument. handle them specifically case OP_CALL: case OP_TAILCALL: case OP_ENDSCOPE: return 0; + default: ERROR("unknown stack effect of opcode %d",opcode); } @@ -172,21 +175,31 @@ void single_form(Compiler *C, AstVec l, Op op) { static Local *locate_local(Compiler *C, char *name); void set_form(Compiler *C, AstVec l, Op _, int flags) { - AstNode ident = l.vals[1]; - CHECK(ident.ty == AST_IDENT, "set's first argument must be identifier"); - char *name = ident.as.str; - - Local *loc = locate_local(C, name); - if (loc != NULL) { - compile_node(C, l.vals[2], 0); - compile_opcode(C, OP_SETLOCAL); - compile_byte(C, loc->slot); - } else { - // write global - ObjString *o = objstring_copy_cstr(C->S, name); + AstNode target = l.vals[1]; + if (target.ty == AST_IDENT) { + // set variable, local or global + char *name = target.as.str; + + Local *loc = locate_local(C, name); + if (loc != NULL) { + compile_node(C, l.vals[2], 0); + compile_opcode(C, OP_SETLOCAL); + compile_byte(C, loc->slot); + } else { + // write global + ObjString *o = objstring_copy_cstr(C->S, name); + compile_node(C, l.vals[2], 0); + compile_opcode(C, OP_SETGLOBAL); + compile_byte(C, compile_constant(C, VAL_OBJ(o))); + } + } else if (target.ty == AST_LIST) { + AstVec pair = target.as.list; + CHECK(pair.len == 2, "can only set to (arr, ix) 2-pair"); + // (value arr ix) <- TOS compile_node(C, l.vals[2], 0); - compile_opcode(C, OP_SETGLOBAL); - compile_byte(C, compile_constant(C, VAL_OBJ(o))); + compile_node(C, pair.vals[0], 0); + compile_node(C, pair.vals[1], 0); + compile_opcode(C, OP_SETIDX); } } @@ -332,6 +345,8 @@ void def_form(Compiler *C, AstVec l, Op _, int flags) { compile_node(C, l.vals[2], 0); declare_local(C, l.vals[1].as.str); // whatever is calling us will compile an OP_DROP next + // or, well. not if we're in tail position. but i can't see + // any circumstance where you'd want that anyway compile_opcode(C, OP_NIL); } |