mirror of
https://github.com/janet-lang/janet
synced 2024-12-29 09:50:27 +00:00
Allow parser to parse files rather than just a repl. I think
there are some memory leak issues (problems with gc).
This commit is contained in:
parent
f456de5fac
commit
f52e290206
2
Makefile
2
Makefile
@ -3,7 +3,7 @@
|
||||
######################################################
|
||||
##### Set global variables for all gst Makefiles #####
|
||||
######################################################
|
||||
CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -g -I./include
|
||||
CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -I./include -g
|
||||
PREFIX=/usr/local
|
||||
GST_TARGET=client/gst
|
||||
GST_CORELIB=core/libgst.a
|
||||
|
159
client/main.c
159
client/main.c
@ -6,96 +6,95 @@
|
||||
#include <gst/stl.h>
|
||||
#include <gst/disasm.h>
|
||||
|
||||
/* A simple repl for debugging */
|
||||
void debug_repl(FILE *in, FILE *out) {
|
||||
/* Parse a file and execute it */
|
||||
int debug_run(Gst *vm, FILE *in) {
|
||||
char buffer[1024] = {0};
|
||||
const char * reader = buffer;
|
||||
const char *reader = buffer;
|
||||
GstValue func;
|
||||
Gst vm;
|
||||
GstParser p;
|
||||
GstCompiler c;
|
||||
|
||||
gst_parser(&p, vm);
|
||||
|
||||
/* Create do struct */
|
||||
GstArray *arr = gst_array(vm, 10);
|
||||
gst_array_push(vm, arr, gst_string_cv(vm, "do"));
|
||||
|
||||
/* Get and parse input until we have a full form */
|
||||
while (p.status != GST_PARSER_ERROR) {
|
||||
if (*reader == '\0') {
|
||||
if (!fgets(buffer, sizeof(buffer), in)) {
|
||||
break;
|
||||
}
|
||||
reader = buffer;
|
||||
}
|
||||
reader += gst_parse_cstring(&p, reader);
|
||||
if (gst_parse_hasvalue(&p))
|
||||
gst_array_push(vm, arr, gst_parse_consume(&p));
|
||||
}
|
||||
|
||||
/* Turn array into tuple */
|
||||
GstValue *tup = gst_tuple_begin(vm, arr->count);
|
||||
gst_memcpy(tup, arr->data, arr->count * sizeof(GstValue));
|
||||
vm->ret.type = GST_TUPLE;
|
||||
vm->ret.data.tuple = gst_tuple_end(vm, tup);
|
||||
|
||||
/* Check if file read in correctly */
|
||||
if (p.error) {
|
||||
printf("Parse error: %s\n", p.error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check that parser is complete */
|
||||
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
|
||||
printf("Unexpected end of source\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Try to compile generated AST */
|
||||
gst_compiler(&c, vm);
|
||||
func.type = GST_NIL;
|
||||
gst_compiler_usemodule(&c, "std");
|
||||
func.type = GST_FUNCTION;
|
||||
func.data.function = gst_compiler_compile(&c, vm->ret);
|
||||
|
||||
/* Check for compilation errors */
|
||||
if (c.error) {
|
||||
printf("Compiler error: %s\n", c.error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Execute function */
|
||||
if (gst_run(vm, func)) {
|
||||
if (vm->crash) {
|
||||
printf("VM crash: %s\n", vm->crash);
|
||||
} else {
|
||||
printf("VM error: %s\n", (char *)gst_to_string(vm, vm->ret));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
|
||||
Gst vm;
|
||||
int status = 0;
|
||||
gst_init(&vm);
|
||||
gst_stl_load(&vm);
|
||||
|
||||
for (;;) {
|
||||
const char *filename;
|
||||
|
||||
/* Reset state */
|
||||
gst_parser(&p, &vm);
|
||||
// if (argc > 1) {
|
||||
// filename = argv[1];
|
||||
//} else {
|
||||
filename = "libs/stl.gst";
|
||||
//}
|
||||
|
||||
/* Get and parse input until we have a full form */
|
||||
while (p.status == GST_PARSER_PENDING) {
|
||||
/* Get some input if we are done */
|
||||
if (*reader == '\0') {
|
||||
if (out)
|
||||
fprintf(out, ">> ");
|
||||
if (!fgets(buffer, sizeof(buffer), in)) {
|
||||
return;
|
||||
}
|
||||
p.index = 0;
|
||||
reader = buffer;
|
||||
}
|
||||
reader += gst_parse_cstring(&p, reader);
|
||||
}
|
||||
FILE *f = fopen(filename, "rb");
|
||||
status = debug_run(&vm, f);
|
||||
|
||||
/* Check for parsing errors */
|
||||
if (p.error) {
|
||||
unsigned i;
|
||||
if (out) {
|
||||
fprintf(out, "\n");
|
||||
fprintf(out, "%s\n", buffer);
|
||||
for (i = 1; i < p.index; ++i) {
|
||||
fprintf(out, " ");
|
||||
}
|
||||
fprintf(out, "^\n");
|
||||
fprintf(out, "\nParse error: %s\n", p.error);
|
||||
}
|
||||
reader = buffer; /* Flush the input buffer */
|
||||
buffer[0] = '\0';
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try to compile generated AST */
|
||||
gst_compiler(&c, &vm);
|
||||
func.type = GST_NIL;
|
||||
gst_compiler_usemodule(&c, "std");
|
||||
gst_compiler_global(&c, "ans", gst_object_get(vm.rootenv, gst_string_cv(&vm, "ans")));
|
||||
func.type = GST_FUNCTION;
|
||||
func.data.function = gst_compiler_compile(&c, p.value);
|
||||
|
||||
/* Check for compilation errors */
|
||||
if (c.error) {
|
||||
if (out) {
|
||||
fprintf(out, "Compiler error: %s\n", c.error);
|
||||
}
|
||||
reader = buffer;
|
||||
buffer[0] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Execute function */
|
||||
if (gst_run(&vm, func)) {
|
||||
if (out) {
|
||||
if (vm.crash) {
|
||||
fprintf(out, "VM crash: %s\n", vm.crash);
|
||||
} else {
|
||||
fprintf(out, "VM error: ");
|
||||
fprintf(out, "%s\n", (char *)gst_to_string(&vm, vm.ret));
|
||||
}
|
||||
}
|
||||
reader = buffer;
|
||||
buffer[0] = 0;
|
||||
continue;
|
||||
} else if (out) {
|
||||
fprintf(out, "%s\n", (char *)gst_to_string(&vm, vm.ret));
|
||||
gst_object_put(&vm, vm.rootenv, gst_string_cv(&vm, "ans"), vm.ret);
|
||||
}
|
||||
}
|
||||
gst_deinit(&vm);
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("GST v0.0 repl\nCopyright 2017 Calvin Rose\n");
|
||||
debug_repl(stdin, stdout);
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
@ -555,9 +555,6 @@ static Slot compile_function(GstCompiler *c, FormOptions opts, const GstValue *f
|
||||
if (opts.resultUnused) return nil_slot();
|
||||
ret = compiler_get_target(c, opts);
|
||||
subGstScope = compiler_push_scope(c, 0);
|
||||
/* Check for function documentation - for now just ignore. */
|
||||
if (form[current].type == GST_STRING)
|
||||
++current;
|
||||
/* Define the function parameters */
|
||||
if (form[current].type != GST_ARRAY)
|
||||
c_error(c, "expected function arguments array");
|
||||
@ -672,6 +669,7 @@ static Slot compile_try(GstCompiler *c, FormOptions opts, const GstValue *form)
|
||||
Slot body;
|
||||
uint16_t errorIndex;
|
||||
uint32_t countAtTry, countTemp, countAtJump;
|
||||
countAtJump = 0;
|
||||
/* Check argument count */
|
||||
if (gst_tuple_length(form) < 3 || gst_tuple_length(form) > 4)
|
||||
c_error(c, "try takes either 2 or 3 arguments");
|
||||
|
@ -145,10 +145,8 @@ void gst_mark(Gst *vm, GstValueUnion x, GstType type) {
|
||||
gc_header(x.object)->color = vm->black;
|
||||
gc_header(x.object->data)->color = vm->black;
|
||||
for (i = 0; i < x.object->capacity; i += 2) {
|
||||
if (x.object->data[i].type != GST_NIL) {
|
||||
gst_mark_value(vm, x.object->data[i]);
|
||||
gst_mark_value(vm, x.object->data[i + 1]);
|
||||
}
|
||||
gst_mark_value(vm, x.object->data[i]);
|
||||
gst_mark_value(vm, x.object->data[i + 1]);
|
||||
}
|
||||
if (x.object->parent != NULL) {
|
||||
GstValueUnion temp;
|
||||
@ -254,6 +252,9 @@ void gst_collect(Gst *vm) {
|
||||
renv.object = vm->rootenv;
|
||||
gst_mark(vm, renv, GST_OBJECT);
|
||||
gst_mark_value(vm, vm->ret);
|
||||
if (vm->scratch) {
|
||||
gc_header(vm->scratch)->color = vm->black;
|
||||
}
|
||||
gst_sweep(vm);
|
||||
vm->nextCollection = 0;
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ const GstValue *gst_struct_end(Gst *vm, GstValue *st) {
|
||||
|
||||
/* Get an item from a struct */
|
||||
GstValue gst_struct_get(const GstValue *st, GstValue key) {
|
||||
GstValue *bucket = gst_struct_find(st, key);
|
||||
const GstValue *bucket = gst_struct_find(st, key);
|
||||
if (!bucket || bucket[0].type == GST_NIL) {
|
||||
GstValue ret;
|
||||
ret.type = GST_NIL;
|
||||
|
27
core/parse.c
27
core/parse.c
@ -341,6 +341,8 @@ static int string_state(GstParser *p, uint8_t c) {
|
||||
|
||||
/* Root state of the parser */
|
||||
static int root_state(GstParser *p, uint8_t c) {
|
||||
if (is_whitespace(c)) return 1;
|
||||
p->status = GST_PARSER_PENDING;
|
||||
if (c == ']' || c == ')' || c == '}') {
|
||||
p_error(p, UNEXPECTED_CLOSING_DELIM);
|
||||
return 1;
|
||||
@ -357,7 +359,6 @@ static int root_state(GstParser *p, uint8_t c) {
|
||||
p->quoteCount++;
|
||||
return 1;
|
||||
}
|
||||
if (is_whitespace(c)) return 1;
|
||||
if (is_symbol_char(c)) {
|
||||
parser_push(p, PTYPE_TOKEN, c);
|
||||
return 0;
|
||||
@ -421,7 +422,7 @@ static void dispatch_char(GstParser *p, uint8_t c) {
|
||||
}
|
||||
}
|
||||
/* Dispatch character to state */
|
||||
while (!done && p->status == GST_PARSER_PENDING) {
|
||||
while (!done && (p->status == GST_PARSER_PENDING || p->status == GST_PARSER_ROOT)) {
|
||||
GstParseState *top = parser_peek(p);
|
||||
switch (top->type) {
|
||||
case PTYPE_ROOT:
|
||||
@ -447,8 +448,8 @@ static void dispatch_char(GstParser *p, uint8_t c) {
|
||||
*/
|
||||
int gst_parse_cstring(GstParser *p, const char *string) {
|
||||
int bytesRead = 0;
|
||||
p->status = GST_PARSER_PENDING;
|
||||
while ((p->status == GST_PARSER_PENDING) && (string[bytesRead] != '\0')) {
|
||||
while ((p->status == GST_PARSER_PENDING || p->status == GST_PARSER_ROOT)
|
||||
&& (string[bytesRead] != '\0')) {
|
||||
dispatch_char(p, string[bytesRead++]);
|
||||
}
|
||||
return bytesRead;
|
||||
@ -457,14 +458,26 @@ int gst_parse_cstring(GstParser *p, const char *string) {
|
||||
/* Parse a gst string */
|
||||
int gst_parse_string(GstParser *p, const uint8_t *string) {
|
||||
uint32_t i;
|
||||
p->status = GST_PARSER_PENDING;
|
||||
for (i = 0; i < gst_string_length(string); ++i) {
|
||||
if (p->status != GST_PARSER_PENDING) break;
|
||||
if (p->status != GST_PARSER_PENDING && p->status != GST_PARSER_ROOT) break;
|
||||
dispatch_char(p, string[i]);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Check if a parser has a value that needs to be handled. If
|
||||
* so, the parser will not parse any more input until that value
|
||||
* is consumed. */
|
||||
int gst_parse_hasvalue(GstParser *p) {
|
||||
return p->status == GST_PARSER_FULL;
|
||||
}
|
||||
|
||||
/* Gets a value from the parser */
|
||||
GstValue gst_parse_consume(GstParser *p) {
|
||||
p->status = GST_PARSER_ROOT;
|
||||
return p->value;
|
||||
}
|
||||
|
||||
/* Parser initialization (memory allocation) */
|
||||
void gst_parser(GstParser *p, Gst *vm) {
|
||||
p->vm = vm;
|
||||
@ -475,7 +488,7 @@ void gst_parser(GstParser *p, Gst *vm) {
|
||||
p->index = 0;
|
||||
p->quoteCount = 0;
|
||||
p->error = NULL;
|
||||
p->status = GST_PARSER_PENDING;
|
||||
p->status = GST_PARSER_ROOT;
|
||||
p->value.type = GST_NIL;
|
||||
p->flags = GST_PARSER_FLAG_EXPECTING_COMMENT;
|
||||
parser_push(p, PTYPE_ROOT, ' ');
|
||||
|
@ -88,7 +88,7 @@ static const char *gst_deserialize_impl(
|
||||
#define deser_assert(c, e) do{if(!(c))deser_error(e);}while(0)
|
||||
|
||||
/* Assert enough buffer */
|
||||
#define deser_datacheck(len) do{if (end - data < (len)) deser_error(UEB);}while(0)
|
||||
#define deser_datacheck(len) do{if (end < (data + len)) deser_error(UEB);}while(0)
|
||||
|
||||
/* Check for enough space to read uint32_t */
|
||||
#define read_u32(out) do{deser_datacheck(4); (out)=bytes2u32(data); data += 4; }while(0)
|
||||
@ -485,6 +485,19 @@ const char *gst_serialize_impl(
|
||||
write_byte(x.data.string[i]);
|
||||
}
|
||||
break;
|
||||
case GST_STRUCT:
|
||||
write_byte(206);
|
||||
count = gst_struct_length(x.data.st);
|
||||
write_u32(count);
|
||||
for (i = 0; i < gst_struct_capacity(x.data.st); i += 2) {
|
||||
if (x.data.st[i].type != GST_NIL) {
|
||||
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i]);
|
||||
if (err != NULL) return err;
|
||||
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i + 1]);
|
||||
if (err != NULL) return err;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GST_BYTEBUFFER:
|
||||
write_byte(207);
|
||||
count = x.data.buffer->count;
|
||||
|
@ -363,8 +363,10 @@ int gst_stl_print(Gst *vm) {
|
||||
uint32_t len = gst_string_length(string);
|
||||
for (i = 0; i < len; ++i)
|
||||
fputc(string[i], stdout);
|
||||
fputc('\n', stdout);
|
||||
if (j < count - 1)
|
||||
fputc(' ', stdout);
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
return GST_RETURN_OK;
|
||||
}
|
||||
|
||||
|
66
core/vm.c
66
core/vm.c
@ -19,28 +19,16 @@ static const char GST_EXPECTED_FUNCTION[] = "expected function";
|
||||
static const char GST_EXPECTED_NUMBER_ROP[] = "expected right operand to be number";
|
||||
static const char GST_EXPECTED_NUMBER_LOP[] = "expected left operand to be number";
|
||||
|
||||
/* Contextual macro to state in function with VM */
|
||||
#define GST_STATE_SYNC() do { \
|
||||
thread = *vm->thread; \
|
||||
stack = thread.data + thread.count; \
|
||||
} while (0)
|
||||
|
||||
/* Write local state back to VM */
|
||||
#define GST_STATE_WRITE() do { \
|
||||
*vm->thread = thread; \
|
||||
} while (0)
|
||||
|
||||
/* Start running the VM from where it left off. Continue running
|
||||
* until the stack size is smaller than minStackSize. */
|
||||
static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
/* VM state */
|
||||
GstThread thread;
|
||||
GstValue *stack;
|
||||
GstValue temp, v1, v2;
|
||||
uint16_t *pc;
|
||||
|
||||
/* Intialize local state */
|
||||
GST_STATE_SYNC();
|
||||
stack = vm->thread->data + vm->thread->count;
|
||||
pc = gst_frame_pc(stack);
|
||||
|
||||
/* Main interpreter loop */
|
||||
@ -158,9 +146,8 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
gst_error(vm, GST_EXPECTED_FUNCTION);
|
||||
if (gst_frame_env(stack) == NULL) {
|
||||
gst_frame_env(stack) = gst_alloc(vm, sizeof(GstFuncEnv));
|
||||
*vm->thread = thread;
|
||||
gst_frame_env(stack)->thread = vm->thread;
|
||||
gst_frame_env(stack)->stackOffset = thread.count;
|
||||
gst_frame_env(stack)->stackOffset = vm->thread->count;
|
||||
gst_frame_env(stack)->values = NULL;
|
||||
}
|
||||
if (pc[2] > v1.data.function->def->literalsLen)
|
||||
@ -179,10 +166,6 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
}
|
||||
break;
|
||||
|
||||
case GST_OP_ERR: /* Throw error */
|
||||
vm->ret = stack[pc[1]];
|
||||
goto vm_error;
|
||||
|
||||
case GST_OP_TRY: /* Begin try block */
|
||||
gst_frame_errloc(stack) = pc[1];
|
||||
gst_frame_errjmp(stack) = pc + *(uint32_t *)(pc + 2);
|
||||
@ -195,10 +178,9 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
continue;
|
||||
|
||||
case GST_OP_RTN: /* Return nil */
|
||||
stack = gst_thread_popframe(vm, &thread);
|
||||
if (thread.count < stackBase) {
|
||||
stack = gst_thread_popframe(vm, vm->thread);
|
||||
if (vm->thread->count < stackBase) {
|
||||
vm->ret.type = GST_NIL;
|
||||
GST_STATE_WRITE();
|
||||
return GST_RETURN_OK;
|
||||
}
|
||||
pc = gst_frame_pc(stack);
|
||||
@ -207,10 +189,9 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
|
||||
case GST_OP_RET: /* Return */
|
||||
temp = stack[pc[1]];
|
||||
stack = gst_thread_popframe(vm, &thread);
|
||||
if (thread.count < stackBase) {
|
||||
stack = gst_thread_popframe(vm, vm->thread);
|
||||
if (vm->thread->count < stackBase) {
|
||||
vm->ret = temp;
|
||||
GST_STATE_WRITE();
|
||||
return GST_RETURN_OK;
|
||||
}
|
||||
pc = gst_frame_pc(stack);
|
||||
@ -230,17 +211,17 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
/* Push new frame */
|
||||
if (temp.type != GST_FUNCTION && temp.type != GST_CFUNCTION)
|
||||
gst_error(vm, GST_EXPECTED_FUNCTION);
|
||||
stack = gst_thread_beginframe(vm, &thread, temp, arity);
|
||||
stack = gst_thread_beginframe(vm, vm->thread, temp, arity);
|
||||
oldStack = stack - GST_FRAME_SIZE - gst_frame_prevsize(stack);
|
||||
/* Write arguments */
|
||||
size = gst_frame_size(stack);
|
||||
for (i = 0; i < arity; ++i)
|
||||
stack[i + size - arity] = oldStack[pc[offset + i]];
|
||||
/* Finish new frame */
|
||||
gst_thread_endframe(vm, &thread);
|
||||
gst_thread_endframe(vm, vm->thread);
|
||||
/* Check tail call - if so, replace frame. */
|
||||
if (isTCall) {
|
||||
stack = gst_thread_tail(vm, &thread);
|
||||
stack = gst_thread_tail(vm, vm->thread);
|
||||
} else {
|
||||
gst_frame_ret(oldStack) = ret;
|
||||
}
|
||||
@ -254,14 +235,11 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
} else {
|
||||
int status;
|
||||
gst_frame_pc(stack) = pc;
|
||||
GST_STATE_WRITE();
|
||||
vm->ret.type = GST_NIL;
|
||||
status = temp.data.cfunction(vm);
|
||||
GST_STATE_SYNC();
|
||||
stack = gst_thread_popframe(vm, &thread);
|
||||
stack = gst_thread_popframe(vm, vm->thread);
|
||||
if (status == GST_RETURN_OK) {
|
||||
if (thread.count < stackBase) {
|
||||
GST_STATE_WRITE();
|
||||
if (vm->thread->count < stackBase) {
|
||||
return status;
|
||||
} else {
|
||||
stack[gst_frame_ret(stack)] = vm->ret;
|
||||
@ -281,6 +259,10 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
* These opcodes are nto strictlyre required and can
|
||||
* be reimplemented with stanard library functions */
|
||||
|
||||
case GST_OP_ERR: /* Throw error */
|
||||
vm->ret = stack[pc[1]];
|
||||
goto vm_error;
|
||||
|
||||
#define OP_BINARY_MATH(op) \
|
||||
v1 = stack[pc[2]]; \
|
||||
v2 = stack[pc[3]]; \
|
||||
@ -401,15 +383,13 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
|
||||
case GST_OP_YLD: /* Yield from function */
|
||||
temp = stack[pc[1]];
|
||||
if (thread.parent == NULL) {
|
||||
if (vm->thread->parent == NULL) {
|
||||
vm->ret = temp;
|
||||
return GST_RETURN_OK;
|
||||
}
|
||||
gst_frame_pc(stack) = pc + 2;
|
||||
GST_STATE_WRITE();
|
||||
vm->thread = thread.parent;
|
||||
thread = *vm->thread;
|
||||
stack = thread.data + thread.count;
|
||||
vm->thread = vm->thread->parent;
|
||||
stack = vm->thread->data + vm->thread->count;
|
||||
pc = gst_frame_pc(stack);
|
||||
break;
|
||||
|
||||
@ -418,8 +398,8 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
if (stack == NULL)
|
||||
return GST_RETURN_ERROR;
|
||||
while (gst_frame_errjmp(stack) == NULL) {
|
||||
stack = gst_thread_popframe(vm, &thread);
|
||||
if (thread.count < stackBase)
|
||||
stack = gst_thread_popframe(vm, vm->thread);
|
||||
if (vm->thread->count < stackBase)
|
||||
return GST_RETURN_ERROR;
|
||||
}
|
||||
pc = gst_frame_errjmp(stack);
|
||||
@ -428,9 +408,9 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
|
||||
} /* end switch */
|
||||
|
||||
/* TODO: Move collection only to places that allocate memory */
|
||||
/* This, however, is good for testing to ensure no memory leaks */
|
||||
*vm->thread = thread;
|
||||
/* Check for collection every cycle. If the instruction definitely does
|
||||
* not allocate memory, it can use continue instead of break to
|
||||
* skip this check */
|
||||
gst_maybe_collect(vm);
|
||||
|
||||
} /* end for */
|
||||
|
@ -20,7 +20,8 @@ struct GstParser {
|
||||
enum {
|
||||
GST_PARSER_PENDING = 0,
|
||||
GST_PARSER_FULL,
|
||||
GST_PARSER_ERROR
|
||||
GST_PARSER_ERROR,
|
||||
GST_PARSER_ROOT
|
||||
} status;
|
||||
};
|
||||
|
||||
@ -37,4 +38,12 @@ int gst_parse_cstring(GstParser *p, const char *string);
|
||||
/* Parse a gst string. Returns number of bytes read */
|
||||
int gst_parse_string(GstParser *p, const uint8_t *string);
|
||||
|
||||
/* Check if a parser has a value that needs to be handled. If
|
||||
* so, the parser will not parse any more input until that value
|
||||
* is consumed. */
|
||||
int gst_parse_hasvalue(GstParser *p);
|
||||
|
||||
/* Gets a value from the parser */
|
||||
GstValue gst_parse_consume(GstParser *p);
|
||||
|
||||
#endif /* end of include guard: PARSE_H_ONYWMADW */
|
||||
|
@ -1 +1,6 @@
|
||||
(: f (fn [x] (strcat (tostring x) "-abumba")))
|
||||
|
||||
(: i 100)
|
||||
(while (> i 0) (print i) (: i (- i 1)))
|
||||
|
||||
(print (strcat (tostring (+ 1 2 3)) 'a 'b (f 'c)))
|
||||
|
Loading…
Reference in New Issue
Block a user