add functinos
This commit is contained in:
752
source/quickjs.c
752
source/quickjs.c
@@ -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_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_NOP,
|
||||||
|
|
||||||
MACH_OP_COUNT
|
MACH_OP_COUNT
|
||||||
@@ -632,6 +635,8 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
|||||||
[MACH_HASPROP] = "hasprop",
|
[MACH_HASPROP] = "hasprop",
|
||||||
[MACH_REGEXP] = "regexp",
|
[MACH_REGEXP] = "regexp",
|
||||||
[MACH_CALLMETHOD] = "callmethod",
|
[MACH_CALLMETHOD] = "callmethod",
|
||||||
|
[MACH_EQ_TOL] = "eq_tol",
|
||||||
|
[MACH_NEQ_TOL] = "neq_tol",
|
||||||
[MACH_NOP] = "nop",
|
[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;
|
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) {
|
static JSValue JS_ConcatString (JSContext *ctx, JSValue op1, JSValue op2) {
|
||||||
if (unlikely (!JS_IsText (op1))) {
|
if (unlikely (!JS_IsText (op1))) {
|
||||||
op1 = JS_ToString (ctx, op1);
|
op1 = JS_ToString (ctx, op1);
|
||||||
@@ -28582,6 +28602,13 @@ redo:
|
|||||||
} else if (p[1] == '=') {
|
} else if (p[1] == '=') {
|
||||||
p += 2;
|
p += 2;
|
||||||
s->token_val = TOK_DIV_ASSIGN;
|
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 {
|
} else {
|
||||||
p++;
|
p++;
|
||||||
s->token_val = c;
|
s->token_val = c;
|
||||||
@@ -28705,70 +28732,250 @@ redo:
|
|||||||
case '*':
|
case '*':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_MUL_ASSIGN; }
|
if (p[1] == '=') { p += 2; s->token_val = TOK_MUL_ASSIGN; }
|
||||||
else if (p[1] == '*') {
|
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 { 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;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_MOD_ASSIGN; }
|
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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_PLUS_ASSIGN; }
|
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] == '+') { 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_MINUS_ASSIGN; }
|
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] == '-') { 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '<':
|
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] == '<') {
|
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 { 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;
|
break;
|
||||||
case '>':
|
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] == '>') {
|
else if (p[1] == '>') {
|
||||||
if (p[2] == '>') {
|
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 { 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 { 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;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
if (p[1] == '=') {
|
if (p[1] == '=') {
|
||||||
if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_EQ; }
|
if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_EQ; }
|
||||||
else { p += 2; s->token_val = TOK_EQ; }
|
else { p += 2; s->token_val = TOK_EQ; }
|
||||||
} else if (p[1] == '>') { p += 2; s->token_val = TOK_ARROW; }
|
} 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '!':
|
case '!':
|
||||||
if (p[1] == '=') {
|
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 { p += 2; s->token_val = TOK_NEQ; }
|
||||||
} else { goto def_token; }
|
} else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '&':
|
case '&':
|
||||||
if (p[1] == '&') {
|
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 { 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '|':
|
case '|':
|
||||||
if (p[1] == '|') {
|
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 { 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '^':
|
case '^':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_XOR_ASSIGN; }
|
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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
@@ -28905,6 +29112,13 @@ static int tokenize_next (ASTParseState *s) {
|
|||||||
} else if (p[1] == '=') {
|
} else if (p[1] == '=') {
|
||||||
p += 2;
|
p += 2;
|
||||||
s->token_val = TOK_DIV_ASSIGN;
|
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 {
|
} else {
|
||||||
p++;
|
p++;
|
||||||
s->token_val = c;
|
s->token_val = c;
|
||||||
@@ -29026,70 +29240,250 @@ static int tokenize_next (ASTParseState *s) {
|
|||||||
case '*':
|
case '*':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_MUL_ASSIGN; }
|
if (p[1] == '=') { p += 2; s->token_val = TOK_MUL_ASSIGN; }
|
||||||
else if (p[1] == '*') {
|
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 { 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;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_MOD_ASSIGN; }
|
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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_PLUS_ASSIGN; }
|
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] == '+') { 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_MINUS_ASSIGN; }
|
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] == '-') { 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '<':
|
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] == '<') {
|
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 { 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;
|
break;
|
||||||
case '>':
|
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] == '>') {
|
else if (p[1] == '>') {
|
||||||
if (p[2] == '>') {
|
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 { 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 { 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;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
if (p[1] == '=') {
|
if (p[1] == '=') {
|
||||||
if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_EQ; }
|
if (p[2] == '=') { p += 3; s->token_val = TOK_STRICT_EQ; }
|
||||||
else { p += 2; s->token_val = TOK_EQ; }
|
else { p += 2; s->token_val = TOK_EQ; }
|
||||||
} else if (p[1] == '>') { p += 2; s->token_val = TOK_ARROW; }
|
} 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '!':
|
case '!':
|
||||||
if (p[1] == '=') {
|
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 { p += 2; s->token_val = TOK_NEQ; }
|
||||||
} else { goto def_token; }
|
} else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '&':
|
case '&':
|
||||||
if (p[1] == '&') {
|
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 { 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '|':
|
case '|':
|
||||||
if (p[1] == '|') {
|
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 { 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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '^':
|
case '^':
|
||||||
if (p[1] == '=') { p += 2; s->token_val = TOK_XOR_ASSIGN; }
|
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; }
|
else { goto def_token; }
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
@@ -30491,6 +30885,18 @@ static int ast_sem_in_loop (ASTSemScope *scope) {
|
|||||||
return 0;
|
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_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr);
|
||||||
static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt);
|
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) {
|
if (strcmp (kind, "name") == 0) {
|
||||||
const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (expr, "name"));
|
const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (expr, "name"));
|
||||||
if (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);
|
ASTSemLookup r = ast_sem_lookup_var (scope, name);
|
||||||
if (r.var) {
|
if (r.var) {
|
||||||
cJSON_AddNumberToObject (expr, "level", r.level);
|
cJSON_AddNumberToObject (expr, "level", r.level);
|
||||||
@@ -31701,6 +32112,111 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
|||||||
if (fn_expr)
|
if (fn_expr)
|
||||||
fn_kind = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(fn_expr, "kind"));
|
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) {
|
if (fn_kind && strcmp(fn_kind, ".") == 0) {
|
||||||
/* Method call with dot notation: obj.method(args) */
|
/* Method call with dot notation: obj.method(args) */
|
||||||
int save_freereg = cs->freereg;
|
int save_freereg = cs->freereg;
|
||||||
@@ -33479,6 +33995,33 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
break;
|
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: {
|
case MACH_NEG: {
|
||||||
JSValue v = frame->slots[b];
|
JSValue v = frame->slots[b];
|
||||||
if (JS_IsInt(v)) {
|
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);
|
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) {
|
static void mach_gen_emit_const_num (MachGenState *s, int dest, double val) {
|
||||||
cJSON *instr = cJSON_CreateArray ();
|
cJSON *instr = cJSON_CreateArray ();
|
||||||
cJSON_AddItemToArray (instr, cJSON_CreateString ("access"));
|
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);
|
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) {
|
static const char *mach_gen_binop_to_string (const char *kind) {
|
||||||
if (strcmp (kind, "+") == 0) return "add";
|
if (strcmp (kind, "+") == 0) return "add";
|
||||||
if (strcmp (kind, "-") == 0) return "subtract";
|
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) {
|
if (strcmp (kind, "(") == 0) {
|
||||||
cJSON *callee = cJSON_GetObjectItemCaseSensitive (expr, "expression");
|
cJSON *callee = cJSON_GetObjectItemCaseSensitive (expr, "expression");
|
||||||
cJSON *args_list = cJSON_GetObjectItemCaseSensitive (expr, "list");
|
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_slots = cJSON_CreateArray ();
|
||||||
cJSON *arg;
|
cJSON *arg;
|
||||||
cJSON_ArrayForEach (arg, args_list) {
|
cJSON_ArrayForEach (arg, args_list) {
|
||||||
int arg_slot = mach_gen_expr (s, arg, -1);
|
int arg_slot = mach_gen_expr (s, arg, -1);
|
||||||
cJSON_AddItemToArray (arg_slots, cJSON_CreateNumber (arg_slot));
|
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);
|
int dest = mach_gen_alloc_slot (s);
|
||||||
if (strcmp (callee_kind, ".") == 0) {
|
if (strcmp (callee_kind, ".") == 0) {
|
||||||
cJSON *obj = cJSON_GetObjectItemCaseSensitive (callee, "left");
|
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;
|
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) {
|
else if (strcmp(op, "lt") == 0) {
|
||||||
int dest = (int)a1->valuedouble;
|
int dest = (int)a1->valuedouble;
|
||||||
JSValue left = frame->slots[(int)a2->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);
|
printf("r%d, r%d, r%d", a, b, c);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MACH_EQ_TOL: case MACH_NEQ_TOL:
|
||||||
|
printf("r%d, r%d, %d", a, b, c);
|
||||||
|
break;
|
||||||
|
|
||||||
/* Property access */
|
/* Property access */
|
||||||
case MACH_GETFIELD:
|
case MACH_GETFIELD:
|
||||||
printf("r%d, r%d, #%d", a, b, c);
|
printf("r%d, r%d, #%d", a, b, c);
|
||||||
|
|||||||
Reference in New Issue
Block a user