Add 64 bit signed integers as a basic type. Will enable

more native bitwise operations and c integration at the expense
of complicating arithmetic.
This commit is contained in:
Calvin Rose 2017-04-24 16:02:54 -04:00
parent 81987dca45
commit a54548eaa0
10 changed files with 299 additions and 413 deletions

View File

@ -106,7 +106,8 @@ static FormOptions form_options_default() {
* to the byte buffer. This helps us create the byte code for the compiled
* functions. */
BUFFER_DEFINE(i32, int32_t)
BUFFER_DEFINE(number, GstNumber)
BUFFER_DEFINE(i64, int64_t)
BUFFER_DEFINE(real, GstReal)
BUFFER_DEFINE(u16, uint16_t)
BUFFER_DEFINE(i16, int16_t)
@ -321,13 +322,13 @@ static uint16_t compiler_add_literal(GstCompiler *c, GstScope *scope, GstValue x
uint16_t literalIndex = 0;
if (checkDup.type != GST_NIL) {
/* An equal literal is already registered in the current scope */
return (uint16_t) checkDup.data.number;
return (uint16_t) checkDup.data.integer;
} else {
/* Add our literal for tracking */
GstValue valIndex;
valIndex.type = GST_NUMBER;
valIndex.type = GST_INTEGER;
literalIndex = scope->literalsArray->count;
valIndex.data.number = literalIndex;
valIndex.data.integer = literalIndex;
gst_object_put(c->vm, scope->literals, x, valIndex);
gst_array_push(c->vm, scope->literalsArray, x);
}
@ -341,8 +342,8 @@ static uint16_t compiler_declare_symbol(GstCompiler *c, GstScope *scope, GstValu
if (sym.type != GST_STRING)
c_error(c, "expected string");
target = compiler_get_local(c, scope);
x.type = GST_NUMBER;
x.data.number = target;
x.type = GST_INTEGER;
x.data.integer = target;
gst_object_put(c->vm, scope->locals, sym, x);
return target;
}
@ -356,7 +357,7 @@ static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t
GstValue check = gst_object_get(scope->locals, x);
if (check.type != GST_NIL) {
*level = currentLevel - scope->level;
*index = (uint16_t) check.data.number;
*index = (uint16_t) check.data.integer;
return 1;
}
@ -405,24 +406,23 @@ static Slot compile_nonref_type(GstCompiler *c, FormOptions opts, GstValue x) {
} else if (x.type == GST_BOOLEAN) {
gst_buffer_push_u16(c->vm, buffer, x.data.boolean ? GST_OP_TRU : GST_OP_FLS);
gst_buffer_push_u16(c->vm, buffer, ret.index);
} else if (x.type == GST_NUMBER) {
GstNumber number = x.data.number;
int32_t int32Num = (int32_t) number;
if (number == (GstNumber) int32Num) {
if (int32Num <= 32767 && int32Num >= -32768) {
int16_t int16Num = (int16_t) number;
gst_buffer_push_u16(c->vm, buffer, GST_OP_I16);
gst_buffer_push_u16(c->vm, buffer, ret.index);
gst_buffer_push_i16(c->vm, buffer, int16Num);
} else {
gst_buffer_push_u16(c->vm, buffer, GST_OP_I32);
gst_buffer_push_u16(c->vm, buffer, ret.index);
gst_buffer_push_i32(c->vm, buffer, int32Num);
}
} else {
gst_buffer_push_u16(c->vm, buffer, GST_OP_F64);
} else if (x.type == GST_REAL) {
gst_buffer_push_u16(c->vm, buffer, GST_OP_F64);
gst_buffer_push_u16(c->vm, buffer, ret.index);
gst_buffer_push_real(c->vm, buffer, x.data.real);
} else if (x.type == GST_INTEGER) {
if (x.data.integer <= 32767 && x.data.integer >= -32768) {
gst_buffer_push_u16(c->vm, buffer, GST_OP_I16);
gst_buffer_push_u16(c->vm, buffer, ret.index);
gst_buffer_push_number(c->vm, buffer, number);
gst_buffer_push_i16(c->vm, buffer, x.data.integer);
} else if (x.data.integer <= 2147483647 && x.data.integer >= -2147483648) {
gst_buffer_push_u16(c->vm, buffer, GST_OP_I32);
gst_buffer_push_u16(c->vm, buffer, ret.index);
gst_buffer_push_i32(c->vm, buffer, x.data.integer);
} else {
gst_buffer_push_u16(c->vm, buffer, GST_OP_I64);
gst_buffer_push_u16(c->vm, buffer, ret.index);
gst_buffer_push_i64(c->vm, buffer, x.data.integer);
}
} else {
c_error(c, "expected boolean, nil, or number type");
@ -743,7 +743,8 @@ static Slot compile_quote(GstCompiler *c, FormOptions opts, const GstValue *form
GstValue x = form[1];
if (x.type == GST_NIL ||
x.type == GST_BOOLEAN ||
x.type == GST_NUMBER) {
x.type == GST_REAL ||
x.type == GST_INTEGER) {
return compile_nonref_type(c, opts, x);
}
if (opts.resultUnused) return nil_slot();
@ -1007,7 +1008,8 @@ static Slot compile_value(GstCompiler *c, FormOptions opts, GstValue x) {
switch (x.type) {
case GST_NIL:
case GST_BOOLEAN:
case GST_NUMBER:
case GST_REAL:
case GST_INTEGER:
return compile_nonref_type(c, opts, x);
case GST_STRING:
return compile_symbol(c, opts, x);

View File

@ -94,21 +94,6 @@ void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
default:
current += dasm_fixed_op(out, current, "unknown", 0);
break;
case GST_OP_ADD:
current += dasm_fixed_op(out, current, "add", 3);
break;
case GST_OP_SUB:
current += dasm_fixed_op(out, current, "sub", 3);
break;
case GST_OP_MUL:
current += dasm_fixed_op(out, current, "mul", 3);
break;
case GST_OP_DIV:
current += dasm_fixed_op(out, current, "div", 3);
break;
case GST_OP_NOT:
current += dasm_fixed_op(out, current, "not", 2);
break;
case GST_OP_FLS:
current += dasm_fixed_op(out, current, "loadFalse", 1);
break;
@ -174,15 +159,6 @@ void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
dasm_print_literal(out, current[2]);
current += 3;
break;
case GST_OP_EQL:
current += dasm_fixed_op(out, current, "equals", 3);
break;
case GST_OP_LTN:
current += dasm_fixed_op(out, current, "lessThan", 3);
break;
case GST_OP_LTE:
current += dasm_fixed_op(out, current, "lessThanEquals", 3);
break;
case GST_OP_ARR:
current += dasm_varg_op(out, current, "array", 1);
break;

View File

@ -88,10 +88,7 @@ void gst_mark_value(Gst *vm, GstValue x) {
* the main function for doing the garbage collection mark phase. */
void gst_mark(Gst *vm, GstValueUnion x, GstType type) {
switch (type) {
case GST_NIL:
case GST_BOOLEAN:
case GST_NUMBER:
case GST_CFUNCTION:
default:
break;
case GST_STRING:

View File

@ -184,10 +184,10 @@ static double exp10(int power) {
}
}
/* Read a number from a string. Returns if successfuly
* parsed a number from the enitre input string.
/* Read a real from a string. Returns if successfuly
* parsed a real from the enitre input string.
* If returned 1, output is int ret.*/
static int read_number(const uint8_t *string, const uint8_t *end, double *ret, int forceInt) {
static int read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt) {
int sign = 1, x = 0;
double accum = 0, exp = 1, place = 1;
/* Check the sign */
@ -205,7 +205,7 @@ static int read_number(const uint8_t *string, const uint8_t *end, double *ret, i
/* Read the exponent */
++string;
if (string >= end) return 0;
if (!read_number(string, end, &exp, 1))
if (!read_real(string, end, &exp, 1))
return 0;
exp = exp10(exp);
break;
@ -227,6 +227,27 @@ static int read_number(const uint8_t *string, const uint8_t *end, double *ret, i
return 1;
}
static int read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret) {
int sign = 1, x = 0;
int64_t accum = 0;
if (*string == '-') {
sign = -1;
++string;
} else if (*string == '+') {
++string;
}
if (string >= end) return 0;
while (string < end) {
x = *string;
if (x < '0' || x > '9') return 0;
x -= '0';
accum = accum * 10 + x;
++string;
}
*ret = accum * sign;
return 1;
}
/* Checks if a string slice is equal to a string constant */
static int check_str_const(const char *ref, const uint8_t *start, const uint8_t *end) {
while (*ref && start < end) {
@ -240,12 +261,16 @@ static int check_str_const(const char *ref, const uint8_t *start, const uint8_t
/* Build from the token buffer */
static GstValue build_token(GstParser *p, GstBuffer *buf) {
GstValue x;
GstNumber number;
GstReal real;
GstInteger integer;
uint8_t *data = buf->data;
uint8_t *back = data + buf->count;
if (read_number(data, back, &number, 0)) {
x.type = GST_NUMBER;
x.data.number = number;
if (read_integer(data, back, &integer)) {
x.type = GST_INTEGER;
x.data.integer = integer;
} else if (read_real(data, back, &real, 0)) {
x.type = GST_REAL;
x.data.real = real;
} else if (check_str_const("nil", data, back)) {
x.type = GST_NIL;
x.data.boolean = 0;

View File

@ -50,6 +50,7 @@
* Byte 215: LUdata - [value meta][u32 length]*[u8... bytes]
* Byte 216: CFunc - [u32 length]*[u8... idstring]
* Byte 217: Ref - [u32 id]
* Byte 218: Integer - [i64 value]
*/
/* Error at buffer end */
@ -76,7 +77,7 @@ static uint16_t bytes2u16(const uint8_t *bytes) {
}
/* Read 8 bytes as a double */
static uint32_t bytes2dbl(const uint8_t *bytes) {
static double bytes2dbl(const uint8_t *bytes) {
union {
uint8_t bytes[8];
double dbl;
@ -85,6 +86,16 @@ static uint32_t bytes2dbl(const uint8_t *bytes) {
return u.dbl;
}
/* Read 8 bytes as a integer */
static int64_t bytes2int(const uint8_t *bytes) {
union {
uint8_t bytes[8];
int64_t i;
} u;
gst_memcpy(u.bytes, bytes, 8 * sizeof(uint8_t));
return u.i;
}
/* Read a string and turn it into a gst value. Returns
* an error message if there is an error message during
* deserialization. If successful, the resulting value is
@ -116,14 +127,15 @@ static const char *gst_deserialize_impl(
#define read_u32(out) do{deser_datacheck(4); (out)=bytes2u32(data); data += 4; }while(0)
#define read_u16(out) do{deser_datacheck(2); (out)=bytes2u16(data); data += 2; }while(0)
#define read_dbl(out) do{deser_datacheck(8); (out)=bytes2dbl(data); data += 8; }while(0)
#define read_i64(out) do{deser_datacheck(8); (out)=bytes2int(data); data += 8; }while(0)
/* Check enough buffer left to read one byte */
if (data >= end) deser_error(UEB);
/* Small integer */
if (*data < 201) {
ret.type = GST_NUMBER;
ret.data.number = *data - 100;
ret.type = GST_INTEGER;
ret.data.integer = *data - 100;
*newData = data + 1;
*out = ret;
return NULL;
@ -150,8 +162,8 @@ static const char *gst_deserialize_impl(
break;
case 204: /* Long number (double) */
ret.type = GST_NUMBER;
read_dbl(ret.data.number);
ret.type = GST_REAL;
read_dbl(ret.data.real);
break;
case 205: /* String */
@ -410,6 +422,11 @@ static const char *gst_deserialize_impl(
deser_assert(visited->count > length, "invalid reference");
ret = visited->data[length];
break;
case 218: /* Integer */
ret.type = GST_INTEGER;
read_i64(ret.data.integer);
break;
}
/* Handle a successful return */
@ -435,8 +452,8 @@ const char *gst_deserialize(
}
/* Allow appending other types to buffers */
BUFFER_DEFINE(number, GstNumber)
/*BUFFER_DEFINE(u16, uint16_t)*/
BUFFER_DEFINE(real, GstReal)
BUFFER_DEFINE(integer, GstInteger)
BUFFER_DEFINE(u32, uint32_t)
/* Serialize a value and write to a buffer. Returns possible
@ -455,7 +472,8 @@ const char *gst_serialize_impl(
#define write_byte(b) gst_buffer_push(vm, buffer, (b))
#define write_u32(b) gst_buffer_push_u32(vm, buffer, (b))
#define write_u16(b) gst_buffer_push_u16(vm, buffer, (b))
#define write_dbl(b) gst_buffer_push_number(vm, buffer, (b))
#define write_dbl(b) gst_buffer_push_real(vm, buffer, (b))
#define write_int(b) gst_buffer_push_integer(vm, buffer, (b))
/* Check non reference types - if successful, return NULL */
switch (x.type) {
@ -465,17 +483,16 @@ const char *gst_serialize_impl(
case GST_BOOLEAN:
write_byte(x.data.boolean ? 202 : 203);
return NULL;
case GST_NUMBER:
{
GstNumber number = x.data.number;
int32_t int32Num = (int32_t) number;
if (number == (GstNumber) int32Num &&
int32Num <= 100 && int32Num >= -100) {
write_byte(int32Num + 100);
} else {
write_byte(204);
write_dbl(number);
}
case GST_REAL:
write_byte(204);
write_dbl(x.data.real);
return NULL;
case GST_INTEGER:
if (x.data.integer <= 100 && x.data.integer >= -100) {
write_byte(x.data.integer + 100);
} else {
write_byte(218);
write_int(x.data.integer);
}
return NULL;
case GST_CFUNCTION:
@ -487,9 +504,9 @@ const char *gst_serialize_impl(
/* Check if already seen - if so, use reference */
check = gst_object_get(visited, x);
if (check.type == GST_NUMBER) {
if (check.type == GST_INTEGER) {
write_byte(217);
write_u32((uint32_t) check.data.number);
write_u32((uint32_t) check.data.integer);
return NULL;
}
@ -549,8 +566,8 @@ const char *gst_serialize_impl(
}
/* Record reference */
check.type = GST_NUMBER;
check.data.number = *nextId++;
check.type = GST_INTEGER;
check.data.integer = *nextId++;
gst_object_put(vm, visited, x, check);
/* Return success */

View File

@ -27,68 +27,54 @@
#include <gst/disasm.h>
static const char GST_EXPECTED_NUMBER_OP[] = "expected operand to be number";
static const char GST_EXPECTED_INTEGER[] = "expected integer";
static const char GST_EXPECTED_STRING[] = "expected string";
/***/
/* Arithmetic */
/***/
#define SIMPLE_ACCUM_FUNCTION(name, start, op)\
int gst_stl_##name(Gst* vm) {\
GstValue ret;\
uint32_t j, count;\
ret.type = GST_NUMBER;\
ret.data.number = start;\
count = gst_count_args(vm);\
for (j = 0; j < count; ++j) {\
GstValue operand = gst_arg(vm, j);\
if (operand.type != GST_NUMBER)\
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP);\
ret.data.number op operand.data.number;\
}\
gst_c_return(vm, ret);\
#define MAKE_BINOP(name, op)\
GstValue gst_stl_binop_##name(GstValue lhs, GstValue rhs) {\
if (lhs.type == GST_INTEGER)\
if (rhs.type == GST_INTEGER)\
return gst_wrap_integer(lhs.data.integer op rhs.data.integer);\
else if (rhs.type == GST_REAL)\
return gst_wrap_real(lhs.data.integer op rhs.data.real);\
else\
return gst_wrap_nil();\
else if (lhs.type == GST_REAL)\
if (rhs.type == GST_INTEGER)\
return gst_wrap_real(lhs.data.real op rhs.data.integer);\
else if (rhs.type == GST_REAL)\
return gst_wrap_real(lhs.data.real op rhs.data.real);\
else\
return gst_wrap_nil();\
else\
return gst_wrap_nil();\
}
SIMPLE_ACCUM_FUNCTION(add, 0, +=)
SIMPLE_ACCUM_FUNCTION(mul, 1, *=)
#define SIMPLE_ACCUM_FUNCTION(name, start, op)\
MAKE_BINOP(name, op)\
int gst_stl_##name(Gst* vm) {\
GstValue lhs, rhs;\
uint32_t j, count;\
count = gst_count_args(vm);\
lhs = gst_arg(vm, 0);\
for (j = 1; j < count; ++j) {\
rhs = gst_arg(vm, j);\
lhs = gst_stl_binop_##name(lhs, rhs);\
}\
gst_c_return(vm, lhs);\
}
SIMPLE_ACCUM_FUNCTION(add, 0, +)
SIMPLE_ACCUM_FUNCTION(mul, 1, *)
SIMPLE_ACCUM_FUNCTION(sub, 0, -)
SIMPLE_ACCUM_FUNCTION(div, 1, /)
#undef SIMPLE_ACCUM_FUNCTION
#define UNARY_ACCUM_FUNCTION(name, zeroval, unaryop, op)\
int gst_stl_##name(Gst* vm) {\
GstValue ret;\
GstValue operand;\
uint32_t j, count;\
ret.type = GST_NUMBER;\
count = gst_count_args(vm);\
if (count == 0) {\
ret.data.number = zeroval;\
gst_c_return(vm, ret);\
}\
operand = gst_arg(vm, 0);\
if (operand.type != GST_NUMBER)\
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP);\
if (count == 1) {\
ret.data.number = unaryop operand.data.number;\
gst_c_return(vm, ret);\
} else {\
ret.data.number = operand.data.number;\
}\
for (j = 1; j < count; ++j) {\
operand = gst_arg(vm, j);\
if (operand.type != GST_NUMBER)\
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP);\
ret.data.number op operand.data.number;\
}\
gst_c_return(vm, ret);\
}
UNARY_ACCUM_FUNCTION(sub, 0, -, -=)
UNARY_ACCUM_FUNCTION(div, 1, 1/, /=)
#undef UNARY_ACCUM_FUNCTION
#define COMPARE_FUNCTION(name, check)\
int gst_stl_##name(Gst *vm) {\
GstValue ret;\
@ -131,43 +117,49 @@ int gst_stl_length(Gst *vm) {
gst_c_return(vm, ret);
}
if (count == 1) {
ret.type = GST_NUMBER;
ret.type = GST_INTEGER;
GstValue x = gst_arg(vm, 0);
switch (x.type) {
default:
gst_c_throwc(vm, "cannot get length");
case GST_STRING:
ret.data.number = gst_string_length(x.data.string);
ret.data.integer = gst_string_length(x.data.string);
break;
case GST_ARRAY:
ret.data.number = x.data.array->count;
ret.data.integer = x.data.array->count;
break;
case GST_BYTEBUFFER:
ret.data.number = x.data.buffer->count;
ret.data.integer = x.data.buffer->count;
break;
case GST_TUPLE:
ret.data.number = gst_tuple_length(x.data.tuple);
ret.data.integer = gst_tuple_length(x.data.tuple);
break;
case GST_OBJECT:
ret.data.number = x.data.object->count;
ret.data.integer = x.data.object->count;
break;
}
}
gst_c_return(vm, ret);
}
/* Get nth argument, not including first argument */
int gst_stl_select(Gst *vm) {
GstValue selector;
uint32_t count, n;
count = gst_count_args(vm);
if (count == 0)
gst_c_throwc(vm, "select takes at least one argument");
selector = gst_arg(vm, 0);
if (selector.type != GST_NUMBER)
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP);
n = selector.data.number;
gst_c_return(vm, gst_arg(vm, n + 1));
/* Convert to integer */
int gst_stl_to_int(Gst *vm) {
GstValue x = gst_arg(vm, 0);
if (x.type == GST_INTEGER) gst_c_return(vm, x);
if (x.type == GST_REAL)
gst_c_return(vm, gst_wrap_integer((GstInteger) x.data.real));
else
gst_c_throwc(vm, "expected number");
}
/* Convert to integer */
int gst_stl_to_real(Gst *vm) {
GstValue x = gst_arg(vm, 0);
if (x.type == GST_REAL) gst_c_return(vm, x);
if (x.type == GST_INTEGER)
gst_c_return(vm, gst_wrap_real((GstReal) x.data.integer));
else
gst_c_throwc(vm, "expected number");
}
/* Get a slice of a sequence */
@ -178,7 +170,7 @@ int gst_stl_slice(Gst *vm) {
const GstValue *data;
uint32_t length;
uint32_t newlength;
GstNumber num;
GstInteger num;
/* Get data */
x = gst_arg(vm, 0);
@ -189,18 +181,18 @@ int gst_stl_slice(Gst *vm) {
if (count < 2) {
from = 0;
} else {
if (!gst_check_number(vm, 1, &num))
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP);
from = gst_to_index(num, length);
if (!gst_check_integer(vm, 1, &num))
gst_c_throwc(vm, GST_EXPECTED_INTEGER);
from = gst_startrange(num, length);
}
/* Get to index */
if (count < 3) {
to = length;
} else {
if (!gst_check_number(vm, 2, &num))
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP);
to = gst_to_endrange(num, length);
if (!gst_check_integer(vm, 2, &num))
gst_c_throwc(vm, GST_EXPECTED_INTEGER);
to = gst_endrange(num, length);
}
/* Check from bad bounds */
@ -232,8 +224,11 @@ int gst_stl_type(Gst *vm) {
switch (x.type) {
default:
break;
case GST_NUMBER:
typestr = "number";
case GST_REAL:
typestr = "real";
break;
case GST_INTEGER:
typestr = "integer";
break;
case GST_BOOLEAN:
typestr = "boolean";
@ -419,9 +414,9 @@ int gst_stl_ensure(Gst *vm) {
GstValue cap = gst_arg(vm, 1);
if (ds.type != GST_ARRAY)
gst_c_throwc(vm, "expected array");
if (cap.type != GST_NUMBER)
gst_c_throwc(vm, "expected number");
gst_array_ensure(vm, ds.data.array, (uint32_t) cap.data.number);
if (cap.type != GST_INTEGER)
gst_c_throwc(vm, GST_EXPECTED_INTEGER);
gst_array_ensure(vm, ds.data.array, (uint32_t) cap.data.integer);
gst_c_return(vm, ds);
}
@ -464,8 +459,8 @@ int gst_stl_tostring(Gst *vm) {
/* Exit */
int gst_stl_exit(Gst *vm) {
int ret;
GstValue exitValue = gst_arg(vm, 0);
ret = (exitValue.type == GST_NUMBER) ? exitValue.data.number : 0;
GstValue x = gst_arg(vm, 0);
ret = x.type == GST_INTEGER ? x.data.integer : (x.type == GST_REAL ? x.data.real : 0);
exit(ret);
return GST_RETURN_OK;
}
@ -532,31 +527,6 @@ int gst_stl_open(Gst *vm) {
gst_c_return(vm, gst_wrap_userdata(fp));
}
/* Write a string to a file */
int gst_stl_write(Gst *vm) {
GstValue f = gst_arg(vm, 0);
FILE *f;
if (f.type != GST_USERDATA)
gst_c_throwc(vm, "expected file userdata");
f = *(FILE **)f.data.pointer
}
/* Read an entire file in one go. Will be faster than sequential reads for
* small to moderately sized files */
int gst_stl_slurp(Gst *vm) {
GstValue x = gst_arg(vm, 0);
const uint8_t *fname;
FILE *f;
if (gst_count_args(vm) < 1 || x.type != GST_STRING)
gst_c_throwc(vm, "expected file name");
fname = gst_to_string(vm, gst_arg(vm, 0));
f = fopen((const char *) fname, "rb");
if (!f)
gst_c_throwc(vm, "could not open file for reading");
// TODO use fseek and like functions to read file into a buffer.
}
/* Write a string to a file in one go. Overwrites an existing file. */
/****/
@ -595,8 +565,9 @@ static const GstModuleItem const std_module[] = {
{"<=", gst_stl_lessthaneq},
{">=", gst_stl_greaterthaneq},
{"length", gst_stl_length},
{"to-integer", gst_stl_to_int},
{"to-real", gst_stl_to_real},
{"type", gst_stl_type},
{"select", gst_stl_select},
{"slice", gst_stl_slice},
{"array", gst_stl_array},
{"tuple", gst_stl_tuple},

View File

@ -51,7 +51,8 @@ int gst_check_##NAME(Gst *vm, uint32_t i, TYPE (*out)) {\
return 1;\
}\
GST_WRAP_DEFINE(number, GstNumber, GST_NUMBER, number)
GST_WRAP_DEFINE(real, GstReal, GST_REAL, real)
GST_WRAP_DEFINE(integer, GstInteger, GST_INTEGER, integer)
GST_WRAP_DEFINE(boolean, int, GST_BOOLEAN, boolean)
GST_WRAP_DEFINE(string, const uint8_t *, GST_STRING, string)
GST_WRAP_DEFINE(array, GstArray *, GST_ARRAY, array)
@ -166,41 +167,26 @@ int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap) {
return 0;
}
/* Allow negative indexing to get from end of array like structure */
/* This probably isn't very fast - look at Lua conversion function.
* I would like to keep this standard C for as long as possible, though. */
int32_t gst_to_index(GstNumber raw, int64_t len) {
int32_t toInt = raw;
if ((GstNumber) toInt == raw) {
/* We were able to convert */
if (toInt < 0 && len > 0) {
/* Index from end */
if (toInt < -len) return -1;
return len + toInt;
} else {
/* Normal indexing */
if (toInt >= len) return -1;
return toInt;
}
} else {
return -1;
}
GstReal gst_integer_to_real(GstInteger x) {
return (GstReal) x;
}
int32_t gst_to_endrange(GstNumber raw, int64_t len) {
int32_t toInt = raw;
if ((GstNumber) toInt == raw) {
/* We were able to convert */
if (toInt < 0 && len > 0) {
/* Index from end */
if (toInt < -len - 1) return -1;
return len + toInt + 1;
} else {
/* Normal indexing */
if (toInt >= len) return -1;
return toInt;
}
} else {
return -1;
}
GstInteger gst_real_to_integer(GstReal x) {
return (GstInteger) x;
}
GstInteger gst_startrange(GstInteger raw, uint32_t len) {
if (raw > len)
return -1;
if (raw < 0)
return len + raw;
return raw;
}
GstInteger gst_endrange(GstInteger raw, uint32_t len) {
if (raw > len)
return -1;
if (raw < 0)
return len + raw + 1;
return raw;
}

View File

@ -31,13 +31,18 @@ int gst_truthy(GstValue v) {
/* Temporary buffer size */
#define GST_BUFSIZE 36
static const uint8_t *number_to_string(Gst *vm, GstNumber x) {
static const uint8_t *real_to_string(Gst *vm, GstReal x) {
uint8_t buf[GST_BUFSIZE];
/* TODO - not depend on stdio */
int count = snprintf((char *) buf, GST_BUFSIZE, "%.21g", x);
return gst_string_b(vm, buf, (uint32_t) count);
}
static const uint8_t *integer_to_string(Gst *vm, GstInteger x) {
uint8_t buf[GST_BUFSIZE];
int count = snprintf((char *) buf, GST_BUFSIZE, "%ld", x);
return gst_string_b(vm, buf, (uint32_t) count);
}
static const char *HEX_CHARACTERS = "0123456789abcdef";
#define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)])
@ -77,13 +82,14 @@ const uint8_t *gst_to_string(Gst *vm, GstValue x) {
case GST_NIL:
return gst_string_c(vm, "nil");
case GST_BOOLEAN:
if (x.data.boolean) {
if (x.data.boolean)
return gst_string_c(vm, "true");
} else {
else
return gst_string_c(vm, "false");
}
case GST_NUMBER:
return number_to_string(vm, x.data.number);
case GST_REAL:
return real_to_string(vm, x.data.real);
case GST_INTEGER:
return integer_to_string(vm, x.data.integer);
case GST_ARRAY:
return string_description(vm, "array", x.data.pointer);
case GST_TUPLE:
@ -125,8 +131,11 @@ int gst_equals(GstValue x, GstValue y) {
case GST_BOOLEAN:
result = (x.data.boolean == y.data.boolean);
break;
case GST_NUMBER:
result = (x.data.number == y.data.number);
case GST_REAL:
result = (x.data.real == y.data.real);
break;
case GST_INTEGER:
result = (x.data.integer == y.data.integer);
break;
default:
/* compare pointers */
@ -147,17 +156,6 @@ uint32_t gst_hash(GstValue x) {
case GST_BOOLEAN:
hash = x.data.boolean;
break;
case GST_NUMBER:
{
union {
uint32_t hash;
GstNumber number;
} u;
u.number = x.data.number;
hash = u.hash;
}
break;
/* String hashes */
case GST_STRING:
hash = gst_string_hash(x.data.string);
break;
@ -168,15 +166,7 @@ uint32_t gst_hash(GstValue x) {
hash = gst_struct_hash(x.data.st);
break;
default:
/* Cast the pointer */
{
union {
void * pointer;
uint32_t hash;
} u;
u.pointer = x.data.pointer;
hash = u.hash;
}
hash = x.data.dwords[0] ^ x.data.dwords[1];
break;
}
return hash;
@ -196,12 +186,17 @@ int gst_compare(GstValue x, GstValue y) {
} else {
return x.data.boolean ? 1 : -1;
}
case GST_NUMBER:
/* TODO: define behavior for NaN and infinties. */
if (x.data.number == y.data.number) {
case GST_REAL:
if (x.data.real == y.data.real) {
return 0;
} else {
return x.data.number > y.data.number ? 1 : -1;
return x.data.real > y.data.real ? 1 : -1;
}
case GST_INTEGER:
if (x.data.integer == y.data.integer) {
return 0;
} else {
return x.data.integer > y.data.integer ? 1 : -1;
}
case GST_STRING:
return gst_string_compare(x.data.string, y.data.string);
@ -236,45 +231,38 @@ int gst_compare(GstValue x, GstValue y) {
return 1;
}
/* Convert a number into a byte. */
static uint8_t to_byte(GstNumber raw) {
if (raw > 255) return 255;
if (raw < 0) return 0;
return (uint8_t) raw;
}
/* Get a value out af an associated data structure.
* Returns possible c error message, and NULL for no error. The
* useful return value is written to out on success */
const char *gst_get(GstValue ds, GstValue key, GstValue *out) {
int32_t index;
GstInteger index;
GstValue ret;
switch (ds.type) {
case GST_ARRAY:
if (key.type != GST_NUMBER) return "expected numeric key";
index = gst_to_index(key.data.number, ds.data.array->count);
if (index == -1) return "invalid array access";
if (key.type != GST_INTEGER) return "expected integer key";
index = gst_startrange(key.data.integer, ds.data.array->count);
if (index < 0) return "invalid array access";
ret = ds.data.array->data[index];
break;
case GST_TUPLE:
if (key.type != GST_NUMBER) return "expected numeric key";
index = gst_to_index(key.data.number, gst_tuple_length(ds.data.tuple));
if (key.type != GST_INTEGER) return "expected integer key";
index = gst_startrange(key.data.integer, gst_tuple_length(ds.data.tuple));
if (index < 0) return "invalid tuple access";
ret = ds.data.tuple[index];
break;
case GST_BYTEBUFFER:
if (key.type != GST_NUMBER) return "expected numeric key";
index = gst_to_index(key.data.number, ds.data.buffer->count);
if (index == -1) return "invalid buffer access";
ret.type = GST_NUMBER;
ret.data.number = ds.data.buffer->data[index];
if (key.type != GST_INTEGER) return "expected integer key";
index = gst_startrange(key.data.integer, ds.data.buffer->count);
if (index < 0) return "invalid buffer access";
ret.type = GST_INTEGER;
ret.data.integer = ds.data.buffer->data[index];
break;
case GST_STRING:
if (key.type != GST_NUMBER) return "expected numeric key";
index = gst_to_index(key.data.number, gst_string_length(ds.data.string));
if (index == -1) return "invalid string access";
ret.type = GST_NUMBER;
ret.data.number = ds.data.string[index];
if (key.type != GST_INTEGER) return "expected integer key";
index = gst_startrange(key.data.integer, gst_string_length(ds.data.string));
if (index < 0) return "invalid string access";
ret.type = GST_INTEGER;
ret.data.integer = ds.data.string[index];
break;
case GST_STRUCT:
ret = gst_struct_get(ds.data.st, key);
@ -292,20 +280,20 @@ const char *gst_get(GstValue ds, GstValue key, GstValue *out) {
/* Set a value in an associative data structure. Returns possible
* error message, and NULL if no error. */
const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) {
int32_t index;
GstInteger index;
switch (ds.type) {
case GST_ARRAY:
if (key.type != GST_NUMBER) return "expected numeric key";
index = gst_to_index(key.data.number, ds.data.array->count);
if (index == -1) return "invalid array access";
if (key.type != GST_INTEGER) return "expected integer key";
index = gst_startrange(key.data.integer, ds.data.array->count);
if (index < 0) return "invalid array access";
ds.data.array->data[index] = value;
break;
case GST_BYTEBUFFER:
if (key.type != GST_NUMBER) return "expected numeric key";
if (value.type != GST_NUMBER) return "expected numeric value";
index = gst_to_index(key.data.number, ds.data.buffer->count);
if (index == -1) return "invalid buffer access";
ds.data.buffer->data[index] = to_byte(value.data.number);
if (key.type != GST_INTEGER) return "expected integer key";
if (value.type != GST_INTEGER) return "expected integer value";
index = gst_startrange(key.data.integer, ds.data.buffer->count);
if (index < 0) return "invalid buffer access";
ds.data.buffer->data[index] = (uint8_t) value.data.integer;
break;
case GST_OBJECT:
gst_object_put(vm, ds.data.object, key, value);
@ -317,8 +305,8 @@ const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) {
}
/* Get the length of an object. Returns errors for invalid types */
int gst_length(Gst *vm, GstValue x, GstValue *len) {
uint32_t length;
GstInteger gst_length(Gst *vm, GstValue x) {
GstInteger length;
switch (x.type) {
default:
vm->ret = gst_string_cv(vm, "cannot get length");
@ -342,9 +330,6 @@ int gst_length(Gst *vm, GstValue x, GstValue *len) {
length = x.data.object->count;
break;
}
/* Normal numeric return */
len->type = GST_NUMBER;
len->data.number = (GstNumber) length;
return GST_RETURN_OK;
return length;
}

View File

@ -24,8 +24,6 @@
static const char GST_NO_UPVALUE[] = "no upvalue";
static const char GST_EXPECTED_FUNCTION[] = "expected function";
static const char GST_EXPECTED_NUMBER_ROP[] = "expected right operand to be number";
static const char GST_EXPECTED_NUMBER_LOP[] = "expected left operand to be number";
/* Start running the VM from where it left off. */
int gst_continue(Gst *vm) {
@ -73,8 +71,8 @@ int gst_continue(Gst *vm) {
continue;
case GST_OP_I16: /* Load Small Integer */
temp.type = GST_NUMBER;
temp.data.number = ((int16_t *)(pc))[2];
temp.type = GST_INTEGER;
temp.data.integer = ((int16_t *)(pc))[2];
stack[pc[1]] = temp;
pc += 3;
continue;
@ -132,15 +130,22 @@ int gst_continue(Gst *vm) {
continue;
case GST_OP_I32: /* Load 32 bit integer */
temp.type = GST_NUMBER;
temp.data.number = *((int32_t *)(pc + 2));
temp.type = GST_INTEGER;
temp.data.integer = *((int32_t *)(pc + 2));
stack[pc[1]] = temp;
pc += 4;
continue;
case GST_OP_I64: /* Load 64 bit integer */
temp.type = GST_INTEGER;
temp.data.integer = (GstInteger) *((int64_t *)(pc + 2));
stack[pc[1]] = temp;
pc += 6;
continue;
case GST_OP_F64: /* Load 64 bit float */
temp.type = GST_NUMBER;
temp.data.number = (GstNumber) *((double *)(pc + 2));
temp.type = GST_REAL;
temp.data.real = (GstReal) *((double *)(pc + 2));
stack[pc[1]] = temp;
pc += 6;
continue;
@ -310,81 +315,6 @@ int gst_continue(Gst *vm) {
}
break;
/* Faster implementations of standard functions
* These opcodes are nto strictlyre required and can
* be reimplemented with stanard library functions */
#define OP_BINARY_MATH(op) \
v1 = stack[pc[2]]; \
v2 = stack[pc[3]]; \
gst_assert(vm, v1.type == GST_NUMBER, GST_EXPECTED_NUMBER_LOP); \
gst_assert(vm, v2.type == GST_NUMBER, GST_EXPECTED_NUMBER_ROP); \
temp.type = GST_NUMBER; \
temp.data.number = v1.data.number op v2.data.number; \
stack[pc[1]] = temp; \
pc += 4; \
continue;
case GST_OP_ADD: /* Addition */
OP_BINARY_MATH(+)
case GST_OP_SUB: /* Subtraction */
OP_BINARY_MATH(-)
case GST_OP_MUL: /* Multiplication */
OP_BINARY_MATH(*)
case GST_OP_DIV: /* Division */
OP_BINARY_MATH(/)
#undef OP_BINARY_MATH
case GST_OP_NOT: /* Boolean unary (Boolean not) */
temp.type = GST_BOOLEAN;
temp.data.boolean = !gst_truthy(stack[pc[2]]);
stack[pc[1]] = temp;
pc += 3;
continue;
case GST_OP_NEG: /* Unary negation */
v1 = stack[pc[2]];
gst_assert(vm, v1.type == GST_NUMBER, GST_EXPECTED_NUMBER_LOP);
temp.type = GST_NUMBER;
temp.data.number = -v1.data.number;
stack[pc[1]] = temp;
pc += 3;
continue;
case GST_OP_INV: /* Unary multiplicative inverse */
v1 = stack[pc[2]];
gst_assert(vm, v1.type == GST_NUMBER, GST_EXPECTED_NUMBER_LOP);
temp.type = GST_NUMBER;
temp.data.number = 1 / v1.data.number;
stack[pc[1]] = temp;
pc += 3;
continue;
case GST_OP_EQL: /* Equality */
temp.type = GST_BOOLEAN;
temp.data.boolean = gst_equals(stack[pc[2]], stack[pc[3]]);
stack[pc[1]] = temp;
pc += 4;
continue;
case GST_OP_LTN: /* Less Than */
temp.type = GST_BOOLEAN;
temp.data.boolean = (gst_compare(stack[pc[2]], stack[pc[3]]) == -1);
stack[pc[1]] = temp;
pc += 4;
continue;
case GST_OP_LTE: /* Less Than or Equal to */
temp.type = GST_BOOLEAN;
temp.data.boolean = (gst_compare(stack[pc[2]], stack[pc[3]]) != 1);
stack[pc[1]] = temp;
pc += 4;
continue;
case GST_OP_ARR: /* Array literal */
{
uint32_t i;

View File

@ -83,10 +83,10 @@
/* Macros for referencing a stack frame given a stack */
#define gst_frame_callee(s) (*(s - 1))
#define gst_frame_size(s) ((s - 2)->data.hws[0])
#define gst_frame_prevsize(s) ((s - 2)->data.hws[1])
#define gst_frame_args(s) ((s - 2)->data.hws[2])
#define gst_frame_ret(s) ((s - 2)->data.hws[3])
#define gst_frame_size(s) ((s - 2)->data.words[0])
#define gst_frame_prevsize(s) ((s - 2)->data.words[1])
#define gst_frame_args(s) ((s - 2)->data.words[2])
#define gst_frame_ret(s) ((s - 2)->data.words[3])
#define gst_frame_pc(s) ((s - 3)->data.u16p)
#define gst_frame_env(s) ((s - 4)->data.env)
@ -111,13 +111,11 @@
#define GST_OUT_OF_MEMORY do { printf("out of memory\n"); exit(1); } while (0)
#endif
/* Max search depth for classes. */
#define GST_MAX_SEARCH_DEPTH 128
/* Various types */
typedef enum GstType {
GST_NIL = 0,
GST_NUMBER,
GST_REAL,
GST_INTEGER,
GST_BOOLEAN,
GST_STRING,
GST_ARRAY,
@ -140,8 +138,9 @@ typedef struct Gst Gst;
typedef struct GstValue GstValue;
/* All of the gst types */
typedef double GstNumber;
typedef uint8_t GstBoolean;
typedef double GstReal;
typedef int64_t GstInteger;
typedef int GstBoolean;
typedef struct GstFunction GstFunction;
typedef struct GstArray GstArray;
typedef struct GstBuffer GstBuffer;
@ -167,7 +166,8 @@ struct GstModuleItem {
/* Union datatype */
union GstValueUnion {
GstBoolean boolean;
GstNumber number;
GstReal real;
GstInteger integer;
GstArray *array;
GstBuffer *buffer;
GstObject *object;
@ -179,12 +179,13 @@ union GstValueUnion {
GstFuncDef *def;
const GstValue *st;
const uint8_t *string;
const char *cstring; /* Alias for ease of use from c */
/* Indirectly used union members */
uint16_t *u16p;
uint16_t hws[4];
uint32_t dwords[2];
uint16_t words[4];
uint8_t bytes[8];
void *pointer;
const char *cstring;
};
/* The general gst value type. Contains a large union and
@ -296,29 +297,20 @@ struct Gst {
/* Bytecode */
enum GstOpCode {
GST_OP_ADD = 0, /* Addition */
GST_OP_SUB, /* Subtraction */
GST_OP_MUL, /* Multiplication */
GST_OP_DIV, /* Division */
GST_OP_NOT, /* Boolean invert */
GST_OP_NEG, /* Unary negation */
GST_OP_INV, /* Unary multiplicative inverse */
GST_OP_FLS, /* Load false */
GST_OP_TRU, /* Load true */
GST_OP_NIL, /* Load nil */
GST_OP_I16, /* Load 16 bit signed integer */
GST_OP_UPV, /* Load upvalue */
GST_OP_JIF, /* Jump if */
GST_OP_JMP, /* Jump */
GST_OP_SUV, /* Set upvalue */
GST_OP_CST, /* Load constant */
GST_OP_I16, /* Load 16 bit signed integer */
GST_OP_I32, /* Load 32 bit signed integer */
GST_OP_I64, /* Load 64 bit signed integer */
GST_OP_F64, /* Load 64 bit IEEE double */
GST_OP_MOV, /* Move value */
GST_OP_CLN, /* Create a closure */
GST_OP_EQL, /* Check equality */
GST_OP_LTN, /* Check less than */
GST_OP_LTE, /* Check less than or equal to */
GST_OP_ARR, /* Create array */
GST_OP_DIC, /* Create object */
GST_OP_TUP, /* Create tuple */
@ -430,7 +422,7 @@ const char *gst_get(GstValue ds, GstValue key, GstValue *out);
const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value);
const uint8_t *gst_to_string(Gst *vm, GstValue x);
uint32_t gst_hash(GstValue x);
int gst_length(Gst *vm, GstValue x, GstValue *len);
GstInteger gst_length(Gst *vm, GstValue x);
/****/
/* Serialization */
@ -464,6 +456,7 @@ int gst_length(Gst *vm, GstValue x, GstValue *len);
* Byte 215: LUdata - [value meta][u32 length]*[u8... bytes]
* Byte 216: CFunc - [u32 length]*[u8... idstring]
* Byte 217: Ref - [u32 id]
* Byte 218: Integer - [i64 value]
*/
const char *gst_deserialize(
@ -517,7 +510,8 @@ GstValue gst_register_get(Gst *vm, const char *name);
/* Wrap data in GstValue */
GstValue gst_wrap_nil();
GstValue gst_wrap_number(GstNumber x);
GstValue gst_wrap_real(GstReal x);
GstValue gst_wrap_integer(GstInteger x);
GstValue gst_wrap_boolean(int x);
GstValue gst_wrap_string(const uint8_t *x);
GstValue gst_wrap_array(GstArray *x);
@ -534,7 +528,8 @@ GstValue gst_wrap_funcdef(GstFuncDef *x);
/* Check data from arguments */
int gst_check_nil(Gst *vm, uint32_t i);
int gst_check_number(Gst *vm, uint32_t i, GstNumber (*x));
int gst_check_real(Gst *vm, uint32_t i, GstReal (*x));
int gst_check_integer(Gst *vm, uint32_t i, GstInteger (*x));
int gst_check_boolean(Gst *vm, uint32_t i, int (*x));
int gst_check_string(Gst *vm, uint32_t i, const uint8_t *(*x));
int gst_check_array(Gst *vm, uint32_t i, GstArray *(*x));
@ -557,7 +552,9 @@ int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap);
/* Misc */
/****/
int32_t gst_to_index(GstNumber raw, int64_t len);
int32_t gst_to_endrange(GstNumber raw, int64_t len);
GstReal gst_integer_to_real(GstInteger x);
GstInteger gst_real_to_integer(GstReal x);
GstInteger gst_startrange(GstInteger raw, uint32_t len);
GstInteger gst_endrange(GstInteger raw, uint32_t len);
#endif // GST_H_defined