add functinos

This commit is contained in:
2026-02-07 23:38:39 -06:00
parent 243d92f7f3
commit 2f6700415e

View File

@@ -570,6 +570,9 @@ typedef enum MachOpcode {
MACH_CALLMETHOD, /* Method call: R(A)=obj, B=nargs in R(A+2)..R(A+1+B), C=cpool key */
MACH_EQ_TOL, /* R(A) = eq_tol(R(B), R(B+1), R(B+2)), C=3 */
MACH_NEQ_TOL, /* R(A) = ne_tol(R(B), R(B+1), R(B+2)), C=3 */
MACH_NOP,
MACH_OP_COUNT
@@ -632,6 +635,8 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
[MACH_HASPROP] = "hasprop",
[MACH_REGEXP] = "regexp",
[MACH_CALLMETHOD] = "callmethod",
[MACH_EQ_TOL] = "eq_tol",
[MACH_NEQ_TOL] = "neq_tol",
[MACH_NOP] = "nop",
};
@@ -3886,6 +3891,21 @@ static int js_string_compare_value (JSContext *ctx, JSValue op1, JSValue op2, BO
return (len1 < len2) ? -1 : 1;
}
static int js_string_compare_value_nocase (JSContext *ctx, JSValue op1, JSValue op2) {
(void)ctx;
int len1 = js_string_value_len (op1);
int len2 = js_string_value_len (op2);
if (len1 != len2) return 1;
for (int i = 0; i < len1; i++) {
uint32_t c1 = js_string_value_get (op1, i);
uint32_t c2 = js_string_value_get (op2, i);
if (c1 >= 'A' && c1 <= 'Z') c1 += 32;
if (c2 >= 'A' && c2 <= 'Z') c2 += 32;
if (c1 != c2) return 1;
}
return 0;
}
static JSValue JS_ConcatString (JSContext *ctx, JSValue op1, JSValue op2) {
if (unlikely (!JS_IsText (op1))) {
op1 = JS_ToString (ctx, op1);
@@ -28582,6 +28602,13 @@ redo:
} else if (p[1] == '=') {
p += 2;
s->token_val = TOK_DIV_ASSIGN;
} else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
} else {
p++;
s->token_val = c;
@@ -28705,70 +28732,250 @@ redo:
case '*':
if (p[1] == '=') { p += 2; s->token_val = TOK_MUL_ASSIGN; }
else if (p[1] == '*') {
if (p[2] == '=') { p += 3; s->token_val = TOK_POW_ASSIGN; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_POW_ASSIGN; }
else { p += 2; s->token_val = TOK_POW; }
} else { goto def_token; }
}
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '%':
if (p[1] == '=') { p += 2; s->token_val = TOK_MOD_ASSIGN; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '+':
if (p[1] == '=') { p += 2; s->token_val = TOK_PLUS_ASSIGN; }
else if (p[1] == '+') { p += 2; s->token_val = TOK_INC; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '-':
if (p[1] == '=') { p += 2; s->token_val = TOK_MINUS_ASSIGN; }
else if (p[1] == '-') { p += 2; s->token_val = TOK_DEC; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '<':
if (p[1] == '=') { p += 2; s->token_val = TOK_LTE; }
if (p[1] == '=' && p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[1] == '=') { p += 2; s->token_val = TOK_LTE; }
else if (p[1] == '<') {
if (p[2] == '=') { p += 3; s->token_val = TOK_SHL_ASSIGN; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_SHL_ASSIGN; }
else { p += 2; s->token_val = TOK_SHL; }
} else { goto def_token; }
}
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '>':
if (p[1] == '=') { p += 2; s->token_val = TOK_GTE; }
if (p[1] == '=' && p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[1] == '=') { p += 2; s->token_val = TOK_GTE; }
else if (p[1] == '>') {
if (p[2] == '>') {
if (p[3] == '=') { p += 4; s->token_val = TOK_SHR_ASSIGN; }
if (p[3] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 4;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 4;
}
else if (p[3] == '=') { p += 4; s->token_val = TOK_SHR_ASSIGN; }
else { p += 3; s->token_val = TOK_SHR; }
} else if (p[2] == '=') { p += 3; s->token_val = TOK_SAR_ASSIGN; }
}
else if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_SAR_ASSIGN; }
else { p += 2; s->token_val = TOK_SAR; }
} else { goto def_token; }
}
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '=':
if (p[1] == '=') {
if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_EQ; }
else { p += 2; s->token_val = TOK_EQ; }
} else if (p[1] == '>') { p += 2; s->token_val = TOK_ARROW; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '!':
if (p[1] == '=') {
if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_NEQ; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_NEQ; }
else { p += 2; s->token_val = TOK_NEQ; }
} else { goto def_token; }
break;
case '&':
if (p[1] == '&') {
if (p[2] == '=') { p += 3; s->token_val = TOK_LAND_ASSIGN; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_LAND_ASSIGN; }
else { p += 2; s->token_val = TOK_LAND; }
} else if (p[1] == '=') { p += 2; s->token_val = TOK_AND_ASSIGN; }
}
else if (p[1] == '=') { p += 2; s->token_val = TOK_AND_ASSIGN; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '|':
if (p[1] == '|') {
if (p[2] == '=') { p += 3; s->token_val = TOK_LOR_ASSIGN; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_LOR_ASSIGN; }
else { p += 2; s->token_val = TOK_LOR; }
} else if (p[1] == '=') { p += 2; s->token_val = TOK_OR_ASSIGN; }
}
else if (p[1] == '=') { p += 2; s->token_val = TOK_OR_ASSIGN; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '^':
if (p[1] == '=') { p += 2; s->token_val = TOK_XOR_ASSIGN; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '[':
if (p[1] == ']' && p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else { goto def_token; }
break;
case '~':
if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '?':
@@ -28905,6 +29112,13 @@ static int tokenize_next (ASTParseState *s) {
} else if (p[1] == '=') {
p += 2;
s->token_val = TOK_DIV_ASSIGN;
} else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
} else {
p++;
s->token_val = c;
@@ -29026,70 +29240,250 @@ static int tokenize_next (ASTParseState *s) {
case '*':
if (p[1] == '=') { p += 2; s->token_val = TOK_MUL_ASSIGN; }
else if (p[1] == '*') {
if (p[2] == '=') { p += 3; s->token_val = TOK_POW_ASSIGN; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_POW_ASSIGN; }
else { p += 2; s->token_val = TOK_POW; }
} else { goto def_token; }
}
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '%':
if (p[1] == '=') { p += 2; s->token_val = TOK_MOD_ASSIGN; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '+':
if (p[1] == '=') { p += 2; s->token_val = TOK_PLUS_ASSIGN; }
else if (p[1] == '+') { p += 2; s->token_val = TOK_INC; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '-':
if (p[1] == '=') { p += 2; s->token_val = TOK_MINUS_ASSIGN; }
else if (p[1] == '-') { p += 2; s->token_val = TOK_DEC; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '<':
if (p[1] == '=') { p += 2; s->token_val = TOK_LTE; }
if (p[1] == '=' && p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[1] == '=') { p += 2; s->token_val = TOK_LTE; }
else if (p[1] == '<') {
if (p[2] == '=') { p += 3; s->token_val = TOK_SHL_ASSIGN; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_SHL_ASSIGN; }
else { p += 2; s->token_val = TOK_SHL; }
} else { goto def_token; }
}
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '>':
if (p[1] == '=') { p += 2; s->token_val = TOK_GTE; }
if (p[1] == '=' && p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[1] == '=') { p += 2; s->token_val = TOK_GTE; }
else if (p[1] == '>') {
if (p[2] == '>') {
if (p[3] == '=') { p += 4; s->token_val = TOK_SHR_ASSIGN; }
if (p[3] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 4;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 4;
}
else if (p[3] == '=') { p += 4; s->token_val = TOK_SHR_ASSIGN; }
else { p += 3; s->token_val = TOK_SHR; }
} else if (p[2] == '=') { p += 3; s->token_val = TOK_SAR_ASSIGN; }
}
else if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_SAR_ASSIGN; }
else { p += 2; s->token_val = TOK_SAR; }
} else { goto def_token; }
}
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '=':
if (p[1] == '=') {
if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_EQ; }
else { p += 2; s->token_val = TOK_EQ; }
} else if (p[1] == '>') { p += 2; s->token_val = TOK_ARROW; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '!':
if (p[1] == '=') {
if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_NEQ; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_NEQ; }
else { p += 2; s->token_val = TOK_NEQ; }
} else { goto def_token; }
break;
case '&':
if (p[1] == '&') {
if (p[2] == '=') { p += 3; s->token_val = TOK_LAND_ASSIGN; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_LAND_ASSIGN; }
else { p += 2; s->token_val = TOK_LAND; }
} else if (p[1] == '=') { p += 2; s->token_val = TOK_AND_ASSIGN; }
}
else if (p[1] == '=') { p += 2; s->token_val = TOK_AND_ASSIGN; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '|':
if (p[1] == '|') {
if (p[2] == '=') { p += 3; s->token_val = TOK_LOR_ASSIGN; }
if (p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else if (p[2] == '=') { p += 3; s->token_val = TOK_LOR_ASSIGN; }
else { p += 2; s->token_val = TOK_LOR; }
} else if (p[1] == '=') { p += 2; s->token_val = TOK_OR_ASSIGN; }
}
else if (p[1] == '=') { p += 2; s->token_val = TOK_OR_ASSIGN; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '^':
if (p[1] == '=') { p += 2; s->token_val = TOK_XOR_ASSIGN; }
else if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '[':
if (p[1] == ']' && p[2] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 3;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 3;
}
else { goto def_token; }
break;
case '~':
if (p[1] == '!') {
s->token_u.ident.str = (const char *)p;
s->token_u.ident.len = 2;
s->token_u.ident.has_escape = FALSE;
s->token_u.ident.is_reserved = FALSE;
s->token_val = TOK_IDENT;
p += 2;
}
else { goto def_token; }
break;
case '?':
@@ -30491,6 +30885,18 @@ static int ast_sem_in_loop (ASTSemScope *scope) {
return 0;
}
static BOOL is_functino_name(const char *name) {
static const char *functinos[] = {
"+!", "-!", "*!", "/!", "%!", "**!",
"<!", ">!", "<=!", ">=!", "=!", "!=!",
"&!", "|!", "^!", "<<!", ">>!", ">>>!",
"&&!", "||!", "~!", "[]!", NULL
};
for (int i = 0; functinos[i]; i++)
if (strcmp(name, functinos[i]) == 0) return TRUE;
return FALSE;
}
static void ast_sem_check_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr);
static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt);
@@ -30743,6 +31149,11 @@ static void ast_sem_check_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr
if (strcmp (kind, "name") == 0) {
const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (expr, "name"));
if (name) {
if (is_functino_name(name)) {
cJSON_AddStringToObject (expr, "make", "functino");
cJSON_AddNumberToObject (expr, "level", -1);
return;
}
ASTSemLookup r = ast_sem_lookup_var (scope, name);
if (r.var) {
cJSON_AddNumberToObject (expr, "level", r.level);
@@ -31701,6 +32112,111 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
if (fn_expr)
fn_kind = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(fn_expr, "kind"));
/* Functino: inline operator call */
if (fn_kind && strcmp(fn_kind, "name") == 0) {
const char *fn_make = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(fn_expr, "make"));
if (fn_make && strcmp(fn_make, "functino") == 0) {
const char *fname = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(fn_expr, "name"));
if (dest < 0) dest = mach_reserve_reg(cs);
if (strcmp(fname, "~!") == 0) {
int save = cs->freereg;
int r = mach_compile_expr(cs, cJSON_GetArrayItem(args, 0), -1);
mach_emit(cs, MACH_ABC(MACH_BNOT, dest, r, 0));
mach_free_reg_to(cs, save);
return dest;
}
if (strcmp(fname, "[]!") == 0) {
int save = cs->freereg;
int r0 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 0), -1);
if (cs->freereg <= r0) cs->freereg = r0 + 1;
int r1 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 1), -1);
mach_emit(cs, MACH_ABC(MACH_GETINDEX, dest, r0, r1));
mach_free_reg_to(cs, save);
return dest;
}
if ((strcmp(fname, "=!") == 0 || strcmp(fname, "!=!") == 0) && nargs == 3) {
int save = cs->freereg;
int base = mach_reserve_reg(cs);
int r0 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 0), base);
if (r0 != base) mach_emit(cs, MACH_ABC(MACH_MOVE, base, r0, 0));
int r1_reg = mach_reserve_reg(cs);
int r1 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 1), r1_reg);
if (r1 != r1_reg) mach_emit(cs, MACH_ABC(MACH_MOVE, r1_reg, r1, 0));
int r2_reg = mach_reserve_reg(cs);
int r2 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 2), r2_reg);
if (r2 != r2_reg) mach_emit(cs, MACH_ABC(MACH_MOVE, r2_reg, r2, 0));
MachOpcode top = (strcmp(fname, "=!") == 0) ? MACH_EQ_TOL : MACH_NEQ_TOL;
mach_emit(cs, MACH_ABC(top, dest, base, 3));
mach_free_reg_to(cs, save);
return dest;
}
if (strcmp(fname, "&&!") == 0) {
int save = cs->freereg;
int r0 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 0), -1);
if (cs->freereg <= r0) cs->freereg = r0 + 1;
int r1 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 1), -1);
/* Non-short-circuiting: if left is falsy, result=left, else result=right */
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, r0, 0));
int jmp_pc = mach_current_pc(cs);
mach_emit(cs, MACH_AsBx(MACH_JMPFALSE, dest, 0));
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, r1, 0));
{
int offset = mach_current_pc(cs) - (jmp_pc + 1);
cs->code[jmp_pc] = MACH_AsBx(MACH_GET_OP(cs->code[jmp_pc]), dest, (int16_t)offset);
}
mach_free_reg_to(cs, save);
return dest;
}
if (strcmp(fname, "||!") == 0) {
int save = cs->freereg;
int r0 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 0), -1);
if (cs->freereg <= r0) cs->freereg = r0 + 1;
int r1 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 1), -1);
/* Non-short-circuiting: if left is truthy, result=left, else result=right */
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, r0, 0));
int jmp_pc = mach_current_pc(cs);
mach_emit(cs, MACH_AsBx(MACH_JMPTRUE, dest, 0));
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, r1, 0));
{
int offset = mach_current_pc(cs) - (jmp_pc + 1);
cs->code[jmp_pc] = MACH_AsBx(MACH_GET_OP(cs->code[jmp_pc]), dest, (int16_t)offset);
}
mach_free_reg_to(cs, save);
return dest;
}
/* Standard 2-arg binary functino */
{
int save = cs->freereg;
int r0 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 0), -1);
if (cs->freereg <= r0) cs->freereg = r0 + 1;
int r1 = mach_compile_expr(cs, cJSON_GetArrayItem(args, 1), -1);
MachOpcode op;
if (strcmp(fname, "+!") == 0) op = MACH_ADD;
else if (strcmp(fname, "-!") == 0) op = MACH_SUB;
else if (strcmp(fname, "*!") == 0) op = MACH_MUL;
else if (strcmp(fname, "/!") == 0) op = MACH_DIV;
else if (strcmp(fname, "%!") == 0) op = MACH_MOD;
else if (strcmp(fname, "**!") == 0) op = MACH_POW;
else if (strcmp(fname, "<!") == 0) op = MACH_LT;
else if (strcmp(fname, ">!") == 0) op = MACH_GT;
else if (strcmp(fname, "<=!") == 0) op = MACH_LE;
else if (strcmp(fname, ">=!") == 0) op = MACH_GE;
else if (strcmp(fname, "=!") == 0) op = MACH_EQ;
else if (strcmp(fname, "!=!") == 0) op = MACH_NEQ;
else if (strcmp(fname, "&!") == 0) op = MACH_BAND;
else if (strcmp(fname, "|!") == 0) op = MACH_BOR;
else if (strcmp(fname, "^!") == 0) op = MACH_BXOR;
else if (strcmp(fname, "<<!") == 0) op = MACH_SHL;
else if (strcmp(fname, ">>!") == 0) op = MACH_SHR;
else op = MACH_USHR; /* >>>! */
mach_emit(cs, MACH_ABC(op, dest, r0, r1));
mach_free_reg_to(cs, save);
return dest;
}
}
}
if (fn_kind && strcmp(fn_kind, ".") == 0) {
/* Method call with dot notation: obj.method(args) */
int save_freereg = cs->freereg;
@@ -33479,6 +33995,33 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
break;
}
case MACH_EQ_TOL:
case MACH_NEQ_TOL: {
/* A=dest, B=base, C=3; args in R(B), R(B+1), R(B+2) */
JSValue left = frame->slots[b];
JSValue right = frame->slots[b + 1];
JSValue tol = frame->slots[b + 2];
BOOL is_eq_op = (op == MACH_EQ_TOL);
if (JS_IsNumber(left) && JS_IsNumber(right) && JS_IsNumber(tol)) {
double da, db, dt;
JS_ToFloat64(ctx, &da, left);
JS_ToFloat64(ctx, &db, right);
JS_ToFloat64(ctx, &dt, tol);
BOOL eq = fabs(da - db) <= dt;
frame->slots[a] = JS_NewBool(ctx, is_eq_op ? eq : !eq);
} else if (JS_IsText(left) && JS_IsText(right) && JS_VALUE_GET_TAG(tol) == JS_TAG_BOOL && JS_VALUE_GET_BOOL(tol)) {
BOOL eq = js_string_compare_value_nocase(ctx, left, right) == 0;
frame->slots[a] = JS_NewBool(ctx, is_eq_op ? eq : !eq);
} else {
/* Fall through to standard eq/neq */
JSValue res = reg_vm_binop(ctx, is_eq_op ? MACH_EQ : MACH_NEQ, left, right);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
if (JS_IsException(res)) { goto disrupt; }
frame->slots[a] = res;
}
break;
}
case MACH_NEG: {
JSValue v = frame->slots[b];
if (JS_IsInt(v)) {
@@ -34288,6 +34831,16 @@ static void mach_gen_emit_3 (MachGenState *s, const char *op, int a, int b, int
mach_gen_add_instr (s, instr);
}
static void mach_gen_emit_4 (MachGenState *s, const char *op, int a, int b, int c, int d) {
cJSON *instr = cJSON_CreateArray ();
cJSON_AddItemToArray (instr, cJSON_CreateString (op));
cJSON_AddItemToArray (instr, cJSON_CreateNumber (a));
cJSON_AddItemToArray (instr, cJSON_CreateNumber (b));
cJSON_AddItemToArray (instr, cJSON_CreateNumber (c));
cJSON_AddItemToArray (instr, cJSON_CreateNumber (d));
mach_gen_add_instr (s, instr);
}
static void mach_gen_emit_const_num (MachGenState *s, int dest, double val) {
cJSON *instr = cJSON_CreateArray ();
cJSON_AddItemToArray (instr, cJSON_CreateString ("access"));
@@ -34428,6 +34981,32 @@ static void mach_gen_emit_go_call_method (MachGenState *s, int obj, const char *
mach_gen_emit_1 (s, "goinvoke", frame_slot);
}
static const char *functino_to_mcode_op (const char *name) {
if (strcmp (name, "+!") == 0) return "add";
if (strcmp (name, "-!") == 0) return "subtract";
if (strcmp (name, "*!") == 0) return "multiply";
if (strcmp (name, "/!") == 0) return "divide";
if (strcmp (name, "%!") == 0) return "modulo";
if (strcmp (name, "**!") == 0) return "pow";
if (strcmp (name, "<!") == 0) return "lt";
if (strcmp (name, ">!") == 0) return "gt";
if (strcmp (name, "<=!") == 0) return "le";
if (strcmp (name, ">=!") == 0) return "ge";
if (strcmp (name, "=!") == 0) return "eq";
if (strcmp (name, "!=!") == 0) return "ne";
if (strcmp (name, "&!") == 0) return "bitand";
if (strcmp (name, "|!") == 0) return "bitor";
if (strcmp (name, "^!") == 0) return "bitxor";
if (strcmp (name, "<<!") == 0) return "shl";
if (strcmp (name, ">>!") == 0) return "shr";
if (strcmp (name, ">>>!") == 0) return "ushr";
if (strcmp (name, "&&!") == 0) return "and";
if (strcmp (name, "||!") == 0) return "or";
if (strcmp (name, "~!") == 0) return "bitnot";
if (strcmp (name, "[]!") == 0) return "load";
return NULL;
}
static const char *mach_gen_binop_to_string (const char *kind) {
if (strcmp (kind, "+") == 0) return "add";
if (strcmp (kind, "-") == 0) return "subtract";
@@ -34828,13 +35407,69 @@ static int mach_gen_expr (MachGenState *s, cJSON *expr, int target) {
if (strcmp (kind, "(") == 0) {
cJSON *callee = cJSON_GetObjectItemCaseSensitive (expr, "expression");
cJSON *args_list = cJSON_GetObjectItemCaseSensitive (expr, "list");
/* Functino: inline operator call */
const char *callee_kind = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (callee, "kind"));
if (callee_kind && strcmp (callee_kind, "name") == 0) {
const char *callee_make = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (callee, "make"));
if (callee_make && strcmp (callee_make, "functino") == 0) {
const char *fname = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (callee, "name"));
const char *mop = functino_to_mcode_op (fname);
int nargs = args_list ? cJSON_GetArraySize (args_list) : 0;
if (strcmp (fname, "~!") == 0) {
int a0 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 0), -1);
int d = mach_gen_alloc_slot (s);
mach_gen_emit_2 (s, mop, d, a0);
return d;
}
if (strcmp (fname, "[]!") == 0) {
int a0 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 0), -1);
int a1 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 1), -1);
int d = mach_gen_alloc_slot (s);
mach_gen_emit_get_elem (s, d, a0, a1);
return d;
}
if ((strcmp (fname, "=!") == 0 || strcmp (fname, "!=!") == 0) && nargs == 3) {
int a0 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 0), -1);
int a1 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 1), -1);
int a2 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 2), -1);
int d = mach_gen_alloc_slot (s);
const char *top = (strcmp (fname, "=!") == 0) ? "eq_tol" : "ne_tol";
mach_gen_emit_4 (s, top, d, a0, a1, a2);
return d;
}
if (strcmp (fname, "&&!") == 0) {
int a0 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 0), -1);
int a1 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 1), -1);
int d = mach_gen_alloc_slot (s);
mach_gen_emit_3 (s, "and", d, a0, a1);
return d;
}
if (strcmp (fname, "||!") == 0) {
int a0 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 0), -1);
int a1 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 1), -1);
int d = mach_gen_alloc_slot (s);
mach_gen_emit_3 (s, "or", d, a0, a1);
return d;
}
/* Standard 2-arg binary functino */
{
int a0 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 0), -1);
int a1 = mach_gen_expr (s, cJSON_GetArrayItem (args_list, 1), -1);
int d = mach_gen_alloc_slot (s);
mach_gen_emit_3 (s, mop, d, a0, a1);
return d;
}
}
}
cJSON *arg_slots = cJSON_CreateArray ();
cJSON *arg;
cJSON_ArrayForEach (arg, args_list) {
int arg_slot = mach_gen_expr (s, arg, -1);
cJSON_AddItemToArray (arg_slots, cJSON_CreateNumber (arg_slot));
}
const char *callee_kind = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (callee, "kind"));
int dest = mach_gen_alloc_slot (s);
if (strcmp (callee_kind, ".") == 0) {
cJSON *obj = cJSON_GetObjectItemCaseSensitive (callee, "left");
@@ -36317,6 +36952,61 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
frame->slots[dest] = JS_TRUE;
}
}
else if (strcmp(op, "eq_tol") == 0) {
int dest = (int)a1->valuedouble;
JSValue left = frame->slots[(int)a2->valuedouble];
JSValue right = frame->slots[(int)a3->valuedouble];
cJSON *a4 = cJSON_GetArrayItem(instr, 4);
JSValue tol = frame->slots[(int)a4->valuedouble];
if (JS_IsNumber(left) && JS_IsNumber(right) && JS_IsNumber(tol)) {
double a, b, t;
JS_ToFloat64(ctx, &a, left);
JS_ToFloat64(ctx, &b, right);
JS_ToFloat64(ctx, &t, tol);
frame->slots[dest] = JS_NewBool(ctx, fabs(a - b) <= t);
} else if (JS_IsText(left) && JS_IsText(right) && JS_VALUE_GET_TAG(tol) == JS_TAG_BOOL && JS_VALUE_GET_BOOL(tol)) {
frame->slots[dest] = JS_NewBool(ctx, js_string_compare_value_nocase(ctx, left, right) == 0);
} else {
/* Fall through to standard eq */
if (left == right) frame->slots[dest] = JS_TRUE;
else if (JS_IsText(left) && JS_IsText(right))
frame->slots[dest] = JS_NewBool(ctx, js_string_compare_value(ctx, left, right, TRUE) == 0);
else frame->slots[dest] = JS_FALSE;
}
}
else if (strcmp(op, "ne_tol") == 0) {
int dest = (int)a1->valuedouble;
JSValue left = frame->slots[(int)a2->valuedouble];
JSValue right = frame->slots[(int)a3->valuedouble];
cJSON *a4 = cJSON_GetArrayItem(instr, 4);
JSValue tol = frame->slots[(int)a4->valuedouble];
if (JS_IsNumber(left) && JS_IsNumber(right) && JS_IsNumber(tol)) {
double a, b, t;
JS_ToFloat64(ctx, &a, left);
JS_ToFloat64(ctx, &b, right);
JS_ToFloat64(ctx, &t, tol);
frame->slots[dest] = JS_NewBool(ctx, fabs(a - b) > t);
} else if (JS_IsText(left) && JS_IsText(right) && JS_VALUE_GET_TAG(tol) == JS_TAG_BOOL && JS_VALUE_GET_BOOL(tol)) {
frame->slots[dest] = JS_NewBool(ctx, js_string_compare_value_nocase(ctx, left, right) != 0);
} else {
if (left == right) frame->slots[dest] = JS_FALSE;
else if (JS_IsText(left) && JS_IsText(right))
frame->slots[dest] = JS_NewBool(ctx, js_string_compare_value(ctx, left, right, TRUE) != 0);
else frame->slots[dest] = JS_TRUE;
}
}
else if (strcmp(op, "and") == 0) {
int dest = (int)a1->valuedouble;
JSValue left = frame->slots[(int)a2->valuedouble];
JSValue right = frame->slots[(int)a3->valuedouble];
frame->slots[dest] = JS_ToBool(ctx, left) ? right : left;
}
else if (strcmp(op, "or") == 0) {
int dest = (int)a1->valuedouble;
JSValue left = frame->slots[(int)a2->valuedouble];
JSValue right = frame->slots[(int)a3->valuedouble];
frame->slots[dest] = JS_ToBool(ctx, left) ? left : right;
}
else if (strcmp(op, "lt") == 0) {
int dest = (int)a1->valuedouble;
JSValue left = frame->slots[(int)a2->valuedouble];
@@ -37561,6 +38251,10 @@ static void dump_register_code(JSContext *ctx, JSCodeRegister *code, int indent)
printf("r%d, r%d, r%d", a, b, c);
break;
case MACH_EQ_TOL: case MACH_NEQ_TOL:
printf("r%d, r%d, %d", a, b, c);
break;
/* Property access */
case MACH_GETFIELD:
printf("r%d, r%d, #%d", a, b, c);