mirror of
https://github.com/janet-lang/janet
synced 2025-02-17 17:20:01 +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"
|
#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 */
|
||||||
|
313
datatypes.h
313
datatypes.h
@ -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
212
disasm.c
@ -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");
|
||||||
|
6
disasm.h
6
disasm.h
@ -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
203
ds.c
@ -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
52
ds.h
@ -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
46
main.c
@ -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
199
parse.c
@ -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
10
parse.h
@ -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
251
value.c
@ -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
23
value.h
@ -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 */
|
||||||
|
36
vm.h
36
vm.h
@ -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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user