mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 07:33:01 +00:00 
			
		
		
		
	Add get and set instructions. GC is still buggy and currently
crashes everything all the time. :(
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| # TIL | # TIL | ||||||
|  |  | ||||||
| CFLAGS=-std=c99 -Wall -Wextra -g | CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -g | ||||||
|  |  | ||||||
| TARGET=interp | TARGET=interp | ||||||
| PREFIX=/usr/local | PREFIX=/usr/local | ||||||
|   | |||||||
							
								
								
									
										81
									
								
								compile.c
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								compile.c
									
									
									
									
									
								
							| @@ -87,11 +87,11 @@ static FormOptions FormOptionsDefault() { | |||||||
| /* Create some helpers that allows us to push more than just raw bytes | /* Create some helpers that allows us to push more than just raw bytes | ||||||
|  * to the byte buffer. This helps us create the byte code for the compiled |  * to the byte buffer. This helps us create the byte code for the compiled | ||||||
|  * functions. */ |  * functions. */ | ||||||
| BufferDefine(UInt32, uint32_t); | BufferDefine(UInt32, uint32_t) | ||||||
| BufferDefine(Int32, int32_t); | BufferDefine(Int32, int32_t) | ||||||
| BufferDefine(Number, Number); | BufferDefine(Number, Number) | ||||||
| BufferDefine(UInt16, uint16_t); | BufferDefine(UInt16, uint16_t) | ||||||
| BufferDefine(Int16, int16_t); | BufferDefine(Int16, int16_t) | ||||||
|  |  | ||||||
| /* If there is an error during compilation, | /* If there is an error during compilation, | ||||||
|  * jump back to start */ |  * jump back to start */ | ||||||
| @@ -553,7 +553,7 @@ static Slot CompileArray(Compiler * c, FormOptions opts, Array * array) { | |||||||
|  * called with n arguments, the number of arguments is written |  * called with n arguments, the number of arguments is written | ||||||
|  * after the op code, followed by those arguments. |  * after the op code, followed by those arguments. | ||||||
|  * |  * | ||||||
|  * This makes a few assumptions about the opertors. One, no side |  * This makes a few assumptions about the operators. One, no side | ||||||
|  * effects. With this assumptions, if the result of the operator |  * effects. With this assumptions, if the result of the operator | ||||||
|  * is unused, it's calculation can be ignored (the evaluation of |  * is unused, it's calculation can be ignored (the evaluation of | ||||||
|  * its argument is still carried out, but their results can |  * its argument is still carried out, but their results can | ||||||
| @@ -576,7 +576,7 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form, | |||||||
|         if (form->count < 2) { |         if (form->count < 2) { | ||||||
|             if (op0 < 0) { |             if (op0 < 0) { | ||||||
|                 if (opn < 0) CError(c, "This operator does not take 0 arguments."); |                 if (opn < 0) CError(c, "This operator does not take 0 arguments."); | ||||||
|                 /* Use multiple form */ |                 /* Use multiple form of op */ | ||||||
|                 BufferPushUInt16(c->vm, buffer, opn); |                 BufferPushUInt16(c->vm, buffer, opn); | ||||||
|                 BufferPushUInt16(c->vm, buffer, ret.index); |                 BufferPushUInt16(c->vm, buffer, ret.index); | ||||||
|                 BufferPushUInt16(c->vm, buffer, 0); |                 BufferPushUInt16(c->vm, buffer, 0); | ||||||
| @@ -587,7 +587,7 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form, | |||||||
|         } else if (form->count == 2) { |         } else if (form->count == 2) { | ||||||
|             if (op1 < 0) { |             if (op1 < 0) { | ||||||
|                 if (opn < 0) CError(c, "This operator does not take 1 argument."); |                 if (opn < 0) CError(c, "This operator does not take 1 argument."); | ||||||
|                 /* Use multiple form */ |                 /* Use multiple form of op */ | ||||||
|                 BufferPushUInt16(c->vm, buffer, opn); |                 BufferPushUInt16(c->vm, buffer, opn); | ||||||
|                 BufferPushUInt16(c->vm, buffer, ret.index); |                 BufferPushUInt16(c->vm, buffer, ret.index); | ||||||
|                 BufferPushUInt16(c->vm, buffer, 1); |                 BufferPushUInt16(c->vm, buffer, 1); | ||||||
| @@ -642,6 +642,39 @@ static Slot CompileGreaterThanOrEqual(Compiler * c, FormOptions opts, Array * fo | |||||||
| static Slot CompileNot(Compiler * c, FormOptions opts, Array * form) { | static Slot CompileNot(Compiler * c, FormOptions opts, Array * form) { | ||||||
|     return CompileOperator(c, opts, form, VM_OP_FLS, VM_OP_NOT, -1, -1, 0); |     return CompileOperator(c, opts, form, VM_OP_FLS, VM_OP_NOT, -1, -1, 0); | ||||||
| } | } | ||||||
|  | static Slot CompileGet(Compiler * c, FormOptions opts, Array * form) { | ||||||
|  | 	return CompileOperator(c, opts, form, -1, -1, VM_OP_GET, -1, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Associative set */ | ||||||
|  | static Slot CompileSet(Compiler * c, FormOptions opts, Array * form) { | ||||||
|  |     Buffer * buffer = c->buffer; | ||||||
|  |     FormOptions subOpts = FormOptionsDefault(); | ||||||
|  |     Slot ds, key, val; | ||||||
|  |     if (form->count != 4) CError(c, "Set expects 4 arguments"); | ||||||
|  |     if (opts.resultUnused) { | ||||||
|  |         ds = CompilerRealizeSlot(c, CompileValue(c, subOpts, form->data[1])); | ||||||
|  |     } else { | ||||||
|  |         subOpts = opts; | ||||||
|  |         subOpts.isTail = 0; | ||||||
|  |         ds = CompilerRealizeSlot(c, CompileValue(c, subOpts, form->data[1])); | ||||||
|  |         subOpts = FormOptionsDefault(); | ||||||
|  |     } | ||||||
|  |     key = CompilerRealizeSlot(c, CompileValue(c, subOpts, form->data[2])); | ||||||
|  |    	val = CompilerRealizeSlot(c, CompileValue(c, subOpts, form->data[3])); | ||||||
|  |     BufferPushUInt16(c->vm, buffer, VM_OP_SET); | ||||||
|  |     BufferPushUInt16(c->vm, buffer, ds.index); | ||||||
|  |     BufferPushUInt16(c->vm, buffer, key.index); | ||||||
|  |     BufferPushUInt16(c->vm, buffer,	val.index); | ||||||
|  |     CompilerDropSlot(c, c->tail, key); | ||||||
|  |     CompilerDropSlot(c, c->tail, val); | ||||||
|  |     if (opts.resultUnused) { | ||||||
|  |         CompilerDropSlot(c, c->tail, ds); | ||||||
|  |         return NilSlot(); | ||||||
|  |     } else { | ||||||
|  | 		return ds; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Compile an assignment operation */ | /* Compile an assignment operation */ | ||||||
| static Slot CompileAssign(Compiler * c, FormOptions opts, Value left, Value right) { | static Slot CompileAssign(Compiler * c, FormOptions opts, Value left, Value right) { | ||||||
| @@ -939,7 +972,7 @@ static Slot CompileQuote(Compiler * c, FormOptions opts, Array * form) { | |||||||
| } | } | ||||||
|  |  | ||||||
| /* Assignment special */ | /* Assignment special */ | ||||||
| static Slot CompileSet(Compiler * c, FormOptions opts, Array * form) { | static Slot CompileVar(Compiler * c, FormOptions opts, Array * form) { | ||||||
|     if (form->count != 3) |     if (form->count != 3) | ||||||
|         CError(c, "Assignment expects 2 arguments"); |         CError(c, "Assignment expects 2 arguments"); | ||||||
|     return CompileAssign(c, opts, form->data[1], form->data[2]); |     return CompileAssign(c, opts, form->data[1], form->data[2]); | ||||||
| @@ -968,7 +1001,6 @@ static SpecialFormHelper GetSpecial(Array * form) { | |||||||
|             case '>': return CompileGreaterThan; |             case '>': return CompileGreaterThan; | ||||||
|             case '<': return CompileLessThan; |             case '<': return CompileLessThan; | ||||||
|             case '=': return CompileEquals; |             case '=': return CompileEquals; | ||||||
|             case '\'': return CompileQuote; |  | ||||||
|             default: |             default: | ||||||
|                        break; |                        break; | ||||||
|         } |         } | ||||||
| @@ -991,6 +1023,14 @@ static SpecialFormHelper GetSpecial(Array * form) { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|  |         case 'g': | ||||||
|  |             { | ||||||
|  | 				if (VStringSize(name) == 3 && | ||||||
|  |     				    name[1] == 'e' && | ||||||
|  |     				    name[2] == 't') { | ||||||
|  | 					return CompileGet; | ||||||
|  | 			    } | ||||||
|  |             } | ||||||
|         case 'd': |         case 'd': | ||||||
|             { |             { | ||||||
|                 if (VStringSize(name) == 2 && |                 if (VStringSize(name) == 2 && | ||||||
| @@ -1053,6 +1093,15 @@ static SpecialFormHelper GetSpecial(Array * form) { | |||||||
|                     return CompileWhile; |                     return CompileWhile; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             break; | ||||||
|  |         case ':': | ||||||
|  |             { | ||||||
|  |                 if (VStringSize(name) == 2 && | ||||||
|  |                         name[1] == '=') { | ||||||
|  |                     return CompileVar; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|         default: |         default: | ||||||
|             break; |             break; | ||||||
|     } |     } | ||||||
| @@ -1152,7 +1201,7 @@ void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f) { | |||||||
|     Value func; |     Value func; | ||||||
|     func.type = TYPE_CFUNCTION; |     func.type = TYPE_CFUNCTION; | ||||||
|     func.data.cfunction = f; |     func.data.cfunction = f; | ||||||
|     return CompilerAddGlobal(c, name, func); |     CompilerAddGlobal(c, name, func); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Compile interface. Returns a function that evaluates the | /* Compile interface. Returns a function that evaluates the | ||||||
| @@ -1175,8 +1224,12 @@ Func * CompilerCompile(Compiler * c, Value form) { | |||||||
|         uint32_t envSize = c->env->count; |         uint32_t envSize = c->env->count; | ||||||
|         FuncEnv * env = VMAlloc(c->vm, sizeof(FuncEnv)); |         FuncEnv * env = VMAlloc(c->vm, sizeof(FuncEnv)); | ||||||
|         Func * func = VMAlloc(c->vm, sizeof(Func)); |         Func * func = VMAlloc(c->vm, sizeof(Func)); | ||||||
|         env->values = VMAlloc(c->vm, sizeof(Value) * envSize); |         if (envSize) { | ||||||
|         memcpy(env->values, c->env->data, envSize * sizeof(Value)); |         	env->values = VMAlloc(c->vm, sizeof(Value) * envSize); | ||||||
|  |         	memcpy(env->values, c->env->data, envSize * sizeof(Value)); | ||||||
|  |         } else { | ||||||
|  | 			env->values = NULL; | ||||||
|  |         } | ||||||
|         env->stackOffset = envSize; |         env->stackOffset = envSize; | ||||||
|         env->thread = NULL; |         env->thread = NULL; | ||||||
|         func->parent = NULL; |         func->parent = NULL; | ||||||
| @@ -1201,7 +1254,7 @@ int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out) { | |||||||
|         VMLoad(vm, macroFn); |         VMLoad(vm, macroFn); | ||||||
|         if (VMStart(vm)) { |         if (VMStart(vm)) { | ||||||
|             /* We encountered an error during parsing */         |             /* We encountered an error during parsing */         | ||||||
|             return 1;; |             return 1; | ||||||
|         } else { |         } else { | ||||||
|             x = vm->ret; |             x = vm->ret; | ||||||
|         } |         } | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								datatypes.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								datatypes.h
									
									
									
									
									
								
							| @@ -43,6 +43,7 @@ typedef struct Parser Parser; | |||||||
| typedef struct ParseState ParseState; | typedef struct ParseState ParseState; | ||||||
| typedef struct Scope Scope; | typedef struct Scope Scope; | ||||||
| typedef struct Compiler Compiler; | typedef struct Compiler Compiler; | ||||||
|  | typedef struct StackFrame StackFrame; | ||||||
|  |  | ||||||
| union ValueData { | union ValueData { | ||||||
|     Boolean boolean; |     Boolean boolean; | ||||||
| @@ -116,6 +117,15 @@ struct DictBucket { | |||||||
|     DictBucket * next; |     DictBucket * next; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct StackFrame { | ||||||
|  |     Value callee; | ||||||
|  |     uint16_t size; | ||||||
|  |     uint16_t prevSize; | ||||||
|  |     uint16_t ret; | ||||||
|  |     FuncEnv * env; | ||||||
|  |     uint16_t * pc; | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct VM { | struct VM { | ||||||
|     /* Garbage collection */ |     /* Garbage collection */ | ||||||
|     void * blocks; |     void * blocks; | ||||||
| @@ -127,7 +137,7 @@ struct VM { | |||||||
|     uint16_t * pc; |     uint16_t * pc; | ||||||
|     Array * thread; |     Array * thread; | ||||||
|     Value * base; |     Value * base; | ||||||
|     Value root; /* Global state - prevents GC cleanup */ |     StackFrame * frame; | ||||||
|     /* Return state */ |     /* Return state */ | ||||||
|     const char * error; |     const char * error; | ||||||
|     jmp_buf jump; |     jmp_buf jump; | ||||||
| @@ -206,7 +216,7 @@ enum OpCode { | |||||||
|     VM_OP_DVM,        /* 0x001f */ |     VM_OP_DVM,        /* 0x001f */ | ||||||
|     VM_OP_RTN,        /* 0x0020 */ |     VM_OP_RTN,        /* 0x0020 */ | ||||||
|     VM_OP_SET,        /* 0x0021 */ |     VM_OP_SET,        /* 0x0021 */ | ||||||
|     VM_OP_GET,        /* 0x0022 */ |     VM_OP_GET         /* 0x0022 */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif /* end of include guard: DATATYPES_H_PJJ035NT */ | #endif | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								disasm.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								disasm.c
									
									
									
									
									
								
							| @@ -67,7 +67,7 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) { | |||||||
| 	uint16_t *current = byteCode; | 	uint16_t *current = byteCode; | ||||||
| 	uint16_t *end = byteCode + len; | 	uint16_t *end = byteCode + len; | ||||||
|  |  | ||||||
| 	fprintf(out, "----- ASM BYTECODE AT %p -----\n", byteCode); | 	fprintf(out, "----- ASM BYTECODE START -----\n"); | ||||||
|  |  | ||||||
| 	while (current < end) { | 	while (current < end) { | ||||||
| 		switch (*current) { | 		switch (*current) { | ||||||
| @@ -196,6 +196,12 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) { | |||||||
|         case VM_OP_RTN: |         case VM_OP_RTN: | ||||||
| 			current += dasmPrintFixedOp(out, current, "returnNil", 0); | 			current += dasmPrintFixedOp(out, current, "returnNil", 0); | ||||||
|             break; |             break; | ||||||
|  |         case VM_OP_GET: | ||||||
|  |             current += dasmPrintFixedOp(out, current, "get", 3); | ||||||
|  |             break; | ||||||
|  |         case VM_OP_SET: | ||||||
|  |             current += dasmPrintFixedOp(out, current, "set", 3); | ||||||
|  |             break; | ||||||
| 		} | 		} | ||||||
| 		fprintf(out, "\n"); | 		fprintf(out, "\n"); | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								ds.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								ds.h
									
									
									
									
									
								
							| @@ -29,7 +29,7 @@ uint8_t * BufferToString(VM * vm, Buffer * buffer); | |||||||
| #define BufferDefine(name, type) \ | #define BufferDefine(name, type) \ | ||||||
| static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \ | static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \ | ||||||
|     union { type t; uint8_t bytes[sizeof(type)]; } u; \ |     union { type t; uint8_t bytes[sizeof(type)]; } u; \ | ||||||
|     u.t = x; return BufferAppendData(vm, buffer, u.bytes, sizeof(type)); \ |     u.t = x; BufferAppendData(vm, buffer, u.bytes, sizeof(type)); \ | ||||||
| } | } | ||||||
|  |  | ||||||
| /****/ | /****/ | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								main.c
									
									
									
									
									
								
							| @@ -37,7 +37,7 @@ void debugRepl() { | |||||||
|   for (;;) { |   for (;;) { | ||||||
|  |  | ||||||
|     /* Run garbage collection */ |     /* Run garbage collection */ | ||||||
|     VMMaybeCollect(&vm); | /*    VMMaybeCollect(&vm);*/ | ||||||
|  |  | ||||||
|     /* Reset state */ |     /* Reset state */ | ||||||
|     ParserInit(&p, &vm); |     ParserInit(&p, &vm); | ||||||
| @@ -85,6 +85,11 @@ void debugRepl() { | |||||||
|       continue; |       continue; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /* Print asm */ | ||||||
|  |     printf("\n"); | ||||||
|  |     dasmFunc(stdout, func.data.func); | ||||||
|  |     printf("\n"); | ||||||
|  |  | ||||||
|     /* Execute function */ |     /* Execute function */ | ||||||
|     VMLoad(&vm, func); |     VMLoad(&vm, func); | ||||||
|     if (VMStart(&vm)) { |     if (VMStart(&vm)) { | ||||||
| @@ -103,4 +108,5 @@ void debugRepl() { | |||||||
| int main() { | int main() { | ||||||
|   printf("Super cool interpreter v0.0\n"); |   printf("Super cool interpreter v0.0\n"); | ||||||
|   debugRepl(); |   debugRepl(); | ||||||
|  |   return 0; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								parse.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								parse.c
									
									
									
									
									
								
							| @@ -130,7 +130,7 @@ static int isWhitespace(uint8_t c) { | |||||||
| static int isSymbolChar(uint8_t c) { | static int isSymbolChar(uint8_t c) { | ||||||
|     if (c >= 'a' && c <= 'z') return 1; |     if (c >= 'a' && c <= 'z') return 1; | ||||||
|     if (c >= 'A' && c <= 'Z') return 1; |     if (c >= 'A' && c <= 'Z') return 1; | ||||||
|     if (c >= '0' && c <= '9') return 1; |     if (c >= '0' && c <= ':') return 1; | ||||||
|     if (c >= '<' && c <= '@') return 1; |     if (c >= '<' && c <= '@') return 1; | ||||||
|     if (c >= '*' && c <= '/') return 1; |     if (c >= '*' && c <= '/') return 1; | ||||||
|     if (c >= '#' && c <= '&') return 1; |     if (c >= '#' && c <= '&') return 1; | ||||||
|   | |||||||
							
								
								
									
										142
									
								
								value.c
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								value.c
									
									
									
									
									
								
							| @@ -148,26 +148,26 @@ uint8_t * ValueToString(VM * vm, Value x) { | |||||||
|         case TYPE_NUMBER: |         case TYPE_NUMBER: | ||||||
|             return NumberToString(vm, x.data.number); |             return NumberToString(vm, x.data.number); | ||||||
|         case TYPE_ARRAY: |         case TYPE_ARRAY: | ||||||
|             return StringDescription(vm, "array", 5, x.data.array); |             return StringDescription(vm, "array", 5, x.data.pointer); | ||||||
|         case TYPE_FORM: |         case TYPE_FORM: | ||||||
|             return StringDescription(vm, "form", 4, x.data.array); |             return StringDescription(vm, "form", 4, x.data.pointer); | ||||||
|         case TYPE_STRING: |         case TYPE_STRING: | ||||||
|         case TYPE_SYMBOL: |         case TYPE_SYMBOL: | ||||||
|             return x.data.string; |             return x.data.string; | ||||||
|         case TYPE_BYTEBUFFER: |         case TYPE_BYTEBUFFER: | ||||||
|             return StringDescription(vm, "buffer", 6, x.data.buffer); |             return StringDescription(vm, "buffer", 6, x.data.pointer); | ||||||
|         case TYPE_CFUNCTION: |         case TYPE_CFUNCTION: | ||||||
|             return StringDescription(vm, "cfunction", 9, x.data.cfunction); |             return StringDescription(vm, "cfunction", 9, x.data.pointer); | ||||||
|         case TYPE_FUNCTION: |         case TYPE_FUNCTION: | ||||||
|             return StringDescription(vm, "function", 8, x.data.func); |             return StringDescription(vm, "function", 8, x.data.pointer); | ||||||
|         case TYPE_DICTIONARY: |         case TYPE_DICTIONARY: | ||||||
|             return StringDescription(vm, "dictionary", 10, x.data.dict); |             return StringDescription(vm, "dictionary", 10, x.data.pointer); | ||||||
|         case TYPE_FUNCDEF: |         case TYPE_FUNCDEF: | ||||||
|             return StringDescription(vm, "funcdef", 7, x.data.funcdef); |             return StringDescription(vm, "funcdef", 7, x.data.pointer); | ||||||
|         case TYPE_FUNCENV: |         case TYPE_FUNCENV: | ||||||
|             return StringDescription(vm, "funcenv", 7, x.data.funcenv); |             return StringDescription(vm, "funcenv", 7, x.data.pointer); | ||||||
|         case TYPE_THREAD: |         case TYPE_THREAD: | ||||||
|             return StringDescription(vm, "thread", 6, x.data.array); |             return StringDescription(vm, "thread", 6, x.data.pointer); | ||||||
|     } |     } | ||||||
|     return NULL; |     return NULL; | ||||||
| } | } | ||||||
| @@ -352,23 +352,115 @@ int ValueCompare(Value x, Value y) { | |||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Get a value out af an associated data structure. Can throw VM error. */ | /* Allow negative indexing to get from end of array like structure */ | ||||||
| Value ValueGet(VM * vm, Value ds, Value key) { | /* This probably isn't very fast - look at Lua conversion function. | ||||||
| 	switch (ds.type) { |  * I would like to keep this standard C for as long as possible, though. */ | ||||||
| 	case TYPE_ARRAY: | static int32_t ToIndex(Number raw, int64_t len) { | ||||||
|     case TYPE_FORM: | 	int32_t toInt = raw; | ||||||
|     case TYPE_BYTEBUFFER: | 	if ((Number) toInt == raw) { | ||||||
|     case TYPE_SYMBOL: | 		/* We were able to convert */ | ||||||
|     case TYPE_STRING: | 		if (toInt < 0) {	 | ||||||
|     case TYPE_DICTIONARY: |     		/* Index from end */ | ||||||
|    	case TYPE_FUNCENV: | 			if (toInt < -len) return -1;	 | ||||||
|     default: | 			return len + toInt; | ||||||
|         VMError(vm, "Cannot get."); | 		} else {	 | ||||||
|         break; |     		/* Normal indexing */ | ||||||
|  |     		if (toInt >= len) return -1; | ||||||
|  |         	return toInt; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  |         return -1; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Set a value in an associative data structure. Can throw VM error. */ | /* Convert a number into a byte. */ | ||||||
| int ValueSet(VM * vm, Value ds, Value key, Value value) { | static uint8_t NumberToByte(Number 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) { | ||||||
|  |     int32_t index; | ||||||
|  |     Value ret; | ||||||
|  | 	switch (ds.type) { | ||||||
|  | 	case TYPE_ARRAY: | ||||||
|  |     case TYPE_FORM: | ||||||
|  |         VMAssertType(vm, key, TYPE_NUMBER); | ||||||
|  | 		index = ToIndex(key.data.number, ds.data.array->count); | ||||||
|  | 		if (index == -1) VMError(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; | ||||||
|  | 		ret.data.number = ds.data.buffer->data[index]; | ||||||
|  | 		break; | ||||||
|  |     case TYPE_SYMBOL: | ||||||
|  |     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; | ||||||
|  | 		ret.data.number = ds.data.string[index]; | ||||||
|  | 		break; | ||||||
|  |     case TYPE_DICTIONARY: | ||||||
|  |         return DictGet(ds.data.dict, key); | ||||||
|  |    	case TYPE_FUNCENV: | ||||||
|  |         VMAssertType(vm, key, TYPE_NUMBER); | ||||||
|  |         if (ds.data.funcenv->thread) { | ||||||
|  |            	Array * thread = ds.data.funcenv->thread; | ||||||
|  | 			index = ToIndex(key.data.number, vm->frame->size); | ||||||
|  |     		if (index == -1) VMError(vm, "Invalid funcenv access"); | ||||||
|  |     		return thread->data[thread->count + index]; | ||||||
|  |         } else { | ||||||
|  |     		index = ToIndex(key.data.number, ds.data.funcenv->stackOffset); | ||||||
|  |     		if (index == -1) VMError(vm, "Invalid funcenv access"); | ||||||
|  |     		return ds.data.funcenv->values[index]; | ||||||
|  |         } | ||||||
|  |     default: | ||||||
|  |         VMError(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) { | ||||||
|  |     int32_t index; | ||||||
|  | 	switch (ds.type) { | ||||||
|  | 	case TYPE_ARRAY: | ||||||
|  |     case TYPE_FORM: | ||||||
|  |         VMAssertType(vm, key, TYPE_NUMBER); | ||||||
|  | 		index = ToIndex(key.data.number, ds.data.array->count); | ||||||
|  | 		if (index == -1) VMError(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); | ||||||
|  | 		break; | ||||||
|  |     case TYPE_DICTIONARY: | ||||||
|  |         DictPut(vm, ds.data.dict, key, value); | ||||||
|  |         break; | ||||||
|  |    	case TYPE_FUNCENV: | ||||||
|  |         VMAssertType(vm, key, TYPE_NUMBER); | ||||||
|  |         if (ds.data.funcenv->thread) { | ||||||
|  |            	Array * thread = ds.data.funcenv->thread; | ||||||
|  | 			index = ToIndex(key.data.number, vm->frame->size); | ||||||
|  |     		if (index == -1) VMError(vm, "Invalid funcenv access"); | ||||||
|  |     		thread->data[thread->count + index] = value; | ||||||
|  |         } else { | ||||||
|  |     		index = ToIndex(key.data.number, ds.data.funcenv->stackOffset); | ||||||
|  |     		if (index == -1) VMError(vm, "Invalid funcenv access"); | ||||||
|  |     		ds.data.funcenv->values[index] = value; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         VMError(vm, "Cannot set."); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								value.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								value.h
									
									
									
									
									
								
							| @@ -11,7 +11,7 @@ int ValueEqual(Value x, Value y); | |||||||
|  |  | ||||||
| Value ValueGet(VM * vm, Value ds, Value key); | Value ValueGet(VM * vm, Value ds, Value key); | ||||||
|  |  | ||||||
| int ValueSet(VM * vm, Value ds, Value key, Value value); | void ValueSet(VM * vm, Value ds, Value key, Value value); | ||||||
|  |  | ||||||
| Value ValueLoadCString(VM * vm, const char * string); | Value ValueLoadCString(VM * vm, const char * string); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										184
									
								
								vm.c
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								vm.c
									
									
									
									
									
								
							| @@ -11,17 +11,6 @@ static const char EXPECTED_FUNCTION[] = "Expected function"; | |||||||
| static const char VMS_EXPECTED_NUMBER_ROP[] = "Expected right operand to be number"; | static const char VMS_EXPECTED_NUMBER_ROP[] = "Expected right operand to be number"; | ||||||
| static const char VMS_EXPECTED_NUMBER_LOP[] = "Expected left operand to be number"; | static const char VMS_EXPECTED_NUMBER_LOP[] = "Expected left operand to be number"; | ||||||
|  |  | ||||||
| /* The stack frame data */ |  | ||||||
| typedef struct StackFrame StackFrame; |  | ||||||
| struct StackFrame { |  | ||||||
|     Value callee; |  | ||||||
|     uint16_t size; |  | ||||||
|     uint16_t prevSize; |  | ||||||
|     uint16_t ret; |  | ||||||
|     FuncEnv * env; |  | ||||||
|     uint16_t * pc; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* The size of a StackFrame in units of Values. */ | /* The size of a StackFrame in units of Values. */ | ||||||
| #define FRAME_SIZE ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value)) | #define FRAME_SIZE ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value)) | ||||||
|  |  | ||||||
| @@ -37,7 +26,7 @@ static StackFrame * ThreadFrame(Array * thread) { | |||||||
| typedef struct GCMemoryHeader GCMemoryHeader; | typedef struct GCMemoryHeader GCMemoryHeader; | ||||||
| struct GCMemoryHeader { | struct GCMemoryHeader { | ||||||
|     GCMemoryHeader * next; |     GCMemoryHeader * next; | ||||||
|     uint32_t color; |     uint32_t color : 1; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* Forward declaration */ | /* Forward declaration */ | ||||||
| @@ -52,17 +41,43 @@ static void VMMarkFuncEnv(VM * vm, FuncEnv * env) { | |||||||
|             temp.type = TYPE_THREAD; |             temp.type = TYPE_THREAD; | ||||||
|             temp.data.array = env->thread; |             temp.data.array = env->thread; | ||||||
|             VMMark(vm, &temp); |             VMMark(vm, &temp); | ||||||
|         } else { |         } else if (env->values) { | ||||||
|             uint32_t count = env->stackOffset; |             uint32_t count = env->stackOffset; | ||||||
|             uint32_t i; |             uint32_t i; | ||||||
|             GCHeader(env->values)->color = vm->black; |             GCHeader(env->values)->color = vm->black; | ||||||
|             for (i = 0; i < count; ++i) { |             for (i = 0; i < count; ++i) | ||||||
|                 VMMark(vm, env->values + i); |                 VMMark(vm, env->values + i); | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* GC helper to mark a FuncDef */ | ||||||
|  | static void VMMarkFuncDef(VM * vm, FuncDef * def) { | ||||||
|  |     if (GCHeader(def)->color != vm->black) { | ||||||
|  |         GCHeader(def)->color = vm->black; | ||||||
|  |         GCHeader(def->byteCode)->color = vm->black; | ||||||
|  |         uint32_t count, i; | ||||||
|  |         if (def->literals) { | ||||||
|  |             count = def->literalsLen; | ||||||
|  |             GCHeader(def->literals)->color = vm->black; | ||||||
|  |             for (i = 0; i < count; ++i) | ||||||
|  |                 VMMark(vm, def->literals + i); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Helper to mark a stack frame. Returns the next frame. */ | ||||||
|  | static StackFrame * VMMarkStackFrame(VM * vm, StackFrame * frame) { | ||||||
|  |     uint32_t i; | ||||||
|  |     Value * stack = (Value *)frame + FRAME_SIZE; | ||||||
|  |     VMMark(vm, &frame->callee); | ||||||
|  |     if (frame->env) | ||||||
|  |         VMMarkFuncEnv(vm, frame->env); | ||||||
|  |     for (i = 0; i < frame->size; ++i) | ||||||
|  |         VMMark(vm, stack + i); | ||||||
|  |     return (StackFrame *)(stack + frame->size); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Mark allocated memory associated with a value. This is | /* Mark allocated memory associated with a value. This is | ||||||
|  * the main function for doing garbage collection. */ |  * the main function for doing garbage collection. */ | ||||||
| static void VMMark(VM * vm, Value * x) { | static void VMMark(VM * vm, Value * x) { | ||||||
| @@ -97,22 +112,13 @@ static void VMMark(VM * vm, Value * x) { | |||||||
|  |  | ||||||
|         case TYPE_THREAD: |         case TYPE_THREAD: | ||||||
|             if (GCHeader(x->data.array)->color != vm->black) { |             if (GCHeader(x->data.array)->color != vm->black) { | ||||||
|                 uint32_t i; |  | ||||||
|                 Array * thread = x->data.array; |                 Array * thread = x->data.array; | ||||||
|                 StackFrame * frame = (StackFrame *)thread->data; |                 StackFrame * frame = (StackFrame *)thread->data; | ||||||
|                 StackFrame * end = (StackFrame *)(thread->data + thread->count - FRAME_SIZE); |                 StackFrame * end = ThreadFrame(thread); | ||||||
|                 GCHeader(thread)->color = vm->black; |                 GCHeader(thread)->color = vm->black; | ||||||
|                 GCHeader(thread->data)->color = vm->black; |                 GCHeader(thread->data)->color = vm->black; | ||||||
|                 while (frame <= end) { |                 while (frame <= end) | ||||||
|                     Value * stack = (Value *)frame + FRAME_SIZE; |                     frame = VMMarkStackFrame(vm, frame); | ||||||
|                     VMMark(vm, &frame->callee); |  | ||||||
|                     if (frame->env) |  | ||||||
|                         VMMarkFuncEnv(vm, frame->env); |  | ||||||
|                     for (i = 0; i < frame->size; ++i) { |  | ||||||
|                         VMMark(vm, stack + i); |  | ||||||
|                     } |  | ||||||
|                     frame = (StackFrame *)(stack + frame->size); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
| @@ -121,16 +127,12 @@ static void VMMark(VM * vm, Value * x) { | |||||||
|                 Func * f = x->data.func; |                 Func * f = x->data.func; | ||||||
|                 GCHeader(f)->color = vm->black; |                 GCHeader(f)->color = vm->black; | ||||||
|                 VMMarkFuncEnv(vm, f->env); |                 VMMarkFuncEnv(vm, f->env); | ||||||
|                 { |                 VMMarkFuncDef(vm, f->def); | ||||||
|  |                 if (f->parent) { | ||||||
|                     Value temp; |                     Value temp; | ||||||
|                     temp.type = TYPE_FUNCDEF; |                     temp.type = TYPE_FUNCTION; | ||||||
|                     temp.data.funcdef = x->data.funcdef; |                     temp.data.func = f->parent; | ||||||
|                     VMMark(vm, &temp); |                     VMMark(vm, &temp); | ||||||
|                     if (f->parent) { |  | ||||||
|                         temp.type = TYPE_FUNCTION; |  | ||||||
|                         temp.data.func = f->parent; |  | ||||||
|                         VMMark(vm, &temp); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
| @@ -151,16 +153,7 @@ static void VMMark(VM * vm, Value * x) { | |||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case TYPE_FUNCDEF: |         case TYPE_FUNCDEF: | ||||||
|             if (GCHeader(x->data.funcdef)->color != vm->black) { | 			VMMarkFuncDef(vm, x->data.funcdef); | ||||||
|                 GCHeader(x->data.funcdef->byteCode)->color = vm->black; |  | ||||||
|                 uint32_t count, i; |  | ||||||
|                 count = x->data.funcdef->literalsLen; |  | ||||||
|                 if (x->data.funcdef->literals) { |  | ||||||
|                     GCHeader(x->data.funcdef->literals)->color = vm->black; |  | ||||||
|                     for (i = 0; i < count; ++i) |  | ||||||
|                         VMMark(vm, x->data.funcdef->literals + i); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case TYPE_FUNCENV: |         case TYPE_FUNCENV: | ||||||
| @@ -223,14 +216,11 @@ void * VMZalloc(VM * vm, uint32_t size) { | |||||||
| void VMCollect(VM * vm) { | void VMCollect(VM * vm) { | ||||||
|     if (vm->lock > 0) return; |     if (vm->lock > 0) return; | ||||||
|     /* Thread can be null */ |     /* Thread can be null */ | ||||||
|     if (vm->thread) { |     Value thread; | ||||||
|         Value thread; |     thread.type = TYPE_THREAD; | ||||||
|         thread.type = TYPE_THREAD; |     thread.data.array = vm->thread; | ||||||
|         thread.data.array = vm->thread; |     VMMark(vm, &thread); | ||||||
|         VMMark(vm, &thread); |  | ||||||
|     } |  | ||||||
|     VMMark(vm, &vm->ret); |     VMMark(vm, &vm->ret); | ||||||
|     VMMark(vm, &vm->root); |  | ||||||
|     VMSweep(vm); |     VMSweep(vm); | ||||||
|     vm->nextCollection = 0; |     vm->nextCollection = 0; | ||||||
| } | } | ||||||
| @@ -259,22 +249,23 @@ static void VMThreadPush(VM * vm, Array * thread, Value callee, uint32_t size) { | |||||||
|      * the garabage collector */ |      * the garabage collector */ | ||||||
|     for (i = nextCount; i < nextCount + size; ++i) |     for (i = nextCount; i < nextCount + size; ++i) | ||||||
|         thread->data[i].type = TYPE_NIL; |         thread->data[i].type = TYPE_NIL; | ||||||
|     frame = ThreadFrame(thread); |     vm->base = thread->data + thread->count; | ||||||
|  |     vm->frame = frame = (StackFrame *)(vm->base - FRAME_SIZE); | ||||||
|     /* Set up the new stack frame */ |     /* Set up the new stack frame */ | ||||||
|     frame->prevSize = oldSize; |     frame->prevSize = oldSize; | ||||||
|     frame->size = size; |     frame->size = size; | ||||||
|     frame->env = NULL; |     frame->env = NULL; | ||||||
|     frame->callee = callee; |     frame->callee = callee; | ||||||
|     vm->base = thread->data + thread->count; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Copy the current function stack to the current closure | /* Copy the current function stack to the current closure | ||||||
|    environment */ |    environment */ | ||||||
| static void VMThreadSplitStack(VM * vm, Array * thread) { | static void VMThreadSplitStack(VM * vm) { | ||||||
|     StackFrame * frame = ThreadFrame(thread); |     StackFrame * frame = vm->frame; | ||||||
|     FuncEnv * env = frame->env; |     FuncEnv * env = frame->env; | ||||||
|     /* Check for closures */ |     /* Check for closures */ | ||||||
|     if (env) { |     if (env) { | ||||||
|  |         Array * thread = vm->thread; | ||||||
|         uint32_t size = frame->size; |         uint32_t size = frame->size; | ||||||
|         env->thread = NULL; |         env->thread = NULL; | ||||||
|         env->stackOffset = size; |         env->stackOffset = size; | ||||||
| @@ -284,16 +275,18 @@ static void VMThreadSplitStack(VM * vm, Array * thread) { | |||||||
| } | } | ||||||
|  |  | ||||||
| /* Pop the top-most stack frame from stack */ | /* Pop the top-most stack frame from stack */ | ||||||
| static void VMThreadPop(VM * vm, Array * thread) { | static void VMThreadPop(VM * vm) { | ||||||
|     StackFrame * frame = ThreadFrame(thread); |     Array * thread = vm->thread; | ||||||
|  |     StackFrame * frame = vm->frame; | ||||||
|     uint32_t delta = FRAME_SIZE + frame->prevSize; |     uint32_t delta = FRAME_SIZE + frame->prevSize; | ||||||
|     if (thread->count) { |     if (thread->count) { | ||||||
|         VMThreadSplitStack(vm, thread); |         VMThreadSplitStack(vm); | ||||||
|     } else { |     } else { | ||||||
|         VMError(vm, "Nothing to pop from stack."); |         VMError(vm, "Nothing to pop from stack."); | ||||||
|     } |     } | ||||||
|     thread->count -= delta; |     thread->count -= delta; | ||||||
|     vm->base -= delta; |     vm->base -= delta; | ||||||
|  |     vm->frame = (StackFrame *)(vm->base - FRAME_SIZE); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Get an upvalue */ | /* Get an upvalue */ | ||||||
| @@ -329,28 +322,24 @@ static int truthy(Value v) { | |||||||
|  |  | ||||||
| /* Return from the vm */ | /* Return from the vm */ | ||||||
| static void VMReturn(VM * vm, Value ret) { | static void VMReturn(VM * vm, Value ret) { | ||||||
|     Array * thread = vm->thread; |     VMThreadPop(vm); | ||||||
|     StackFrame * frame = ThreadFrame(thread); |     if (vm->thread->count == 0) { | ||||||
|     VMThreadPop(vm, thread); |  | ||||||
|     if (thread->count == 0) { |  | ||||||
|         VMExit(vm, ret); |         VMExit(vm, ret); | ||||||
|     } |     } | ||||||
|     frame = ThreadFrame(thread); |     vm->pc = vm->frame->pc; | ||||||
|     vm->pc = frame->pc; |     vm->base[vm->frame->ret] = ret; | ||||||
|     vm->base[frame->ret] = ret; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Implementation of the opcode for function calls */ | /* Implementation of the opcode for function calls */ | ||||||
| static void VMCallOp(VM * vm) { | static void VMCallOp(VM * vm) { | ||||||
|     Array * thread = vm->thread; |     Array * thread = vm->thread; | ||||||
|     StackFrame * frame = ThreadFrame(thread); |  | ||||||
|     Value callee = vm->base[vm->pc[1]]; |     Value callee = vm->base[vm->pc[1]]; | ||||||
|     uint32_t arity = vm->pc[3]; |     uint32_t arity = vm->pc[3]; | ||||||
|     uint32_t oldCount = thread->count; |     uint32_t oldCount = thread->count; | ||||||
|     uint32_t i; |     uint32_t i; | ||||||
|     Value * oldBase; |     Value * oldBase; | ||||||
|     frame->pc = vm->pc + 4 + arity; |     vm->frame->pc = vm->pc + 4 + arity; | ||||||
|     frame->ret = vm->pc[2]; |     vm->frame->ret = vm->pc[2]; | ||||||
|     if (callee.type == TYPE_FUNCTION) { |     if (callee.type == TYPE_FUNCTION) { | ||||||
|         Func * fn = callee.data.func; |         Func * fn = callee.data.func; | ||||||
|         VMThreadPush(vm, thread, callee, fn->def->locals); |         VMThreadPush(vm, thread, callee, fn->def->locals); | ||||||
| @@ -375,19 +364,17 @@ static void VMCallOp(VM * vm) { | |||||||
|             vm->base[i].type = TYPE_NIL; |             vm->base[i].type = TYPE_NIL; | ||||||
|         vm->pc = f->def->byteCode; |         vm->pc = f->def->byteCode; | ||||||
|     } |     } | ||||||
|     VMMaybeCollect(vm); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Implementation of the opcode for tail calls */ | /* Implementation of the opcode for tail calls */ | ||||||
| static void VMTailCallOp(VM * vm) { | static void VMTailCallOp(VM * vm) { | ||||||
|     Array * thread = vm->thread; |     Array * thread = vm->thread; | ||||||
|     StackFrame * frame = ThreadFrame(thread); |  | ||||||
|     Value callee = vm->base[vm->pc[1]]; |     Value callee = vm->base[vm->pc[1]]; | ||||||
|     uint32_t arity = vm->pc[2]; |     uint32_t arity = vm->pc[2]; | ||||||
|     uint16_t newFrameSize, currentFrameSize; |     uint16_t newFrameSize, currentFrameSize; | ||||||
|     uint32_t i; |     uint32_t i; | ||||||
|     /* Check for closures */ |     /* Check for closures */ | ||||||
|     VMThreadSplitStack(vm, thread); |     VMThreadSplitStack(vm); | ||||||
|     if (callee.type == TYPE_CFUNCTION) { |     if (callee.type == TYPE_CFUNCTION) { | ||||||
|         newFrameSize = arity; |         newFrameSize = arity; | ||||||
|     } else if (callee.type == TYPE_FUNCTION) { |     } else if (callee.type == TYPE_FUNCTION) { | ||||||
| @@ -397,9 +384,8 @@ static void VMTailCallOp(VM * vm) { | |||||||
|         VMError(vm, EXPECTED_FUNCTION); |         VMError(vm, EXPECTED_FUNCTION); | ||||||
|     } |     } | ||||||
|     /* Ensure stack has enough space for copies of arguments */ |     /* Ensure stack has enough space for copies of arguments */ | ||||||
|     currentFrameSize = frame->size; |     currentFrameSize = vm->frame->size; | ||||||
|     ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity); |     ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity); | ||||||
|     frame = ThreadFrame(thread); |  | ||||||
|     vm->base = thread->data + thread->count; |     vm->base = thread->data + thread->count; | ||||||
|     /* Copy the arguments into the extra space */ |     /* Copy the arguments into the extra space */ | ||||||
|     for (i = 0; i < arity; ++i) { |     for (i = 0; i < arity; ++i) { | ||||||
| @@ -412,9 +398,9 @@ static void VMTailCallOp(VM * vm) { | |||||||
|         vm->base[i].type = TYPE_NIL; |         vm->base[i].type = TYPE_NIL; | ||||||
|     } |     } | ||||||
|     /* Update the stack frame */ |     /* Update the stack frame */ | ||||||
|     frame->size = newFrameSize; |     vm->frame->size = newFrameSize; | ||||||
|     frame->callee = callee; |     vm->frame->callee = callee; | ||||||
|     frame->env = NULL; |     vm->frame->env = NULL; | ||||||
|     if (callee.type == TYPE_CFUNCTION) { |     if (callee.type == TYPE_CFUNCTION) { | ||||||
|         ++vm->lock; |         ++vm->lock; | ||||||
|         VMReturn(vm, callee.data.cfunction(vm)); |         VMReturn(vm, callee.data.cfunction(vm)); | ||||||
| @@ -423,27 +409,25 @@ static void VMTailCallOp(VM * vm) { | |||||||
|         Func * f = callee.data.func; |         Func * f = callee.data.func; | ||||||
|         vm->pc = f->def->byteCode; |         vm->pc = f->def->byteCode; | ||||||
|     } |     } | ||||||
|     VMMaybeCollect(vm); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Instantiate a closure */ | /* Instantiate a closure */ | ||||||
| static Value VMMakeClosure(VM * vm, uint16_t literal) { | static Value VMMakeClosure(VM * vm, uint16_t literal) { | ||||||
|     Array * thread = vm->thread; |     Array * thread = vm->thread; | ||||||
|     StackFrame * frame = ThreadFrame(thread); |     if (vm->frame->callee.type != TYPE_FUNCTION) { | ||||||
|     if (frame->callee.type != TYPE_FUNCTION) { |  | ||||||
|         VMError(vm, EXPECTED_FUNCTION); |         VMError(vm, EXPECTED_FUNCTION); | ||||||
|     } else { |     } else { | ||||||
|         Value constant, ret; |         Value constant, ret; | ||||||
|         Func * fn, * current; |         Func * fn, * current; | ||||||
|         FuncEnv * env = frame->env; |         FuncEnv * env = vm->frame->env; | ||||||
|         if (!env) { |         if (!env) { | ||||||
|             env = VMAlloc(vm, sizeof(FuncEnv)); |             env = VMAlloc(vm, sizeof(FuncEnv)); | ||||||
|             env->thread = thread; |             env->thread = thread; | ||||||
|             env->stackOffset = thread->count; |             env->stackOffset = thread->count; | ||||||
|             env->values = NULL; |             env->values = NULL; | ||||||
|             frame->env = env; |             vm->frame->env = env; | ||||||
|         } |         } | ||||||
|         current = frame->callee.data.func; |         current = vm->frame->callee.data.func; | ||||||
|         constant = LoadConstant(vm, current, literal); |         constant = LoadConstant(vm, current, literal); | ||||||
|         if (constant.type != TYPE_FUNCDEF) { |         if (constant.type != TYPE_FUNCDEF) { | ||||||
|             VMError(vm, EXPECTED_FUNCTION); |             VMError(vm, EXPECTED_FUNCTION); | ||||||
| @@ -500,10 +484,10 @@ int VMStart(VM * vm) { | |||||||
|                 DO_BINARY_MATH(-) |                 DO_BINARY_MATH(-) | ||||||
|  |  | ||||||
|             case VM_OP_MUL: /* Multiplication */ |             case VM_OP_MUL: /* Multiplication */ | ||||||
|                     DO_BINARY_MATH(*) |                 DO_BINARY_MATH(*) | ||||||
|  |  | ||||||
|             case VM_OP_DIV: /* Division */ |             case VM_OP_DIV: /* Division */ | ||||||
|                         DO_BINARY_MATH(/) |                 DO_BINARY_MATH(/) | ||||||
|  |  | ||||||
|             #undef DO_BINARY_MATH |             #undef DO_BINARY_MATH | ||||||
|  |  | ||||||
| @@ -556,7 +540,7 @@ int VMStart(VM * vm) { | |||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|             case VM_OP_UPV: /* Load Up Value */ |             case VM_OP_UPV: /* Load Up Value */ | ||||||
|                 temp = ThreadFrame(vm->thread)->callee; |                 temp = vm->frame->callee; | ||||||
|                 VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); |                 VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); | ||||||
|                 vm->base[vm->pc[1]] = *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]); |                 vm->base[vm->pc[1]] = *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]); | ||||||
|                 vm->pc += 4; |                 vm->pc += 4; | ||||||
| @@ -583,14 +567,14 @@ int VMStart(VM * vm) { | |||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|             case VM_OP_SUV: /* Set Up Value */ |             case VM_OP_SUV: /* Set Up Value */ | ||||||
|                 temp = ThreadFrame(vm->thread)->callee; |                 temp = vm->frame->callee; | ||||||
|                 VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); |                 VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); | ||||||
|                 *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]) = vm->base[vm->pc[1]]; |                 *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]) = vm->base[vm->pc[1]]; | ||||||
|                 vm->pc += 4; |                 vm->pc += 4; | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|             case VM_OP_CST: /* Load constant value */ |             case VM_OP_CST: /* Load constant value */ | ||||||
|                 temp = ThreadFrame(vm->thread)->callee; |                 temp = vm->frame->callee; | ||||||
|                 VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); |                 VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); | ||||||
|                 vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]); |                 vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]); | ||||||
|                 vm->pc += 3; |                 vm->pc += 3; | ||||||
| @@ -653,7 +637,6 @@ int VMStart(VM * vm) { | |||||||
|                     temp.data.array = array; |                     temp.data.array = array; | ||||||
|                     vm->base[vm->pc[1]] = temp; |                     vm->base[vm->pc[1]] = temp; | ||||||
|                     vm->pc += 3 + arrayLen; |                     vm->pc += 3 + arrayLen; | ||||||
|                     VMMaybeCollect(vm); |  | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
| @@ -661,7 +644,7 @@ int VMStart(VM * vm) { | |||||||
|                 { |                 { | ||||||
|                     uint32_t i = 3; |                     uint32_t i = 3; | ||||||
|                     uint32_t kvs = vm->pc[2]; |                     uint32_t kvs = vm->pc[2]; | ||||||
|                     Dictionary * dict = DictNew(vm, kvs); |                     Dictionary * dict = DictNew(vm, kvs + 2); | ||||||
|                     kvs = kvs + 3; |                     kvs = kvs + 3; | ||||||
|                     while (i < kvs) { |                     while (i < kvs) { | ||||||
|                         v1 = vm->base[vm->pc[i++]]; |                         v1 = vm->base[vm->pc[i++]]; | ||||||
| @@ -672,7 +655,6 @@ int VMStart(VM * vm) { | |||||||
|                     temp.data.dict = dict; |                     temp.data.dict = dict; | ||||||
|                     vm->base[vm->pc[1]] = temp; |                     vm->base[vm->pc[1]] = temp; | ||||||
|                     vm->pc += kvs; |                     vm->pc += kvs; | ||||||
|                     VMMaybeCollect(vm); |  | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
| @@ -718,40 +700,48 @@ int VMStart(VM * vm) { | |||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|             case VM_OP_GET: |             case VM_OP_GET: | ||||||
|  | 				temp = ValueGet(vm, vm->base[vm->pc[2]], vm->base[vm->pc[3]]); | ||||||
|  | 				vm->base[vm->pc[1]] = temp; | ||||||
|  | 				vm->pc += 4; | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             case VM_OP_SET: | ||||||
|  | 				ValueSet(vm, vm->base[vm->pc[1]], vm->base[vm->pc[2]], vm->base[vm->pc[3]]); | ||||||
|  | 				vm->pc += 4; | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|             default: |             default: | ||||||
|                 VMError(vm, "Unknown opcode"); |                 VMError(vm, "Unknown opcode"); | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
|  |         VMMaybeCollect(vm); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Get an argument from the stack */ | /* Get an argument from the stack */ | ||||||
| Value VMGetArg(VM * vm, uint16_t index) { | Value VMGetArg(VM * vm, uint16_t index) { | ||||||
|     uint16_t frameSize = ThreadFrame(vm->thread)->size; |     uint16_t frameSize = vm->frame->size; | ||||||
|     VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds"); |     VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds"); | ||||||
|     return vm->base[index]; |     return vm->base[index]; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Put a value on the stack */ | /* Put a value on the stack */ | ||||||
| void VMSetArg(VM * vm, uint16_t index, Value x) { | void VMSetArg(VM * vm, uint16_t index, Value x) { | ||||||
|     uint16_t frameSize = ThreadFrame(vm->thread)->size; |     uint16_t frameSize = vm->frame->size; | ||||||
|     VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds"); |     VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds"); | ||||||
|     vm->base[index] = x; |     vm->base[index] = x; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Get the size of the VMStack */ | /* Get the size of the VMStack */ | ||||||
| uint16_t VMCountArgs(VM * vm) { | uint16_t VMCountArgs(VM * vm) { | ||||||
|     return ThreadFrame(vm->thread)->size; |     return vm->frame->size; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Initialize the VM */ | /* Initialize the VM */ | ||||||
| void VMInit(VM * vm) { | void VMInit(VM * vm) { | ||||||
|     vm->ret.type = TYPE_NIL; |     vm->ret.type = TYPE_NIL; | ||||||
|     vm->root.type = TYPE_NIL; |  | ||||||
|     vm->base = NULL; |     vm->base = NULL; | ||||||
|  |     vm->frame = NULL; | ||||||
|     vm->pc = NULL; |     vm->pc = NULL; | ||||||
|     vm->error = NULL; |     vm->error = NULL; | ||||||
|     /* Garbage collection */ |     /* Garbage collection */ | ||||||
| @@ -760,8 +750,8 @@ void VMInit(VM * vm) { | |||||||
|     vm->memoryInterval = 0; |     vm->memoryInterval = 0; | ||||||
|     vm->black = 0; |     vm->black = 0; | ||||||
|     vm->lock = 0; |     vm->lock = 0; | ||||||
|     /* Set to empty thread */ |     /* Add thread */ | ||||||
|     vm->thread = NULL; |     vm->thread = ArrayNew(vm, 20); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Load a function into the VM. The function will be called with | /* Load a function into the VM. The function will be called with | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								vm.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								vm.h
									
									
									
									
									
								
							| @@ -17,8 +17,8 @@ | |||||||
|     { if (!(cond)) { VMError((vm), (e)); } } while (0) |     { if (!(cond)) { VMError((vm), (e)); } } while (0) | ||||||
|  |  | ||||||
| /* Type assertion */ | /* Type assertion */ | ||||||
| #define VMAssertType(vm, f, type) \ | #define VMAssertType(vm, f, t) \ | ||||||
|     VMAssert(vm, (f).type == (type), "Expected type " type) |     VMAssert((vm), (f).type == (t), "Expected type,") | ||||||
|  |  | ||||||
| /* Initialize the VM */ | /* Initialize the VM */ | ||||||
| void VMInit(VM * vm); | void VMInit(VM * vm); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose