Rename everything to be prefixed with gst. No particluar meaning

or reason for that name, but its available and it irked me to see
non prefixed c code for something that is supposed to be emeddable.
This commit is contained in:
Calvin Rose 2017-02-15 21:02:00 -05:00
parent 8cdc0610e3
commit 6677dff337
14 changed files with 1407 additions and 1422 deletions

826
compile.c

File diff suppressed because it is too large Load Diff

View File

@ -4,21 +4,21 @@
#include "datatypes.h"
/* Initialize the Compiler */
void CompilerInit(Compiler * c, VM * vm);
void gst_compiler(GstCompiler *c, Gst *vm);
/* Register a global for the compilation environment. */
void CompilerAddGlobal(Compiler * c, const char * name, Value x);
void gst_compiler_add_global(GstCompiler *c, const char *name, GstValue x);
/* Register a global c function for the compilation environment. */
void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f);
void gst_compiler_add_global_cfunction(GstCompiler *c, const char *name, GstCFunction f);
/* Compile a function that evaluates the given form. */
Func * CompilerCompile(Compiler * c, Value form);
GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form);
/* Macro expansion. Macro expansion happens prior to the compilation process
* and is completely separate. This allows the compilation to not have to worry
* about garbage collection and other issues that would complicate both the
* runtime and the compilation. */
int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out);
int gst_macro_expand(Gst *vm, GstValue x, GstObject *macros, GstValue *out);
#endif /* end of include guard: COMPILE_H_9VXF71HY */

View File

@ -4,227 +4,234 @@
#include <stdint.h>
#include <setjmp.h>
typedef enum Type {
TYPE_NIL = 0,
TYPE_NUMBER,
TYPE_BOOLEAN,
TYPE_STRING,
TYPE_ARRAY,
TYPE_THREAD,
TYPE_BYTEBUFFER,
TYPE_FUNCTION,
TYPE_CFUNCTION,
TYPE_DICTIONARY
} Type;
typedef enum GstType {
GST_NIL = 0,
GST_NUMBER,
GST_BOOLEAN,
GST_STRING,
GST_ARRAY,
GST_THREAD,
GST_BYTEBUFFER,
GST_FUNCTION,
GST_CFUNCTION,
GST_OBJECT
} GstType;
typedef double Number;
typedef uint8_t Boolean;
typedef struct VM VM;
typedef struct Value Value;
typedef Value (*CFunction)(VM * vm);
typedef struct Func Func;
typedef struct FuncDef FuncDef;
typedef struct FuncEnv FuncEnv;
typedef union ValueData ValueData;
typedef struct DictBucket DictBucket;
typedef struct Array Array;
typedef struct Buffer Buffer;
typedef struct Dictionary Dictionary;
typedef struct DictionaryIterator DictionaryIterator;
typedef struct Parser Parser;
typedef struct ParseState ParseState;
typedef struct Scope Scope;
typedef struct Compiler Compiler;
typedef struct Thread Thread;
typedef struct StackFrame StackFrame;
/* The state of the virtual machine */
typedef struct Gst Gst;
union ValueData {
Boolean boolean;
Number number;
uint8_t * string;
Array * array;
Buffer * buffer;
Dictionary * dict;
Func * func;
Thread * thread;
void * pointer;
CFunction cfunction;
uint16_t u16[4];
uint8_t u8[8];
} data;
/* A general gst value type */
typedef struct GstValue GstValue;
struct Value {
Type type;
ValueData data;
/* All of the gst types */
typedef double GstNumber;
typedef uint8_t GstBoolean;
typedef struct GstFunction GstFunction;
typedef struct GstArray GstArray;
typedef struct GstBuffer GstBuffer;
typedef struct GstObject GstObject;
typedef struct GstThread GstThread;
typedef GstValue (*GstCFunction)(Gst * vm);
/* Implementation details */
typedef struct GstParser GstParser;
typedef struct GstCompiler GstCompiler;
typedef struct GstFuncDef GstFuncDef;
typedef struct GstFuncEnv GstFuncEnv;
/* Definitely implementation details */
typedef struct GstStackFrame GstStackFrame;
typedef struct GstParseState GstParseState;
typedef struct GstBucket GstBucket;
typedef struct GstScope GstScope;
/* The general gst value type. Contains a large union and
* the type information of the value */
struct GstValue {
GstType type;
union {
/* The various types */
GstBoolean boolean;
GstNumber number;
GstArray *array;
GstBuffer *buffer;
GstObject *object;
GstThread *thread;
GstCFunction cfunction;
GstFunction *function;
uint8_t *string;
void *pointer;
} data;
};
struct Thread {
/* A lightweight thread in gst. Does not correspond to
* operating system threads. Used in coroutines. */
struct GstThread {
uint32_t count;
uint32_t capacity;
Value * data;
GstValue *data;
enum {
THREAD_PENDING = 0,
THREAD_ALIVE,
TRHEAD_DEAD
GST_THREAD_PENDING = 0,
GST_THREAD_ALIVE,
GST_TRHEAD_DEAD
} status;
};
struct Array {
/* A dynamic array type */
struct GstArray {
uint32_t count;
uint32_t capacity;
Value * data;
GstValue *data;
uint32_t flags;
};
struct Buffer {
/* A bytebuffer type. Used as a mutable string or string builder. */
struct GstBuffer {
uint32_t count;
uint32_t capacity;
uint8_t * data;
uint8_t *data;
uint32_t flags;
};
struct Dictionary {
/* The main Gst type, an obect. Objects are just hashtables with some meta
* information attached in the meta value */
struct GstObject {
uint32_t count;
uint32_t capacity;
DictBucket ** buckets;
GstBucket **buckets;
uint32_t flags;
Value meta;
GstValue meta;
};
struct DictionaryIterator {
Dictionary * dict;
uint32_t index;
DictBucket * bucket;
};
struct FuncDef {
/* A function defintion. Contains information need to instatiate closures. */
struct GstFuncDef {
uint32_t locals;
uint32_t arity;
uint32_t literalsLen;
uint32_t byteCodeLen;
Value * literals; /* Contains strings, FuncDefs, etc. */
uint16_t * byteCode;
GstValue *literals; /* Contains strings, FuncDefs, etc. */
uint16_t *byteCode;
};
struct FuncEnv {
Thread * thread; /* When nil, index the local values */
/* A fuction environment */
struct GstFuncEnv {
GstThread *thread; /* When nil, index the local values */
uint32_t stackOffset; /* Used as environment size when off stack */
Value * values;
GstValue *values;
};
struct Func {
FuncDef * def;
FuncEnv * env;
Func * parent;
/* A function */
struct GstFunction {
GstFuncDef *def;
GstFuncEnv *env;
GstFunction *parent;
};
struct DictBucket {
Value key;
Value value;
DictBucket * next;
/* A hash table bucket in an object */
struct GstBucket {
GstValue key;
GstValue value;
GstBucket *next;
};
struct StackFrame {
Value callee;
/* A stack frame in the VM */
struct GstStackFrame {
GstValue callee;
uint16_t size;
uint16_t prevSize;
uint16_t ret;
FuncEnv * env;
uint16_t * pc;
GstFuncEnv *env;
uint16_t *pc;
};
struct VM {
/* The VM state */
struct Gst {
/* Garbage collection */
void * blocks;
void *blocks;
uint32_t memoryInterval;
uint32_t nextCollection;
uint32_t black : 1;
uint32_t lock : 31;
/* Thread */
uint16_t * pc;
Thread * thread;
Value * base;
StackFrame * frame;
uint16_t *pc;
GstThread *thread;
GstValue *base;
GstStackFrame *frame;
/* Return state */
const char * error;
const char *error;
jmp_buf jump;
Value ret; /* Returned value from VMStart */
GstValue ret; /* Returned value from VMStart */
/* Object definitions */
Value metas[TYPE_DICTIONARY];
GstValue metas[GST_OBJECT];
};
/* Parsing */
struct Parser {
VM * vm;
const char * error;
ParseState * data;
Value value;
struct GstParser {
Gst *vm;
const char *error;
GstParseState *data;
GstValue value;
uint32_t count;
uint32_t cap;
uint32_t index;
enum {
PARSER_PENDING = 0,
PARSER_FULL,
PARSER_ERROR
GST_PARSER_PENDING = 0,
GST_PARSER_FULL,
GST_PARSER_ERROR
} status;
};
/* Compiling */
struct Compiler {
VM * vm;
const char * error;
/* Compilation state */
struct GstCompiler {
Gst *vm;
const char *error;
jmp_buf onError;
Scope * tail;
Array * env;
Buffer * buffer;
GstScope *tail;
GstArray *env;
GstBuffer *buffer;
};
/* String utils */
#define VStringRaw(s) ((uint32_t *)(s) - 2)
#define VStringSize(v) (VStringRaw(v)[0])
#define VStringHash(v) (VStringRaw(v)[1])
#define gst_string_raw(s) ((uint32_t *)(s) - 2)
#define gst_string_length(v) (gst_string_raw(v)[0])
#define gst_string_hash(v) (gst_string_raw(v)[1])
/* Bytecode */
enum OpCode {
VM_OP_ADD = 0, /* 0x0000 */
VM_OP_SUB, /* 0x0001 */
VM_OP_MUL, /* 0x0002 */
VM_OP_DIV, /* 0x0003 */
VM_OP_NOT, /* 0x0004 */
VM_OP_LD0, /* 0x0005 */
VM_OP_LD1, /* 0x0006 */
VM_OP_FLS, /* 0x0007 */
VM_OP_TRU, /* 0x0008 */
VM_OP_NIL, /* 0x0009 */
VM_OP_I16, /* 0x000a */
VM_OP_UPV, /* 0x000b */
VM_OP_JIF, /* 0x000c */
VM_OP_JMP, /* 0x000d */
VM_OP_CAL, /* 0x000e */
VM_OP_RET, /* 0x000f */
VM_OP_SUV, /* 0x0010 */
VM_OP_CST, /* 0x0011 */
VM_OP_I32, /* 0x0012 */
VM_OP_F64, /* 0x0013 */
VM_OP_MOV, /* 0x0014 */
VM_OP_CLN, /* 0x0015 */
VM_OP_EQL, /* 0x0016 */
VM_OP_LTN, /* 0x0017 */
VM_OP_LTE, /* 0x0018 */
VM_OP_ARR, /* 0x0019 */
VM_OP_DIC, /* 0x001a */
VM_OP_TCL, /* 0x001b */
VM_OP_ADM, /* 0x001c */
VM_OP_SBM, /* 0x001d */
VM_OP_MUM, /* 0x001e */
VM_OP_DVM, /* 0x001f */
VM_OP_RTN, /* 0x0020 */
VM_OP_SET, /* 0x0021 */
VM_OP_GET /* 0x0022 */
enum GstOpCode {
GST_OP_ADD = 0, /* 0x0000 */
GST_OP_SUB, /* 0x0001 */
GST_OP_MUL, /* 0x0002 */
GST_OP_DIV, /* 0x0003 */
GST_OP_NOT, /* 0x0004 */
GST_OP_LD0, /* 0x0005 */
GST_OP_LD1, /* 0x0006 */
GST_OP_FLS, /* 0x0007 */
GST_OP_TRU, /* 0x0008 */
GST_OP_NIL, /* 0x0009 */
GST_OP_I16, /* 0x000a */
GST_OP_UPV, /* 0x000b */
GST_OP_JIF, /* 0x000c */
GST_OP_JMP, /* 0x000d */
GST_OP_CAL, /* 0x000e */
GST_OP_RET, /* 0x000f */
GST_OP_SUV, /* 0x0010 */
GST_OP_CST, /* 0x0011 */
GST_OP_I32, /* 0x0012 */
GST_OP_F64, /* 0x0013 */
GST_OP_MOV, /* 0x0014 */
GST_OP_CLN, /* 0x0015 */
GST_OP_EQL, /* 0x0016 */
GST_OP_LTN, /* 0x0017 */
GST_OP_LTE, /* 0x0018 */
GST_OP_ARR, /* 0x0019 */
GST_OP_DIC, /* 0x001a */
GST_OP_TCL, /* 0x001b */
GST_OP_ADM, /* 0x001c */
GST_OP_SBM, /* 0x001d */
GST_OP_MUM, /* 0x001e */
GST_OP_DVM, /* 0x001f */
GST_OP_RTN, /* 0x0020 */
GST_OP_SET, /* 0x0021 */
GST_OP_GET /* 0x0022 */
};
#endif

212
disasm.c
View File

@ -4,17 +4,17 @@
#define OP_WIDTH 20
/* Print various register and arguments to instructions */
static void dasmPrintSlot(FILE * out, uint16_t index) { fprintf(out, "%d ", index); }
static void dasmPrintI16(FILE * out, int16_t number) { fprintf(out, "#%d ", number); }
static void dasmPrintI32(FILE * out, int32_t number) { fprintf(out, "#%d ", number); }
static void dasmPrintF64(FILE * out, double number) { fprintf(out, "#%f ", number); }
static void dasmPrintLiteral(FILE * out, uint16_t index) { fprintf(out, "(%d) ", index); }
static void dasmPrintUpValue(FILE * out, uint16_t level, uint16_t index) {
static void dasm_print_slot(FILE * out, uint16_t index) { fprintf(out, "%d ", index); }
static void dasm_print_i16(FILE * out, int16_t number) { fprintf(out, "#%d ", number); }
static void dasm_print_i32(FILE * out, int32_t number) { fprintf(out, "#%d ", number); }
static void dasm_print_f64(FILE * out, double number) { fprintf(out, "#%f ", number); }
static void dasm_print_literal(FILE * out, uint16_t index) { fprintf(out, "(%d) ", index); }
static void dasm_print_upvalue(FILE * out, uint16_t level, uint16_t index) {
fprintf(out, "<%d, %d> ", level, index);
}
/* Print the name of the argument but pad it */
static void dasmPrintArg(FILE * out, const char * name) {
static void dasm_print_arg(FILE * out, const char * name) {
uint32_t i = 0;
char c;
while ((c = *name++)) {
@ -26,44 +26,44 @@ static void dasmPrintArg(FILE * out, const char * name) {
}
/* Print instructions that take a fixed number of arguments */
static uint32_t dasmPrintFixedOp(FILE * out, const uint16_t * current,
static uint32_t dasm_fixed_op(FILE * out, const uint16_t * current,
const char * name, uint32_t size) {
uint32_t i;
dasmPrintArg(out, name);
dasm_print_arg(out, name);
for (i = 1; i <= size; ++i) {
dasmPrintSlot(out, current[i]);
dasm_print_slot(out, current[i]);
}
return size + 1;
}
/* Print instructions that take a variable number of arguments */
static uint32_t dasmPrintVarArgOp(FILE * out, const uint16_t * current,
static uint32_t dasm_varg_op(FILE * out, const uint16_t * current,
const char * name, uint32_t extra) {
uint32_t i, argCount;
dasmPrintArg(out, name);
dasm_print_arg(out, name);
for (i = 0; i < extra; ++i) {
dasmPrintSlot(out, current[i + 1]);
dasm_print_slot(out, current[i + 1]);
}
argCount = current[extra + 1];
fprintf(out, ": "); /* Argument separator */
for (i = 0; i < argCount; ++i) {
dasmPrintSlot(out, current[i + extra + 2]);
dasm_print_slot(out, current[i + extra + 2]);
}
return argCount + extra + 2;
}
/* Print the disassembly for a function definition */
void dasmFuncDef(FILE * out, FuncDef * def) {
dasm(out, def->byteCode, def->byteCodeLen);
void gst_dasm_funcdef(FILE * out, GstFuncDef * def) {
gst_dasm(out, def->byteCode, def->byteCodeLen);
}
/* Print the disassembly for a function */
void dasmFunc(FILE * out, Func * f) {
dasm(out, f->def->byteCode, f->def->byteCodeLen);
void gst_dasm_function(FILE * out, GstFunction * f) {
gst_dasm(out, f->def->byteCode, f->def->byteCodeLen);
}
/* Disassemble some bytecode and display it as opcode + arguments assembly */
void dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
uint16_t *current = byteCode;
uint16_t *end = byteCode + len;
@ -71,136 +71,136 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
while (current < end) {
switch (*current) {
case VM_OP_ADD:
current += dasmPrintFixedOp(out, current, "add", 3);
case GST_OP_ADD:
current += dasm_fixed_op(out, current, "add", 3);
break;
case VM_OP_SUB:
current += dasmPrintFixedOp(out, current, "sub", 3);
case GST_OP_SUB:
current += dasm_fixed_op(out, current, "sub", 3);
break;
case VM_OP_MUL:
current += dasmPrintFixedOp(out, current, "mul", 3);
case GST_OP_MUL:
current += dasm_fixed_op(out, current, "mul", 3);
break;
case VM_OP_DIV:
current += dasmPrintFixedOp(out, current, "div", 3);
case GST_OP_DIV:
current += dasm_fixed_op(out, current, "div", 3);
break;
case VM_OP_NOT:
current += dasmPrintFixedOp(out, current, "not", 2);
case GST_OP_NOT:
current += dasm_fixed_op(out, current, "not", 2);
break;
case VM_OP_LD0:
current += dasmPrintFixedOp(out, current, "load0", 1);
case GST_OP_LD0:
current += dasm_fixed_op(out, current, "load0", 1);
break;
case VM_OP_LD1:
current += dasmPrintFixedOp(out, current, "load1", 1);
case GST_OP_LD1:
current += dasm_fixed_op(out, current, "load1", 1);
break;
case VM_OP_FLS:
current += dasmPrintFixedOp(out, current, "loadFalse", 1);
case GST_OP_FLS:
current += dasm_fixed_op(out, current, "loadFalse", 1);
break;
case VM_OP_TRU:
current += dasmPrintFixedOp(out, current, "loadTrue", 1);
case GST_OP_TRU:
current += dasm_fixed_op(out, current, "loadTrue", 1);
break;
case VM_OP_NIL:
current += dasmPrintFixedOp(out, current, "loadNil", 1);
case GST_OP_NIL:
current += dasm_fixed_op(out, current, "loadNil", 1);
break;
case VM_OP_I16:
dasmPrintArg(out, "loadInt16");
dasmPrintSlot(out, current[1]);
dasmPrintI16(out, ((int16_t *)current)[2]);
case GST_OP_I16:
dasm_print_arg(out, "loadInt16");
dasm_print_slot(out, current[1]);
dasm_print_i16(out, ((int16_t *)current)[2]);
current += 3;
break;
case VM_OP_UPV:
dasmPrintArg(out, "loadUpValue");
dasmPrintSlot(out, current[1]);
dasmPrintUpValue(out, current[2], current[3]);
case GST_OP_UPV:
dasm_print_arg(out, "loadUpValue");
dasm_print_slot(out, current[1]);
dasm_print_upvalue(out, current[2], current[3]);
current += 4;
break;
case VM_OP_JIF:
dasmPrintArg(out, "jumpIf");
dasmPrintSlot(out, current[1]);
dasmPrintI32(out, ((int32_t *)(current + 2))[0]);
case GST_OP_JIF:
dasm_print_arg(out, "jumpIf");
dasm_print_slot(out, current[1]);
dasm_print_i32(out, ((int32_t *)(current + 2))[0]);
current += 4;
break;
case VM_OP_JMP:
dasmPrintArg(out, "jump");
dasmPrintI32(out, ((int32_t *)(current + 1))[0]);
case GST_OP_JMP:
dasm_print_arg(out, "jump");
dasm_print_i32(out, ((int32_t *)(current + 1))[0]);
current += 3;
break;
case VM_OP_CAL:
current += dasmPrintVarArgOp(out, current, "call", 2);
case GST_OP_CAL:
current += dasm_varg_op(out, current, "call", 2);
break;
case VM_OP_RET:
current += dasmPrintFixedOp(out, current, "return", 1);
case GST_OP_RET:
current += dasm_fixed_op(out, current, "return", 1);
break;
case VM_OP_SUV:
dasmPrintArg(out, "setUpValue");
dasmPrintSlot(out, current[1]);
dasmPrintUpValue(out, current[2], current[3]);
case GST_OP_SUV:
dasm_print_arg(out, "setUpValue");
dasm_print_slot(out, current[1]);
dasm_print_upvalue(out, current[2], current[3]);
current += 4;
break;
case VM_OP_CST:
dasmPrintArg(out, "loadLiteral");
dasmPrintSlot(out, current[1]);
dasmPrintLiteral(out, current[2]);
case GST_OP_CST:
dasm_print_arg(out, "loadLiteral");
dasm_print_slot(out, current[1]);
dasm_print_literal(out, current[2]);
current += 3;
break;
case VM_OP_I32:
dasmPrintArg(out, "loadInt32");
dasmPrintSlot(out, current[1]);
dasmPrintI32(out, ((int32_t *)(current + 2))[0]);
case GST_OP_I32:
dasm_print_arg(out, "loadInt32");
dasm_print_slot(out, current[1]);
dasm_print_i32(out, ((int32_t *)(current + 2))[0]);
current += 4;
break;
case VM_OP_F64:
dasmPrintArg(out, "loadFloat64");
dasmPrintSlot(out, current[1]);
dasmPrintF64(out, ((double *)(current + 2))[0]);
case GST_OP_F64:
dasm_print_arg(out, "loadFloat64");
dasm_print_slot(out, current[1]);
dasm_print_f64(out, ((double *)(current + 2))[0]);
current += 6;
break;
case VM_OP_MOV:
current += dasmPrintFixedOp(out, current, "move", 2);
case GST_OP_MOV:
current += dasm_fixed_op(out, current, "move", 2);
break;
case VM_OP_CLN:
dasmPrintArg(out, "makeClosure");
dasmPrintSlot(out, current[1]);
dasmPrintLiteral(out, current[2]);
case GST_OP_CLN:
dasm_print_arg(out, "makeClosure");
dasm_print_slot(out, current[1]);
dasm_print_literal(out, current[2]);
current += 3;
break;
case VM_OP_EQL:
current += dasmPrintFixedOp(out, current, "equals", 3);
case GST_OP_EQL:
current += dasm_fixed_op(out, current, "equals", 3);
break;
case VM_OP_LTN:
current += dasmPrintFixedOp(out, current, "lessThan", 3);
case GST_OP_LTN:
current += dasm_fixed_op(out, current, "lessThan", 3);
break;
case VM_OP_LTE:
current += dasmPrintFixedOp(out, current, "lessThanEquals", 3);
case GST_OP_LTE:
current += dasm_fixed_op(out, current, "lessThanEquals", 3);
break;
case VM_OP_ARR:
current += dasmPrintVarArgOp(out, current, "array", 1);
case GST_OP_ARR:
current += dasm_varg_op(out, current, "array", 1);
break;
case VM_OP_DIC:
current += dasmPrintVarArgOp(out, current, "dictionary", 1);
case GST_OP_DIC:
current += dasm_varg_op(out, current, "dictionary", 1);
break;
case VM_OP_TCL:
current += dasmPrintVarArgOp(out, current, "tailCall", 1);
case GST_OP_TCL:
current += dasm_varg_op(out, current, "tailCall", 1);
break;
case VM_OP_ADM:
current += dasmPrintVarArgOp(out, current, "addMultiple", 1);
case GST_OP_ADM:
current += dasm_varg_op(out, current, "addMultiple", 1);
break;
case VM_OP_SBM:
current += dasmPrintVarArgOp(out, current, "subMultiple", 1);
case GST_OP_SBM:
current += dasm_varg_op(out, current, "subMultiple", 1);
break;
case VM_OP_MUM:
current += dasmPrintVarArgOp(out, current, "mulMultiple", 1);
case GST_OP_MUM:
current += dasm_varg_op(out, current, "mulMultiple", 1);
break;
case VM_OP_DVM:
current += dasmPrintVarArgOp(out, current, "divMultiple", 1);
case GST_OP_DVM:
current += dasm_varg_op(out, current, "divMultiple", 1);
break;
case VM_OP_RTN:
current += dasmPrintFixedOp(out, current, "returnNil", 0);
case GST_OP_RTN:
current += dasm_fixed_op(out, current, "returnNil", 0);
break;
case VM_OP_GET:
current += dasmPrintFixedOp(out, current, "get", 3);
case GST_OP_GET:
current += dasm_fixed_op(out, current, "get", 3);
break;
case VM_OP_SET:
current += dasmPrintFixedOp(out, current, "set", 3);
case GST_OP_SET:
current += dasm_fixed_op(out, current, "set", 3);
break;
}
fprintf(out, "\n");

View File

@ -5,13 +5,13 @@
#include <stdio.h>
/* Print disassembly for a given funciton */
void dasm(FILE * out, uint16_t * byteCode, uint32_t len);
void gst_dasm(FILE * out, uint16_t * byteCode, uint32_t len);
/* Print the disassembly for a function definition */
void dasmFuncDef(FILE * out, FuncDef * def);
void gst_dasm_funcdef(FILE * out, GstFuncDef * def);
/* Print the disassembly for a function */
void dasmFunc(FILE * out, Func * f);
void gst_dasm_function(FILE * out, GstFunction * f);
#endif // disasm_h_INCLUDED

203
ds.c
View File

@ -8,9 +8,9 @@
/****/
/* Create a new Buffer */
Buffer * BufferNew(VM * vm, uint32_t capacity) {
Buffer * buffer = VMAlloc(vm, sizeof(Buffer));
uint8_t * data = VMAlloc(vm, sizeof(uint8_t) * capacity);
GstBuffer *gst_buffer(Gst *vm, uint32_t capacity) {
GstBuffer *buffer = gst_alloc(vm, sizeof(GstBuffer));
uint8_t *data = gst_alloc(vm, sizeof(uint8_t) * capacity);
buffer->data = data;
buffer->count = 0;
buffer->capacity = capacity;
@ -19,17 +19,17 @@ Buffer * BufferNew(VM * vm, uint32_t capacity) {
}
/* Ensure that the buffer has enough internal capacity */
void BufferEnsure(VM * vm, Buffer * buffer, uint32_t capacity) {
void gst_buffer_ensure(Gst *vm, GstBuffer *buffer, uint32_t capacity) {
uint8_t * newData;
if (capacity <= buffer->capacity) return;
newData = VMAlloc(vm, capacity * sizeof(uint8_t));
newData = gst_alloc(vm, capacity * sizeof(uint8_t));
memcpy(newData, buffer->data, buffer->count * sizeof(uint8_t));
buffer->data = newData;
buffer->capacity = capacity;
}
/* Get a byte from an index in the buffer */
int32_t BufferGet(Buffer * buffer, uint32_t index) {
int gst_buffer_get(GstBuffer *buffer, uint32_t index) {
if (index < buffer->count) {
return buffer->data[index];
} else {
@ -38,29 +38,29 @@ int32_t BufferGet(Buffer * buffer, uint32_t index) {
}
/* Push a byte into the buffer */
void BufferPush(VM * vm, Buffer * buffer, uint8_t c) {
void gst_buffer_push(Gst *vm, GstBuffer * buffer, uint8_t c) {
if (buffer->count >= buffer->capacity) {
BufferEnsure(vm, buffer, 2 * buffer->count);
gst_buffer_ensure(vm, buffer, 2 * buffer->count);
}
buffer->data[buffer->count++] = c;
}
/* Push multiple bytes into the buffer */
void BufferAppendData(VM * vm, Buffer * buffer, uint8_t * string, uint32_t length) {
void gst_buffer_append(Gst *vm, GstBuffer *buffer, uint8_t *string, uint32_t length) {
uint32_t newSize = buffer->count + length;
if (newSize > buffer->capacity) {
BufferEnsure(vm, buffer, 2 * newSize);
gst_buffer_ensure(vm, buffer, 2 * newSize);
}
memcpy(buffer->data + buffer->count, string, length);
buffer->count = newSize;
}
/* Convert the buffer to a string */
uint8_t * BufferToString(VM * vm, Buffer * buffer) {
uint8_t * data = VMAlloc(vm, buffer->count + 2 * sizeof(uint32_t));
uint8_t *gst_buffer_to_string(Gst *vm, GstBuffer *buffer) {
uint8_t *data = gst_alloc(vm, buffer->count + 2 * sizeof(uint32_t));
data += 2 * sizeof(uint32_t);
VStringSize(data) = buffer->count;
VStringHash(data) = 0;
gst_string_length(data) = buffer->count;
gst_string_hash(data) = 0;
memcpy(data, buffer->data, buffer->count * sizeof(uint8_t));
return data;
}
@ -70,9 +70,9 @@ uint8_t * BufferToString(VM * vm, Buffer * buffer) {
/****/
/* Creates a new array */
Array * ArrayNew(VM * vm, uint32_t capacity) {
Array * array = VMAlloc(vm, sizeof(Array));
Value * data = VMAlloc(vm, capacity * sizeof(Value));
GstArray *gst_array(Gst * vm, uint32_t capacity) {
GstArray *array = gst_alloc(vm, sizeof(GstArray));
GstValue *data = gst_alloc(vm, capacity * sizeof(GstValue));
array->data = data;
array->count = 0;
array->capacity = capacity;
@ -81,30 +81,29 @@ Array * ArrayNew(VM * vm, uint32_t capacity) {
}
/* Ensure the array has enough capacity for capacity elements */
void ArrayEnsure(VM * vm, Array * array, uint32_t capacity) {
Value * newData;
void gst_array_ensure(Gst *vm, GstArray *array, uint32_t capacity) {
GstValue *newData;
if (capacity <= array->capacity) return;
newData = VMAlloc(vm, capacity * sizeof(Value));
memcpy(newData, array->data, array->capacity * sizeof(Value));
newData = gst_alloc(vm, capacity * sizeof(GstValue));
memcpy(newData, array->data, array->capacity * sizeof(GstValue));
array->data = newData;
array->capacity = capacity;
}
/* Get a value of an array with bounds checking. */
Value ArrayGet(Array * array, uint32_t index) {
GstValue gst_array_get(GstArray *array, uint32_t index) {
if (index < array->count) {
return array->data[index];
} else {
Value v;
v.type = TYPE_NIL;
v.data.boolean = 0;
GstValue v;
v.type = GST_NIL;
return v;
}
}
/* Try to set an index in the array. Return 1 if successful, 0
* on failiure */
int ArraySet(Array * array, uint32_t index, Value x) {
int gst_array_set(GstArray *array, uint32_t index, GstValue x) {
if (index < array->count) {
array->data[index] = x;
return 1;
@ -114,33 +113,31 @@ int ArraySet(Array * array, uint32_t index, Value x) {
}
/* Add an item to the end of the array */
void ArrayPush(VM * vm, Array * array, Value x) {
void gst_array_push(Gst *vm, GstArray *array, GstValue x) {
if (array->count >= array->capacity) {
ArrayEnsure(vm, array, 2 * array->count);
gst_array_ensure(vm, array, 2 * array->count);
}
array->data[array->count++] = x;
}
/* Remove the last item from the Array and return it */
Value ArrayPop(Array * array) {
GstValue gst_array_pop(GstArray *array) {
if (array->count) {
return array->data[--array->count];
} else {
Value v;
v.type = TYPE_NIL;
v.data.boolean = 0;
GstValue v;
v.type = GST_NIL;
return v;
}
}
/* Look at the last item in the Array */
Value ArrayPeek(Array * array) {
GstValue gst_array_peek(GstArray *array) {
if (array->count) {
return array->data[array->count - 1];
} else {
Value v;
v.type = TYPE_NIL;
v.data.boolean = 0;
GstValue v;
v.type = GST_NIL;
return v;
}
}
@ -150,76 +147,76 @@ Value ArrayPeek(Array * array) {
/****/
/* Create a new dictionary */
Dictionary * DictNew(VM * vm, uint32_t capacity) {
Dictionary * dict = VMAlloc(vm, sizeof(Dictionary));
DictBucket ** buckets = VMZalloc(vm, capacity * sizeof(DictBucket *));
dict->buckets = buckets;
dict->capacity = capacity;
dict->count = 0;
dict->flags = 0;
return dict;
GstObject* gst_object(Gst *vm, uint32_t capacity) {
GstObject *o = gst_alloc(vm, sizeof(GstObject));
GstBucket **buckets = gst_zalloc(vm, capacity * sizeof(GstBucket *));
o->buckets = buckets;
o->capacity = capacity;
o->count = 0;
o->flags = 0;
return o;
}
/* Resize the dictionary table. */
static void DictReHash(VM * vm, Dictionary * dict, uint32_t size) {
DictBucket ** newBuckets = VMZalloc(vm, size * sizeof(DictBucket *));
static void gst_object_rehash(Gst *vm, GstObject *o, uint32_t size) {
GstBucket **newBuckets = gst_zalloc(vm, size * sizeof(GstBucket *));
uint32_t i, count;
for (i = 0, count = dict->capacity; i < count; ++i) {
DictBucket * bucket = dict->buckets[i];
for (i = 0, count = o->capacity; i < count; ++i) {
GstBucket *bucket = o->buckets[i];
while (bucket) {
uint32_t index;
DictBucket * next = bucket->next;
index = ValueHash(bucket->key) % size;
GstBucket *next = bucket->next;
index = gst_hash(bucket->key) % size;
bucket->next = newBuckets[index];
newBuckets[index] = bucket;
bucket = next;
}
}
dict->buckets = newBuckets;
dict->capacity = size;
o->buckets = newBuckets;
o->capacity = size;
}
/* Find the bucket that contains the given key */
static DictBucket * DictFind(Dictionary * dict, Value key) {
uint32_t index = ValueHash(key) % dict->capacity;
DictBucket * bucket = dict->buckets[index];
static GstBucket *gst_object_find(GstObject *o, GstValue key) {
uint32_t index = gst_hash(key) % o->capacity;
GstBucket *bucket = o->buckets[index];
while (bucket) {
if (ValueEqual(bucket->key, key))
if (gst_equals(bucket->key, key))
return bucket;
bucket = bucket->next;
}
return (DictBucket *)0;
return (GstBucket *)0;
}
/* Get a value out of the dictionary */
Value DictGet(Dictionary * dict, Value key) {
DictBucket * bucket = DictFind(dict, key);
GstValue gst_object_get(GstObject *o, GstValue key) {
GstBucket *bucket = gst_object_find(o, key);
if (bucket) {
return bucket->value;
} else {
Value nil;
nil.type = TYPE_NIL;
GstValue nil;
nil.type = GST_NIL;
return nil;
}
}
/* Remove an entry from the dictionary */
Value DictRemove(VM * vm, Dictionary * dict, Value key) {
DictBucket * bucket, * previous;
uint32_t index = ValueHash(key) % dict->capacity;
bucket = dict->buckets[index];
previous = (DictBucket *)0;
GstValue gst_object_remove(Gst * vm, GstObject *o, GstValue key) {
GstBucket *bucket, *previous;
uint32_t index = gst_hash(key) % o->capacity;
bucket = o->buckets[index];
previous = (GstBucket *)0;
while (bucket) {
if (ValueEqual(bucket->key, key)) {
if (gst_equals(bucket->key, key)) {
if (previous) {
previous->next = bucket->next;
} else {
dict->buckets[index] = bucket->next;
o->buckets[index] = bucket->next;
}
if (dict->count < dict->capacity / 4) {
DictReHash(vm, dict, dict->capacity / 2);
if (o->count < o->capacity / 4) {
gst_object_rehash(vm, o, o->capacity / 2);
}
--dict->count;
--o->count;
return bucket->value;
}
previous = bucket;
@ -227,74 +224,52 @@ Value DictRemove(VM * vm, Dictionary * dict, Value key) {
}
/* Return nil if we found nothing */
{
Value nil;
nil.type = TYPE_NIL;
GstValue nil;
nil.type = GST_NIL;
return nil;
}
}
/* Put a value into the dictionary. Returns 1 if successful, 0 if out of memory.
* The VM pointer is needed for memory allocation. */
void DictPut(VM * vm, Dictionary * dict, Value key, Value value) {
DictBucket * bucket, * previous;
uint32_t index = ValueHash(key) % dict->capacity;
if (key.type == TYPE_NIL) return;
void gst_object_put(Gst *vm, GstObject *o, GstValue key, GstValue value) {
GstBucket *bucket, *previous;
uint32_t index = gst_hash(key) % o->capacity;
if (key.type == GST_NIL) return;
/* Do a removal if value is nil */
if (value.type == TYPE_NIL) {
bucket = dict->buckets[index];
previous = (DictBucket *)0;
if (value.type == GST_NIL) {
bucket = o->buckets[index];
previous = (GstBucket *)0;
while (bucket) {
if (ValueEqual(bucket->key, key)) {
if (gst_equals(bucket->key, key)) {
if (previous) {
previous->next = bucket->next;
} else {
dict->buckets[index] = bucket->next;
o->buckets[index] = bucket->next;
}
if (dict->count < dict->capacity / 4) {
DictReHash(vm, dict, dict->capacity / 2);
if (o->count < o->capacity / 4) {
gst_object_rehash(vm, o, o->capacity / 2);
}
--dict->count;
--o->count;
return;
}
previous = bucket;
bucket = bucket->next;
}
} else {
bucket = DictFind(dict, key);
bucket = gst_object_find(o, key);
if (bucket) {
bucket->value = value;
} else {
if (dict->count >= 2 * dict->capacity) {
DictReHash(vm, dict, 2 * dict->capacity);
if (o->count >= 2 * o->capacity) {
gst_object_rehash(vm, o, 2 * o->capacity);
}
bucket = VMAlloc(vm, sizeof(DictBucket));
bucket->next = dict->buckets[index];
bucket = gst_alloc(vm, sizeof(GstBucket));
bucket->next = o->buckets[index];
bucket->value = value;
bucket->key = key;
dict->buckets[index] = bucket;
++dict->count;
o->buckets[index] = bucket;
++o->count;
}
}
}
/* Begin iteration through a dictionary */
void DictIterate(Dictionary * dict, DictionaryIterator * iterator) {
iterator->index = 0;
iterator->dict = dict;
iterator->bucket = dict->buckets[0];
}
/* Provides a mechanism for iterating through a table. */
int DictIterateNext(DictionaryIterator * iterator, DictBucket ** bucket) {
Dictionary * dict = iterator->dict;
for (;;) {
if (iterator->bucket) {
*bucket = iterator->bucket;
iterator->bucket = iterator->bucket->next;
return 1;
}
if (++iterator->index >= dict->capacity) break;
iterator->bucket = dict->buckets[iterator->index];
}
return 0;
}

52
ds.h
View File

@ -6,35 +6,35 @@
/*
* Data type flags
*/
#define DS_LOCKED 0x01
#define GST_DS_LOCKED 0x01
/****/
/* Buffer functions */
/****/
/* Create a new buffer */
Buffer * BufferNew(VM * vm, uint32_t capacity);
GstBuffer *gst_buffer(Gst *vm, uint32_t capacity);
/* Ensure the buffer has enough capacity */
void BufferEnsure(VM * vm, Buffer * buffer, uint32_t capacity);
void gst_buffer_ensure(Gst *vm, GstBuffer *buffer, uint32_t capacity);
/* Get a value from the buffer */
int32_t BufferGet(Buffer * buffer, uint32_t index);
int gst_buffer_get(GstBuffer *buffer, uint32_t index);
/* Push a value to the buffer */
void BufferPush(VM * vm, Buffer * buffer, uint8_t c);
void gst_buffer_push(Gst *vm, GstBuffer *buffer, uint8_t c);
/* Append a piece of memory to the buffer */
void BufferAppendData(VM * vm, Buffer * buffer, uint8_t * string, uint32_t length);
void gst_buffer_append(Gst *vm, GstBuffer *buffer, uint8_t *string, uint32_t length);
/* Convert the buffer to a string */
uint8_t * BufferToString(VM * vm, Buffer * buffer);
uint8_t *gst_buffer_to_string(Gst * vm, GstBuffer * buffer);
/* Define a push function for pushing a certain type to the buffer */
#define BufferDefine(name, type) \
static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \
#define BUFFER_DEFINE(name, type) \
static void gst_buffer_push_##name(Gst * vm, GstBuffer * buffer, type x) { \
union { type t; uint8_t bytes[sizeof(type)]; } u; \
u.t = x; BufferAppendData(vm, buffer, u.bytes, sizeof(type)); \
u.t = x; gst_buffer_append(vm, buffer, u.bytes, sizeof(type)); \
}
/****/
@ -42,51 +42,45 @@ static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \
/****/
/* Create a new Array */
Array * ArrayNew(VM * vm, uint32_t capacity);
GstArray *gst_array(Gst *vm, uint32_t capacity);
/* Get a value of an array with bounds checking. Returns nil if
* outside bounds. */
Value ArrayGet(Array * array, uint32_t index);
GstValue gst_array_get(GstArray *array, uint32_t index);
/* Set a value in the array. Does bounds checking but will not grow
* or shrink the array */
int ArraySet(Array * array, uint32_t index, Value x);
int gst_array_set(GstArray *array, uint32_t index, GstValue x);
/* Ensure that the internal memory hash enough space for capacity items */
void ArrayEnsure(VM * vm, Array * array, uint32_t capacity);
void gst_array_ensure(Gst *vm, GstArray *array, uint32_t capacity);
/* Set a value in an array. Will also append to the array if the index is
* greater than the current max index. */
void ArrayPush(VM * vm, Array * array, Value x);
void gst_array_push(Gst *vm, GstArray *array, GstValue x);
/* Pop the last item in the array, or return NIL if empty */
Value ArrayPop(Array * array);
GstValue gst_array_pop(GstArray *array);
/* Look at the top most item of an Array */
Value ArrayPeek(Array * array);
GstValue ArrayPeek(GstArray *array);
/****/
/* Dictionary functions */
/* Object functions */
/****/
/* Create a new dictionary */
Dictionary * DictNew(VM * vm, uint32_t capacity);
/* Create a new object */
GstObject *gst_object(Gst *vm, uint32_t capacity);
/* Get a value out of the dictionary */
Value DictGet(Dictionary * dict, Value key);
GstValue gst_object_get(GstObject *obj, GstValue key);
/* Get a Value from the dictionary, but remove it at the same
* time. */
Value DictRemove(VM * vm, Dictionary * dict, Value key);
GstValue gst_object_remove(Gst *vm, GstObject *obj, GstValue key);
/* Put a value into the dictionary. Returns 1 if successful, 0 if out of memory.
* The VM pointer is needed for memory allocation. */
void DictPut(VM * vm, Dictionary * dict, Value key, Value value);
/* Begin iteration through a dictionary */
void DictIterate(Dictionary * dict, DictionaryIterator * iterator);
/* Provides a mechanism for iterating through a table. */
int DictIterateNext(DictionaryIterator * iterator, DictBucket ** bucket);
void gst_object_put(Gst *vm, GstObject *obj, GstValue key, GstValue value);
#endif // ds_h_INCLUDED

46
main.c
View File

@ -7,24 +7,23 @@
#include "value.h"
#include "disasm.h"
void StringPut(uint8_t * string) {
void string_put(uint8_t * string) {
uint32_t i;
uint32_t len = VStringSize(string);
uint32_t len = gst_string_length(string);
for (i = 0; i < len; ++i)
fputc(string[i], stdout);
}
/* Test c function */
Value print(VM * vm) {
GstValue print(Gst *vm) {
uint32_t j, count;
Value nil;
count = VMCountArgs(vm);
GstValue nil;
count = gst_count_args(vm);
for (j = 0; j < count; ++j) {
uint8_t * string = ValueToString(vm, VMGetArg(vm, j));
StringPut(string);
string_put(gst_to_string(vm, gst_arg(vm, j)));
fputc('\n', stdout);
}
nil.type = TYPE_NIL;
nil.type = GST_NIL;
return nil;
}
@ -32,20 +31,20 @@ Value print(VM * vm) {
void debugRepl() {
char buffer[1024] = {0};
const char * reader = buffer;
Value func;
VM vm;
Parser p;
Compiler c;
GstValue func;
Gst vm;
GstParser p;
GstCompiler c;
VMInit(&vm);
gst_init(&vm);
for (;;) {
/* Reset state */
ParserInit(&p, &vm);
gst_parser(&p, &vm);
/* Get and parse input until we have a full form */
while (p.status == PARSER_PENDING) {
while (p.status == GST_PARSER_PENDING) {
/* Get some input if we are done */
if (*reader == '\0') {
printf(">> ");
@ -55,7 +54,7 @@ void debugRepl() {
p.index = 0;
reader = buffer;
}
reader += ParserParseCString(&p, reader);
reader += gst_parse_cstring(&p, reader);
}
/* Check for parsing errors */
@ -74,10 +73,10 @@ void debugRepl() {
}
/* Try to compile generated AST */
CompilerInit(&c, &vm);
CompilerAddGlobalCFunc(&c, "print", print);
func.type = TYPE_FUNCTION;
func.data.func = CompilerCompile(&c, p.value);
gst_compiler(&c, &vm);
gst_compiler_add_global_cfunction(&c, "print", print);
func.type = GST_FUNCTION;
func.data.function = gst_compiler_compile(&c, p.value);
/* Check for compilation errors */
if (c.error) {
@ -93,15 +92,14 @@ void debugRepl() {
//printf("\n");
/* Execute function */
VMLoad(&vm, func);
if (VMStart(&vm)) {
gst_load(&vm, func);
if (gst_start(&vm)) {
printf("VM error: %s\n", vm.error);
reader = buffer;
buffer[0] = 0;
continue;
} else {
uint8_t * string = ValueToString(&vm, vm.ret);
StringPut(string);
string_put(gst_to_string(&vm, vm.ret));
printf("\n");
}
}

199
parse.c
View File

@ -19,15 +19,15 @@ typedef enum ParseType {
} ParseType;
/* Contain a parse state that goes on the parse stack */
struct ParseState {
struct GstParseState {
ParseType type;
union {
struct {
uint8_t endDelimiter;
Array * array;
GstArray * array;
} form;
struct {
Buffer * buffer;
GstBuffer * buffer;
enum {
STRING_STATE_BASE,
STRING_STATE_ESCAPE,
@ -39,37 +39,37 @@ struct ParseState {
};
/* Handle error in parsing */
#define PError(p, e) ((p)->error = (e), (p)->status = PARSER_ERROR)
#define p_error(p, e) ((p)->error = (e), (p)->status = GST_PARSER_ERROR)
/* Get the top ParseState in the parse stack */
static ParseState * ParserPeek(Parser * p) {
static GstParseState *parser_peek(GstParser *p) {
if (!p->count) {
PError(p, "Parser stack underflow. (Peek)");
p_error(p, "Parser stack underflow. (Peek)");
return NULL;
}
return p->data + p->count - 1;
}
/* Remove the top state from the ParseStack */
static ParseState * ParserPop(Parser * p) {
static GstParseState *parser_pop(GstParser * p) {
if (!p->count) {
PError(p, "Parser stack underflow. (Pop)");
p_error(p, "Parser stack underflow. (Pop)");
return NULL;
}
return p->data + --p->count;
}
/* Add a new, empty ParseState to the ParseStack. */
static void ParserPush(Parser *p, ParseType type, uint8_t character) {
ParseState * top;
static void parser_push(GstParser *p, ParseType type, uint8_t character) {
GstParseState *top;
if (p->count >= p->cap) {
uint32_t newCap = 2 * p->count;
ParseState * data = VMAlloc(p->vm, newCap);
GstParseState *data = gst_alloc(p->vm, newCap);
p->data = data;
p->cap = newCap;
}
++p->count;
top = ParserPeek(p);
top = parser_peek(p);
if (!top) return;
top->type = type;
switch (type) {
@ -78,48 +78,48 @@ static void ParserPush(Parser *p, ParseType type, uint8_t character) {
case PTYPE_STRING:
top->buf.string.state = STRING_STATE_BASE;
case PTYPE_TOKEN:
top->buf.string.buffer = BufferNew(p->vm, 10);
top->buf.string.buffer = gst_buffer(p->vm, 10);
break;
case PTYPE_FORM:
top->buf.form.array = ArrayNew(p->vm, 10);
top->buf.form.array = gst_array(p->vm, 10);
if (character == '(') top->buf.form.endDelimiter = ')';
if (character == '[') {
top->buf.form.endDelimiter = ']';
ArrayPush(p->vm, top->buf.form.array, ValueLoadCString(p->vm, "array"));
gst_array_push(p->vm, top->buf.form.array, gst_load_cstring(p->vm, "array"));
}
if (character == '{') {
top->buf.form.endDelimiter = '}';
ArrayPush(p->vm, top->buf.form.array, ValueLoadCString(p->vm, "dict"));
gst_array_push(p->vm, top->buf.form.array, gst_load_cstring(p->vm, "dict"));
}
break;
}
}
/* Append a value to the top-most state in the Parser's stack. */
static void ParserTopAppend(Parser * p, Value x) {
ParseState * top = ParserPeek(p);
static void parser_append(GstParser *p, GstValue x) {
GstParseState *top = parser_peek(p);
if (!top) return;
switch (top->type) {
case PTYPE_ROOT:
p->value = x;
p->status = PARSER_FULL;
p->status = GST_PARSER_FULL;
break;
case PTYPE_FORM:
ArrayPush(p->vm, top->buf.form.array, x);
gst_array_push(p->vm, top->buf.form.array, x);
break;
default:
PError(p, "Expected container type.");
p_error(p, "Expected container type.");
break;
}
}
/* Check if a character is whitespace */
static int isWhitespace(uint8_t c) {
static int is_whitespace(uint8_t c) {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0' || c == ',';
}
/* Check if a character is a valid symbol character */
static int isSymbolChar(uint8_t c) {
static int is_symbol_char(uint8_t c) {
if (c >= 'a' && c <= 'z') return 1;
if (c >= 'A' && c <= 'Z') return 1;
if (c >= '0' && c <= ':') return 1;
@ -148,10 +148,13 @@ static double exp10(int power) {
}
}
/* Read a number from a string */
static int ParseReadNumber(const uint8_t * string, const uint8_t * end, double * ret, int forceInt) {
/* Read a number from a string. Returns if successfuly
* parsed a number 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) {
int sign = 1, x = 0;
double accum = 0, exp = 1, place = 1;
/* Check the sign */
if (*string == '-') {
sign = -1;
++string;
@ -163,8 +166,10 @@ static int ParseReadNumber(const uint8_t * string, const uint8_t * end, double *
if (*string == '.' && !forceInt) {
place = 0.1;
} else if (!forceInt && (*string == 'e' || *string == 'E')) {
/* Read the exponent */
++string;
if (!ParseReadNumber(string, end, &exp, 1))
if (string >= end) return 0;
if (!read_number(string, end, &exp, 1))
return 0;
exp = exp10(exp);
break;
@ -187,7 +192,7 @@ static int ParseReadNumber(const uint8_t * string, const uint8_t * end, double *
}
/* Checks if a string slice is equal to a string constant */
static int checkStrConst(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) {
if (*ref != *(char *)start) return 0;
++ref;
@ -197,72 +202,72 @@ static int checkStrConst(const char * ref, const uint8_t * start, const uint8_t
}
/* Build from the token buffer */
static Value ParserBuildTokenBuffer(Parser * p, Buffer * buf) {
Value x;
Number number;
static GstValue build_token(GstParser *p, GstBuffer *buf) {
GstValue x;
GstNumber number;
uint8_t * data = buf->data;
uint8_t * back = data + buf->count;
if (ParseReadNumber(data, back, &number, 0)) {
x.type = TYPE_NUMBER;
if (read_number(data, back, &number, 0)) {
x.type = GST_NUMBER;
x.data.number = number;
} else if (checkStrConst("nil", data, back)) {
x.type = TYPE_NIL;
} else if (check_str_const("nil", data, back)) {
x.type = GST_NIL;
x.data.boolean = 0;
} else if (checkStrConst("false", data, back)) {
x.type = TYPE_BOOLEAN;
} else if (check_str_const("false", data, back)) {
x.type = GST_BOOLEAN;
x.data.boolean = 0;
} else if (checkStrConst("true", data, back)) {
x.type = TYPE_BOOLEAN;
} else if (check_str_const("true", data, back)) {
x.type = GST_BOOLEAN;
x.data.boolean = 1;
} else {
if (buf->data[0] >= '0' && buf->data[0] <= '9') {
PError(p, "Symbols cannot start with digits.");
x.type = TYPE_NIL;
p_error(p, "Symbols cannot start with digits.");
x.type = GST_NIL;
} else {
x.type = TYPE_STRING;
x.data.string = BufferToString(p->vm, buf);
x.type = GST_STRING;
x.data.string = gst_buffer_to_string(p->vm, buf);
}
}
return x;
}
/* Handle parsing a token */
static int ParserTokenState(Parser * p, uint8_t c) {
ParseState * top = ParserPeek(p);
Buffer * buf = top->buf.string.buffer;
if (isWhitespace(c) || c == ')' || c == ']' || c == '}') {
ParserPop(p);
ParserTopAppend(p, ParserBuildTokenBuffer(p, buf));
static int token_state(GstParser *p, uint8_t c) {
GstParseState *top = parser_peek(p);
GstBuffer *buf = top->buf.string.buffer;
if (is_whitespace(c) || c == ')' || c == ']' || c == '}') {
parser_pop(p);
parser_append(p, build_token(p, buf));
return !(c == ')' || c == ']' || c == '}');
} else if (isSymbolChar(c)) {
BufferPush(p->vm, buf, c);
} else if (is_symbol_char(c)) {
gst_buffer_push(p->vm, buf, c);
return 1;
} else {
PError(p, "Expected symbol character.");
p_error(p, "Expected symbol character.");
return 1;
}
}
/* Handle parsing a string literal */
static int ParserStringState(Parser * p, uint8_t c) {
ParseState * top = ParserPeek(p);
static int string_state(GstParser *p, uint8_t c) {
GstParseState *top = parser_peek(p);
switch (top->buf.string.state) {
case STRING_STATE_BASE:
if (c == '\\') {
top->buf.string.state = STRING_STATE_ESCAPE;
} else if (c == '"') {
/* Load a quote form to get the string literal */
Value x, array;
x.type = TYPE_STRING;
x.data.string = BufferToString(p->vm, top->buf.string.buffer);
array.type = TYPE_ARRAY;
array.data.array = ArrayNew(p->vm, 2);
ArrayPush(p->vm, array.data.array, ValueLoadCString(p->vm, "quote"));
ArrayPush(p->vm, array.data.array, x);
ParserPop(p);
ParserTopAppend(p, array);
GstValue x, array;
x.type = GST_STRING;
x.data.string = gst_buffer_to_string(p->vm, top->buf.string.buffer);
array.type = GST_ARRAY;
array.data.array = gst_array(p->vm, 2);
gst_array_push(p->vm, array.data.array, gst_load_cstring(p->vm, "quote"));
gst_array_push(p->vm, array.data.array, x);
parser_pop(p);
parser_append(p, array);
} else {
BufferPush(p->vm, top->buf.string.buffer, c);
gst_buffer_push(p->vm, top->buf.string.buffer, c);
}
break;
case STRING_STATE_ESCAPE:
@ -278,10 +283,10 @@ static int ParserStringState(Parser * p, uint8_t c) {
case '\'': next = '\''; break;
case 'z': next = '\0'; break;
default:
PError(p, "Unknown string escape sequence.");
p_error(p, "Unknown string escape sequence.");
return 1;
}
BufferPush(p->vm, top->buf.string.buffer, next);
gst_buffer_push(p->vm, top->buf.string.buffer, next);
top->buf.string.state = STRING_STATE_BASE;
}
break;
@ -294,60 +299,60 @@ static int ParserStringState(Parser * p, uint8_t c) {
}
/* Root state of the parser */
static int ParserRootState(Parser * p, uint8_t c) {
static int root_state(GstParser *p, uint8_t c) {
if (c == ']' || c == ')' || c == '}') {
PError(p, UNEXPECTED_CLOSING_DELIM);
p_error(p, UNEXPECTED_CLOSING_DELIM);
return 1;
}
if (c == '(' || c == '[' || c == '{') {
ParserPush(p, PTYPE_FORM, c);
parser_push(p, PTYPE_FORM, c);
return 1;
}
if (c == '"') {
ParserPush(p, PTYPE_STRING, c);
parser_push(p, PTYPE_STRING, c);
return 1;
}
if (isWhitespace(c)) return 1;
if (isSymbolChar(c)) {
ParserPush(p, PTYPE_TOKEN, c);
if (is_whitespace(c)) return 1;
if (is_symbol_char(c)) {
parser_push(p, PTYPE_TOKEN, c);
return 0;
}
PError(p, "Unexpected character.");
p_error(p, "Unexpected character.");
return 1;
}
/* Handle parsing a form */
static int ParserFormState(Parser * p, uint8_t c) {
ParseState * top = ParserPeek(p);
static int form_state(GstParser *p, uint8_t c) {
GstParseState *top = parser_peek(p);
if (c == top->buf.form.endDelimiter) {
Array * array = top->buf.form.array;
Value x;
x.type = TYPE_ARRAY;
GstArray *array = top->buf.form.array;
GstValue x;
x.type = GST_ARRAY;
x.data.array = array;
ParserPop(p);
ParserTopAppend(p, x);
parser_pop(p);
parser_append(p, x);
return 1;
}
return ParserRootState(p, c);
return root_state(p, c);
}
/* Handle a character */
static int ParserDispatchChar(Parser * p, uint8_t c) {
static int dispatch_char(GstParser *p, uint8_t c) {
int done = 0;
while (!done && p->status == PARSER_PENDING) {
ParseState * top = ParserPeek(p);
while (!done && p->status == GST_PARSER_PENDING) {
GstParseState *top = parser_peek(p);
switch (top->type) {
case PTYPE_ROOT:
done = ParserRootState(p, c);
done = root_state(p, c);
break;
case PTYPE_TOKEN:
done = ParserTokenState(p, c);
done = token_state(p, c);
break;
case PTYPE_FORM:
done = ParserFormState(p, c);
done = form_state(p, c);
break;
case PTYPE_STRING:
done = ParserStringState(p, c);
done = string_state(p, c);
break;
}
}
@ -360,25 +365,25 @@ static int ParserDispatchChar(Parser * p, uint8_t c) {
* was not read. Returns 1 if any values were read, otherwise returns 0.
* Returns the number of bytes read.
*/
int ParserParseCString(Parser * p, const char * string) {
int gst_parse_cstring(GstParser *p, const char *string) {
int bytesRead = 0;
p->status = PARSER_PENDING;
while ((p->status == PARSER_PENDING) && (string[bytesRead] != '\0')) {
ParserDispatchChar(p, string[bytesRead++]);
p->status = GST_PARSER_PENDING;
while ((p->status == GST_PARSER_PENDING) && (string[bytesRead] != '\0')) {
dispatch_char(p, string[bytesRead++]);
}
return bytesRead;
}
/* Parser initialization (memory allocation) */
void ParserInit(Parser * p, VM * vm) {
void gst_parser(GstParser *p, Gst *vm) {
p->vm = vm;
ParseState * data = VMAlloc(vm, sizeof(ParseState) * 10);
GstParseState *data = gst_alloc(vm, sizeof(GstParseState) * 10);
p->data = data;
p->count = 0;
p->cap = 10;
p->index = 0;
p->error = NULL;
p->status = PARSER_PENDING;
p->value.type = TYPE_NIL;
ParserPush(p, PTYPE_ROOT, ' ');
p->status = GST_PARSER_PENDING;
p->value.type = GST_NIL;
parser_push(p, PTYPE_ROOT, ' ');
}

10
parse.h
View File

@ -3,12 +3,10 @@
#include "datatypes.h"
#define PARSE_ERROR -1
#define PARSE_VALUE_READ 1
#define PARSE_VALUE_PENDING 0
/* Initialize a parser */
void gst_parser(GstParser *p, Gst *vm);
void ParserInit(Parser * p, VM * vm);
int ParserParseCString(Parser * p, const char * string);
/* Parse a c style string. Returns true if successful */
int gst_parse_cstring(GstParser *p, const char *string);
#endif /* end of include guard: PARSE_H_ONYWMADW */

251
value.c
View File

@ -5,44 +5,44 @@
#include "ds.h"
#include "vm.h"
static uint8_t * LoadCString(VM * vm, const char * string, uint32_t len) {
uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t));
static uint8_t * load_cstring(Gst *vm, const char *string, uint32_t len) {
uint8_t *data = gst_alloc(vm, len + 2 * sizeof(uint32_t));
data += 2 * sizeof(uint32_t);
VStringHash(data) = 0;
VStringSize(data) = len;
gst_string_hash(data) = 0;
gst_string_length(data) = len;
memcpy(data, string, len);
return data;
}
Value ValueLoadCString(VM * vm, const char * string) {
Value ret;
ret.type = TYPE_STRING;
ret.data.string = LoadCString(vm, string, strlen(string));
GstValue gst_load_cstring(Gst *vm, const char *string) {
GstValue ret;
ret.type = GST_STRING;
ret.data.string = load_cstring(vm, string, strlen(string));
return ret;
}
static uint8_t * NumberToString(VM * vm, Number x) {
static uint8_t * number_to_string(Gst *vm, GstNumber x) {
static const uint32_t SIZE = 20;
uint8_t * data = VMAlloc(vm, SIZE + 2 * sizeof(uint32_t));
uint8_t *data = gst_alloc(vm, SIZE + 2 * sizeof(uint32_t));
data += 2 * sizeof(uint32_t);
snprintf((char *) data, SIZE, "%.17g", x);
VStringHash(data) = 0;
VStringSize(data) = strlen((char *) data);
gst_string_hash(data) = 0;
gst_string_length(data) = strlen((char *) data);
return data;
}
static const char * HEX_CHARACTERS = "0123456789abcdef";
static const char *HEX_CHARACTERS = "0123456789abcdef";
#define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)])
/* Returns a string description for a pointer */
static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlelen, void * pointer) {
static uint8_t *string_description(Gst *vm, const char *title, uint32_t titlelen, void *pointer) {
uint32_t len = 5 + titlelen + sizeof(void *) * 2;
uint32_t i;
uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t));
uint8_t * c;
uint8_t *data = gst_alloc(vm, len + 2 * sizeof(uint32_t));
uint8_t *c;
union {
uint8_t bytes[sizeof(void *)];
void * p;
void *p;
} buf;
buf.p = pointer;
data += 2 * sizeof(uint32_t);
@ -61,58 +61,57 @@ static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlele
*c++ = HEX(byte & 0xF);
}
*c++ = '>';
VStringHash(data) = 0;
VStringSize(data) = c - data;
gst_string_hash(data) = 0;
gst_string_length(data) = c - data;
return data;
}
/* Returns a string pointer or NULL if could not allocate memory. */
uint8_t * ValueToString(VM * vm, Value x) {
uint8_t *gst_to_string(Gst *vm, GstValue x) {
switch (x.type) {
case TYPE_NIL:
return LoadCString(vm, "nil", 3);
case TYPE_BOOLEAN:
case GST_NIL:
return load_cstring(vm, "nil", 3);
case GST_BOOLEAN:
if (x.data.boolean) {
return LoadCString(vm, "true", 4);
return load_cstring(vm, "true", 4);
} else {
return LoadCString(vm, "false", 5);
return load_cstring(vm, "false", 5);
}
case TYPE_NUMBER:
return NumberToString(vm, x.data.number);
case TYPE_ARRAY:
case GST_NUMBER:
return number_to_string(vm, x.data.number);
case GST_ARRAY:
{
uint32_t i;
Buffer * b = BufferNew(vm, 40);
BufferPush(vm, b, '(');
GstBuffer * b = gst_buffer(vm, 40);
gst_buffer_push(vm, b, '(');
for (i = 0; i < x.data.array->count; ++i) {
uint8_t * substr = ValueToString(vm, x.data.array->data[i]);
BufferAppendData(vm, b, substr, VStringSize(substr));
uint8_t * substr = gst_to_string(vm, x.data.array->data[i]);
gst_buffer_append(vm, b, substr, gst_string_length(substr));
if (i < x.data.array->count - 1)
BufferPush(vm, b, ' ');
gst_buffer_push(vm, b, ' ');
}
BufferPush(vm, b, ')');
return BufferToString(vm, b);
gst_buffer_push(vm, b, ')');
return gst_buffer_to_string(vm, b);
}
return StringDescription(vm, "array", 5, x.data.pointer);
case TYPE_STRING:
case GST_STRING:
return x.data.string;
case TYPE_BYTEBUFFER:
return StringDescription(vm, "buffer", 6, x.data.pointer);
case TYPE_CFUNCTION:
return StringDescription(vm, "cfunction", 9, x.data.pointer);
case TYPE_FUNCTION:
return StringDescription(vm, "function", 8, x.data.pointer);
case TYPE_DICTIONARY:
return StringDescription(vm, "dictionary", 10, x.data.pointer);
case TYPE_THREAD:
return StringDescription(vm, "thread", 6, x.data.pointer);
case GST_BYTEBUFFER:
return string_description(vm, "buffer", 6, x.data.pointer);
case GST_CFUNCTION:
return string_description(vm, "cfunction", 9, x.data.pointer);
case GST_FUNCTION:
return string_description(vm, "function", 8, x.data.pointer);
case GST_OBJECT:
return string_description(vm, "object", 6, x.data.pointer);
case GST_THREAD:
return string_description(vm, "thread", 6, x.data.pointer);
}
return NULL;
}
/* Simple hash function */
uint32_t djb2(const uint8_t * str) {
const uint8_t * end = str + VStringSize(str);
const uint8_t * end = str + gst_string_length(str);
uint32_t hash = 5381;
while (str < end)
hash = (hash << 5) + hash + *str++;
@ -120,45 +119,45 @@ uint32_t djb2(const uint8_t * str) {
}
/* Check if two values are equal. This is strict equality with no conversion. */
int ValueEqual(Value x, Value y) {
int gst_equals(GstValue x, GstValue y) {
int result = 0;
if (x.type != y.type) {
result = 0;
} else {
switch (x.type) {
case TYPE_NIL:
case GST_NIL:
result = 1;
break;
case TYPE_BOOLEAN:
case GST_BOOLEAN:
result = (x.data.boolean == y.data.boolean);
break;
case TYPE_NUMBER:
case GST_NUMBER:
result = (x.data.number == y.data.number);
break;
/* Assume that when strings are created, equal strings
* are set to the same string */
case TYPE_STRING:
case GST_STRING:
if (x.data.string == y.data.string) {
result = 1;
break;
}
if (ValueHash(x) != ValueHash(y) ||
VStringSize(x.data.string) != VStringSize(y.data.string)) {
if (gst_hash(x) != gst_hash(y) ||
gst_string_length(x.data.string) != gst_string_length(y.data.string)) {
result = 0;
break;
}
if (!strncmp((char *) x.data.string, (char *) y.data.string, VStringSize(x.data.string))) {
if (!strncmp((char *) x.data.string, (char *) y.data.string, gst_string_length(x.data.string))) {
result = 1;
break;
}
result = 0;
break;
case TYPE_ARRAY:
case TYPE_BYTEBUFFER:
case TYPE_CFUNCTION:
case TYPE_DICTIONARY:
case TYPE_FUNCTION:
case TYPE_THREAD:
case GST_ARRAY:
case GST_BYTEBUFFER:
case GST_CFUNCTION:
case GST_OBJECT:
case GST_FUNCTION:
case GST_THREAD:
/* compare pointers */
result = (x.data.array == y.data.array);
break;
@ -168,39 +167,39 @@ int ValueEqual(Value x, Value y) {
}
/* Computes a hash value for a function */
uint32_t ValueHash(Value x) {
uint32_t gst_hash(GstValue x) {
uint32_t hash = 0;
switch (x.type) {
case TYPE_NIL:
case GST_NIL:
hash = 0;
break;
case TYPE_BOOLEAN:
case GST_BOOLEAN:
hash = x.data.boolean;
break;
case TYPE_NUMBER:
case GST_NUMBER:
{
union {
uint32_t hash;
Number number;
GstNumber number;
} u;
u.number = x.data.number;
hash = u.hash;
}
break;
/* String hashes */
case TYPE_STRING:
case GST_STRING:
/* Assume 0 is not hashed. */
if (VStringHash(x.data.string))
hash = VStringHash(x.data.string);
if (gst_string_hash(x.data.string))
hash = gst_string_hash(x.data.string);
else
hash = VStringHash(x.data.string) = djb2(x.data.string);
hash = gst_string_hash(x.data.string) = djb2(x.data.string);
break;
case TYPE_ARRAY:
case TYPE_BYTEBUFFER:
case TYPE_CFUNCTION:
case TYPE_DICTIONARY:
case TYPE_FUNCTION:
case TYPE_THREAD:
case GST_ARRAY:
case GST_BYTEBUFFER:
case GST_CFUNCTION:
case GST_OBJECT:
case GST_FUNCTION:
case GST_THREAD:
/* Cast the pointer */
{
union {
@ -218,30 +217,30 @@ uint32_t ValueHash(Value x) {
/* Compares x to y. If they are equal retuns 0. If x is less, returns -1.
* If y is less, returns 1. All types are comparable
* and should have strict ordering. */
int ValueCompare(Value x, Value y) {
int gst_compare(GstValue x, GstValue y) {
if (x.type == y.type) {
switch (x.type) {
case TYPE_NIL:
case GST_NIL:
return 0;
case TYPE_BOOLEAN:
case GST_BOOLEAN:
if (x.data.boolean == y.data.boolean) {
return 0;
} else {
return x.data.boolean ? 1 : -1;
}
case TYPE_NUMBER:
case GST_NUMBER:
/* TODO: define behavior for NaN and infinties. */
if (x.data.number == y.data.number) {
return 0;
} else {
return x.data.number > y.data.number ? 1 : -1;
}
case TYPE_STRING:
case GST_STRING:
if (x.data.string == y.data.string) {
return 0;
} else {
uint32_t xlen = VStringSize(x.data.string);
uint32_t ylen = VStringSize(y.data.string);
uint32_t xlen = gst_string_length(x.data.string);
uint32_t ylen = gst_string_length(y.data.string);
uint32_t len = xlen > ylen ? ylen : xlen;
uint32_t i;
for (i = 0; i < len; ++i) {
@ -259,12 +258,12 @@ int ValueCompare(Value x, Value y) {
return xlen < ylen ? -1 : 1;
}
}
case TYPE_ARRAY:
case TYPE_BYTEBUFFER:
case TYPE_CFUNCTION:
case TYPE_FUNCTION:
case TYPE_DICTIONARY:
case TYPE_THREAD:
case GST_ARRAY:
case GST_BYTEBUFFER:
case GST_CFUNCTION:
case GST_FUNCTION:
case GST_OBJECT:
case GST_THREAD:
if (x.data.string == y.data.string) {
return 0;
} else {
@ -280,9 +279,9 @@ int ValueCompare(Value x, Value y) {
/* 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. */
static int32_t ToIndex(Number raw, int64_t len) {
static int32_t to_index(GstNumber raw, int64_t len) {
int32_t toInt = raw;
if ((Number) toInt == raw) {
if ((GstNumber) toInt == raw) {
/* We were able to convert */
if (toInt < 0) {
/* Index from end */
@ -299,65 +298,65 @@ static int32_t ToIndex(Number raw, int64_t len) {
}
/* Convert a number into a byte. */
static uint8_t NumberToByte(Number raw) {
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. Can throw VM error. */
Value ValueGet(VM * vm, Value ds, Value key) {
GstValue gst_get(Gst *vm, GstValue ds, GstValue key) {
int32_t index;
Value ret;
GstValue ret;
switch (ds.type) {
case TYPE_ARRAY:
VMAssertType(vm, key, TYPE_NUMBER);
index = ToIndex(key.data.number, ds.data.array->count);
if (index == -1) VMError(vm, "Invalid array access");
case GST_ARRAY:
gst_assert_type(vm, key, GST_NUMBER);
index = to_index(key.data.number, ds.data.array->count);
if (index == -1) gst_error(vm, "Invalid array access");
return ds.data.array->data[index];
case TYPE_BYTEBUFFER:
VMAssertType(vm, key, TYPE_NUMBER);
index = ToIndex(key.data.number, ds.data.buffer->count);
if (index == -1) VMError(vm, "Invalid buffer access");
ret.type = TYPE_NUMBER;
case GST_BYTEBUFFER:
gst_assert_type(vm, key, GST_NUMBER);
index = to_index(key.data.number, ds.data.buffer->count);
if (index == -1) gst_error(vm, "Invalid buffer access");
ret.type = GST_NUMBER;
ret.data.number = ds.data.buffer->data[index];
break;
case TYPE_STRING:
VMAssertType(vm, key, TYPE_NUMBER);
index = ToIndex(key.data.number, VStringSize(ds.data.string));
if (index == -1) VMError(vm, "Invalid string access");
ret.type = TYPE_NUMBER;
case GST_STRING:
gst_assert_type(vm, key, GST_NUMBER);
index = to_index(key.data.number, gst_string_length(ds.data.string));
if (index == -1) gst_error(vm, "Invalid string access");
ret.type = GST_NUMBER;
ret.data.number = ds.data.string[index];
break;
case TYPE_DICTIONARY:
return DictGet(ds.data.dict, key);
case GST_OBJECT:
return gst_object_get(ds.data.object, key);
default:
VMError(vm, "Cannot get.");
gst_error(vm, "Cannot get.");
}
return ret;
}
/* Set a value in an associative data structure. Can throw VM error. */
void ValueSet(VM * vm, Value ds, Value key, Value value) {
void gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) {
int32_t index;
switch (ds.type) {
case TYPE_ARRAY:
VMAssertType(vm, key, TYPE_NUMBER);
index = ToIndex(key.data.number, ds.data.array->count);
if (index == -1) VMError(vm, "Invalid array access");
case GST_ARRAY:
gst_assert_type(vm, key, GST_NUMBER);
index = to_index(key.data.number, ds.data.array->count);
if (index == -1) gst_error(vm, "Invalid array access");
ds.data.array->data[index] = value;
break;
case TYPE_BYTEBUFFER:
VMAssertType(vm, key, TYPE_NUMBER);
VMAssertType(vm, value, TYPE_NUMBER);
index = ToIndex(key.data.number, ds.data.buffer->count);
if (index == -1) VMError(vm, "Invalid buffer access");
ds.data.buffer->data[index] = NumberToByte(value.data.number);
case GST_BYTEBUFFER:
gst_assert_type(vm, key, GST_NUMBER);
gst_assert_type(vm, value, GST_NUMBER);
index = to_index(key.data.number, ds.data.buffer->count);
if (index == -1) gst_error(vm, "Invalid buffer access");
ds.data.buffer->data[index] = to_byte(value.data.number);
break;
case TYPE_DICTIONARY:
DictPut(vm, ds.data.dict, key, value);
case GST_OBJECT:
gst_object_put(vm, ds.data.object, key, value);
break;
default:
VMError(vm, "Cannot set.");
gst_error(vm, "Cannot set.");
}
}

23
value.h
View File

@ -3,18 +3,27 @@
#include "datatypes.h"
int ValueCompare(Value x, Value y);
/* Compare two gst values. All gst values are comparable and strictly
* ordered by default. Return 0 if equal, -1 if x is less than y, and
* 1 and x is greater than y. */
int gst_compare(GstValue x, GstValue y);
int ValueEqual(Value x, Value y);
/* Returns if two values are equal. */
int gst_equals(GstValue x, GstValue y);
Value ValueGet(VM * vm, Value ds, Value key);
/* Get a value from an associative gst object. Can throw errors. */
GstValue gst_get(Gst *vm, GstValue ds, GstValue key);
void ValueSet(VM * vm, Value ds, Value key, Value value);
/* Set a value in an associative gst object. Can throw errors. */
void gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value);
Value ValueLoadCString(VM * vm, const char * string);
/* Load a c style string into a gst value (copies data) */
GstValue gst_load_cstring(Gst *vm, const char *string);
uint8_t * ValueToString(VM * vm, Value x);
/* Convert any gst value into a string */
uint8_t *gst_to_string(Gst *vm, GstValue x);
uint32_t ValueHash(Value x);
/* Generate a hash value for a gst object */
uint32_t gst_hash(GstValue x);
#endif /* end of include guard: VALUE_H_1RJPQKFM */

642
vm.c

File diff suppressed because it is too large Load Diff

36
vm.h
View File

@ -4,54 +4,54 @@
#include "datatypes.h"
/* Exit from the VM normally */
#define VMExit(vm, r) ((vm)->ret = (r), longjmp((vm)->jump, 1))
#define gst_exit(vm, r) ((vm)->ret = (r), longjmp((vm)->jump, 1))
/* Bail from the VM with an error. */
#define VMError(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 2))
#define gst_error(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 2))
/* Crash. Not catchable, unlike error. */
#define VMCrash(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 3))
#define gst_crash(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 3))
/* Error if the condition is false */
#define VMAssert(vm, cond, e) do \
{ if (!(cond)) { VMError((vm), (e)); } } while (0)
#define gst_assert(vm, cond, e) do \
{ if (!(cond)) { gst_error((vm), (e)); } } while (0)
/* Type assertion */
#define VMAssertType(vm, f, t) \
VMAssert((vm), (f).type == (t), "Expected type,")
#define gst_assert_type(vm, f, t) \
gst_assert((vm), (f).type == (t), "Expected a different type.")
/* Initialize the VM */
void VMInit(VM * vm);
void gst_init(Gst * vm);
/* Deinitialize the VM */
void VMDeinit(VM * vm);
void gst_deinit(Gst * vm);
/* Load a function to be run on the VM */
void VMLoad(VM * vm, Value func);
void gst_load(Gst * vm, GstValue func);
/* Start running the VM */
int VMStart(VM * vm);
int gst_start(Gst * vm);
/* Run garbage collection */
void VMCollect(VM * vm);
void gst_collect(Gst * vm);
/* Collect garbage if enough memory has been allocated since
* the previous collection */
void VMMaybeCollect(VM * vm);
void gst_maybe_collect(Gst * vm);
/* Allocate memory */
void * VMAlloc(VM * vm, uint32_t amount);
void * gst_alloc(Gst * vm, uint32_t amount);
/* Allocate zeroed memory */
void * VMZalloc(VM * vm, uint32_t amount);
void * gst_zalloc(Gst * vm, uint32_t amount);
/* Get an argument from the stack */
Value VMGetArg(VM * vm, uint16_t index);
GstValue gst_arg(Gst * vm, uint16_t index);
/* Put a value on the stack */
void VMSetArg(VM * vm, uint16_t index, Value x);
void gst_set_arg(Gst * vm, uint16_t index, GstValue x);
/* Get the number of arguments on the stack */
uint16_t VMCountArgs(VM * vm);
uint16_t gst_count_args(Gst * vm);
#endif /* end of include guard: VM_H_C4OZU8CQ */