void FParser::OPdivide(svalue_t &result, int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); // haleyjd: 8-17 if(left.type == svt_fixed || right.type == svt_fixed) { auto fr = floatvalue(right); if(fr == 0) script_error("divide by zero\n"); else { result.setDouble(floatvalue(left) / fr); } } else { auto ir = intvalue(right); if(!ir) script_error("divide by zero\n"); else { result.type = svt_int; result.value.i = intvalue(left) / ir; } } }
void FParser::OPdecrement(svalue_t &result, int start, int n, int stop) { if(start == n) // ++n { DFsVariable *var; var = Script->FindVariable(Tokens[stop]); if(!var) { script_error("unknown variable '%s'\n", Tokens[stop]); } var->GetValue(result); // haleyjd if(var->type != svt_fixed) { result.value.i = intvalue(result) - 1; result.type = svt_int; var->SetValue (result); } else { result.setDouble(floatvalue(result)-1); result.type = svt_fixed; var->SetValue (result); } } else if(stop == n) // n++ { svalue_t newvalue; DFsVariable *var; var = Script->FindVariable(Tokens[start]); if(!var) { script_error("unknown variable '%s'\n", Tokens[start]); } var->GetValue(result); // haleyjd if(var->type != svt_fixed) { newvalue.type = svt_int; newvalue.value.i = intvalue(result) - 1; var->SetValue (newvalue); } else { newvalue.setDouble(floatvalue(result)-1); var->SetValue (newvalue); } } else { script_error("incorrect arguments to ++ operator\n"); } }
static int numeric_equal(const SpnValue *lhs, const SpnValue *rhs) { assert(isnum(lhs) && isnum(rhs)); if (isfloat(lhs)) { return isfloat(rhs) ? floatvalue(lhs) == floatvalue(rhs) : floatvalue(lhs) == intvalue(rhs); } else { return isfloat(rhs) ? intvalue(lhs) == floatvalue(rhs) : intvalue(lhs) == intvalue(rhs); } }
static int numeric_compare(const SpnValue *lhs, const SpnValue *rhs) { assert(isnum(lhs) && isnum(rhs)); if (isfloat(lhs)) { if (isfloat(rhs)) { return floatvalue(lhs) < floatvalue(rhs) ? -1 : floatvalue(lhs) > floatvalue(rhs) ? +1 : 0; } else { return floatvalue(lhs) < intvalue(rhs) ? -1 : floatvalue(lhs) > intvalue(rhs) ? +1 : 0; } } else { if (isfloat(rhs)) { return intvalue(lhs) < floatvalue(rhs) ? -1 : intvalue(lhs) > floatvalue(rhs) ? +1 : 0; } else { return intvalue(lhs) < intvalue(rhs) ? -1 : intvalue(lhs) > intvalue(rhs) ? +1 : 0; } } }
void FParser::OPplus(svalue_t &result, int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); if (left.type == svt_string) { if (right.type == svt_string) { result.string.Format("%s%s", left.string.GetChars(), right.string.GetChars()); } else if (right.type == svt_fixed) { result.string.Format("%s%4.4f", left.string.GetChars(), floatvalue(right)); } else { result.string.Format("%s%i", left.string.GetChars(), intvalue(right)); } result.type = svt_string; } // haleyjd: 8-17 else if(left.type == svt_fixed || right.type == svt_fixed) { result.type = svt_fixed; result.value.f = fixedvalue(left) + fixedvalue(right); } else { result.type = svt_int; result.value.i = intvalue(left) + intvalue(right); } }
void FParser::OPmultiply(svalue_t &result,int start, int n, int stop) { svalue_t left, right; evaluate_leftnright(start, n, stop); // haleyjd: 8-17 if(left.type == svt_fixed || right.type == svt_fixed) { result.setDouble(floatvalue(left) * floatvalue(right)); } else { result.type = svt_int; result.value.i = intvalue(left) * intvalue(right); } }
void spn_value_print(const SpnValue *val) { switch (valtype(val)) { case SPN_TTAG_NIL: { fputs("nil", stdout); break; } case SPN_TTAG_BOOL: { fputs(boolvalue(val) ? "true" : "false", stdout); break; } case SPN_TTAG_NUMBER: { if (isfloat(val)) { printf("%.*g", DBL_DIG, floatvalue(val)); } else { printf("%ld", intvalue(val)); } break; } case SPN_TTAG_STRING: { SpnString *s = stringvalue(val); fputs(s->cstr, stdout); break; } case SPN_TTAG_ARRAY: { SpnArray *array = objvalue(val); print_array(array, 0); break; } case SPN_TTAG_HASHMAP: { SpnHashMap *hashmap = objvalue(val); print_hashmap(hashmap, 0); break; } case SPN_TTAG_FUNC: { SpnFunction *func = funcvalue(val); void *p; if (func->native) { p = (void *)(ptrdiff_t)(func->repr.fn); } else { p = func->repr.bc; } printf("<function %p>", p); break; } case SPN_TTAG_USERINFO: { void *ptr = isobject(val) ? objvalue(val) : ptrvalue(val); printf("<userinfo %p>", ptr); break; } default: SHANT_BE_REACHED(); break; } }
unsigned long spn_hash_value(const SpnValue *key) { switch (valtype(key)) { case SPN_TTAG_NIL: { return 0; } case SPN_TTAG_BOOL: { return boolvalue(key); /* 0 or 1 */ } case SPN_TTAG_NUMBER: { if (isfloat(key)) { double f = floatvalue(key); /* only test for integer if it fits into one (anti-UB) */ if (LONG_MIN <= f && f <= LONG_MAX) { long i = f; /* truncate */ if (f == i) { /* it's really an integer. * This takes care of the +/- 0 problem too * (since 0 itself is an integer) */ return i; } } else { return spn_hash_bytes(&f, sizeof f); } } /* the hash value of an integer is itself */ return intvalue(key); } case SPN_TTAG_STRING: case SPN_TTAG_ARRAY: case SPN_TTAG_HASHMAP: case SPN_TTAG_FUNC: { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } case SPN_TTAG_USERINFO: { if (isobject(key)) { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } return (unsigned long)(ptrvalue(key)); } default: SHANT_BE_REACHED(); } return 0; }
unsigned long spn_hash_value(const SpnValue *key) { switch (valtype(key)) { case SPN_TTAG_NIL: { return 0; } case SPN_TTAG_BOOL: { return boolvalue(key); /* 0 or 1 */ } case SPN_TTAG_NUMBER: { if (isfloat(key)) { double f = floatvalue(key); long i = f; /* truncate */ if (f == i) { return i; /* it's really an integer */ } else { return spn_hash_bytes(&f, sizeof f); } } /* the hash value of an integer is itself */ return intvalue(key); } case SPN_TTAG_STRING: case SPN_TTAG_ARRAY: case SPN_TTAG_HASHMAP: case SPN_TTAG_FUNC: { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } case SPN_TTAG_USERINFO: { if (isobject(key)) { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } return (unsigned long)(ptrvalue(key)); } default: SHANT_BE_REACHED(); } return 0; }
/* returns zero on success, nonzero on error */ static int append_format( struct string_builder *bld, const struct format_args *args, void *argv, int *argidx, int isval, char **errmsg ) { switch (args->spec) { case '%': append_string(bld, "%", 1); break; case 's': { const char *str; size_t len; if (isval) { SpnString *strobj; /* must be a string */ SpnValue *val = getarg_val(argv, argidx); if (!isstring(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TYPE_STRING, val->type ); return -1; } strobj = stringvalue(val); str = strobj->cstr; len = strobj->len; } else { str = getarg_raw(argv, argidx); len = strlen(str); } if (args->precision >= 0 && args->precision < len) { len = args->precision; } if (args->width >= 0 && args->width > len) { size_t pad = args->width - len; expand_buffer(bld, pad); while (pad-- > 0) { bld->buf[bld->len++] = ' '; } } append_string(bld, str, len); break; } case 'i': case 'd': case 'b': case 'o': case 'u': case 'x': case 'X': { char *buf, *end, *begin; size_t len = PR_LONG_DIGITS; enum format_flags flags = args->flags; unsigned base = base_for_specifier(args->spec); long n; unsigned long u; if (isval) { /* must be a number */ SpnValue *val = getarg_val(argv, argidx); if (!isnum(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TTAG_NUMBER, val->type ); return -1; } if (isint(val)) { n = intvalue(val); } else { n = floatvalue(val); /* truncate */ } } else { /* "%i" expects an int, others expect a long */ if (args->spec == 'i') { n = *(const int *)getarg_raw(argv, argidx); } else { n = *(const long *)getarg_raw(argv, argidx); } } if (args->spec == 'i' || args->spec == 'd') { /* signed conversion specifiers */ if (n < 0) { flags |= FLAG_NEGATIVE; u = -n; } else { u = n; } } else { /* unsigned conversion specifiers */ u = n; } if (args->spec == 'X') { flags |= FLAG_CAPS; } if (args->width >= 0 && args->width > len) { len = args->width; } buf = spn_malloc(len); end = buf + len; begin = ulong2str(end, u, base, args->width, flags); assert(buf <= begin); append_string(bld, begin, end - begin); free(buf); break; } case 'c': { unsigned char ch; int len = 1; /* one character is one character long... */ if (isval) { /* must be an integer */ SpnValue *val = getarg_val(argv, argidx); if (!isnum(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TTAG_NUMBER, val->type ); return -1; } if (isfloat(val)) { format_errmsg(errmsg, EXPECT_INTEGER, *argidx); return -1; } ch = intvalue(val); } else { ch = *(const long *)getarg_raw(argv, argidx); } if (args->width > len) { len = args->width; } expand_buffer(bld, len); while (len-- > 1) { bld->buf[bld->len++] = ' '; } bld->buf[bld->len++] = ch; break; } case 'f': case 'F': { char *buf, *end, *begin; size_t len; int prec; double x; enum format_flags flags = args->flags; if (isval) { SpnValue *val = getarg_val(argv, argidx); if (!isnum(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TTAG_NUMBER, val->type ); return -1; } if (isfloat(val)) { x = floatvalue(val); } else { x = intvalue(val); } } else { x = *(const double *)getarg_raw(argv, argidx); } if (args->spec == 'F') { flags |= FLAG_CAPS; } /* handle special cases */ if (+1.0 / x == +1.0 / -0.0) { /* negative zero: set sign flag and carry on */ flags |= FLAG_NEGATIVE; } else if ( x != x /* NaN */ || x == +1.0 / 0.0 /* +inf */ || x == -1.0 / 0.0 /* -inf */ ) { print_special_fp(bld, flags, args->width, x); break; } if (x < 0.0) { flags |= FLAG_NEGATIVE; x = -x; } /* at this point, `x' is non-negative or -0 */ if (x >= 1.0) { len = ceil(log10(x)) + 1; /* 10 ^ n is n + 1 digits long */ } else { len = 1; /* leading zero needs exactly one character */ } prec = args->precision < 0 ? DBL_DIG : args->precision; len += prec + 3; /* decimal point, sign, leading zero */ if (args->width >= 0 && args->width > len) { len = args->width; } buf = spn_malloc(len); end = buf + len; begin = double2str(end, x, args->width, prec, flags); assert(buf <= begin); append_string(bld, begin, end - begin); free(buf); break; } case 'B': { int boolval; const char *str; size_t len; if (isval) { /* must be a boolean */ SpnValue *val = getarg_val(argv, argidx); if (!isbool(val)) { format_errmsg( errmsg, TYPE_MISMATCH, *argidx, SPN_TTAG_BOOL, val->type ); return -1; } boolval = boolvalue(val); } else { boolval = *(const int *)getarg_raw(argv, argidx); } str = boolval ? "true" : "false"; len = strlen(str); if (args->precision >= 0 && args->precision < len) { len = args->precision; } if (args->width >= 0 && args->width > len) { size_t pad = args->width - len; expand_buffer(bld, pad); while (pad-- > 0) { bld->buf[bld->len++] = ' '; } } append_string(bld, str, len); break; } default: format_errmsg(errmsg, INVALID_SPECIFIER, ++*argidx, args->spec); return -1; } return 0; }