/* match */ static int strpto_match(PSTATE *ps, Value *args, Value *_this, Value *ret, int asc) { if (asc) die("Execute String.prototype.match as constructor\n"); if (_this->vt != VT_OBJECT || _this->d.obj->ot != OT_STRING) { die("apply String.prototype.match to a non-string object\n"); } unichar *v = _this->d.obj->d.str; Value *seq = value_object_lookup_array(args, 0, NULL); if (!seq || seq->vt != VT_OBJECT || seq->d.obj->ot != OT_REGEXP) { value_make_null(*ret); return 0; } regex_t *reg = seq->d.obj->d.robj; regmatch_t pos[MAX_SUBREGEX]; memset(&pos, 0, MAX_SUBREGEX * sizeof(regmatch_t)); int r; if ((r = regexec(reg, tochars(v), MAX_SUBREGEX, pos, 0)) != 0) { if (r == REG_NOMATCH) { value_make_null(*ret); return 0; } else die("Out of memory\n"); } Object *obj = object_new(); obj->__proto__ = Array_prototype; value_make_object(*ret, obj); object_set_length(ret->d.obj, 0); int i; for (i = 0; i < MAX_SUBREGEX; ++i) { if (pos[i].rm_so <= 0 && pos[i].rm_eo <= 0) break; Value *val = value_new(); value_make_string(*val, unisubstrdup(v, pos[i].rm_so, pos[i].rm_eo - pos[i].rm_so)); value_object_utils_insert_array(ret, i, val, 1, 1, 1); } Value *vind = value_new(); value_make_number(*vind, pos[0].rm_so); value_object_utils_insert(ret, INDEX.unistr, vind, 1, 1, 1); Value *vinput = value_new(); value_make_string(*vinput, unistrdup(v)); value_object_utils_insert(ret, INPUT.unistr, vinput, 1, 1, 1); return 0; }
void proto_string_init(Value *global) { if (!String_prototype) bug("proto init failed?"); int i; for (i = 0; i < sizeof(strpro_funcs) / sizeof(struct st_strpro_tab); ++i) { Value *n = func_utils_make_func_value(strpro_funcs[i].func); n->d.obj->__proto__ = Function_prototype; value_object_utils_insert(String_prototype, tounichars(strpro_funcs[i].name), n, 0, 0, 0); } }
void proto_number_init(Value *global) { if (!Number_prototype) bug("proto init failed?"); int i; for (i = 0; i < sizeof(numpro_funcs) / sizeof(struct st_numpro_tab); ++i) { Value *n = func_utils_make_func_value(numpro_funcs[i].func); n->d.obj->__proto__ = Function_prototype; value_object_utils_insert(Number_prototype, tounichars(numpro_funcs[i].name), n, 0, 0, 0); } Value *NaN = value_new(); value_make_number(*NaN, ieee_makenan()); Value *Inf = value_new(); value_make_number(*Inf, ieee_makeinf(1)); value_object_utils_insert(global, tounichars("NaN"), NaN, 0, 0, 0); value_object_utils_insert(global, tounichars("Infinity"), Inf, 0, 0, 0); }
int eval(PSTATE *ps, OpCodes *opcodes, ScopeChain *scope, Value *currentScope, /* scope chain */ Value *_this, Value *vret) { int context_id = ps->_context_id++; OpCode *ip = &opcodes->codes[0]; OpCode *end = &opcodes->codes[opcodes->code_len]; TryList *trylist = NULL; if (currentScope->vt != VT_OBJECT) { bug("Eval: current scope is not a object\n"); } while(ip < end) { #ifdef DEBUG int i; printf("STACK%d: ", sp); for (i = 0; i < sp; ++i) { printf("%s ", vprint(&stack[i])); } printf("\tthis: %s ", vprint(_this)); TryList *tlt = trylist; for (i = 0; tlt; tlt = tlt->next) i++; printf("TL: %d, excpt: %s\n", i, vprint(&ps->last_exception)); code_decode(ip, ip - opcodes->codes); #endif switch(ip->op) { case OP_NOP: case OP_LASTOP: break; case OP_PUSHNUM: value_make_number(stack[sp], (*((double *)ip->data))); sp++; break; case OP_PUSHSTR: value_make_string(stack[sp], unistrdup(ip->data)); sp++; break; case OP_PUSHVAR: { FastVar *n = ip->data; Value *v = NULL; if (n->context_id == context_id) { v = n->var.lval; } else { unichar *varname = n->var.varname; v = value_object_lookup(currentScope, (ObjKey *)varname, NULL); if (!v) v = scope_chain_object_lookup(scope, (ObjKey *)varname); if (!v) { /* add to global scope */ Value *global_scope = scope->chains_cnt > 0 ? scope->chains[0]:currentScope; Value key; value_make_string(key, varname); /* varname is not dupped, do not erase*/ Value val; value_make_undef(val); v = value_object_key_assign(global_scope, &key, &val, OM_DONTEMU); /* key assign dup key and insert into object, so release ourself */ } n->context_id = context_id; n->var.lval = v; } stack[sp].vt = VT_VARIABLE; stack[sp].d.lval = v; sp++; break; } case OP_PUSHUND: value_make_undef(stack[sp]); sp++; break; case OP_PUSHBOO: value_make_bool(stack[sp], (int)ip->data); sp++; break; case OP_PUSHFUN: { FuncObj *fo = funcobj_new((Func *)ip->data); fo->scope = scope_chain_dup_next(scope, currentScope); Object *obj = object_new(); obj->ot = OT_FUNCTION; obj->d.fobj = fo; obj->__proto__ = Function_prototype; Value *fun_prototype = value_object_utils_new_object(); fun_prototype->d.obj->__proto__ = Object_prototype; value_make_object(stack[sp], obj); value_object_utils_insert(&stack[sp], PROTOTYPE.unistr, fun_prototype, 0, 1, 0); /* todo: make own prototype and prototype.constructor */ sp++; break; } case OP_PUSHREG: { Object *obj = object_new(); obj->ot = OT_REGEXP; obj->d.robj = (regex_t *)ip->data; obj->__proto__ = RegExp_prototype; value_make_object(stack[sp], obj); sp++; break; } case OP_PUSHARG: value_copy(stack[sp], *currentScope); sp++; break; case OP_PUSHTHS: value_copy(stack[sp], *_this); sp++; break; case OP_PUSHTOP: value_copy(stack[sp], TOP); sp++; break; case OP_UNREF: topeval1(); break; case OP_PUSHTOP2: value_copy(stack[sp], TOQ); value_copy(stack[sp+1], TOP); sp += 2; break; case OP_CHTHIS: { int t = sp - 2; if (ip->data) { value_erase(obj_this[t]); value_copy(obj_this[t], TOQ); if (obj_this[t].vt == VT_VARIABLE) { Value *v = obj_this[t].d.lval; value_copy(obj_this[t], *v); } value_toobject(&obj_this[t]); } break; } case OP_LOCAL: { ObjKey *strkey = objkey_new((const unichar *)ip->data, OM_DONTEMU); value_object_insert(currentScope, strkey, value_new()); /* make all FastVar to be relocated */ context_id = ps->_context_id++; break; } case OP_POP: pop_n(ip->data); break; case OP_NEG: topeval1(); value_tonumber(&TOP); TOP.d.num = -(TOP.d.num); break; case OP_POS: topeval1(); value_tonumber(&TOP); break; case OP_NOT: { int val = 0; topeval1(); val = value_istrue(&TOP); value_erase(TOP); value_make_bool(TOP, !val); break; } case OP_BNOT: { topeval1(); value_toint32(&TOP); TOP.d.num = (double)(~((int)TOP.d.num)); break; } case OP_ADD: { topeval2(); value_toprimitive(&TOP); value_toprimitive(&TOQ); if (TOP.vt == VT_STRING || TOQ.vt == VT_STRING) { value_tostring(&TOP); value_tostring(&TOQ); unichar *v = unistrcat(TOQ.d.str, TOP.d.str); value_erase(TOQ); value_make_string(TOQ, v); } else { value_tonumber(&TOP); value_tonumber(&TOQ); double n = TOP.d.num + TOQ.d.num; value_erase(TOQ); value_make_number(TOQ, n); } pop(); break; } case OP_SUB: /* god, the notes in ecma is so long, pray to run correctly */ common_math_opr(-); break; case OP_MUL: common_math_opr(*); break; case OP_DIV: common_math_opr(/); break; case OP_MOD: { topeval2(); if (!is_number(&TOP)) value_tonumber(&TOP); if (!is_number(&TOQ)) value_tonumber(&TOQ); TOQ.d.num = fmod(TOQ.d.num, TOP.d.num); pop(); break; } case OP_LESS: topeval2(); logic_less(TOQ, TOP, TOQ); pop(); break; case OP_GREATER: topeval2(); logic_less(TOP, TOQ, TOQ); pop(); break; case OP_LESSEQU: topeval2(); logic_less(TOP, TOQ, TOQ); TOQ.d.val = !TOQ.d.val; pop(); break; case OP_GREATEREQU: topeval2(); logic_less(TOQ, TOP, TOQ); TOQ.d.val = !TOQ.d.val; pop(); break; case OP_EQUAL: case OP_NOTEQUAL: { /* awful, equal opration */ int r = 0; topeval2(); if (TOP.vt != TOQ.vt) { value_toprimitive(&TOP); value_toprimitive(&TOQ); } if (TOP.vt != TOQ.vt) { if ((is_undef(&TOP) || is_null(&TOP)) && (is_undef(&TOQ) || is_null(&TOQ))) { r = 1; } else { value_tonumber(&TOP); value_tonumber(&TOQ); r = (TOP.d.num == TOQ.d.num); } } else { switch (TOP.vt) { case VT_NUMBER: r = (TOP.d.num == TOQ.d.num); break; case VT_BOOL: r = (TOP.d.val == TOQ.d.val); break; case VT_STRING: r = (unistrcmp(TOQ.d.str, TOP.d.str) == 0); break; case VT_OBJECT: /* todo: refer to objects joined to each other */ r = (TOP.d.obj == TOQ.d.obj); break; case VT_UNDEF: case VT_NULL: r = 1; break; default: bug("Unexpected value type\n"); } } r = (ip->op == OP_EQUAL ? r : !r); value_erase(TOQ); value_make_bool(TOQ, r); pop(); break; } case OP_STRICTEQU: case OP_STRICTNEQ: { int r = 0; topeval2(); if (TOP.vt == TOQ.vt) { switch (TOP.vt) { case VT_NUMBER: r = (TOP.d.num == TOQ.d.num); break; case VT_BOOL: r = (TOP.d.val == TOQ.d.val); break; case VT_STRING: r = (unistrcmp(TOQ.d.str, TOP.d.str) == 0); break; case VT_OBJECT: /* todo: refer to objects joined to each other */ r = (TOP.d.obj == TOQ.d.obj); break; case VT_UNDEF: case VT_NULL: r = 1; break; default: bug("Unexpected value type\n"); } } r = (ip->op == OP_STRICTEQU ? r : !r); value_erase(TOQ); value_make_bool(TOQ, r); pop(); break; } case OP_BAND: common_bitwise_opr(&); break; case OP_BOR: common_bitwise_opr(|); break; case OP_BXOR: common_bitwise_opr(^); break; case OP_SHF: { topeval2(); value_toint32(&TOQ); value_toint32(&TOP); int t1 = (int)TOQ.d.num; int t2 = ((unsigned int)TOP.d.num) & 0x1f; if (ip->data) { /* thift right */ if ((int)ip->data == 2) { /* unsigned shift */ unsigned int t3 = (unsigned int)t1; t3 >>= t2; value_make_number(TOQ, t3); } else { t1 >>= t2; value_make_number(TOQ, t1); } } else { t1 <<= t2; value_make_number(TOQ, t1); } pop(); break; }