1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-16 18:29:56 +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:
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" #include "datatypes.h"
/* Initialize the Compiler */ /* Initialize the Compiler */
void CompilerInit(Compiler * c, VM * vm); void gst_compiler(GstCompiler *c, Gst *vm);
/* Register a global for the compilation environment. */ /* 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. */ /* 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. */ /* 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 /* Macro expansion. Macro expansion happens prior to the compilation process
* and is completely separate. This allows the compilation to not have to worry * and is completely separate. This allows the compilation to not have to worry
* about garbage collection and other issues that would complicate both the * about garbage collection and other issues that would complicate both the
* runtime and the compilation. */ * 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 */ #endif /* end of include guard: COMPILE_H_9VXF71HY */

View File

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

212
disasm.c
View File

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

View File

@ -5,13 +5,13 @@
#include <stdio.h> #include <stdio.h>
/* Print disassembly for a given funciton */ /* 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 */ /* 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 */ /* Print the disassembly for a function */
void dasmFunc(FILE * out, Func * f); void gst_dasm_function(FILE * out, GstFunction * f);
#endif // disasm_h_INCLUDED #endif // disasm_h_INCLUDED

203
ds.c
View File

@ -8,9 +8,9 @@
/****/ /****/
/* Create a new Buffer */ /* Create a new Buffer */
Buffer * BufferNew(VM * vm, uint32_t capacity) { GstBuffer *gst_buffer(Gst *vm, uint32_t capacity) {
Buffer * buffer = VMAlloc(vm, sizeof(Buffer)); GstBuffer *buffer = gst_alloc(vm, sizeof(GstBuffer));
uint8_t * data = VMAlloc(vm, sizeof(uint8_t) * capacity); uint8_t *data = gst_alloc(vm, sizeof(uint8_t) * capacity);
buffer->data = data; buffer->data = data;
buffer->count = 0; buffer->count = 0;
buffer->capacity = capacity; buffer->capacity = capacity;
@ -19,17 +19,17 @@ Buffer * BufferNew(VM * vm, uint32_t capacity) {
} }
/* Ensure that the buffer has enough internal 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; uint8_t * newData;
if (capacity <= buffer->capacity) return; 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)); memcpy(newData, buffer->data, buffer->count * sizeof(uint8_t));
buffer->data = newData; buffer->data = newData;
buffer->capacity = capacity; buffer->capacity = capacity;
} }
/* Get a byte from an index in the buffer */ /* 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) { if (index < buffer->count) {
return buffer->data[index]; return buffer->data[index];
} else { } else {
@ -38,29 +38,29 @@ int32_t BufferGet(Buffer * buffer, uint32_t index) {
} }
/* Push a byte into the buffer */ /* 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) { if (buffer->count >= buffer->capacity) {
BufferEnsure(vm, buffer, 2 * buffer->count); gst_buffer_ensure(vm, buffer, 2 * buffer->count);
} }
buffer->data[buffer->count++] = c; buffer->data[buffer->count++] = c;
} }
/* Push multiple bytes into the buffer */ /* 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; uint32_t newSize = buffer->count + length;
if (newSize > buffer->capacity) { if (newSize > buffer->capacity) {
BufferEnsure(vm, buffer, 2 * newSize); gst_buffer_ensure(vm, buffer, 2 * newSize);
} }
memcpy(buffer->data + buffer->count, string, length); memcpy(buffer->data + buffer->count, string, length);
buffer->count = newSize; buffer->count = newSize;
} }
/* Convert the buffer to a string */ /* Convert the buffer to a string */
uint8_t * BufferToString(VM * vm, Buffer * buffer) { uint8_t *gst_buffer_to_string(Gst *vm, GstBuffer *buffer) {
uint8_t * data = VMAlloc(vm, buffer->count + 2 * sizeof(uint32_t)); uint8_t *data = gst_alloc(vm, buffer->count + 2 * sizeof(uint32_t));
data += 2 * sizeof(uint32_t); data += 2 * sizeof(uint32_t);
VStringSize(data) = buffer->count; gst_string_length(data) = buffer->count;
VStringHash(data) = 0; gst_string_hash(data) = 0;
memcpy(data, buffer->data, buffer->count * sizeof(uint8_t)); memcpy(data, buffer->data, buffer->count * sizeof(uint8_t));
return data; return data;
} }
@ -70,9 +70,9 @@ uint8_t * BufferToString(VM * vm, Buffer * buffer) {
/****/ /****/
/* Creates a new array */ /* Creates a new array */
Array * ArrayNew(VM * vm, uint32_t capacity) { GstArray *gst_array(Gst * vm, uint32_t capacity) {
Array * array = VMAlloc(vm, sizeof(Array)); GstArray *array = gst_alloc(vm, sizeof(GstArray));
Value * data = VMAlloc(vm, capacity * sizeof(Value)); GstValue *data = gst_alloc(vm, capacity * sizeof(GstValue));
array->data = data; array->data = data;
array->count = 0; array->count = 0;
array->capacity = capacity; array->capacity = capacity;
@ -81,30 +81,29 @@ Array * ArrayNew(VM * vm, uint32_t capacity) {
} }
/* Ensure the array has enough capacity for capacity elements */ /* Ensure the array has enough capacity for capacity elements */
void ArrayEnsure(VM * vm, Array * array, uint32_t capacity) { void gst_array_ensure(Gst *vm, GstArray *array, uint32_t capacity) {
Value * newData; GstValue *newData;
if (capacity <= array->capacity) return; if (capacity <= array->capacity) return;
newData = VMAlloc(vm, capacity * sizeof(Value)); newData = gst_alloc(vm, capacity * sizeof(GstValue));
memcpy(newData, array->data, array->capacity * sizeof(Value)); memcpy(newData, array->data, array->capacity * sizeof(GstValue));
array->data = newData; array->data = newData;
array->capacity = capacity; array->capacity = capacity;
} }
/* Get a value of an array with bounds checking. */ /* 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) { if (index < array->count) {
return array->data[index]; return array->data[index];
} else { } else {
Value v; GstValue v;
v.type = TYPE_NIL; v.type = GST_NIL;
v.data.boolean = 0;
return v; return v;
} }
} }
/* Try to set an index in the array. Return 1 if successful, 0 /* Try to set an index in the array. Return 1 if successful, 0
* on failiure */ * 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) { if (index < array->count) {
array->data[index] = x; array->data[index] = x;
return 1; return 1;
@ -114,33 +113,31 @@ int ArraySet(Array * array, uint32_t index, Value x) {
} }
/* Add an item to the end of the array */ /* 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) { if (array->count >= array->capacity) {
ArrayEnsure(vm, array, 2 * array->count); gst_array_ensure(vm, array, 2 * array->count);
} }
array->data[array->count++] = x; array->data[array->count++] = x;
} }
/* Remove the last item from the Array and return it */ /* Remove the last item from the Array and return it */
Value ArrayPop(Array * array) { GstValue gst_array_pop(GstArray *array) {
if (array->count) { if (array->count) {
return array->data[--array->count]; return array->data[--array->count];
} else { } else {
Value v; GstValue v;
v.type = TYPE_NIL; v.type = GST_NIL;
v.data.boolean = 0;
return v; return v;
} }
} }
/* Look at the last item in the Array */ /* Look at the last item in the Array */
Value ArrayPeek(Array * array) { GstValue gst_array_peek(GstArray *array) {
if (array->count) { if (array->count) {
return array->data[array->count - 1]; return array->data[array->count - 1];
} else { } else {
Value v; GstValue v;
v.type = TYPE_NIL; v.type = GST_NIL;
v.data.boolean = 0;
return v; return v;
} }
} }
@ -150,76 +147,76 @@ Value ArrayPeek(Array * array) {
/****/ /****/
/* Create a new dictionary */ /* Create a new dictionary */
Dictionary * DictNew(VM * vm, uint32_t capacity) { GstObject* gst_object(Gst *vm, uint32_t capacity) {
Dictionary * dict = VMAlloc(vm, sizeof(Dictionary)); GstObject *o = gst_alloc(vm, sizeof(GstObject));
DictBucket ** buckets = VMZalloc(vm, capacity * sizeof(DictBucket *)); GstBucket **buckets = gst_zalloc(vm, capacity * sizeof(GstBucket *));
dict->buckets = buckets; o->buckets = buckets;
dict->capacity = capacity; o->capacity = capacity;
dict->count = 0; o->count = 0;
dict->flags = 0; o->flags = 0;
return dict; return o;
} }
/* Resize the dictionary table. */ /* Resize the dictionary table. */
static void DictReHash(VM * vm, Dictionary * dict, uint32_t size) { static void gst_object_rehash(Gst *vm, GstObject *o, uint32_t size) {
DictBucket ** newBuckets = VMZalloc(vm, size * sizeof(DictBucket *)); GstBucket **newBuckets = gst_zalloc(vm, size * sizeof(GstBucket *));
uint32_t i, count; uint32_t i, count;
for (i = 0, count = dict->capacity; i < count; ++i) { for (i = 0, count = o->capacity; i < count; ++i) {
DictBucket * bucket = dict->buckets[i]; GstBucket *bucket = o->buckets[i];
while (bucket) { while (bucket) {
uint32_t index; uint32_t index;
DictBucket * next = bucket->next; GstBucket *next = bucket->next;
index = ValueHash(bucket->key) % size; index = gst_hash(bucket->key) % size;
bucket->next = newBuckets[index]; bucket->next = newBuckets[index];
newBuckets[index] = bucket; newBuckets[index] = bucket;
bucket = next; bucket = next;
} }
} }
dict->buckets = newBuckets; o->buckets = newBuckets;
dict->capacity = size; o->capacity = size;
} }
/* Find the bucket that contains the given key */ /* Find the bucket that contains the given key */
static DictBucket * DictFind(Dictionary * dict, Value key) { static GstBucket *gst_object_find(GstObject *o, GstValue key) {
uint32_t index = ValueHash(key) % dict->capacity; uint32_t index = gst_hash(key) % o->capacity;
DictBucket * bucket = dict->buckets[index]; GstBucket *bucket = o->buckets[index];
while (bucket) { while (bucket) {
if (ValueEqual(bucket->key, key)) if (gst_equals(bucket->key, key))
return bucket; return bucket;
bucket = bucket->next; bucket = bucket->next;
} }
return (DictBucket *)0; return (GstBucket *)0;
} }
/* Get a value out of the dictionary */ /* Get a value out of the dictionary */
Value DictGet(Dictionary * dict, Value key) { GstValue gst_object_get(GstObject *o, GstValue key) {
DictBucket * bucket = DictFind(dict, key); GstBucket *bucket = gst_object_find(o, key);
if (bucket) { if (bucket) {
return bucket->value; return bucket->value;
} else { } else {
Value nil; GstValue nil;
nil.type = TYPE_NIL; nil.type = GST_NIL;
return nil; return nil;
} }
} }
/* Remove an entry from the dictionary */ /* Remove an entry from the dictionary */
Value DictRemove(VM * vm, Dictionary * dict, Value key) { GstValue gst_object_remove(Gst * vm, GstObject *o, GstValue key) {
DictBucket * bucket, * previous; GstBucket *bucket, *previous;
uint32_t index = ValueHash(key) % dict->capacity; uint32_t index = gst_hash(key) % o->capacity;
bucket = dict->buckets[index]; bucket = o->buckets[index];
previous = (DictBucket *)0; previous = (GstBucket *)0;
while (bucket) { while (bucket) {
if (ValueEqual(bucket->key, key)) { if (gst_equals(bucket->key, key)) {
if (previous) { if (previous) {
previous->next = bucket->next; previous->next = bucket->next;
} else { } else {
dict->buckets[index] = bucket->next; o->buckets[index] = bucket->next;
} }
if (dict->count < dict->capacity / 4) { if (o->count < o->capacity / 4) {
DictReHash(vm, dict, dict->capacity / 2); gst_object_rehash(vm, o, o->capacity / 2);
} }
--dict->count; --o->count;
return bucket->value; return bucket->value;
} }
previous = bucket; previous = bucket;
@ -227,74 +224,52 @@ Value DictRemove(VM * vm, Dictionary * dict, Value key) {
} }
/* Return nil if we found nothing */ /* Return nil if we found nothing */
{ {
Value nil; GstValue nil;
nil.type = TYPE_NIL; nil.type = GST_NIL;
return nil; return nil;
} }
} }
/* Put a value into the dictionary. Returns 1 if successful, 0 if out of memory. /* Put a value into the dictionary. Returns 1 if successful, 0 if out of memory.
* The VM pointer is needed for memory allocation. */ * The VM pointer is needed for memory allocation. */
void DictPut(VM * vm, Dictionary * dict, Value key, Value value) { void gst_object_put(Gst *vm, GstObject *o, GstValue key, GstValue value) {
DictBucket * bucket, * previous; GstBucket *bucket, *previous;
uint32_t index = ValueHash(key) % dict->capacity; uint32_t index = gst_hash(key) % o->capacity;
if (key.type == TYPE_NIL) return; if (key.type == GST_NIL) return;
/* Do a removal if value is nil */ /* Do a removal if value is nil */
if (value.type == TYPE_NIL) { if (value.type == GST_NIL) {
bucket = dict->buckets[index]; bucket = o->buckets[index];
previous = (DictBucket *)0; previous = (GstBucket *)0;
while (bucket) { while (bucket) {
if (ValueEqual(bucket->key, key)) { if (gst_equals(bucket->key, key)) {
if (previous) { if (previous) {
previous->next = bucket->next; previous->next = bucket->next;
} else { } else {
dict->buckets[index] = bucket->next; o->buckets[index] = bucket->next;
} }
if (dict->count < dict->capacity / 4) { if (o->count < o->capacity / 4) {
DictReHash(vm, dict, dict->capacity / 2); gst_object_rehash(vm, o, o->capacity / 2);
} }
--dict->count; --o->count;
return; return;
} }
previous = bucket; previous = bucket;
bucket = bucket->next; bucket = bucket->next;
} }
} else { } else {
bucket = DictFind(dict, key); bucket = gst_object_find(o, key);
if (bucket) { if (bucket) {
bucket->value = value; bucket->value = value;
} else { } else {
if (dict->count >= 2 * dict->capacity) { if (o->count >= 2 * o->capacity) {
DictReHash(vm, dict, 2 * dict->capacity); gst_object_rehash(vm, o, 2 * o->capacity);
} }
bucket = VMAlloc(vm, sizeof(DictBucket)); bucket = gst_alloc(vm, sizeof(GstBucket));
bucket->next = dict->buckets[index]; bucket->next = o->buckets[index];
bucket->value = value; bucket->value = value;
bucket->key = key; bucket->key = key;
dict->buckets[index] = bucket; o->buckets[index] = bucket;
++dict->count; ++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 * Data type flags
*/ */
#define DS_LOCKED 0x01 #define GST_DS_LOCKED 0x01
/****/ /****/
/* Buffer functions */ /* Buffer functions */
/****/ /****/
/* Create a new buffer */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 a push function for pushing a certain type to the buffer */
#define BufferDefine(name, type) \ #define BUFFER_DEFINE(name, type) \
static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \ static void gst_buffer_push_##name(Gst * vm, GstBuffer * buffer, type x) { \
union { type t; uint8_t bytes[sizeof(type)]; } u; \ 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 */ /* 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 /* Get a value of an array with bounds checking. Returns nil if
* outside bounds. */ * 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 /* Set a value in the array. Does bounds checking but will not grow
* or shrink the array */ * 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 */ /* 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 /* Set a value in an array. Will also append to the array if the index is
* greater than the current max index. */ * 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 */ /* 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 */ /* 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 */ /* Create a new object */
Dictionary * DictNew(VM * vm, uint32_t capacity); GstObject *gst_object(Gst *vm, uint32_t capacity);
/* Get a value out of the dictionary */ /* 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 /* Get a Value from the dictionary, but remove it at the same
* time. */ * 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. /* Put a value into the dictionary. Returns 1 if successful, 0 if out of memory.
* The VM pointer is needed for memory allocation. */ * The VM pointer is needed for memory allocation. */
void DictPut(VM * vm, Dictionary * dict, Value key, Value value); void gst_object_put(Gst *vm, GstObject *obj, GstValue key, GstValue 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);
#endif // ds_h_INCLUDED #endif // ds_h_INCLUDED

46
main.c
View File

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

199
parse.c
View File

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

10
parse.h
View File

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

251
value.c
View File

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

23
value.h
View File

@ -3,18 +3,27 @@
#include "datatypes.h" #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 */ #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" #include "datatypes.h"
/* Exit from the VM normally */ /* 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. */ /* 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. */ /* 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 */ /* Error if the condition is false */
#define VMAssert(vm, cond, e) do \ #define gst_assert(vm, cond, e) do \
{ if (!(cond)) { VMError((vm), (e)); } } while (0) { if (!(cond)) { gst_error((vm), (e)); } } while (0)
/* Type assertion */ /* Type assertion */
#define VMAssertType(vm, f, t) \ #define gst_assert_type(vm, f, t) \
VMAssert((vm), (f).type == (t), "Expected type,") gst_assert((vm), (f).type == (t), "Expected a different type.")
/* Initialize the VM */ /* Initialize the VM */
void VMInit(VM * vm); void gst_init(Gst * vm);
/* Deinitialize the VM */ /* Deinitialize the VM */
void VMDeinit(VM * vm); void gst_deinit(Gst * vm);
/* Load a function to be run on the 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 */ /* Start running the VM */
int VMStart(VM * vm); int gst_start(Gst * vm);
/* Run garbage collection */ /* Run garbage collection */
void VMCollect(VM * vm); void gst_collect(Gst * vm);
/* Collect garbage if enough memory has been allocated since /* Collect garbage if enough memory has been allocated since
* the previous collection */ * the previous collection */
void VMMaybeCollect(VM * vm); void gst_maybe_collect(Gst * vm);
/* Allocate memory */ /* Allocate memory */
void * VMAlloc(VM * vm, uint32_t amount); void * gst_alloc(Gst * vm, uint32_t amount);
/* Allocate zeroed memory */ /* Allocate zeroed memory */
void * VMZalloc(VM * vm, uint32_t amount); void * gst_zalloc(Gst * vm, uint32_t amount);
/* Get an argument from the stack */ /* 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 */ /* 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 */ /* 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 */ #endif /* end of include guard: VM_H_C4OZU8CQ */