move to meson for build system

This commit is contained in:
Lobo 2026-01-19 10:25:56 -03:00
parent fdd1ee61b5
commit 9616fb616e
28 changed files with 123 additions and 24 deletions

29
src/chunk.c Normal file
View file

@ -0,0 +1,29 @@
#include "chunk.h"
#include "vendor/yar.h"
V chunk_emit_byte(Bc *chunk, U8 byte) { *yar_append(chunk) = byte; }
V chunk_emit_sleb128(Bc *chunk, I num) {
I more = 1;
while (more) {
U8 byte = num & 0x7f;
num >>= 7;
if ((num == 0 && !(byte & 0x40)) || (num == -1 && (byte & 0x40))) {
more = 0;
} else {
byte |= 0x80;
}
chunk_emit_byte(chunk, byte);
}
}
I chunk_add_constant(Bc *chunk, O value) {
I mark = chunk->constants.count;
*yar_append(&chunk->constants) = value;
return mark;
}
V chunk_free(Bc *chunk) {
yar_free(&chunk->constants);
yar_free(chunk);
}

22
src/chunk.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef CHUNK_H
#define CHUNK_H
#include "common.h"
#include "object.h"
/** Bytecode chunk */
typedef struct Bc {
U8 *items;
Z count, capacity;
struct {
O *items;
Z count, capacity;
} constants;
} Bc;
V chunk_emit_byte(Bc *, U8);
V chunk_emit_sleb128(Bc *, I);
I chunk_add_constant(Bc *, O);
V chunk_free(Bc *);
#endif

15
src/common.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef COMMON_H
#define COMMON_H
#include <stdint.h>
#include <stddef.h>
typedef void V;
typedef intptr_t I;
typedef uintptr_t U;
typedef double F;
typedef size_t Z;
typedef uint8_t U8;
typedef uint32_t U32;
#endif

6
src/compile.c Normal file
View file

@ -0,0 +1,6 @@
#include "compile.h"
I compile_program(mpc_ast_t *ast) {
}

4
src/compile.h Normal file
View file

@ -0,0 +1,4 @@
#include "common.h"
#include "vendor/mpc.h"
I compile_program(mpc_ast_t *);

134
src/gc.c Normal file
View file

@ -0,0 +1,134 @@
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include "chunk.h"
#include "gc.h"
#include "object.h"
#include "vendor/yar.h"
#define ALIGN(n) (((n) + 7) & ~7)
static inline int infrom(Gc *gc, V *ptr) {
const U8 *x = (const U8 *)ptr;
return (x >= gc->from.start && x < gc->from.end);
}
V gc_addroot(Gc *gc, O *ptr) { *yar_append(&gc->roots) = ptr; }
I gc_mark(Gc *gc) { return gc->roots.count; }
V gc_reset(Gc *gc, I mark) { gc->roots.count = mark; }
static O copy(Gc *gc, Hd *hdr) {
assert(infrom(gc, hdr));
assert(hdr->type != OBJ_FWD);
Z sz = ALIGN(hdr->size);
Hd *new = (Hd *)gc->to.free;
gc->to.free += sz;
memcpy(new, hdr, sz);
hdr->type = OBJ_FWD;
O *obj = (O *)(hdr + 1);
*obj = BOX(new);
return *obj;
}
static O forward(Gc *gc, O obj) {
if (obj == 0)
return 0;
if (IMM(obj))
return obj;
if (!infrom(gc, (V *)obj))
return obj;
Hd *hdr = UNBOX(obj);
if (hdr->type == OBJ_FWD) {
O *o = (O *)(hdr + 1);
return *o;
} else {
return copy(gc, hdr);
}
}
#if GC_DEBUG
static V printstats(Gc *gc, const char *label) {
Z used = (Z)(gc->from.free - gc->from.start);
fprintf(stderr, "[%s] used=%zu/%zu bytes (%.1f%%)\n", label, used,
(Z)HEAP_BYTES, (F)used / (F)HEAP_BYTES * 100.0);
}
#endif
V gc_collect(Gc *gc) {
uint8_t *scan = gc->to.free;
#if GC_DEBUG
printstats(gc, "before GC");
#endif
for (Z i = 0; i < gc->roots.count; i++) {
O *o = gc->roots.items[i];
*o = forward(gc, *o);
}
while (scan < gc->to.free) {
if (scan >= gc->to.end) {
fprintf(stderr, "fatal GC error: out of memory\n");
abort();
}
Hd *hdr = (Hd *)scan;
switch (hdr->type) {
// TODO: the rest of the owl
case OBJ_QUOT: {
Bc *chunk = (Bc *)(hdr + 1);
for (Z i = 0; i < chunk->constants.count; i++)
chunk->constants.items[i] = forward(gc, chunk->constants.items[i]);
break;
}
case OBJ_FWD:
fprintf(stderr, "fatal GC error: forwarding pointer in to-space\n");
abort();
default:
fprintf(stderr, "GC warning: junk object type %" PRId32 "\n", hdr->type);
}
scan += ALIGN(hdr->size);
}
Gs tmp = gc->from;
gc->from = gc->to;
gc->to = tmp;
gc->to.free = gc->to.start;
#if GC_DEBUG
printstats(gc, "after GC");
#endif
}
void gc_init(Gc *gc) {
gc->from.start = malloc(HEAP_BYTES);
if (!gc->from.start)
goto fatal;
gc->from.end = gc->from.start + HEAP_BYTES;
gc->from.free = gc->from.start;
gc->to.start = malloc(HEAP_BYTES);
if (!gc->to.start)
goto fatal;
gc->to.end = gc->to.start + HEAP_BYTES;
gc->to.free = gc->to.start;
gc->roots.capacity = 0;
gc->roots.count = 0;
gc->roots.items = NULL;
return;
fatal:
fprintf(stderr, "failed to allocate heap space\n");
abort();
}
void gc_deinit(Gc *gc) {
gc_collect(gc);
free(gc->from.start);
free(gc->to.start);
yar_free(&gc->roots);
}

31
src/gc.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef GC_H
#define GC_H
#include "common.h"
#include "object.h"
#define GC_DEBUG 1
#define HEAP_BYTES (4 * 1024 * 1024)
typedef struct Gs {
U8 *start, *end;
U8 *free;
} Gs;
typedef struct Gc {
Gs from, to;
struct {
O **items;
Z count, capacity;
} roots;
} Gc;
V gc_addroot(Gc *, O *);
I gc_mark(Gc *);
V gc_reset(Gc *, I);
V gc_collect(Gc *);
Hd *gc_alloc(Gc *, Z);
V gc_init(Gc *);
V gc_deinit(Gc *);
#endif

89
src/main.c Normal file
View file

@ -0,0 +1,89 @@
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "chunk.h"
#include "gc.h"
#include "parser.h"
#include "vendor/mpc.h"
#include "vm.h"
void dump(const V *data, Z size) {
char ascii[17];
Z i, j;
ascii[16] = '\0';
for (i = 0; i < size; ++i) {
printf("%02X ", ((unsigned char *)data)[i]);
if (((unsigned char *)data)[i] >= ' ' &&
((unsigned char *)data)[i] <= '~') {
ascii[i % 16] = ((unsigned char *)data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i + 1) % 8 == 0 || i + 1 == size) {
printf(" ");
if ((i + 1) % 16 == 0) {
printf("| %s \n", ascii);
} else if (i + 1 == size) {
ascii[(i + 1) % 16] = '\0';
if ((i + 1) % 16 <= 8) {
printf(" ");
}
for (j = (i + 1) % 16; j < 16; ++j) {
printf(" ");
}
printf("| %s \n", ascii);
}
}
}
}
I repl(void) {
Bc chunk = {0};
Vm vm = {0};
vm_init(&vm);
I idx = chunk_add_constant(&chunk, NUM(10));
chunk_emit_byte(&chunk, OP_CONST);
chunk_emit_sleb128(&chunk, idx);
chunk_emit_byte(&chunk, OP_RETURN);
vm_run(&vm, &chunk, 0);
return 0;
}
I loadfile(const char *fname) {
Gc gc = {0};
gc_init(&gc);
mpc_result_t res;
if (!mpc_parse_contents(fname, Program, &res)) {
mpc_err_print_to(res.error, stderr);
mpc_err_delete(res.error);
gc_deinit(&gc);
return 1;
}
mpc_ast_print(res.output);
mpc_ast_delete(res.output);
gc_deinit(&gc);
return 0;
}
int main(int argc, const char *argv[]) {
parser_init();
atexit(parser_deinit);
switch (argc) {
case 1:
return repl();
case 2:
return loadfile(argv[1]);
default:
fprintf(stderr, "usage: growl [file]\n");
return 64;
}
}

10
src/object.c Normal file
View file

@ -0,0 +1,10 @@
#include "object.h"
I type(O o) {
if (o == NIL)
return TYPE_NIL;
if (IMM(o))
return TYPE_NUM;
Hd *h = UNBOX(o);
return h->type;
}

33
src/object.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef OBJECT_H
#define OBJECT_H
#include "common.h"
#define NIL ((O)0)
#define BOX(x) ((O)(x))
#define UNBOX(x) ((Hd *)(x))
#define IMM(x) ((O)(x) & (O)1)
#define NUM(x) (((O)((intptr_t)(x) << 1)) | (O)1)
#define ORD(x) ((O)(x) >> 1)
enum {
OBJ_FWD = 2,
OBJ_QUOT,
};
enum {
TYPE_NIL = 0,
TYPE_NUM = 1,
TYPE_FWD = OBJ_FWD,
};
typedef uintptr_t O;
/** Object header */
typedef struct Hd {
U32 size, type;
} Hd;
I type(O);
#endif

51
src/parser.c Normal file
View file

@ -0,0 +1,51 @@
#include "parser.h"
#include "vendor/mpc.h"
mpc_parser_t *Pragma, *Comment, *Expr, *Number, *String, *Word, *Definition,
*Command, *List, *Table, *Quotation, *Program;
V parser_init(V) {
Pragma = mpc_new("pragma");
Comment = mpc_new("comment");
Expr = mpc_new("expr");
Number = mpc_new("number");
String = mpc_new("string");
Word = mpc_new("word");
Definition = mpc_new("def");
Command = mpc_new("command");
List = mpc_new("list");
Table = mpc_new("table");
Quotation = mpc_new("quotation");
Program = mpc_new("program");
mpc_err_t *err = mpca_lang(
MPCA_LANG_DEFAULT,
" pragma : '#' <word> ('(' <expr>* ')')? ; "
" comment : /\\\\[^\\n]*/ ; "
" expr : ( <pragma> | <def> | <command> | <quotation> "
" | <number> | <list> | <table> | <string> "
" | <word> | <comment> ) ; "
" number : ( /0x[0-9A-Fa-f]+/ | /-?[0-9]+/ ) ; "
" string : /\"(\\\\.|[^\"])*\"/ ; "
" word : /[a-zA-Z0-9_!.,@#$%^&*_+\\-=><|\\/]+/ ; "
" def : ':' <word> <expr>* ';' ; "
" command : <word> ':' <expr>+ ';' ; "
" list : '(' <expr>* ')' ; "
" table : '{' <expr>* '}' ; "
" quotation : '[' <expr>* ']' ; "
" program : /^/ <expr>* /$/ ; ",
Pragma, Comment, Expr, Number, String, Word, Definition, Command, List,
Table, Quotation, Program, NULL);
// crash if i do a woopsie
if (err != NULL) {
mpc_err_print(err);
mpc_err_delete(err);
abort();
}
}
V parser_deinit(V) {
mpc_cleanup(12, Pragma, Comment, Expr, Number, String, Word, Definition,
Command, List, Table, Quotation, Program);
}

12
src/parser.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef PARSER_H
#define PARSER_H
#include "common.h"
#include "vendor/mpc.h"
V parser_init(V);
V parser_deinit(V);
extern mpc_parser_t *Program;
#endif

20
src/print.c Normal file
View file

@ -0,0 +1,20 @@
#include <inttypes.h>
#include <stdio.h>
#include "object.h"
#include "print.h"
V print(O o) {
if (o == NIL) {
printf("nil");
} else if (IMM(o)) {
printf("%" PRIdPTR, ORD(o));
} else {
printf("<obj type=%ld ptr=%p>", type(o), (void *)o);
}
}
V println(O o) {
print(o);
putchar('\n');
}

10
src/print.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef PRINT_H
#define PRINT_H
#include "common.h"
#include "object.h"
V print(O);
V println(O);
#endif

4128
src/vendor/mpc.c vendored Normal file

File diff suppressed because it is too large Load diff

391
src/vendor/mpc.h vendored Normal file
View file

@ -0,0 +1,391 @@
/*
** mpc - Micro Parser Combinator library for C
**
** https://github.com/orangeduck/mpc
**
** Daniel Holden - contact@daniel-holden.com
** Licensed under BSD3
*/
#ifndef mpc_h
#define mpc_h
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <ctype.h>
/*
** State Type
*/
typedef struct {
long pos;
long row;
long col;
int term;
} mpc_state_t;
/*
** Error Type
*/
typedef struct {
mpc_state_t state;
int expected_num;
char *filename;
char *failure;
char **expected;
char received;
} mpc_err_t;
void mpc_err_delete(mpc_err_t *e);
char *mpc_err_string(mpc_err_t *e);
void mpc_err_print(mpc_err_t *e);
void mpc_err_print_to(mpc_err_t *e, FILE *f);
/*
** Parsing
*/
typedef void mpc_val_t;
typedef union {
mpc_err_t *error;
mpc_val_t *output;
} mpc_result_t;
struct mpc_parser_t;
typedef struct mpc_parser_t mpc_parser_t;
int mpc_parse(const char *filename, const char *string, mpc_parser_t *p, mpc_result_t *r);
int mpc_nparse(const char *filename, const char *string, size_t length, mpc_parser_t *p, mpc_result_t *r);
int mpc_parse_file(const char *filename, FILE *file, mpc_parser_t *p, mpc_result_t *r);
int mpc_parse_pipe(const char *filename, FILE *pipe, mpc_parser_t *p, mpc_result_t *r);
int mpc_parse_contents(const char *filename, mpc_parser_t *p, mpc_result_t *r);
/*
** Function Types
*/
typedef void(*mpc_dtor_t)(mpc_val_t*);
typedef mpc_val_t*(*mpc_ctor_t)(void);
typedef mpc_val_t*(*mpc_apply_t)(mpc_val_t*);
typedef mpc_val_t*(*mpc_apply_to_t)(mpc_val_t*,void*);
typedef mpc_val_t*(*mpc_fold_t)(int,mpc_val_t**);
typedef int(*mpc_check_t)(mpc_val_t**);
typedef int(*mpc_check_with_t)(mpc_val_t**,void*);
/*
** Building a Parser
*/
mpc_parser_t *mpc_new(const char *name);
mpc_parser_t *mpc_copy(mpc_parser_t *a);
mpc_parser_t *mpc_define(mpc_parser_t *p, mpc_parser_t *a);
mpc_parser_t *mpc_undefine(mpc_parser_t *p);
void mpc_delete(mpc_parser_t *p);
void mpc_cleanup(int n, ...);
/*
** Basic Parsers
*/
mpc_parser_t *mpc_any(void);
mpc_parser_t *mpc_char(char c);
mpc_parser_t *mpc_range(char s, char e);
mpc_parser_t *mpc_oneof(const char *s);
mpc_parser_t *mpc_noneof(const char *s);
mpc_parser_t *mpc_satisfy(int(*f)(char));
mpc_parser_t *mpc_string(const char *s);
/*
** Other Parsers
*/
mpc_parser_t *mpc_pass(void);
mpc_parser_t *mpc_fail(const char *m);
mpc_parser_t *mpc_failf(const char *fmt, ...);
mpc_parser_t *mpc_lift(mpc_ctor_t f);
mpc_parser_t *mpc_lift_val(mpc_val_t *x);
mpc_parser_t *mpc_anchor(int(*f)(char,char));
mpc_parser_t *mpc_state(void);
/*
** Combinator Parsers
*/
mpc_parser_t *mpc_expect(mpc_parser_t *a, const char *e);
mpc_parser_t *mpc_expectf(mpc_parser_t *a, const char *fmt, ...);
mpc_parser_t *mpc_apply(mpc_parser_t *a, mpc_apply_t f);
mpc_parser_t *mpc_apply_to(mpc_parser_t *a, mpc_apply_to_t f, void *x);
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *e);
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *e);
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *fmt, ...);
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *fmt, ...);
mpc_parser_t *mpc_not(mpc_parser_t *a, mpc_dtor_t da);
mpc_parser_t *mpc_not_lift(mpc_parser_t *a, mpc_dtor_t da, mpc_ctor_t lf);
mpc_parser_t *mpc_maybe(mpc_parser_t *a);
mpc_parser_t *mpc_maybe_lift(mpc_parser_t *a, mpc_ctor_t lf);
mpc_parser_t *mpc_many(mpc_fold_t f, mpc_parser_t *a);
mpc_parser_t *mpc_many1(mpc_fold_t f, mpc_parser_t *a);
mpc_parser_t *mpc_count(int n, mpc_fold_t f, mpc_parser_t *a, mpc_dtor_t da);
mpc_parser_t *mpc_or(int n, ...);
mpc_parser_t *mpc_and(int n, mpc_fold_t f, ...);
mpc_parser_t *mpc_predictive(mpc_parser_t *a);
/*
** Common Parsers
*/
mpc_parser_t *mpc_eoi(void);
mpc_parser_t *mpc_soi(void);
mpc_parser_t *mpc_boundary(void);
mpc_parser_t *mpc_boundary_newline(void);
mpc_parser_t *mpc_whitespace(void);
mpc_parser_t *mpc_whitespaces(void);
mpc_parser_t *mpc_blank(void);
mpc_parser_t *mpc_newline(void);
mpc_parser_t *mpc_tab(void);
mpc_parser_t *mpc_escape(void);
mpc_parser_t *mpc_digit(void);
mpc_parser_t *mpc_hexdigit(void);
mpc_parser_t *mpc_octdigit(void);
mpc_parser_t *mpc_digits(void);
mpc_parser_t *mpc_hexdigits(void);
mpc_parser_t *mpc_octdigits(void);
mpc_parser_t *mpc_lower(void);
mpc_parser_t *mpc_upper(void);
mpc_parser_t *mpc_alpha(void);
mpc_parser_t *mpc_underscore(void);
mpc_parser_t *mpc_alphanum(void);
mpc_parser_t *mpc_int(void);
mpc_parser_t *mpc_hex(void);
mpc_parser_t *mpc_oct(void);
mpc_parser_t *mpc_number(void);
mpc_parser_t *mpc_real(void);
mpc_parser_t *mpc_float(void);
mpc_parser_t *mpc_char_lit(void);
mpc_parser_t *mpc_string_lit(void);
mpc_parser_t *mpc_regex_lit(void);
mpc_parser_t *mpc_ident(void);
/*
** Useful Parsers
*/
mpc_parser_t *mpc_startwith(mpc_parser_t *a);
mpc_parser_t *mpc_endwith(mpc_parser_t *a, mpc_dtor_t da);
mpc_parser_t *mpc_whole(mpc_parser_t *a, mpc_dtor_t da);
mpc_parser_t *mpc_stripl(mpc_parser_t *a);
mpc_parser_t *mpc_stripr(mpc_parser_t *a);
mpc_parser_t *mpc_strip(mpc_parser_t *a);
mpc_parser_t *mpc_tok(mpc_parser_t *a);
mpc_parser_t *mpc_sym(const char *s);
mpc_parser_t *mpc_total(mpc_parser_t *a, mpc_dtor_t da);
mpc_parser_t *mpc_between(mpc_parser_t *a, mpc_dtor_t ad, const char *o, const char *c);
mpc_parser_t *mpc_parens(mpc_parser_t *a, mpc_dtor_t ad);
mpc_parser_t *mpc_braces(mpc_parser_t *a, mpc_dtor_t ad);
mpc_parser_t *mpc_brackets(mpc_parser_t *a, mpc_dtor_t ad);
mpc_parser_t *mpc_squares(mpc_parser_t *a, mpc_dtor_t ad);
mpc_parser_t *mpc_tok_between(mpc_parser_t *a, mpc_dtor_t ad, const char *o, const char *c);
mpc_parser_t *mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad);
mpc_parser_t *mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad);
mpc_parser_t *mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad);
mpc_parser_t *mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad);
mpc_parser_t *mpc_sepby1(mpc_fold_t f, mpc_parser_t *sep, mpc_parser_t *a);
/*
** Common Function Parameters
*/
void mpcf_dtor_null(mpc_val_t *x);
mpc_val_t *mpcf_ctor_null(void);
mpc_val_t *mpcf_ctor_str(void);
mpc_val_t *mpcf_free(mpc_val_t *x);
mpc_val_t *mpcf_int(mpc_val_t *x);
mpc_val_t *mpcf_hex(mpc_val_t *x);
mpc_val_t *mpcf_oct(mpc_val_t *x);
mpc_val_t *mpcf_float(mpc_val_t *x);
mpc_val_t *mpcf_strtriml(mpc_val_t *x);
mpc_val_t *mpcf_strtrimr(mpc_val_t *x);
mpc_val_t *mpcf_strtrim(mpc_val_t *x);
mpc_val_t *mpcf_escape(mpc_val_t *x);
mpc_val_t *mpcf_escape_regex(mpc_val_t *x);
mpc_val_t *mpcf_escape_string_raw(mpc_val_t *x);
mpc_val_t *mpcf_escape_char_raw(mpc_val_t *x);
mpc_val_t *mpcf_unescape(mpc_val_t *x);
mpc_val_t *mpcf_unescape_regex(mpc_val_t *x);
mpc_val_t *mpcf_unescape_string_raw(mpc_val_t *x);
mpc_val_t *mpcf_unescape_char_raw(mpc_val_t *x);
mpc_val_t *mpcf_null(int n, mpc_val_t** xs);
mpc_val_t *mpcf_fst(int n, mpc_val_t** xs);
mpc_val_t *mpcf_snd(int n, mpc_val_t** xs);
mpc_val_t *mpcf_trd(int n, mpc_val_t** xs);
mpc_val_t *mpcf_fst_free(int n, mpc_val_t** xs);
mpc_val_t *mpcf_snd_free(int n, mpc_val_t** xs);
mpc_val_t *mpcf_trd_free(int n, mpc_val_t** xs);
mpc_val_t *mpcf_all_free(int n, mpc_val_t** xs);
mpc_val_t *mpcf_freefold(int n, mpc_val_t** xs);
mpc_val_t *mpcf_strfold(int n, mpc_val_t** xs);
/*
** Regular Expression Parsers
*/
enum {
MPC_RE_DEFAULT = 0,
MPC_RE_M = 1,
MPC_RE_S = 2,
MPC_RE_MULTILINE = 1,
MPC_RE_DOTALL = 2
};
mpc_parser_t *mpc_re(const char *re);
mpc_parser_t *mpc_re_mode(const char *re, int mode);
/*
** AST
*/
typedef struct mpc_ast_t {
char *tag;
char *contents;
mpc_state_t state;
int children_num;
struct mpc_ast_t** children;
} mpc_ast_t;
mpc_ast_t *mpc_ast_new(const char *tag, const char *contents);
mpc_ast_t *mpc_ast_build(int n, const char *tag, ...);
mpc_ast_t *mpc_ast_add_root(mpc_ast_t *a);
mpc_ast_t *mpc_ast_add_child(mpc_ast_t *r, mpc_ast_t *a);
mpc_ast_t *mpc_ast_add_tag(mpc_ast_t *a, const char *t);
mpc_ast_t *mpc_ast_add_root_tag(mpc_ast_t *a, const char *t);
mpc_ast_t *mpc_ast_tag(mpc_ast_t *a, const char *t);
mpc_ast_t *mpc_ast_state(mpc_ast_t *a, mpc_state_t s);
void mpc_ast_delete(mpc_ast_t *a);
void mpc_ast_print(mpc_ast_t *a);
void mpc_ast_print_to(mpc_ast_t *a, FILE *fp);
int mpc_ast_get_index(mpc_ast_t *ast, const char *tag);
int mpc_ast_get_index_lb(mpc_ast_t *ast, const char *tag, int lb);
mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, const char *tag);
mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb);
typedef enum {
mpc_ast_trav_order_pre,
mpc_ast_trav_order_post
} mpc_ast_trav_order_t;
typedef struct mpc_ast_trav_t {
mpc_ast_t *curr_node;
struct mpc_ast_trav_t *parent;
int curr_child;
mpc_ast_trav_order_t order;
} mpc_ast_trav_t;
mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast,
mpc_ast_trav_order_t order);
mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav);
void mpc_ast_traverse_free(mpc_ast_trav_t **trav);
/*
** Warning: This function currently doesn't test for equality of the `state` member!
*/
int mpc_ast_eq(mpc_ast_t *a, mpc_ast_t *b);
mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **as);
mpc_val_t *mpcf_str_ast(mpc_val_t *c);
mpc_val_t *mpcf_state_ast(int n, mpc_val_t **xs);
mpc_parser_t *mpca_tag(mpc_parser_t *a, const char *t);
mpc_parser_t *mpca_add_tag(mpc_parser_t *a, const char *t);
mpc_parser_t *mpca_root(mpc_parser_t *a);
mpc_parser_t *mpca_state(mpc_parser_t *a);
mpc_parser_t *mpca_total(mpc_parser_t *a);
mpc_parser_t *mpca_not(mpc_parser_t *a);
mpc_parser_t *mpca_maybe(mpc_parser_t *a);
mpc_parser_t *mpca_many(mpc_parser_t *a);
mpc_parser_t *mpca_many1(mpc_parser_t *a);
mpc_parser_t *mpca_count(int n, mpc_parser_t *a);
mpc_parser_t *mpca_or(int n, ...);
mpc_parser_t *mpca_and(int n, ...);
enum {
MPCA_LANG_DEFAULT = 0,
MPCA_LANG_PREDICTIVE = 1,
MPCA_LANG_WHITESPACE_SENSITIVE = 2
};
mpc_parser_t *mpca_grammar(int flags, const char *grammar, ...);
mpc_err_t *mpca_lang(int flags, const char *language, ...);
mpc_err_t *mpca_lang_file(int flags, FILE *f, ...);
mpc_err_t *mpca_lang_pipe(int flags, FILE *f, ...);
mpc_err_t *mpca_lang_contents(int flags, const char *filename, ...);
/*
** Misc
*/
void mpc_print(mpc_parser_t *p);
void mpc_optimise(mpc_parser_t *p);
void mpc_stats(mpc_parser_t *p);
int mpc_test_pass(mpc_parser_t *p, const char *s, const void *d,
int(*tester)(const void*, const void*),
mpc_dtor_t destructor,
void(*printer)(const void*));
int mpc_test_fail(mpc_parser_t *p, const char *s, const void *d,
int(*tester)(const void*, const void*),
mpc_dtor_t destructor,
void(*printer)(const void*));
#ifdef __cplusplus
}
#endif
#endif

2
src/vendor/yar.c vendored Normal file
View file

@ -0,0 +1,2 @@
#define YAR_IMPLEMENTATION
#include "yar.h"

229
src/vendor/yar.h vendored Normal file
View file

@ -0,0 +1,229 @@
/* yar - dynamic arrays in C - public domain Nicholas Rixson 2025
*
* https://github.com/segcore/yar
*
* Licence: see end of file
Sample usage:
#define YAR_IMPLEMENTATION
#include "yar.h"
int main() {
// struct { double *items; size_t count; size_t capacity; } numbers = {0};
yar(double) numbers = {0};
*yar_append(&numbers) = 3.14159;
*yar_append(&numbers) = 2.71828;
*yar_append(&numbers) = 1.61803;
for(size_t i = 0; i < numbers.count; i++) {
printf("%f\n", numbers.items[i]);
}
yar_free(&numbers);
}
*/
#ifndef YAR_H
#define YAR_H
#include <stddef.h> // size_t
#include <string.h> // strlen
/*
* yar(type) - Declare a new basic dynamic array
*
* yar_append(array) - Add a new item at the end of the array, and return a pointer to it
*
* yar_reserve(array, extra) - Reserve space for `extra` count of items
*
* yar_append_many(array, data, num) - Append a copy of existing data
*
* yar_append_cstr(array, data) - Append a C string (nul-terminated char array)
*
* yar_insert(array, index, num) - Insert items somewhere within the array. Moves items to higher indexes as required. Returns &array[index]
*
* yar_remove(array, index, num) - Remove items from somewhere within the array. Moves items to lower indexes as required.
*
* yar_reset(array) - Reset the count of elements to 0, to re-use the memory. Does not free the memory.
*
* yar_init(array) - Set items, count, and capacity to 0. Can usually be avoided with <declaration> = {0};
*
* yar_free(array) - Free items memory, and set the items, count, and capacity to 0.
*/
#define yar(type) struct { type *items; size_t count; size_t capacity; }
#define yar_append(array) ((_yar_append((void**)&(array)->items, &(array)->count, &(array)->capacity, sizeof((array)->items[0])) ? \
&(array)->items[(array)->count - 1] : NULL))
#define yar_reserve(array, extra) ((_yar_reserve((void**)&(array)->items, &(array)->count, &(array)->capacity, sizeof((array)->items[0]), (extra)) ? \
&(array)->items[(array)->count] : NULL))
#define yar_append_many(array, data, num) ((_yar_append_many((void**)&(array)->items, &(array)->count, &(array)->capacity, sizeof((array)->items[0]), 1 ? (data) : ((array)->items), (num)) ))
#define yar_append_cstr(array, data) yar_append_many(array, data, strlen(data))
#define yar_insert(array, index, num) ((_yar_insert((void**)&(array)->items, &(array)->count, &(array)->capacity, sizeof((array)->items[0]), index, num) ))
#define yar_remove(array, index, num) ((_yar_remove((void**)&(array)->items, &(array)->count, sizeof((array)->items[0]), index, num) ))
#define yar_reset(array) (((array)->count = 0))
#define yar_init(array) ((array)->items = NULL, (array)->count = 0, (array)->capacity = 0)
#define yar_free(array) ((_yar_free((array)->items)), (array)->items = NULL, (array)->count = 0, (array)->capacity = 0)
#ifndef YARAPI
#define YARAPI // nothing; overridable if needed.
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Implementation functions
YARAPI void* _yar_append(void** items_pointer, size_t* count, size_t* capacity, size_t item_size);
YARAPI void* _yar_append_many(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, void* data, size_t extra);
YARAPI void* _yar_reserve(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, size_t extra);
YARAPI void* _yar_insert(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, size_t index, size_t extra);
YARAPI void* _yar_remove(void** items_pointer, size_t* count, size_t item_size, size_t index, size_t remove);
YARAPI void* _yar_realloc(void* p, size_t new_size);
YARAPI void _yar_free(void* p);
#ifdef __cplusplus
}
#endif
#endif // YAR_H
#if defined(YAR_IMPLEMENTATION)
#ifndef YAR_MIN_CAP
#define YAR_MIN_CAP 16
#endif
#ifndef YAR_REALLOC
#define YAR_REALLOC realloc
#endif
#ifndef YAR_FREE
#define YAR_FREE free
#endif
#include <string.h> // mem* functions
YARAPI void* _yar_append(void** items_pointer, size_t* count, size_t* capacity, size_t item_size)
{
void* result = _yar_reserve(items_pointer, count, capacity, item_size, 1);
if (result != NULL) *count += 1;
return result;
}
YARAPI void* _yar_append_many(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, void* data, size_t extra)
{
void* result = _yar_reserve(items_pointer, count, capacity, item_size, extra);
if (result != NULL) {
memcpy(result, data, item_size * extra);
*count += extra;
}
return result;
}
YARAPI void* _yar_reserve(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, size_t extra)
{
char* items = *items_pointer;
size_t newcount = *count + extra;
if (newcount > *capacity) {
size_t newcap = (*capacity < YAR_MIN_CAP) ? YAR_MIN_CAP : *capacity * 8 / 5;
if (newcap < newcount) newcap = newcount;
void* next = _yar_realloc(items, newcap * item_size);
if (next == NULL) return NULL;
items = next;
*items_pointer = next;
*capacity = newcap;
}
void* result = items + (*count * item_size);
if (extra && result) memset(result, 0, item_size * extra);
return result;
}
YARAPI void* _yar_insert(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, size_t index, size_t extra)
{
void* next = _yar_reserve(items_pointer, count, capacity, item_size, extra);
if(next == NULL) return NULL;
char* items = *items_pointer;
if (index < *count)
{
memmove(&items[item_size * (index + extra)], &items[item_size * index], (*count - index) * item_size);
memset(&items[item_size * index], 0, extra * item_size);
}
*count += extra;
return items + index * item_size;
}
YARAPI void* _yar_remove(void** items_pointer, size_t* count, size_t item_size, size_t index, size_t remove)
{
if(remove >= *count) {
*count = 0;
return *items_pointer;
}
if (index >= *count) {
return *items_pointer;
}
char* items = *items_pointer;
memmove(&items[item_size * index], &items[item_size * (index + remove)], item_size * (*count - (index + remove)));
*count -= remove;
return items + item_size * index;
}
YARAPI void* _yar_realloc(void* p, size_t new_size)
{
// Declaration, so we can call it if the definition is overridden
extern void* YAR_REALLOC(void *ptr, size_t size);
return YAR_REALLOC(p, new_size);
}
YARAPI void _yar_free(void* p)
{
extern void YAR_FREE(void *ptr);
YAR_FREE(p);
}
#endif // YAR_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2025 Nicholas Rixson
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.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
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 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.
------------------------------------------------------------------------------
*/

69
src/vm.c Normal file
View file

@ -0,0 +1,69 @@
#include "vm.h"
#include "gc.h"
#include "print.h"
#include <stdio.h>
static I decode_sleb128(U8 **ptr) {
I result = 0;
I shift = 0;
U8 byte;
do {
byte = **ptr;
(*ptr)++;
result |= (I)(byte & 0x7F) << shift;
shift += 7;
} while (byte & 0x80);
if ((shift < 64) && (byte & 0x40)) {
result |= -(1LL << shift);
}
return result;
}
V vm_init(Vm *vm) {
vm->sp = vm->stack;
vm->rsp = vm->rstack;
gc_init(&vm->gc);
for (Z i = 0; i < STACK_SIZE; i++) {
vm->stack[i] = NIL;
gc_addroot(&vm->gc, &vm->stack[i]);
}
}
V vm_push(Vm *vm, O o) { *vm->sp++ = o; }
O vm_pop(Vm *vm) { return *--vm->sp; }
O vm_peek(Vm *vm) { return *(vm->sp - 1); }
V vm_run(Vm *vm, Bc *chunk, I offset) {
I mark = gc_mark(&vm->gc);
for (Z i = 0; i < chunk->constants.count; i++)
gc_addroot(&vm->gc, &chunk->constants.items[i]);
vm->ip = chunk->items + offset;
for (;;) {
U8 opcode;
switch (opcode = *vm->ip++) {
case OP_NOP:
continue;
case OP_CONST: {
I idx = decode_sleb128(&vm->ip);
vm_push(vm, chunk->constants.items[idx]);
break;
}
case OP_RETURN:
goto done;
}
}
done:
gc_reset(&vm->gc, mark);
// print stack :3
for (O *i = vm->stack; i < vm->sp; i++) {
print(*i);
putchar(' ');
}
putchar('\n');
}

34
src/vm.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef VM_H
#define VM_H
#include "common.h"
#include "chunk.h"
#include "gc.h"
#include "object.h"
enum {
OP_NOP = 0,
OP_CONST, // Push constant to stack
OP_JUMP, // Relative jump
OP_JUMP_IF_NIL, // Relative jump if top-of-stack is nil
OP_DOWORD,
OP_CALL,
OP_RETURN,
};
#define STACK_SIZE 256
typedef struct Vm {
Gc gc;
O stack[256], *sp;
U rstack[256], *rsp;
U8 *ip;
} Vm;
V vm_init(Vm *);
V vm_push(Vm *, O);
O vm_pop(Vm *);
O vm_peek(Vm *);
V vm_run(Vm *, Bc *, I);
#endif