mirror of
https://github.com/janet-lang/janet
synced 2025-11-02 08:33:04 +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:
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user