Beispiel #1
0
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;
		}
	}
}
Beispiel #2
0
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");
	}
}
Beispiel #3
0
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);
	}
}
Beispiel #4
0
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;
		}
	}
}
Beispiel #5
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);
	}
}
Beispiel #6
0
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);
	}
}
Beispiel #7
0
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;
	}
}
Beispiel #8
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);

			/* 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;
}
Beispiel #9
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;
}
Beispiel #10
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;
}