mirror of
https://github.com/janet-lang/janet
synced 2024-11-24 17:27:18 +00:00
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:
parent
8cdc0610e3
commit
6677dff337
10
compile.h
10
compile.h
@ -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 */
|
||||
|
313
datatypes.h
313
datatypes.h
@ -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
212
disasm.c
@ -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");
|
||||
|
6
disasm.h
6
disasm.h
@ -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
203
ds.c
@ -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
52
ds.h
@ -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
46
main.c
@ -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
199
parse.c
@ -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
10
parse.h
@ -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
251
value.c
@ -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
23
value.h
@ -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 */
|
||||
|
36
vm.h
36
vm.h
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user