···8686 #define F_RETURN 16U // return has been executed
8787 #define F_THROW 32U // throw has been executed
8888 #define F_SWITCH 64U // we are inside a switch statement
8989+ #define F_STRICT 128U // strict mode is enabled
8990 jsoff_t clen; // code snippet length
9091 jsoff_t pos; // current parsing position
9192 jsoff_t toff; // offset of the last parsed token
···39823983 return res;
39833984}
3984398539863986+static jsval_t js_with(struct js *js) {
39873987+ uint8_t flags = js->flags, exe = !(flags & F_NOEXEC);
39883988+ jsval_t res = js_mkundef();
39893989+39903990+ if (flags & F_STRICT) {
39913991+ return js_mkerr(js, "with statement not allowed in strict mode");
39923992+ }
39933993+39943994+ js->consumed = 1;
39953995+ if (!expect(js, TOK_LPAREN, &res)) return res;
39963996+39973997+ jsval_t obj_expr = js_expr(js);
39983998+ if (is_err(obj_expr)) return obj_expr;
39993999+40004000+ if (!expect(js, TOK_RPAREN, &res)) return res;
40014001+40024002+ if (exe) {
40034003+ jsval_t obj = resolveprop(js, obj_expr);
40044004+ if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) {
40054005+ return js_mkerr(js, "with requires object");
40064006+ }
40074007+40084008+ jsval_t with_obj = obj;
40094009+ if (vtype(obj) == T_FUNC) {
40104010+ with_obj = mkval(T_OBJ, vdata(obj));
40114011+ }
40124012+40134013+ jsoff_t parent_scope_offset = (jsoff_t) vdata(js->scope);
40144014+ jsval_t with_scope = mkentity(js, 0 | T_OBJ, &parent_scope_offset, sizeof(parent_scope_offset));
40154015+40164016+ jsoff_t prop_off = loadoff(js, (jsoff_t) vdata(with_obj)) & ~(3U | CONSTMASK);
40174017+ while (prop_off < js->brk && prop_off != 0) {
40184018+ jsoff_t koff = loadoff(js, prop_off + (jsoff_t) sizeof(prop_off));
40194019+ jsval_t val = loadval(js, prop_off + (jsoff_t) (sizeof(prop_off) + sizeof(koff)));
40204020+40214021+ jsval_t new_prop = mkprop(js, with_scope, mkval(T_STR, koff), val, false);
40224022+ if (is_err(new_prop)) return new_prop;
40234023+40244024+ prop_off = loadoff(js, prop_off) & ~(3U | CONSTMASK);
40254025+ }
40264026+40274027+ jsval_t saved_scope = js->scope;
40284028+ js->scope = with_scope;
40294029+40304030+ res = js_block_or_stmt(js);
40314031+40324032+ js->scope = saved_scope;
40334033+ } else {
40344034+ res = js_block_or_stmt(js);
40354035+ }
40364036+40374037+ js->flags = flags;
40384038+ return res;
40394039+}
40404040+39854041static jsval_t js_class_decl(struct js *js) {
39864042 uint8_t exe = !(js->flags & F_NOEXEC);
39874043 js->consumed = 1;
···41794235 }
41804236}
4181423742384238+static void js_var(struct js *js, jsval_t *res) {
42394239+ if (!js->var_warning_shown) {
42404240+ fprintf(stderr, "Warning: 'var' is deprecated, use 'let' or 'const' instead\n");
42414241+ js->var_warning_shown = true;
42424242+ }
42434243+ *res = js_let(js);
42444244+}
42454245+42464246+static void js_async(struct js *js, jsval_t *res) {
42474247+ js->consumed = 1;
42484248+ if (next(js) == TOK_FUNC) {
42494249+ *res = js_func_decl_async(js);
42504250+ return;
42514251+ }
42524252+ *res = js_mkerr(js, "async must be followed by function");
42534253+}
42544254+41824255static jsval_t js_stmt(struct js *js) {
41834256 jsval_t res;
41844257 if (js->brk > js->gct) js_gc(js);
···41884261 case TOK_DEFAULT: case TOK_FINALLY:
41894262 res = js_mkerr(js, "SyntaxError '%.*s'", (int) js->tlen, js->code + js->toff);
41904263 break;
41914191- case TOK_WITH: case TOK_YIELD:
41924192- res = js_mkerr(js, "'%.*s' not implemented", (int) js->tlen, js->code + js->toff);
41934193- break;
41944194- case TOK_THROW: js_throw_handle(js, &res); break;
41954195- case TOK_VAR:
41964196- if (!js->var_warning_shown) {
41974197- fprintf(stderr, "Warning: 'var' is deprecated, use 'let' or 'const' instead\n");
41984198- js->var_warning_shown = true;
41994199- }
42004200- res = js_let(js);
42644264+ case TOK_YIELD:
42654265+ res = js_mkerr(js, " '%.*s' not implemented", (int) js->tlen, js->code + js->toff);
42014266 break;
42674267+ case TOK_THROW: js_throw_handle(js, &res); break;
42684268+ case TOK_VAR: js_var(js, &res); break;
42694269+ case TOK_ASYNC: js_async(js, &res); break;
42704270+ case TOK_WITH: res = js_with(js); break;
42024271 case TOK_SWITCH: res = js_switch(js); break;
42034272 case TOK_WHILE: res = js_while(js); break;
42044273 case TOK_DO: res = js_do_while(js); break;
···42074276 case TOK_LET: res = js_let(js); break;
42084277 case TOK_CONST: res = js_const(js); break;
42094278 case TOK_FUNC: res = js_func_decl(js); break;
42104210- case TOK_ASYNC: js->consumed = 1; if (next(js) == TOK_FUNC) res = js_func_decl_async(js); else return js_mkerr(js, "async must be followed by function"); break;
42114279 case TOK_CLASS: res = js_class_decl(js); break;
42124280 case TOK_IF: res = js_if(js); break;
42134281 case TOK_LBRACE: res = js_block(js, !(js->flags & F_NOEXEC)); break;
42144282 case TOK_FOR: res = js_for(js); break;
42154283 case TOK_RETURN: res = js_return(js); break;
42164216- case TOK_TRY: res = js_try(js); break;
42844284+ case TOK_TRY: res = js_try(js); break;
42174285 default: res = resolveprop(js, js_expr(js)); break;
42184286 }
42194287···58155883 js->clen = (jsoff_t) len;
58165884 js->pos = 0;
58175885 js->cstk = &res;
58865886+58875887+ uint8_t saved_tok = js->tok;
58885888+ jsoff_t saved_pos = js->pos;
58895889+ uint8_t saved_consumed = js->consumed;
58905890+ js->consumed = 1;
58915891+58925892+ if (next(js) == TOK_STRING) {
58935893+ const char *str = &js->code[js->toff + 1];
58945894+ size_t str_len = js->tlen - 2;
58955895+ if (str_len == 10 && memcmp(str, "use strict", 10) == 0) {
58965896+ js->flags |= F_STRICT;
58975897+ }
58985898+ }
58995899+59005900+ js->tok = saved_tok;
59015901+ js->pos = saved_pos;
59025902+ js->consumed = saved_consumed;
59035903+58185904 while (next(js) != TOK_EOF && !is_err(res)) {
58195905 res = js_stmt(js);
58205906 if (js->flags & F_RETURN) break;
+7
tests/test_with_strict.cjs
···11+"use strict";
22+33+// Test 2: with statement should fail with 'use strict'
44+let obj = { x: 10, y: 20 };
55+with (obj) {
66+ console.log("This should not run");
77+}
+7
tests/test_without_strict.cjs
···11+// Test 1: with statement should work without 'use strict'
22+let obj = { x: 10, y: 20 };
33+with (obj) {
44+ console.log("Test 1 - x:", x); // should print 10
55+ console.log("Test 1 - y:", y); // should print 20
66+}
77+console.log("Test 1 passed");