Added the Float type and many fixes. (0.24.0)
This commit is contained in:
parent
95eba1eb12
commit
41fa946f1c
19 changed files with 432 additions and 69 deletions
|
|
@ -38,11 +38,20 @@
|
|||
case OP_ADD: {
|
||||
Value b = pop_value(vm);
|
||||
Value a = pop_value(vm);
|
||||
if (a.type == VAL_INT && b.type == VAL_INT) {
|
||||
Value res = make_int(a.i + b.i);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
if ((a.type == VAL_INT || a.type == VAL_FLOAT) && (b.type == VAL_INT || b.type == VAL_FLOAT)) {
|
||||
if (a.type == VAL_FLOAT || b.type == VAL_FLOAT) {
|
||||
double da = (a.type == VAL_FLOAT) ? a.d : (double)a.i;
|
||||
double db = (b.type == VAL_FLOAT) ? b.d : (double)b.i;
|
||||
Value res = make_float(da + db);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
} else {
|
||||
Value res = make_int(a.i + b.i);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
}
|
||||
} else if (a.type == VAL_STRING && b.type == VAL_STRING) {
|
||||
const char *sa = a.s ? a.s : "";
|
||||
const char *sb = b.s ? b.s : "";
|
||||
|
|
@ -68,7 +77,7 @@ case OP_ADD: {
|
|||
free_value(b);
|
||||
push_value(vm, res);
|
||||
} else {
|
||||
fprintf(stderr, "Runtime type error: ADD expects both ints, both strings, or both arrays, got %s and %s\n",
|
||||
fprintf(stderr, "Runtime type error: ADD expects both numbers, both strings, or both arrays, got %s and %s\n",
|
||||
value_type_name(a.type), value_type_name(b.type));
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,18 +35,32 @@
|
|||
case OP_DIV: {
|
||||
Value b = pop_value(vm);
|
||||
Value a = pop_value(vm);
|
||||
if (a.type != VAL_INT || b.type != VAL_INT) {
|
||||
fprintf(stderr, "Runtime type error: DIV expects ints, got %s and %s\n",
|
||||
if ((a.type == VAL_INT || a.type == VAL_FLOAT) && (b.type == VAL_INT || b.type == VAL_FLOAT)) {
|
||||
if (a.type == VAL_FLOAT || b.type == VAL_FLOAT) {
|
||||
double da = (a.type == VAL_FLOAT) ? a.d : (double)a.i;
|
||||
double db = (b.type == VAL_FLOAT) ? b.d : (double)b.i;
|
||||
if (db == 0.0) {
|
||||
fprintf(stderr, "Runtime error: division by zero\n");
|
||||
exit(1);
|
||||
}
|
||||
Value res = make_float(da / db);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
} else {
|
||||
if (b.i == 0) {
|
||||
fprintf(stderr, "Runtime error: division by zero\n");
|
||||
exit(1);
|
||||
}
|
||||
Value res = make_int(a.i / b.i);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Runtime type error: DIV expects numbers, got %s and %s\n",
|
||||
value_type_name(a.type), value_type_name(b.type));
|
||||
exit(1);
|
||||
}
|
||||
if (b.i == 0) {
|
||||
fprintf(stderr, "Runtime error: division by zero\n");
|
||||
exit(1);
|
||||
}
|
||||
Value res = make_int(a.i / b.i);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,14 +34,24 @@
|
|||
case OP_MUL: {
|
||||
Value b = pop_value(vm);
|
||||
Value a = pop_value(vm);
|
||||
if (a.type != VAL_INT || b.type != VAL_INT) {
|
||||
fprintf(stderr, "Runtime type error: MUL expects ints, got %s and %s\n",
|
||||
if ((a.type == VAL_INT || a.type == VAL_FLOAT) && (b.type == VAL_INT || b.type == VAL_FLOAT)) {
|
||||
if (a.type == VAL_FLOAT || b.type == VAL_FLOAT) {
|
||||
double da = (a.type == VAL_FLOAT) ? a.d : (double)a.i;
|
||||
double db = (b.type == VAL_FLOAT) ? b.d : (double)b.i;
|
||||
Value res = make_float(da * db);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
} else {
|
||||
Value res = make_int(a.i * b.i);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Runtime type error: MUL expects numbers, got %s and %s\n",
|
||||
value_type_name(a.type), value_type_name(b.type));
|
||||
exit(1);
|
||||
}
|
||||
Value res = make_int(a.i * b.i);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,14 +34,24 @@
|
|||
case OP_SUB: {
|
||||
Value b = pop_value(vm);
|
||||
Value a = pop_value(vm);
|
||||
if (a.type != VAL_INT || b.type != VAL_INT) {
|
||||
fprintf(stderr, "Runtime type error: SUB expects ints, got %s and %s\n",
|
||||
if ((a.type == VAL_INT || a.type == VAL_FLOAT) && (b.type == VAL_INT || b.type == VAL_FLOAT)) {
|
||||
if (a.type == VAL_FLOAT || b.type == VAL_FLOAT) {
|
||||
double da = (a.type == VAL_FLOAT) ? a.d : (double)a.i;
|
||||
double db = (b.type == VAL_FLOAT) ? b.d : (double)b.i;
|
||||
Value res = make_float(da - db);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
} else {
|
||||
Value res = make_int(a.i - b.i);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Runtime type error: SUB expects numbers, got %s and %s\n",
|
||||
value_type_name(a.type), value_type_name(b.type));
|
||||
exit(1);
|
||||
}
|
||||
Value res = make_int(a.i - b.i);
|
||||
free_value(a);
|
||||
free_value(b);
|
||||
push_value(vm, res);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,27 +8,35 @@
|
|||
*/
|
||||
|
||||
case OP_SCLAMP: {
|
||||
/* Saturating clamp to signed N-bit range: [-2^(N-1) .. 2^(N-1)-1] */
|
||||
/* Two's complement wrap to signed N-bit range:
|
||||
- Mask to N bits
|
||||
- If sign bit is set, sign-extend to 64-bit
|
||||
This yields values in [-2^(N-1) .. 2^(N-1)-1]. */
|
||||
Value v = pop_value(vm);
|
||||
int bits = inst.operand;
|
||||
int64_t vi = (v.type == VAL_INT) ? v.i : 0;
|
||||
|
||||
int64_t smin, smax;
|
||||
int64_t out = 0;
|
||||
if (bits <= 0) {
|
||||
smin = 0; smax = 0;
|
||||
} else if (bits >= 63) {
|
||||
/* cover full int64_t domain for 63+ bits */
|
||||
smin = INT64_MIN;
|
||||
smax = INT64_MAX;
|
||||
out = 0;
|
||||
} else {
|
||||
smin = -(1LL << (bits - 1));
|
||||
smax = (1LL << (bits - 1)) - 1LL;
|
||||
uint64_t mask = (bits >= 64) ? UINT64_MAX : ((1ULL << bits) - 1ULL);
|
||||
uint64_t wrapped = ((uint64_t)vi) & mask;
|
||||
if (bits >= 64) {
|
||||
/* 64-bit: already full width; interpret as signed */
|
||||
out = (int64_t)wrapped;
|
||||
} else {
|
||||
uint64_t sign_bit = 1ULL << (bits - 1);
|
||||
if (wrapped & sign_bit) {
|
||||
/* sign-extend */
|
||||
out = (int64_t)(wrapped | (~mask));
|
||||
} else {
|
||||
out = (int64_t)wrapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vi < smin) vi = smin;
|
||||
else if (vi > smax) vi = smax;
|
||||
|
||||
push_value(vm, make_int(vi));
|
||||
push_value(vm, make_int(out));
|
||||
free_value(v);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,22 +34,56 @@
|
|||
case OP_TO_NUMBER: {
|
||||
Value v = pop_value(vm);
|
||||
if (v.type == VAL_INT) {
|
||||
Value out = make_int(v.i);
|
||||
push_value(vm, make_int(v.i));
|
||||
free_value(v);
|
||||
} else if (v.type == VAL_FLOAT) {
|
||||
double d = v.d;
|
||||
if (d >= (double)INT64_MIN && d <= (double)INT64_MAX) {
|
||||
int64_t ii = (int64_t)d;
|
||||
if ((double)ii == d) {
|
||||
push_value(vm, make_int(ii));
|
||||
} else {
|
||||
push_value(vm, make_float(d));
|
||||
}
|
||||
} else {
|
||||
push_value(vm, make_float(d));
|
||||
}
|
||||
free_value(v);
|
||||
push_value(vm, out);
|
||||
} else if (v.type == VAL_STRING) {
|
||||
const char *s = v.s ? v.s : "";
|
||||
const char *p = s;
|
||||
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p++;
|
||||
char *endp = NULL;
|
||||
long long parsed = strtoll(p, &endp, 10);
|
||||
/* Try float first to support decimals and scientific notation */
|
||||
double dval = strtod(p, &endp);
|
||||
while (endp && (*endp == ' ' || *endp == '\t' || *endp == '\r' || *endp == '\n')) endp++;
|
||||
if (endp && *endp != '\0') {
|
||||
push_value(vm, make_int(0));
|
||||
if (!endp || *endp != '\0') {
|
||||
/* Fallback to integer-only parse */
|
||||
endp = NULL;
|
||||
long long parsed = strtoll(p, &endp, 10);
|
||||
while (endp && (*endp == ' ' || *endp == '\t' || *endp == '\r' || *endp == '\n')) endp++;
|
||||
if (endp && *endp == '\0') {
|
||||
push_value(vm, make_int((int64_t)parsed));
|
||||
} else {
|
||||
push_value(vm, make_int(0));
|
||||
}
|
||||
} else {
|
||||
push_value(vm, make_int((int64_t)parsed));
|
||||
/* Preserve int when exact; else float */
|
||||
if (dval >= (double)INT64_MIN && dval <= (double)INT64_MAX) {
|
||||
int64_t ii = (int64_t)dval;
|
||||
if ((double)ii == dval) {
|
||||
push_value(vm, make_int(ii));
|
||||
} else {
|
||||
push_value(vm, make_float(dval));
|
||||
}
|
||||
} else {
|
||||
push_value(vm, make_float(dval));
|
||||
}
|
||||
}
|
||||
free_value(v);
|
||||
} else if (v.type == VAL_BOOL) {
|
||||
push_value(vm, make_int(v.i ? 1 : 0));
|
||||
free_value(v);
|
||||
} else {
|
||||
free_value(v);
|
||||
push_value(vm, make_int(0));
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ case OP_TYPEOF: {
|
|||
const char *tname = "Unknown";
|
||||
switch (v.type) {
|
||||
case VAL_INT: tname = "Number"; break;
|
||||
case VAL_FLOAT: tname = "Float"; break;
|
||||
case VAL_BOOL: tname = "Boolean"; break;
|
||||
case VAL_STRING: tname = "String"; break;
|
||||
case VAL_FUNCTION: tname = "Function"; break;
|
||||
|
|
|
|||
|
|
@ -8,27 +8,22 @@
|
|||
*/
|
||||
|
||||
case OP_UCLAMP: {
|
||||
/* Saturating clamp to unsigned N-bit range: [0 .. 2^N - 1] */
|
||||
/* Unsigned wrap to N bits: mask lower N bits (operand = bits) */
|
||||
Value v = pop_value(vm);
|
||||
int bits = inst.operand;
|
||||
int64_t vi = (v.type == VAL_INT) ? v.i : 0;
|
||||
|
||||
uint64_t umax;
|
||||
uint64_t mask;
|
||||
if (bits <= 0) {
|
||||
/* treat as clamp to 0..0 */
|
||||
umax = 0;
|
||||
mask = 0ULL;
|
||||
} else if (bits >= 64) {
|
||||
umax = UINT64_MAX;
|
||||
mask = UINT64_MAX;
|
||||
} else {
|
||||
umax = (1ULL << bits) - 1ULL;
|
||||
mask = (1ULL << bits) - 1ULL;
|
||||
}
|
||||
|
||||
uint64_t u;
|
||||
if (vi < 0) u = 0;
|
||||
else if ((uint64_t)vi > umax) u = umax;
|
||||
else u = (uint64_t)vi;
|
||||
|
||||
push_value(vm, make_int((int64_t)u));
|
||||
uint64_t wrapped = ((uint64_t)vi) & mask;
|
||||
push_value(vm, make_int((int64_t)wrapped));
|
||||
free_value(v);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue