mirror of
https://github.com/janet-lang/janet
synced 2024-12-28 17:30:31 +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:
parent
81987dca45
commit
a54548eaa0
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
41
core/parse.c
41
core/parse.c
@ -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;
|
||||
|
@ -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 */
|
||||
|
189
core/stl.c
189
core/stl.c
@ -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},
|
||||
|
58
core/util.c
58
core/util.c
@ -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;
|
||||
}
|
||||
|
127
core/value.c
127
core/value.c
@ -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;
|
||||
}
|
||||
|
||||
|
96
core/vm.c
96
core/vm.c
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user