MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

squash

+125 -4
+1 -1
meson.build
··· 79 79 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 80 80 81 81 version_conf = configuration_data() 82 - version_conf.set('ANT_VERSION', '0.2.3.11') 82 + version_conf.set('ANT_VERSION', '0.2.3.12') 83 83 version_conf.set('ANT_GIT_HASH', git_hash) 84 84 version_conf.set('ANT_BUILD_DATE', build_date) 85 85
+124 -3
src/ant.c
··· 7670 7670 jsval_t obj = mkobj(js, 0); 7671 7671 jsval_t saved_this = js->this_val; 7672 7672 js->this_val = obj; 7673 - jsval_t result = js_postfix(js); 7673 + 7674 + // Parse constructor: can be identifier, member expression, or grouped 7675 + // We need to parse the constructor WITHOUT continuing to parse property access 7676 + // after the call, because property access should be on the constructed object. 7677 + jsval_t ctor = js_group(js); // Parse identifier or (expr) 7678 + if (is_err(ctor)) { 7679 + js->this_val = saved_this; 7680 + return ctor; 7681 + } 7682 + 7683 + // Handle member access on the constructor itself: new foo.Bar(), new foo[x]() 7684 + while (next(js) == TOK_DOT || next(js) == TOK_LBRACKET) { 7685 + if (js->tok == TOK_DOT) { 7686 + js->consumed = 1; 7687 + if (vtype(ctor) == T_CODEREF) { 7688 + ctor = lookup(js, &js->code[coderefoff(ctor)], codereflen(ctor)); 7689 + if (is_err(ctor)) { js->this_val = saved_this; return ctor; } 7690 + } 7691 + if (next(js) != TOK_IDENTIFIER && !is_keyword_propname(js->tok)) { 7692 + js->this_val = saved_this; 7693 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected"); 7694 + } 7695 + js->consumed = 1; 7696 + jsval_t prop_name = mkcoderef((jsoff_t)js->toff, (jsoff_t)js->tlen); 7697 + ctor = do_op(js, TOK_DOT, ctor, prop_name); 7698 + } else { 7699 + js->consumed = 1; 7700 + if (vtype(ctor) == T_CODEREF) { 7701 + ctor = lookup(js, &js->code[coderefoff(ctor)], codereflen(ctor)); 7702 + if (is_err(ctor)) { js->this_val = saved_this; return ctor; } 7703 + } 7704 + jsval_t idx = js_expr(js); 7705 + if (is_err(idx)) { js->this_val = saved_this; return idx; } 7706 + if (next(js) != TOK_RBRACKET) { js->this_val = saved_this; return js_mkerr_typed(js, JS_ERR_SYNTAX, "] expected"); } 7707 + js->consumed = 1; 7708 + ctor = do_op(js, TOK_BRACKET, ctor, idx); 7709 + } 7710 + } 7711 + 7712 + // Resolve the constructor if it's still a coderef 7713 + if (vtype(ctor) == T_CODEREF) { 7714 + ctor = lookup(js, &js->code[coderefoff(ctor)], codereflen(ctor)); 7715 + if (is_err(ctor)) { js->this_val = saved_this; return ctor; } 7716 + } 7717 + if (vtype(ctor) == T_PROP || vtype(ctor) == T_PROPREF) { 7718 + ctor = resolveprop(js, ctor); 7719 + } 7720 + 7721 + // Now handle optional call arguments: new Foo() vs new Foo 7722 + jsval_t result; 7723 + if (next(js) == TOK_LPAREN) { 7724 + push_this(obj); 7725 + jsval_t params = js_call_params(js); 7726 + if (is_err(params)) { 7727 + pop_this(); 7728 + js->this_val = saved_this; 7729 + return params; 7730 + } 7731 + result = do_op(js, TOK_CALL, ctor, params); 7732 + pop_this(); 7733 + } else { 7734 + // new Foo without parentheses - call with no args 7735 + push_this(obj); 7736 + result = do_op(js, TOK_CALL, ctor, mkcoderef(0, 0)); 7737 + pop_this(); 7738 + // do_call_op set consumed=1, but we didn't consume the peeked token 7739 + // Reset consumed so the peeked token can be seen by caller 7740 + js->consumed = 0; 7741 + } 7742 + 7674 7743 jsval_t constructed_obj = js->this_val; 7675 7744 js->this_val = saved_this; 7676 - if (vtype(result) == T_OBJ || vtype(result) == T_ARR || vtype(result) == T_PROMISE || vtype(result) == T_FUNC) return result; 7677 - return constructed_obj; 7745 + 7746 + jsval_t new_result; 7747 + if (vtype(result) == T_OBJ || vtype(result) == T_ARR || vtype(result) == T_PROMISE || vtype(result) == T_FUNC) { 7748 + new_result = result; 7749 + } else { 7750 + new_result = constructed_obj; 7751 + } 7752 + 7753 + // Continue parsing property access after 'new X()' - e.g., new A().foo 7754 + // Track the object for method calls (this binding) 7755 + jsval_t call_obj = js_mkundef(); 7756 + while (next(js) == TOK_DOT || next(js) == TOK_LBRACKET || next(js) == TOK_OPTIONAL_CHAIN || next(js) == TOK_LPAREN) { 7757 + if (js->tok == TOK_DOT || js->tok == TOK_OPTIONAL_CHAIN) { 7758 + uint8_t op = js->tok; 7759 + js->consumed = 1; 7760 + call_obj = new_result; // Save object for potential method call 7761 + if (op == TOK_OPTIONAL_CHAIN && (vtype(call_obj) == T_NULL || vtype(call_obj) == T_UNDEF)) { 7762 + new_result = js_mkundef(); 7763 + call_obj = js_mkundef(); 7764 + } else { 7765 + if (next(js) != TOK_IDENTIFIER && !is_keyword_propname(js->tok)) { 7766 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected"); 7767 + } 7768 + js->consumed = 1; 7769 + jsval_t prop_name = mkcoderef((jsoff_t)js->toff, (jsoff_t)js->tlen); 7770 + new_result = do_op(js, op, new_result, prop_name); 7771 + } 7772 + } else if (js->tok == TOK_LBRACKET) { 7773 + js->consumed = 1; 7774 + call_obj = new_result; // Save object for potential method call 7775 + jsval_t idx = js_expr(js); 7776 + if (is_err(idx)) return idx; 7777 + if (next(js) != TOK_RBRACKET) return js_mkerr_typed(js, JS_ERR_SYNTAX, "] expected"); 7778 + js->consumed = 1; 7779 + new_result = do_op(js, TOK_BRACKET, new_result, idx); 7780 + } else if (js->tok == TOK_LPAREN) { 7781 + // Method call - use saved object as 'this' 7782 + jsval_t func_this = call_obj; 7783 + if (vtype(func_this) == T_UNDEF) { 7784 + // No property access before call, use global this 7785 + func_this = js->this_val; 7786 + } 7787 + push_this(func_this); 7788 + jsval_t params = js_call_params(js); 7789 + if (is_err(params)) { 7790 + pop_this(); 7791 + return params; 7792 + } 7793 + new_result = do_op(js, TOK_CALL, new_result, params); 7794 + pop_this(); 7795 + call_obj = js_mkundef(); // Reset after call 7796 + } 7797 + } 7798 + return new_result; 7678 7799 } else if (next(js) == TOK_DELETE) { 7679 7800 js->consumed = 1; 7680 7801