summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--quickjs.c86
-rw-r--r--tests/test_builtin.js129
2 files changed, 176 insertions, 39 deletions
diff --git a/quickjs.c b/quickjs.c
index 11a6367..7d9943f 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -16302,6 +16302,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
+ sf->cur_pc = pc;
val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
if (unlikely(JS_IsException(val)))
goto exception;
@@ -16654,6 +16655,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
int magic;
magic = get_u16(pc);
pc += 2;
+ sf->cur_pc = pc;
ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
if (unlikely(JS_IsException(ret_val)))
@@ -16800,6 +16802,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
scope_idx = get_u16(pc) + ARG_SCOPE_END;
pc += 2;
+ sf->cur_pc = pc;
tab = build_arg_list(ctx, &len, sp[-1]);
if (!tab)
goto exception;
@@ -16835,6 +16838,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_get_super):
{
JSValue proto;
+ sf->cur_pc = pc;
proto = JS_GetPrototype(ctx, sp[-1]);
if (JS_IsException(proto))
goto exception;
@@ -16846,6 +16850,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_import):
{
JSValue val;
+ sf->cur_pc = pc;
val = js_dynamic_import(ctx, sp[-1]);
if (JS_IsException(val))
goto exception;
@@ -16860,6 +16865,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
ret = JS_CheckGlobalVar(ctx, atom);
if (ret < 0)
@@ -16875,6 +16881,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
if (unlikely(JS_IsException(val)))
@@ -16890,6 +16897,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
sp--;
@@ -16904,6 +16912,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
/* sp[-2] is JS_TRUE or JS_FALSE */
if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
@@ -16924,6 +16933,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
flags = pc[4];
pc += 5;
+ sf->cur_pc = pc;
if (JS_CheckDefineGlobalVar(ctx, atom, flags))
goto exception;
}
@@ -16935,6 +16945,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
flags = pc[4];
pc += 5;
+ sf->cur_pc = pc;
if (JS_DefineGlobalVar(ctx, atom, flags))
goto exception;
}
@@ -16946,6 +16957,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
flags = pc[4];
pc += 5;
+ sf->cur_pc = pc;
if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
goto exception;
JS_FreeValue(ctx, sp[-1]);
@@ -17224,6 +17236,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
if (JS_GetGlobalVarRef(ctx, atom, sp))
goto exception;
@@ -17369,15 +17382,18 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_for_in_start):
+ sf->cur_pc = pc;
if (js_for_in_start(ctx, sp))
goto exception;
BREAK;
CASE(OP_for_in_next):
+ sf->cur_pc = pc;
if (js_for_in_next(ctx, sp))
goto exception;
sp += 2;
BREAK;
CASE(OP_for_of_start):
+ sf->cur_pc = pc;
if (js_for_of_start(ctx, sp, FALSE))
goto exception;
sp += 1;
@@ -17387,23 +17403,27 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int offset = -3 - pc[0];
pc += 1;
+ sf->cur_pc = pc;
if (js_for_of_next(ctx, sp, offset))
goto exception;
sp += 2;
}
BREAK;
CASE(OP_for_await_of_next):
+ sf->cur_pc = pc;
if (js_for_await_of_next(ctx, sp))
goto exception;
sp++;
BREAK;
CASE(OP_for_await_of_start):
+ sf->cur_pc = pc;
if (js_for_of_start(ctx, sp, TRUE))
goto exception;
sp += 1;
*sp++ = JS_NewCatchOffset(ctx, 0);
BREAK;
CASE(OP_iterator_get_value_done):
+ sf->cur_pc = pc;
if (js_iterator_get_value_done(ctx, sp))
goto exception;
sp += 1;
@@ -17421,6 +17441,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_FreeValue(ctx, sp[-1]); /* drop the next method */
sp--;
if (!JS_IsUndefined(sp[-1])) {
+ sf->cur_pc = pc;
if (JS_IteratorClose(ctx, sp[-1], FALSE))
goto exception;
JS_FreeValue(ctx, sp[-1]);
@@ -17449,6 +17470,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
/* stack: iter_obj next catch_offset val */
{
JSValue ret;
+ sf->cur_pc = pc;
ret = JS_Call(ctx, sp[-3], sp[-4],
1, (JSValueConst *)(sp - 1));
if (JS_IsException(ret))
@@ -17465,6 +17487,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BOOL ret_flag;
int flags;
flags = *pc++;
+ sf->cur_pc = pc;
method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
JS_ATOM_throw : JS_ATOM_return);
if (JS_IsException(method))
@@ -17513,6 +17536,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
val = JS_GetProperty(ctx, sp[-1], atom);
if (unlikely(JS_IsException(val)))
goto exception;
@@ -17528,6 +17552,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
val = JS_GetProperty(ctx, sp[-1], atom);
if (unlikely(JS_IsException(val)))
goto exception;
@@ -17541,6 +17566,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2],
JS_PROP_THROW_STRICT);
@@ -17640,6 +17666,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_set_proto):
{
JSValue proto;
+ sf->cur_pc = pc;
proto = sp[-1];
if (JS_IsObject(proto) || JS_IsNull(proto)) {
if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
@@ -17732,6 +17759,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
+ sf->cur_pc = pc;
val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
JS_FreeValue(ctx, sp[-2]);
sp[-2] = val;
@@ -17745,6 +17773,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
+ sf->cur_pc = pc;
val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
sp[-1] = val;
if (unlikely(JS_IsException(val)))
@@ -17758,6 +17787,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSAtom atom;
int ret;
+ sf->cur_pc = pc;
atom = JS_ValueToAtom(ctx, sp[-1]);
if (atom == JS_ATOM_NULL)
goto exception;
@@ -17793,6 +17823,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue val;
JSAtom atom;
+ sf->cur_pc = pc;
atom = JS_ValueToAtom(ctx, sp[-1]);
if (unlikely(atom == JS_ATOM_NULL))
goto exception;
@@ -17812,6 +17843,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int ret;
+ sf->cur_pc = pc;
ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
JS_FreeValue(ctx, sp[-3]);
sp -= 3;
@@ -17824,6 +17856,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int ret;
JSAtom atom;
+ sf->cur_pc = pc;
atom = JS_ValueToAtom(ctx, sp[-2]);
if (unlikely(atom == JS_ATOM_NULL))
goto exception;
@@ -17862,6 +17895,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int ret;
JSAtom atom;
+ sf->cur_pc = pc;
if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
JS_ThrowTypeErrorNotAnObject(ctx);
goto exception;
@@ -17894,6 +17928,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_append): /* array pos enumobj -- array pos */
{
+ sf->cur_pc = pc;
if (js_append_enumerate(ctx, sp))
goto exception;
JS_FreeValue(ctx, *--sp);
@@ -17909,6 +17944,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
int mask;
mask = *pc++;
+ sf->cur_pc = pc;
if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
sp[-1 - ((mask >> 2) & 7)],
sp[-1 - ((mask >> 5) & 7)], 0))
@@ -17939,6 +17975,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
goto exception;
} else {
add_slow:
+ sf->cur_pc = pc;
if (js_add_slow(ctx, sp))
goto exception;
sp--;
@@ -17968,6 +18005,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp--;
} else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
sp--;
+ sf->cur_pc = pc;
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
if (JS_IsException(op2))
goto exception;
@@ -17984,6 +18022,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
add_loc_slow:
/* In case of exception, js_add_slow frees ops[0]
and ops[1], so we must duplicate *pv */
+ sf->cur_pc = pc;
ops[0] = JS_DupValue(ctx, *pv);
ops[1] = op2;
sp--;
@@ -18086,6 +18125,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_pow):
binary_arith_slow:
+ sf->cur_pc = pc;
if (js_binary_arith_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -18099,6 +18139,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
tag = JS_VALUE_GET_TAG(op1);
if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
} else {
+ sf->cur_pc = pc;
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -18129,6 +18170,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
neg_fp_res:
sp[-1] = __JS_NewFloat64(ctx, d);
} else {
+ sf->cur_pc = pc;
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -18146,6 +18188,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-1] = JS_NewInt32(ctx, val + 1);
} else {
inc_slow:
+ sf->cur_pc = pc;
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -18163,6 +18206,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-1] = JS_NewInt32(ctx, val - 1);
} else {
dec_slow:
+ sf->cur_pc = pc;
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -18170,6 +18214,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_post_inc):
CASE(OP_post_dec):
+ sf->cur_pc = pc;
if (js_post_inc_slow(ctx, sp, opcode))
goto exception;
sp++;
@@ -18190,6 +18235,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
var_buf[idx] = JS_NewInt32(ctx, val + 1);
} else {
inc_loc_slow:
+ sf->cur_pc = pc;
/* must duplicate otherwise the variable value may
be destroyed before JS code accesses it */
op1 = JS_DupValue(ctx, op1);
@@ -18215,6 +18261,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
var_buf[idx] = JS_NewInt32(ctx, val - 1);
} else {
dec_loc_slow:
+ sf->cur_pc = pc;
/* must duplicate otherwise the variable value may
be destroyed before JS code accesses it */
op1 = JS_DupValue(ctx, op1);
@@ -18231,6 +18278,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
} else {
+ sf->cur_pc = pc;
if (js_not_slow(ctx, sp))
goto exception;
}
@@ -18250,6 +18298,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-2] = JS_NewInt32(ctx, v1 << v2);
sp--;
} else {
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -18270,6 +18319,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
v2);
sp--;
} else {
+ sf->cur_pc = pc;
if (js_shr_slow(ctx, sp))
goto exception;
sp--;
@@ -18289,6 +18339,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
(int)JS_VALUE_GET_INT(op1) >> v2);
sp--;
} else {
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -18306,6 +18357,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_VALUE_GET_INT(op2));
sp--;
} else {
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -18323,6 +18375,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_VALUE_GET_INT(op2));
sp--;
} else {
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -18340,6 +18393,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_VALUE_GET_INT(op2));
sp--;
} else {
+ sf->cur_pc = pc;
if (js_binary_logic_slow(ctx, sp, opcode))
goto exception;
sp--;
@@ -18358,6 +18412,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
sp--; \
} else { \
+ sf->cur_pc = pc; \
if (slow_call) \
goto exception; \
sp--; \
@@ -18375,16 +18430,19 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
CASE(OP_in):
+ sf->cur_pc = pc;
if (js_operator_in(ctx, sp))
goto exception;
sp--;
BREAK;
CASE(OP_private_in):
+ sf->cur_pc = pc;
if (js_operator_private_in(ctx, sp))
goto exception;
sp--;
BREAK;
CASE(OP_instanceof):
+ sf->cur_pc = pc;
if (js_operator_instanceof(ctx, sp))
goto exception;
sp--;
@@ -18401,6 +18459,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
CASE(OP_delete):
+ sf->cur_pc = pc;
if (js_operator_delete(ctx, sp))
goto exception;
sp--;
@@ -18412,6 +18471,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
pc += 4;
+ sf->cur_pc = pc;
ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0);
if (unlikely(ret < 0))
@@ -18422,6 +18482,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_to_object):
if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
+ sf->cur_pc = pc;
ret_val = JS_ToObject(ctx, sp[-1]);
if (JS_IsException(ret_val))
goto exception;
@@ -18437,6 +18498,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
case JS_TAG_SYMBOL:
break;
default:
+ sf->cur_pc = pc;
ret_val = JS_ToPropertyKey(ctx, sp[-1]);
if (JS_IsException(ret_val))
goto exception;
@@ -18458,6 +18520,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
case JS_TAG_SYMBOL:
break;
default:
+ sf->cur_pc = pc;
ret_val = JS_ToPropertyKey(ctx, sp[-1]);
if (JS_IsException(ret_val))
goto exception;
@@ -18491,6 +18554,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
diff = get_u32(pc + 4);
is_with = pc[8];
pc += 9;
+ sf->cur_pc = pc;
obj = sp[-1];
ret = JS_HasProperty(ctx, obj, atom);
@@ -24692,14 +24756,13 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
case TOK_IDENT:
{
JSAtom name;
+ const uint8_t *source_ptr;
if (s->token.u.ident.is_reserved) {
return js_parse_error_reserved_identifier(s);
}
+ source_ptr = s->token.ptr;
if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
peek_token(s, TRUE) != '\n') {
- const uint8_t *source_ptr;
-
- source_ptr = s->token.ptr;
if (next_token(s))
return -1;
if (s->token.val == TOK_FUNCTION) {
@@ -24718,11 +24781,12 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
return -1;
}
name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s)) { /* update line number before emitting code */
+ if (next_token(s)) {
JS_FreeAtom(s->ctx, name);
return -1;
}
do_get_var:
+ emit_source_pos(s, source_ptr);
emit_op(s, OP_scope_get_var);
emit_u32(s, name);
emit_u16(s, s->cur_func->scope_level);
@@ -25315,6 +25379,7 @@ static __exception int js_parse_delete(JSParseState *s)
static __exception int js_parse_unary(JSParseState *s, int parse_flags)
{
int op;
+ const uint8_t *op_token_ptr;
switch(s->token.val) {
case '+':
@@ -25322,6 +25387,7 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
case '!':
case '~':
case TOK_VOID:
+ op_token_ptr = s->token.ptr;
op = s->token.val;
if (next_token(s))
return -1;
@@ -25329,15 +25395,18 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
return -1;
switch(op) {
case '-':
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_neg);
break;
case '+':
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_plus);
break;
case '!':
emit_op(s, OP_lnot);
break;
case '~':
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_not);
break;
case TOK_VOID:
@@ -25355,12 +25424,14 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
int opcode, op, scope, label;
JSAtom name;
op = s->token.val;
+ op_token_ptr = s->token.ptr;
if (next_token(s))
return -1;
if (js_parse_unary(s, 0))
return -1;
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
return -1;
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_dec + op - TOK_DEC);
put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
FALSE);
@@ -25409,8 +25480,10 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
int opcode, op, scope, label;
JSAtom name;
op = s->token.val;
+ op_token_ptr = s->token.ptr;
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
return -1;
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_post_dec + op - TOK_DEC);
put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
FALSE);
@@ -25430,10 +25503,12 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
return -1;
}
+ op_token_ptr = s->token.ptr;
if (next_token(s))
return -1;
if (js_parse_unary(s, PF_POW_ALLOWED))
return -1;
+ emit_source_pos(s, op_token_ptr);
emit_op(s, OP_pow);
}
}
@@ -25903,6 +25978,8 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
op = s->token.val;
if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
int label;
+ const uint8_t *op_token_ptr;
+ op_token_ptr = s->token.ptr;
if (next_token(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
@@ -25924,6 +26001,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
OP_pow,
};
op = assign_opcodes[op - TOK_MUL_ASSIGN];
+ emit_source_pos(s, op_token_ptr);
emit_op(s, op);
}
put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);
diff --git a/tests/test_builtin.js b/tests/test_builtin.js
index 174f216..423841d 100644
--- a/tests/test_builtin.js
+++ b/tests/test_builtin.js
@@ -509,28 +509,52 @@ function test_typed_array()
assert(a.toString(), "1,2,10,11");
}
-function check_error_pos(e, expected_error, line_num, col_num)
+/* return [s, line_num, col_num] where line_num and col_num are the
+ position of the '@' character in 'str'. 's' is str without the '@'
+ character */
+function get_string_pos(str)
{
- var expected_pos;
+ var p, line_num, col_num, s, q, r;
+ p = str.indexOf('@');
+ assert(p >= 0, true);
+ q = 0;
+ line_num = 1;
+ for(;;) {
+ r = str.indexOf('\n', q);
+ if (r < 0 || r >= p)
+ break;
+ q = r + 1;
+ line_num++;
+ }
+ col_num = p - q + 1;
+ s = str.slice(0, p) + str.slice(p + 1);
+ return [s, line_num, col_num];
+}
+
+function check_error_pos(e, expected_error, line_num, col_num, level)
+{
+ var expected_pos, tab, line;
+ level |= 0;
expected_pos = ":" + line_num + ":" + col_num;
- if (expected_error === SyntaxError)
- expected_pos += "\n";
- else
- expected_pos += ")";
- if (e.stack.indexOf(expected_pos) < 0) {
+ tab = e.stack.split("\n");
+ line = tab[level];
+ if (line.slice(-1) == ')')
+ line = line.slice(0, -1);
+ if (line.indexOf(expected_pos) < 0) {
throw_error("unexpected line or column number. error=" + e.message +
- ".got |" + e.stack +
- "|, expected |" + expected_pos + "|");
+ ".got |" + line + "|, expected |" + expected_pos + "|");
}
}
function assert_json_error(str, line_num, col_num)
{
var err = false;
- var expected_pos;
+ var expected_pos, tab;
+
+ tab = get_string_pos(str);
try {
- JSON.parse(str);
+ JSON.parse(tab[0]);
} catch(e) {
err = true;
if (!(e instanceof SyntaxError)) {
@@ -538,7 +562,7 @@ function assert_json_error(str, line_num, col_num)
return;
}
/* XXX: the way quickjs returns JSON errors is not similar to Node or spiderMonkey */
- check_error_pos(e, SyntaxError, line_num, col_num);
+ check_error_pos(e, SyntaxError, tab[1], tab[2]);
}
if (!err) {
throw_error("expected exception");
@@ -569,8 +593,8 @@ function test_json()
]
]`);
- assert_json_error('\n" \\x"', 2, 4);
- assert_json_error('\n{ "a": x }"', 2, 8);
+ assert_json_error('\n" @\\x"');
+ assert_json_error('\n{ "a": @x }"');
}
function test_date()
@@ -1005,53 +1029,88 @@ function test_rope()
rope_concat(100000, -1);
}
-
-function eval_error(eval_str, expected_error, line_num, col_num)
+function eval_error(eval_str, expected_error, level)
{
var err = false;
- var expected_pos;
+ var expected_pos, tab;
+
+ tab = get_string_pos(eval_str);
try {
- eval(eval_str);
+ eval(tab[0]);
} catch(e) {
err = true;
if (!(e instanceof expected_error)) {
throw_error("unexpected exception type");
return;
}
- check_error_pos(e, expected_error, line_num, col_num);
+ check_error_pos(e, expected_error, tab[1], tab[2], level);
}
if (!err) {
throw_error("expected exception");
}
}
+var poisoned_number = {
+ valueOf: function() { throw Error("poisoned number") },
+};
+
function test_line_column_numbers()
{
- var f, e;
+ var f, e, tab;
+ /* The '@' character provides the expected position of the
+ error. It is removed before evaluating the string. */
+
/* parsing */
- eval_error("\n 123 a ", SyntaxError, 2, 6);
- eval_error("\n /* ", SyntaxError, 2, 3);
- eval_error("function f a", SyntaxError, 1, 13);
+ eval_error("\n 123 @a ", SyntaxError);
+ eval_error("\n @/* ", SyntaxError);
+ eval_error("function f @a", SyntaxError);
/* currently regexp syntax errors point to the start of the regexp */
- eval_error("\n /aaa]/u", SyntaxError, 2, 3);
+ eval_error("\n @/aaa]/u", SyntaxError);
/* function definitions */
- e = eval("\n function f() { }; f;");
- assert(e.lineNumber, 2);
- assert(e.columnNumber, 4);
+ tab = get_string_pos("\n @function f() { }; f;");
+ e = eval(tab[0]);
+ assert(e.lineNumber, tab[1]);
+ assert(e.columnNumber, tab[2]);
/* errors */
- e = eval('\n Error("hello");');
- check_error_pos(e, Error, 2, 8);
- eval_error('\n throw Error("hello");', Error, 2, 14);
- eval_error('\n 2 * Symbol();', TypeError, 2, 5);
- eval_error('\n "café" * Symbol();', TypeError, 2, 10);
- eval_error('\n null[0];', TypeError, 2, 6);
- eval_error('\n null . abcd;', TypeError, 2, 7);
- eval_error('\n null ( 1234 );', TypeError, 2, 7);
+ tab = get_string_pos('\n Error@("hello");');
+ e = eval(tab[0]);
+ check_error_pos(e, Error, tab[1], tab[2]);
+
+ eval_error('\n throw Error@("hello");', Error);
+
+ /* operators */
+ eval_error('\n 1 + 2 @* poisoned_number;', Error, 1);
+ eval_error('\n 1 + "café" @* poisoned_number;', Error, 1);
+ eval_error('\n 1 + 2 @** poisoned_number;', Error, 1);
+ eval_error('\n 2 * @+ poisoned_number;', Error, 1);
+ eval_error('\n 2 * @- poisoned_number;', Error, 1);
+ eval_error('\n 2 * @~ poisoned_number;', Error, 1);
+ eval_error('\n 2 * @++ poisoned_number;', Error, 1);
+ eval_error('\n 2 * @-- poisoned_number;', Error, 1);
+ eval_error('\n 2 * poisoned_number @++;', Error, 1);
+ eval_error('\n 2 * poisoned_number @--;', Error, 1);
+
+ /* accessors */
+ eval_error('\n 1 + null@[0];', TypeError);
+ eval_error('\n 1 + null @. abcd;', TypeError);
+ eval_error('\n 1 + null @( 1234 );', TypeError);
+ eval_error('var obj = { get a() { throw Error("test"); } }\n 1 + obj @. a;',
+ Error, 1);
+ eval_error('var obj = { set a(b) { throw Error("test"); } }\n obj @. a = 1;',
+ Error, 1);
+
+ /* variables reference */
+ eval_error('\n 1 + @not_def', ReferenceError, 0);
+
+ /* assignments */
+ eval_error('1 + (@not_def = 1)', ReferenceError, 0);
+ eval_error('1 + (@not_def += 2)', ReferenceError, 0);
+ eval_error('var a;\n 1 + (a @+= poisoned_number);', Error, 1);
}
test();