2008-06-30 21:54:22 -04:00
|
|
|
#ifdef BITS64
|
2019-08-09 07:02:02 -04:00
|
|
|
#define NWORDS(sz) (((sz) + 7) >> 3)
|
2008-06-30 21:54:22 -04:00
|
|
|
#else
|
2019-08-09 07:02:02 -04:00
|
|
|
#define NWORDS(sz) (((sz) + 3) >> 2)
|
2008-06-30 21:54:22 -04:00
|
|
|
#endif
|
|
|
|
|
2008-08-02 12:18:39 -04:00
|
|
|
static int ALIGN2, ALIGN4, ALIGN8, ALIGNPTR;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
|
|
|
value_t int8sym, uint8sym, int16sym, uint16sym, int32sym, uint32sym;
|
|
|
|
value_t int64sym, uint64sym;
|
2008-12-23 23:43:36 -05:00
|
|
|
value_t longsym, ulongsym, bytesym, wcharsym;
|
2008-06-30 21:54:22 -04:00
|
|
|
value_t floatsym, doublesym;
|
2008-12-10 23:04:17 -05:00
|
|
|
value_t gftypesym, stringtypesym, wcstringtypesym;
|
2008-06-30 21:54:22 -04:00
|
|
|
value_t emptystringsym;
|
|
|
|
|
|
|
|
value_t structsym, arraysym, enumsym, cfunctionsym, voidsym, pointersym;
|
|
|
|
value_t unionsym;
|
|
|
|
|
2019-08-09 12:26:09 -04:00
|
|
|
static struct htable TypeTable;
|
|
|
|
static struct htable reverse_dlsym_lookup_table;
|
2019-08-09 12:33:04 -04:00
|
|
|
static struct fltype *int8type, *uint8type;
|
|
|
|
static struct fltype *int16type, *uint16type;
|
|
|
|
static struct fltype *int32type, *uint32type;
|
|
|
|
static struct fltype *int64type, *uint64type;
|
|
|
|
static struct fltype *longtype, *ulongtype;
|
|
|
|
static struct fltype *floattype, *doubletype;
|
|
|
|
struct fltype *bytetype, *wchartype;
|
|
|
|
struct fltype *stringtype, *wcstringtype;
|
|
|
|
struct fltype *builtintype;
|
|
|
|
|
|
|
|
static void cvalue_init(struct fltype *type, value_t v, void *dest);
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-12-10 23:04:17 -05:00
|
|
|
// cvalues-specific builtins
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t cvalue_new(value_t *args, uint32_t nargs);
|
|
|
|
value_t cvalue_sizeof(value_t *args, uint32_t nargs);
|
|
|
|
value_t cvalue_typeof(value_t *args, uint32_t nargs);
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-12-20 01:16:00 -05:00
|
|
|
// trigger unconditional GC after this many bytes are allocated
|
|
|
|
#define ALLOC_LIMIT_TRIGGER 67108864
|
|
|
|
|
2010-05-04 20:00:37 -04:00
|
|
|
static size_t malloc_pressure = 0;
|
|
|
|
|
2019-08-09 12:36:20 -04:00
|
|
|
static struct cvalue **Finalizers = NULL;
|
2019-08-09 07:02:02 -04:00
|
|
|
static size_t nfinalizers = 0;
|
|
|
|
static size_t maxfinalizers = 0;
|
2008-12-20 01:16:00 -05:00
|
|
|
|
2019-08-09 12:36:20 -04:00
|
|
|
void add_finalizer(struct cvalue *cv)
|
2008-12-20 01:16:00 -05:00
|
|
|
{
|
|
|
|
if (nfinalizers == maxfinalizers) {
|
2019-08-09 07:02:02 -04:00
|
|
|
size_t nn = (maxfinalizers == 0 ? 256 : maxfinalizers * 2);
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue **temp =
|
|
|
|
(struct cvalue **)realloc(Finalizers, nn * sizeof(value_t));
|
2008-12-20 01:16:00 -05:00
|
|
|
if (temp == NULL)
|
|
|
|
lerror(MemoryError, "out of memory");
|
|
|
|
Finalizers = temp;
|
|
|
|
maxfinalizers = nn;
|
|
|
|
}
|
|
|
|
Finalizers[nfinalizers++] = cv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove dead objects from finalization list in-place
|
2013-06-08 19:29:15 -04:00
|
|
|
static void sweep_finalizers(void)
|
2008-12-20 01:16:00 -05:00
|
|
|
{
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue **lst = Finalizers;
|
2019-08-09 07:02:02 -04:00
|
|
|
size_t n = 0, ndel = 0, l = nfinalizers;
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *tmp;
|
2019-08-09 07:02:02 -04:00
|
|
|
#define SWAP_sf(a, b) (tmp = a, a = b, b = tmp, 1)
|
2008-12-20 01:16:00 -05:00
|
|
|
if (l == 0)
|
|
|
|
return;
|
|
|
|
do {
|
|
|
|
tmp = lst[n];
|
|
|
|
if (isforwarded((value_t)tmp)) {
|
|
|
|
// object is alive
|
2019-08-09 12:36:20 -04:00
|
|
|
lst[n] = (struct cvalue *)ptr(forwardloc((value_t)tmp));
|
2008-12-20 01:16:00 -05:00
|
|
|
n++;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2019-08-09 12:33:04 -04:00
|
|
|
struct fltype *t = cv_class(tmp);
|
2008-12-20 01:16:00 -05:00
|
|
|
if (t->vtable != NULL && t->vtable->finalize != NULL) {
|
|
|
|
t->vtable->finalize(tagptr(tmp, TAG_CVALUE));
|
|
|
|
}
|
|
|
|
if (!isinlined(tmp) && owned(tmp)) {
|
2009-04-19 18:22:17 -04:00
|
|
|
#ifndef NDEBUG
|
|
|
|
memset(cv_data(tmp), 0xbb, cv_len(tmp));
|
|
|
|
#endif
|
2010-05-03 01:07:22 -04:00
|
|
|
free(cv_data(tmp));
|
2008-12-20 01:16:00 -05:00
|
|
|
}
|
|
|
|
ndel++;
|
|
|
|
}
|
2019-08-09 07:02:02 -04:00
|
|
|
} while ((n < l - ndel) && SWAP_sf(lst[n], lst[n + ndel]));
|
2008-12-20 01:16:00 -05:00
|
|
|
|
|
|
|
nfinalizers -= ndel;
|
2008-12-22 01:36:50 -05:00
|
|
|
#ifdef VERBOSEGC
|
|
|
|
if (ndel > 0)
|
|
|
|
printf("GC: finalized %d objects\n", ndel);
|
|
|
|
#endif
|
2008-12-20 01:16:00 -05:00
|
|
|
|
|
|
|
malloc_pressure = 0;
|
|
|
|
}
|
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
// compute the size of the metadata object for a cvalue
|
2019-08-09 12:36:20 -04:00
|
|
|
static size_t cv_nwords(struct cvalue *cv)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2008-12-10 23:04:17 -05:00
|
|
|
if (isinlined(cv)) {
|
|
|
|
size_t n = cv_len(cv);
|
2019-08-09 07:02:02 -04:00
|
|
|
if (n == 0 || cv_isstr(cv))
|
2008-12-10 23:04:17 -05:00
|
|
|
n++;
|
|
|
|
return CVALUE_NWORDS - 1 + NWORDS(n);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2008-09-06 18:19:51 -04:00
|
|
|
return CVALUE_NWORDS;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 12:36:20 -04:00
|
|
|
static void autorelease(struct cvalue *cv)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 14:07:16 -04:00
|
|
|
cv->type = (struct fltype *)(((uintptr_t)cv->type) | CV_OWNED_BIT);
|
2008-12-20 01:16:00 -05:00
|
|
|
add_finalizer(cv);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 12:36:20 -04:00
|
|
|
void cv_autorelease(struct cvalue *cv) { autorelease(cv); }
|
2008-12-27 01:02:53 -05:00
|
|
|
|
2019-08-09 12:33:04 -04:00
|
|
|
static value_t cprim(struct fltype *type, size_t sz)
|
2009-01-02 18:00:21 -05:00
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
struct cprim *pcp;
|
|
|
|
|
2019-08-09 14:07:16 -04:00
|
|
|
assert(!ismanaged((uintptr_t)type));
|
2010-05-04 14:17:55 -04:00
|
|
|
assert(sz == type->size);
|
2019-08-18 18:14:09 -04:00
|
|
|
pcp = (struct cprim *)alloc_words(CPRIM_NWORDS - 1 + NWORDS(sz));
|
2009-01-02 18:00:21 -05:00
|
|
|
pcp->type = type;
|
|
|
|
return tagptr(pcp, TAG_CPRIM);
|
|
|
|
}
|
|
|
|
|
2019-08-09 12:33:04 -04:00
|
|
|
value_t cvalue(struct fltype *type, size_t sz)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *pcv;
|
2019-08-18 18:14:09 -04:00
|
|
|
int str;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2019-08-18 18:14:09 -04:00
|
|
|
str = 0;
|
2009-01-02 18:00:21 -05:00
|
|
|
if (valid_numtype(type->numtype)) {
|
|
|
|
return cprim(type, sz);
|
|
|
|
}
|
2008-12-28 03:01:18 -05:00
|
|
|
if (type->eltype == bytetype) {
|
|
|
|
if (sz == 0)
|
|
|
|
return symbol_value(emptystringsym);
|
|
|
|
sz++;
|
2019-08-09 07:02:02 -04:00
|
|
|
str = 1;
|
2008-12-28 03:01:18 -05:00
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
if (sz <= MAX_INL_SIZE) {
|
2019-08-09 07:02:02 -04:00
|
|
|
size_t nw = CVALUE_NWORDS - 1 + NWORDS(sz) + (sz == 0 ? 1 : 0);
|
2019-08-09 12:36:20 -04:00
|
|
|
pcv = (struct cvalue *)alloc_words(nw);
|
2008-12-20 01:16:00 -05:00
|
|
|
pcv->type = type;
|
2008-12-10 23:04:17 -05:00
|
|
|
pcv->data = &pcv->_space[0];
|
2008-12-20 01:16:00 -05:00
|
|
|
if (type->vtable != NULL && type->vtable->finalize != NULL)
|
|
|
|
add_finalizer(pcv);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2008-12-20 01:16:00 -05:00
|
|
|
if (malloc_pressure > ALLOC_LIMIT_TRIGGER)
|
|
|
|
gc(0);
|
2019-08-09 12:36:20 -04:00
|
|
|
pcv = (struct cvalue *)alloc_words(CVALUE_NWORDS);
|
2008-12-20 01:16:00 -05:00
|
|
|
pcv->type = type;
|
2010-05-03 01:07:22 -04:00
|
|
|
pcv->data = malloc(sz);
|
2008-06-30 21:54:22 -04:00
|
|
|
autorelease(pcv);
|
2008-12-20 01:16:00 -05:00
|
|
|
malloc_pressure += sz;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2008-12-28 03:01:18 -05:00
|
|
|
if (str) {
|
|
|
|
sz--;
|
2019-08-09 07:02:02 -04:00
|
|
|
((char *)pcv->data)[sz] = '\0';
|
2008-12-28 03:01:18 -05:00
|
|
|
}
|
2008-12-10 23:04:17 -05:00
|
|
|
pcv->len = sz;
|
2008-08-04 21:43:12 -04:00
|
|
|
return tagptr(pcv, TAG_CVALUE);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 12:33:04 -04:00
|
|
|
value_t cvalue_from_data(struct fltype *type, void *data, size_t sz)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
value_t cv;
|
2019-08-18 18:14:09 -04:00
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
cv = cvalue(type, sz);
|
2009-01-02 18:00:21 -05:00
|
|
|
memcpy(cptr(cv), data, sz);
|
2008-06-30 21:54:22 -04:00
|
|
|
return cv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this effectively dereferences a pointer
|
|
|
|
// just like *p in C, it only removes a level of indirection from the type,
|
|
|
|
// it doesn't copy any data.
|
|
|
|
// this method of creating a cvalue only allocates metadata.
|
|
|
|
// ptr is user-managed; we don't autorelease it unless the
|
|
|
|
// user explicitly calls (autorelease ) on the result of this function.
|
|
|
|
// 'parent' is an optional cvalue that this pointer is known to point
|
2008-07-26 18:04:02 -04:00
|
|
|
// into; NIL if none.
|
2019-08-09 12:33:04 -04:00
|
|
|
value_t cvalue_from_ref(struct fltype *type, void *ptr, size_t sz,
|
|
|
|
value_t parent)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *pcv;
|
2008-06-30 21:54:22 -04:00
|
|
|
value_t cv;
|
|
|
|
|
2019-08-09 12:36:20 -04:00
|
|
|
pcv = (struct cvalue *)alloc_words(CVALUE_NWORDS);
|
2008-06-30 21:54:22 -04:00
|
|
|
pcv->data = ptr;
|
|
|
|
pcv->len = sz;
|
2008-12-10 23:04:17 -05:00
|
|
|
pcv->type = type;
|
2008-07-26 18:04:02 -04:00
|
|
|
if (parent != NIL) {
|
2019-08-09 14:07:16 -04:00
|
|
|
pcv->type = (struct fltype *)(((uintptr_t)pcv->type) | CV_PARENT_BIT);
|
2008-12-10 23:04:17 -05:00
|
|
|
pcv->parent = parent;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2008-08-04 21:43:12 -04:00
|
|
|
cv = tagptr(pcv, TAG_CVALUE);
|
2008-06-30 21:54:22 -04:00
|
|
|
return cv;
|
|
|
|
}
|
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
value_t cvalue_string(size_t sz) { return cvalue(stringtype, sz); }
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2009-03-24 22:28:21 -04:00
|
|
|
value_t cvalue_static_cstring(const char *str)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 07:02:02 -04:00
|
|
|
return cvalue_from_ref(stringtype, (char *)str, strlen(str), NIL);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-11 16:27:12 -04:00
|
|
|
value_t string_from_cstrn(const char *str, size_t n)
|
2008-09-10 22:37:38 -04:00
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
value_t v;
|
|
|
|
|
|
|
|
v = cvalue_string(n);
|
2008-09-10 22:37:38 -04:00
|
|
|
memcpy(cvalue_data(v), str, n);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2019-08-11 16:27:12 -04:00
|
|
|
value_t string_from_cstr(const char *str)
|
2009-03-04 22:48:17 -05:00
|
|
|
{
|
|
|
|
return string_from_cstrn(str, strlen(str));
|
|
|
|
}
|
|
|
|
|
2009-08-23 03:06:57 -04:00
|
|
|
int fl_isstring(value_t v)
|
2008-08-05 00:34:14 -04:00
|
|
|
{
|
2019-08-09 12:36:20 -04:00
|
|
|
return (iscvalue(v) && cv_isstr((struct cvalue *)ptr(v)));
|
2008-08-05 00:34:14 -04:00
|
|
|
}
|
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
// convert to malloc representation (fixed address)
|
2019-08-09 12:36:20 -04:00
|
|
|
void cv_pin(struct cvalue *cv)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
size_t sz;
|
|
|
|
void *data;
|
|
|
|
|
2009-04-09 00:04:27 -04:00
|
|
|
if (!isinlined(cv))
|
2008-06-30 21:54:22 -04:00
|
|
|
return;
|
2019-08-18 18:14:09 -04:00
|
|
|
sz = cv_len(cv);
|
2019-08-09 07:02:02 -04:00
|
|
|
if (cv_isstr(cv))
|
|
|
|
sz++;
|
2019-08-18 18:14:09 -04:00
|
|
|
data = malloc(sz);
|
2009-04-09 00:04:27 -04:00
|
|
|
memcpy(data, cv_data(cv), sz);
|
|
|
|
cv->data = data;
|
2008-06-30 21:54:22 -04:00
|
|
|
autorelease(cv);
|
|
|
|
}
|
|
|
|
|
2019-08-09 12:33:04 -04:00
|
|
|
#define num_init(ctype, cnvt, tag) \
|
|
|
|
static int cvalue_##ctype##_init(struct fltype *type, value_t arg, \
|
|
|
|
void *dest) \
|
|
|
|
{ \
|
2019-08-09 14:00:03 -04:00
|
|
|
ctype##_t n = 0; \
|
2019-08-09 12:33:04 -04:00
|
|
|
(void)type; \
|
|
|
|
if (isfixnum(arg)) { \
|
|
|
|
n = numval(arg); \
|
|
|
|
} else if (iscprim(arg)) { \
|
|
|
|
struct cprim *cp = (struct cprim *)ptr(arg); \
|
|
|
|
void *p = cp_data(cp); \
|
2019-08-09 14:00:03 -04:00
|
|
|
n = (ctype##_t)conv_to_##cnvt(p, cp_numtype(cp)); \
|
2019-08-09 12:33:04 -04:00
|
|
|
} else { \
|
|
|
|
return 1; \
|
|
|
|
} \
|
2019-08-09 14:00:03 -04:00
|
|
|
*((ctype##_t *)dest) = n; \
|
2019-08-09 12:33:04 -04:00
|
|
|
return 0; \
|
2019-08-09 07:02:02 -04:00
|
|
|
}
|
|
|
|
num_init(int8, int32, T_INT8) num_init(uint8, uint32, T_UINT8)
|
|
|
|
num_init(int16, int32, T_INT16) num_init(uint16, uint32, T_UINT16)
|
|
|
|
num_init(int32, int32, T_INT32) num_init(uint32, uint32, T_UINT32)
|
|
|
|
num_init(int64, int64, T_INT64) num_init(uint64, uint64, T_UINT64)
|
|
|
|
num_init(float, double, T_FLOAT) num_init(double, double, T_DOUBLE)
|
|
|
|
|
2019-08-09 12:25:43 -04:00
|
|
|
#define num_ctor_init(typenam, ctype, tag) \
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t cvalue_##typenam(value_t *args, uint32_t nargs) \
|
2019-08-09 12:25:43 -04:00
|
|
|
{ \
|
2019-08-18 18:14:09 -04:00
|
|
|
value_t cp; \
|
2019-08-09 12:25:43 -04:00
|
|
|
if (nargs == 0) { \
|
|
|
|
PUSH(fixnum(0)); \
|
|
|
|
args = &Stack[SP - 1]; \
|
|
|
|
} \
|
2019-08-18 18:14:09 -04:00
|
|
|
cp = cprim(typenam##type, sizeof(ctype##_t)); \
|
2019-08-09 12:25:43 -04:00
|
|
|
if (cvalue_##ctype##_init(typenam##type, args[0], \
|
|
|
|
cp_data((struct cprim *)ptr(cp)))) \
|
|
|
|
type_error(#typenam, "number", args[0]); \
|
|
|
|
return cp; \
|
2019-08-09 07:02:02 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
#define num_ctor_ctor(typenam, ctype, tag) \
|
|
|
|
value_t mk_##typenam(ctype##_t n) \
|
|
|
|
{ \
|
|
|
|
value_t cp = cprim(typenam##type, sizeof(ctype##_t)); \
|
|
|
|
*(ctype##_t *)cp_data((struct cprim *)ptr(cp)) = n; \
|
|
|
|
return cp; \
|
2019-08-09 07:02:02 -04:00
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2009-03-16 23:29:17 -04:00
|
|
|
#define num_ctor(typenam, ctype, tag) \
|
2019-08-09 07:02:02 -04:00
|
|
|
num_ctor_init(typenam, ctype, tag) num_ctor_ctor(typenam, ctype, tag)
|
|
|
|
|
|
|
|
num_ctor(int8, int8, T_INT8) num_ctor(uint8, uint8, T_UINT8)
|
|
|
|
num_ctor(int16, int16, T_INT16) num_ctor(uint16, uint16, T_UINT16)
|
|
|
|
num_ctor(int32, int32, T_INT32) num_ctor(uint32, uint32, T_UINT32)
|
|
|
|
num_ctor(int64, int64, T_INT64) num_ctor(uint64, uint64, T_UINT64)
|
|
|
|
num_ctor(byte, uint8, T_UINT8) num_ctor(wchar, int32, T_INT32)
|
2008-06-30 21:54:22 -04:00
|
|
|
#ifdef BITS64
|
2019-08-09 07:02:02 -04:00
|
|
|
num_ctor(long, int64, T_INT64) num_ctor(ulong, uint64, T_UINT64)
|
2008-06-30 21:54:22 -04:00
|
|
|
#else
|
2019-08-09 07:02:02 -04:00
|
|
|
num_ctor(long, int32, T_INT32) num_ctor(ulong, uint32, T_UINT32)
|
2008-06-30 21:54:22 -04:00
|
|
|
#endif
|
2019-08-09 07:02:02 -04:00
|
|
|
num_ctor(float, float, T_FLOAT) num_ctor(double, double, T_DOUBLE)
|
2008-06-30 21:54:22 -04:00
|
|
|
|
|
|
|
value_t size_wrap(size_t sz)
|
|
|
|
{
|
|
|
|
if (fits_fixnum(sz))
|
|
|
|
return fixnum(sz);
|
2019-08-09 07:02:02 -04:00
|
|
|
assert(sizeof(void *) == sizeof(size_t));
|
2008-06-30 21:54:22 -04:00
|
|
|
return mk_ulong(sz);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t toulong(value_t n, char *fname)
|
|
|
|
{
|
|
|
|
if (isfixnum(n))
|
|
|
|
return numval(n);
|
2009-01-02 18:00:21 -05:00
|
|
|
if (iscprim(n)) {
|
2019-08-09 12:25:43 -04:00
|
|
|
struct cprim *cp = (struct cprim *)ptr(n);
|
2009-01-02 18:00:21 -05:00
|
|
|
return conv_to_ulong(cp_data(cp), cp_numtype(cp));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
type_error(fname, "number", n);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-09 12:33:04 -04:00
|
|
|
static int cvalue_enum_init(struct fltype *ft, value_t arg, void *dest)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 07:02:02 -04:00
|
|
|
int n = 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
value_t syms;
|
2008-12-10 23:04:17 -05:00
|
|
|
value_t type = ft->type;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-08-28 23:27:59 -04:00
|
|
|
syms = car(cdr(type));
|
2009-03-11 15:16:40 -04:00
|
|
|
if (!isvector(syms))
|
|
|
|
type_error("enum", "vector", syms);
|
2008-08-28 23:27:59 -04:00
|
|
|
if (issymbol(arg)) {
|
2019-08-09 07:02:02 -04:00
|
|
|
for (n = 0; n < (int)vector_size(syms); n++) {
|
2009-03-11 15:16:40 -04:00
|
|
|
if (vector_elt(syms, n) == arg) {
|
2019-08-09 07:02:02 -04:00
|
|
|
*(int *)dest = n;
|
2009-03-04 22:48:17 -05:00
|
|
|
return 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
lerror(ArgError, "enum: invalid enum value");
|
|
|
|
}
|
2008-08-28 23:27:59 -04:00
|
|
|
if (isfixnum(arg)) {
|
|
|
|
n = (int)numval(arg);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (iscprim(arg)) {
|
2019-08-09 12:25:43 -04:00
|
|
|
struct cprim *cp = (struct cprim *)ptr(arg);
|
2009-01-02 18:00:21 -05:00
|
|
|
n = conv_to_int32(cp_data(cp), cp_numtype(cp));
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2009-01-02 18:00:21 -05:00
|
|
|
type_error("enum", "number", arg);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2009-03-11 15:16:40 -04:00
|
|
|
if ((unsigned)n >= vector_size(syms))
|
2008-06-30 21:54:22 -04:00
|
|
|
lerror(ArgError, "enum: value out of range");
|
2019-08-09 07:02:02 -04:00
|
|
|
*(int *)dest = n;
|
2009-03-04 22:48:17 -05:00
|
|
|
return 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t cvalue_enum(value_t *args, uint32_t nargs)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
value_t cv, type;
|
|
|
|
struct fltype *ft;
|
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
argcount("enum", nargs, 2);
|
2019-08-18 18:14:09 -04:00
|
|
|
type = fl_list2(enumsym, args[0]);
|
|
|
|
ft = get_type(type);
|
|
|
|
cv = cvalue(ft, sizeof(int32_t));
|
2019-08-09 12:25:43 -04:00
|
|
|
cvalue_enum_init(ft, args[1], cp_data((struct cprim *)ptr(cv)));
|
2008-06-30 21:54:22 -04:00
|
|
|
return cv;
|
|
|
|
}
|
|
|
|
|
2008-08-28 23:27:59 -04:00
|
|
|
static int isarray(value_t v)
|
|
|
|
{
|
2019-08-09 12:36:20 -04:00
|
|
|
return iscvalue(v) && cv_class((struct cvalue *)ptr(v))->eltype != NULL;
|
2008-08-28 23:27:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static size_t predict_arraylen(value_t arg)
|
|
|
|
{
|
|
|
|
if (isvector(arg))
|
|
|
|
return vector_size(arg);
|
|
|
|
else if (iscons(arg))
|
|
|
|
return llength(arg);
|
|
|
|
else if (arg == NIL)
|
|
|
|
return 0;
|
|
|
|
if (isarray(arg))
|
|
|
|
return cvalue_arraylen(arg);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-08-09 12:33:04 -04:00
|
|
|
static int cvalue_array_init(struct fltype *ft, value_t arg, void *dest)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2008-12-10 23:04:17 -05:00
|
|
|
value_t type = ft->type;
|
2008-08-28 23:27:59 -04:00
|
|
|
size_t elsize, i, cnt, sz;
|
2019-08-09 12:33:04 -04:00
|
|
|
struct fltype *eltype = ft->eltype;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-12-10 23:04:17 -05:00
|
|
|
elsize = ft->elsz;
|
2008-08-28 23:27:59 -04:00
|
|
|
cnt = predict_arraylen(arg);
|
|
|
|
|
|
|
|
if (iscons(cdr_(cdr_(type)))) {
|
|
|
|
size_t tc = toulong(car_(cdr_(cdr_(type))), "array");
|
|
|
|
if (tc != cnt)
|
|
|
|
lerror(ArgError, "array: size mismatch");
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2008-08-28 23:27:59 -04:00
|
|
|
|
|
|
|
sz = elsize * cnt;
|
|
|
|
|
|
|
|
if (isvector(arg)) {
|
2010-05-04 14:17:55 -04:00
|
|
|
assert(cnt <= vector_size(arg));
|
2019-08-09 07:02:02 -04:00
|
|
|
for (i = 0; i < cnt; i++) {
|
|
|
|
cvalue_init(eltype, vector_elt(arg, i), dest);
|
|
|
|
dest = (char *)dest + elsize;
|
2009-03-26 23:06:55 -04:00
|
|
|
}
|
2009-03-04 22:48:17 -05:00
|
|
|
return 0;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (iscons(arg) || arg == NIL) {
|
2008-08-28 23:27:59 -04:00
|
|
|
i = 0;
|
|
|
|
while (iscons(arg)) {
|
2019-08-09 07:02:02 -04:00
|
|
|
if (i == cnt) {
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
} // trigger error
|
2009-03-26 23:06:55 -04:00
|
|
|
cvalue_init(eltype, car_(arg), dest);
|
2008-08-28 23:27:59 -04:00
|
|
|
i++;
|
2019-08-09 07:02:02 -04:00
|
|
|
dest = (char *)dest + elsize;
|
2008-08-28 23:27:59 -04:00
|
|
|
arg = cdr_(arg);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2008-08-28 23:27:59 -04:00
|
|
|
if (i != cnt)
|
|
|
|
lerror(ArgError, "array: size mismatch");
|
2009-03-04 22:48:17 -05:00
|
|
|
return 0;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (iscvalue(arg)) {
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *cv = (struct cvalue *)ptr(arg);
|
2008-08-28 23:27:59 -04:00
|
|
|
if (isarray(arg)) {
|
2019-08-09 12:33:04 -04:00
|
|
|
struct fltype *aet = cv_class(cv)->eltype;
|
2008-08-28 23:27:59 -04:00
|
|
|
if (aet == eltype) {
|
|
|
|
if (cv_len(cv) == sz)
|
|
|
|
memcpy(dest, cv_data(cv), sz);
|
|
|
|
else
|
|
|
|
lerror(ArgError, "array: size mismatch");
|
2009-03-04 22:48:17 -05:00
|
|
|
return 0;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2008-08-28 23:27:59 -04:00
|
|
|
// TODO: initialize array from different type elements
|
|
|
|
lerror(ArgError, "array: element type mismatch");
|
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
}
|
2008-08-28 23:27:59 -04:00
|
|
|
if (cnt == 1)
|
|
|
|
cvalue_init(eltype, arg, dest);
|
|
|
|
else
|
|
|
|
type_error("array", "sequence", arg);
|
2009-03-04 22:48:17 -05:00
|
|
|
return 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t cvalue_array(value_t *args, uint32_t nargs)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2009-03-26 23:06:55 -04:00
|
|
|
size_t elsize, cnt, sz, i;
|
2019-08-18 18:14:09 -04:00
|
|
|
value_t arg, cv;
|
|
|
|
struct fltype *type;
|
|
|
|
char *dest;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-08-28 23:27:59 -04:00
|
|
|
if (nargs < 1)
|
|
|
|
argcount("array", nargs, 1);
|
|
|
|
|
|
|
|
cnt = nargs - 1;
|
2019-08-18 18:14:09 -04:00
|
|
|
type = get_array_type(args[0]);
|
2008-12-10 23:04:17 -05:00
|
|
|
elsize = type->elsz;
|
2008-06-30 21:54:22 -04:00
|
|
|
sz = elsize * cnt;
|
|
|
|
|
2019-08-18 18:14:09 -04:00
|
|
|
cv = cvalue(type, sz);
|
|
|
|
dest = cv_data((struct cvalue *)ptr(cv));
|
2019-08-09 07:02:02 -04:00
|
|
|
FOR_ARGS(i, 1, arg, args)
|
|
|
|
{
|
2009-03-26 23:06:55 -04:00
|
|
|
cvalue_init(type->eltype, arg, dest);
|
|
|
|
dest += elsize;
|
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
return cv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: v must be an array
|
|
|
|
size_t cvalue_arraylen(value_t v)
|
|
|
|
{
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *cv = (struct cvalue *)ptr(v);
|
2019-08-09 07:02:02 -04:00
|
|
|
return cv_len(cv) / (cv_class(cv)->elsz);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
static size_t cvalue_struct_offs(value_t type, value_t field,
|
|
|
|
int computeTotal, int *palign)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
value_t fld = car(cdr_(type));
|
|
|
|
size_t fsz, ssz = 0;
|
|
|
|
int al;
|
|
|
|
|
2019-08-18 18:14:09 -04:00
|
|
|
*palign = 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
while (iscons(fld)) {
|
|
|
|
fsz = ctype_sizeof(car(cdr(car_(fld))), &al);
|
|
|
|
|
2019-08-26 18:25:11 -04:00
|
|
|
ssz = ALIGN(ssz, al);
|
2008-06-30 21:54:22 -04:00
|
|
|
if (al > *palign)
|
|
|
|
*palign = al;
|
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
if (!computeTotal && field == car_(car_(fld))) {
|
2008-06-30 21:54:22 -04:00
|
|
|
// found target field
|
|
|
|
return ssz;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssz += fsz;
|
|
|
|
fld = cdr_(fld);
|
|
|
|
}
|
2019-08-26 18:25:11 -04:00
|
|
|
return ALIGN(ssz, *palign);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static size_t cvalue_union_size(value_t type, int *palign)
|
|
|
|
{
|
|
|
|
value_t fld = car(cdr_(type));
|
|
|
|
size_t fsz, usz = 0;
|
|
|
|
int al;
|
|
|
|
|
2019-08-18 18:14:09 -04:00
|
|
|
*palign = 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
while (iscons(fld)) {
|
|
|
|
fsz = ctype_sizeof(car(cdr(car_(fld))), &al);
|
2019-08-09 07:02:02 -04:00
|
|
|
if (al > *palign)
|
|
|
|
*palign = al;
|
|
|
|
if (fsz > usz)
|
|
|
|
usz = fsz;
|
2008-06-30 21:54:22 -04:00
|
|
|
fld = cdr_(fld);
|
|
|
|
}
|
2019-08-26 18:25:11 -04:00
|
|
|
return ALIGN(usz, *palign);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// *palign is an output argument giving the alignment required by type
|
|
|
|
size_t ctype_sizeof(value_t type, int *palign)
|
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
value_t hed, t, n;
|
|
|
|
size_t sz;
|
|
|
|
|
2008-12-23 23:43:36 -05:00
|
|
|
if (type == int8sym || type == uint8sym || type == bytesym) {
|
2008-06-30 21:54:22 -04:00
|
|
|
*palign = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (type == int16sym || type == uint16sym) {
|
|
|
|
*palign = ALIGN2;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
if (type == int32sym || type == uint32sym || type == wcharsym ||
|
|
|
|
type == floatsym) {
|
|
|
|
*palign = ALIGN4;
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
if (type == int64sym || type == uint64sym || type == doublesym) {
|
|
|
|
*palign = ALIGN8;
|
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
if (type == longsym || type == ulongsym) {
|
|
|
|
#ifdef BITS64
|
|
|
|
*palign = ALIGN8;
|
|
|
|
return 8;
|
|
|
|
#else
|
|
|
|
*palign = ALIGN4;
|
|
|
|
return 4;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if (iscons(type)) {
|
2019-08-18 18:14:09 -04:00
|
|
|
hed = car_(type);
|
2008-12-10 23:04:17 -05:00
|
|
|
if (hed == pointersym || hed == cfunctionsym) {
|
2008-08-02 12:18:39 -04:00
|
|
|
*palign = ALIGNPTR;
|
2019-08-09 07:02:02 -04:00
|
|
|
return sizeof(void *);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
if (hed == arraysym) {
|
2019-08-18 18:14:09 -04:00
|
|
|
t = car(cdr_(type));
|
2008-06-30 21:54:22 -04:00
|
|
|
if (!iscons(cdr_(cdr_(type))))
|
|
|
|
lerror(ArgError, "sizeof: incomplete type");
|
2019-08-18 18:14:09 -04:00
|
|
|
n = car_(cdr_(cdr_(type)));
|
|
|
|
sz = toulong(n, "sizeof");
|
2008-06-30 21:54:22 -04:00
|
|
|
return sz * ctype_sizeof(t, palign);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (hed == structsym) {
|
2008-06-30 21:54:22 -04:00
|
|
|
return cvalue_struct_offs(type, NIL, 1, palign);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (hed == unionsym) {
|
2008-06-30 21:54:22 -04:00
|
|
|
return cvalue_union_size(type, palign);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (hed == enumsym) {
|
2008-06-30 21:54:22 -04:00
|
|
|
*palign = ALIGN4;
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lerror(ArgError, "sizeof: invalid c type");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-09 12:33:04 -04:00
|
|
|
extern struct fltype *iostreamtype;
|
2009-04-19 12:48:09 -04:00
|
|
|
|
2009-03-04 22:48:17 -05:00
|
|
|
// get pointer and size for any plain-old-data value
|
|
|
|
void to_sized_ptr(value_t v, char *fname, char **pdata, size_t *psz)
|
|
|
|
{
|
2009-04-19 12:48:09 -04:00
|
|
|
if (iscvalue(v)) {
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *pcv = (struct cvalue *)ptr(v);
|
2019-08-09 12:26:20 -04:00
|
|
|
struct ios *x = value2c(struct ios *, v);
|
2009-04-19 12:48:09 -04:00
|
|
|
if (cv_class(pcv) == iostreamtype && (x->bm == bm_mem)) {
|
|
|
|
*pdata = x->buf;
|
|
|
|
*psz = x->size;
|
|
|
|
return;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (cv_isPOD(pcv)) {
|
2009-04-19 12:48:09 -04:00
|
|
|
*pdata = cv_data(pcv);
|
|
|
|
*psz = cv_len(pcv);
|
|
|
|
return;
|
|
|
|
}
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (iscprim(v)) {
|
2019-08-09 12:25:43 -04:00
|
|
|
struct cprim *pcp = (struct cprim *)ptr(v);
|
2009-03-04 22:48:17 -05:00
|
|
|
*pdata = cp_data(pcp);
|
|
|
|
*psz = cp_class(pcp)->size;
|
2009-04-19 12:48:09 -04:00
|
|
|
return;
|
2009-03-04 22:48:17 -05:00
|
|
|
}
|
2009-04-19 12:48:09 -04:00
|
|
|
type_error(fname, "plain-old-data", v);
|
2009-03-04 22:48:17 -05:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t cvalue_sizeof(value_t *args, uint32_t nargs)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
char *data;
|
|
|
|
size_t n;
|
|
|
|
int a;
|
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
argcount("sizeof", nargs, 1);
|
2009-03-04 22:48:17 -05:00
|
|
|
if (issymbol(args[0]) || iscons(args[0])) {
|
|
|
|
return size_wrap(ctype_sizeof(args[0], &a));
|
2009-01-02 18:00:21 -05:00
|
|
|
}
|
2009-03-04 22:48:17 -05:00
|
|
|
to_sized_ptr(args[0], "sizeof", &data, &n);
|
|
|
|
return size_wrap(n);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t cvalue_typeof(value_t *args, uint32_t nargs)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
argcount("typeof", nargs, 1);
|
2019-08-09 07:02:02 -04:00
|
|
|
switch (tag(args[0])) {
|
|
|
|
case TAG_CONS:
|
|
|
|
return pairsym;
|
2008-08-04 21:43:12 -04:00
|
|
|
case TAG_NUM1:
|
2019-08-09 07:02:02 -04:00
|
|
|
case TAG_NUM:
|
|
|
|
return fixnumsym;
|
|
|
|
case TAG_SYM:
|
|
|
|
return symbolsym;
|
|
|
|
case TAG_VECTOR:
|
|
|
|
return vectorsym;
|
2009-04-28 00:10:18 -04:00
|
|
|
case TAG_FUNCTION:
|
switching to scheme #t, #f, and () values
porting code to sort out which NILs are false and which are
empty lists
switching to scheme-style special forms. however you feel about
scheme names vs. CL names, using both is silly.
mostly switching to scheme predicate names, with compatibility
aliases for now. adding set-constant! to make this efficient.
adding null?, eqv?, assq, assv, assoc, memq, memv, member
adding 2-argument form of if
allowing else as final cond condition
looking for init file in same directory as executable, so flisp
can be started from anywhere
renaming T to FL_T, since exporting a 1-character symbol is
not very nice
adding opaque type boilerplate example file
adding correctness checking for the pattern-lambda benchmark
bugfix in int2str
2009-01-28 20:04:23 -05:00
|
|
|
if (args[0] == FL_T || args[0] == FL_F)
|
|
|
|
return booleansym;
|
|
|
|
if (args[0] == NIL)
|
|
|
|
return nullsym;
|
2009-08-09 14:04:03 -04:00
|
|
|
if (args[0] == FL_EOF)
|
|
|
|
return symbol("eof-object");
|
2009-04-28 00:10:18 -04:00
|
|
|
if (isbuiltin(args[0]))
|
|
|
|
return builtinsym;
|
|
|
|
return FUNCTION;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2019-08-09 12:36:20 -04:00
|
|
|
return cv_type((struct cvalue *)ptr(args[0]));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2010-08-04 15:03:19 -04:00
|
|
|
static value_t cvalue_relocate(value_t v)
|
2009-03-11 22:47:34 -04:00
|
|
|
{
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *cv = (struct cvalue *)ptr(v);
|
|
|
|
struct cvalue *nv;
|
2019-08-18 18:14:09 -04:00
|
|
|
struct fltype *t;
|
2009-03-11 22:47:34 -04:00
|
|
|
value_t ncv;
|
2019-08-18 18:14:09 -04:00
|
|
|
size_t nw;
|
2009-03-11 22:47:34 -04:00
|
|
|
|
|
|
|
nw = cv_nwords(cv);
|
2019-08-09 12:36:20 -04:00
|
|
|
nv = (struct cvalue *)alloc_words(nw);
|
2019-08-09 07:02:02 -04:00
|
|
|
memcpy(nv, cv, nw * sizeof(value_t));
|
2009-03-11 22:47:34 -04:00
|
|
|
if (isinlined(cv))
|
|
|
|
nv->data = &nv->_space[0];
|
|
|
|
ncv = tagptr(nv, TAG_CVALUE);
|
2019-08-18 18:14:09 -04:00
|
|
|
t = cv_class(cv);
|
2009-03-11 22:47:34 -04:00
|
|
|
if (t->vtable != NULL && t->vtable->relocate != NULL)
|
|
|
|
t->vtable->relocate(v, ncv);
|
|
|
|
forward(v, ncv);
|
|
|
|
return ncv;
|
|
|
|
}
|
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
value_t cvalue_copy(value_t v)
|
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
struct cvalue *ncv;
|
|
|
|
struct cvalue *cv;
|
|
|
|
size_t nw, len;
|
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
assert(iscvalue(v));
|
|
|
|
PUSH(v);
|
2019-08-18 18:14:09 -04:00
|
|
|
cv = (struct cvalue *)ptr(v);
|
|
|
|
nw = cv_nwords(cv);
|
|
|
|
ncv = (struct cvalue *)alloc_words(nw);
|
2019-08-09 07:02:02 -04:00
|
|
|
v = POP();
|
2019-08-09 12:36:20 -04:00
|
|
|
cv = (struct cvalue *)ptr(v);
|
2009-02-23 23:12:33 -05:00
|
|
|
memcpy(ncv, cv, nw * sizeof(value_t));
|
2008-12-10 23:04:17 -05:00
|
|
|
if (!isinlined(cv)) {
|
2019-08-18 18:14:09 -04:00
|
|
|
len = cv_len(cv);
|
2019-08-09 07:02:02 -04:00
|
|
|
if (cv_isstr(cv))
|
|
|
|
len++;
|
2010-05-03 01:07:22 -04:00
|
|
|
ncv->data = malloc(len);
|
2009-02-23 23:12:33 -05:00
|
|
|
memcpy(ncv->data, cv_data(cv), len);
|
|
|
|
autorelease(ncv);
|
|
|
|
if (hasparent(cv)) {
|
2019-08-09 12:33:04 -04:00
|
|
|
ncv->type =
|
2019-08-09 14:07:16 -04:00
|
|
|
(struct fltype *)(((uintptr_t)ncv->type) & ~CV_PARENT_BIT);
|
2009-02-23 23:12:33 -05:00
|
|
|
ncv->parent = NIL;
|
|
|
|
}
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2009-02-23 23:12:33 -05:00
|
|
|
ncv->data = &ncv->_space[0];
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2009-02-23 23:12:33 -05:00
|
|
|
return tagptr(ncv, TAG_CVALUE);
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t fl_copy(value_t *args, uint32_t nargs)
|
2009-02-23 23:12:33 -05:00
|
|
|
{
|
|
|
|
argcount("copy", nargs, 1);
|
|
|
|
if (iscons(args[0]) || isvector(args[0]))
|
|
|
|
lerror(ArgError, "copy: argument must be a leaf atom");
|
|
|
|
if (!iscvalue(args[0]))
|
|
|
|
return args[0];
|
2019-08-09 12:36:20 -04:00
|
|
|
if (!cv_isPOD((struct cvalue *)ptr(args[0])))
|
2009-04-19 12:48:09 -04:00
|
|
|
lerror(ArgError, "copy: argument must be a plain-old-data type");
|
2009-02-23 23:12:33 -05:00
|
|
|
return cvalue_copy(args[0]);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t fl_podp(value_t *args, uint32_t nargs)
|
2009-04-19 12:48:09 -04:00
|
|
|
{
|
|
|
|
argcount("plain-old-data?", nargs, 1);
|
|
|
|
return (iscprim(args[0]) ||
|
2019-08-09 12:36:20 -04:00
|
|
|
(iscvalue(args[0]) && cv_isPOD((struct cvalue *)ptr(args[0]))))
|
2019-08-09 07:02:02 -04:00
|
|
|
? FL_T
|
|
|
|
: FL_F;
|
2009-04-19 12:48:09 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 12:33:04 -04:00
|
|
|
static void cvalue_init(struct fltype *type, value_t v, void *dest)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 07:02:02 -04:00
|
|
|
cvinitfunc_t f = type->init;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-08-28 23:27:59 -04:00
|
|
|
if (f == NULL)
|
|
|
|
lerror(ArgError, "c-value: invalid c type");
|
|
|
|
|
2008-12-10 23:04:17 -05:00
|
|
|
f(type, v, dest);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static numerictype_t sym_to_numtype(value_t type)
|
|
|
|
{
|
|
|
|
if (type == int8sym)
|
|
|
|
return T_INT8;
|
2008-12-23 23:43:36 -05:00
|
|
|
else if (type == uint8sym || type == bytesym)
|
2008-06-30 21:54:22 -04:00
|
|
|
return T_UINT8;
|
|
|
|
else if (type == int16sym)
|
|
|
|
return T_INT16;
|
|
|
|
else if (type == uint16sym)
|
|
|
|
return T_UINT16;
|
|
|
|
#ifdef BITS64
|
|
|
|
else if (type == int32sym || type == wcharsym)
|
|
|
|
#else
|
|
|
|
else if (type == int32sym || type == wcharsym || type == longsym)
|
|
|
|
#endif
|
|
|
|
return T_INT32;
|
|
|
|
#ifdef BITS64
|
|
|
|
else if (type == uint32sym)
|
|
|
|
#else
|
|
|
|
else if (type == uint32sym || type == ulongsym)
|
|
|
|
#endif
|
|
|
|
return T_UINT32;
|
|
|
|
#ifdef BITS64
|
|
|
|
else if (type == int64sym || type == longsym)
|
|
|
|
#else
|
|
|
|
else if (type == int64sym)
|
|
|
|
#endif
|
|
|
|
return T_INT64;
|
|
|
|
#ifdef BITS64
|
|
|
|
else if (type == uint64sym || type == ulongsym)
|
|
|
|
#else
|
|
|
|
else if (type == uint64sym)
|
|
|
|
#endif
|
|
|
|
return T_UINT64;
|
2008-12-10 23:04:17 -05:00
|
|
|
else if (type == floatsym)
|
|
|
|
return T_FLOAT;
|
|
|
|
else if (type == doublesym)
|
|
|
|
return T_DOUBLE;
|
2008-06-30 21:54:22 -04:00
|
|
|
return N_NUMTYPES;
|
|
|
|
}
|
|
|
|
|
|
|
|
// (new type . args)
|
|
|
|
// this provides (1) a way to allocate values with a shared type for
|
|
|
|
// efficiency, (2) a uniform interface for allocating cvalues of any
|
|
|
|
// type, including user-defined.
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t cvalue_new(value_t *args, uint32_t nargs)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
struct fltype *ft;
|
|
|
|
value_t cv, type;
|
|
|
|
size_t elsz, cnt;
|
|
|
|
|
2008-08-28 23:27:59 -04:00
|
|
|
if (nargs < 1 || nargs > 2)
|
|
|
|
argcount("c-value", nargs, 2);
|
2019-08-18 18:14:09 -04:00
|
|
|
type = args[0];
|
|
|
|
ft = get_type(type);
|
2008-12-10 23:04:17 -05:00
|
|
|
if (ft->eltype != NULL) {
|
2008-06-30 21:54:22 -04:00
|
|
|
// special case to handle incomplete array types bla[]
|
2019-08-18 18:14:09 -04:00
|
|
|
elsz = ft->elsz;
|
2008-08-28 23:27:59 -04:00
|
|
|
if (iscons(cdr_(cdr_(type))))
|
|
|
|
cnt = toulong(car_(cdr_(cdr_(type))), "array");
|
|
|
|
else if (nargs == 2)
|
|
|
|
cnt = predict_arraylen(args[1]);
|
|
|
|
else
|
|
|
|
cnt = 0;
|
2008-12-28 03:01:18 -05:00
|
|
|
cv = cvalue(ft, elsz * cnt);
|
2008-08-28 23:27:59 -04:00
|
|
|
if (nargs == 2)
|
2019-08-09 12:36:20 -04:00
|
|
|
cvalue_array_init(ft, args[1], cv_data((struct cvalue *)ptr(cv)));
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2008-12-10 23:04:17 -05:00
|
|
|
cv = cvalue(ft, ft->size);
|
2008-08-28 23:27:59 -04:00
|
|
|
if (nargs == 2)
|
2009-01-02 18:00:21 -05:00
|
|
|
cvalue_init(ft, args[1], cptr(cv));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
return cv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: this only compares lexicographically; it ignores numeric formats
|
|
|
|
value_t cvalue_compare(value_t a, value_t b)
|
|
|
|
{
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *ca = (struct cvalue *)ptr(a);
|
|
|
|
struct cvalue *cb = (struct cvalue *)ptr(b);
|
2008-06-30 21:54:22 -04:00
|
|
|
char *adata = cv_data(ca);
|
|
|
|
char *bdata = cv_data(cb);
|
|
|
|
size_t asz = cv_len(ca);
|
|
|
|
size_t bsz = cv_len(cb);
|
|
|
|
size_t minsz = asz < bsz ? asz : bsz;
|
|
|
|
int diff = memcmp(adata, bdata, minsz);
|
2019-08-18 18:14:09 -04:00
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
if (diff == 0) {
|
|
|
|
if (asz > bsz)
|
|
|
|
return fixnum(1);
|
|
|
|
else if (asz < bsz)
|
|
|
|
return fixnum(-1);
|
|
|
|
}
|
|
|
|
return fixnum(diff);
|
|
|
|
}
|
|
|
|
|
2008-12-27 01:02:53 -05:00
|
|
|
static void check_addr_args(char *fname, value_t arr, value_t ind,
|
2019-08-09 14:00:03 -04:00
|
|
|
char **data, unsigned long *index)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2008-12-27 01:02:53 -05:00
|
|
|
size_t numel;
|
2019-08-18 18:14:09 -04:00
|
|
|
struct cvalue *cv;
|
|
|
|
|
|
|
|
cv = (struct cvalue *)ptr(arr);
|
2008-12-27 01:02:53 -05:00
|
|
|
*data = cv_data(cv);
|
2019-08-09 07:02:02 -04:00
|
|
|
numel = cv_len(cv) / (cv_class(cv)->elsz);
|
2008-12-27 01:02:53 -05:00
|
|
|
*index = toulong(ind, fname);
|
|
|
|
if (*index >= numel)
|
|
|
|
bounds_error(fname, arr, ind);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2008-12-27 01:02:53 -05:00
|
|
|
static value_t cvalue_array_aref(value_t *args)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 07:02:02 -04:00
|
|
|
char *data;
|
2019-08-09 14:00:03 -04:00
|
|
|
unsigned long index;
|
2019-08-09 12:36:20 -04:00
|
|
|
struct fltype *eltype = cv_class((struct cvalue *)ptr(args[0]))->eltype;
|
2010-08-04 15:03:19 -04:00
|
|
|
value_t el = 0;
|
2009-03-16 23:29:17 -04:00
|
|
|
numerictype_t nt = eltype->numtype;
|
2019-08-18 18:14:09 -04:00
|
|
|
char *dest;
|
|
|
|
size_t sz;
|
|
|
|
|
2009-03-16 23:29:17 -04:00
|
|
|
if (nt >= T_INT32)
|
|
|
|
el = cvalue(eltype, eltype->size);
|
2008-12-27 01:02:53 -05:00
|
|
|
check_addr_args("aref", args[0], args[1], &data, &index);
|
2009-03-16 23:29:17 -04:00
|
|
|
if (nt < T_INT32) {
|
|
|
|
if (nt == T_INT8)
|
|
|
|
return fixnum((int8_t)data[index]);
|
|
|
|
else if (nt == T_UINT8)
|
|
|
|
return fixnum((uint8_t)data[index]);
|
|
|
|
else if (nt == T_INT16)
|
2019-08-09 07:02:02 -04:00
|
|
|
return fixnum(((int16_t *)data)[index]);
|
|
|
|
return fixnum(((uint16_t *)data)[index]);
|
2009-03-16 23:29:17 -04:00
|
|
|
}
|
2019-08-18 18:14:09 -04:00
|
|
|
dest = cptr(el);
|
|
|
|
sz = eltype->size;
|
2008-12-27 01:02:53 -05:00
|
|
|
if (sz == 1)
|
|
|
|
*dest = data[index];
|
|
|
|
else if (sz == 2)
|
2019-08-09 07:02:02 -04:00
|
|
|
*(int16_t *)dest = ((int16_t *)data)[index];
|
2008-12-27 01:02:53 -05:00
|
|
|
else if (sz == 4)
|
2019-08-09 07:02:02 -04:00
|
|
|
*(int32_t *)dest = ((int32_t *)data)[index];
|
2008-12-27 01:02:53 -05:00
|
|
|
else if (sz == 8)
|
2019-08-09 07:02:02 -04:00
|
|
|
*(int64_t *)dest = ((int64_t *)data)[index];
|
2008-06-30 21:54:22 -04:00
|
|
|
else
|
2019-08-09 07:02:02 -04:00
|
|
|
memcpy(dest, data + index * sz, sz);
|
2008-12-27 01:02:53 -05:00
|
|
|
return el;
|
|
|
|
}
|
|
|
|
|
|
|
|
static value_t cvalue_array_aset(value_t *args)
|
|
|
|
{
|
2019-08-09 07:02:02 -04:00
|
|
|
char *data;
|
2019-08-18 18:14:09 -04:00
|
|
|
char *dest;
|
2019-08-09 14:00:03 -04:00
|
|
|
unsigned long index;
|
2019-08-18 18:14:09 -04:00
|
|
|
struct fltype *eltype;
|
|
|
|
|
|
|
|
eltype = cv_class((struct cvalue *)ptr(args[0]))->eltype;
|
2009-01-31 20:53:58 -05:00
|
|
|
check_addr_args("aset!", args[0], args[1], &data, &index);
|
2019-08-18 18:14:09 -04:00
|
|
|
dest = data + index * eltype->size;
|
2008-12-27 01:02:53 -05:00
|
|
|
cvalue_init(eltype, args[2], dest);
|
2008-06-30 21:54:22 -04:00
|
|
|
return args[2];
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
value_t fl_builtin(value_t *args, uint32_t nargs)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
struct symbol *name;
|
2019-08-09 12:36:20 -04:00
|
|
|
struct cvalue *cv;
|
2019-08-18 18:14:09 -04:00
|
|
|
|
|
|
|
argcount("builtin", nargs, 1);
|
|
|
|
name = tosymbol(args[0], "builtin");
|
2019-08-09 07:02:02 -04:00
|
|
|
if (ismanaged(args[0]) || (cv = name->dlcache) == NULL) {
|
2010-08-04 15:03:19 -04:00
|
|
|
lerrorf(ArgError, "builtin: function %s not found", name->name);
|
2008-12-21 00:55:00 -05:00
|
|
|
}
|
2009-04-28 00:10:18 -04:00
|
|
|
return tagptr(cv, TAG_CVALUE);
|
2008-12-21 00:55:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
value_t cbuiltin(char *name, builtin_t f)
|
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
struct cvalue *cv;
|
|
|
|
value_t sym;
|
|
|
|
|
|
|
|
cv = (struct cvalue *)malloc(CVALUE_NWORDS * sizeof(value_t));
|
2009-04-28 00:10:18 -04:00
|
|
|
cv->type = builtintype;
|
|
|
|
cv->data = &cv->_space[0];
|
|
|
|
cv->len = sizeof(value_t);
|
2019-08-09 07:02:02 -04:00
|
|
|
*(void **)cv->data = f;
|
2019-08-18 18:14:09 -04:00
|
|
|
sym = symbol(name);
|
2019-08-09 12:30:15 -04:00
|
|
|
((struct symbol *)ptr(sym))->dlcache = cv;
|
2019-08-09 07:02:02 -04:00
|
|
|
ptrhash_put(&reverse_dlsym_lookup_table, cv, (void *)sym);
|
2009-04-28 00:10:18 -04:00
|
|
|
return tagptr(cv, TAG_CVALUE);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
static value_t fl_logand(value_t *args, uint32_t nargs);
|
|
|
|
static value_t fl_logior(value_t *args, uint32_t nargs);
|
|
|
|
static value_t fl_logxor(value_t *args, uint32_t nargs);
|
|
|
|
static value_t fl_lognot(value_t *args, uint32_t nargs);
|
|
|
|
static value_t fl_ash(value_t *args, uint32_t nargs);
|
2009-03-24 22:28:21 -04:00
|
|
|
|
2019-08-09 12:20:18 -04:00
|
|
|
static struct builtinspec cvalues_builtin_info[] = {
|
|
|
|
{ "c-value", cvalue_new },
|
|
|
|
{ "typeof", cvalue_typeof },
|
|
|
|
{ "sizeof", cvalue_sizeof },
|
|
|
|
{ "builtin", fl_builtin },
|
|
|
|
{ "copy", fl_copy },
|
|
|
|
{ "plain-old-data?", fl_podp },
|
|
|
|
|
|
|
|
{ "logand", fl_logand },
|
|
|
|
{ "logior", fl_logior },
|
|
|
|
{ "logxor", fl_logxor },
|
|
|
|
{ "lognot", fl_lognot },
|
|
|
|
{ "ash", fl_ash },
|
|
|
|
// todo: autorelease
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
2009-02-23 23:12:33 -05:00
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
#define cv_intern(tok) tok##sym = symbol(#tok)
|
2008-12-21 00:55:00 -05:00
|
|
|
#define ctor_cv_intern(tok) \
|
2019-08-09 07:02:02 -04:00
|
|
|
cv_intern(tok); \
|
|
|
|
set(tok##sym, cbuiltin(#tok, cvalue_##tok))
|
2008-12-10 23:04:17 -05:00
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
#define mk_primtype(name) \
|
|
|
|
name##type = get_type(name##sym); \
|
|
|
|
name##type->init = &cvalue_##name##_init
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
#define mk_primtype_(name, ctype) \
|
|
|
|
name##type = get_type(name##sym); \
|
|
|
|
name##type->init = &cvalue_##ctype##_init
|
2009-03-04 22:48:17 -05:00
|
|
|
|
2013-06-08 19:29:15 -04:00
|
|
|
static void cvalues_init(void)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2008-12-10 23:04:17 -05:00
|
|
|
htable_new(&TypeTable, 256);
|
2008-12-21 00:55:00 -05:00
|
|
|
htable_new(&reverse_dlsym_lookup_table, 256);
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2008-12-10 23:04:17 -05:00
|
|
|
// compute struct field alignment required for primitives
|
2019-08-09 07:02:02 -04:00
|
|
|
ALIGN2 = sizeof(struct {
|
|
|
|
char a;
|
|
|
|
int16_t i;
|
|
|
|
}) -
|
|
|
|
2;
|
|
|
|
ALIGN4 = sizeof(struct {
|
|
|
|
char a;
|
|
|
|
int32_t i;
|
|
|
|
}) -
|
|
|
|
4;
|
|
|
|
ALIGN8 = sizeof(struct {
|
|
|
|
char a;
|
|
|
|
int64_t i;
|
|
|
|
}) -
|
|
|
|
8;
|
|
|
|
ALIGNPTR = sizeof(struct {
|
|
|
|
char a;
|
|
|
|
void *i;
|
|
|
|
}) -
|
|
|
|
sizeof(void *);
|
|
|
|
|
|
|
|
builtintype =
|
|
|
|
define_opaque_type(builtinsym, sizeof(builtin_t), NULL, NULL);
|
2008-06-30 21:54:22 -04:00
|
|
|
|
|
|
|
ctor_cv_intern(int8);
|
|
|
|
ctor_cv_intern(uint8);
|
|
|
|
ctor_cv_intern(int16);
|
|
|
|
ctor_cv_intern(uint16);
|
|
|
|
ctor_cv_intern(int32);
|
2008-12-10 23:04:17 -05:00
|
|
|
ctor_cv_intern(uint32);
|
2008-06-30 21:54:22 -04:00
|
|
|
ctor_cv_intern(int64);
|
|
|
|
ctor_cv_intern(uint64);
|
2008-12-23 23:43:36 -05:00
|
|
|
ctor_cv_intern(byte);
|
2008-06-30 21:54:22 -04:00
|
|
|
ctor_cv_intern(wchar);
|
|
|
|
ctor_cv_intern(long);
|
|
|
|
ctor_cv_intern(ulong);
|
|
|
|
ctor_cv_intern(float);
|
|
|
|
ctor_cv_intern(double);
|
|
|
|
|
|
|
|
ctor_cv_intern(array);
|
|
|
|
ctor_cv_intern(enum);
|
2009-08-12 00:56:32 -04:00
|
|
|
cv_intern(pointer);
|
2008-06-30 21:54:22 -04:00
|
|
|
cv_intern(struct);
|
|
|
|
cv_intern(union);
|
|
|
|
cv_intern(void);
|
2009-08-12 00:56:32 -04:00
|
|
|
cfunctionsym = symbol("c-function");
|
2008-12-10 23:04:17 -05:00
|
|
|
|
2009-02-23 23:12:33 -05:00
|
|
|
assign_global_builtins(cvalues_builtin_info);
|
2008-06-30 21:54:22 -04:00
|
|
|
|
|
|
|
stringtypesym = symbol("*string-type*");
|
2010-04-29 14:01:26 -04:00
|
|
|
setc(stringtypesym, fl_list2(arraysym, bytesym));
|
2008-06-30 21:54:22 -04:00
|
|
|
|
|
|
|
wcstringtypesym = symbol("*wcstring-type*");
|
2010-04-29 14:01:26 -04:00
|
|
|
setc(wcstringtypesym, fl_list2(arraysym, wcharsym));
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2009-01-04 21:45:21 -05:00
|
|
|
mk_primtype(int8);
|
|
|
|
mk_primtype(uint8);
|
|
|
|
mk_primtype(int16);
|
|
|
|
mk_primtype(uint16);
|
|
|
|
mk_primtype(int32);
|
|
|
|
mk_primtype(uint32);
|
|
|
|
mk_primtype(int64);
|
|
|
|
mk_primtype(uint64);
|
2009-03-04 22:48:17 -05:00
|
|
|
#ifdef BITS64
|
2019-08-09 07:02:02 -04:00
|
|
|
mk_primtype_(long, int64);
|
|
|
|
mk_primtype_(ulong, uint64);
|
2009-03-04 22:48:17 -05:00
|
|
|
#else
|
2019-08-09 07:02:02 -04:00
|
|
|
mk_primtype_(long, int32);
|
|
|
|
mk_primtype_(ulong, uint32);
|
2009-03-04 22:48:17 -05:00
|
|
|
#endif
|
2019-08-09 07:02:02 -04:00
|
|
|
mk_primtype_(byte, uint8);
|
|
|
|
mk_primtype_(wchar, int32);
|
2009-01-04 21:45:21 -05:00
|
|
|
mk_primtype(float);
|
|
|
|
mk_primtype(double);
|
|
|
|
|
|
|
|
stringtype = get_type(symbol_value(stringtypesym));
|
|
|
|
wcstringtype = get_type(symbol_value(wcstringtypesym));
|
2008-12-10 23:04:17 -05:00
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
emptystringsym = symbol("*empty-string*");
|
2008-09-10 22:37:38 -04:00
|
|
|
setc(emptystringsym, cvalue_static_cstring(""));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
#define RETURN_NUM_AS(var, type) return (mk_##type((type##_t)var))
|
2008-06-30 21:54:22 -04:00
|
|
|
|
|
|
|
value_t return_from_uint64(uint64_t Uaccum)
|
|
|
|
{
|
|
|
|
if (fits_fixnum(Uaccum)) {
|
|
|
|
return fixnum((fixnum_t)Uaccum);
|
|
|
|
}
|
|
|
|
if (Uaccum > (uint64_t)S64_MAX) {
|
|
|
|
RETURN_NUM_AS(Uaccum, uint64);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (Uaccum > (uint64_t)UINT_MAX) {
|
2008-06-30 21:54:22 -04:00
|
|
|
RETURN_NUM_AS(Uaccum, int64);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (Uaccum > (uint64_t)INT_MAX) {
|
2008-06-30 21:54:22 -04:00
|
|
|
RETURN_NUM_AS(Uaccum, uint32);
|
|
|
|
}
|
|
|
|
RETURN_NUM_AS(Uaccum, int32);
|
|
|
|
}
|
|
|
|
|
|
|
|
value_t return_from_int64(int64_t Saccum)
|
|
|
|
{
|
|
|
|
if (fits_fixnum(Saccum)) {
|
|
|
|
return fixnum((fixnum_t)Saccum);
|
|
|
|
}
|
|
|
|
if (Saccum > (int64_t)UINT_MAX || Saccum < (int64_t)INT_MIN) {
|
|
|
|
RETURN_NUM_AS(Saccum, int64);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (Saccum > (int64_t)INT_MAX) {
|
2008-06-30 21:54:22 -04:00
|
|
|
RETURN_NUM_AS(Saccum, uint32);
|
|
|
|
}
|
|
|
|
RETURN_NUM_AS(Saccum, int32);
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
static value_t fl_add_any(value_t *args, uint32_t nargs, fixnum_t carryIn)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 07:02:02 -04:00
|
|
|
uint64_t Uaccum = 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
int64_t Saccum = carryIn;
|
2019-08-09 07:02:02 -04:00
|
|
|
double Faccum = 0;
|
2017-08-09 14:21:29 -04:00
|
|
|
int32_t inexact = 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
uint32_t i;
|
2019-08-09 07:02:02 -04:00
|
|
|
value_t arg = NIL;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
FOR_ARGS(i, 0, arg, args)
|
|
|
|
{
|
2009-03-26 23:06:55 -04:00
|
|
|
if (isfixnum(arg)) {
|
|
|
|
Saccum += numval(arg);
|
2008-06-30 21:54:22 -04:00
|
|
|
continue;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (iscprim(arg)) {
|
2019-08-09 12:25:43 -04:00
|
|
|
struct cprim *cp = (struct cprim *)ptr(arg);
|
2009-01-02 18:00:21 -05:00
|
|
|
void *a = cp_data(cp);
|
2008-06-30 21:54:22 -04:00
|
|
|
int64_t i64;
|
2019-08-09 07:02:02 -04:00
|
|
|
switch (cp_numtype(cp)) {
|
|
|
|
case T_INT8:
|
|
|
|
Saccum += *(int8_t *)a;
|
|
|
|
break;
|
|
|
|
case T_UINT8:
|
|
|
|
Saccum += *(uint8_t *)a;
|
|
|
|
break;
|
|
|
|
case T_INT16:
|
|
|
|
Saccum += *(int16_t *)a;
|
|
|
|
break;
|
|
|
|
case T_UINT16:
|
|
|
|
Saccum += *(uint16_t *)a;
|
|
|
|
break;
|
|
|
|
case T_INT32:
|
|
|
|
Saccum += *(int32_t *)a;
|
|
|
|
break;
|
|
|
|
case T_UINT32:
|
|
|
|
Saccum += *(uint32_t *)a;
|
|
|
|
break;
|
2008-06-30 21:54:22 -04:00
|
|
|
case T_INT64:
|
2019-08-09 07:02:02 -04:00
|
|
|
i64 = *(int64_t *)a;
|
2008-06-30 21:54:22 -04:00
|
|
|
if (i64 > 0)
|
|
|
|
Uaccum += (uint64_t)i64;
|
|
|
|
else
|
|
|
|
Saccum += i64;
|
|
|
|
break;
|
2019-08-09 07:02:02 -04:00
|
|
|
case T_UINT64:
|
|
|
|
Uaccum += *(uint64_t *)a;
|
|
|
|
break;
|
|
|
|
case T_FLOAT:
|
|
|
|
Faccum += *(float *)a;
|
|
|
|
inexact = 1;
|
|
|
|
break;
|
|
|
|
case T_DOUBLE:
|
|
|
|
Faccum += *(double *)a;
|
|
|
|
inexact = 1;
|
|
|
|
break;
|
2008-06-30 21:54:22 -04:00
|
|
|
default:
|
|
|
|
goto add_type_error;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
add_type_error:
|
2009-03-26 23:06:55 -04:00
|
|
|
type_error("+", "number", arg);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2017-08-09 14:21:29 -04:00
|
|
|
if (inexact) {
|
2008-06-30 21:54:22 -04:00
|
|
|
Faccum += Uaccum;
|
|
|
|
Faccum += Saccum;
|
|
|
|
return mk_double(Faccum);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (Saccum < 0) {
|
2008-06-30 21:54:22 -04:00
|
|
|
uint64_t negpart = (uint64_t)(-Saccum);
|
|
|
|
if (negpart > Uaccum) {
|
|
|
|
Saccum += (int64_t)Uaccum;
|
|
|
|
// return value in Saccum
|
|
|
|
if (Saccum >= INT_MIN) {
|
|
|
|
if (fits_fixnum(Saccum)) {
|
|
|
|
return fixnum((fixnum_t)Saccum);
|
|
|
|
}
|
|
|
|
RETURN_NUM_AS(Saccum, int32);
|
|
|
|
}
|
|
|
|
RETURN_NUM_AS(Saccum, int64);
|
|
|
|
}
|
|
|
|
Uaccum -= negpart;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2008-06-30 21:54:22 -04:00
|
|
|
Uaccum += (uint64_t)Saccum;
|
|
|
|
}
|
|
|
|
// return value in Uaccum
|
|
|
|
return return_from_uint64(Uaccum);
|
|
|
|
}
|
|
|
|
|
2009-03-11 15:16:40 -04:00
|
|
|
static value_t fl_neg(value_t n)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
|
|
|
if (isfixnum(n)) {
|
2016-11-15 17:49:18 -05:00
|
|
|
fixnum_t s = fixnum(-numval(n));
|
2019-08-09 12:53:35 -04:00
|
|
|
if (__unlikely(n == (ufixnum_t)s))
|
2019-08-09 07:02:02 -04:00
|
|
|
return mk_long(-numval(n)); // negate overflows
|
2016-11-15 17:49:18 -05:00
|
|
|
else
|
|
|
|
return s;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (iscprim(n)) {
|
2019-08-09 12:25:43 -04:00
|
|
|
struct cprim *cp = (struct cprim *)ptr(n);
|
2009-01-02 18:00:21 -05:00
|
|
|
void *a = cp_data(cp);
|
2008-06-30 21:54:22 -04:00
|
|
|
uint32_t ui32;
|
|
|
|
int32_t i32;
|
|
|
|
int64_t i64;
|
2019-08-09 07:02:02 -04:00
|
|
|
switch (cp_numtype(cp)) {
|
|
|
|
case T_INT8:
|
|
|
|
return fixnum(-(int32_t) * (int8_t *)a);
|
|
|
|
case T_UINT8:
|
|
|
|
return fixnum(-(int32_t) * (uint8_t *)a);
|
|
|
|
case T_INT16:
|
|
|
|
return fixnum(-(int32_t) * (int16_t *)a);
|
|
|
|
case T_UINT16:
|
|
|
|
return fixnum(-(int32_t) * (uint16_t *)a);
|
2008-06-30 21:54:22 -04:00
|
|
|
case T_INT32:
|
2019-08-09 07:02:02 -04:00
|
|
|
i32 = *(int32_t *)a;
|
2019-10-13 18:22:56 -04:00
|
|
|
if (i32 == (int32_t)INT32_TOP_BIT)
|
|
|
|
return mk_uint32((uint32_t)INT32_TOP_BIT);
|
2008-06-30 21:54:22 -04:00
|
|
|
return mk_int32(-i32);
|
|
|
|
case T_UINT32:
|
2019-08-09 07:02:02 -04:00
|
|
|
ui32 = *(uint32_t *)a;
|
|
|
|
if (ui32 <= ((uint32_t)INT_MAX) + 1)
|
|
|
|
return mk_int32(-(int32_t)ui32);
|
2008-06-30 21:54:22 -04:00
|
|
|
return mk_int64(-(int64_t)ui32);
|
|
|
|
case T_INT64:
|
2019-08-09 07:02:02 -04:00
|
|
|
i64 = *(int64_t *)a;
|
2019-10-13 18:22:56 -04:00
|
|
|
if (i64 == (int64_t)INT64_TOP_BIT)
|
|
|
|
return mk_uint64((uint64_t)INT64_TOP_BIT);
|
2008-06-30 21:54:22 -04:00
|
|
|
return mk_int64(-i64);
|
2019-08-09 07:02:02 -04:00
|
|
|
case T_UINT64:
|
|
|
|
return mk_int64(-(int64_t) * (uint64_t *)a);
|
|
|
|
case T_FLOAT:
|
|
|
|
return mk_float(-*(float *)a);
|
|
|
|
case T_DOUBLE:
|
|
|
|
return mk_double(-*(double *)a);
|
2008-06-30 21:54:22 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
type_error("-", "number", n);
|
2019-08-18 18:14:09 -04:00
|
|
|
return FL_NIL; // TODO: remove
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
static value_t fl_mul_any(value_t *args, uint32_t nargs, int64_t Saccum)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 07:02:02 -04:00
|
|
|
uint64_t Uaccum = 1;
|
|
|
|
double Faccum = 1;
|
2017-08-09 14:21:29 -04:00
|
|
|
int32_t inexact = 0;
|
2008-06-30 21:54:22 -04:00
|
|
|
uint32_t i;
|
2019-08-09 07:02:02 -04:00
|
|
|
value_t arg = NIL;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
FOR_ARGS(i, 0, arg, args)
|
|
|
|
{
|
2009-03-26 23:06:55 -04:00
|
|
|
if (isfixnum(arg)) {
|
|
|
|
Saccum *= numval(arg);
|
2008-06-30 21:54:22 -04:00
|
|
|
continue;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (iscprim(arg)) {
|
2019-08-09 12:25:43 -04:00
|
|
|
struct cprim *cp = (struct cprim *)ptr(arg);
|
2009-01-02 18:00:21 -05:00
|
|
|
void *a = cp_data(cp);
|
2008-06-30 21:54:22 -04:00
|
|
|
int64_t i64;
|
2019-08-09 07:02:02 -04:00
|
|
|
switch (cp_numtype(cp)) {
|
|
|
|
case T_INT8:
|
|
|
|
Saccum *= *(int8_t *)a;
|
|
|
|
break;
|
|
|
|
case T_UINT8:
|
|
|
|
Saccum *= *(uint8_t *)a;
|
|
|
|
break;
|
|
|
|
case T_INT16:
|
|
|
|
Saccum *= *(int16_t *)a;
|
|
|
|
break;
|
|
|
|
case T_UINT16:
|
|
|
|
Saccum *= *(uint16_t *)a;
|
|
|
|
break;
|
|
|
|
case T_INT32:
|
|
|
|
Saccum *= *(int32_t *)a;
|
|
|
|
break;
|
|
|
|
case T_UINT32:
|
|
|
|
Saccum *= *(uint32_t *)a;
|
|
|
|
break;
|
2008-06-30 21:54:22 -04:00
|
|
|
case T_INT64:
|
2019-08-09 07:02:02 -04:00
|
|
|
i64 = *(int64_t *)a;
|
2008-06-30 21:54:22 -04:00
|
|
|
if (i64 > 0)
|
|
|
|
Uaccum *= (uint64_t)i64;
|
|
|
|
else
|
|
|
|
Saccum *= i64;
|
|
|
|
break;
|
2019-08-09 07:02:02 -04:00
|
|
|
case T_UINT64:
|
|
|
|
Uaccum *= *(uint64_t *)a;
|
|
|
|
break;
|
|
|
|
case T_FLOAT:
|
|
|
|
Faccum *= *(float *)a;
|
|
|
|
inexact = 1;
|
|
|
|
break;
|
|
|
|
case T_DOUBLE:
|
|
|
|
Faccum *= *(double *)a;
|
|
|
|
inexact = 1;
|
|
|
|
break;
|
2008-06-30 21:54:22 -04:00
|
|
|
default:
|
|
|
|
goto mul_type_error;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
mul_type_error:
|
2009-03-26 23:06:55 -04:00
|
|
|
type_error("*", "number", arg);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2017-08-09 14:21:29 -04:00
|
|
|
if (inexact) {
|
2008-06-30 21:54:22 -04:00
|
|
|
Faccum *= Uaccum;
|
|
|
|
Faccum *= Saccum;
|
|
|
|
return mk_double(Faccum);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (Saccum < 0) {
|
2008-06-30 21:54:22 -04:00
|
|
|
Saccum *= (int64_t)Uaccum;
|
|
|
|
if (Saccum >= INT_MIN) {
|
|
|
|
if (fits_fixnum(Saccum)) {
|
|
|
|
return fixnum((fixnum_t)Saccum);
|
|
|
|
}
|
|
|
|
RETURN_NUM_AS(Saccum, int32);
|
|
|
|
}
|
|
|
|
RETURN_NUM_AS(Saccum, int64);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2008-06-30 21:54:22 -04:00
|
|
|
Uaccum *= (uint64_t)Saccum;
|
|
|
|
}
|
|
|
|
return return_from_uint64(Uaccum);
|
|
|
|
}
|
|
|
|
|
2009-04-15 23:05:38 -04:00
|
|
|
static int num_to_ptr(value_t a, fixnum_t *pi, numerictype_t *pt, void **pp)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 12:25:43 -04:00
|
|
|
struct cprim *cp;
|
2008-06-30 21:54:22 -04:00
|
|
|
if (isfixnum(a)) {
|
2009-04-15 23:05:38 -04:00
|
|
|
*pi = numval(a);
|
|
|
|
*pp = pi;
|
|
|
|
*pt = T_FIXNUM;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else if (iscprim(a)) {
|
2019-08-09 12:25:43 -04:00
|
|
|
cp = (struct cprim *)ptr(a);
|
2009-04-15 23:05:38 -04:00
|
|
|
*pp = cp_data(cp);
|
|
|
|
*pt = cp_numtype(cp);
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2009-04-15 23:05:38 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
returns -1, 0, or 1 based on ordering of a and b
|
|
|
|
eq: consider equality only, returning 0 or nonzero
|
|
|
|
eqnans: NaNs considered equal to each other
|
2009-05-13 21:30:25 -04:00
|
|
|
-0.0 not considered equal to 0.0
|
|
|
|
inexact not considered equal to exact
|
2009-04-15 23:05:38 -04:00
|
|
|
fname: if not NULL, throws type errors, else returns 2 for type errors
|
|
|
|
*/
|
|
|
|
int numeric_compare(value_t a, value_t b, int eq, int eqnans, char *fname)
|
|
|
|
{
|
2019-08-09 14:04:19 -04:00
|
|
|
intptr_t ai, bi;
|
2009-04-15 23:05:38 -04:00
|
|
|
numerictype_t ta, tb;
|
|
|
|
void *aptr, *bptr;
|
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
if (bothfixnums(a, b)) {
|
|
|
|
if (a == b)
|
|
|
|
return 0;
|
|
|
|
if (numval(a) < numval(b))
|
|
|
|
return -1;
|
2009-04-15 23:05:38 -04:00
|
|
|
return 1;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2009-04-15 23:05:38 -04:00
|
|
|
if (!num_to_ptr(a, &ai, &ta, &aptr)) {
|
2019-08-09 07:02:02 -04:00
|
|
|
if (fname)
|
|
|
|
type_error(fname, "number", a);
|
|
|
|
else
|
|
|
|
return 2;
|
2009-04-15 23:05:38 -04:00
|
|
|
}
|
|
|
|
if (!num_to_ptr(b, &bi, &tb, &bptr)) {
|
2019-08-09 07:02:02 -04:00
|
|
|
if (fname)
|
|
|
|
type_error(fname, "number", b);
|
|
|
|
else
|
|
|
|
return 2;
|
2009-04-15 23:05:38 -04:00
|
|
|
}
|
2009-05-13 21:30:25 -04:00
|
|
|
if (eq && eqnans && ((ta >= T_FLOAT) != (tb >= T_FLOAT)))
|
|
|
|
return 1;
|
2009-04-15 23:05:38 -04:00
|
|
|
if (cmp_eq(aptr, ta, bptr, tb, eqnans))
|
|
|
|
return 0;
|
2019-08-09 07:02:02 -04:00
|
|
|
if (eq)
|
|
|
|
return 1;
|
2009-04-15 23:05:38 -04:00
|
|
|
if (cmp_lt(aptr, ta, bptr, tb))
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static value_t fl_div2(value_t a, value_t b)
|
|
|
|
{
|
|
|
|
double da, db;
|
2019-08-09 14:04:19 -04:00
|
|
|
intptr_t ai, bi;
|
2009-04-15 23:05:38 -04:00
|
|
|
numerictype_t ta, tb;
|
|
|
|
void *aptr, *bptr;
|
|
|
|
|
|
|
|
if (!num_to_ptr(a, &ai, &ta, &aptr))
|
2008-06-30 21:54:22 -04:00
|
|
|
type_error("/", "number", a);
|
2009-04-15 23:05:38 -04:00
|
|
|
if (!num_to_ptr(b, &bi, &tb, &bptr))
|
2008-06-30 21:54:22 -04:00
|
|
|
type_error("/", "number", b);
|
|
|
|
|
2009-05-13 21:30:25 -04:00
|
|
|
da = conv_to_double(aptr, ta);
|
|
|
|
db = conv_to_double(bptr, tb);
|
|
|
|
|
|
|
|
if (db == 0 && tb < T_FLOAT) // exact 0
|
2009-05-13 22:53:04 -04:00
|
|
|
DivideByZeroError();
|
2009-05-13 21:30:25 -04:00
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
da = da / db;
|
2009-05-13 21:30:25 -04:00
|
|
|
|
|
|
|
if (ta < T_FLOAT && tb < T_FLOAT && (double)(int64_t)da == da)
|
|
|
|
return return_from_int64((int64_t)da);
|
|
|
|
return mk_double(da);
|
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
|
2009-05-13 21:30:25 -04:00
|
|
|
static value_t fl_idiv2(value_t a, value_t b)
|
|
|
|
{
|
2019-08-09 14:04:19 -04:00
|
|
|
intptr_t ai, bi;
|
2009-05-13 21:30:25 -04:00
|
|
|
numerictype_t ta, tb;
|
|
|
|
void *aptr, *bptr;
|
2008-06-30 21:54:22 -04:00
|
|
|
int64_t a64, b64;
|
|
|
|
|
2009-05-13 21:30:25 -04:00
|
|
|
if (!num_to_ptr(a, &ai, &ta, &aptr))
|
2009-05-14 13:54:59 -04:00
|
|
|
type_error("div0", "number", a);
|
2009-05-13 21:30:25 -04:00
|
|
|
if (!num_to_ptr(b, &bi, &tb, &bptr))
|
2009-05-14 13:54:59 -04:00
|
|
|
type_error("div0", "number", b);
|
2009-05-13 21:30:25 -04:00
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
if (ta == T_UINT64) {
|
|
|
|
if (tb == T_UINT64) {
|
2019-08-09 07:02:02 -04:00
|
|
|
if (*(uint64_t *)bptr == 0)
|
|
|
|
goto div_error;
|
|
|
|
return return_from_uint64(*(uint64_t *)aptr / *(uint64_t *)bptr);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
b64 = conv_to_int64(bptr, tb);
|
|
|
|
if (b64 < 0) {
|
2019-08-09 07:02:02 -04:00
|
|
|
return return_from_int64(
|
|
|
|
-(int64_t)(*(uint64_t *)aptr / (uint64_t)(-b64)));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
if (b64 == 0)
|
|
|
|
goto div_error;
|
2019-08-09 07:02:02 -04:00
|
|
|
return return_from_uint64(*(uint64_t *)aptr / (uint64_t)b64);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
if (tb == T_UINT64) {
|
2019-08-09 07:02:02 -04:00
|
|
|
if (*(uint64_t *)bptr == 0)
|
|
|
|
goto div_error;
|
2008-06-30 21:54:22 -04:00
|
|
|
a64 = conv_to_int64(aptr, ta);
|
|
|
|
if (a64 < 0) {
|
2019-08-09 07:02:02 -04:00
|
|
|
return return_from_int64(
|
|
|
|
-((int64_t)((uint64_t)(-a64) / *(uint64_t *)bptr)));
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
2019-08-09 07:02:02 -04:00
|
|
|
return return_from_uint64((uint64_t)a64 / *(uint64_t *)bptr);
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
b64 = conv_to_int64(bptr, tb);
|
2019-08-09 07:02:02 -04:00
|
|
|
if (b64 == 0)
|
|
|
|
goto div_error;
|
2008-06-30 21:54:22 -04:00
|
|
|
|
|
|
|
return return_from_int64(conv_to_int64(aptr, ta) / b64);
|
2019-08-09 07:02:02 -04:00
|
|
|
div_error:
|
2009-05-13 22:53:04 -04:00
|
|
|
DivideByZeroError();
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
|
2009-03-11 15:16:40 -04:00
|
|
|
static value_t fl_bitwise_op(value_t a, value_t b, int opcode, char *fname)
|
2008-06-30 21:54:22 -04:00
|
|
|
{
|
2019-08-09 14:04:19 -04:00
|
|
|
intptr_t ai, bi;
|
2009-04-15 23:05:38 -04:00
|
|
|
numerictype_t ta, tb, itmp;
|
2019-08-09 07:02:02 -04:00
|
|
|
void *aptr = NULL, *bptr = NULL, *ptmp;
|
2008-06-30 21:54:22 -04:00
|
|
|
int64_t b64;
|
|
|
|
|
2009-04-15 23:05:38 -04:00
|
|
|
if (!num_to_ptr(a, &ai, &ta, &aptr) || ta >= T_FLOAT)
|
|
|
|
type_error(fname, "integer", a);
|
|
|
|
if (!num_to_ptr(b, &bi, &tb, &bptr) || tb >= T_FLOAT)
|
|
|
|
type_error(fname, "integer", b);
|
|
|
|
|
2008-06-30 21:54:22 -04:00
|
|
|
if (ta < tb) {
|
2019-08-09 07:02:02 -04:00
|
|
|
itmp = ta;
|
|
|
|
ta = tb;
|
|
|
|
tb = itmp;
|
|
|
|
ptmp = aptr;
|
|
|
|
aptr = bptr;
|
|
|
|
bptr = ptmp;
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
// now a's type is larger than or same as b's
|
|
|
|
b64 = conv_to_int64(bptr, tb);
|
|
|
|
switch (opcode) {
|
|
|
|
case 0:
|
2019-08-09 07:02:02 -04:00
|
|
|
switch (ta) {
|
|
|
|
case T_INT8:
|
|
|
|
return fixnum(*(int8_t *)aptr & (int8_t)b64);
|
|
|
|
case T_UINT8:
|
|
|
|
return fixnum(*(uint8_t *)aptr & (uint8_t)b64);
|
|
|
|
case T_INT16:
|
|
|
|
return fixnum(*(int16_t *)aptr & (int16_t)b64);
|
|
|
|
case T_UINT16:
|
|
|
|
return fixnum(*(uint16_t *)aptr & (uint16_t)b64);
|
|
|
|
case T_INT32:
|
|
|
|
return mk_int32(*(int32_t *)aptr & (int32_t)b64);
|
|
|
|
case T_UINT32:
|
|
|
|
return mk_uint32(*(uint32_t *)aptr & (uint32_t)b64);
|
|
|
|
case T_INT64:
|
|
|
|
return mk_int64(*(int64_t *)aptr & (int64_t)b64);
|
|
|
|
case T_UINT64:
|
|
|
|
return mk_uint64(*(uint64_t *)aptr & (uint64_t)b64);
|
|
|
|
case T_FLOAT:
|
|
|
|
case T_DOUBLE:
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
break;
|
2008-06-30 21:54:22 -04:00
|
|
|
case 1:
|
2019-08-09 07:02:02 -04:00
|
|
|
switch (ta) {
|
|
|
|
case T_INT8:
|
|
|
|
return fixnum(*(int8_t *)aptr | (int8_t)b64);
|
|
|
|
case T_UINT8:
|
|
|
|
return fixnum(*(uint8_t *)aptr | (uint8_t)b64);
|
|
|
|
case T_INT16:
|
|
|
|
return fixnum(*(int16_t *)aptr | (int16_t)b64);
|
|
|
|
case T_UINT16:
|
|
|
|
return fixnum(*(uint16_t *)aptr | (uint16_t)b64);
|
|
|
|
case T_INT32:
|
|
|
|
return mk_int32(*(int32_t *)aptr | (int32_t)b64);
|
|
|
|
case T_UINT32:
|
|
|
|
return mk_uint32(*(uint32_t *)aptr | (uint32_t)b64);
|
|
|
|
case T_INT64:
|
|
|
|
return mk_int64(*(int64_t *)aptr | (int64_t)b64);
|
|
|
|
case T_UINT64:
|
|
|
|
return mk_uint64(*(uint64_t *)aptr | (uint64_t)b64);
|
|
|
|
case T_FLOAT:
|
|
|
|
case T_DOUBLE:
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
break;
|
2008-06-30 21:54:22 -04:00
|
|
|
case 2:
|
2019-08-09 07:02:02 -04:00
|
|
|
switch (ta) {
|
|
|
|
case T_INT8:
|
|
|
|
return fixnum(*(int8_t *)aptr ^ (int8_t)b64);
|
|
|
|
case T_UINT8:
|
|
|
|
return fixnum(*(uint8_t *)aptr ^ (uint8_t)b64);
|
|
|
|
case T_INT16:
|
|
|
|
return fixnum(*(int16_t *)aptr ^ (int16_t)b64);
|
|
|
|
case T_UINT16:
|
|
|
|
return fixnum(*(uint16_t *)aptr ^ (uint16_t)b64);
|
|
|
|
case T_INT32:
|
|
|
|
return mk_int32(*(int32_t *)aptr ^ (int32_t)b64);
|
|
|
|
case T_UINT32:
|
|
|
|
return mk_uint32(*(uint32_t *)aptr ^ (uint32_t)b64);
|
|
|
|
case T_INT64:
|
|
|
|
return mk_int64(*(int64_t *)aptr ^ (int64_t)b64);
|
|
|
|
case T_UINT64:
|
|
|
|
return mk_uint64(*(uint64_t *)aptr ^ (uint64_t)b64);
|
|
|
|
case T_FLOAT:
|
|
|
|
case T_DOUBLE:
|
|
|
|
assert(0);
|
|
|
|
}
|
2008-06-30 21:54:22 -04:00
|
|
|
}
|
|
|
|
assert(0);
|
|
|
|
return NIL;
|
|
|
|
}
|
2009-03-24 22:28:21 -04:00
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
static value_t fl_logand(value_t *args, uint32_t nargs)
|
2009-03-24 22:28:21 -04:00
|
|
|
{
|
|
|
|
value_t v, e;
|
|
|
|
int i;
|
|
|
|
if (nargs == 0)
|
|
|
|
return fixnum(-1);
|
|
|
|
v = args[0];
|
2019-08-09 07:02:02 -04:00
|
|
|
FOR_ARGS(i, 1, e, args)
|
|
|
|
{
|
2009-03-24 22:28:21 -04:00
|
|
|
if (bothfixnums(v, e))
|
|
|
|
v = v & e;
|
|
|
|
else
|
|
|
|
v = fl_bitwise_op(v, e, 0, "logand");
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
static value_t fl_logior(value_t *args, uint32_t nargs)
|
2009-03-24 22:28:21 -04:00
|
|
|
{
|
|
|
|
value_t v, e;
|
|
|
|
int i;
|
|
|
|
if (nargs == 0)
|
|
|
|
return fixnum(0);
|
|
|
|
v = args[0];
|
2019-08-09 07:02:02 -04:00
|
|
|
FOR_ARGS(i, 1, e, args)
|
|
|
|
{
|
2009-03-24 22:28:21 -04:00
|
|
|
if (bothfixnums(v, e))
|
|
|
|
v = v | e;
|
|
|
|
else
|
|
|
|
v = fl_bitwise_op(v, e, 1, "logior");
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
static value_t fl_logxor(value_t *args, uint32_t nargs)
|
2009-03-24 22:28:21 -04:00
|
|
|
{
|
|
|
|
value_t v, e;
|
|
|
|
int i;
|
|
|
|
if (nargs == 0)
|
|
|
|
return fixnum(0);
|
|
|
|
v = args[0];
|
2019-08-09 07:02:02 -04:00
|
|
|
FOR_ARGS(i, 1, e, args)
|
|
|
|
{
|
2009-03-24 22:28:21 -04:00
|
|
|
if (bothfixnums(v, e))
|
|
|
|
v = fixnum(numval(v) ^ numval(e));
|
|
|
|
else
|
|
|
|
v = fl_bitwise_op(v, e, 2, "logxor");
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
static value_t fl_lognot(value_t *args, uint32_t nargs)
|
2009-04-01 23:53:38 -04:00
|
|
|
{
|
2019-08-09 12:25:43 -04:00
|
|
|
struct cprim *cp;
|
2009-04-01 23:53:38 -04:00
|
|
|
void *aptr;
|
2019-08-18 18:14:09 -04:00
|
|
|
value_t a;
|
|
|
|
int ta;
|
2009-04-01 23:53:38 -04:00
|
|
|
|
2019-08-18 18:14:09 -04:00
|
|
|
argcount("lognot", nargs, 1);
|
|
|
|
a = args[0];
|
|
|
|
if (isfixnum(a))
|
|
|
|
return fixnum(~numval(a));
|
2009-04-01 23:53:38 -04:00
|
|
|
if (iscprim(a)) {
|
2019-08-09 12:25:43 -04:00
|
|
|
cp = (struct cprim *)ptr(a);
|
2009-04-01 23:53:38 -04:00
|
|
|
ta = cp_numtype(cp);
|
|
|
|
aptr = cp_data(cp);
|
|
|
|
switch (ta) {
|
2019-08-09 07:02:02 -04:00
|
|
|
case T_INT8:
|
|
|
|
return fixnum(~*(int8_t *)aptr);
|
|
|
|
case T_UINT8:
|
|
|
|
return fixnum(~*(uint8_t *)aptr);
|
|
|
|
case T_INT16:
|
|
|
|
return fixnum(~*(int16_t *)aptr);
|
|
|
|
case T_UINT16:
|
|
|
|
return fixnum(~*(uint16_t *)aptr);
|
|
|
|
case T_INT32:
|
|
|
|
return mk_int32(~*(int32_t *)aptr);
|
|
|
|
case T_UINT32:
|
|
|
|
return mk_uint32(~*(uint32_t *)aptr);
|
|
|
|
case T_INT64:
|
|
|
|
return mk_int64(~*(int64_t *)aptr);
|
|
|
|
case T_UINT64:
|
|
|
|
return mk_uint64(~*(uint64_t *)aptr);
|
2009-04-01 23:53:38 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
type_error("lognot", "integer", a);
|
2019-08-18 18:14:09 -04:00
|
|
|
return FL_NIL; // TODO: remove
|
2009-04-01 23:53:38 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 14:00:03 -04:00
|
|
|
static value_t fl_ash(value_t *args, uint32_t nargs)
|
2009-03-24 22:28:21 -04:00
|
|
|
{
|
2019-08-18 18:14:09 -04:00
|
|
|
int64_t accum, i64;
|
|
|
|
value_t a;
|
2009-03-24 22:28:21 -04:00
|
|
|
fixnum_t n;
|
2019-08-18 18:14:09 -04:00
|
|
|
struct cprim *cp;
|
|
|
|
void *aptr;
|
|
|
|
int ta;
|
|
|
|
|
2009-03-24 22:28:21 -04:00
|
|
|
argcount("ash", nargs, 2);
|
2019-08-18 18:14:09 -04:00
|
|
|
a = args[0];
|
2009-03-24 22:28:21 -04:00
|
|
|
n = tofixnum(args[1], "ash");
|
|
|
|
if (isfixnum(a)) {
|
|
|
|
if (n <= 0)
|
2019-08-09 07:02:02 -04:00
|
|
|
return fixnum(numval(a) >> (-n));
|
|
|
|
accum = ((int64_t)numval(a)) << n;
|
2009-03-24 22:28:21 -04:00
|
|
|
if (fits_fixnum(accum))
|
|
|
|
return fixnum(accum);
|
|
|
|
else
|
|
|
|
return return_from_int64(accum);
|
|
|
|
}
|
|
|
|
if (iscprim(a)) {
|
2019-08-09 07:02:02 -04:00
|
|
|
if (n == 0)
|
|
|
|
return a;
|
2019-08-09 12:25:43 -04:00
|
|
|
cp = (struct cprim *)ptr(a);
|
2009-03-24 22:28:21 -04:00
|
|
|
ta = cp_numtype(cp);
|
|
|
|
aptr = cp_data(cp);
|
|
|
|
if (n < 0) {
|
|
|
|
n = -n;
|
|
|
|
switch (ta) {
|
2019-08-09 07:02:02 -04:00
|
|
|
case T_INT8:
|
|
|
|
return fixnum((*(int8_t *)aptr) >> n);
|
|
|
|
case T_UINT8:
|
|
|
|
return fixnum((*(uint8_t *)aptr) >> n);
|
|
|
|
case T_INT16:
|
|
|
|
return fixnum((*(int16_t *)aptr) >> n);
|
|
|
|
case T_UINT16:
|
|
|
|
return fixnum((*(uint16_t *)aptr) >> n);
|
|
|
|
case T_INT32:
|
|
|
|
return mk_int32((*(int32_t *)aptr) >> n);
|
|
|
|
case T_UINT32:
|
|
|
|
return mk_uint32((*(uint32_t *)aptr) >> n);
|
|
|
|
case T_INT64:
|
|
|
|
return mk_int64((*(int64_t *)aptr) >> n);
|
|
|
|
case T_UINT64:
|
|
|
|
return mk_uint64((*(uint64_t *)aptr) >> n);
|
2009-03-24 22:28:21 -04:00
|
|
|
}
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
2009-03-24 22:28:21 -04:00
|
|
|
if (ta == T_UINT64)
|
2019-08-09 07:02:02 -04:00
|
|
|
return return_from_uint64((*(uint64_t *)aptr) << n);
|
2009-04-01 23:53:38 -04:00
|
|
|
else if (ta < T_FLOAT) {
|
2019-08-18 18:14:09 -04:00
|
|
|
i64 = conv_to_int64(aptr, ta);
|
2019-08-09 07:02:02 -04:00
|
|
|
return return_from_int64(i64 << n);
|
2009-04-01 23:53:38 -04:00
|
|
|
}
|
2009-03-24 22:28:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
type_error("ash", "integer", a);
|
|
|
|
return NIL;
|
|
|
|
}
|