mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +00:00 
			
		
		
		
	Flesh out support for userdata
Add file reading via file objects. Finalizer option for userdata.
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -16,7 +16,7 @@ all: $(GST_TARGET) | |||||||
| ##### The core vm and runtime ##### | ##### The core vm and runtime ##### | ||||||
| ################################### | ################################### | ||||||
| GST_CORE_SOURCES=$(addprefix core/,\ | GST_CORE_SOURCES=$(addprefix core/,\ | ||||||
| 				 compile.c disasm.c parse.c stl.c strings.c ids.c util.c\ | 				 compile.c disasm.c parse.c stl.c ids.c util.c\ | ||||||
| 				 value.c vm.c ds.c gc.c thread.c serialize.c) | 				 value.c vm.c ds.c gc.c thread.c serialize.c) | ||||||
| GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES)) | GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES)) | ||||||
| $(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS) | $(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS) | ||||||
|   | |||||||
| @@ -28,5 +28,6 @@ | |||||||
| void gst_cache_remove_string(Gst *vm, char *strmem); | void gst_cache_remove_string(Gst *vm, char *strmem); | ||||||
| void gst_cache_remove_tuple(Gst *vm, char *tuplemem); | void gst_cache_remove_tuple(Gst *vm, char *tuplemem); | ||||||
| void gst_cache_remove_struct(Gst *vm, char *structmem); | void gst_cache_remove_struct(Gst *vm, char *structmem); | ||||||
|  | void gst_cache_remove_userdata(Gst *vm, char *usermem); | ||||||
|  |  | ||||||
| #endif /* end of include guard: CACHE_H_LVYZMBLR */ | #endif /* end of include guard: CACHE_H_LVYZMBLR */ | ||||||
|   | |||||||
| @@ -159,12 +159,13 @@ GstValue gst_array_peek(GstArray *array) { | |||||||
| /****/ | /****/ | ||||||
|  |  | ||||||
| /* Create new userdata */ | /* Create new userdata */ | ||||||
| void *gst_userdata(Gst *vm, uint32_t size, const GstValue *meta) { | void *gst_userdata(Gst *vm, uint32_t size, const GstUserType *utype) { | ||||||
|     char *data = gst_alloc(vm, sizeof(GstUserdataHeader) + size); |     char *data = gst_alloc(vm, sizeof(GstUserdataHeader) + size); | ||||||
|     GstUserdataHeader *header = (GstUserdataHeader *)data; |     GstUserdataHeader *header = (GstUserdataHeader *)data; | ||||||
|     void *user = data + sizeof(GstUserdataHeader); |     void *user = data + sizeof(GstUserdataHeader); | ||||||
|     header->size = size; |     header->size = size; | ||||||
|     header->meta = meta; |     header->type = utype; | ||||||
|  |     gst_mem_tag(header, GST_MEMTAG_USER); | ||||||
|     return user; |     return user; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								core/gc.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								core/gc.c
									
									
									
									
									
								
							| @@ -174,10 +174,8 @@ void gst_mark(Gst *vm, GstValueUnion x, GstType type) { | |||||||
|             if (gc_header(x.string - sizeof(GstUserdataHeader))->color != vm->black) { |             if (gc_header(x.string - sizeof(GstUserdataHeader))->color != vm->black) { | ||||||
|                 GstUserdataHeader *userHeader = (GstUserdataHeader *)x.string - 1; |                 GstUserdataHeader *userHeader = (GstUserdataHeader *)x.string - 1; | ||||||
|                 gc_header(userHeader)->color = vm->black; |                 gc_header(userHeader)->color = vm->black; | ||||||
|                 GstValueUnion temp; |  | ||||||
|                 temp.st = userHeader->meta; |  | ||||||
|                 gst_mark(vm, temp, GST_STRUCT); |  | ||||||
|             } |             } | ||||||
|  |             break; | ||||||
|  |  | ||||||
|         case GST_FUNCENV: |         case GST_FUNCENV: | ||||||
|             gst_mark_funcenv(vm, x.env); |             gst_mark_funcenv(vm, x.env); | ||||||
| @@ -210,6 +208,12 @@ void gst_sweep(Gst *vm) { | |||||||
|                     gst_cache_remove_struct(vm, (char *)(current + 1)); |                     gst_cache_remove_struct(vm, (char *)(current + 1)); | ||||||
|                 if (current->tags & GST_MEMTAG_TUPLE) |                 if (current->tags & GST_MEMTAG_TUPLE) | ||||||
|                     gst_cache_remove_tuple(vm, (char *)(current + 1)); |                     gst_cache_remove_tuple(vm, (char *)(current + 1)); | ||||||
|  |                 if (current->tags & GST_MEMTAG_USER) { | ||||||
|  |                     GstUserdataHeader *h = (GstUserdataHeader *)(current + 1);  | ||||||
|  |                     if (h->type->finalize) { | ||||||
|  |                         h->type->finalize(vm, h + 1, h->size); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             gst_raw_free(current); |             gst_raw_free(current); | ||||||
|         } else { |         } else { | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								core/ids.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								core/ids.c
									
									
									
									
									
								
							| @@ -395,3 +395,25 @@ GstValue gst_string_cv(Gst *vm, const char *str) { | |||||||
|     ret.data.string = data; |     ret.data.string = data; | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Compares two strings */ | ||||||
|  | int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs) { | ||||||
|  |     uint32_t xlen = gst_string_length(lhs); | ||||||
|  |     uint32_t ylen = gst_string_length(rhs); | ||||||
|  |     uint32_t len = xlen > ylen ? ylen : xlen; | ||||||
|  |     uint32_t i; | ||||||
|  |     for (i = 0; i < len; ++i) { | ||||||
|  |         if (lhs[i] == rhs[i]) { | ||||||
|  |             continue; | ||||||
|  |         } else if (lhs[i] < rhs[i]) { | ||||||
|  |             return -1; /* x is less than y */ | ||||||
|  |         } else { | ||||||
|  |             return 1; /* y is less than x */ | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (xlen == ylen) { | ||||||
|  |         return 0; | ||||||
|  |     } else { | ||||||
|  |         return xlen < ylen ? -1 : 1; | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										193
									
								
								core/serialize.c
									
									
									
									
									
								
							
							
						
						
									
										193
									
								
								core/serialize.c
									
									
									
									
									
								
							| @@ -38,12 +38,12 @@ | |||||||
|  * Byte 207: Buffer  - [u32 length]*[u8... characters] |  * Byte 207: Buffer  - [u32 length]*[u8... characters] | ||||||
|  * Byte 208: Array   - [u32 length]*[value... elements] |  * Byte 208: Array   - [u32 length]*[value... elements] | ||||||
|  * Byte 209: Tuple   - [u32 length]*[value... elements] |  * Byte 209: Tuple   - [u32 length]*[value... elements] | ||||||
|  * Byte 210: Thread  - [u8 state][u32 frames]*[[value callee][value env] |  * Byte 210: Thread  - [value parent][u8 state][u32 frames]*[[value callee][value env] | ||||||
|  *  [u32 pcoffset][u16 ret][u16 args][u16 size]*[value ...stack] |  *  [u32 pcoffset][u32 ret][u32 args][u32 size]*[value ...stack]] | ||||||
|  * Byte 211: Table   - [u32 length]*2*[value... kvs] |  * Byte 211: Table   - [u32 length]*2*[value... kvs] | ||||||
|  * Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value... |  * Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value... | ||||||
|  *  literals][u32 bytecodelen]*[u16... bytecode] |  *  literals][u32 bytecodelen]*[u16... bytecode] | ||||||
|  * Byte 213: FunEnv  - [value thread][u32 length]*[value ...upvalues] |  * Byte 213: FuncEnv - [value thread][u32 length]*[value ...upvalues] | ||||||
|  *  (upvalues is not read if thread is a thread object) |  *  (upvalues is not read if thread is a thread object) | ||||||
|  * Byte 214: Func    - [value parent][value def][value env] |  * Byte 214: Func    - [value parent][value def][value env] | ||||||
|  *  (nil values indicate empty) |  *  (nil values indicate empty) | ||||||
| @@ -232,14 +232,15 @@ static const char *gst_deserialize_impl( | |||||||
|  |  | ||||||
|         case 210: /* Thread */ |         case 210: /* Thread */ | ||||||
|             { |             { | ||||||
|                 GstValue nil; |  | ||||||
|                 GstThread *t; |                 GstThread *t; | ||||||
|                 GstValue *stack; |                 GstValue *stack; | ||||||
|                 uint16_t prevsize = 0; |                 uint16_t prevsize = 0; | ||||||
|                 uint8_t statusbyte; |                 uint8_t statusbyte; | ||||||
|                 nil.type = GST_NIL; |                 t = gst_thread(vm, gst_wrap_nil(), 64); | ||||||
|                 t = gst_thread(vm, nil, 64); |                 err = gst_deserialize_impl(vm, data, end, &data, visited, &ret); | ||||||
|                 ret.type = GST_THREAD; |                 if (err != NULL) return err; | ||||||
|  |                 if (ret.type != GST_THREAD) return "expected thread parent to thread"; | ||||||
|  |                 t->parent = ret.data.thread; | ||||||
|                 ret.data.thread = t; |                 ret.data.thread = t; | ||||||
|                 deser_assert(data < end, UEB); |                 deser_assert(data < end, UEB); | ||||||
|                 statusbyte = *data++; |                 statusbyte = *data++; | ||||||
| @@ -258,16 +259,16 @@ static const char *gst_deserialize_impl( | |||||||
|                     uint16_t ret, args, size, j; |                     uint16_t ret, args, size, j; | ||||||
|                     /* Create a new frame */ |                     /* Create a new frame */ | ||||||
|                     if (i > 0) |                     if (i > 0) | ||||||
|                         gst_thread_beginframe(vm, t, nil, 0); |                         gst_thread_beginframe(vm, t, gst_wrap_nil(), 0); | ||||||
|                     /* Read the stack */ |                     /* Read the stack */ | ||||||
|                     err = gst_deserialize_impl(vm, data, end, &data, visited, &callee); |                     err = gst_deserialize_impl(vm, data, end, &data, visited, &callee); | ||||||
|                     if (err != NULL) return err; |                     if (err != NULL) return err; | ||||||
|                     err = gst_deserialize_impl(vm, data, end, &data, visited, &env); |                     err = gst_deserialize_impl(vm, data, end, &data, visited, &env); | ||||||
|                     if (err != NULL) return err; |                     if (err != NULL) return err; | ||||||
|                     read_u32(pcoffset); |                     read_u32(pcoffset); | ||||||
|                     read_u16(ret); |                     read_u32(ret); | ||||||
|                     read_u16(args); |                     read_u32(args); | ||||||
|                     read_u16(size); |                     read_u32(size); | ||||||
|                     /* Set up the stack */ |                     /* Set up the stack */ | ||||||
|                     stack = gst_thread_stack(t); |                     stack = gst_thread_stack(t); | ||||||
|                     if (callee.type == GST_FUNCTION) { |                     if (callee.type == GST_FUNCTION) { | ||||||
| @@ -295,7 +296,7 @@ static const char *gst_deserialize_impl( | |||||||
|                 ret.type = GST_TABLE; |                 ret.type = GST_TABLE; | ||||||
|                 read_u32(length); |                 read_u32(length); | ||||||
|                 ret.data.table = gst_table(vm, 2 * length); |                 ret.data.table = gst_table(vm, 2 * length); | ||||||
|                 for (i = 0; i < length; i += 2) { |                 for (i = 0; i < length; ++i) { | ||||||
|                     GstValue key, value; |                     GstValue key, value; | ||||||
|                     err = gst_deserialize_impl(vm, data, end, &data, visited, &key); |                     err = gst_deserialize_impl(vm, data, end, &data, visited, &key); | ||||||
|                     if (err != NULL) return err; |                     if (err != NULL) return err; | ||||||
| @@ -393,16 +394,8 @@ static const char *gst_deserialize_impl( | |||||||
|  |  | ||||||
|         case 215: /* LUdata */ |         case 215: /* LUdata */ | ||||||
|             { |             { | ||||||
|                 GstValue meta; |                 /* TODO enable deserialization of userdata through registration | ||||||
|                 ret.type = GST_USERDATA; |                  * to names in vm. */  | ||||||
|                 err = gst_deserialize_impl(vm, data, end, &data, visited, &meta); |  | ||||||
|                 if (err != NULL) return err; |  | ||||||
|                 deser_assert(meta.type == GST_STRUCT, "userdata requires valid meta struct"); |  | ||||||
|                 read_u32(length); |  | ||||||
|                 deser_datacheck(length); |  | ||||||
|                 ret.data.pointer = gst_userdata(vm, length, meta.data.st); |  | ||||||
|                 gst_memcpy(ret.data.pointer, data, length); |  | ||||||
|                 gst_array_push(vm, visited, ret); |  | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
| @@ -508,56 +501,124 @@ const char *gst_serialize_impl( | |||||||
|     /* Check reference types */ |     /* Check reference types */ | ||||||
|     switch (x.type) { |     switch (x.type) { | ||||||
|         default: |         default: | ||||||
|            return "unable to serialize type";  |             return "unable to serialize type";  | ||||||
|         case GST_STRING: |         case GST_STRING: | ||||||
|            write_byte(205); |             write_byte(205); | ||||||
|            count = gst_string_length(x.data.string); |             count = gst_string_length(x.data.string); | ||||||
|            write_u32(count); |             write_u32(count); | ||||||
|            for (i = 0; i < count; ++i) { |             for (i = 0; i < count; ++i) { | ||||||
|                write_byte(x.data.string[i]); |                 write_byte(x.data.string[i]); | ||||||
|            } |             } | ||||||
|            break; |             break; | ||||||
|         case GST_STRUCT: |         case GST_STRUCT: | ||||||
|            write_byte(206); |             write_byte(206); | ||||||
|            count = gst_struct_length(x.data.st); |             count = gst_struct_length(x.data.st); | ||||||
|            write_u32(count); |             write_u32(count); | ||||||
|            for (i = 0; i < gst_struct_capacity(x.data.st); i += 2) { |             for (i = 0; i < gst_struct_capacity(x.data.st); i += 2) { | ||||||
|                if (x.data.st[i].type != GST_NIL) { |                 if (x.data.st[i].type != GST_NIL) { | ||||||
|                    err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i]);  |                     err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i]);  | ||||||
|                    if (err != NULL) return err; |                     if (err != NULL) return err; | ||||||
|                    err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i + 1]);  |                     err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i + 1]);  | ||||||
|                    if (err != NULL) return err; |                     if (err != NULL) return err; | ||||||
|                } |                 } | ||||||
|            } |             } | ||||||
|            break; |             break; | ||||||
|         case GST_BYTEBUFFER: |         case GST_BYTEBUFFER: | ||||||
|            write_byte(207); |             write_byte(207); | ||||||
|            count = x.data.buffer->count; |             count = x.data.buffer->count; | ||||||
|            write_u32(count); |             write_u32(count); | ||||||
|            for (i = 0; i < count; ++i) { |             for (i = 0; i < count; ++i) { | ||||||
|                 write_byte(x.data.buffer->data[i]); |                 write_byte(x.data.buffer->data[i]); | ||||||
|            } |             } | ||||||
|            break; |             break; | ||||||
|         case GST_ARRAY: |         case GST_ARRAY: | ||||||
|            write_byte(208); |             write_byte(208); | ||||||
|            count = x.data.array->count; |             count = x.data.array->count; | ||||||
|            write_u32(count); |             write_u32(count); | ||||||
|            for (i = 0; i < count; ++i) { |             for (i = 0; i < count; ++i) { | ||||||
|                err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.array->data[i]);  |                 err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.array->data[i]);  | ||||||
|                if (err != NULL) return err; |                 if (err != NULL) return err; | ||||||
|            } |             } | ||||||
|            break; |             break; | ||||||
|         case GST_TUPLE: |         case GST_TUPLE: | ||||||
|            write_byte(209); |             write_byte(209); | ||||||
|            count = gst_tuple_length(x.data.tuple); |             count = gst_tuple_length(x.data.tuple); | ||||||
|            write_u32(count); |             write_u32(count); | ||||||
|            for (i = 0; i < count; ++i) { |             for (i = 0; i < count; ++i) { | ||||||
|                err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i]);  |                 err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i]);  | ||||||
|                if (err != NULL) return err; |                 if (err != NULL) return err; | ||||||
|            } |             } | ||||||
|            break; |             break; | ||||||
|         /*case GST_THREAD:*/ |         case GST_THREAD: | ||||||
|            /*break;*/ |             { | ||||||
|  |                 GstThread *t = x.data.thread; | ||||||
|  |                 const GstValue *stack; | ||||||
|  |                 uint32_t framecount = gst_thread_countframes(t); | ||||||
|  |                 uint32_t i; | ||||||
|  |                 err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_thread(t->parent)); | ||||||
|  |                 if (err != NULL) return err; | ||||||
|  |                 /* Write the status byte */ | ||||||
|  |                 if (t->status == GST_THREAD_PENDING) write_byte(0); | ||||||
|  |                 else if (t->status == GST_THREAD_ALIVE) write_byte(1); | ||||||
|  |                 else write_byte(2); | ||||||
|  |                 /* Write number of stack frames */ | ||||||
|  |                 write_u32(framecount); | ||||||
|  |                 /* Write stack frames */ | ||||||
|  |                 for (i = 0; i < framecount; ++i) { | ||||||
|  |                     uint32_t j, size; | ||||||
|  |                     GstValue callee = gst_frame_callee(stack); | ||||||
|  |                     GstFuncEnv *env = gst_frame_env(stack);  | ||||||
|  |                     err = gst_serialize_impl(vm, buffer, visited, nextId, callee);  | ||||||
|  |                     if (err != NULL) return err; | ||||||
|  |                     err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_funcenv(env)); | ||||||
|  |                     if (err != NULL) return err; | ||||||
|  |                     if (callee.type == GST_FUNCTION) { | ||||||
|  |                         write_u32(gst_frame_pc(stack) - callee.data.function->def->byteCode); | ||||||
|  |                     } else { | ||||||
|  |                         write_u32(0); | ||||||
|  |                     } | ||||||
|  |                     write_u32(gst_frame_ret(stack)); | ||||||
|  |                     write_u32(gst_frame_args(stack)); | ||||||
|  |                     size = gst_frame_size(stack); | ||||||
|  |                     write_u32(size); | ||||||
|  |                     for (j = 0; j < size; ++j) { | ||||||
|  |                         err = gst_serialize_impl(vm, buffer, visited, nextId, stack[j]); | ||||||
|  |                         if (err != NULL) return err; | ||||||
|  |                     }  | ||||||
|  |                     /* Next stack frame */ | ||||||
|  |                     stack = t->data + GST_FRAME_SIZE; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case GST_TABLE: | ||||||
|  |             write_byte(211); | ||||||
|  |             count = x.data.table->count; | ||||||
|  |             write_u32(count); | ||||||
|  |             for (i = 0; i < x.data.table->capacity; i += 2) { | ||||||
|  |                 if (x.data.table->data[i].type == GST_NIL) continue; | ||||||
|  |                 err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i]);  | ||||||
|  |                 if (err != NULL) return err; | ||||||
|  |                 err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i+1]);  | ||||||
|  |                 if (err != NULL) return err; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         case GST_FUNCDEF: /* Funcdef */ | ||||||
|  |             { | ||||||
|  |                 /* TODO */ | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |         case GST_FUNCENV: /* Funcenv */ | ||||||
|  |             { | ||||||
|  |                 /* TODO */ | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |         case GST_FUNCTION: /* Function */ | ||||||
|  |             { | ||||||
|  |                 /* TODO */ | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* Record reference */ |     /* Record reference */ | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								core/stl.c
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								core/stl.c
									
									
									
									
									
								
							| @@ -328,17 +328,21 @@ int gst_stl_struct(Gst *vm) { | |||||||
| /* Create a buffer */ | /* Create a buffer */ | ||||||
| int gst_stl_buffer(Gst *vm) { | int gst_stl_buffer(Gst *vm) { | ||||||
|     uint32_t i, count; |     uint32_t i, count; | ||||||
|  |     const uint8_t *dat; | ||||||
|  |     uint32_t slen; | ||||||
|     GstBuffer *buf = gst_buffer(vm, 10); |     GstBuffer *buf = gst_buffer(vm, 10); | ||||||
|     count = gst_count_args(vm); |     count = gst_count_args(vm); | ||||||
|     for (i = 0; i < count; ++i) { |     for (i = 0; i < count; ++i) { | ||||||
|         const uint8_t *string = gst_to_string(vm, gst_arg(vm, i)); |         if (gst_chararray_view(gst_arg(vm, i), &dat, &slen)) | ||||||
|         gst_buffer_append(vm, buf, string, gst_string_length(string)); |             gst_buffer_append(vm, buf, dat, slen); | ||||||
|  |         else | ||||||
|  |             gst_c_throwc(vm, GST_EXPECTED_STRING); | ||||||
|     } |     } | ||||||
|     gst_c_return(vm, gst_wrap_buffer(buf)); |     gst_c_return(vm, gst_wrap_buffer(buf)); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Concatenate strings */ | /* Create a string */ | ||||||
| int gst_stl_strcat(Gst *vm) { | int gst_stl_string(Gst *vm) { | ||||||
|     uint32_t j; |     uint32_t j; | ||||||
|     uint32_t count = gst_count_args(vm); |     uint32_t count = gst_count_args(vm); | ||||||
|     uint32_t length = 0; |     uint32_t length = 0; | ||||||
| @@ -515,7 +519,13 @@ int gst_stl_setglobal(Gst *vm) { | |||||||
| /* IO */ | /* IO */ | ||||||
| /****/ | /****/ | ||||||
|  |  | ||||||
| /* TODO - add userdata to allow for manipulation of FILE pointers. */ | /* File type definition */ | ||||||
|  | static GstUserType gst_stl_filetype = { | ||||||
|  |     "io.file", | ||||||
|  |     NULL, | ||||||
|  |     NULL,  | ||||||
|  |     NULL | ||||||
|  | }; | ||||||
|  |  | ||||||
| /* Open a a file and return a userdata wrapper arounf the C file API. */ | /* Open a a file and return a userdata wrapper arounf the C file API. */ | ||||||
| int gst_stl_open(Gst *vm) { | int gst_stl_open(Gst *vm) { | ||||||
| @@ -523,20 +533,44 @@ int gst_stl_open(Gst *vm) { | |||||||
|     const uint8_t *fmode = gst_to_string(vm, gst_arg(vm, 1)); |     const uint8_t *fmode = gst_to_string(vm, gst_arg(vm, 1)); | ||||||
|     FILE *f; |     FILE *f; | ||||||
|     FILE **fp; |     FILE **fp; | ||||||
|     GstValue *st; |  | ||||||
|     if (gst_count_args(vm) < 2 || gst_arg(vm, 0).type != GST_STRING  |     if (gst_count_args(vm) < 2 || gst_arg(vm, 0).type != GST_STRING  | ||||||
|             || gst_arg(vm, 1).type != GST_STRING) |             || gst_arg(vm, 1).type != GST_STRING) | ||||||
|         gst_c_throwc(vm, "expected filename and filemode"); |         gst_c_throwc(vm, "expected filename and filemode"); | ||||||
|     f = fopen((const char *)fname, (const char *)fmode); |     f = fopen((const char *)fname, (const char *)fmode); | ||||||
|     if (!f) |     if (!f) | ||||||
|         gst_c_throwc(vm, "could not open file"); |         gst_c_throwc(vm, "could not open file"); | ||||||
|     st = gst_struct_begin(vm, 0); |     fp = gst_userdata(vm, sizeof(FILE *), &gst_stl_filetype); | ||||||
|     fp = gst_userdata(vm, sizeof(FILE *), gst_struct_end(vm, st)); |  | ||||||
|     *fp = f; |     *fp = f; | ||||||
|     gst_c_return(vm, gst_wrap_userdata(fp)); |     gst_c_return(vm, gst_wrap_userdata(fp)); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Write a string to a file in one go. Overwrites an existing file. */ | /* Read an entire file into memory */ | ||||||
|  | int gst_stl_slurp(Gst *vm) { | ||||||
|  |     GstBuffer *b; | ||||||
|  |     long fsize; | ||||||
|  |     FILE *f; | ||||||
|  |     FILE **fp = gst_check_userdata(vm, 0, &gst_stl_filetype); | ||||||
|  |     if (fp == NULL) gst_c_throwc(vm, "expected file"); | ||||||
|  |     if (!gst_check_buffer(vm, 1, &b)) b = gst_buffer(vm, 10); | ||||||
|  |     f = *fp; | ||||||
|  |     /* Read whole file */ | ||||||
|  |     fseek(f, 0, SEEK_END); | ||||||
|  |     fsize = ftell(f); | ||||||
|  |     fseek(f, 0, SEEK_SET); | ||||||
|  |     /* Ensure buffer size */ | ||||||
|  |     gst_buffer_ensure(vm, b, b->count + fsize); | ||||||
|  |     fread((char *)(b->data + b->count), fsize, 1, f); | ||||||
|  |     b->count += fsize; | ||||||
|  |     gst_c_return(vm, gst_wrap_buffer(b)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Close a file */ | ||||||
|  | int gst_stl_close(Gst *vm) { | ||||||
|  |     FILE **fp = gst_check_userdata(vm, 0, &gst_stl_filetype); | ||||||
|  |     if (fp == NULL) gst_c_throwc(vm, "expected file"); | ||||||
|  |     fclose(*fp); | ||||||
|  |     gst_c_return(vm, gst_wrap_nil()); | ||||||
|  | } | ||||||
|  |  | ||||||
| /****/ | /****/ | ||||||
| /* Temporary */ | /* Temporary */ | ||||||
| @@ -576,8 +610,8 @@ static const GstModuleItem const std_module[] = { | |||||||
|     {"not", gst_stl_not}, |     {"not", gst_stl_not}, | ||||||
|     {"length", gst_stl_length}, |     {"length", gst_stl_length}, | ||||||
|     {"hash", gst_stl_hash}, |     {"hash", gst_stl_hash}, | ||||||
|     {"to-integer", gst_stl_to_int}, |     {"integer", gst_stl_to_int}, | ||||||
|     {"to-real", gst_stl_to_real}, |     {"real", gst_stl_to_real}, | ||||||
|     {"type", gst_stl_type}, |     {"type", gst_stl_type}, | ||||||
|     {"slice", gst_stl_slice}, |     {"slice", gst_stl_slice}, | ||||||
|     {"array", gst_stl_array}, |     {"array", gst_stl_array}, | ||||||
| @@ -585,7 +619,7 @@ static const GstModuleItem const std_module[] = { | |||||||
|     {"table", gst_stl_table}, |     {"table", gst_stl_table}, | ||||||
|     {"struct", gst_stl_struct}, |     {"struct", gst_stl_struct}, | ||||||
|     {"buffer", gst_stl_buffer}, |     {"buffer", gst_stl_buffer}, | ||||||
|     {"strcat", gst_stl_strcat}, |     {"string", gst_stl_string}, | ||||||
|     {"print", gst_stl_print}, |     {"print", gst_stl_print}, | ||||||
|     {"tostring", gst_stl_tostring}, |     {"tostring", gst_stl_tostring}, | ||||||
|     {"exit", gst_stl_exit}, |     {"exit", gst_stl_exit}, | ||||||
| @@ -601,6 +635,8 @@ static const GstModuleItem const std_module[] = { | |||||||
|     {"peek", gst_stl_peek}, |     {"peek", gst_stl_peek}, | ||||||
|     {"ensure", gst_stl_ensure}, |     {"ensure", gst_stl_ensure}, | ||||||
|     {"open", gst_stl_open}, |     {"open", gst_stl_open}, | ||||||
|  |     {"slurp", gst_stl_slurp}, | ||||||
|  |     {"close", gst_stl_close}, | ||||||
|     {"dasm", gst_stl_dasm}, |     {"dasm", gst_stl_dasm}, | ||||||
|     {NULL, NULL} |     {NULL, NULL} | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,45 +0,0 @@ | |||||||
| /* |  | ||||||
| * Copyright (c) 2017 Calvin Rose |  | ||||||
| *  |  | ||||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
| * of this software and associated documentation files (the "Software"), to |  | ||||||
| * deal in the Software without restriction, including without limitation the |  | ||||||
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |  | ||||||
| * sell copies of the Software, and to permit persons to whom the Software is |  | ||||||
| * furnished to do so, subject to the following conditions: |  | ||||||
| *  |  | ||||||
| * The above copyright notice and this permission notice shall be included in |  | ||||||
| * all copies or substantial portions of the Software. |  | ||||||
| *  |  | ||||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |  | ||||||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |  | ||||||
| * IN THE SOFTWARE. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| #include <gst/gst.h> |  | ||||||
|  |  | ||||||
| /* Compares two strings */ |  | ||||||
| int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs) { |  | ||||||
|     uint32_t xlen = gst_string_length(lhs); |  | ||||||
|     uint32_t ylen = gst_string_length(rhs); |  | ||||||
|     uint32_t len = xlen > ylen ? ylen : xlen; |  | ||||||
|     uint32_t i; |  | ||||||
|     for (i = 0; i < len; ++i) { |  | ||||||
|         if (lhs[i] == rhs[i]) { |  | ||||||
|             continue; |  | ||||||
|         } else if (lhs[i] < rhs[i]) { |  | ||||||
|             return -1; /* x is less than y */ |  | ||||||
|         } else { |  | ||||||
|             return 1; /* y is less than x */ |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     if (xlen == ylen) { |  | ||||||
|         return 0; |  | ||||||
|     } else { |  | ||||||
|         return xlen < ylen ? -1 : 1; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -173,3 +173,15 @@ GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) { | |||||||
|     else |     else | ||||||
|         return NULL; |         return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Count the number of stack frames in a thread */ | ||||||
|  | uint32_t gst_thread_countframes(GstThread *thread) { | ||||||
|  |     uint32_t count = 0; | ||||||
|  |     const GstValue *stack = thread->data + GST_FRAME_SIZE; | ||||||
|  |     const GstValue *laststack = thread->data + thread->count; | ||||||
|  |     while (stack <= laststack) { | ||||||
|  |         ++count; | ||||||
|  |         stack += gst_frame_size(stack) + GST_FRAME_SIZE; | ||||||
|  |     } | ||||||
|  |     return count; | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								core/util.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								core/util.c
									
									
									
									
									
								
							| @@ -63,12 +63,27 @@ GST_WRAP_DEFINE(buffer, GstBuffer *, GST_BYTEBUFFER, buffer) | |||||||
| GST_WRAP_DEFINE(function, GstFunction *, GST_FUNCTION, function) | GST_WRAP_DEFINE(function, GstFunction *, GST_FUNCTION, function) | ||||||
| GST_WRAP_DEFINE(cfunction, GstCFunction, GST_CFUNCTION, cfunction) | GST_WRAP_DEFINE(cfunction, GstCFunction, GST_CFUNCTION, cfunction) | ||||||
| GST_WRAP_DEFINE(table, GstTable *, GST_TABLE, table) | GST_WRAP_DEFINE(table, GstTable *, GST_TABLE, table) | ||||||
| GST_WRAP_DEFINE(userdata, void *, GST_USERDATA, pointer) |  | ||||||
| GST_WRAP_DEFINE(funcenv, GstFuncEnv *, GST_FUNCENV, env) | GST_WRAP_DEFINE(funcenv, GstFuncEnv *, GST_FUNCENV, env) | ||||||
| GST_WRAP_DEFINE(funcdef, GstFuncDef *, GST_FUNCDEF, def) | GST_WRAP_DEFINE(funcdef, GstFuncDef *, GST_FUNCDEF, def) | ||||||
|  |  | ||||||
| #undef GST_WRAP_DEFINE | #undef GST_WRAP_DEFINE | ||||||
|  |  | ||||||
|  | GstValue gst_wrap_userdata(void *x) { | ||||||
|  |     GstValue ret; | ||||||
|  |     ret.type = GST_USERDATA; | ||||||
|  |     ret.data.pointer = x; | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void *gst_check_userdata(Gst *vm, uint32_t i, const GstUserType *type) { | ||||||
|  |     GstValue x = gst_arg(vm, i); | ||||||
|  |     GstUserdataHeader *h; | ||||||
|  |     if (x.type != GST_USERDATA) return NULL; | ||||||
|  |     h = ((GstUserdataHeader *)x.data.pointer) - 1; | ||||||
|  |     if (h->type != type) return NULL; | ||||||
|  |     return x.data.pointer; | ||||||
|  | } | ||||||
|  |  | ||||||
| GstValue gst_cmodule_table(Gst *vm, const GstModuleItem *mod) { | GstValue gst_cmodule_table(Gst *vm, const GstModuleItem *mod) { | ||||||
|     GstTable *module = gst_table(vm, 10); |     GstTable *module = gst_table(vm, 10); | ||||||
|     while (mod->name != NULL) { |     while (mod->name != NULL) { | ||||||
|   | |||||||
| @@ -148,14 +148,13 @@ typedef struct GstTable GstTable; | |||||||
| typedef struct GstThread GstThread; | typedef struct GstThread GstThread; | ||||||
| typedef int (*GstCFunction)(Gst * vm); | typedef int (*GstCFunction)(Gst * vm); | ||||||
|  |  | ||||||
| /* Implementation details */ | /* Other structs */ | ||||||
| typedef struct GstUserdataHeader GstUserdataHeader; | typedef struct GstUserdataHeader GstUserdataHeader; | ||||||
| typedef struct GstFuncDef GstFuncDef; | typedef struct GstFuncDef GstFuncDef; | ||||||
| typedef struct GstFuncEnv GstFuncEnv; | typedef struct GstFuncEnv GstFuncEnv; | ||||||
| typedef union GstValueUnion GstValueUnion; | typedef union GstValueUnion GstValueUnion; | ||||||
|  |  | ||||||
| /* API Types */ |  | ||||||
| typedef struct GstModuleItem GstModuleItem; | typedef struct GstModuleItem GstModuleItem; | ||||||
|  | typedef struct GstUserType GstUserType; | ||||||
|  |  | ||||||
| /* C Api data types */ | /* C Api data types */ | ||||||
| struct GstModuleItem { | struct GstModuleItem { | ||||||
| @@ -259,10 +258,18 @@ struct GstFunction { | |||||||
|     GstFunction *parent; |     GstFunction *parent; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /* Defines a type for userdata */ | ||||||
|  | struct GstUserType { | ||||||
|  |     const char *id; | ||||||
|  |     GstValue (*serialize)(Gst *vm, void *data, uint32_t len); | ||||||
|  |     GstValue (*deserialize)(Gst *vm, GstValue in); | ||||||
|  |     void (*finalize)(Gst *vm, void *data, uint32_t len); | ||||||
|  | }; | ||||||
|  |  | ||||||
| /* Contains information about userdata */ | /* Contains information about userdata */ | ||||||
| struct GstUserdataHeader { | struct GstUserdataHeader { | ||||||
|     uint32_t size; |     uint32_t size; | ||||||
|     const GstValue *meta; |     const GstUserType *type; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* VM return status from c function */ | /* VM return status from c function */ | ||||||
| @@ -356,7 +363,7 @@ GstValue gst_array_peek(GstArray *array); | |||||||
| /* Userdata functions */ | /* Userdata functions */ | ||||||
| /****/ | /****/ | ||||||
|  |  | ||||||
| void *gst_userdata(Gst *vm, uint32_t size, const GstValue *meta); | void *gst_userdata(Gst *vm, uint32_t size, const GstUserType *utype); | ||||||
|  |  | ||||||
| /****/ | /****/ | ||||||
| /* Tuple functions */ | /* Tuple functions */ | ||||||
| @@ -409,6 +416,7 @@ void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n); | |||||||
| GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity);  | GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity);  | ||||||
| void gst_thread_endframe(Gst *vm, GstThread *thread); | void gst_thread_endframe(Gst *vm, GstThread *thread); | ||||||
| GstValue *gst_thread_popframe(Gst *vm, GstThread *thread);  | GstValue *gst_thread_popframe(Gst *vm, GstThread *thread);  | ||||||
|  | uint32_t gst_thread_countframes(GstThread *thread); | ||||||
|  |  | ||||||
| /****/ | /****/ | ||||||
| /* Value manipulation */ | /* Value manipulation */ | ||||||
| @@ -427,43 +435,13 @@ GstInteger gst_length(Gst *vm, GstValue x); | |||||||
| /* Serialization */ | /* Serialization */ | ||||||
| /****/ | /****/ | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Data format |  | ||||||
|  * State is encoded as a string of unsigned bytes. |  | ||||||
|  * |  | ||||||
|  * Types: |  | ||||||
|  * |  | ||||||
|  * Byte 0 to 200: small integer byte - 100 |  | ||||||
|  * Byte 201: Nil |  | ||||||
|  * Byte 202: True |  | ||||||
|  * Byte 203: False |  | ||||||
|  * Byte 204: Number  - double format |  | ||||||
|  * Byte 205: String  - [u32 length]*[u8... characters] |  | ||||||
|  * Byte 206: Symbol  - [u32 length]*[u8... characters] |  | ||||||
|  * Byte 207: Buffer  - [u32 length]*[u8... characters] |  | ||||||
|  * Byte 208: Array   - [u32 length]*[value... elements] |  | ||||||
|  * Byte 209: Tuple   - [u32 length]*[value... elements] |  | ||||||
|  * Byte 210: Thread  - [u8 state][u32 frames]*[[value callee][value env] |  | ||||||
|  *  [u32 pcoffset][u32 erroffset][u16 ret][u16 errloc][u16 size]*[value ...stack] |  | ||||||
|  * Byte 211: Table   - [u32 length]*2*[value... kvs] |  | ||||||
|  * Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value... |  | ||||||
|  *  literals][u32 bytecodelen]*[u16... bytecode] |  | ||||||
|  * Byte 213: FunEnv  - [value thread][u32 length]*[value ...upvalues] |  | ||||||
|  *  (upvalues is not read if thread is a thread object) |  | ||||||
|  * Byte 214: Func    - [value parent][value def][value env] |  | ||||||
|  *  (nil values indicate empty) |  | ||||||
|  * Byte 215: LUdata  - [value meta][u32 length]*[u8... bytes] |  | ||||||
|  * Byte 216: CFunc   - [u32 length]*[u8... idstring] |  | ||||||
|  * Byte 217: Ref     - [u32 id] |  | ||||||
|  * Byte 218: Integer - [i64 value] |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| const char *gst_deserialize( | const char *gst_deserialize( | ||||||
|         Gst *vm, |         Gst *vm, | ||||||
|         const uint8_t *data, |         const uint8_t *data, | ||||||
|         uint32_t len, |         uint32_t len, | ||||||
|         GstValue *out, |         GstValue *out, | ||||||
|         const uint8_t *nextData); |         const uint8_t *nextData); | ||||||
|  |  | ||||||
| const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x); | const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x); | ||||||
|  |  | ||||||
| /****/ | /****/ | ||||||
| @@ -473,6 +451,7 @@ const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x); | |||||||
| #define GST_MEMTAG_STRING 4 | #define GST_MEMTAG_STRING 4 | ||||||
| #define GST_MEMTAG_TUPLE 8 | #define GST_MEMTAG_TUPLE 8 | ||||||
| #define GST_MEMTAG_STRUCT 16 | #define GST_MEMTAG_STRUCT 16 | ||||||
|  | #define GST_MEMTAG_USER 32 | ||||||
|  |  | ||||||
| void gst_mark_value(Gst *vm, GstValue x); | void gst_mark_value(Gst *vm, GstValue x); | ||||||
| void gst_mark(Gst *vm, GstValueUnion x, GstType type); | void gst_mark(Gst *vm, GstValueUnion x, GstType type); | ||||||
| @@ -539,10 +518,11 @@ int gst_check_buffer(Gst *vm, uint32_t i, GstBuffer *(*x)); | |||||||
| int gst_check_function(Gst *vm, uint32_t i, GstFunction *(*x)); | int gst_check_function(Gst *vm, uint32_t i, GstFunction *(*x)); | ||||||
| int gst_check_cfunction(Gst *vm, uint32_t i, GstCFunction (*x)); | int gst_check_cfunction(Gst *vm, uint32_t i, GstCFunction (*x)); | ||||||
| int gst_check_table(Gst *vm, uint32_t i, GstTable *(*x)); | int gst_check_table(Gst *vm, uint32_t i, GstTable *(*x)); | ||||||
| int gst_check_userdata(Gst *vm, uint32_t i, void *(*x)); |  | ||||||
| int gst_check_funcenv(Gst *vm, uint32_t i, GstFuncEnv *(*x)); | int gst_check_funcenv(Gst *vm, uint32_t i, GstFuncEnv *(*x)); | ||||||
| int gst_check_funcdef(Gst *vm, uint32_t i, GstFuncDef *(*x)); | int gst_check_funcdef(Gst *vm, uint32_t i, GstFuncDef *(*x)); | ||||||
|  | void *gst_check_userdata(Gst *vm, uint32_t i, const GstUserType *type); | ||||||
|  |  | ||||||
|  | /* Treat similar types through uniform interfaces */ | ||||||
| int gst_seq_view(GstValue seq, const GstValue **data, uint32_t *len); | int gst_seq_view(GstValue seq, const GstValue **data, uint32_t *len); | ||||||
| int gst_chararray_view(GstValue str, const uint8_t **data, uint32_t *len); | int gst_chararray_view(GstValue str, const uint8_t **data, uint32_t *len); | ||||||
| int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap); | int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap); | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ | |||||||
|         (: i (+ 1 i))) |         (: i (+ 1 i))) | ||||||
|     (if (> len 0) (pop parts)) |     (if (> len 0) (pop parts)) | ||||||
|     (push parts end) |     (push parts end) | ||||||
|     (apply strcat start parts))) |     (apply string start parts))) | ||||||
|  |  | ||||||
| # Pretty print an object or struct | # Pretty print an object or struct | ||||||
| (: print-struct (fn [start end s] | (: print-struct (fn [start end s] | ||||||
| @@ -28,7 +28,7 @@ | |||||||
|         (: key (next s key))) |         (: key (next s key))) | ||||||
|     (if (> (length parts) 0) (pop parts)) |     (if (> (length parts) 0) (pop parts)) | ||||||
|     (push parts end) |     (push parts end) | ||||||
|     (apply strcat start parts))) |     (apply string start parts))) | ||||||
|  |  | ||||||
| # Pretty  | # Pretty  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose