mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 07:33: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:
		
							
								
								
									
										10
									
								
								compile.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								compile.h
									
									
									
									
									
								
							| @@ -4,21 +4,21 @@ | ||||
| #include "datatypes.h" | ||||
|  | ||||
| /* Initialize the Compiler */ | ||||
| void CompilerInit(Compiler * c, VM * vm); | ||||
| void gst_compiler(GstCompiler *c, Gst *vm); | ||||
|  | ||||
| /* Register a global for the compilation environment. */ | ||||
| void CompilerAddGlobal(Compiler * c, const char * name, Value x); | ||||
| void gst_compiler_add_global(GstCompiler *c, const char *name, GstValue x); | ||||
|  | ||||
| /* Register a global c function for the compilation environment. */ | ||||
| void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f); | ||||
| void gst_compiler_add_global_cfunction(GstCompiler *c, const char *name, GstCFunction f); | ||||
|  | ||||
| /* Compile a function that evaluates the given form. */ | ||||
| Func * CompilerCompile(Compiler * c, Value form); | ||||
| GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form); | ||||
|  | ||||
| /* Macro expansion. Macro expansion happens prior to the compilation process | ||||
|  * and is completely separate. This allows the compilation to not have to worry | ||||
|  * about garbage collection and other issues that would complicate both the | ||||
|  * runtime and the compilation. */ | ||||
| int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out); | ||||
| int gst_macro_expand(Gst *vm, GstValue x, GstObject *macros, GstValue *out); | ||||
|  | ||||
| #endif /* end of include guard: COMPILE_H_9VXF71HY */ | ||||
|   | ||||
							
								
								
									
										313
									
								
								datatypes.h
									
									
									
									
									
								
							
							
						
						
									
										313
									
								
								datatypes.h
									
									
									
									
									
								
							| @@ -4,227 +4,234 @@ | ||||
| #include <stdint.h> | ||||
| #include <setjmp.h> | ||||
|  | ||||
| typedef enum Type { | ||||
|     TYPE_NIL = 0, | ||||
|     TYPE_NUMBER, | ||||
|     TYPE_BOOLEAN, | ||||
|     TYPE_STRING, | ||||
|     TYPE_ARRAY, | ||||
|     TYPE_THREAD, | ||||
|     TYPE_BYTEBUFFER, | ||||
|     TYPE_FUNCTION, | ||||
|     TYPE_CFUNCTION, | ||||
|     TYPE_DICTIONARY | ||||
| } Type; | ||||
| typedef enum GstType { | ||||
|     GST_NIL = 0, | ||||
|     GST_NUMBER, | ||||
|     GST_BOOLEAN, | ||||
|     GST_STRING, | ||||
|     GST_ARRAY, | ||||
|     GST_THREAD, | ||||
|     GST_BYTEBUFFER, | ||||
|     GST_FUNCTION, | ||||
|     GST_CFUNCTION, | ||||
|     GST_OBJECT | ||||
| } GstType; | ||||
|  | ||||
| typedef double Number; | ||||
| typedef uint8_t Boolean; | ||||
| typedef struct VM VM; | ||||
| typedef struct Value Value; | ||||
| typedef Value (*CFunction)(VM * vm); | ||||
| typedef struct Func Func; | ||||
| typedef struct FuncDef FuncDef; | ||||
| typedef struct FuncEnv FuncEnv; | ||||
| typedef union ValueData ValueData; | ||||
| typedef struct DictBucket DictBucket; | ||||
| typedef struct Array Array; | ||||
| typedef struct Buffer Buffer; | ||||
| typedef struct Dictionary Dictionary; | ||||
| typedef struct DictionaryIterator DictionaryIterator; | ||||
| typedef struct Parser Parser; | ||||
| typedef struct ParseState ParseState; | ||||
| typedef struct Scope Scope; | ||||
| typedef struct Compiler Compiler; | ||||
| typedef struct Thread Thread; | ||||
| typedef struct StackFrame StackFrame; | ||||
| /* The state of the virtual machine */ | ||||
| typedef struct Gst Gst; | ||||
|  | ||||
| union ValueData { | ||||
|     Boolean boolean; | ||||
|     Number number; | ||||
|     uint8_t * string; | ||||
|     Array * array; | ||||
|     Buffer * buffer; | ||||
|     Dictionary * dict; | ||||
|     Func * func; | ||||
|     Thread * thread; | ||||
|     void * pointer; | ||||
|     CFunction cfunction; | ||||
|     uint16_t u16[4]; | ||||
|     uint8_t u8[8]; | ||||
| } data; | ||||
| /* A general gst value type */ | ||||
| typedef struct GstValue GstValue; | ||||
|  | ||||
| struct Value { | ||||
|     Type type; | ||||
|     ValueData data; | ||||
| /* All of the gst types */ | ||||
| typedef double GstNumber; | ||||
| typedef uint8_t GstBoolean; | ||||
| typedef struct GstFunction GstFunction; | ||||
| typedef struct GstArray GstArray; | ||||
| typedef struct GstBuffer GstBuffer; | ||||
| typedef struct GstObject GstObject; | ||||
| typedef struct GstThread GstThread; | ||||
| typedef GstValue (*GstCFunction)(Gst * vm); | ||||
|  | ||||
| /* Implementation details */ | ||||
| typedef struct GstParser GstParser; | ||||
| typedef struct GstCompiler GstCompiler; | ||||
| typedef struct GstFuncDef GstFuncDef; | ||||
| typedef struct GstFuncEnv GstFuncEnv; | ||||
|  | ||||
| /* Definitely implementation details */ | ||||
| typedef struct GstStackFrame GstStackFrame; | ||||
| typedef struct GstParseState GstParseState; | ||||
| typedef struct GstBucket GstBucket; | ||||
| typedef struct GstScope GstScope; | ||||
|  | ||||
| /* The general gst value type. Contains a large union and | ||||
|  * the type information of the value */ | ||||
| struct GstValue { | ||||
|     GstType type; | ||||
|     union { | ||||
|         /* The various types */ | ||||
|         GstBoolean boolean; | ||||
|         GstNumber number; | ||||
|         GstArray *array; | ||||
|         GstBuffer *buffer; | ||||
|         GstObject *object; | ||||
|         GstThread *thread; | ||||
|         GstCFunction cfunction; | ||||
|         GstFunction *function; | ||||
|         uint8_t *string; | ||||
|         void *pointer; | ||||
|     } data; | ||||
| }; | ||||
|  | ||||
| struct Thread { | ||||
| /* A lightweight thread in gst. Does not correspond to | ||||
|  * operating system threads. Used in coroutines. */ | ||||
| struct GstThread { | ||||
| 	uint32_t count; | ||||
| 	uint32_t capacity; | ||||
| 	Value * data; | ||||
| 	GstValue *data; | ||||
| 	enum { | ||||
| 		THREAD_PENDING = 0, | ||||
| 		THREAD_ALIVE, | ||||
| 		TRHEAD_DEAD | ||||
| 		GST_THREAD_PENDING = 0, | ||||
| 		GST_THREAD_ALIVE, | ||||
| 		GST_TRHEAD_DEAD | ||||
| 	} status; | ||||
| }; | ||||
|  | ||||
| struct Array { | ||||
| /* A dynamic array type */ | ||||
| struct GstArray { | ||||
|     uint32_t count; | ||||
|     uint32_t capacity; | ||||
|     Value * data; | ||||
|     GstValue *data; | ||||
|     uint32_t flags; | ||||
| }; | ||||
|  | ||||
| struct Buffer { | ||||
| /* A bytebuffer type. Used as a mutable string or string builder. */ | ||||
| struct GstBuffer { | ||||
|     uint32_t count; | ||||
|     uint32_t capacity; | ||||
|     uint8_t * data; | ||||
|     uint8_t *data; | ||||
|     uint32_t flags; | ||||
| }; | ||||
|  | ||||
| struct Dictionary { | ||||
| /* The main Gst type, an obect. Objects are just hashtables with some meta | ||||
|  * information attached in the meta value */ | ||||
| struct GstObject { | ||||
|     uint32_t count; | ||||
|     uint32_t capacity; | ||||
|     DictBucket ** buckets; | ||||
|     GstBucket **buckets; | ||||
|     uint32_t flags; | ||||
|     Value meta; | ||||
|     GstValue meta; | ||||
| }; | ||||
|  | ||||
| struct DictionaryIterator { | ||||
|     Dictionary * dict; | ||||
|     uint32_t index; | ||||
|     DictBucket * bucket; | ||||
| }; | ||||
|  | ||||
| struct FuncDef { | ||||
| /* A function defintion. Contains information need to instatiate closures. */ | ||||
| struct GstFuncDef { | ||||
|     uint32_t locals; | ||||
|     uint32_t arity; | ||||
|     uint32_t literalsLen; | ||||
|     uint32_t byteCodeLen; | ||||
|     Value * literals; /* Contains strings, FuncDefs, etc. */ | ||||
|     uint16_t * byteCode; | ||||
|     GstValue *literals; /* Contains strings, FuncDefs, etc. */ | ||||
|     uint16_t *byteCode; | ||||
| }; | ||||
|  | ||||
| struct FuncEnv { | ||||
|     Thread * thread; /* When nil, index the local values */ | ||||
| /* A fuction environment */ | ||||
| struct GstFuncEnv { | ||||
|     GstThread *thread; /* When nil, index the local values */ | ||||
|     uint32_t stackOffset; /* Used as environment size when off stack */ | ||||
|     Value * values; | ||||
|     GstValue *values; | ||||
| }; | ||||
|  | ||||
| struct Func { | ||||
|     FuncDef * def; | ||||
|     FuncEnv * env; | ||||
|     Func * parent; | ||||
| /* A function */ | ||||
| struct GstFunction { | ||||
|     GstFuncDef *def; | ||||
|     GstFuncEnv *env; | ||||
|     GstFunction *parent; | ||||
| }; | ||||
|  | ||||
| struct DictBucket { | ||||
|     Value key; | ||||
|     Value value; | ||||
|     DictBucket * next; | ||||
| /* A hash table bucket in an object */ | ||||
| struct GstBucket { | ||||
|     GstValue key; | ||||
|     GstValue value; | ||||
|     GstBucket *next; | ||||
| }; | ||||
|  | ||||
| struct StackFrame { | ||||
|     Value callee; | ||||
| /* A stack frame in the VM */ | ||||
| struct GstStackFrame { | ||||
|     GstValue callee; | ||||
|     uint16_t size; | ||||
|     uint16_t prevSize; | ||||
|     uint16_t ret; | ||||
|     FuncEnv * env; | ||||
|     uint16_t * pc; | ||||
|     GstFuncEnv *env; | ||||
|     uint16_t *pc; | ||||
| }; | ||||
|  | ||||
| struct VM { | ||||
| /* The VM state */ | ||||
| struct Gst { | ||||
|     /* Garbage collection */ | ||||
|     void * blocks; | ||||
|     void *blocks; | ||||
|     uint32_t memoryInterval; | ||||
|     uint32_t nextCollection; | ||||
|     uint32_t black : 1; | ||||
|     uint32_t lock : 31; | ||||
|     /* Thread */ | ||||
|     uint16_t * pc; | ||||
|     Thread * thread; | ||||
|     Value * base; | ||||
|     StackFrame * frame; | ||||
|     uint16_t *pc; | ||||
|     GstThread *thread; | ||||
|     GstValue *base; | ||||
|     GstStackFrame *frame; | ||||
|     /* Return state */ | ||||
|     const char * error; | ||||
|     const char *error; | ||||
|     jmp_buf jump; | ||||
|     Value ret; /* Returned value from VMStart */ | ||||
|     GstValue ret; /* Returned value from VMStart */ | ||||
|     /* Object definitions */ | ||||
|     Value metas[TYPE_DICTIONARY]; | ||||
|     GstValue metas[GST_OBJECT]; | ||||
| }; | ||||
|  | ||||
| /* Parsing */ | ||||
|  | ||||
| struct Parser { | ||||
|     VM * vm; | ||||
|     const char * error; | ||||
|     ParseState * data; | ||||
|     Value value; | ||||
| struct GstParser { | ||||
|     Gst *vm; | ||||
|     const char *error; | ||||
|     GstParseState *data; | ||||
|     GstValue value; | ||||
|     uint32_t count; | ||||
|     uint32_t cap; | ||||
|     uint32_t index; | ||||
|     enum { | ||||
| 		PARSER_PENDING = 0, | ||||
| 		PARSER_FULL, | ||||
| 		PARSER_ERROR | ||||
| 		GST_PARSER_PENDING = 0, | ||||
| 		GST_PARSER_FULL, | ||||
| 		GST_PARSER_ERROR | ||||
|     } status; | ||||
| }; | ||||
|  | ||||
| /* Compiling */ | ||||
|  | ||||
| struct Compiler { | ||||
|     VM * vm; | ||||
|     const char * error; | ||||
| /* Compilation state */ | ||||
| struct GstCompiler { | ||||
|     Gst *vm; | ||||
|     const char *error; | ||||
|     jmp_buf onError; | ||||
|     Scope * tail; | ||||
|     Array * env; | ||||
|     Buffer * buffer; | ||||
|     GstScope *tail; | ||||
|     GstArray *env; | ||||
|     GstBuffer *buffer; | ||||
| }; | ||||
|  | ||||
| /* String utils */ | ||||
|  | ||||
| #define VStringRaw(s) ((uint32_t *)(s) - 2) | ||||
| #define VStringSize(v) (VStringRaw(v)[0]) | ||||
| #define VStringHash(v) (VStringRaw(v)[1]) | ||||
| #define gst_string_raw(s) ((uint32_t *)(s) - 2) | ||||
| #define gst_string_length(v) (gst_string_raw(v)[0]) | ||||
| #define gst_string_hash(v) (gst_string_raw(v)[1]) | ||||
|  | ||||
| /* Bytecode */ | ||||
|  | ||||
| enum OpCode { | ||||
|     VM_OP_ADD = 0,    /* 0x0000 */ | ||||
|     VM_OP_SUB,        /* 0x0001 */ | ||||
|     VM_OP_MUL,        /* 0x0002 */ | ||||
|     VM_OP_DIV,        /* 0x0003 */ | ||||
|     VM_OP_NOT,        /* 0x0004 */ | ||||
|     VM_OP_LD0,        /* 0x0005 */ | ||||
|     VM_OP_LD1,        /* 0x0006 */ | ||||
|     VM_OP_FLS,        /* 0x0007 */ | ||||
|     VM_OP_TRU,        /* 0x0008 */ | ||||
|     VM_OP_NIL,        /* 0x0009 */ | ||||
|     VM_OP_I16,        /* 0x000a */ | ||||
|     VM_OP_UPV,        /* 0x000b */ | ||||
|     VM_OP_JIF,        /* 0x000c */ | ||||
|     VM_OP_JMP,        /* 0x000d */ | ||||
|     VM_OP_CAL,        /* 0x000e */ | ||||
|     VM_OP_RET,        /* 0x000f */ | ||||
|     VM_OP_SUV,        /* 0x0010 */ | ||||
|     VM_OP_CST,        /* 0x0011 */ | ||||
|     VM_OP_I32,        /* 0x0012 */ | ||||
|     VM_OP_F64,        /* 0x0013 */ | ||||
|     VM_OP_MOV,        /* 0x0014 */ | ||||
|     VM_OP_CLN,        /* 0x0015 */ | ||||
|     VM_OP_EQL,        /* 0x0016 */ | ||||
|     VM_OP_LTN,        /* 0x0017 */ | ||||
|     VM_OP_LTE,        /* 0x0018 */ | ||||
|     VM_OP_ARR,        /* 0x0019 */ | ||||
|     VM_OP_DIC,        /* 0x001a */ | ||||
|     VM_OP_TCL,        /* 0x001b */ | ||||
|     VM_OP_ADM,        /* 0x001c */ | ||||
|     VM_OP_SBM,        /* 0x001d */ | ||||
|     VM_OP_MUM,        /* 0x001e */ | ||||
|     VM_OP_DVM,        /* 0x001f */ | ||||
|     VM_OP_RTN,        /* 0x0020 */ | ||||
|     VM_OP_SET,        /* 0x0021 */ | ||||
|     VM_OP_GET         /* 0x0022 */ | ||||
| enum GstOpCode { | ||||
|     GST_OP_ADD = 0,    /* 0x0000 */ | ||||
|     GST_OP_SUB,        /* 0x0001 */ | ||||
|     GST_OP_MUL,        /* 0x0002 */ | ||||
|     GST_OP_DIV,        /* 0x0003 */ | ||||
|     GST_OP_NOT,        /* 0x0004 */ | ||||
|     GST_OP_LD0,        /* 0x0005 */ | ||||
|     GST_OP_LD1,        /* 0x0006 */ | ||||
|     GST_OP_FLS,        /* 0x0007 */ | ||||
|     GST_OP_TRU,        /* 0x0008 */ | ||||
|     GST_OP_NIL,        /* 0x0009 */ | ||||
|     GST_OP_I16,        /* 0x000a */ | ||||
|     GST_OP_UPV,        /* 0x000b */ | ||||
|     GST_OP_JIF,        /* 0x000c */ | ||||
|     GST_OP_JMP,        /* 0x000d */ | ||||
|     GST_OP_CAL,        /* 0x000e */ | ||||
|     GST_OP_RET,        /* 0x000f */ | ||||
|     GST_OP_SUV,        /* 0x0010 */ | ||||
|     GST_OP_CST,        /* 0x0011 */ | ||||
|     GST_OP_I32,        /* 0x0012 */ | ||||
|     GST_OP_F64,        /* 0x0013 */ | ||||
|     GST_OP_MOV,        /* 0x0014 */ | ||||
|     GST_OP_CLN,        /* 0x0015 */ | ||||
|     GST_OP_EQL,        /* 0x0016 */ | ||||
|     GST_OP_LTN,        /* 0x0017 */ | ||||
|     GST_OP_LTE,        /* 0x0018 */ | ||||
|     GST_OP_ARR,        /* 0x0019 */ | ||||
|     GST_OP_DIC,        /* 0x001a */ | ||||
|     GST_OP_TCL,        /* 0x001b */ | ||||
|     GST_OP_ADM,        /* 0x001c */ | ||||
|     GST_OP_SBM,        /* 0x001d */ | ||||
|     GST_OP_MUM,        /* 0x001e */ | ||||
|     GST_OP_DVM,        /* 0x001f */ | ||||
|     GST_OP_RTN,        /* 0x0020 */ | ||||
|     GST_OP_SET,        /* 0x0021 */ | ||||
|     GST_OP_GET         /* 0x0022 */ | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										212
									
								
								disasm.c
									
									
									
									
									
								
							
							
						
						
									
										212
									
								
								disasm.c
									
									
									
									
									
								
							| @@ -4,17 +4,17 @@ | ||||
| #define OP_WIDTH 20 | ||||
|  | ||||
| /* Print various register and arguments to instructions */ | ||||
| static void dasmPrintSlot(FILE * out, uint16_t index) { fprintf(out, "%d ", index); } | ||||
| static void dasmPrintI16(FILE * out, int16_t number) { fprintf(out, "#%d ", number); } | ||||
| static void dasmPrintI32(FILE * out, int32_t number) { fprintf(out, "#%d ", number); } | ||||
| static void dasmPrintF64(FILE * out, double number) { fprintf(out, "#%f ", number); } | ||||
| static void dasmPrintLiteral(FILE * out, uint16_t index) { fprintf(out, "(%d) ", index); } | ||||
| static void dasmPrintUpValue(FILE * out, uint16_t level, uint16_t index) { | ||||
| static void dasm_print_slot(FILE * out, uint16_t index) { fprintf(out, "%d ", index); } | ||||
| static void dasm_print_i16(FILE * out, int16_t number) { fprintf(out, "#%d ", number); } | ||||
| static void dasm_print_i32(FILE * out, int32_t number) { fprintf(out, "#%d ", number); } | ||||
| static void dasm_print_f64(FILE * out, double number) { fprintf(out, "#%f ", number); } | ||||
| static void dasm_print_literal(FILE * out, uint16_t index) { fprintf(out, "(%d) ", index); } | ||||
| static void dasm_print_upvalue(FILE * out, uint16_t level, uint16_t index) { | ||||
| 	fprintf(out, "<%d, %d> ", level, index); | ||||
| } | ||||
|  | ||||
| /* Print the name of the argument but pad it */ | ||||
| static void dasmPrintArg(FILE * out, const char * name) {  | ||||
| static void dasm_print_arg(FILE * out, const char * name) {  | ||||
|     uint32_t i = 0; | ||||
|     char c; | ||||
|     while ((c = *name++)) { | ||||
| @@ -26,44 +26,44 @@ static void dasmPrintArg(FILE * out, const char * name) { | ||||
| } | ||||
|  | ||||
| /* Print instructions that take a fixed number of arguments */ | ||||
| static uint32_t dasmPrintFixedOp(FILE * out, const uint16_t * current, | ||||
| static uint32_t dasm_fixed_op(FILE * out, const uint16_t * current, | ||||
|                                  const char * name, uint32_t size) { | ||||
|     uint32_t i; | ||||
| 	dasmPrintArg(out, name); | ||||
| 	dasm_print_arg(out, name); | ||||
| 	for (i = 1; i <= size; ++i) { | ||||
| 		dasmPrintSlot(out, current[i]); | ||||
| 		dasm_print_slot(out, current[i]); | ||||
| 	} | ||||
| 	return size + 1; | ||||
| } | ||||
|  | ||||
| /* Print instructions that take a variable number of arguments */ | ||||
| static uint32_t dasmPrintVarArgOp(FILE * out, const uint16_t * current, | ||||
| static uint32_t dasm_varg_op(FILE * out, const uint16_t * current, | ||||
|                                   const char * name, uint32_t extra) { | ||||
| 	uint32_t i, argCount; | ||||
| 	dasmPrintArg(out, name); | ||||
| 	dasm_print_arg(out, name); | ||||
| 	for (i = 0; i < extra; ++i) { | ||||
| 		dasmPrintSlot(out, current[i + 1]); | ||||
| 		dasm_print_slot(out, current[i + 1]); | ||||
| 	} | ||||
| 	argCount = current[extra + 1]; | ||||
| 	fprintf(out, ": "); /* Argument separator */ | ||||
| 	for (i = 0; i < argCount; ++i) { | ||||
| 		dasmPrintSlot(out, current[i + extra + 2]); | ||||
| 		dasm_print_slot(out, current[i + extra + 2]); | ||||
| 	} | ||||
| 	return argCount + extra + 2; | ||||
| } | ||||
|  | ||||
| /* Print the disassembly for a function definition */ | ||||
| void dasmFuncDef(FILE * out, FuncDef * def) { | ||||
| 	dasm(out, def->byteCode, def->byteCodeLen); | ||||
| void gst_dasm_funcdef(FILE * out, GstFuncDef * def) { | ||||
| 	gst_dasm(out, def->byteCode, def->byteCodeLen); | ||||
| } | ||||
|  | ||||
| /* Print the disassembly for a function */ | ||||
| void dasmFunc(FILE * out, Func * f) { | ||||
| 	dasm(out, f->def->byteCode, f->def->byteCodeLen); | ||||
| void gst_dasm_function(FILE * out, GstFunction * f) { | ||||
| 	gst_dasm(out, f->def->byteCode, f->def->byteCodeLen); | ||||
| } | ||||
|  | ||||
| /* Disassemble some bytecode and display it as opcode + arguments assembly */ | ||||
| void dasm(FILE * out, uint16_t *byteCode, uint32_t len) { | ||||
| void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) { | ||||
| 	uint16_t *current = byteCode; | ||||
| 	uint16_t *end = byteCode + len; | ||||
|  | ||||
| @@ -71,136 +71,136 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) { | ||||
|  | ||||
| 	while (current < end) { | ||||
| 		switch (*current) { | ||||
| 		case VM_OP_ADD: | ||||
|     		current += dasmPrintFixedOp(out, current, "add", 3); | ||||
| 		case GST_OP_ADD: | ||||
|     		current += dasm_fixed_op(out, current, "add", 3); | ||||
|     		break; | ||||
| 		case VM_OP_SUB: | ||||
|     		current += dasmPrintFixedOp(out, current, "sub", 3); | ||||
| 		case GST_OP_SUB: | ||||
|     		current += dasm_fixed_op(out, current, "sub", 3); | ||||
|     		break;		 | ||||
|     	case VM_OP_MUL: | ||||
|     		current += dasmPrintFixedOp(out, current, "mul", 3); | ||||
|     	case GST_OP_MUL: | ||||
|     		current += dasm_fixed_op(out, current, "mul", 3); | ||||
|     		break;		 | ||||
|     	case VM_OP_DIV: | ||||
|     		current += dasmPrintFixedOp(out, current, "div", 3); | ||||
|     	case GST_OP_DIV: | ||||
|     		current += dasm_fixed_op(out, current, "div", 3); | ||||
|     		break; | ||||
|     	case VM_OP_NOT: | ||||
|         	current += dasmPrintFixedOp(out, current, "not", 2); | ||||
|     	case GST_OP_NOT: | ||||
|         	current += dasm_fixed_op(out, current, "not", 2); | ||||
|         	break; | ||||
|        	case VM_OP_LD0: | ||||
|            	current += dasmPrintFixedOp(out, current, "load0", 1); | ||||
|        	case GST_OP_LD0: | ||||
|            	current += dasm_fixed_op(out, current, "load0", 1); | ||||
|            	break; | ||||
|        	case VM_OP_LD1: | ||||
|            	current += dasmPrintFixedOp(out, current, "load1", 1); | ||||
|        	case GST_OP_LD1: | ||||
|            	current += dasm_fixed_op(out, current, "load1", 1); | ||||
|            	break; | ||||
|        	case VM_OP_FLS: | ||||
|            	current += dasmPrintFixedOp(out, current, "loadFalse", 1); | ||||
|        	case GST_OP_FLS: | ||||
|            	current += dasm_fixed_op(out, current, "loadFalse", 1); | ||||
|            	break; | ||||
|        	case VM_OP_TRU: | ||||
|            	current += dasmPrintFixedOp(out, current, "loadTrue", 1); | ||||
|        	case GST_OP_TRU: | ||||
|            	current += dasm_fixed_op(out, current, "loadTrue", 1); | ||||
|            	break; | ||||
|        	case VM_OP_NIL: | ||||
|            	current += dasmPrintFixedOp(out, current, "loadNil", 1); | ||||
|        	case GST_OP_NIL: | ||||
|            	current += dasm_fixed_op(out, current, "loadNil", 1); | ||||
|            	break; | ||||
|        	case VM_OP_I16: | ||||
|            	dasmPrintArg(out, "loadInt16"); | ||||
|            	dasmPrintSlot(out, current[1]); | ||||
|            	dasmPrintI16(out, ((int16_t *)current)[2]); | ||||
|        	case GST_OP_I16: | ||||
|            	dasm_print_arg(out, "loadInt16"); | ||||
|            	dasm_print_slot(out, current[1]); | ||||
|            	dasm_print_i16(out, ((int16_t *)current)[2]); | ||||
|            	current += 3; | ||||
|            	break; | ||||
|        	case VM_OP_UPV: | ||||
|            	dasmPrintArg(out, "loadUpValue"); | ||||
|            	dasmPrintSlot(out, current[1]); | ||||
|            	dasmPrintUpValue(out, current[2], current[3]); | ||||
|        	case GST_OP_UPV: | ||||
|            	dasm_print_arg(out, "loadUpValue"); | ||||
|            	dasm_print_slot(out, current[1]); | ||||
|            	dasm_print_upvalue(out, current[2], current[3]); | ||||
|            	current += 4; | ||||
|            	break; | ||||
|        	case VM_OP_JIF: | ||||
|            	dasmPrintArg(out, "jumpIf"); | ||||
|            	dasmPrintSlot(out, current[1]); | ||||
|            	dasmPrintI32(out, ((int32_t *)(current + 2))[0]); | ||||
|        	case GST_OP_JIF: | ||||
|            	dasm_print_arg(out, "jumpIf"); | ||||
|            	dasm_print_slot(out, current[1]); | ||||
|            	dasm_print_i32(out, ((int32_t *)(current + 2))[0]); | ||||
|            	current += 4; | ||||
|            	break; | ||||
|        	case VM_OP_JMP: | ||||
|            	dasmPrintArg(out, "jump"); | ||||
|            	dasmPrintI32(out, ((int32_t *)(current + 1))[0]); | ||||
|        	case GST_OP_JMP: | ||||
|            	dasm_print_arg(out, "jump"); | ||||
|            	dasm_print_i32(out, ((int32_t *)(current + 1))[0]); | ||||
|            	current += 3; | ||||
|            	break; | ||||
|        	case VM_OP_CAL: | ||||
|            	current += dasmPrintVarArgOp(out, current, "call", 2); | ||||
|        	case GST_OP_CAL: | ||||
|            	current += dasm_varg_op(out, current, "call", 2); | ||||
|            	break; | ||||
|        	case VM_OP_RET: | ||||
|            	current += dasmPrintFixedOp(out, current, "return", 1); | ||||
|        	case GST_OP_RET: | ||||
|            	current += dasm_fixed_op(out, current, "return", 1); | ||||
|            	break; | ||||
|        	case VM_OP_SUV: | ||||
|            	dasmPrintArg(out, "setUpValue"); | ||||
|            	dasmPrintSlot(out, current[1]); | ||||
|            	dasmPrintUpValue(out, current[2], current[3]); | ||||
|        	case GST_OP_SUV: | ||||
|            	dasm_print_arg(out, "setUpValue"); | ||||
|            	dasm_print_slot(out, current[1]); | ||||
|            	dasm_print_upvalue(out, current[2], current[3]); | ||||
|            	current += 4; | ||||
|            	break; | ||||
|        	case VM_OP_CST: | ||||
|            	dasmPrintArg(out, "loadLiteral"); | ||||
|            	dasmPrintSlot(out, current[1]); | ||||
|            	dasmPrintLiteral(out, current[2]); | ||||
|        	case GST_OP_CST: | ||||
|            	dasm_print_arg(out, "loadLiteral"); | ||||
|            	dasm_print_slot(out, current[1]); | ||||
|            	dasm_print_literal(out, current[2]); | ||||
|            	current += 3; | ||||
|            	break; | ||||
|        	case VM_OP_I32: | ||||
|            	dasmPrintArg(out, "loadInt32"); | ||||
|            	dasmPrintSlot(out, current[1]); | ||||
|            	dasmPrintI32(out, ((int32_t *)(current + 2))[0]); | ||||
|        	case GST_OP_I32: | ||||
|            	dasm_print_arg(out, "loadInt32"); | ||||
|            	dasm_print_slot(out, current[1]); | ||||
|            	dasm_print_i32(out, ((int32_t *)(current + 2))[0]); | ||||
|            	current += 4; | ||||
|            	break; | ||||
|        	case VM_OP_F64: | ||||
|            	dasmPrintArg(out, "loadFloat64"); | ||||
|            	dasmPrintSlot(out, current[1]); | ||||
|            	dasmPrintF64(out, ((double *)(current + 2))[0]); | ||||
|        	case GST_OP_F64: | ||||
|            	dasm_print_arg(out, "loadFloat64"); | ||||
|            	dasm_print_slot(out, current[1]); | ||||
|            	dasm_print_f64(out, ((double *)(current + 2))[0]); | ||||
|            	current += 6; | ||||
|            	break; | ||||
|        	case VM_OP_MOV: | ||||
|            	current += dasmPrintFixedOp(out, current, "move", 2); | ||||
|        	case GST_OP_MOV: | ||||
|            	current += dasm_fixed_op(out, current, "move", 2); | ||||
|            	break; | ||||
|        	case VM_OP_CLN: | ||||
|            	dasmPrintArg(out, "makeClosure"); | ||||
|            	dasmPrintSlot(out, current[1]); | ||||
|            	dasmPrintLiteral(out, current[2]); | ||||
|        	case GST_OP_CLN: | ||||
|            	dasm_print_arg(out, "makeClosure"); | ||||
|            	dasm_print_slot(out, current[1]); | ||||
|            	dasm_print_literal(out, current[2]); | ||||
|            	current += 3; | ||||
|            	break; | ||||
|        	case VM_OP_EQL: | ||||
|            	current += dasmPrintFixedOp(out, current, "equals", 3); | ||||
|        	case GST_OP_EQL: | ||||
|            	current += dasm_fixed_op(out, current, "equals", 3); | ||||
|            	break; | ||||
|        	case VM_OP_LTN: | ||||
|            	current += dasmPrintFixedOp(out, current, "lessThan", 3); | ||||
|        	case GST_OP_LTN: | ||||
|            	current += dasm_fixed_op(out, current, "lessThan", 3); | ||||
|            	break; | ||||
|        	case VM_OP_LTE: | ||||
|            	current += dasmPrintFixedOp(out, current, "lessThanEquals", 3); | ||||
|        	case GST_OP_LTE: | ||||
|            	current += dasm_fixed_op(out, current, "lessThanEquals", 3); | ||||
|            	break; | ||||
|        	case VM_OP_ARR: | ||||
|            	current += dasmPrintVarArgOp(out, current, "array", 1); | ||||
|        	case GST_OP_ARR: | ||||
|            	current += dasm_varg_op(out, current, "array", 1); | ||||
|            	break; | ||||
|        	case VM_OP_DIC: | ||||
|            	current += dasmPrintVarArgOp(out, current, "dictionary", 1); | ||||
|        	case GST_OP_DIC: | ||||
|            	current += dasm_varg_op(out, current, "dictionary", 1); | ||||
|            	break; | ||||
|        	case VM_OP_TCL: | ||||
|            	current += dasmPrintVarArgOp(out, current, "tailCall", 1); | ||||
|        	case GST_OP_TCL: | ||||
|            	current += dasm_varg_op(out, current, "tailCall", 1); | ||||
|            	break; | ||||
|        	case VM_OP_ADM: | ||||
|            	current += dasmPrintVarArgOp(out, current, "addMultiple", 1); | ||||
|        	case GST_OP_ADM: | ||||
|            	current += dasm_varg_op(out, current, "addMultiple", 1); | ||||
|            	break; | ||||
|        	case VM_OP_SBM: | ||||
|            	current += dasmPrintVarArgOp(out, current, "subMultiple", 1); | ||||
|        	case GST_OP_SBM: | ||||
|            	current += dasm_varg_op(out, current, "subMultiple", 1); | ||||
|            	break; | ||||
|        	case VM_OP_MUM: | ||||
|            	current += dasmPrintVarArgOp(out, current, "mulMultiple", 1); | ||||
|        	case GST_OP_MUM: | ||||
|            	current += dasm_varg_op(out, current, "mulMultiple", 1); | ||||
|            	break; | ||||
|        	case VM_OP_DVM: | ||||
|            	current += dasmPrintVarArgOp(out, current, "divMultiple", 1); | ||||
|        	case GST_OP_DVM: | ||||
|            	current += dasm_varg_op(out, current, "divMultiple", 1); | ||||
|            	break; | ||||
|         case VM_OP_RTN: | ||||
| 			current += dasmPrintFixedOp(out, current, "returnNil", 0); | ||||
|         case GST_OP_RTN: | ||||
| 			current += dasm_fixed_op(out, current, "returnNil", 0); | ||||
|             break; | ||||
|         case VM_OP_GET: | ||||
|             current += dasmPrintFixedOp(out, current, "get", 3); | ||||
|         case GST_OP_GET: | ||||
|             current += dasm_fixed_op(out, current, "get", 3); | ||||
|             break; | ||||
|         case VM_OP_SET: | ||||
|             current += dasmPrintFixedOp(out, current, "set", 3); | ||||
|         case GST_OP_SET: | ||||
|             current += dasm_fixed_op(out, current, "set", 3); | ||||
|             break; | ||||
| 		} | ||||
| 		fprintf(out, "\n"); | ||||
|   | ||||
							
								
								
									
										6
									
								
								disasm.h
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								disasm.h
									
									
									
									
									
								
							| @@ -5,13 +5,13 @@ | ||||
| #include <stdio.h> | ||||
|  | ||||
| /* Print disassembly for a given funciton */ | ||||
| void dasm(FILE * out, uint16_t * byteCode, uint32_t len); | ||||
| void gst_dasm(FILE * out, uint16_t * byteCode, uint32_t len); | ||||
|  | ||||
| /* Print the disassembly for a function definition */ | ||||
| void dasmFuncDef(FILE * out, FuncDef * def); | ||||
| void gst_dasm_funcdef(FILE * out, GstFuncDef * def); | ||||
|  | ||||
| /* Print the disassembly for a function */ | ||||
| void dasmFunc(FILE * out, Func * f); | ||||
| void gst_dasm_function(FILE * out, GstFunction * f); | ||||
|  | ||||
| #endif // disasm_h_INCLUDED | ||||
|  | ||||
|   | ||||
							
								
								
									
										203
									
								
								ds.c
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								ds.c
									
									
									
									
									
								
							| @@ -8,9 +8,9 @@ | ||||
| /****/ | ||||
|  | ||||
| /* Create a new Buffer */ | ||||
| Buffer * BufferNew(VM * vm, uint32_t capacity) { | ||||
|     Buffer * buffer = VMAlloc(vm, sizeof(Buffer)); | ||||
|     uint8_t * data = VMAlloc(vm, sizeof(uint8_t) * capacity); | ||||
| GstBuffer *gst_buffer(Gst *vm, uint32_t capacity) { | ||||
|     GstBuffer *buffer = gst_alloc(vm, sizeof(GstBuffer)); | ||||
|     uint8_t *data = gst_alloc(vm, sizeof(uint8_t) * capacity); | ||||
|     buffer->data = data; | ||||
|     buffer->count = 0; | ||||
|     buffer->capacity = capacity; | ||||
| @@ -19,17 +19,17 @@ Buffer * BufferNew(VM * vm, uint32_t capacity) { | ||||
| } | ||||
|  | ||||
| /* Ensure that the buffer has enough internal capacity */ | ||||
| void BufferEnsure(VM * vm, Buffer * buffer, uint32_t capacity) { | ||||
| void gst_buffer_ensure(Gst *vm, GstBuffer *buffer, uint32_t capacity) { | ||||
|     uint8_t * newData; | ||||
|     if (capacity <= buffer->capacity) return; | ||||
|     newData = VMAlloc(vm, capacity * sizeof(uint8_t)); | ||||
|     newData = gst_alloc(vm, capacity * sizeof(uint8_t)); | ||||
|     memcpy(newData, buffer->data, buffer->count * sizeof(uint8_t)); | ||||
|     buffer->data = newData; | ||||
|     buffer->capacity = capacity; | ||||
| } | ||||
|  | ||||
| /* Get a byte from an index in the buffer */ | ||||
| int32_t BufferGet(Buffer * buffer, uint32_t index) { | ||||
| int gst_buffer_get(GstBuffer *buffer, uint32_t index) { | ||||
|     if (index < buffer->count) { | ||||
|         return buffer->data[index]; | ||||
|     } else { | ||||
| @@ -38,29 +38,29 @@ int32_t BufferGet(Buffer * buffer, uint32_t index) { | ||||
| } | ||||
|  | ||||
| /* Push a byte into the buffer */ | ||||
| void BufferPush(VM * vm, Buffer * buffer, uint8_t c) { | ||||
| void gst_buffer_push(Gst *vm, GstBuffer * buffer, uint8_t c) { | ||||
|     if (buffer->count >= buffer->capacity) { | ||||
|         BufferEnsure(vm, buffer, 2 * buffer->count); | ||||
|         gst_buffer_ensure(vm, buffer, 2 * buffer->count); | ||||
|     } | ||||
|     buffer->data[buffer->count++] = c; | ||||
| } | ||||
|  | ||||
| /* Push multiple bytes into the buffer */ | ||||
| void BufferAppendData(VM * vm, Buffer * buffer, uint8_t * string, uint32_t length) { | ||||
| void gst_buffer_append(Gst *vm, GstBuffer *buffer, uint8_t *string, uint32_t length) { | ||||
|     uint32_t newSize = buffer->count + length; | ||||
|     if (newSize > buffer->capacity) { | ||||
|         BufferEnsure(vm, buffer, 2 * newSize); | ||||
|         gst_buffer_ensure(vm, buffer, 2 * newSize); | ||||
|     } | ||||
|     memcpy(buffer->data + buffer->count, string, length); | ||||
|     buffer->count = newSize; | ||||
| } | ||||
|  | ||||
| /* Convert the buffer to a string */ | ||||
| uint8_t * BufferToString(VM * vm, Buffer * buffer) { | ||||
|     uint8_t * data = VMAlloc(vm, buffer->count + 2 * sizeof(uint32_t)); | ||||
| uint8_t *gst_buffer_to_string(Gst *vm, GstBuffer *buffer) { | ||||
|     uint8_t *data = gst_alloc(vm, buffer->count + 2 * sizeof(uint32_t)); | ||||
|     data += 2 * sizeof(uint32_t); | ||||
|     VStringSize(data) = buffer->count; | ||||
|     VStringHash(data) = 0; | ||||
|     gst_string_length(data) = buffer->count; | ||||
|     gst_string_hash(data) = 0; | ||||
|     memcpy(data, buffer->data, buffer->count * sizeof(uint8_t)); | ||||
|     return data; | ||||
| } | ||||
| @@ -70,9 +70,9 @@ uint8_t * BufferToString(VM * vm, Buffer * buffer) { | ||||
| /****/ | ||||
|  | ||||
| /* Creates a new array */ | ||||
| Array * ArrayNew(VM * vm, uint32_t capacity) { | ||||
|     Array * array = VMAlloc(vm, sizeof(Array)); | ||||
|     Value * data = VMAlloc(vm, capacity * sizeof(Value)); | ||||
| GstArray *gst_array(Gst * vm, uint32_t capacity) { | ||||
|     GstArray *array = gst_alloc(vm, sizeof(GstArray)); | ||||
|     GstValue *data = gst_alloc(vm, capacity * sizeof(GstValue)); | ||||
|     array->data = data; | ||||
|     array->count = 0; | ||||
|     array->capacity = capacity; | ||||
| @@ -81,30 +81,29 @@ Array * ArrayNew(VM * vm, uint32_t capacity) { | ||||
| } | ||||
|  | ||||
| /* Ensure the array has enough capacity for capacity elements */ | ||||
| void ArrayEnsure(VM * vm, Array * array, uint32_t capacity) { | ||||
|     Value * newData; | ||||
| void gst_array_ensure(Gst *vm, GstArray *array, uint32_t capacity) { | ||||
|     GstValue *newData; | ||||
|     if (capacity <= array->capacity) return; | ||||
|     newData = VMAlloc(vm, capacity * sizeof(Value)); | ||||
|     memcpy(newData, array->data, array->capacity * sizeof(Value)); | ||||
|     newData = gst_alloc(vm, capacity * sizeof(GstValue)); | ||||
|     memcpy(newData, array->data, array->capacity * sizeof(GstValue)); | ||||
|     array->data = newData; | ||||
|     array->capacity = capacity; | ||||
| } | ||||
|  | ||||
| /* Get a value of an array with bounds checking. */ | ||||
| Value ArrayGet(Array * array, uint32_t index) { | ||||
| GstValue gst_array_get(GstArray *array, uint32_t index) { | ||||
|     if (index < array->count) { | ||||
|         return array->data[index]; | ||||
|     } else { | ||||
|         Value v; | ||||
|         v.type = TYPE_NIL; | ||||
|         v.data.boolean = 0; | ||||
|         GstValue v; | ||||
|         v.type = GST_NIL; | ||||
|         return v; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Try to set an index in the array. Return 1 if successful, 0 | ||||
|  * on failiure */ | ||||
| int ArraySet(Array * array, uint32_t index, Value x) { | ||||
| int gst_array_set(GstArray *array, uint32_t index, GstValue x) { | ||||
|     if (index < array->count) { | ||||
|         array->data[index] = x; | ||||
|         return 1; | ||||
| @@ -114,33 +113,31 @@ int ArraySet(Array * array, uint32_t index, Value x) { | ||||
| } | ||||
|  | ||||
| /* Add an item to the end of the array */ | ||||
| void ArrayPush(VM * vm, Array * array, Value x) { | ||||
| void gst_array_push(Gst *vm, GstArray *array, GstValue x) { | ||||
|     if (array->count >= array->capacity) { | ||||
|         ArrayEnsure(vm, array, 2 * array->count); | ||||
|         gst_array_ensure(vm, array, 2 * array->count); | ||||
|     } | ||||
|     array->data[array->count++] = x; | ||||
| } | ||||
|  | ||||
| /* Remove the last item from the Array and return it */ | ||||
| Value ArrayPop(Array * array) { | ||||
| GstValue gst_array_pop(GstArray *array) { | ||||
|     if (array->count) { | ||||
|         return array->data[--array->count]; | ||||
|     } else { | ||||
|         Value v; | ||||
|         v.type = TYPE_NIL; | ||||
|         v.data.boolean = 0; | ||||
|         GstValue v; | ||||
|         v.type = GST_NIL; | ||||
|         return v; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Look at the last item in the Array */ | ||||
| Value ArrayPeek(Array * array) { | ||||
| GstValue gst_array_peek(GstArray *array) { | ||||
|     if (array->count) { | ||||
|         return array->data[array->count - 1]; | ||||
|     } else { | ||||
|         Value v; | ||||
|         v.type = TYPE_NIL; | ||||
|         v.data.boolean = 0; | ||||
|         GstValue v; | ||||
|         v.type = GST_NIL; | ||||
|         return v; | ||||
|     } | ||||
| } | ||||
| @@ -150,76 +147,76 @@ Value ArrayPeek(Array * array) { | ||||
| /****/ | ||||
|  | ||||
| /* Create a new dictionary */ | ||||
| Dictionary * DictNew(VM * vm, uint32_t capacity) { | ||||
|     Dictionary * dict = VMAlloc(vm, sizeof(Dictionary)); | ||||
|     DictBucket ** buckets = VMZalloc(vm, capacity * sizeof(DictBucket *)); | ||||
|     dict->buckets = buckets; | ||||
|     dict->capacity = capacity; | ||||
|     dict->count = 0; | ||||
|     dict->flags = 0; | ||||
|     return dict; | ||||
| GstObject* gst_object(Gst *vm, uint32_t capacity) { | ||||
|     GstObject *o = gst_alloc(vm, sizeof(GstObject)); | ||||
|     GstBucket **buckets = gst_zalloc(vm, capacity * sizeof(GstBucket *)); | ||||
|     o->buckets = buckets; | ||||
|     o->capacity = capacity; | ||||
|     o->count = 0; | ||||
|     o->flags = 0; | ||||
|     return o; | ||||
| } | ||||
|  | ||||
| /* Resize the dictionary table. */ | ||||
| static void DictReHash(VM * vm, Dictionary * dict, uint32_t size) { | ||||
|     DictBucket ** newBuckets = VMZalloc(vm, size * sizeof(DictBucket *)); | ||||
| static void gst_object_rehash(Gst *vm, GstObject *o, uint32_t size) { | ||||
|     GstBucket **newBuckets = gst_zalloc(vm, size * sizeof(GstBucket *)); | ||||
|     uint32_t i, count; | ||||
|     for (i = 0, count = dict->capacity; i < count; ++i) { | ||||
|         DictBucket * bucket = dict->buckets[i]; | ||||
|     for (i = 0, count = o->capacity; i < count; ++i) { | ||||
|         GstBucket *bucket = o->buckets[i]; | ||||
|         while (bucket) { | ||||
|             uint32_t index; | ||||
|             DictBucket * next = bucket->next; | ||||
|             index = ValueHash(bucket->key) % size; | ||||
|             GstBucket *next = bucket->next; | ||||
|             index = gst_hash(bucket->key) % size; | ||||
|             bucket->next = newBuckets[index]; | ||||
|             newBuckets[index] = bucket; | ||||
|             bucket = next; | ||||
|         } | ||||
|     } | ||||
|     dict->buckets = newBuckets; | ||||
|     dict->capacity = size; | ||||
|     o->buckets = newBuckets; | ||||
|     o->capacity = size; | ||||
| } | ||||
|  | ||||
| /* Find the bucket that contains the given key */ | ||||
| static DictBucket * DictFind(Dictionary * dict, Value key) { | ||||
|     uint32_t index = ValueHash(key) % dict->capacity; | ||||
|     DictBucket * bucket = dict->buckets[index]; | ||||
| static GstBucket *gst_object_find(GstObject *o, GstValue key) { | ||||
|     uint32_t index = gst_hash(key) % o->capacity; | ||||
|     GstBucket *bucket = o->buckets[index]; | ||||
|     while (bucket) { | ||||
|         if (ValueEqual(bucket->key, key)) | ||||
|         if (gst_equals(bucket->key, key)) | ||||
|             return bucket; | ||||
|         bucket = bucket->next; | ||||
|     } | ||||
|     return (DictBucket *)0; | ||||
|     return (GstBucket *)0; | ||||
| } | ||||
|  | ||||
| /* Get a value out of the dictionary */ | ||||
| Value DictGet(Dictionary * dict, Value key) { | ||||
|     DictBucket * bucket = DictFind(dict, key); | ||||
| GstValue gst_object_get(GstObject *o, GstValue key) { | ||||
|     GstBucket *bucket = gst_object_find(o, key); | ||||
|     if (bucket) { | ||||
|         return bucket->value; | ||||
|     } else { | ||||
|         Value nil; | ||||
|         nil.type = TYPE_NIL; | ||||
|         GstValue nil; | ||||
|         nil.type = GST_NIL; | ||||
|         return nil; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Remove an entry from the dictionary */ | ||||
| Value DictRemove(VM * vm, Dictionary * dict, Value key) { | ||||
|     DictBucket * bucket, * previous; | ||||
|     uint32_t index = ValueHash(key) % dict->capacity; | ||||
|     bucket = dict->buckets[index]; | ||||
|     previous = (DictBucket *)0; | ||||
| GstValue gst_object_remove(Gst * vm, GstObject *o, GstValue key) { | ||||
|     GstBucket *bucket, *previous; | ||||
|     uint32_t index = gst_hash(key) % o->capacity; | ||||
|     bucket = o->buckets[index]; | ||||
|     previous = (GstBucket *)0; | ||||
|     while (bucket) { | ||||
|         if (ValueEqual(bucket->key, key)) { | ||||
|         if (gst_equals(bucket->key, key)) { | ||||
|             if (previous) { | ||||
|                 previous->next = bucket->next; | ||||
|             } else { | ||||
|                 dict->buckets[index] = bucket->next; | ||||
|                 o->buckets[index] = bucket->next; | ||||
|             } | ||||
|             if (dict->count < dict->capacity / 4) { | ||||
|                 DictReHash(vm, dict, dict->capacity / 2); | ||||
|             if (o->count < o->capacity / 4) { | ||||
|                 gst_object_rehash(vm, o, o->capacity / 2); | ||||
|             } | ||||
|             --dict->count; | ||||
|             --o->count; | ||||
|             return bucket->value; | ||||
|         } | ||||
|         previous = bucket; | ||||
| @@ -227,74 +224,52 @@ Value DictRemove(VM * vm, Dictionary * dict, Value key) { | ||||
|     } | ||||
|     /* Return nil if we found nothing */ | ||||
|     { | ||||
|         Value nil; | ||||
|         nil.type = TYPE_NIL; | ||||
|         GstValue nil; | ||||
|         nil.type = GST_NIL; | ||||
|         return nil; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Put a value into the dictionary. Returns 1 if successful, 0 if out of memory. | ||||
|  * The VM pointer is needed for memory allocation. */ | ||||
| void DictPut(VM * vm, Dictionary * dict, Value key, Value value) { | ||||
|     DictBucket * bucket, * previous; | ||||
|     uint32_t index = ValueHash(key) % dict->capacity; | ||||
|     if (key.type == TYPE_NIL) return; | ||||
| void gst_object_put(Gst *vm, GstObject *o, GstValue key, GstValue value) { | ||||
|     GstBucket *bucket, *previous; | ||||
|     uint32_t index = gst_hash(key) % o->capacity; | ||||
|     if (key.type == GST_NIL) return; | ||||
|     /* Do a removal if value is nil */ | ||||
|     if (value.type == TYPE_NIL) { | ||||
|         bucket = dict->buckets[index]; | ||||
|         previous = (DictBucket *)0; | ||||
|     if (value.type == GST_NIL) { | ||||
|         bucket = o->buckets[index]; | ||||
|         previous = (GstBucket *)0; | ||||
|         while (bucket) { | ||||
|             if (ValueEqual(bucket->key, key)) { | ||||
|             if (gst_equals(bucket->key, key)) { | ||||
|                 if (previous) { | ||||
|                     previous->next = bucket->next; | ||||
|                 } else { | ||||
|                     dict->buckets[index] = bucket->next; | ||||
|                     o->buckets[index] = bucket->next; | ||||
|                 } | ||||
|                 if (dict->count < dict->capacity / 4) { | ||||
|                     DictReHash(vm, dict, dict->capacity / 2); | ||||
|                 if (o->count < o->capacity / 4) { | ||||
|                     gst_object_rehash(vm, o, o->capacity / 2); | ||||
|                 } | ||||
|                 --dict->count; | ||||
|                 --o->count; | ||||
|                 return; | ||||
|             } | ||||
|             previous = bucket; | ||||
|             bucket = bucket->next; | ||||
|         } | ||||
|     } else { | ||||
|         bucket = DictFind(dict, key); | ||||
|         bucket = gst_object_find(o, key); | ||||
|         if (bucket) { | ||||
|             bucket->value = value; | ||||
|         } else { | ||||
|             if (dict->count >= 2 * dict->capacity) { | ||||
|                 DictReHash(vm, dict, 2 * dict->capacity); | ||||
|             if (o->count >= 2 * o->capacity) { | ||||
|                 gst_object_rehash(vm, o, 2 * o->capacity); | ||||
|             } | ||||
|             bucket = VMAlloc(vm, sizeof(DictBucket)); | ||||
|             bucket->next = dict->buckets[index]; | ||||
|             bucket = gst_alloc(vm, sizeof(GstBucket)); | ||||
|             bucket->next = o->buckets[index]; | ||||
|             bucket->value = value; | ||||
|             bucket->key = key; | ||||
|             dict->buckets[index] = bucket; | ||||
|             ++dict->count; | ||||
|             o->buckets[index] = bucket; | ||||
|             ++o->count; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Begin iteration through a dictionary */ | ||||
| void DictIterate(Dictionary * dict, DictionaryIterator * iterator) { | ||||
|     iterator->index = 0; | ||||
|     iterator->dict = dict; | ||||
|     iterator->bucket = dict->buckets[0]; | ||||
| } | ||||
|  | ||||
| /* Provides a mechanism for iterating through a table. */ | ||||
| int DictIterateNext(DictionaryIterator * iterator, DictBucket ** bucket) { | ||||
|     Dictionary * dict = iterator->dict; | ||||
|     for (;;) { | ||||
|         if (iterator->bucket) { | ||||
|             *bucket = iterator->bucket; | ||||
|             iterator->bucket = iterator->bucket->next; | ||||
|             return 1; | ||||
|         } | ||||
|         if (++iterator->index >= dict->capacity) break; | ||||
|         iterator->bucket = dict->buckets[iterator->index]; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
							
								
								
									
										52
									
								
								ds.h
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								ds.h
									
									
									
									
									
								
							| @@ -6,35 +6,35 @@ | ||||
| /* | ||||
|  * Data type flags | ||||
|  */ | ||||
| #define DS_LOCKED 0x01 | ||||
| #define GST_DS_LOCKED 0x01 | ||||
|  | ||||
| /****/ | ||||
| /* Buffer functions */ | ||||
| /****/ | ||||
|  | ||||
| /* Create a new buffer */ | ||||
| Buffer * BufferNew(VM * vm, uint32_t capacity); | ||||
| GstBuffer *gst_buffer(Gst *vm, uint32_t capacity); | ||||
|  | ||||
| /* Ensure the buffer has enough capacity */ | ||||
| void BufferEnsure(VM * vm, Buffer * buffer, uint32_t capacity); | ||||
| void gst_buffer_ensure(Gst *vm, GstBuffer *buffer, uint32_t capacity); | ||||
|  | ||||
| /* Get a value from the buffer */ | ||||
| int32_t BufferGet(Buffer * buffer, uint32_t index); | ||||
| int gst_buffer_get(GstBuffer *buffer, uint32_t index); | ||||
|  | ||||
| /* Push a value to the buffer */ | ||||
| void BufferPush(VM * vm, Buffer * buffer, uint8_t c); | ||||
| void gst_buffer_push(Gst *vm, GstBuffer *buffer, uint8_t c); | ||||
|  | ||||
| /* Append a piece of memory to the buffer */ | ||||
| void BufferAppendData(VM * vm, Buffer * buffer, uint8_t * string, uint32_t length); | ||||
| void gst_buffer_append(Gst *vm, GstBuffer *buffer, uint8_t *string, uint32_t length); | ||||
|  | ||||
| /* Convert the buffer to a string */ | ||||
| uint8_t * BufferToString(VM * vm, Buffer * buffer); | ||||
| uint8_t *gst_buffer_to_string(Gst * vm, GstBuffer * buffer); | ||||
|  | ||||
| /* Define a push function for pushing a certain type to the buffer */ | ||||
| #define BufferDefine(name, type) \ | ||||
| static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \ | ||||
| #define BUFFER_DEFINE(name, type) \ | ||||
| static void gst_buffer_push_##name(Gst * vm, GstBuffer * buffer, type x) { \ | ||||
|     union { type t; uint8_t bytes[sizeof(type)]; } u; \ | ||||
|     u.t = x; BufferAppendData(vm, buffer, u.bytes, sizeof(type)); \ | ||||
|     u.t = x; gst_buffer_append(vm, buffer, u.bytes, sizeof(type)); \ | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| @@ -42,51 +42,45 @@ static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \ | ||||
| /****/ | ||||
|  | ||||
| /* Create a new Array */ | ||||
| Array * ArrayNew(VM * vm, uint32_t capacity); | ||||
| GstArray *gst_array(Gst *vm, uint32_t capacity); | ||||
|  | ||||
| /* Get a value of an array with bounds checking. Returns nil if | ||||
|  * outside bounds. */ | ||||
| Value ArrayGet(Array * array, uint32_t index); | ||||
| GstValue gst_array_get(GstArray *array, uint32_t index); | ||||
|  | ||||
| /* Set a value in the array. Does bounds checking but will not grow | ||||
|  * or shrink the array */ | ||||
| int ArraySet(Array * array, uint32_t index, Value x); | ||||
| int gst_array_set(GstArray *array, uint32_t index, GstValue x); | ||||
|  | ||||
| /* Ensure that the internal memory hash enough space for capacity items */ | ||||
| void ArrayEnsure(VM * vm, Array * array, uint32_t capacity); | ||||
| void gst_array_ensure(Gst *vm, GstArray *array, uint32_t capacity); | ||||
|  | ||||
| /* Set a value in an array. Will also append to the array if the index is | ||||
|  * greater than the current max index. */ | ||||
| void ArrayPush(VM * vm, Array * array, Value x); | ||||
| void gst_array_push(Gst *vm, GstArray *array, GstValue x); | ||||
|  | ||||
| /* Pop the last item in the array, or return NIL if empty */ | ||||
| Value ArrayPop(Array * array); | ||||
| GstValue gst_array_pop(GstArray *array); | ||||
|  | ||||
| /* Look at the top most item of an Array */ | ||||
| Value ArrayPeek(Array * array); | ||||
| GstValue ArrayPeek(GstArray *array); | ||||
|  | ||||
| /****/ | ||||
| /* Dictionary functions */ | ||||
| /* Object functions */ | ||||
| /****/ | ||||
|  | ||||
| /* Create a new dictionary */ | ||||
| Dictionary * DictNew(VM * vm, uint32_t capacity); | ||||
| /* Create a new object */ | ||||
| GstObject *gst_object(Gst *vm, uint32_t capacity); | ||||
|  | ||||
| /* Get a value out of the dictionary */ | ||||
| Value DictGet(Dictionary * dict, Value key); | ||||
| GstValue gst_object_get(GstObject *obj, GstValue key); | ||||
|  | ||||
| /* Get a Value from the dictionary, but remove it at the same | ||||
|  * time. */ | ||||
| Value DictRemove(VM * vm, Dictionary * dict, Value key); | ||||
| GstValue gst_object_remove(Gst *vm, GstObject *obj, GstValue key); | ||||
|  | ||||
| /* Put a value into the dictionary. Returns 1 if successful, 0 if out of memory. | ||||
|  * The VM pointer is needed for memory allocation. */ | ||||
| void DictPut(VM * vm, Dictionary * dict, Value key, Value value); | ||||
|  | ||||
| /* Begin iteration through a dictionary */ | ||||
| void DictIterate(Dictionary * dict, DictionaryIterator * iterator); | ||||
|  | ||||
| /* Provides a mechanism for iterating through a table. */ | ||||
| int DictIterateNext(DictionaryIterator * iterator, DictBucket ** bucket); | ||||
| void gst_object_put(Gst *vm, GstObject *obj, GstValue key, GstValue value); | ||||
|  | ||||
| #endif // ds_h_INCLUDED | ||||
|   | ||||
							
								
								
									
										46
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								main.c
									
									
									
									
									
								
							| @@ -7,24 +7,23 @@ | ||||
| #include "value.h" | ||||
| #include "disasm.h" | ||||
|  | ||||
| void StringPut(uint8_t * string) { | ||||
| void string_put(uint8_t * string) { | ||||
|     uint32_t i; | ||||
|     uint32_t len = VStringSize(string); | ||||
|     uint32_t len = gst_string_length(string); | ||||
|     for (i = 0; i < len; ++i) | ||||
|         fputc(string[i], stdout); | ||||
| } | ||||
|  | ||||
| /* Test c function */ | ||||
| Value print(VM * vm) { | ||||
| GstValue print(Gst *vm) { | ||||
|     uint32_t j, count; | ||||
|     Value nil; | ||||
|     count = VMCountArgs(vm); | ||||
|     GstValue nil; | ||||
|     count = gst_count_args(vm); | ||||
|     for (j = 0; j < count; ++j) { | ||||
|         uint8_t * string = ValueToString(vm, VMGetArg(vm, j)); | ||||
|         StringPut(string); | ||||
|         string_put(gst_to_string(vm, gst_arg(vm, j))); | ||||
|         fputc('\n', stdout); | ||||
|     } | ||||
|     nil.type = TYPE_NIL; | ||||
|     nil.type = GST_NIL; | ||||
|     return nil; | ||||
| } | ||||
|  | ||||
| @@ -32,20 +31,20 @@ Value print(VM * vm) { | ||||
| void debugRepl() { | ||||
|     char buffer[1024] = {0}; | ||||
|     const char * reader = buffer; | ||||
|     Value func; | ||||
|     VM vm; | ||||
|     Parser p; | ||||
|     Compiler c; | ||||
|     GstValue func; | ||||
|     Gst vm; | ||||
|     GstParser p; | ||||
|     GstCompiler c; | ||||
|  | ||||
|     VMInit(&vm); | ||||
|     gst_init(&vm); | ||||
|  | ||||
|     for (;;) { | ||||
|  | ||||
|         /* Reset state */ | ||||
|         ParserInit(&p, &vm); | ||||
|         gst_parser(&p, &vm); | ||||
|  | ||||
|         /* Get and parse input until we have a full form */ | ||||
|         while (p.status == PARSER_PENDING) { | ||||
|         while (p.status == GST_PARSER_PENDING) { | ||||
|             /* Get some input if we are done */ | ||||
|             if (*reader == '\0') { | ||||
|                 printf(">> "); | ||||
| @@ -55,7 +54,7 @@ void debugRepl() { | ||||
|                 p.index = 0; | ||||
|                 reader = buffer; | ||||
|             } | ||||
|             reader += ParserParseCString(&p, reader); | ||||
|             reader += gst_parse_cstring(&p, reader); | ||||
|         } | ||||
|  | ||||
|         /* Check for parsing errors */ | ||||
| @@ -74,10 +73,10 @@ void debugRepl() { | ||||
|         } | ||||
|  | ||||
|         /* Try to compile generated AST */ | ||||
|         CompilerInit(&c, &vm); | ||||
|         CompilerAddGlobalCFunc(&c, "print", print); | ||||
|         func.type = TYPE_FUNCTION; | ||||
|         func.data.func = CompilerCompile(&c, p.value); | ||||
|         gst_compiler(&c, &vm); | ||||
|         gst_compiler_add_global_cfunction(&c, "print", print); | ||||
|         func.type = GST_FUNCTION; | ||||
|         func.data.function = gst_compiler_compile(&c, p.value); | ||||
|  | ||||
|         /* Check for compilation errors */ | ||||
|         if (c.error) { | ||||
| @@ -93,15 +92,14 @@ void debugRepl() { | ||||
|         //printf("\n"); | ||||
|  | ||||
|         /* Execute function */ | ||||
|         VMLoad(&vm, func); | ||||
|         if (VMStart(&vm)) { | ||||
|         gst_load(&vm, func); | ||||
|         if (gst_start(&vm)) { | ||||
|             printf("VM error: %s\n", vm.error); | ||||
|             reader = buffer; | ||||
|             buffer[0] = 0; | ||||
|             continue; | ||||
|         } else { | ||||
|             uint8_t * string = ValueToString(&vm, vm.ret); | ||||
|             StringPut(string); | ||||
|             string_put(gst_to_string(&vm, vm.ret)); | ||||
|             printf("\n"); | ||||
|         } | ||||
|     } | ||||
|   | ||||
							
								
								
									
										199
									
								
								parse.c
									
									
									
									
									
								
							
							
						
						
									
										199
									
								
								parse.c
									
									
									
									
									
								
							| @@ -19,15 +19,15 @@ typedef enum ParseType { | ||||
| } ParseType; | ||||
|  | ||||
| /* Contain a parse state that goes on the parse stack */ | ||||
| struct ParseState { | ||||
| struct GstParseState { | ||||
|     ParseType type; | ||||
|     union { | ||||
|         struct { | ||||
| 			uint8_t endDelimiter; | ||||
|             Array * array; | ||||
|             GstArray * array; | ||||
|         } form; | ||||
|         struct { | ||||
|             Buffer * buffer; | ||||
|             GstBuffer * buffer; | ||||
|             enum { | ||||
|                 STRING_STATE_BASE, | ||||
|                 STRING_STATE_ESCAPE, | ||||
| @@ -39,37 +39,37 @@ struct ParseState { | ||||
| }; | ||||
|  | ||||
| /* Handle error in parsing */ | ||||
| #define PError(p, e) ((p)->error = (e), (p)->status = PARSER_ERROR) | ||||
| #define p_error(p, e) ((p)->error = (e), (p)->status = GST_PARSER_ERROR) | ||||
|  | ||||
| /* Get the top ParseState in the parse stack */ | ||||
| static ParseState * ParserPeek(Parser * p) { | ||||
| static GstParseState *parser_peek(GstParser *p) { | ||||
|     if (!p->count) { | ||||
|         PError(p, "Parser stack underflow. (Peek)"); | ||||
|         p_error(p, "Parser stack underflow. (Peek)"); | ||||
|         return NULL; | ||||
|     } | ||||
|     return p->data + p->count - 1; | ||||
| } | ||||
|  | ||||
| /* Remove the top state from the ParseStack */ | ||||
| static ParseState * ParserPop(Parser * p) { | ||||
| static GstParseState *parser_pop(GstParser * p) { | ||||
|     if (!p->count) { | ||||
|         PError(p, "Parser stack underflow. (Pop)"); | ||||
|         p_error(p, "Parser stack underflow. (Pop)"); | ||||
|         return NULL; | ||||
|     } | ||||
|     return p->data + --p->count; | ||||
| } | ||||
|  | ||||
| /* Add a new, empty ParseState to the ParseStack. */ | ||||
| static void ParserPush(Parser *p, ParseType type, uint8_t character) { | ||||
|     ParseState * top; | ||||
| static void parser_push(GstParser *p, ParseType type, uint8_t character) { | ||||
|     GstParseState *top; | ||||
|     if (p->count >= p->cap) { | ||||
|         uint32_t newCap = 2 * p->count; | ||||
|         ParseState * data = VMAlloc(p->vm, newCap); | ||||
|         GstParseState *data = gst_alloc(p->vm, newCap); | ||||
|         p->data = data; | ||||
|         p->cap = newCap; | ||||
|     } | ||||
|     ++p->count; | ||||
|     top = ParserPeek(p); | ||||
|     top = parser_peek(p); | ||||
|     if (!top) return; | ||||
|     top->type = type; | ||||
|     switch (type) { | ||||
| @@ -78,48 +78,48 @@ static void ParserPush(Parser *p, ParseType type, uint8_t character) { | ||||
|         case PTYPE_STRING: | ||||
|             top->buf.string.state = STRING_STATE_BASE; | ||||
|         case PTYPE_TOKEN: | ||||
|             top->buf.string.buffer = BufferNew(p->vm, 10); | ||||
|             top->buf.string.buffer = gst_buffer(p->vm, 10); | ||||
|             break; | ||||
|         case PTYPE_FORM: | ||||
|             top->buf.form.array = ArrayNew(p->vm, 10); | ||||
|             top->buf.form.array = gst_array(p->vm, 10); | ||||
|             if (character == '(') top->buf.form.endDelimiter = ')'; | ||||
|             if (character == '[') { | ||||
|                 top->buf.form.endDelimiter = ']'; | ||||
|                 ArrayPush(p->vm, top->buf.form.array, ValueLoadCString(p->vm, "array")); | ||||
|                 gst_array_push(p->vm, top->buf.form.array, gst_load_cstring(p->vm, "array")); | ||||
|             } | ||||
|             if (character == '{') { | ||||
|                 top->buf.form.endDelimiter = '}'; | ||||
|                 ArrayPush(p->vm, top->buf.form.array, ValueLoadCString(p->vm, "dict")); | ||||
|                 gst_array_push(p->vm, top->buf.form.array, gst_load_cstring(p->vm, "dict")); | ||||
|             } | ||||
|             break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Append a value to the top-most state in the Parser's stack. */ | ||||
| static void ParserTopAppend(Parser * p, Value x) { | ||||
|     ParseState * top = ParserPeek(p); | ||||
| static void parser_append(GstParser *p, GstValue x) { | ||||
|     GstParseState *top = parser_peek(p); | ||||
|     if (!top) return; | ||||
|     switch (top->type) { | ||||
|         case PTYPE_ROOT: | ||||
|             p->value = x; | ||||
|             p->status = PARSER_FULL; | ||||
|             p->status = GST_PARSER_FULL; | ||||
|             break; | ||||
|         case PTYPE_FORM: | ||||
|             ArrayPush(p->vm, top->buf.form.array, x); | ||||
|             gst_array_push(p->vm, top->buf.form.array, x); | ||||
|             break; | ||||
|         default: | ||||
|             PError(p, "Expected container type."); | ||||
|             p_error(p, "Expected container type."); | ||||
|             break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Check if a character is whitespace */ | ||||
| static int isWhitespace(uint8_t c) { | ||||
| static int is_whitespace(uint8_t c) { | ||||
|     return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\0' || c == ','; | ||||
| } | ||||
|  | ||||
| /* Check if a character is a valid symbol character */ | ||||
| static int isSymbolChar(uint8_t c) { | ||||
| static int is_symbol_char(uint8_t c) { | ||||
|     if (c >= 'a' && c <= 'z') return 1; | ||||
|     if (c >= 'A' && c <= 'Z') return 1; | ||||
|     if (c >= '0' && c <= ':') return 1; | ||||
| @@ -148,10 +148,13 @@ static double exp10(int power) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Read a number from a string */ | ||||
| static int ParseReadNumber(const uint8_t * string, const uint8_t * end, double * ret, int forceInt) { | ||||
| /* Read a number from a string. Returns if successfuly | ||||
|  * parsed a number from the enitre input string. | ||||
|  * If returned 1, output is int ret.*/ | ||||
| static int read_number(const uint8_t *string, const uint8_t *end, double *ret, int forceInt) { | ||||
|     int sign = 1, x = 0; | ||||
|     double accum = 0, exp = 1, place = 1; | ||||
|     /* Check the sign */ | ||||
|     if (*string == '-') { | ||||
|         sign = -1; | ||||
|         ++string; | ||||
| @@ -163,8 +166,10 @@ static int ParseReadNumber(const uint8_t * string, const uint8_t * end, double * | ||||
|         if (*string == '.' && !forceInt) { | ||||
|             place = 0.1; | ||||
|         } else if (!forceInt && (*string == 'e' || *string == 'E')) { | ||||
|             /* Read the exponent */ | ||||
|             ++string; | ||||
|             if (!ParseReadNumber(string, end, &exp, 1)) | ||||
|             if (string >= end) return 0; | ||||
|             if (!read_number(string, end, &exp, 1)) | ||||
|                 return 0; | ||||
|             exp = exp10(exp); | ||||
|             break; | ||||
| @@ -187,7 +192,7 @@ static int ParseReadNumber(const uint8_t * string, const uint8_t * end, double * | ||||
| } | ||||
|  | ||||
| /* Checks if a string slice is equal to a string constant */ | ||||
| static int checkStrConst(const char * ref, const uint8_t * start, const uint8_t * end) { | ||||
| static int check_str_const(const char *ref, const uint8_t *start, const uint8_t *end) { | ||||
|     while (*ref && start < end) { | ||||
|         if (*ref != *(char *)start) return 0; | ||||
|         ++ref; | ||||
| @@ -197,72 +202,72 @@ static int checkStrConst(const char * ref, const uint8_t * start, const uint8_t | ||||
| } | ||||
|  | ||||
| /* Build from the token buffer */ | ||||
| static Value ParserBuildTokenBuffer(Parser * p, Buffer * buf) { | ||||
|     Value x; | ||||
|     Number number; | ||||
| static GstValue build_token(GstParser *p, GstBuffer *buf) { | ||||
|     GstValue x; | ||||
|     GstNumber number; | ||||
|     uint8_t * data = buf->data; | ||||
|     uint8_t * back = data + buf->count; | ||||
|     if (ParseReadNumber(data, back, &number, 0)) { | ||||
|         x.type = TYPE_NUMBER; | ||||
|     if (read_number(data, back, &number, 0)) { | ||||
|         x.type = GST_NUMBER; | ||||
|         x.data.number = number; | ||||
|     } else if (checkStrConst("nil", data, back)) { | ||||
|         x.type = TYPE_NIL; | ||||
|     } else if (check_str_const("nil", data, back)) { | ||||
|         x.type = GST_NIL; | ||||
|         x.data.boolean = 0; | ||||
|     } else if (checkStrConst("false", data, back)) { | ||||
|         x.type = TYPE_BOOLEAN; | ||||
|     } else if (check_str_const("false", data, back)) { | ||||
|         x.type = GST_BOOLEAN; | ||||
|         x.data.boolean = 0; | ||||
|     } else if (checkStrConst("true", data, back)) { | ||||
|         x.type = TYPE_BOOLEAN; | ||||
|     } else if (check_str_const("true", data, back)) { | ||||
|         x.type = GST_BOOLEAN; | ||||
|         x.data.boolean = 1; | ||||
|     } else { | ||||
|         if (buf->data[0] >= '0' && buf->data[0] <= '9') { | ||||
|             PError(p, "Symbols cannot start with digits."); | ||||
|             x.type = TYPE_NIL; | ||||
|             p_error(p, "Symbols cannot start with digits."); | ||||
|             x.type = GST_NIL; | ||||
|         } else { | ||||
|             x.type = TYPE_STRING; | ||||
|             x.data.string = BufferToString(p->vm, buf); | ||||
|             x.type = GST_STRING; | ||||
|             x.data.string = gst_buffer_to_string(p->vm, buf); | ||||
|         } | ||||
|     } | ||||
|     return x; | ||||
| } | ||||
|  | ||||
| /* Handle parsing a token */ | ||||
| static int ParserTokenState(Parser * p, uint8_t c) { | ||||
|     ParseState * top = ParserPeek(p); | ||||
|     Buffer * buf = top->buf.string.buffer; | ||||
|     if (isWhitespace(c) || c == ')' || c == ']' || c == '}') { | ||||
|         ParserPop(p); | ||||
|         ParserTopAppend(p, ParserBuildTokenBuffer(p, buf)); | ||||
| static int token_state(GstParser *p, uint8_t c) { | ||||
|     GstParseState *top = parser_peek(p); | ||||
|     GstBuffer *buf = top->buf.string.buffer; | ||||
|     if (is_whitespace(c) || c == ')' || c == ']' || c == '}') { | ||||
|         parser_pop(p); | ||||
|         parser_append(p, build_token(p, buf)); | ||||
|         return !(c == ')' || c == ']' || c == '}'); | ||||
|     } else if (isSymbolChar(c)) { | ||||
|         BufferPush(p->vm, buf, c); | ||||
|     } else if (is_symbol_char(c)) { | ||||
|         gst_buffer_push(p->vm, buf, c); | ||||
|         return 1; | ||||
|     } else { | ||||
|         PError(p, "Expected symbol character."); | ||||
|         p_error(p, "Expected symbol character."); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Handle parsing a string literal */ | ||||
| static int ParserStringState(Parser * p, uint8_t c) { | ||||
|     ParseState * top = ParserPeek(p); | ||||
| static int string_state(GstParser *p, uint8_t c) { | ||||
|     GstParseState *top = parser_peek(p); | ||||
|     switch (top->buf.string.state) { | ||||
|         case STRING_STATE_BASE: | ||||
|             if (c == '\\') { | ||||
|                 top->buf.string.state = STRING_STATE_ESCAPE; | ||||
|             } else if (c == '"') { | ||||
|                 /* Load a quote form to get the string literal */ | ||||
|                 Value x, array; | ||||
|                 x.type = TYPE_STRING; | ||||
|                 x.data.string = BufferToString(p->vm, top->buf.string.buffer); | ||||
|                 array.type = TYPE_ARRAY; | ||||
|                 array.data.array = ArrayNew(p->vm, 2); | ||||
|                 ArrayPush(p->vm, array.data.array, ValueLoadCString(p->vm, "quote")); | ||||
|                 ArrayPush(p->vm, array.data.array, x); | ||||
|                 ParserPop(p); | ||||
|                 ParserTopAppend(p, array); | ||||
|                 GstValue x, array; | ||||
|                 x.type = GST_STRING; | ||||
|                 x.data.string = gst_buffer_to_string(p->vm, top->buf.string.buffer); | ||||
|                 array.type = GST_ARRAY; | ||||
|                 array.data.array = gst_array(p->vm, 2); | ||||
|                 gst_array_push(p->vm, array.data.array, gst_load_cstring(p->vm, "quote")); | ||||
|                 gst_array_push(p->vm, array.data.array, x); | ||||
|                 parser_pop(p); | ||||
|                 parser_append(p, array); | ||||
|             } else { | ||||
|                 BufferPush(p->vm, top->buf.string.buffer, c); | ||||
|                 gst_buffer_push(p->vm, top->buf.string.buffer, c); | ||||
|             } | ||||
|             break; | ||||
|         case STRING_STATE_ESCAPE: | ||||
| @@ -278,10 +283,10 @@ static int ParserStringState(Parser * p, uint8_t c) { | ||||
|                     case '\'': next = '\''; break; | ||||
|                     case 'z': next = '\0'; break; | ||||
|                     default: | ||||
|                               PError(p, "Unknown string escape sequence."); | ||||
|                               p_error(p, "Unknown string escape sequence."); | ||||
|                               return 1; | ||||
|                 } | ||||
|                 BufferPush(p->vm, top->buf.string.buffer, next); | ||||
|                 gst_buffer_push(p->vm, top->buf.string.buffer, next); | ||||
|                 top->buf.string.state = STRING_STATE_BASE; | ||||
|             } | ||||
|             break; | ||||
| @@ -294,60 +299,60 @@ static int ParserStringState(Parser * p, uint8_t c) { | ||||
| } | ||||
|  | ||||
| /* Root state of the parser */ | ||||
| static int ParserRootState(Parser * p, uint8_t c) { | ||||
| static int root_state(GstParser *p, uint8_t c) { | ||||
|     if (c == ']' || c == ')' || c == '}') { | ||||
|         PError(p, UNEXPECTED_CLOSING_DELIM); | ||||
|         p_error(p, UNEXPECTED_CLOSING_DELIM); | ||||
|         return 1; | ||||
|     } | ||||
|     if (c == '(' || c == '[' || c == '{') { | ||||
|         ParserPush(p, PTYPE_FORM, c); | ||||
|         parser_push(p, PTYPE_FORM, c); | ||||
|         return 1; | ||||
|     } | ||||
|     if (c == '"') { | ||||
|         ParserPush(p, PTYPE_STRING, c); | ||||
|         parser_push(p, PTYPE_STRING, c); | ||||
|         return 1; | ||||
|     } | ||||
|     if (isWhitespace(c)) return 1; | ||||
|     if (isSymbolChar(c)) { | ||||
|         ParserPush(p, PTYPE_TOKEN, c); | ||||
|     if (is_whitespace(c)) return 1; | ||||
|     if (is_symbol_char(c)) { | ||||
|         parser_push(p, PTYPE_TOKEN, c); | ||||
|         return 0; | ||||
|     } | ||||
|     PError(p, "Unexpected character."); | ||||
|     p_error(p, "Unexpected character."); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| /* Handle parsing a form */ | ||||
| static int ParserFormState(Parser * p, uint8_t c) { | ||||
|     ParseState * top = ParserPeek(p); | ||||
| static int form_state(GstParser *p, uint8_t c) { | ||||
|     GstParseState *top = parser_peek(p); | ||||
|     if (c == top->buf.form.endDelimiter) { | ||||
|         Array * array = top->buf.form.array; | ||||
|         Value x; | ||||
|         x.type = TYPE_ARRAY; | ||||
|         GstArray *array = top->buf.form.array; | ||||
|         GstValue x; | ||||
|         x.type = GST_ARRAY; | ||||
|         x.data.array = array; | ||||
|     	ParserPop(p); | ||||
|         ParserTopAppend(p, x); | ||||
|     	parser_pop(p); | ||||
|         parser_append(p, x); | ||||
|         return 1; | ||||
|     } | ||||
|     return ParserRootState(p, c); | ||||
|     return root_state(p, c); | ||||
| } | ||||
|  | ||||
| /* Handle a character */ | ||||
| static int ParserDispatchChar(Parser * p, uint8_t c) { | ||||
| static int dispatch_char(GstParser *p, uint8_t c) { | ||||
|     int done = 0; | ||||
|     while (!done && p->status == PARSER_PENDING) { | ||||
|         ParseState * top = ParserPeek(p); | ||||
|     while (!done && p->status == GST_PARSER_PENDING) { | ||||
|         GstParseState *top = parser_peek(p); | ||||
|         switch (top->type) { | ||||
|             case PTYPE_ROOT: | ||||
|                 done = ParserRootState(p, c); | ||||
|                 done = root_state(p, c); | ||||
|                 break; | ||||
|             case PTYPE_TOKEN: | ||||
|                 done = ParserTokenState(p, c); | ||||
|                 done = token_state(p, c); | ||||
|                 break; | ||||
|             case PTYPE_FORM: | ||||
|                 done = ParserFormState(p, c); | ||||
|                 done = form_state(p, c); | ||||
|                 break; | ||||
|             case PTYPE_STRING: | ||||
|                 done = ParserStringState(p, c); | ||||
|                 done = string_state(p, c); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| @@ -360,25 +365,25 @@ static int ParserDispatchChar(Parser * p, uint8_t c) { | ||||
|  * was not read. Returns 1 if any values were read, otherwise returns 0. | ||||
|  * Returns the number of bytes read. | ||||
|  */ | ||||
| int ParserParseCString(Parser * p, const char * string) { | ||||
| int gst_parse_cstring(GstParser *p, const char *string) { | ||||
|     int bytesRead = 0; | ||||
|     p->status = PARSER_PENDING; | ||||
|     while ((p->status == PARSER_PENDING) && (string[bytesRead] != '\0')) { | ||||
|         ParserDispatchChar(p, string[bytesRead++]); | ||||
|     p->status = GST_PARSER_PENDING; | ||||
|     while ((p->status == GST_PARSER_PENDING) && (string[bytesRead] != '\0')) { | ||||
|         dispatch_char(p, string[bytesRead++]); | ||||
|     } | ||||
|     return bytesRead; | ||||
| } | ||||
|  | ||||
| /* Parser initialization (memory allocation) */ | ||||
| void ParserInit(Parser * p, VM * vm) { | ||||
| void gst_parser(GstParser *p, Gst *vm) { | ||||
|     p->vm = vm; | ||||
|     ParseState * data = VMAlloc(vm, sizeof(ParseState) * 10); | ||||
|     GstParseState *data = gst_alloc(vm, sizeof(GstParseState) * 10); | ||||
|     p->data = data; | ||||
|     p->count = 0; | ||||
|     p->cap = 10; | ||||
|     p->index = 0; | ||||
|     p->error = NULL; | ||||
|     p->status = PARSER_PENDING; | ||||
|     p->value.type = TYPE_NIL; | ||||
|     ParserPush(p, PTYPE_ROOT, ' '); | ||||
|     p->status = GST_PARSER_PENDING; | ||||
|     p->value.type = GST_NIL; | ||||
|     parser_push(p, PTYPE_ROOT, ' '); | ||||
| } | ||||
|   | ||||
							
								
								
									
										10
									
								
								parse.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								parse.h
									
									
									
									
									
								
							| @@ -3,12 +3,10 @@ | ||||
|  | ||||
| #include "datatypes.h" | ||||
|  | ||||
| #define PARSE_ERROR -1 | ||||
| #define PARSE_VALUE_READ 1 | ||||
| #define PARSE_VALUE_PENDING 0 | ||||
| /* Initialize a parser */ | ||||
| void gst_parser(GstParser *p, Gst *vm); | ||||
|  | ||||
| void ParserInit(Parser * p, VM * vm); | ||||
|  | ||||
| int ParserParseCString(Parser * p, const char * string); | ||||
| /* Parse a c style string. Returns true if successful */ | ||||
| int gst_parse_cstring(GstParser *p, const char *string); | ||||
|  | ||||
| #endif /* end of include guard: PARSE_H_ONYWMADW */ | ||||
|   | ||||
							
								
								
									
										251
									
								
								value.c
									
									
									
									
									
								
							
							
						
						
									
										251
									
								
								value.c
									
									
									
									
									
								
							| @@ -5,44 +5,44 @@ | ||||
| #include "ds.h" | ||||
| #include "vm.h" | ||||
|  | ||||
| static uint8_t * LoadCString(VM * vm, const char * string, uint32_t len) { | ||||
|     uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t)); | ||||
| static uint8_t * load_cstring(Gst *vm, const char *string, uint32_t len) { | ||||
|     uint8_t *data = gst_alloc(vm, len + 2 * sizeof(uint32_t)); | ||||
|     data += 2 * sizeof(uint32_t); | ||||
|     VStringHash(data) = 0; | ||||
|     VStringSize(data) = len; | ||||
|     gst_string_hash(data) = 0; | ||||
|     gst_string_length(data) = len; | ||||
|     memcpy(data, string, len); | ||||
|     return data; | ||||
| } | ||||
|  | ||||
| Value ValueLoadCString(VM * vm, const char * string) { | ||||
|     Value ret; | ||||
|     ret.type = TYPE_STRING; | ||||
|     ret.data.string = LoadCString(vm, string, strlen(string)); | ||||
| GstValue gst_load_cstring(Gst *vm, const char *string) { | ||||
|     GstValue ret; | ||||
|     ret.type = GST_STRING; | ||||
|     ret.data.string = load_cstring(vm, string, strlen(string)); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static uint8_t * NumberToString(VM * vm, Number x) { | ||||
| static uint8_t * number_to_string(Gst *vm, GstNumber x) { | ||||
|     static const uint32_t SIZE = 20; | ||||
|     uint8_t * data = VMAlloc(vm, SIZE + 2 * sizeof(uint32_t)); | ||||
|     uint8_t *data = gst_alloc(vm, SIZE + 2 * sizeof(uint32_t)); | ||||
|     data += 2 * sizeof(uint32_t); | ||||
|     snprintf((char *) data, SIZE, "%.17g", x); | ||||
|     VStringHash(data) = 0; | ||||
|     VStringSize(data) = strlen((char *) data); | ||||
|     gst_string_hash(data) = 0; | ||||
|     gst_string_length(data) = strlen((char *) data); | ||||
|     return data; | ||||
| } | ||||
|  | ||||
| static const char * HEX_CHARACTERS = "0123456789abcdef"; | ||||
| static const char *HEX_CHARACTERS = "0123456789abcdef"; | ||||
| #define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)]) | ||||
|  | ||||
| /* Returns a string description for a pointer */ | ||||
| static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlelen, void * pointer) { | ||||
| static uint8_t *string_description(Gst *vm, const char *title, uint32_t titlelen, void *pointer) { | ||||
|     uint32_t len = 5 + titlelen + sizeof(void *) * 2; | ||||
|     uint32_t i; | ||||
|     uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t)); | ||||
|     uint8_t * c; | ||||
|     uint8_t *data = gst_alloc(vm, len + 2 * sizeof(uint32_t)); | ||||
|     uint8_t *c; | ||||
|     union { | ||||
|         uint8_t bytes[sizeof(void *)]; | ||||
|         void * p; | ||||
|         void *p; | ||||
|     } buf; | ||||
|     buf.p = pointer; | ||||
|     data += 2 * sizeof(uint32_t); | ||||
| @@ -61,58 +61,57 @@ static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlele | ||||
|         *c++ = HEX(byte & 0xF); | ||||
|     } | ||||
|     *c++ = '>'; | ||||
|     VStringHash(data) = 0; | ||||
|     VStringSize(data) = c - data; | ||||
|     gst_string_hash(data) = 0; | ||||
|     gst_string_length(data) = c - data; | ||||
|     return data; | ||||
| } | ||||
|  | ||||
| /* Returns a string pointer or NULL if could not allocate memory. */ | ||||
| uint8_t * ValueToString(VM * vm, Value x) { | ||||
| uint8_t *gst_to_string(Gst *vm, GstValue x) { | ||||
|     switch (x.type) { | ||||
|         case TYPE_NIL: | ||||
|             return LoadCString(vm, "nil", 3); | ||||
|         case TYPE_BOOLEAN: | ||||
|         case GST_NIL: | ||||
|             return load_cstring(vm, "nil", 3); | ||||
|         case GST_BOOLEAN: | ||||
|             if (x.data.boolean) { | ||||
|                 return LoadCString(vm, "true", 4); | ||||
|                 return load_cstring(vm, "true", 4); | ||||
|             } else { | ||||
|                 return LoadCString(vm, "false", 5); | ||||
|                 return load_cstring(vm, "false", 5); | ||||
|             } | ||||
|         case TYPE_NUMBER: | ||||
|             return NumberToString(vm, x.data.number); | ||||
|         case TYPE_ARRAY: | ||||
|         case GST_NUMBER: | ||||
|             return number_to_string(vm, x.data.number); | ||||
|         case GST_ARRAY: | ||||
|             { | ||||
|                 uint32_t i; | ||||
| 				Buffer * b = BufferNew(vm, 40); | ||||
| 				BufferPush(vm, b, '('); | ||||
| 				GstBuffer * b = gst_buffer(vm, 40); | ||||
| 				gst_buffer_push(vm, b, '('); | ||||
| 				for (i = 0; i < x.data.array->count; ++i) { | ||||
|     				uint8_t * substr = ValueToString(vm, x.data.array->data[i]); | ||||
| 					BufferAppendData(vm, b, substr, VStringSize(substr)); | ||||
|     				uint8_t * substr = gst_to_string(vm, x.data.array->data[i]); | ||||
| 					gst_buffer_append(vm, b, substr, gst_string_length(substr)); | ||||
| 					if (i < x.data.array->count - 1) | ||||
|         				BufferPush(vm, b, ' '); | ||||
|         				gst_buffer_push(vm, b, ' '); | ||||
| 				} | ||||
| 				BufferPush(vm, b, ')'); | ||||
| 				return BufferToString(vm, b); | ||||
| 				gst_buffer_push(vm, b, ')'); | ||||
| 				return gst_buffer_to_string(vm, b); | ||||
|             } | ||||
|             return StringDescription(vm, "array", 5, x.data.pointer); | ||||
|         case TYPE_STRING: | ||||
|         case GST_STRING: | ||||
|             return x.data.string; | ||||
|         case TYPE_BYTEBUFFER: | ||||
|             return StringDescription(vm, "buffer", 6, x.data.pointer); | ||||
|         case TYPE_CFUNCTION: | ||||
|             return StringDescription(vm, "cfunction", 9, x.data.pointer); | ||||
|         case TYPE_FUNCTION: | ||||
|             return StringDescription(vm, "function", 8, x.data.pointer); | ||||
|         case TYPE_DICTIONARY: | ||||
|             return StringDescription(vm, "dictionary", 10, x.data.pointer); | ||||
|         case TYPE_THREAD: | ||||
|             return StringDescription(vm, "thread", 6, x.data.pointer); | ||||
|         case GST_BYTEBUFFER: | ||||
|             return string_description(vm, "buffer", 6, x.data.pointer); | ||||
|         case GST_CFUNCTION: | ||||
|             return string_description(vm, "cfunction", 9, x.data.pointer); | ||||
|         case GST_FUNCTION: | ||||
|             return string_description(vm, "function", 8, x.data.pointer); | ||||
|         case GST_OBJECT: | ||||
|             return string_description(vm, "object", 6, x.data.pointer); | ||||
|         case GST_THREAD: | ||||
|             return string_description(vm, "thread", 6, x.data.pointer); | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| /* Simple hash function */ | ||||
| uint32_t djb2(const uint8_t * str) { | ||||
|     const uint8_t * end = str + VStringSize(str); | ||||
|     const uint8_t * end = str + gst_string_length(str); | ||||
|     uint32_t hash = 5381; | ||||
|     while (str < end) | ||||
|         hash = (hash << 5) + hash + *str++; | ||||
| @@ -120,45 +119,45 @@ uint32_t djb2(const uint8_t * str) { | ||||
| } | ||||
|  | ||||
| /* Check if two values are equal. This is strict equality with no conversion. */ | ||||
| int ValueEqual(Value x, Value y) { | ||||
| int gst_equals(GstValue x, GstValue y) { | ||||
|     int result = 0; | ||||
|     if (x.type != y.type) { | ||||
|         result = 0; | ||||
|     } else { | ||||
|         switch (x.type) { | ||||
|             case TYPE_NIL: | ||||
|             case GST_NIL: | ||||
|                 result = 1; | ||||
|                 break; | ||||
|             case TYPE_BOOLEAN: | ||||
|             case GST_BOOLEAN: | ||||
|                 result = (x.data.boolean == y.data.boolean); | ||||
|                 break; | ||||
|             case TYPE_NUMBER: | ||||
|             case GST_NUMBER: | ||||
|                 result = (x.data.number == y.data.number); | ||||
|                 break; | ||||
|                 /* Assume that when strings are created, equal strings | ||||
|                  * are set to the same string */ | ||||
|             case TYPE_STRING: | ||||
|             case GST_STRING: | ||||
|                 if (x.data.string == y.data.string) { | ||||
|                     result = 1; | ||||
|                     break; | ||||
|                 } | ||||
|                 if (ValueHash(x) != ValueHash(y) || | ||||
|                         VStringSize(x.data.string) != VStringSize(y.data.string)) { | ||||
|                 if (gst_hash(x) != gst_hash(y) || | ||||
|                         gst_string_length(x.data.string) != gst_string_length(y.data.string)) { | ||||
|                     result = 0; | ||||
|                     break; | ||||
|                 } | ||||
|                 if (!strncmp((char *) x.data.string, (char *) y.data.string, VStringSize(x.data.string))) { | ||||
|                 if (!strncmp((char *) x.data.string, (char *) y.data.string, gst_string_length(x.data.string))) { | ||||
|                     result = 1; | ||||
|                     break; | ||||
|                 } | ||||
|                 result = 0; | ||||
|                 break; | ||||
|             case TYPE_ARRAY: | ||||
|             case TYPE_BYTEBUFFER: | ||||
|             case TYPE_CFUNCTION: | ||||
|             case TYPE_DICTIONARY: | ||||
|             case TYPE_FUNCTION: | ||||
|             case TYPE_THREAD: | ||||
|             case GST_ARRAY: | ||||
|             case GST_BYTEBUFFER: | ||||
|             case GST_CFUNCTION: | ||||
|             case GST_OBJECT: | ||||
|             case GST_FUNCTION: | ||||
|             case GST_THREAD: | ||||
|                 /* compare pointers */ | ||||
|                 result = (x.data.array == y.data.array); | ||||
|                 break; | ||||
| @@ -168,39 +167,39 @@ int ValueEqual(Value x, Value y) { | ||||
| } | ||||
|  | ||||
| /* Computes a hash value for a function */ | ||||
| uint32_t ValueHash(Value x) { | ||||
| uint32_t gst_hash(GstValue x) { | ||||
|     uint32_t hash = 0; | ||||
|     switch (x.type) { | ||||
|         case TYPE_NIL: | ||||
|         case GST_NIL: | ||||
|             hash = 0; | ||||
|             break; | ||||
|         case TYPE_BOOLEAN: | ||||
|         case GST_BOOLEAN: | ||||
|             hash = x.data.boolean; | ||||
|             break; | ||||
|         case TYPE_NUMBER: | ||||
|         case GST_NUMBER: | ||||
|             { | ||||
|                 union { | ||||
|                     uint32_t hash; | ||||
|                     Number number; | ||||
|                     GstNumber number; | ||||
|                 } u; | ||||
|                 u.number = x.data.number; | ||||
|                 hash = u.hash; | ||||
|             } | ||||
|             break; | ||||
|             /* String hashes */ | ||||
|         case TYPE_STRING: | ||||
|         case GST_STRING: | ||||
|             /* Assume 0 is not hashed. */ | ||||
|             if (VStringHash(x.data.string)) | ||||
|                 hash = VStringHash(x.data.string); | ||||
|             if (gst_string_hash(x.data.string)) | ||||
|                 hash = gst_string_hash(x.data.string); | ||||
|             else | ||||
|                 hash = VStringHash(x.data.string) = djb2(x.data.string); | ||||
|                 hash = gst_string_hash(x.data.string) = djb2(x.data.string); | ||||
|             break; | ||||
|         case TYPE_ARRAY: | ||||
|         case TYPE_BYTEBUFFER: | ||||
|         case TYPE_CFUNCTION: | ||||
|         case TYPE_DICTIONARY: | ||||
|         case TYPE_FUNCTION: | ||||
|         case TYPE_THREAD: | ||||
|         case GST_ARRAY: | ||||
|         case GST_BYTEBUFFER: | ||||
|         case GST_CFUNCTION: | ||||
|         case GST_OBJECT: | ||||
|         case GST_FUNCTION: | ||||
|         case GST_THREAD: | ||||
|             /* Cast the pointer */ | ||||
|             { | ||||
|                 union { | ||||
| @@ -218,30 +217,30 @@ uint32_t ValueHash(Value x) { | ||||
| /* Compares x to y. If they are equal retuns 0. If x is less, returns -1. | ||||
|  * If y is less, returns 1. All types are comparable | ||||
|  * and should have strict ordering. */ | ||||
| int ValueCompare(Value x, Value y) { | ||||
| int gst_compare(GstValue x, GstValue y) { | ||||
|     if (x.type == y.type) { | ||||
|         switch (x.type) { | ||||
|             case TYPE_NIL: | ||||
|             case GST_NIL: | ||||
|                 return 0; | ||||
|             case TYPE_BOOLEAN: | ||||
|             case GST_BOOLEAN: | ||||
|                 if (x.data.boolean == y.data.boolean) { | ||||
|                     return 0; | ||||
|                 } else { | ||||
|                     return x.data.boolean ? 1 : -1; | ||||
|                 } | ||||
|             case TYPE_NUMBER: | ||||
|             case GST_NUMBER: | ||||
|                 /* TODO: define behavior for NaN and infinties. */ | ||||
|                 if (x.data.number == y.data.number) { | ||||
|                     return 0; | ||||
|                 } else { | ||||
|                     return x.data.number > y.data.number ? 1 : -1; | ||||
|                 } | ||||
|             case TYPE_STRING: | ||||
|             case GST_STRING: | ||||
|                 if (x.data.string == y.data.string) { | ||||
|                     return 0; | ||||
|                 } else { | ||||
|                     uint32_t xlen = VStringSize(x.data.string); | ||||
|                     uint32_t ylen = VStringSize(y.data.string); | ||||
|                     uint32_t xlen = gst_string_length(x.data.string); | ||||
|                     uint32_t ylen = gst_string_length(y.data.string); | ||||
|                     uint32_t len = xlen > ylen ? ylen : xlen; | ||||
|                     uint32_t i; | ||||
|                     for (i = 0; i < len; ++i) { | ||||
| @@ -259,12 +258,12 @@ int ValueCompare(Value x, Value y) { | ||||
|                         return xlen < ylen ? -1 : 1; | ||||
|                     } | ||||
|                 } | ||||
|             case TYPE_ARRAY: | ||||
|             case TYPE_BYTEBUFFER: | ||||
|             case TYPE_CFUNCTION: | ||||
|             case TYPE_FUNCTION: | ||||
|             case TYPE_DICTIONARY: | ||||
|             case TYPE_THREAD: | ||||
|             case GST_ARRAY: | ||||
|             case GST_BYTEBUFFER: | ||||
|             case GST_CFUNCTION: | ||||
|             case GST_FUNCTION: | ||||
|             case GST_OBJECT: | ||||
|             case GST_THREAD: | ||||
|                 if (x.data.string == y.data.string) { | ||||
|                     return 0; | ||||
|                 } else { | ||||
| @@ -280,9 +279,9 @@ int ValueCompare(Value x, Value y) { | ||||
| /* Allow negative indexing to get from end of array like structure */ | ||||
| /* This probably isn't very fast - look at Lua conversion function. | ||||
|  * I would like to keep this standard C for as long as possible, though. */ | ||||
| static int32_t ToIndex(Number raw, int64_t len) { | ||||
| static int32_t to_index(GstNumber raw, int64_t len) { | ||||
| 	int32_t toInt = raw; | ||||
| 	if ((Number) toInt == raw) { | ||||
| 	if ((GstNumber) toInt == raw) { | ||||
| 		/* We were able to convert */ | ||||
| 		if (toInt < 0) {	 | ||||
|     		/* Index from end */ | ||||
| @@ -299,65 +298,65 @@ static int32_t ToIndex(Number raw, int64_t len) { | ||||
| } | ||||
|  | ||||
| /* Convert a number into a byte. */ | ||||
| static uint8_t NumberToByte(Number raw) { | ||||
| static uint8_t to_byte(GstNumber raw) { | ||||
| 	if (raw > 255) return 255; | ||||
| 	if (raw < 0) return 0; | ||||
| 	return (uint8_t) raw; | ||||
| } | ||||
|  | ||||
| /* Get a value out af an associated data structure. Can throw VM error. */ | ||||
| Value ValueGet(VM * vm, Value ds, Value key) { | ||||
| GstValue gst_get(Gst *vm, GstValue ds, GstValue key) { | ||||
|     int32_t index; | ||||
|     Value ret; | ||||
|     GstValue ret; | ||||
| 	switch (ds.type) { | ||||
| 	case TYPE_ARRAY: | ||||
|         VMAssertType(vm, key, TYPE_NUMBER); | ||||
| 		index = ToIndex(key.data.number, ds.data.array->count); | ||||
| 		if (index == -1) VMError(vm, "Invalid array access"); | ||||
| 	case GST_ARRAY: | ||||
|        	gst_assert_type(vm, key, GST_NUMBER); | ||||
| 		index = to_index(key.data.number, ds.data.array->count); | ||||
| 		if (index == -1) gst_error(vm, "Invalid array access"); | ||||
| 		return ds.data.array->data[index]; | ||||
|     case TYPE_BYTEBUFFER: | ||||
|         VMAssertType(vm, key, TYPE_NUMBER); | ||||
|         index = ToIndex(key.data.number, ds.data.buffer->count); | ||||
| 		if (index == -1) VMError(vm, "Invalid buffer access"); | ||||
| 		ret.type = TYPE_NUMBER; | ||||
|     case GST_BYTEBUFFER: | ||||
|         gst_assert_type(vm, key, GST_NUMBER); | ||||
|         index = to_index(key.data.number, ds.data.buffer->count); | ||||
| 		if (index == -1) gst_error(vm, "Invalid buffer access"); | ||||
| 		ret.type = GST_NUMBER; | ||||
| 		ret.data.number = ds.data.buffer->data[index]; | ||||
| 		break; | ||||
|     case TYPE_STRING: | ||||
|         VMAssertType(vm, key, TYPE_NUMBER); | ||||
|         index = ToIndex(key.data.number, VStringSize(ds.data.string)); | ||||
| 		if (index == -1) VMError(vm, "Invalid string access"); | ||||
| 		ret.type = TYPE_NUMBER; | ||||
|     case GST_STRING: | ||||
|         gst_assert_type(vm, key, GST_NUMBER); | ||||
|         index = to_index(key.data.number, gst_string_length(ds.data.string)); | ||||
| 		if (index == -1) gst_error(vm, "Invalid string access"); | ||||
| 		ret.type = GST_NUMBER; | ||||
| 		ret.data.number = ds.data.string[index]; | ||||
| 		break; | ||||
|     case TYPE_DICTIONARY: | ||||
|         return DictGet(ds.data.dict, key); | ||||
|     case GST_OBJECT: | ||||
|         return gst_object_get(ds.data.object, key); | ||||
|     default: | ||||
|         VMError(vm, "Cannot get."); | ||||
|         gst_error(vm, "Cannot get."); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* Set a value in an associative data structure. Can throw VM error. */ | ||||
| void ValueSet(VM * vm, Value ds, Value key, Value value) { | ||||
| void gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) { | ||||
|     int32_t index; | ||||
| 	switch (ds.type) { | ||||
| 	case TYPE_ARRAY: | ||||
|         VMAssertType(vm, key, TYPE_NUMBER); | ||||
| 		index = ToIndex(key.data.number, ds.data.array->count); | ||||
| 		if (index == -1) VMError(vm, "Invalid array access"); | ||||
| 	case GST_ARRAY: | ||||
|        	gst_assert_type(vm, key, GST_NUMBER); | ||||
| 		index = to_index(key.data.number, ds.data.array->count); | ||||
| 		if (index == -1) gst_error(vm, "Invalid array access"); | ||||
| 		ds.data.array->data[index] = value; | ||||
| 		break; | ||||
|     case TYPE_BYTEBUFFER: | ||||
|         VMAssertType(vm, key, TYPE_NUMBER); | ||||
|         VMAssertType(vm, value, TYPE_NUMBER); | ||||
|         index = ToIndex(key.data.number, ds.data.buffer->count); | ||||
| 		if (index == -1) VMError(vm, "Invalid buffer access"); | ||||
| 		ds.data.buffer->data[index] = NumberToByte(value.data.number); | ||||
|     case GST_BYTEBUFFER: | ||||
|         gst_assert_type(vm, key, GST_NUMBER); | ||||
|         gst_assert_type(vm, value, GST_NUMBER); | ||||
|         index = to_index(key.data.number, ds.data.buffer->count); | ||||
| 		if (index == -1) gst_error(vm, "Invalid buffer access"); | ||||
| 		ds.data.buffer->data[index] = to_byte(value.data.number); | ||||
| 		break; | ||||
|     case TYPE_DICTIONARY: | ||||
|         DictPut(vm, ds.data.dict, key, value); | ||||
|     case GST_OBJECT: | ||||
|         gst_object_put(vm, ds.data.object, key, value); | ||||
|         break; | ||||
|     default: | ||||
|         VMError(vm, "Cannot set."); | ||||
|         gst_error(vm, "Cannot set."); | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										23
									
								
								value.h
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								value.h
									
									
									
									
									
								
							| @@ -3,18 +3,27 @@ | ||||
|  | ||||
| #include "datatypes.h" | ||||
|  | ||||
| int ValueCompare(Value x, Value y); | ||||
| /* Compare two gst values. All gst values are comparable and strictly | ||||
|  * ordered by default. Return 0 if equal, -1 if x is less than y, and | ||||
|  * 1 and x is greater than y. */ | ||||
| int gst_compare(GstValue x, GstValue y); | ||||
|  | ||||
| int ValueEqual(Value x, Value y); | ||||
| /* Returns if two values are equal. */ | ||||
| int gst_equals(GstValue x, GstValue y); | ||||
|  | ||||
| Value ValueGet(VM * vm, Value ds, Value key); | ||||
| /* Get a value from an associative gst object. Can throw errors. */ | ||||
| GstValue gst_get(Gst *vm, GstValue ds, GstValue key); | ||||
|  | ||||
| void ValueSet(VM * vm, Value ds, Value key, Value value); | ||||
| /* Set a value in an associative gst object. Can throw errors. */ | ||||
| void gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value); | ||||
|  | ||||
| Value ValueLoadCString(VM * vm, const char * string); | ||||
| /* Load a c style string into a gst value (copies data) */ | ||||
| GstValue gst_load_cstring(Gst *vm, const char *string); | ||||
|  | ||||
| uint8_t * ValueToString(VM * vm, Value x); | ||||
| /* Convert any gst value into a string */ | ||||
| uint8_t *gst_to_string(Gst *vm, GstValue x); | ||||
|  | ||||
| uint32_t ValueHash(Value x); | ||||
| /* Generate a hash value for a gst object */ | ||||
| uint32_t gst_hash(GstValue x); | ||||
|  | ||||
| #endif /* end of include guard: VALUE_H_1RJPQKFM */ | ||||
|   | ||||
							
								
								
									
										36
									
								
								vm.h
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								vm.h
									
									
									
									
									
								
							| @@ -4,54 +4,54 @@ | ||||
| #include "datatypes.h" | ||||
|  | ||||
| /* Exit from the VM normally */ | ||||
| #define VMExit(vm, r) ((vm)->ret = (r), longjmp((vm)->jump, 1)) | ||||
| #define gst_exit(vm, r) ((vm)->ret = (r), longjmp((vm)->jump, 1)) | ||||
|  | ||||
| /* Bail from the VM with an error. */ | ||||
| #define VMError(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 2)) | ||||
| #define gst_error(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 2)) | ||||
|  | ||||
| /* Crash. Not catchable, unlike error. */ | ||||
| #define VMCrash(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 3)) | ||||
| #define gst_crash(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 3)) | ||||
|  | ||||
| /* Error if the condition is false */ | ||||
| #define VMAssert(vm, cond, e) do \ | ||||
|     { if (!(cond)) { VMError((vm), (e)); } } while (0) | ||||
| #define gst_assert(vm, cond, e) do \ | ||||
|     { if (!(cond)) { gst_error((vm), (e)); } } while (0) | ||||
|  | ||||
| /* Type assertion */ | ||||
| #define VMAssertType(vm, f, t) \ | ||||
|     VMAssert((vm), (f).type == (t), "Expected type,") | ||||
| #define gst_assert_type(vm, f, t) \ | ||||
|     gst_assert((vm), (f).type == (t), "Expected a different type.") | ||||
|  | ||||
| /* Initialize the VM */ | ||||
| void VMInit(VM * vm); | ||||
| void gst_init(Gst * vm); | ||||
|  | ||||
| /* Deinitialize the VM */ | ||||
| void VMDeinit(VM * vm); | ||||
| void gst_deinit(Gst * vm); | ||||
|  | ||||
| /* Load a function to be run on the VM */ | ||||
| void VMLoad(VM * vm, Value func); | ||||
| void gst_load(Gst * vm, GstValue func); | ||||
|  | ||||
| /* Start running the VM */ | ||||
| int VMStart(VM * vm); | ||||
| int gst_start(Gst * vm); | ||||
|  | ||||
| /* Run garbage collection */ | ||||
| void VMCollect(VM * vm); | ||||
| void gst_collect(Gst * vm); | ||||
|  | ||||
| /* Collect garbage if enough memory has been allocated since | ||||
|  * the previous collection */ | ||||
| void VMMaybeCollect(VM * vm); | ||||
| void gst_maybe_collect(Gst * vm); | ||||
|  | ||||
| /* Allocate memory */ | ||||
| void * VMAlloc(VM * vm, uint32_t amount); | ||||
| void * gst_alloc(Gst * vm, uint32_t amount); | ||||
|  | ||||
| /* Allocate zeroed memory */ | ||||
| void * VMZalloc(VM * vm, uint32_t amount); | ||||
| void * gst_zalloc(Gst * vm, uint32_t amount); | ||||
|  | ||||
| /* Get an argument from the stack */ | ||||
| Value VMGetArg(VM * vm, uint16_t index); | ||||
| GstValue gst_arg(Gst * vm, uint16_t index); | ||||
|  | ||||
| /* Put a value on the stack */ | ||||
| void VMSetArg(VM * vm, uint16_t index, Value x); | ||||
| void gst_set_arg(Gst * vm, uint16_t index, GstValue x); | ||||
|  | ||||
| /* Get the number of arguments on the stack */ | ||||
| uint16_t VMCountArgs(VM * vm); | ||||
| uint16_t gst_count_args(Gst * vm); | ||||
|  | ||||
| #endif /* end of include guard: VM_H_C4OZU8CQ */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose