code_t* var_block(code_t*body, dict_t*vars) { code_t*c = 0; code_t*k = 0; int t; DICT_ITERATE_DATA(vars, variable_t*, v) { if(v->type && v->init) { c = defaultvalue(c, v->type); c = abc_setlocal(c, v->index); } if(v->type && v->kill) { k = abc_kill(k, v->index); } } if(k) { code_t*x = body; while(x) { if(x->opcode== OPCODE___BREAK__ || x->opcode== OPCODE___CONTINUE__) { /* link kill code before break/continue */ code_t*e = code_dup(k); code_t*s = code_start(e); s->prev = x->prev; if(x->prev) { x->prev->next = s; } e->next = x; x->prev = e; } x = x->prev; } } c = code_append(c, body); c = code_append(c, k); return c; }
code_t* cut_last_push(code_t*c) { assert(!c->next); while(c) { if(!c) break; opcode_t*op = opcode_get(c->opcode); /* cut conversion type operations */ if(op->stack_minus == -1 && op->stack_plus == 1 && !(op->flags)) { c = code_cutlast(c); continue; } /* cut any type of push */ else if(op->stack_minus == 0 && op->stack_plus == 1 && !(op->flags)) { return code_cutlast(c); } /* cut register lookups */ else if(c->opcode == OPCODE_GETLOCAL || c->opcode == OPCODE_GETLOCAL_0 || c->opcode == OPCODE_GETLOCAL_1 || c->opcode == OPCODE_GETLOCAL_2 || c->opcode == OPCODE_GETLOCAL_3) { return code_cutlast(c); } /* discard function call values */ else if(c->opcode == OPCODE_CALLPROPERTY) { c->opcode = OPCODE_CALLPROPVOID; return c; } else if(c->opcode == OPCODE_CALLSUPER) { c->opcode = OPCODE_CALLSUPERVOID; return c; } else if((c->opcode == OPCODE_NEWOBJECT || c->opcode == OPCODE_NEWARRAY) && !c->data[0]) { // we can discard these if they're not eating up stack parameters return code_cutlast(c); } else if(op->stack_minus ==0 && op->stack_plus == 0 && !(op->flags&~(OP_REGISTER|OP_SET_DXNS)) && c->prev) { // trim code *before* the kill, inclocal, declocal, dxns code_t*p = c->prev; p->next = 0; c->prev = 0; return code_append(cut_last_push(p), c); } else break; } c = abc_pop(c); return c; }
code_t* method_header(methodstate_t*m) { code_t*c = 0; c = add_scope_code(c, m, 1); methodstate_list_t*l = m->innerfunctions; while(l) { as3_assert(l->methodstate->abc); if(m->uses_slots && l->methodstate->is_a_slot) { c = abc_getscopeobject(c, 1); c = abc_newfunction(c, l->methodstate->abc); c = abc_dup(c); c = abc_setlocal(c, l->methodstate->var_index); c = abc_setslot(c, l->methodstate->slot_index); } else { c = abc_newfunction(c, l->methodstate->abc); c = abc_setlocal(c, l->methodstate->var_index); } free(l->methodstate);l->methodstate=0; l = l->next; } if(m->header) { c = code_append(c, m->header); m->header = 0; } if(m->is_constructor && !m->has_super) { // call default constructor c = abc_getlocal_0(c); c = abc_constructsuper(c, 0); } if(m->slots) { /* all parameters that are used by inner functions need to be copied from local to slot */ as3_assert(m->activation_var); DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) { if(v->is_parameter) { c = abc_getlocal(c, m->activation_var); c = abc_getlocal(c, v->index); c = abc_setslot(c, v->index); } } }
void eval_block(code *block, map* vars) { while (true) { code_skip_whitespace(block); if (block->source[block->pos] == '?') { uint8_t brackets = 0; size_t start, length = 0; mpz_t value; mpz_init(value); block->pos++; code_skip_whitespace(block); _parse_value(block, value, vars); code_skip_whitespace(block); start = block->pos + 1; while (true) { length++; if (block->source[block->pos] == '{') { brackets++; block->pos++; } else if (block->source[block->pos] == '}') { brackets--; block->pos++; if (brackets == 0) break; } else { block->pos++; } } if (mpz_sgn(value) == 0) { code subblock; code_init(&subblock); code_append(&subblock, block->source + start * sizeof(char), length - 2); eval_block(&subblock, vars); code_free(&subblock); } mpz_clear(value); } else if (block->source[block->pos] == '!') { mpz_t value; mpz_init(value); block->pos++; code_skip_whitespace(block); _parse_value(block, value, vars); mpz_out_str(stdout, 10, value); printf("\n"); mpz_clear(value); } else { char *var = malloc(1024 * sizeof(char)); mpz_t value; mpz_init(value); _parse_variable_name(block, var); code_skip_whitespace(block); switch (block->source[block->pos]) { case '=': block->pos++; code_skip_whitespace(block); _parse_value(block, value, vars); map_set(vars, var, value, false); break; case '+': block->pos += 2; code_skip_whitespace(block); _parse_value(block, value, vars); map_set(vars, var, value, true); break; case '-': block->pos += 2; code_skip_whitespace(block); _parse_value(block, value, vars); mpz_neg(value, value); map_set(vars, var, value, true); break; default: fprintf(stderr, "Parse error\n"); } free(var); mpz_clear(value); } code_skip_whitespace(block); if (block->pos >= block->length) return; if (block->source[block->pos] == ';') { block->pos++; } else { fprintf(stderr, "Missing ;\n"); return; } } }