Do not automatically convert floats to ints

This commit is contained in:
Justin Ethier 2016-07-05 23:09:12 -04:00
parent 16c1f8c885
commit 655b56e390

View file

@ -13,6 +13,8 @@
#include "cyclone/types.h"
#include "cyclone/runtime.h"
#include "cyclone/ck_ht_hash.h"
#include <errno.h>
#include <limits.h>
//#include <signal.h> // TODO: only used for debugging!
//int JAE_DEBUG = 0;
@ -1349,21 +1351,78 @@ object Cyc_string2number2_(void *data, object cont, int argc, object str, ...)
Cyc_string2number_(data, cont, str);
}
typedef enum {
STR2INT_SUCCESS,
STR2INT_OVERFLOW,
STR2INT_UNDERFLOW,
STR2INT_INCONVERTIBLE
} str2int_errno;
/*
Convert string s to int out.
@param[out] out The converted int. Cannot be NULL.
@param[in] s Input string to be converted.
The format is the same as strtol,
except that the following are inconvertible:
- empty string
- leading whitespace
- any trailing characters that are not part of the number
Cannot be NULL.
@param[in] base Base to interpret string in. Same range as strtol (2 to 36).
@return Indicates if the operation succeeded, or why it failed.
*/
str2int_errno str2int(int *out, char *s, int base)
{
char *end;
if (s[0] == '\0' || isspace((unsigned char) s[0]))
return STR2INT_INCONVERTIBLE;
errno = 0;
long l = strtol(s, &end, base);
/* Both checks are needed because INT_MAX == LONG_MAX is possible. */
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
return STR2INT_OVERFLOW;
if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
return STR2INT_UNDERFLOW;
if (*end != '\0')
return STR2INT_INCONVERTIBLE;
*out = l;
return STR2INT_SUCCESS;
}
int str2double(double *out, char *s)
{
*out = strtold(s, NULL);
// TODO: error checking, EG: HUGE_VALL
return 0;
}
object Cyc_string2number_(void *data, object cont, object str)
{
int result;
int result, rv;
long l;
double n;
char *s, *end;
Cyc_check_obj(data, string_tag, str);
Cyc_check_str(data, str);
if (type_of(str) == string_tag && ((string_type *) str)->str) {
n = atof(((string_type *) str)->str);
s = ((string_type *) str)->str;
if (ceilf(n) == n) {
result = (int)n;
rv = str2int(&result, s, 10);
if (rv == STR2INT_SUCCESS) {
return_closcall1(data, cont, obj_int2obj(result));
} else {
make_double(result, n);
return_closcall1(data, cont, &result);
str2double(&n, s);
{
make_double(result, n);
return_closcall1(data, cont, &result);
}
}
} else {
// TODO: not good enough because we do pointer comparisons to #f