1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 02:59:54 +00:00

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 * to the byte buffer. This helps us create the byte code for the compiled
* functions. */ * functions. */
BUFFER_DEFINE(i32, int32_t) 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(u16, uint16_t)
BUFFER_DEFINE(i16, int16_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; uint16_t literalIndex = 0;
if (checkDup.type != GST_NIL) { if (checkDup.type != GST_NIL) {
/* An equal literal is already registered in the current scope */ /* An equal literal is already registered in the current scope */
return (uint16_t) checkDup.data.number; return (uint16_t) checkDup.data.integer;
} else { } else {
/* Add our literal for tracking */ /* Add our literal for tracking */
GstValue valIndex; GstValue valIndex;
valIndex.type = GST_NUMBER; valIndex.type = GST_INTEGER;
literalIndex = scope->literalsArray->count; literalIndex = scope->literalsArray->count;
valIndex.data.number = literalIndex; valIndex.data.integer = literalIndex;
gst_object_put(c->vm, scope->literals, x, valIndex); gst_object_put(c->vm, scope->literals, x, valIndex);
gst_array_push(c->vm, scope->literalsArray, x); 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) if (sym.type != GST_STRING)
c_error(c, "expected string"); c_error(c, "expected string");
target = compiler_get_local(c, scope); target = compiler_get_local(c, scope);
x.type = GST_NUMBER; x.type = GST_INTEGER;
x.data.number = target; x.data.integer = target;
gst_object_put(c->vm, scope->locals, sym, x); gst_object_put(c->vm, scope->locals, sym, x);
return target; 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); GstValue check = gst_object_get(scope->locals, x);
if (check.type != GST_NIL) { if (check.type != GST_NIL) {
*level = currentLevel - scope->level; *level = currentLevel - scope->level;
*index = (uint16_t) check.data.number; *index = (uint16_t) check.data.integer;
return 1; return 1;
} }
@ -405,24 +406,23 @@ static Slot compile_nonref_type(GstCompiler *c, FormOptions opts, GstValue x) {
} else if (x.type == GST_BOOLEAN) { } 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, x.data.boolean ? GST_OP_TRU : GST_OP_FLS);
gst_buffer_push_u16(c->vm, buffer, ret.index); gst_buffer_push_u16(c->vm, buffer, ret.index);
} else if (x.type == GST_NUMBER) { } else if (x.type == GST_REAL) {
GstNumber number = x.data.number; gst_buffer_push_u16(c->vm, buffer, GST_OP_F64);
int32_t int32Num = (int32_t) number; gst_buffer_push_u16(c->vm, buffer, ret.index);
if (number == (GstNumber) int32Num) { gst_buffer_push_real(c->vm, buffer, x.data.real);
if (int32Num <= 32767 && int32Num >= -32768) { } else if (x.type == GST_INTEGER) {
int16_t int16Num = (int16_t) number; 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, 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);
gst_buffer_push_u16(c->vm, buffer, ret.index); 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 { } else {
c_error(c, "expected boolean, nil, or number type"); 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]; GstValue x = form[1];
if (x.type == GST_NIL || if (x.type == GST_NIL ||
x.type == GST_BOOLEAN || x.type == GST_BOOLEAN ||
x.type == GST_NUMBER) { x.type == GST_REAL ||
x.type == GST_INTEGER) {
return compile_nonref_type(c, opts, x); return compile_nonref_type(c, opts, x);
} }
if (opts.resultUnused) return nil_slot(); if (opts.resultUnused) return nil_slot();
@ -1007,7 +1008,8 @@ static Slot compile_value(GstCompiler *c, FormOptions opts, GstValue x) {
switch (x.type) { switch (x.type) {
case GST_NIL: case GST_NIL:
case GST_BOOLEAN: case GST_BOOLEAN:
case GST_NUMBER: case GST_REAL:
case GST_INTEGER:
return compile_nonref_type(c, opts, x); return compile_nonref_type(c, opts, x);
case GST_STRING: case GST_STRING:
return compile_symbol(c, opts, x); return compile_symbol(c, opts, x);

View File

@ -94,21 +94,6 @@ void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
default: default:
current += dasm_fixed_op(out, current, "unknown", 0); current += dasm_fixed_op(out, current, "unknown", 0);
break; 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: case GST_OP_FLS:
current += dasm_fixed_op(out, current, "loadFalse", 1); current += dasm_fixed_op(out, current, "loadFalse", 1);
break; break;
@ -174,15 +159,6 @@ void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
dasm_print_literal(out, current[2]); dasm_print_literal(out, current[2]);
current += 3; current += 3;
break; 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: case GST_OP_ARR:
current += dasm_varg_op(out, current, "array", 1); current += dasm_varg_op(out, current, "array", 1);
break; 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. */ * the main function for doing the garbage collection mark phase. */
void gst_mark(Gst *vm, GstValueUnion x, GstType type) { void gst_mark(Gst *vm, GstValueUnion x, GstType type) {
switch (type) { switch (type) {
case GST_NIL: default:
case GST_BOOLEAN:
case GST_NUMBER:
case GST_CFUNCTION:
break; break;
case GST_STRING: case GST_STRING:

View File

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

View File

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

View File

@ -27,68 +27,54 @@
#include <gst/disasm.h> #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"; static const char GST_EXPECTED_STRING[] = "expected string";
/***/ /***/
/* Arithmetic */ /* Arithmetic */
/***/ /***/
#define SIMPLE_ACCUM_FUNCTION(name, start, op)\ #define MAKE_BINOP(name, op)\
int gst_stl_##name(Gst* vm) {\ GstValue gst_stl_binop_##name(GstValue lhs, GstValue rhs) {\
GstValue ret;\ if (lhs.type == GST_INTEGER)\
uint32_t j, count;\ if (rhs.type == GST_INTEGER)\
ret.type = GST_NUMBER;\ return gst_wrap_integer(lhs.data.integer op rhs.data.integer);\
ret.data.number = start;\ else if (rhs.type == GST_REAL)\
count = gst_count_args(vm);\ return gst_wrap_real(lhs.data.integer op rhs.data.real);\
for (j = 0; j < count; ++j) {\ else\
GstValue operand = gst_arg(vm, j);\ return gst_wrap_nil();\
if (operand.type != GST_NUMBER)\ else if (lhs.type == GST_REAL)\
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP);\ if (rhs.type == GST_INTEGER)\
ret.data.number op operand.data.number;\ return gst_wrap_real(lhs.data.real op rhs.data.integer);\
}\ else if (rhs.type == GST_REAL)\
gst_c_return(vm, ret);\ 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, +=) #define SIMPLE_ACCUM_FUNCTION(name, start, op)\
SIMPLE_ACCUM_FUNCTION(mul, 1, *=) 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 #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)\ #define COMPARE_FUNCTION(name, check)\
int gst_stl_##name(Gst *vm) {\ int gst_stl_##name(Gst *vm) {\
GstValue ret;\ GstValue ret;\
@ -131,43 +117,49 @@ int gst_stl_length(Gst *vm) {
gst_c_return(vm, ret); gst_c_return(vm, ret);
} }
if (count == 1) { if (count == 1) {
ret.type = GST_NUMBER; ret.type = GST_INTEGER;
GstValue x = gst_arg(vm, 0); GstValue x = gst_arg(vm, 0);
switch (x.type) { switch (x.type) {
default: default:
gst_c_throwc(vm, "cannot get length"); gst_c_throwc(vm, "cannot get length");
case GST_STRING: case GST_STRING:
ret.data.number = gst_string_length(x.data.string); ret.data.integer = gst_string_length(x.data.string);
break; break;
case GST_ARRAY: case GST_ARRAY:
ret.data.number = x.data.array->count; ret.data.integer = x.data.array->count;
break; break;
case GST_BYTEBUFFER: case GST_BYTEBUFFER:
ret.data.number = x.data.buffer->count; ret.data.integer = x.data.buffer->count;
break; break;
case GST_TUPLE: case GST_TUPLE:
ret.data.number = gst_tuple_length(x.data.tuple); ret.data.integer = gst_tuple_length(x.data.tuple);
break; break;
case GST_OBJECT: case GST_OBJECT:
ret.data.number = x.data.object->count; ret.data.integer = x.data.object->count;
break; break;
} }
} }
gst_c_return(vm, ret); gst_c_return(vm, ret);
} }
/* Get nth argument, not including first argument */ /* Convert to integer */
int gst_stl_select(Gst *vm) { int gst_stl_to_int(Gst *vm) {
GstValue selector; GstValue x = gst_arg(vm, 0);
uint32_t count, n; if (x.type == GST_INTEGER) gst_c_return(vm, x);
count = gst_count_args(vm); if (x.type == GST_REAL)
if (count == 0) gst_c_return(vm, gst_wrap_integer((GstInteger) x.data.real));
gst_c_throwc(vm, "select takes at least one argument"); else
selector = gst_arg(vm, 0); gst_c_throwc(vm, "expected number");
if (selector.type != GST_NUMBER) }
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP);
n = selector.data.number; /* Convert to integer */
gst_c_return(vm, gst_arg(vm, n + 1)); 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 */ /* Get a slice of a sequence */
@ -178,7 +170,7 @@ int gst_stl_slice(Gst *vm) {
const GstValue *data; const GstValue *data;
uint32_t length; uint32_t length;
uint32_t newlength; uint32_t newlength;
GstNumber num; GstInteger num;
/* Get data */ /* Get data */
x = gst_arg(vm, 0); x = gst_arg(vm, 0);
@ -189,18 +181,18 @@ int gst_stl_slice(Gst *vm) {
if (count < 2) { if (count < 2) {
from = 0; from = 0;
} else { } else {
if (!gst_check_number(vm, 1, &num)) if (!gst_check_integer(vm, 1, &num))
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP); gst_c_throwc(vm, GST_EXPECTED_INTEGER);
from = gst_to_index(num, length); from = gst_startrange(num, length);
} }
/* Get to index */ /* Get to index */
if (count < 3) { if (count < 3) {
to = length; to = length;
} else { } else {
if (!gst_check_number(vm, 2, &num)) if (!gst_check_integer(vm, 2, &num))
gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP); gst_c_throwc(vm, GST_EXPECTED_INTEGER);
to = gst_to_endrange(num, length); to = gst_endrange(num, length);
} }
/* Check from bad bounds */ /* Check from bad bounds */
@ -232,8 +224,11 @@ int gst_stl_type(Gst *vm) {
switch (x.type) { switch (x.type) {
default: default:
break; break;
case GST_NUMBER: case GST_REAL:
typestr = "number"; typestr = "real";
break;
case GST_INTEGER:
typestr = "integer";
break; break;
case GST_BOOLEAN: case GST_BOOLEAN:
typestr = "boolean"; typestr = "boolean";
@ -419,9 +414,9 @@ int gst_stl_ensure(Gst *vm) {
GstValue cap = gst_arg(vm, 1); GstValue cap = gst_arg(vm, 1);
if (ds.type != GST_ARRAY) if (ds.type != GST_ARRAY)
gst_c_throwc(vm, "expected array"); gst_c_throwc(vm, "expected array");
if (cap.type != GST_NUMBER) if (cap.type != GST_INTEGER)
gst_c_throwc(vm, "expected number"); gst_c_throwc(vm, GST_EXPECTED_INTEGER);
gst_array_ensure(vm, ds.data.array, (uint32_t) cap.data.number); gst_array_ensure(vm, ds.data.array, (uint32_t) cap.data.integer);
gst_c_return(vm, ds); gst_c_return(vm, ds);
} }
@ -464,8 +459,8 @@ int gst_stl_tostring(Gst *vm) {
/* Exit */ /* Exit */
int gst_stl_exit(Gst *vm) { int gst_stl_exit(Gst *vm) {
int ret; int ret;
GstValue exitValue = gst_arg(vm, 0); GstValue x = gst_arg(vm, 0);
ret = (exitValue.type == GST_NUMBER) ? exitValue.data.number : 0; ret = x.type == GST_INTEGER ? x.data.integer : (x.type == GST_REAL ? x.data.real : 0);
exit(ret); exit(ret);
return GST_RETURN_OK; return GST_RETURN_OK;
} }
@ -532,31 +527,6 @@ int gst_stl_open(Gst *vm) {
gst_c_return(vm, gst_wrap_userdata(fp)); 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. */ /* 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_lessthaneq},
{">=", gst_stl_greaterthaneq}, {">=", gst_stl_greaterthaneq},
{"length", gst_stl_length}, {"length", gst_stl_length},
{"to-integer", gst_stl_to_int},
{"to-real", gst_stl_to_real},
{"type", gst_stl_type}, {"type", gst_stl_type},
{"select", gst_stl_select},
{"slice", gst_stl_slice}, {"slice", gst_stl_slice},
{"array", gst_stl_array}, {"array", gst_stl_array},
{"tuple", gst_stl_tuple}, {"tuple", gst_stl_tuple},

View File

@ -51,7 +51,8 @@ int gst_check_##NAME(Gst *vm, uint32_t i, TYPE (*out)) {\
return 1;\ 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(boolean, int, GST_BOOLEAN, boolean)
GST_WRAP_DEFINE(string, const uint8_t *, GST_STRING, string) GST_WRAP_DEFINE(string, const uint8_t *, GST_STRING, string)
GST_WRAP_DEFINE(array, GstArray *, GST_ARRAY, array) 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; return 0;
} }
/* Allow negative indexing to get from end of array like structure */ GstReal gst_integer_to_real(GstInteger x) {
/* This probably isn't very fast - look at Lua conversion function. return (GstReal) x;
* 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;
}
} }
int32_t gst_to_endrange(GstNumber raw, int64_t len) { GstInteger gst_real_to_integer(GstReal x) {
int32_t toInt = raw; return (GstInteger) x;
if ((GstNumber) toInt == raw) { }
/* We were able to convert */
if (toInt < 0 && len > 0) { GstInteger gst_startrange(GstInteger raw, uint32_t len) {
/* Index from end */ if (raw > len)
if (toInt < -len - 1) return -1; return -1;
return len + toInt + 1; if (raw < 0)
} else { return len + raw;
/* Normal indexing */ return raw;
if (toInt >= len) return -1; }
return toInt;
} GstInteger gst_endrange(GstInteger raw, uint32_t len) {
} else { if (raw > len)
return -1; 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 */ /* Temporary buffer size */
#define GST_BUFSIZE 36 #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]; uint8_t buf[GST_BUFSIZE];
/* TODO - not depend on stdio */
int count = snprintf((char *) buf, GST_BUFSIZE, "%.21g", x); int count = snprintf((char *) buf, GST_BUFSIZE, "%.21g", x);
return gst_string_b(vm, buf, (uint32_t) count); 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"; static const char *HEX_CHARACTERS = "0123456789abcdef";
#define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)]) #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: case GST_NIL:
return gst_string_c(vm, "nil"); return gst_string_c(vm, "nil");
case GST_BOOLEAN: case GST_BOOLEAN:
if (x.data.boolean) { if (x.data.boolean)
return gst_string_c(vm, "true"); return gst_string_c(vm, "true");
} else { else
return gst_string_c(vm, "false"); return gst_string_c(vm, "false");
} case GST_REAL:
case GST_NUMBER: return real_to_string(vm, x.data.real);
return number_to_string(vm, x.data.number); case GST_INTEGER:
return integer_to_string(vm, x.data.integer);
case GST_ARRAY: case GST_ARRAY:
return string_description(vm, "array", x.data.pointer); return string_description(vm, "array", x.data.pointer);
case GST_TUPLE: case GST_TUPLE:
@ -125,8 +131,11 @@ int gst_equals(GstValue x, GstValue y) {
case GST_BOOLEAN: case GST_BOOLEAN:
result = (x.data.boolean == y.data.boolean); result = (x.data.boolean == y.data.boolean);
break; break;
case GST_NUMBER: case GST_REAL:
result = (x.data.number == y.data.number); result = (x.data.real == y.data.real);
break;
case GST_INTEGER:
result = (x.data.integer == y.data.integer);
break; break;
default: default:
/* compare pointers */ /* compare pointers */
@ -147,17 +156,6 @@ uint32_t gst_hash(GstValue x) {
case GST_BOOLEAN: case GST_BOOLEAN:
hash = x.data.boolean; hash = x.data.boolean;
break; 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: case GST_STRING:
hash = gst_string_hash(x.data.string); hash = gst_string_hash(x.data.string);
break; break;
@ -168,15 +166,7 @@ uint32_t gst_hash(GstValue x) {
hash = gst_struct_hash(x.data.st); hash = gst_struct_hash(x.data.st);
break; break;
default: default:
/* Cast the pointer */ hash = x.data.dwords[0] ^ x.data.dwords[1];
{
union {
void * pointer;
uint32_t hash;
} u;
u.pointer = x.data.pointer;
hash = u.hash;
}
break; break;
} }
return hash; return hash;
@ -196,12 +186,17 @@ int gst_compare(GstValue x, GstValue y) {
} else { } else {
return x.data.boolean ? 1 : -1; return x.data.boolean ? 1 : -1;
} }
case GST_NUMBER: case GST_REAL:
/* TODO: define behavior for NaN and infinties. */ if (x.data.real == y.data.real) {
if (x.data.number == y.data.number) {
return 0; return 0;
} else { } 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: case GST_STRING:
return gst_string_compare(x.data.string, y.data.string); return gst_string_compare(x.data.string, y.data.string);
@ -236,45 +231,38 @@ int gst_compare(GstValue x, GstValue y) {
return 1; 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. /* Get a value out af an associated data structure.
* Returns possible c error message, and NULL for no error. The * Returns possible c error message, and NULL for no error. The
* useful return value is written to out on success */ * useful return value is written to out on success */
const char *gst_get(GstValue ds, GstValue key, GstValue *out) { const char *gst_get(GstValue ds, GstValue key, GstValue *out) {
int32_t index; GstInteger index;
GstValue ret; GstValue ret;
switch (ds.type) { switch (ds.type) {
case GST_ARRAY: case GST_ARRAY:
if (key.type != GST_NUMBER) return "expected numeric key"; if (key.type != GST_INTEGER) return "expected integer key";
index = gst_to_index(key.data.number, ds.data.array->count); index = gst_startrange(key.data.integer, ds.data.array->count);
if (index == -1) return "invalid array access"; if (index < 0) return "invalid array access";
ret = ds.data.array->data[index]; ret = ds.data.array->data[index];
break; break;
case GST_TUPLE: case GST_TUPLE:
if (key.type != GST_NUMBER) return "expected numeric key"; if (key.type != GST_INTEGER) return "expected integer key";
index = gst_to_index(key.data.number, gst_tuple_length(ds.data.tuple)); index = gst_startrange(key.data.integer, gst_tuple_length(ds.data.tuple));
if (index < 0) return "invalid tuple access"; if (index < 0) return "invalid tuple access";
ret = ds.data.tuple[index]; ret = ds.data.tuple[index];
break; break;
case GST_BYTEBUFFER: case GST_BYTEBUFFER:
if (key.type != GST_NUMBER) return "expected numeric key"; if (key.type != GST_INTEGER) return "expected integer key";
index = gst_to_index(key.data.number, ds.data.buffer->count); index = gst_startrange(key.data.integer, ds.data.buffer->count);
if (index == -1) return "invalid buffer access"; if (index < 0) return "invalid buffer access";
ret.type = GST_NUMBER; ret.type = GST_INTEGER;
ret.data.number = ds.data.buffer->data[index]; ret.data.integer = ds.data.buffer->data[index];
break; break;
case GST_STRING: case GST_STRING:
if (key.type != GST_NUMBER) return "expected numeric key"; if (key.type != GST_INTEGER) return "expected integer key";
index = gst_to_index(key.data.number, gst_string_length(ds.data.string)); index = gst_startrange(key.data.integer, gst_string_length(ds.data.string));
if (index == -1) return "invalid string access"; if (index < 0) return "invalid string access";
ret.type = GST_NUMBER; ret.type = GST_INTEGER;
ret.data.number = ds.data.string[index]; ret.data.integer = ds.data.string[index];
break; break;
case GST_STRUCT: case GST_STRUCT:
ret = gst_struct_get(ds.data.st, key); 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 /* Set a value in an associative data structure. Returns possible
* error message, and NULL if no error. */ * error message, and NULL if no error. */
const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) { const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) {
int32_t index; GstInteger index;
switch (ds.type) { switch (ds.type) {
case GST_ARRAY: case GST_ARRAY:
if (key.type != GST_NUMBER) return "expected numeric key"; if (key.type != GST_INTEGER) return "expected integer key";
index = gst_to_index(key.data.number, ds.data.array->count); index = gst_startrange(key.data.integer, ds.data.array->count);
if (index == -1) return "invalid array access"; if (index < 0) return "invalid array access";
ds.data.array->data[index] = value; ds.data.array->data[index] = value;
break; break;
case GST_BYTEBUFFER: case GST_BYTEBUFFER:
if (key.type != GST_NUMBER) return "expected numeric key"; if (key.type != GST_INTEGER) return "expected integer key";
if (value.type != GST_NUMBER) return "expected numeric value"; if (value.type != GST_INTEGER) return "expected integer value";
index = gst_to_index(key.data.number, ds.data.buffer->count); index = gst_startrange(key.data.integer, ds.data.buffer->count);
if (index == -1) return "invalid buffer access"; if (index < 0) return "invalid buffer access";
ds.data.buffer->data[index] = to_byte(value.data.number); ds.data.buffer->data[index] = (uint8_t) value.data.integer;
break; break;
case GST_OBJECT: case GST_OBJECT:
gst_object_put(vm, ds.data.object, key, value); 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 */ /* Get the length of an object. Returns errors for invalid types */
int gst_length(Gst *vm, GstValue x, GstValue *len) { GstInteger gst_length(Gst *vm, GstValue x) {
uint32_t length; GstInteger length;
switch (x.type) { switch (x.type) {
default: default:
vm->ret = gst_string_cv(vm, "cannot get length"); 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; length = x.data.object->count;
break; break;
} }
/* Normal numeric return */ return length;
len->type = GST_NUMBER;
len->data.number = (GstNumber) length;
return GST_RETURN_OK;
} }

View File

@ -24,8 +24,6 @@
static const char GST_NO_UPVALUE[] = "no upvalue"; static const char GST_NO_UPVALUE[] = "no upvalue";
static const char GST_EXPECTED_FUNCTION[] = "expected function"; 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. */ /* Start running the VM from where it left off. */
int gst_continue(Gst *vm) { int gst_continue(Gst *vm) {
@ -73,8 +71,8 @@ int gst_continue(Gst *vm) {
continue; continue;
case GST_OP_I16: /* Load Small Integer */ case GST_OP_I16: /* Load Small Integer */
temp.type = GST_NUMBER; temp.type = GST_INTEGER;
temp.data.number = ((int16_t *)(pc))[2]; temp.data.integer = ((int16_t *)(pc))[2];
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 3; pc += 3;
continue; continue;
@ -132,15 +130,22 @@ int gst_continue(Gst *vm) {
continue; continue;
case GST_OP_I32: /* Load 32 bit integer */ case GST_OP_I32: /* Load 32 bit integer */
temp.type = GST_NUMBER; temp.type = GST_INTEGER;
temp.data.number = *((int32_t *)(pc + 2)); temp.data.integer = *((int32_t *)(pc + 2));
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 4; pc += 4;
continue; 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 */ case GST_OP_F64: /* Load 64 bit float */
temp.type = GST_NUMBER; temp.type = GST_REAL;
temp.data.number = (GstNumber) *((double *)(pc + 2)); temp.data.real = (GstReal) *((double *)(pc + 2));
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 6; pc += 6;
continue; continue;
@ -310,81 +315,6 @@ int gst_continue(Gst *vm) {
} }
break; 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 */ case GST_OP_ARR: /* Array literal */
{ {
uint32_t i; uint32_t i;

View File

@ -83,10 +83,10 @@
/* Macros for referencing a stack frame given a stack */ /* Macros for referencing a stack frame given a stack */
#define gst_frame_callee(s) (*(s - 1)) #define gst_frame_callee(s) (*(s - 1))
#define gst_frame_size(s) ((s - 2)->data.hws[0]) #define gst_frame_size(s) ((s - 2)->data.words[0])
#define gst_frame_prevsize(s) ((s - 2)->data.hws[1]) #define gst_frame_prevsize(s) ((s - 2)->data.words[1])
#define gst_frame_args(s) ((s - 2)->data.hws[2]) #define gst_frame_args(s) ((s - 2)->data.words[2])
#define gst_frame_ret(s) ((s - 2)->data.hws[3]) #define gst_frame_ret(s) ((s - 2)->data.words[3])
#define gst_frame_pc(s) ((s - 3)->data.u16p) #define gst_frame_pc(s) ((s - 3)->data.u16p)
#define gst_frame_env(s) ((s - 4)->data.env) #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) #define GST_OUT_OF_MEMORY do { printf("out of memory\n"); exit(1); } while (0)
#endif #endif
/* Max search depth for classes. */
#define GST_MAX_SEARCH_DEPTH 128
/* Various types */ /* Various types */
typedef enum GstType { typedef enum GstType {
GST_NIL = 0, GST_NIL = 0,
GST_NUMBER, GST_REAL,
GST_INTEGER,
GST_BOOLEAN, GST_BOOLEAN,
GST_STRING, GST_STRING,
GST_ARRAY, GST_ARRAY,
@ -140,8 +138,9 @@ typedef struct Gst Gst;
typedef struct GstValue GstValue; typedef struct GstValue GstValue;
/* All of the gst types */ /* All of the gst types */
typedef double GstNumber; typedef double GstReal;
typedef uint8_t GstBoolean; typedef int64_t GstInteger;
typedef int GstBoolean;
typedef struct GstFunction GstFunction; typedef struct GstFunction GstFunction;
typedef struct GstArray GstArray; typedef struct GstArray GstArray;
typedef struct GstBuffer GstBuffer; typedef struct GstBuffer GstBuffer;
@ -167,7 +166,8 @@ struct GstModuleItem {
/* Union datatype */ /* Union datatype */
union GstValueUnion { union GstValueUnion {
GstBoolean boolean; GstBoolean boolean;
GstNumber number; GstReal real;
GstInteger integer;
GstArray *array; GstArray *array;
GstBuffer *buffer; GstBuffer *buffer;
GstObject *object; GstObject *object;
@ -179,12 +179,13 @@ union GstValueUnion {
GstFuncDef *def; GstFuncDef *def;
const GstValue *st; const GstValue *st;
const uint8_t *string; const uint8_t *string;
const char *cstring; /* Alias for ease of use from c */
/* Indirectly used union members */ /* Indirectly used union members */
uint16_t *u16p; uint16_t *u16p;
uint16_t hws[4]; uint32_t dwords[2];
uint16_t words[4];
uint8_t bytes[8]; uint8_t bytes[8];
void *pointer; void *pointer;
const char *cstring;
}; };
/* The general gst value type. Contains a large union and /* The general gst value type. Contains a large union and
@ -296,29 +297,20 @@ struct Gst {
/* Bytecode */ /* Bytecode */
enum GstOpCode { 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_FLS, /* Load false */
GST_OP_TRU, /* Load true */ GST_OP_TRU, /* Load true */
GST_OP_NIL, /* Load nil */ GST_OP_NIL, /* Load nil */
GST_OP_I16, /* Load 16 bit signed integer */
GST_OP_UPV, /* Load upvalue */ GST_OP_UPV, /* Load upvalue */
GST_OP_JIF, /* Jump if */ GST_OP_JIF, /* Jump if */
GST_OP_JMP, /* Jump */ GST_OP_JMP, /* Jump */
GST_OP_SUV, /* Set upvalue */ GST_OP_SUV, /* Set upvalue */
GST_OP_CST, /* Load constant */ GST_OP_CST, /* Load constant */
GST_OP_I16, /* Load 16 bit signed integer */
GST_OP_I32, /* Load 32 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_F64, /* Load 64 bit IEEE double */
GST_OP_MOV, /* Move value */ GST_OP_MOV, /* Move value */
GST_OP_CLN, /* Create a closure */ 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_ARR, /* Create array */
GST_OP_DIC, /* Create object */ GST_OP_DIC, /* Create object */
GST_OP_TUP, /* Create tuple */ 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 char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value);
const uint8_t *gst_to_string(Gst *vm, GstValue x); const uint8_t *gst_to_string(Gst *vm, GstValue x);
uint32_t gst_hash(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 */ /* Serialization */
@ -464,6 +456,7 @@ int gst_length(Gst *vm, GstValue x, GstValue *len);
* Byte 215: LUdata - [value meta][u32 length]*[u8... bytes] * Byte 215: LUdata - [value meta][u32 length]*[u8... bytes]
* Byte 216: CFunc - [u32 length]*[u8... idstring] * Byte 216: CFunc - [u32 length]*[u8... idstring]
* Byte 217: Ref - [u32 id] * Byte 217: Ref - [u32 id]
* Byte 218: Integer - [i64 value]
*/ */
const char *gst_deserialize( const char *gst_deserialize(
@ -517,7 +510,8 @@ GstValue gst_register_get(Gst *vm, const char *name);
/* Wrap data in GstValue */ /* Wrap data in GstValue */
GstValue gst_wrap_nil(); 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_boolean(int x);
GstValue gst_wrap_string(const uint8_t *x); GstValue gst_wrap_string(const uint8_t *x);
GstValue gst_wrap_array(GstArray *x); GstValue gst_wrap_array(GstArray *x);
@ -534,7 +528,8 @@ GstValue gst_wrap_funcdef(GstFuncDef *x);
/* Check data from arguments */ /* Check data from arguments */
int gst_check_nil(Gst *vm, uint32_t i); 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_boolean(Gst *vm, uint32_t i, int (*x));
int gst_check_string(Gst *vm, uint32_t i, const uint8_t *(*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)); 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 */ /* Misc */
/****/ /****/
int32_t gst_to_index(GstNumber raw, int64_t len); GstReal gst_integer_to_real(GstInteger x);
int32_t gst_to_endrange(GstNumber raw, int64_t len); 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 #endif // GST_H_defined