diff --git a/quickjs.c b/quickjs.c index bb2491d8a..bbd3b6447 100644 --- a/quickjs.c +++ b/quickjs.c @@ -422,7 +422,7 @@ struct JSContext { /* if NULL, eval is not supported */ JSValue (*eval_internal)(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, - const char *filename, int flags, int scope_idx); + const char *filename, int line, int flags, int scope_idx); void *user_opaque; }; @@ -1236,7 +1236,7 @@ static void js_async_function_resolve_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); static JSValue JS_EvalInternal(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, - const char *filename, int flags, int scope_idx); + const char *filename, int line, int flags, int scope_idx); static void js_free_module_def(JSContext *ctx, JSModuleDef *m); static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkFunc *mark_func); @@ -33431,12 +33431,12 @@ static __exception int js_parse_program(JSParseState *s) static void js_parse_init(JSContext *ctx, JSParseState *s, const char *input, size_t input_len, - const char *filename) + const char *filename, int line) { memset(s, 0, sizeof(*s)); s->ctx = ctx; s->filename = filename; - s->line_num = 1; + s->line_num = line; s->col_num = 1; s->buf_start = s->buf_ptr = (const uint8_t *)input; s->buf_end = s->buf_ptr + input_len; @@ -33488,7 +33488,7 @@ JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj) /* `export_name` and `input` may be pure ASCII or UTF-8 encoded */ static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, - const char *filename, int flags, int scope_idx) + const char *filename, int line, int flags, int scope_idx) { JSParseState s1, *s = &s1; int err, eval_type; @@ -33500,7 +33500,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, JSModuleDef *m; bool is_strict_mode; - js_parse_init(ctx, s, input, input_len, filename); + js_parse_init(ctx, s, input, input_len, filename, line); skip_shebang(&s->buf_ptr, s->buf_end); eval_type = flags & JS_EVAL_TYPE_MASK; @@ -33530,7 +33530,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, is_strict_mode = true; } } - fd = js_new_function_def(ctx, NULL, true, false, filename, 1, 1); + fd = js_new_function_def(ctx, NULL, true, false, filename, line, 1); if (!fd) goto fail1; s->cur_func = fd; @@ -33603,12 +33603,12 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValue this_obj, /* the indirection is needed to make 'eval' optional */ static JSValue JS_EvalInternal(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, - const char *filename, int flags, int scope_idx) + const char *filename, int line, int flags, int scope_idx) { if (unlikely(!ctx->eval_internal)) { return JS_ThrowTypeError(ctx, "eval is not supported"); } - return ctx->eval_internal(ctx, this_obj, input, input_len, filename, + return ctx->eval_internal(ctx, this_obj, input, input_len, filename, line, flags, scope_idx); } @@ -33624,7 +33624,7 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValue this_obj, str = JS_ToCStringLen(ctx, &len, val); if (!str) return JS_EXCEPTION; - ret = JS_EvalInternal(ctx, this_obj, str, len, "", flags, scope_idx); + ret = JS_EvalInternal(ctx, this_obj, str, len, "", 1, flags, scope_idx); JS_FreeCString(ctx, str); return ret; @@ -33634,11 +33634,36 @@ JSValue JS_EvalThis(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int eval_flags) { + JSEvalOptions options = { + .version = JS_EVAL_OPTIONS_VERSION, + .filename = filename, + .line_num = 1, + .eval_flags = eval_flags + }; + return JS_EvalThis2(ctx, this_obj, input, input_len, &options); +} + +JSValue JS_EvalThis2(JSContext *ctx, JSValue this_obj, + const char *input, size_t input_len, + JSEvalOptions *options) +{ + const char *filename = ""; + int line = 1; + int eval_flags = 0; + if (options) { + if (options->version != JS_EVAL_OPTIONS_VERSION) + return JS_ThrowInternalError(ctx, "bad JSEvalOptions version"); + if (options->filename) + filename = options->filename; + if (options->line_num != 0) + line = options->line_num; + eval_flags = options->eval_flags; + } JSValue ret; assert((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_GLOBAL || (eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE); - ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename, + ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename, line, eval_flags, -1); return ret; } @@ -33646,8 +33671,18 @@ JSValue JS_EvalThis(JSContext *ctx, JSValue this_obj, JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags) { - return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename, - eval_flags); + JSEvalOptions options = { + .version = JS_EVAL_OPTIONS_VERSION, + .filename = filename, + .line_num = 1, + .eval_flags = eval_flags + }; + return JS_EvalThis2(ctx, ctx->global_obj, input, input_len, &options); +} + +JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len, JSEvalOptions *options) +{ + return JS_EvalThis2(ctx, ctx->global_obj, input, input_len, options); } int JS_ResolveModule(JSContext *ctx, JSValue obj) @@ -45293,7 +45328,7 @@ JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, const char JSParseState s1, *s = &s1; JSValue val = JS_UNDEFINED; - js_parse_init(ctx, s, buf, buf_len, filename); + js_parse_init(ctx, s, buf, buf_len, filename, 1); if (json_next_token(s)) goto fail; val = json_parse_value(s); @@ -56236,7 +56271,7 @@ bool JS_DetectModule(const char *input, size_t input_len) return false; } JS_AddIntrinsicRegExp(ctx); // otherwise regexp literals don't parse - val = __JS_EvalInternal(ctx, JS_UNDEFINED, input, input_len, "", + val = __JS_EvalInternal(ctx, JS_UNDEFINED, input, input_len, "", 1, JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY, -1); if (JS_IsException(val)) { const char *msg = JS_ToCString(ctx, rt->current_exception); diff --git a/quickjs.h b/quickjs.h index b54154c7d..863adabee 100644 --- a/quickjs.h +++ b/quickjs.h @@ -540,6 +540,16 @@ typedef struct JSClassDef { JSClassExoticMethods *exotic; } JSClassDef; +#define JS_EVAL_OPTIONS_VERSION 1 + +typedef struct JSEvalOptions { + int version; + int eval_flags; + const char *filename; + int line_num; + // can add new fields in ABI-compatible manner by incrementing JS_EVAL_OPTIONS_VERSION +} JSEvalOptions; + #define JS_INVALID_CLASS_ID 0 JS_EXTERN JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id); /* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */ @@ -803,10 +813,14 @@ JS_EXTERN bool JS_DetectModule(const char *input, size_t input_len); /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ JS_EXTERN JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags); -/* same as JS_Eval() but with an explicit 'this_obj' parameter */ +JS_EXTERN JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len, + JSEvalOptions *options); JS_EXTERN JSValue JS_EvalThis(JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int eval_flags); +JS_EXTERN JSValue JS_EvalThis2(JSContext *ctx, JSValue this_obj, + const char *input, size_t input_len, + JSEvalOptions *options); JS_EXTERN JSValue JS_GetGlobalObject(JSContext *ctx); JS_EXTERN int JS_IsInstanceOf(JSContext *ctx, JSValue val, JSValue obj); JS_EXTERN int JS_DefineProperty(JSContext *ctx, JSValue this_obj,