next: *
This commit is contained in:
parent
2ac2f85512
commit
90175b7e26
12 changed files with 300 additions and 77 deletions
|
|
@ -45,6 +45,7 @@ growl = executable(
|
|||
)
|
||||
|
||||
growlnext_sources = [
|
||||
'next/core/alien.c',
|
||||
'next/core/arena.c',
|
||||
'next/core/callable.c',
|
||||
'next/core/compiler.c',
|
||||
|
|
@ -53,6 +54,7 @@ growlnext_sources = [
|
|||
'next/core/sleb128.c',
|
||||
'next/core/string.c',
|
||||
'next/core/tuple.c',
|
||||
'next/core/value.c',
|
||||
'next/core/vm.c',
|
||||
'next/main.c',
|
||||
]
|
||||
|
|
|
|||
23
next/core/alien.c
Normal file
23
next/core/alien.c
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include <growl.h>
|
||||
|
||||
Growl growl_make_alien(GrowlVM *vm, GrowlAlienType *type, void *data) {
|
||||
size_t size = sizeof(GrowlObjectHeader) + sizeof(GrowlAlien);
|
||||
GrowlObjectHeader *hdr = growl_gc_alloc(vm, size);
|
||||
hdr->type = GROWL_TYPE_ALIEN;
|
||||
GrowlAlien *alien = (GrowlAlien *)(hdr + 1);
|
||||
alien->type = type;
|
||||
alien->data = data;
|
||||
return GROWL_BOX(hdr);
|
||||
}
|
||||
|
||||
GrowlAlien *growl_unwrap_alien(Growl obj, GrowlAlienType *type) {
|
||||
if (obj == GROWL_NIL || GROWL_IMM(obj))
|
||||
return NULL;
|
||||
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
|
||||
if (hdr->type != GROWL_TYPE_ALIEN)
|
||||
return NULL;
|
||||
GrowlAlien *alien = (GrowlAlien *)(hdr + 1);
|
||||
if (alien->type != type)
|
||||
return NULL;
|
||||
return alien;
|
||||
}
|
||||
|
|
@ -16,11 +16,11 @@ void growl_arena_free(GrowlGCArena *arena) {
|
|||
|
||||
void *growl_arena_alloc(GrowlGCArena *arena, size_t size, size_t align,
|
||||
size_t count) {
|
||||
ptrdiff_t padding = -(uintptr_t)arena->start & (align - 1);
|
||||
ptrdiff_t available = arena->end - arena->start - padding;
|
||||
ptrdiff_t padding = -(uintptr_t)arena->free & (align - 1);
|
||||
ptrdiff_t available = arena->end - arena->free - padding;
|
||||
if (available < 0 || count > available / size)
|
||||
abort();
|
||||
void *p = arena->start + padding;
|
||||
arena->start += padding + count * size;
|
||||
void *p = arena->free + padding;
|
||||
arena->free += padding + count * size;
|
||||
return memset(p, 0, count * size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ int growl_callable(Growl obj) {
|
|||
return 0;
|
||||
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
|
||||
switch (hdr->type) {
|
||||
case GROWL_QUOTATION:
|
||||
case GROWL_COMPOSE:
|
||||
case GROWL_CURRY:
|
||||
case GROWL_TYPE_QUOTATION:
|
||||
case GROWL_TYPE_COMPOSE:
|
||||
case GROWL_TYPE_CURRY:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
|
|
@ -21,7 +21,7 @@ Growl growl_make_quotation(GrowlVM *vm, const uint8_t *code, size_t code_size,
|
|||
constants_size * sizeof(Growl);
|
||||
GrowlObjectHeader *constants_hdr =
|
||||
growl_gc_alloc_tenured(vm, constants_obj_size);
|
||||
constants_hdr->type = GROWL_TUPLE;
|
||||
constants_hdr->type = GROWL_TYPE_TUPLE;
|
||||
GrowlTuple *constants_tuple = (GrowlTuple *)(constants_hdr + 1);
|
||||
|
||||
constants_tuple->count = constants_size;
|
||||
|
|
@ -33,7 +33,7 @@ Growl growl_make_quotation(GrowlVM *vm, const uint8_t *code, size_t code_size,
|
|||
sizeof(GrowlObjectHeader) + sizeof(GrowlQuotation) + code_size;
|
||||
GrowlObjectHeader *quotation_hdr =
|
||||
growl_gc_alloc_tenured(vm, quotation_obj_size);
|
||||
quotation_hdr->type = GROWL_QUOTATION;
|
||||
quotation_hdr->type = GROWL_TYPE_QUOTATION;
|
||||
GrowlQuotation *quotation = (GrowlQuotation *)(quotation_hdr + 1);
|
||||
|
||||
quotation->constants = GROWL_BOX(constants_hdr);
|
||||
|
|
@ -47,7 +47,7 @@ GrowlQuotation *growl_unwrap_quotation(Growl obj) {
|
|||
if (obj == GROWL_NIL || GROWL_IMM(obj))
|
||||
return NULL;
|
||||
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
|
||||
if (hdr->type != GROWL_QUOTATION)
|
||||
if (hdr->type != GROWL_TYPE_QUOTATION)
|
||||
return NULL;
|
||||
return (GrowlQuotation *)(hdr + 1);
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ Growl growl_compose(GrowlVM *vm, Growl first, Growl second) {
|
|||
return GROWL_NIL;
|
||||
size_t size = sizeof(GrowlObjectHeader) + sizeof(GrowlCompose);
|
||||
GrowlObjectHeader *hdr = growl_gc_alloc(vm, size);
|
||||
hdr->type = GROWL_COMPOSE;
|
||||
hdr->type = GROWL_TYPE_COMPOSE;
|
||||
GrowlCompose *comp = (GrowlCompose *)(hdr + 1);
|
||||
comp->first = first;
|
||||
comp->second = second;
|
||||
|
|
@ -70,7 +70,7 @@ GrowlCompose *growl_unwrap_compose(Growl obj) {
|
|||
if (obj == GROWL_NIL || GROWL_IMM(obj))
|
||||
return NULL;
|
||||
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
|
||||
if (hdr->type != GROWL_COMPOSE)
|
||||
if (hdr->type != GROWL_TYPE_COMPOSE)
|
||||
return NULL;
|
||||
return (GrowlCompose *)(hdr + 1);
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ Growl growl_curry(GrowlVM *vm, Growl value, Growl callable) {
|
|||
return GROWL_NIL;
|
||||
size_t size = sizeof(GrowlObjectHeader) + sizeof(GrowlCurry);
|
||||
GrowlObjectHeader *hdr = growl_gc_alloc(vm, size);
|
||||
hdr->type = GROWL_CURRY;
|
||||
hdr->type = GROWL_TYPE_CURRY;
|
||||
GrowlCurry *comp = (GrowlCurry *)(hdr + 1);
|
||||
comp->value = value;
|
||||
comp->callable = callable;
|
||||
|
|
@ -91,7 +91,7 @@ GrowlCurry *growl_unwrap_curry(Growl obj) {
|
|||
if (obj == GROWL_NIL || GROWL_IMM(obj))
|
||||
return NULL;
|
||||
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
|
||||
if (hdr->type != GROWL_CURRY)
|
||||
if (hdr->type != GROWL_TYPE_CURRY)
|
||||
return NULL;
|
||||
return (GrowlCurry *)(hdr + 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,38 +67,40 @@ GrowlObjectHeader *growl_gc_alloc_tenured(GrowlVM *vm, size_t size) {
|
|||
|
||||
static void scan(GrowlVM *vm, GrowlObjectHeader *hdr) {
|
||||
switch (hdr->type) {
|
||||
case GROWL_STRING:
|
||||
case GROWL_TYPE_STRING:
|
||||
break;
|
||||
case GROWL_LIST: {
|
||||
case GROWL_TYPE_LIST: {
|
||||
GrowlList *list = (GrowlList *)(hdr + 1);
|
||||
list->head = forward(vm, list->head);
|
||||
list->tail = forward(vm, list->tail);
|
||||
break;
|
||||
}
|
||||
case GROWL_TUPLE: {
|
||||
case GROWL_TYPE_TUPLE: {
|
||||
GrowlTuple *tuple = (GrowlTuple *)(hdr + 1);
|
||||
for (size_t i = 0; i < tuple->count; ++i) {
|
||||
tuple->data[i] = forward(vm, tuple->data[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GROWL_QUOTATION: {
|
||||
case GROWL_TYPE_QUOTATION: {
|
||||
GrowlQuotation *quot = (GrowlQuotation *)(hdr + 1);
|
||||
quot->constants = forward(vm, quot->constants);
|
||||
break;
|
||||
}
|
||||
case GROWL_COMPOSE: {
|
||||
case GROWL_TYPE_COMPOSE: {
|
||||
GrowlCompose *comp = (GrowlCompose *)(hdr + 1);
|
||||
comp->first = forward(vm, comp->first);
|
||||
comp->second = forward(vm, comp->second);
|
||||
break;
|
||||
}
|
||||
case GROWL_CURRY: {
|
||||
case GROWL_TYPE_CURRY: {
|
||||
GrowlCurry *comp = (GrowlCurry *)(hdr + 1);
|
||||
comp->value = forward(vm, comp->value);
|
||||
comp->callable = forward(vm, comp->callable);
|
||||
break;
|
||||
}
|
||||
case GROWL_TYPE_ALIEN:
|
||||
break;
|
||||
case UINT32_MAX:
|
||||
fprintf(stderr, "gc: fwd pointer during scan\n");
|
||||
abort();
|
||||
|
|
@ -109,15 +111,22 @@ static void scan(GrowlVM *vm, GrowlObjectHeader *hdr) {
|
|||
}
|
||||
|
||||
static void gc_print_stats(GrowlVM *vm, const char *label) {
|
||||
size_t used = vm->from.free - vm->from.start;
|
||||
size_t total = vm->from.end - vm->from.start;
|
||||
fprintf(stderr, "[%s] used=%zu/%zu bytes (%.1f%%)\n", label, used, total,
|
||||
(double)used / (double)total * 100.0);
|
||||
size_t nursery_used = vm->from.free - vm->from.start;
|
||||
size_t nursery_total = vm->from.end - vm->from.start;
|
||||
size_t tenured_used = vm->arena.free - vm->arena.start;
|
||||
size_t tenured_total = vm->arena.end - vm->arena.start;
|
||||
|
||||
fprintf(stderr, "%s:\n", label);
|
||||
fprintf(stderr, " tenured: %zu/%zu bytes (%.1f%%)\n", tenured_used,
|
||||
nursery_total, (double)tenured_used / (double)tenured_total * 100.0);
|
||||
fprintf(stderr, " nursery: %zu/%zu bytes (%.1f%%)\n", nursery_used,
|
||||
nursery_total, (double)nursery_used / (double)nursery_total * 100.0);
|
||||
}
|
||||
|
||||
void growl_gc_collect(GrowlVM *vm) {
|
||||
uint8_t *gc_scan = vm->to.free;
|
||||
|
||||
fprintf(stderr, ">>> starting garbage collection\n");
|
||||
gc_print_stats(vm, "before GC");
|
||||
|
||||
for (size_t i = 0; i < GROWL_STACK_SIZE; ++i) {
|
||||
|
|
@ -141,6 +150,26 @@ void growl_gc_collect(GrowlVM *vm) {
|
|||
gc_scan += ALIGN(hdr->size);
|
||||
}
|
||||
|
||||
gc_scan = vm->from.start;
|
||||
while (gc_scan < vm->from.free) {
|
||||
GrowlObjectHeader *hdr = (GrowlObjectHeader *)gc_scan;
|
||||
if (hdr->type != UINT32_MAX) {
|
||||
switch (hdr->type) {
|
||||
case GROWL_TYPE_ALIEN: {
|
||||
GrowlAlien *alien = (GrowlAlien *)(hdr + 1);
|
||||
if (alien->type->finalizer != NULL) {
|
||||
alien->type->finalizer(alien->data);
|
||||
alien->data = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
gc_scan += ALIGN(hdr->size);
|
||||
}
|
||||
|
||||
GrowlGCArena tmp = vm->from;
|
||||
vm->from = vm->to;
|
||||
vm->to = tmp;
|
||||
|
|
@ -148,6 +177,7 @@ void growl_gc_collect(GrowlVM *vm) {
|
|||
vm->scratch.free = vm->scratch.start;
|
||||
|
||||
gc_print_stats(vm, "after GC");
|
||||
fprintf(stderr, ">>> garbage collection finished\n");
|
||||
}
|
||||
|
||||
void growl_gc_root(GrowlVM *vm, Growl *ptr) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,25 @@
|
|||
#ifndef GROWL_OPCODES_H
|
||||
#define GROWL_OPCODES_H
|
||||
|
||||
enum {
|
||||
enum GrowlOpcode {
|
||||
GOP_NOP = 0,
|
||||
GOP_PUSH_NIL,
|
||||
GOP_PUSH_CONSTANT,
|
||||
GOP_DROP,
|
||||
GOP_DUP,
|
||||
GOP_SWAP,
|
||||
GOP_2DROP,
|
||||
GOP_2DUP,
|
||||
GOP_2SWAP,
|
||||
GOP_NIP,
|
||||
GOP_OVER,
|
||||
GOP_BURY,
|
||||
GOP_DIG,
|
||||
GOP_TO_RETAIN,
|
||||
GOP_FROM_RETAIN,
|
||||
GOP_CALL,
|
||||
GOP_CALL_NEXT,
|
||||
GOP_TAIL_CALL,
|
||||
GOP_RETURN,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ intptr_t growl_sleb128_decode(uint8_t **ptr) {
|
|||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
|
||||
if ((shift < 64) && (byte & 0x40)) {
|
||||
if (shift < 64 && byte & 0x40) {
|
||||
result |= -(1LL << shift);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
Growl growl_make_string(GrowlVM *vm, size_t len) {
|
||||
size_t size = sizeof(GrowlObjectHeader) + sizeof(GrowlString) + len;
|
||||
GrowlObjectHeader *hdr = growl_gc_alloc(vm, size);
|
||||
hdr->type = GROWL_STRING;
|
||||
hdr->type = GROWL_TYPE_STRING;
|
||||
GrowlString *str = (GrowlString *)(hdr + 1);
|
||||
str->len = len;
|
||||
memset(str->data, 0, len);
|
||||
|
|
@ -15,7 +15,7 @@ Growl growl_wrap_string(GrowlVM *vm, const char *cstr) {
|
|||
size_t len = strlen(cstr);
|
||||
size_t size = sizeof(GrowlObjectHeader) + sizeof(GrowlString) + len + 1;
|
||||
GrowlObjectHeader *hdr = growl_gc_alloc(vm, size);
|
||||
hdr->type = GROWL_STRING;
|
||||
hdr->type = GROWL_TYPE_STRING;
|
||||
GrowlString *str = (GrowlString *)(hdr + 1);
|
||||
str->len = len;
|
||||
memcpy(str->data, cstr, len);
|
||||
|
|
@ -27,7 +27,7 @@ GrowlString *growl_unwrap_string(Growl obj) {
|
|||
if (obj == 0 || GROWL_IMM(obj))
|
||||
return NULL;
|
||||
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
|
||||
if (hdr->type != GROWL_STRING)
|
||||
if (hdr->type != GROWL_TYPE_STRING)
|
||||
return NULL;
|
||||
return (GrowlString *)(hdr + 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ GrowlTuple *growl_unwrap_tuple(Growl obj) {
|
|||
if (obj == 0 || GROWL_IMM(obj))
|
||||
return NULL;
|
||||
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
|
||||
if (hdr->type != GROWL_TUPLE)
|
||||
if (hdr->type != GROWL_TYPE_TUPLE)
|
||||
return NULL;
|
||||
return (GrowlTuple *)(hdr + 1);
|
||||
}
|
||||
|
|
|
|||
11
next/core/value.c
Normal file
11
next/core/value.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include <growl.h>
|
||||
|
||||
uint32_t growl_type(Growl obj) {
|
||||
if (obj == GROWL_NIL)
|
||||
return GROWL_TYPE_NIL;
|
||||
if (GROWL_IMM(obj))
|
||||
return GROWL_TYPE_NUMBER;
|
||||
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
|
||||
return hdr->type;
|
||||
}
|
||||
|
||||
201
next/core/vm.c
201
next/core/vm.c
|
|
@ -33,6 +33,8 @@ GrowlVM *growl_vm_init(void) {
|
|||
mem->root_count = 0;
|
||||
mem->root_capacity = 0;
|
||||
|
||||
// TODO: initialize compose trampoline
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +65,12 @@ void growl_push(GrowlVM *vm, Growl obj) {
|
|||
*vm->sp++ = obj;
|
||||
}
|
||||
|
||||
Growl growl_peek(GrowlVM *vm, size_t depth) {
|
||||
if (vm->sp <= vm->wst + depth)
|
||||
vm_error(vm, "work stack underflow");
|
||||
return vm->sp[-(depth + 1)];
|
||||
}
|
||||
|
||||
Growl growl_pop(GrowlVM *vm) {
|
||||
if (vm->sp <= vm->wst)
|
||||
vm_error(vm, "work stack underflow");
|
||||
|
|
@ -85,19 +93,47 @@ Growl growl_rpop(GrowlVM *vm) {
|
|||
return obj;
|
||||
}
|
||||
|
||||
static void push_call(GrowlVM *vm, GrowlQuotation *q, uint8_t *ip) {
|
||||
static void callstack_push(GrowlVM *vm, GrowlQuotation *q, uint8_t *ip) {
|
||||
if (vm->csp >= vm->cst + GROWL_CALL_STACK_SIZE)
|
||||
vm_error(vm, "call stack overflow");
|
||||
vm->csp->quot = q;
|
||||
vm->csp->ip = ip;
|
||||
vm->csp++;
|
||||
}
|
||||
static GrowlFrame pop_call(GrowlVM *vm) {
|
||||
|
||||
static GrowlFrame callstack_pop(GrowlVM *vm) {
|
||||
if (vm->csp <= vm->cst)
|
||||
vm_error(vm, "call stack underflow");
|
||||
return *--vm->csp;
|
||||
}
|
||||
|
||||
static inline void dispatch(GrowlVM *vm, Growl obj) {
|
||||
for (;;) {
|
||||
switch (growl_type(obj)) {
|
||||
case GROWL_TYPE_QUOTATION: {
|
||||
GrowlQuotation *q = (GrowlQuotation *)(GROWL_UNBOX(obj) + 1);
|
||||
vm->quotation = q;
|
||||
vm->ip = q->data;
|
||||
return;
|
||||
}
|
||||
case GROWL_TYPE_COMPOSE: {
|
||||
GrowlCompose *c = (GrowlCompose *)(GROWL_UNBOX(obj) + 1);
|
||||
callstack_push(vm, vm->compose_trampoline, vm->compose_trampoline->data);
|
||||
vm->csp[-1].next = c->second;
|
||||
obj = c->first;
|
||||
continue;
|
||||
}
|
||||
case GROWL_TYPE_CURRY: {
|
||||
GrowlCurry *c = (GrowlCurry *)(GROWL_UNBOX(obj) + 1);
|
||||
growl_push(vm, c->value);
|
||||
obj = c->callable;
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
vm_error(vm, "attempt to call non-callable");
|
||||
}
|
||||
}
|
||||
}
|
||||
int vm_doquot(GrowlVM *vm, GrowlQuotation *quot) {
|
||||
size_t gc_mark = growl_gc_mark(vm);
|
||||
int result = setjmp(vm->error);
|
||||
|
|
@ -117,46 +153,129 @@ int vm_doquot(GrowlVM *vm, GrowlQuotation *quot) {
|
|||
vm->ip = quot->data;
|
||||
vm->quotation = quot;
|
||||
|
||||
for (;;) {
|
||||
uint8_t opcode;
|
||||
switch (opcode = *vm->ip++) {
|
||||
case GOP_NOP:
|
||||
break;
|
||||
case GOP_PUSH_NIL:
|
||||
growl_push(vm, GROWL_NIL);
|
||||
break;
|
||||
case GOP_PUSH_CONSTANT: {
|
||||
intptr_t idx = growl_sleb128_decode(&vm->ip);
|
||||
if (constants != NULL) {
|
||||
growl_push(vm, constants->data[idx]);
|
||||
} else {
|
||||
vm_error(vm, "constant index %" PRIdPTR " out of bounds", idx);
|
||||
}
|
||||
break;
|
||||
case GOP_CALL: { // TODO: compose and curry
|
||||
Growl obj = growl_pop(vm);
|
||||
push_call(vm, vm->quotation, vm->ip);
|
||||
GrowlQuotation *obj_quot = growl_unwrap_quotation(obj);
|
||||
if (obj_quot == NULL)
|
||||
vm_error(vm, "attempt to call non-callable");
|
||||
vm->quotation = obj_quot;
|
||||
vm->ip = obj_quot->data;
|
||||
break;
|
||||
}
|
||||
case GOP_RETURN:
|
||||
if (vm->csp != vm->cst) {
|
||||
GrowlFrame frame = pop_call(vm);
|
||||
vm->quotation = frame.quot;
|
||||
vm->ip = frame.ip;
|
||||
} else {
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vm_error(vm, "unknown opcode %d", opcode);
|
||||
}
|
||||
// clang-format off
|
||||
#define VM_START() for (;;) { uint8_t opcode; switch(opcode = *vm->ip++) {
|
||||
#define VM_END() }}
|
||||
#define VM_DEFAULT() default:
|
||||
#define VM_OP(op) case GOP_## op:
|
||||
#define VM_NEXT() break
|
||||
// clang-format on
|
||||
|
||||
VM_START()
|
||||
VM_OP(NOP) VM_NEXT();
|
||||
VM_OP(PUSH_NIL) {
|
||||
growl_push(vm, GROWL_NIL);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(PUSH_CONSTANT) {
|
||||
intptr_t idx = growl_sleb128_decode(&vm->ip);
|
||||
if (constants != NULL) {
|
||||
growl_push(vm, constants->data[idx]);
|
||||
} else {
|
||||
vm_error(vm, "constant index %" PRIdPTR " out of bounds", idx);
|
||||
}
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(DROP) {
|
||||
(void)growl_pop(vm);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(DUP) {
|
||||
growl_push(vm, growl_peek(vm, 0));
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(SWAP) {
|
||||
Growl b = growl_pop(vm);
|
||||
Growl a = growl_pop(vm);
|
||||
growl_push(vm, b);
|
||||
growl_push(vm, a);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(2DROP) {
|
||||
(void)growl_pop(vm);
|
||||
(void)growl_pop(vm);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(2DUP) {
|
||||
growl_push(vm, growl_peek(vm, 1));
|
||||
growl_push(vm, growl_peek(vm, 1));
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(2SWAP) {
|
||||
Growl d = growl_pop(vm);
|
||||
Growl c = growl_pop(vm);
|
||||
Growl b = growl_pop(vm);
|
||||
Growl a = growl_pop(vm);
|
||||
growl_push(vm, c);
|
||||
growl_push(vm, d);
|
||||
growl_push(vm, a);
|
||||
growl_push(vm, b);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(NIP) {
|
||||
Growl b = growl_pop(vm);
|
||||
(void)growl_pop(vm);
|
||||
growl_push(vm, b);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(OVER) {
|
||||
growl_push(vm, growl_peek(vm, 1));
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(BURY) {
|
||||
Growl c = growl_pop(vm);
|
||||
Growl b = growl_pop(vm);
|
||||
Growl a = growl_pop(vm);
|
||||
growl_push(vm, c);
|
||||
growl_push(vm, a);
|
||||
growl_push(vm, b);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(TO_RETAIN) {
|
||||
growl_rpush(vm, growl_pop(vm));
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(FROM_RETAIN) {
|
||||
growl_push(vm, growl_rpop(vm));
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(DIG) {
|
||||
Growl c = growl_pop(vm);
|
||||
Growl b = growl_pop(vm);
|
||||
Growl a = growl_pop(vm);
|
||||
growl_push(vm, b);
|
||||
growl_push(vm, c);
|
||||
growl_push(vm, a);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(CALL) { // TODO: compose and curry
|
||||
Growl obj = growl_pop(vm);
|
||||
callstack_push(vm, vm->quotation, vm->ip);
|
||||
dispatch(vm, obj);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(CALL_NEXT) {
|
||||
growl_push(vm, vm->next);
|
||||
vm->next = GROWL_NIL;
|
||||
__attribute__((__fallthrough__));
|
||||
}
|
||||
VM_OP(TAIL_CALL) {
|
||||
Growl obj = growl_pop(vm);
|
||||
dispatch(vm, obj);
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_OP(RETURN) {
|
||||
if (vm->csp != vm->cst) {
|
||||
GrowlFrame frame = callstack_pop(vm);
|
||||
vm->quotation = frame.quot;
|
||||
vm->ip = frame.ip;
|
||||
} else {
|
||||
goto done;
|
||||
}
|
||||
VM_NEXT();
|
||||
}
|
||||
VM_DEFAULT() { vm_error(vm, "unknown opcode %d", opcode); }
|
||||
VM_END()
|
||||
|
||||
done:
|
||||
growl_gc_reset(vm, gc_mark);
|
||||
|
|
|
|||
|
|
@ -21,19 +21,26 @@ typedef struct GrowlTuple GrowlTuple;
|
|||
typedef struct GrowlQuotation GrowlQuotation;
|
||||
typedef struct GrowlCompose GrowlCompose;
|
||||
typedef struct GrowlCurry GrowlCurry;
|
||||
typedef struct GrowlAlienType GrowlAlienType;
|
||||
typedef struct GrowlAlien GrowlAlien;
|
||||
typedef struct GrowlGCArena GrowlGCArena;
|
||||
typedef struct GrowlFrame GrowlFrame;
|
||||
typedef struct GrowlVM GrowlVM;
|
||||
|
||||
enum {
|
||||
GROWL_STRING,
|
||||
GROWL_LIST,
|
||||
GROWL_TUPLE,
|
||||
GROWL_QUOTATION,
|
||||
GROWL_COMPOSE,
|
||||
GROWL_CURRY,
|
||||
GROWL_TYPE_NIL,
|
||||
GROWL_TYPE_NUMBER,
|
||||
GROWL_TYPE_STRING,
|
||||
GROWL_TYPE_LIST,
|
||||
GROWL_TYPE_TUPLE,
|
||||
GROWL_TYPE_QUOTATION,
|
||||
GROWL_TYPE_COMPOSE,
|
||||
GROWL_TYPE_CURRY,
|
||||
GROWL_TYPE_ALIEN,
|
||||
};
|
||||
|
||||
uint32_t growl_type(Growl obj);
|
||||
|
||||
struct GrowlObjectHeader {
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
|
|
@ -82,6 +89,19 @@ GrowlCompose *growl_unwrap_compose(Growl obj);
|
|||
Growl growl_curry(GrowlVM *vm, Growl value, Growl callable);
|
||||
GrowlCurry *growl_unwrap_curry(Growl obj);
|
||||
|
||||
struct GrowlAlienType {
|
||||
const char *name;
|
||||
void (*finalizer)(void *);
|
||||
};
|
||||
|
||||
struct GrowlAlien {
|
||||
GrowlAlienType *type;
|
||||
void *data;
|
||||
};
|
||||
|
||||
Growl growl_make_alien(GrowlVM *vm, GrowlAlienType *type, void *data);
|
||||
GrowlAlien *growl_unwrap_alien(Growl obj, GrowlAlienType *type);
|
||||
|
||||
struct GrowlGCArena {
|
||||
uint8_t *start, *end;
|
||||
uint8_t *free;
|
||||
|
|
@ -103,6 +123,7 @@ void *growl_arena_alloc(GrowlGCArena *arena, size_t size, size_t align,
|
|||
struct GrowlFrame {
|
||||
GrowlQuotation *quot;
|
||||
uint8_t *ip;
|
||||
Growl next;
|
||||
};
|
||||
|
||||
struct GrowlVM {
|
||||
|
|
@ -116,6 +137,9 @@ struct GrowlVM {
|
|||
Growl rst[GROWL_STACK_SIZE], *rsp;
|
||||
GrowlFrame cst[GROWL_CALL_STACK_SIZE], *csp;
|
||||
|
||||
GrowlQuotation *compose_trampoline;
|
||||
Growl next;
|
||||
|
||||
Growl **roots;
|
||||
size_t root_count, root_capacity;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue