start work on new interpreter

This commit is contained in:
Lobo 2026-02-05 22:34:48 -03:00
parent 7efa99d064
commit 2ac2f85512
15 changed files with 780 additions and 30 deletions

View file

@ -10,4 +10,4 @@ indent_size = 2
[meson.build] [meson.build]
indent_style = space indent_style = space
indent_size = 2 indent_size = 4

View file

@ -1,38 +1,65 @@
project( project(
'growl', 'growl',
'c', 'c',
meson_version : '>= 1.3.0', 'cpp',
version : '0.1', meson_version: '>= 1.3.0',
default_options : ['buildtype=debugoptimized', 'c_std=gnu11', 'warning_level=3'], version: '0.1',
default_options: [
'buildtype=debugoptimized',
'c_std=gnu11',
'cpp_std=c++20',
'warning_level=3',
],
) )
libutf = subproject('libutf') libutf = subproject('libutf')
libutf_dep = libutf.get_variable('libutf_dep') libutf_dep = libutf.get_variable('libutf_dep')
sources = [ growl_sources = [
'src/arena.c', 'src/arena.c',
'src/chunk.c', 'src/chunk.c',
'src/compile.c', 'src/compile.c',
'src/debug.c', 'src/debug.c',
'src/dictionary.c', 'src/dictionary.c',
'src/file.c', 'src/file.c',
'src/lexer.c', 'src/lexer.c',
'src/object.c', 'src/object.c',
'src/gc.c', 'src/gc.c',
'src/parser.c', 'src/parser.c',
'src/primitive.c', 'src/primitive.c',
'src/print.c', 'src/print.c',
'src/stream.c', 'src/stream.c',
'src/string.c', 'src/string.c',
'src/userdata.c', 'src/userdata.c',
'src/vm.c', 'src/vm.c',
'src/vendor/linenoise.c', 'src/vendor/linenoise.c',
'src/vendor/yar.c', 'src/vendor/yar.c',
] ]
exe = executable( growl = executable(
'growl', 'growl',
'src/main.c', sources, 'src/main.c',
dependencies : [libutf_dep], growl_sources,
install : true, dependencies: [libutf_dep],
install: true,
)
growlnext_sources = [
'next/core/arena.c',
'next/core/callable.c',
'next/core/compiler.c',
'next/core/gc.c',
'next/core/list.c',
'next/core/sleb128.c',
'next/core/string.c',
'next/core/tuple.c',
'next/core/vm.c',
'next/main.c',
]
growlnext = executable(
'growlnext',
growlnext_sources,
include_directories: ['next/include'],
install: true,
) )

26
next/core/arena.c Normal file
View file

@ -0,0 +1,26 @@
#include <growl.h>
#include <stdlib.h>
#include <string.h>
void growl_arena_init(GrowlGCArena *arena, size_t size) {
arena->start = arena->free = malloc(size);
if (arena->start == NULL)
abort();
arena->end = arena->start + size;
}
void growl_arena_free(GrowlGCArena *arena) {
free(arena->start);
arena->start = arena->end = arena->free = NULL;
}
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;
if (available < 0 || count > available / size)
abort();
void *p = arena->start + padding;
arena->start += padding + count * size;
return memset(p, 0, count * size);
}

97
next/core/callable.c Normal file
View file

@ -0,0 +1,97 @@
#include <growl.h>
#include <string.h>
int growl_callable(Growl obj) {
if (obj == GROWL_NIL || GROWL_IMM(obj))
return 0;
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
switch (hdr->type) {
case GROWL_QUOTATION:
case GROWL_COMPOSE:
case GROWL_CURRY:
return 1;
default:
return 0;
}
}
Growl growl_make_quotation(GrowlVM *vm, const uint8_t *code, size_t code_size,
const Growl *constants, size_t constants_size) {
size_t constants_obj_size = sizeof(GrowlObjectHeader) + sizeof(GrowlTuple) +
constants_size * sizeof(Growl);
GrowlObjectHeader *constants_hdr =
growl_gc_alloc_tenured(vm, constants_obj_size);
constants_hdr->type = GROWL_TUPLE;
GrowlTuple *constants_tuple = (GrowlTuple *)(constants_hdr + 1);
constants_tuple->count = constants_size;
for (size_t i = 0; i < constants_size; ++i) {
constants_tuple->data[i] = constants[i];
}
size_t quotation_obj_size =
sizeof(GrowlObjectHeader) + sizeof(GrowlQuotation) + code_size;
GrowlObjectHeader *quotation_hdr =
growl_gc_alloc_tenured(vm, quotation_obj_size);
quotation_hdr->type = GROWL_QUOTATION;
GrowlQuotation *quotation = (GrowlQuotation *)(quotation_hdr + 1);
quotation->constants = GROWL_BOX(constants_hdr);
quotation->count = code_size;
memcpy(quotation->data, code, code_size);
return GROWL_BOX(quotation_hdr);
}
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)
return NULL;
return (GrowlQuotation *)(hdr + 1);
}
Growl growl_compose(GrowlVM *vm, Growl first, Growl second) {
if (!growl_callable(first))
return GROWL_NIL;
if (!growl_callable(second))
return GROWL_NIL;
size_t size = sizeof(GrowlObjectHeader) + sizeof(GrowlCompose);
GrowlObjectHeader *hdr = growl_gc_alloc(vm, size);
hdr->type = GROWL_COMPOSE;
GrowlCompose *comp = (GrowlCompose *)(hdr + 1);
comp->first = first;
comp->second = second;
return GROWL_BOX(hdr);
}
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)
return NULL;
return (GrowlCompose *)(hdr + 1);
}
Growl growl_curry(GrowlVM *vm, Growl value, Growl callable) {
if (!growl_callable(callable))
return GROWL_NIL;
size_t size = sizeof(GrowlObjectHeader) + sizeof(GrowlCurry);
GrowlObjectHeader *hdr = growl_gc_alloc(vm, size);
hdr->type = GROWL_CURRY;
GrowlCurry *comp = (GrowlCurry *)(hdr + 1);
comp->value = value;
comp->callable = callable;
return GROWL_BOX(hdr);
}
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)
return NULL;
return (GrowlCurry *)(hdr + 1);
}

2
next/core/compiler.c Normal file
View file

@ -0,0 +1,2 @@
#include <growl.h>

169
next/core/gc.c Normal file
View file

@ -0,0 +1,169 @@
//
// Created by lobo on 2/5/26.
//
#include <assert.h>
#include <growl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ALIGN(n) (((n) + 7) & ~7)
static int in_from(GrowlVM *vm, void *ptr) {
const uint8_t *x = ptr;
return (x >= vm->from.start && x < vm->from.end);
}
static Growl copy(GrowlVM *vm, GrowlObjectHeader *hdr) {
assert(in_from(vm, hdr));
assert(hdr->type != UINT32_MAX);
size_t size = ALIGN(hdr->size);
GrowlObjectHeader *new = (GrowlObjectHeader *)vm->to.free;
vm->to.free += size;
memcpy(new, hdr, size);
hdr->type = UINT32_MAX;
Growl *obj = (Growl *)(hdr + 1);
*obj = (Growl)(new);
return *obj;
}
static Growl forward(GrowlVM *vm, Growl obj) {
if (obj == 0)
return 0;
if (!in_from(vm, (void *)obj))
return obj;
GrowlObjectHeader *hdr = (GrowlObjectHeader *)obj;
if (hdr->type == UINT32_MAX) {
Growl *fwd = (Growl *)(hdr + 1);
return *fwd;
}
return copy(vm, hdr);
}
GrowlObjectHeader *growl_gc_alloc(GrowlVM *vm, size_t size) {
size = ALIGN(size);
if (vm->from.free + size > vm->from.end) {
growl_gc_collect(vm);
if (vm->from.free + size > vm->from.end) {
fprintf(stderr, "gc: oom (requested %" PRIdPTR " bytes)\n", size);
abort();
}
}
GrowlObjectHeader *hdr = (GrowlObjectHeader *)vm->from.free;
vm->from.free += size;
hdr->size = size;
return hdr;
}
GrowlObjectHeader *growl_gc_alloc_tenured(GrowlVM *vm, size_t size) {
size = ALIGN(size);
GrowlObjectHeader *hdr = growl_arena_alloc(&vm->arena, size, 8, 1);
hdr->size = size;
return hdr;
}
static void scan(GrowlVM *vm, GrowlObjectHeader *hdr) {
switch (hdr->type) {
case GROWL_STRING:
break;
case GROWL_LIST: {
GrowlList *list = (GrowlList *)(hdr + 1);
list->head = forward(vm, list->head);
list->tail = forward(vm, list->tail);
break;
}
case GROWL_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: {
GrowlQuotation *quot = (GrowlQuotation *)(hdr + 1);
quot->constants = forward(vm, quot->constants);
break;
}
case GROWL_COMPOSE: {
GrowlCompose *comp = (GrowlCompose *)(hdr + 1);
comp->first = forward(vm, comp->first);
comp->second = forward(vm, comp->second);
break;
}
case GROWL_CURRY: {
GrowlCurry *comp = (GrowlCurry *)(hdr + 1);
comp->value = forward(vm, comp->value);
comp->callable = forward(vm, comp->callable);
break;
}
case UINT32_MAX:
fprintf(stderr, "gc: fwd pointer during scan\n");
abort();
default:
fprintf(stderr, "gc: junk object type %" PRIu32 "\n", hdr->type);
abort();
}
}
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);
}
void growl_gc_collect(GrowlVM *vm) {
uint8_t *gc_scan = vm->to.free;
gc_print_stats(vm, "before GC");
for (size_t i = 0; i < GROWL_STACK_SIZE; ++i) {
vm->wst[i] = forward(vm, vm->wst[i]);
}
for (size_t i = 0; i < vm->root_count; ++i) {
*vm->roots[i] = forward(vm, *vm->roots[i]);
}
uint8_t *arena_scan = vm->arena.start;
while (arena_scan < vm->arena.free) {
GrowlObjectHeader *hdr = (GrowlObjectHeader *)arena_scan;
scan(vm, hdr);
arena_scan += ALIGN(hdr->size);
}
while (gc_scan < vm->to.free) {
GrowlObjectHeader *hdr = (GrowlObjectHeader *)gc_scan;
scan(vm, hdr);
gc_scan += ALIGN(hdr->size);
}
GrowlGCArena tmp = vm->from;
vm->from = vm->to;
vm->to = tmp;
vm->to.free = vm->to.start;
vm->scratch.free = vm->scratch.start;
gc_print_stats(vm, "after GC");
}
void growl_gc_root(GrowlVM *vm, Growl *ptr) {
if (vm->root_count >= vm->root_capacity) {
size_t cap = vm->root_capacity == 0 ? 16 : vm->root_capacity * 2;
Growl **data = realloc(vm->roots, cap * sizeof(Growl *));
if (!data) {
fprintf(stderr, "expanding roots array: oom\n");
abort();
}
vm->root_capacity = cap;
vm->roots = data;
}
vm->roots[vm->root_count++] = ptr;
}
size_t growl_gc_mark(GrowlVM *vm) { return vm->root_count; }
void growl_gc_reset(GrowlVM *vm, size_t mark) { vm->root_count = mark; }

2
next/core/list.c Normal file
View file

@ -0,0 +1,2 @@
#include <growl.h>

12
next/core/opcodes.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef GROWL_OPCODES_H
#define GROWL_OPCODES_H
enum {
GOP_NOP = 0,
GOP_PUSH_NIL,
GOP_PUSH_CONSTANT,
GOP_CALL,
GOP_RETURN,
};
#endif // GROWL_OPCODES_H

45
next/core/sleb128.c Normal file
View file

@ -0,0 +1,45 @@
//
// Created by lobo on 2/5/26.
//
#include "sleb128.h"
intptr_t growl_sleb128_decode(uint8_t **ptr) {
intptr_t result = 0;
intptr_t shift = 0;
uint8_t byte;
do {
byte = **ptr;
(*ptr)++;
result |= (intptr_t)(byte & 0x7F) << shift;
shift += 7;
} while (byte & 0x80);
if ((shift < 64) && (byte & 0x40)) {
result |= -(1LL << shift);
}
return result;
}
size_t growl_sleb128_peek(const uint8_t *ptr, intptr_t *out) {
intptr_t result = 0, shift = 0;
size_t bytes = 0;
uint8_t byte;
do {
byte = ptr[bytes];
bytes++;
result |= (intptr_t)(byte & 0x7f) << shift;
shift += 7;
} while (byte & 0x80);
if (shift < 64 && byte & 0x40) {
result |= -(1LL << shift);
}
if (out)
*out = result;
return bytes;
}

10
next/core/sleb128.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef GROWL_SLEB128_H
#define GROWL_SLEB128_H
#include <stdint.h>
#include <stddef.h>
intptr_t growl_sleb128_decode(uint8_t **ptr);
size_t growl_sleb128_peek(const uint8_t *ptr, intptr_t *out);
#endif // GROWL_SLEB128_H

33
next/core/string.c Normal file
View file

@ -0,0 +1,33 @@
#include <growl.h>
#include <string.h>
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;
GrowlString *str = (GrowlString *)(hdr + 1);
str->len = len;
memset(str->data, 0, len);
return GROWL_BOX(hdr);
}
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;
GrowlString *str = (GrowlString *)(hdr + 1);
str->len = len;
memcpy(str->data, cstr, len);
str->data[len] = 0;
return GROWL_BOX(hdr);
}
GrowlString *growl_unwrap_string(Growl obj) {
if (obj == 0 || GROWL_IMM(obj))
return NULL;
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
if (hdr->type != GROWL_STRING)
return NULL;
return (GrowlString *)(hdr + 1);
}

10
next/core/tuple.c Normal file
View file

@ -0,0 +1,10 @@
#include <growl.h>
GrowlTuple *growl_unwrap_tuple(Growl obj) {
if (obj == 0 || GROWL_IMM(obj))
return NULL;
GrowlObjectHeader *hdr = GROWL_UNBOX(obj);
if (hdr->type != GROWL_TUPLE)
return NULL;
return (GrowlTuple *)(hdr + 1);
}

164
next/core/vm.c Normal file
View file

@ -0,0 +1,164 @@
#include <growl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include "opcodes.h"
#include "sleb128.h"
#include <inttypes.h>
#include <stdio.h>
GrowlVM *growl_vm_init(void) {
GrowlVM *mem = malloc(sizeof(GrowlVM));
if (mem == NULL) {
abort();
}
growl_arena_init(&mem->from, GROWL_HEAP_SIZE);
growl_arena_init(&mem->to, GROWL_HEAP_SIZE);
growl_arena_init(&mem->arena, GROWL_ARENA_SIZE);
growl_arena_init(&mem->scratch, GROWL_SCRATCH_SIZE);
mem->sp = mem->wst;
mem->rsp = mem->rst;
mem->csp = mem->cst;
for (size_t i = 0; i < GROWL_STACK_SIZE; ++i) {
mem->wst[i] = 0;
mem->rst[i] = 0;
}
mem->roots = NULL;
mem->root_count = 0;
mem->root_capacity = 0;
return mem;
}
void growl_vm_free(GrowlVM *vm) {
growl_arena_free(&vm->from);
growl_arena_free(&vm->to);
growl_arena_free(&vm->arena);
growl_arena_free(&vm->scratch);
if (vm->roots != NULL)
free(vm->roots);
free(vm);
}
__attribute__((format(printf, 2, 3))) static noreturn void
vm_error(GrowlVM *vm, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
fprintf(stderr, "vm: ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
longjmp(vm->error, -1);
}
void growl_push(GrowlVM *vm, Growl obj) {
if (vm->sp >= vm->wst + GROWL_STACK_SIZE)
vm_error(vm, "work stack overflow");
*vm->sp++ = obj;
}
Growl growl_pop(GrowlVM *vm) {
if (vm->sp <= vm->wst)
vm_error(vm, "work stack underflow");
Growl obj = *--vm->sp;
*vm->sp = GROWL_NIL;
return obj;
}
void growl_rpush(GrowlVM *vm, Growl obj) {
if (vm->rsp >= vm->rst + GROWL_STACK_SIZE)
vm_error(vm, "work stack overflow");
*vm->rsp++ = obj;
}
Growl growl_rpop(GrowlVM *vm) {
if (vm->rsp <= vm->rst)
vm_error(vm, "work stack underflow");
Growl obj = *--vm->rsp;
*vm->rsp = GROWL_NIL;
return obj;
}
static void push_call(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) {
if (vm->csp <= vm->cst)
vm_error(vm, "call stack underflow");
return *--vm->csp;
}
int vm_doquot(GrowlVM *vm, GrowlQuotation *quot) {
size_t gc_mark = growl_gc_mark(vm);
int result = setjmp(vm->error);
if (result != 0) {
growl_gc_reset(vm, gc_mark);
return result;
}
GrowlTuple *constants = growl_unwrap_tuple(quot->constants);
if (constants != NULL) {
for (size_t i = 0; i < constants->count; ++i) {
growl_gc_root(vm, &constants->data[i]);
}
}
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);
}
}
done:
growl_gc_reset(vm, gc_mark);
return 0;
}

135
next/include/growl.h Normal file
View file

@ -0,0 +1,135 @@
#ifndef GROWL_H
#define GROWL_H
#include <setjmp.h>
#include <stddef.h>
#include <stdint.h>
typedef uintptr_t Growl;
#define GROWL_NIL ((Growl)(0))
#define GROWL_BOX(x) ((Growl)(x))
#define GROWL_UNBOX(x) ((GrowlObjectHeader *)(x))
#define GROWL_IMM(x) ((Growl)(x) & (Growl)1)
#define GROWL_NUM(x) (((Growl)((intptr_t)(x) << 1)) | (Growl)1)
#define GROWL_ORD(x) ((intptr_t)(x) >> 1)
typedef struct GrowlObjectHeader GrowlObjectHeader;
typedef struct GrowlString GrowlString;
typedef struct GrowlList GrowlList;
typedef struct GrowlTuple GrowlTuple;
typedef struct GrowlQuotation GrowlQuotation;
typedef struct GrowlCompose GrowlCompose;
typedef struct GrowlCurry GrowlCurry;
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,
};
struct GrowlObjectHeader {
size_t size;
uint32_t type;
};
struct GrowlString {
size_t len;
char data[];
};
Growl growl_make_string(GrowlVM *vm, size_t len);
Growl growl_wrap_string(GrowlVM *vm, const char *cstr);
GrowlString *growl_unwrap_string(Growl obj);
struct GrowlList {
Growl head, tail;
};
struct GrowlTuple {
size_t count;
Growl data[];
};
GrowlTuple *growl_unwrap_tuple(Growl obj);
struct GrowlQuotation {
size_t count;
Growl constants;
uint8_t data[];
};
struct GrowlCompose {
Growl first, second;
};
struct GrowlCurry {
Growl value, callable;
};
int growl_callable(Growl obj);
Growl growl_make_quotation(GrowlVM *vm, const uint8_t *code, size_t code_size,
const Growl *constants, size_t constants_size);
GrowlQuotation *growl_unwrap_quotation(Growl obj);
Growl growl_compose(GrowlVM *vm, Growl first, Growl second);
GrowlCompose *growl_unwrap_compose(Growl obj);
Growl growl_curry(GrowlVM *vm, Growl value, Growl callable);
GrowlCurry *growl_unwrap_curry(Growl obj);
struct GrowlGCArena {
uint8_t *start, *end;
uint8_t *free;
};
void growl_arena_init(GrowlGCArena *arena, size_t size);
void growl_arena_free(GrowlGCArena *arena);
void *growl_arena_alloc(GrowlGCArena *arena, size_t size, size_t align,
size_t count);
#define growl_arena_new(a, t, n) \
(t *)growl_arena_alloc(a, sizeof(t), _Alignof(t), n)
#define GROWL_STACK_SIZE 128
#define GROWL_CALL_STACK_SIZE 64
#define GROWL_HEAP_SIZE (4 * 1024 * 1024)
#define GROWL_ARENA_SIZE (2 * 1024 * 1024)
#define GROWL_SCRATCH_SIZE (1024 * 1024)
struct GrowlFrame {
GrowlQuotation *quot;
uint8_t *ip;
};
struct GrowlVM {
GrowlGCArena from, to;
GrowlGCArena arena;
GrowlGCArena scratch;
GrowlQuotation *quotation;
uint8_t *ip;
Growl wst[GROWL_STACK_SIZE], *sp;
Growl rst[GROWL_STACK_SIZE], *rsp;
GrowlFrame cst[GROWL_CALL_STACK_SIZE], *csp;
Growl **roots;
size_t root_count, root_capacity;
jmp_buf error;
};
GrowlVM *growl_vm_init(void);
void growl_vm_free(GrowlVM *vm);
GrowlObjectHeader *growl_gc_alloc(GrowlVM *vm, size_t size);
GrowlObjectHeader *growl_gc_alloc_tenured(GrowlVM *vm, size_t size);
void growl_gc_collect(GrowlVM *vm);
void growl_gc_root(GrowlVM *vm, Growl *ptr);
size_t growl_gc_mark(GrowlVM *vm);
void growl_gc_reset(GrowlVM *vm, size_t mark);
int vm_doquot(GrowlVM *vm, GrowlQuotation *quot);
#endif // GROWL_H

18
next/main.c Normal file
View file

@ -0,0 +1,18 @@
#include "core/opcodes.h"
#include <growl.h>
static uint8_t code[] = {
GOP_PUSH_NIL,
GOP_RETURN,
};
int main(void) {
GrowlVM *vm = growl_vm_init();
Growl quot_obj = growl_make_quotation(vm, code, sizeof(code), NULL, 0);
GrowlQuotation *quot = (GrowlQuotation *)(GROWL_UNBOX(quot_obj) + 1);
vm_doquot(vm, quot);
growl_gc_collect(vm);
growl_vm_free(vm);
}