summaryrefslogtreecommitdiff
path: root/src/runtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime.c')
-rw-r--r--src/runtime.c220
1 files changed, 55 insertions, 165 deletions
diff --git a/src/runtime.c b/src/runtime.c
index 6f3759f..7c15a0a 100644
--- a/src/runtime.c
+++ b/src/runtime.c
@@ -1,10 +1,3 @@
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
#include <lcq/pit/utils.h>
#include <lcq/pit/lexer.h>
#include <lcq/pit/parser.h>
@@ -29,17 +22,22 @@ u64 pit_value_data(pit_value v) {
return v & 0x1ffffffffffff;
}
-pit_runtime *pit_runtime_new() {
- pit_runtime *ret = malloc(sizeof(*ret));
- ret->heap = pit_arena_new(64 * 1024 * 1024, sizeof(pit_value_heavy));
- ret->backbuffer = pit_arena_new(64 * 1024 * 1024, sizeof(pit_value_heavy));
- ret->symtab = pit_arena_new(1024 * 1024, sizeof(pit_symtab_entry));
+pit_runtime *pit_runtime_new(u8 *buf, i64 len) {
+ pit_arena *a = pit_arena_new(buf, len, sizeof(u8));
+ pit_runtime *ret = pit_arena_alloc_back(a, sizeof(*ret));
+ i64 heap_size = 64 * 1024 * 1024;
+ i64 symtab_size = 1024 * 1024;
+ i64 scratch_size = 1024 * 1024;
+ i64 stack_size = 64 * 1024;
+ ret->heap = pit_arena_new(pit_arena_alloc_back(a, heap_size), heap_size, sizeof(pit_value_heavy));
+ ret->backbuffer = pit_arena_new(pit_arena_alloc_back(a, heap_size), heap_size, sizeof(pit_value_heavy));
+ ret->symtab = pit_arena_new(pit_arena_alloc_back(a, symtab_size), symtab_size, sizeof(pit_symtab_entry));
ret->symtab_len = 0;
- ret->scratch = pit_arena_new(1024 * 1024, sizeof(u8));
- ret->expr_stack = pit_values_new(64 * 1024);
- ret->result_stack = pit_values_new(64 * 1024);
- ret->program = pit_runtime_eval_program_new(64 * 1024);
- ret->saved_bindings = pit_values_new(64 * 1024);
+ ret->scratch = pit_arena_new(pit_arena_alloc_back(a, scratch_size), scratch_size, sizeof(u8));
+ ret->expr_stack = pit_values_new(pit_arena_alloc_back(a, stack_size), stack_size);
+ ret->result_stack = pit_values_new(pit_arena_alloc_back(a, stack_size), stack_size);
+ ret->program = pit_runtime_eval_program_new(pit_arena_alloc_back(a, stack_size), stack_size);
+ ret->saved_bindings = pit_values_new(pit_arena_alloc_back(a, stack_size), stack_size);
ret->frozen_values = 0;
ret->frozen_symtab = 0;
ret->error = PIT_NIL;
@@ -61,16 +59,6 @@ void pit_runtime_reset(pit_runtime *rt) {
rt->heap->next = rt->frozen_values;
rt->symtab->next = rt->frozen_symtab;
}
-bool pit_runtime_print_error(pit_runtime *rt) {
- if (!pit_eq(rt->error, PIT_NIL)) {
- char buf[1024] = {0};
- i64 end = pit_dump(rt, buf, sizeof(buf) - 1, rt->error, false);
- buf[end] = 0;
- fprintf(stderr, "error at line %ld, column %ld: %s\n", rt->error_line, rt->error_column, buf);
- return true;
- }
- return false;
-}
#define CHECK_BUF if (buf >= end) { return buf - start; }
#define CHECK_BUF_LABEL(label) if (buf >= end) { goto label; }
@@ -79,9 +67,9 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable) {
if (len <= 0) return 0;
switch (pit_value_sort(v)) {
case PIT_VALUE_SORT_DOUBLE:
- return snprintf(buf, (size_t) len, "%lf", pit_as_double(rt, v));
+ return pit_string_snprintf(buf, (size_t) len, "%lf", pit_as_double(rt, v));
case PIT_VALUE_SORT_INTEGER:
- return snprintf(buf, (size_t) len, "%ld", pit_as_integer(rt, v));
+ return pit_string_snprintf(buf, (size_t) len, "%ld", pit_as_integer(rt, v));
case PIT_VALUE_SORT_SYMBOL: {
pit_symtab_entry *ent = pit_symtab_lookup(rt, v);
if (ent
@@ -94,7 +82,7 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable) {
}
return i;
} else {
- return snprintf(buf, (size_t) len, "<broken symbol %ld>", pit_as_symbol(rt, v));
+ return pit_string_snprintf(buf, (size_t) len, "<broken symbol %ld>", pit_as_symbol(rt, v));
}
}
case PIT_VALUE_SORT_REF: {
@@ -102,7 +90,7 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable) {
char *end = buf + len;
char *start = buf;
h = pit_deref(rt, r);
- if (!h) snprintf(buf, (size_t) len, "<ref %ld>", r);
+ if (!h) pit_string_snprintf(buf, (size_t) len, "<ref %ld>", r);
else {
switch (h->hsort) {
case PIT_VALUE_HEAVY_SORT_CELL: {
@@ -119,7 +107,7 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable) {
CHECK_BUF_LABEL(list_end); *(buf++) = ' ';
CHECK_BUF_LABEL(list_end); buf += pit_dump(rt, buf, end - buf, pit_car(rt, cur), readable);
} else {
- CHECK_BUF_LABEL(list_end); buf += snprintf(buf, (size_t) (end - buf), " . ");
+ CHECK_BUF_LABEL(list_end); buf += pit_string_snprintf(buf, (size_t) (end - buf), " . ");
CHECK_BUF_LABEL(list_end); buf += pit_dump(rt, buf, end - buf, cur, readable);
}
} while (!pit_eq((cur = pit_cdr(rt, cur)), PIT_NIL));
@@ -158,7 +146,7 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable) {
return i;
}
default:
- return snprintf(buf, (size_t) len, "<ref %ld>", r);
+ return pit_string_snprintf(buf, (size_t) len, "<ref %ld>", r);
}
}
break;
@@ -167,19 +155,12 @@ i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable) {
return 0;
}
-void pit_trace_(pit_runtime *rt, const char *format, pit_value v) {
- char buf[1024] = {0};
- i64 end = pit_dump(rt, buf, sizeof(buf) - 1, v, true);
- buf[end] = 0;
- fprintf(stderr, format, buf);
-}
-
-void pit_error(pit_runtime *rt, const char *format, ...) {
+void pit_error(pit_runtime *rt, char *format, ...) {
if (rt->error == PIT_NIL) { /* only record the first error encountered */
char buf[1024] = {0};
va_list vargs;
va_start(vargs, format);
- vsnprintf(buf, sizeof(buf), format, vargs);
+ pit_string_snprintf(buf, sizeof(buf), format, vargs);
va_end(vargs);
rt->error = PIT_T; /* we set the error now to prevent infinite recursion */
rt->error = pit_bytes_new_cstr(rt, buf); /* in case this errs also */
@@ -379,7 +360,7 @@ bool pit_equal(pit_runtime *rt, pit_value a, pit_value b) {
pit_value pit_bytes_new(pit_runtime *rt, u8 *buf, i64 len) {
u8 *dest = pit_arena_alloc_back(rt->heap, len);
if (!dest) { pit_error(rt, "failed to allocate bytes"); return PIT_NIL; }
- memcpy(dest, buf, (size_t) len);
+ pit_string_memcpy(dest, buf, (size_t) len);
pit_value ret = pit_heavy_new(rt);
pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, ret));
if (!h) { pit_error(rt, "failed to create new heavy value for bytes"); return PIT_NIL; }
@@ -389,33 +370,7 @@ pit_value pit_bytes_new(pit_runtime *rt, u8 *buf, i64 len) {
return ret;
}
pit_value pit_bytes_new_cstr(pit_runtime *rt, char *s) {
- return pit_bytes_new(rt, (u8 *) s, (i64) strlen(s));
-}
-pit_value pit_bytes_new_file(pit_runtime *rt, char *path) {
- if (rt->error != PIT_NIL) return PIT_NIL;
- FILE *f = fopen(path, "r");
- if (f == NULL) {
- pit_error(rt, "failed to open file: %s", path);
- return PIT_NIL;
- }
- fseek(f, 0, SEEK_END);
- i64 len = ftell(f);
- fseek(f, 0, SEEK_SET);
- u8 *dest = pit_arena_alloc_bulk(rt->heap, len);
- if (!dest) { pit_error(rt, "failed to allocate bytes"); fclose(f); return PIT_NIL; }
- if ((size_t) len != fread(dest, sizeof(char), (size_t) len, f)) {
- fclose(f);
- pit_error(rt, "failed to read file: %s", path);
- return PIT_NIL;
- }
- fclose(f);
- pit_value ret = pit_heavy_new(rt);
- pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, ret));
- if (!h) { pit_error(rt, "failed to create new heavy value for bytes"); return PIT_NIL; }
- h->hsort = PIT_VALUE_HEAVY_SORT_BYTES;
- h->in.bytes.data = dest;
- h->in.bytes.len = len;
- return ret;
+ return pit_bytes_new(rt, (u8 *) s, (i64) pit_string_strlen(s));
}
/* return true if v is a reference to bytes that are the same as those in buf */
bool pit_bytes_match(pit_runtime *rt, pit_value v, u8 *buf, i64 len) {
@@ -465,7 +420,7 @@ pit_value pit_intern(pit_runtime *rt, u8 *nm, i64 len) {
return pit_symbol_new(rt, idx);
}
pit_value pit_intern_cstr(pit_runtime *rt, char *nm) {
- return pit_intern(rt, (u8 *) nm, (i64) strlen(nm));
+ return pit_intern(rt, (u8 *) nm, (i64) pit_string_strlen(nm));
}
pit_value pit_symbol_name(pit_runtime *rt, pit_value sym) {
pit_symtab_entry *ent = pit_symtab_lookup(rt, sym);
@@ -478,7 +433,7 @@ bool pit_symbol_name_match(pit_runtime *rt, pit_value sym, u8 *buf, i64 len) {
return pit_bytes_match(rt, ent->name, buf, len);
}
bool pit_symbol_name_match_cstr(pit_runtime *rt, pit_value sym, char *s) {
- return pit_symbol_name_match(rt, sym, (u8 *) s, (i64) strlen(s));
+ return pit_symbol_name_match(rt, sym, (u8 *) s, (i64) pit_string_strlen(s));
}
pit_symtab_entry *pit_symtab_lookup(pit_runtime *rt, pit_value sym) {
pit_symbol s = pit_as_symbol(rt, sym);
@@ -624,7 +579,7 @@ pit_value pit_array_from_buf(pit_runtime *rt, pit_value *xs, i64 len) {
pit_value ret = pit_array_new(rt, len);
pit_value_heavy *h = pit_deref(rt, pit_as_ref(rt, ret));
if (!h) { pit_error(rt, "failed to deref heavy value for array"); return PIT_NIL; }
- memcpy(h->in.array.data, xs, (size_t) len * (size_t) sizeof(pit_value));
+ pit_string_memcpy((u8 *) h->in.array.data, (u8 *) xs, (size_t) len * (size_t) sizeof(pit_value));
return ret;
}
i64 pit_array_len(pit_runtime *rt, pit_value arr) {
@@ -944,9 +899,14 @@ void *pit_nativedata_get(pit_runtime *rt, pit_value tag, pit_value v) {
return h->in.nativedata.data;
}
-pit_values *pit_values_new(i64 capacity) {
- i64 cap = capacity / (i64) sizeof(pit_value);
- pit_values *ret = malloc(sizeof(*ret) + (size_t) cap * sizeof(pit_value));
+pit_values *pit_values_new(u8 *buf, i64 buf_len) {
+ uintptr_t base = (uintptr_t) buf;
+ uintptr_t aligned = pit_align_up(base, sizeof(void *));
+ pit_values *ret = (pit_values *) aligned;
+ uintptr_t data = aligned + sizeof(pit_values);
+ i64 offset = (i64) data - (i64) base;
+ i64 remaining = (i64) (buf_len - offset);
+ i64 cap = remaining / (i64) sizeof(pit_value);
ret->next = 0;
ret->capacity = cap;
return ret;
@@ -961,9 +921,14 @@ pit_value pit_values_pop(pit_runtime *rt, pit_values *s) {
return s->data[--s->next];
}
-pit_runtime_eval_program *pit_runtime_eval_program_new(i64 capacity) {
- i64 cap = capacity / (i64) sizeof(pit_runtime_eval_program_entry);
- pit_runtime_eval_program *ret = malloc(sizeof(*ret) + (size_t) cap * sizeof(pit_runtime_eval_program_entry));
+pit_runtime_eval_program *pit_runtime_eval_program_new(u8 *buf, i64 buf_len) {
+ uintptr_t base = (uintptr_t) buf;
+ uintptr_t aligned = pit_align_up(base, sizeof(void *));
+ pit_runtime_eval_program *ret = (pit_runtime_eval_program *) aligned;
+ uintptr_t data = aligned + sizeof(pit_arena);
+ i64 offset = (i64) data - (i64) base;
+ i64 remaining = (i64) (buf_len - offset);
+ i64 cap = remaining / (i64) sizeof(pit_runtime_eval_program_entry);
ret->next = 0;
ret->capacity = cap;
return ret;
@@ -1240,93 +1205,18 @@ void pit_collect_garbage(pit_runtime *rt) {
rt->backbuffer = fromspace;
}
-static void check_invariants(pit_runtime *rt) {
- if (rt->scratch->next != 0) {
- pit_error(rt, "leaked scratch memory! %ld", rt->scratch->next);
- }
- if (rt->scratch->next != 0) {
- pit_error(rt, "leaked scratch memory! %ld", rt->scratch->next);
- }
-}
-
-pit_value pit_load_file(pit_runtime *rt, char *path) {
+int pit_runtime_test(u8 *out, i64 out_len, u8 *buf, i64 len) {
+ pit_runtime *rt = pit_runtime_new(buf, len);
+ pit_install_library_essential(rt);
+ pit_install_library_plist(rt);
+ pit_install_library_alist(rt);
pit_lexer lex;
pit_parser parse;
- bool eof = false;
- pit_value p = PIT_NIL;
- pit_value ret = PIT_NIL;
- if (pit_lex_file(&lex, path) < 0) {
- pit_error(rt, "failed to lex file: %s", path);
- return PIT_NIL;
- }
+ pit_lex_cstr(&lex, "(cons (list 1 2 3) (cons '(a b c) 21))");
pit_parser_from_lexer(&parse, &lex);
- while (p = pit_parse(rt, &parse, &eof), !eof) {
- check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL;
- ret = pit_eval(rt, p);
- check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL;
- pit_collect_garbage(rt);
- check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL;
- }
- check_invariants(rt); if (pit_runtime_print_error(rt)) return PIT_NIL;
- fprintf(stderr, "value allocs at exit: %ld\n", rt->heap->next);
- return ret;
-}
-
-void pit_repl(pit_runtime *rt) {
- size_t bufcap = 8;
- char *buf = malloc(bufcap);
- i64 len = 0;
- pit_runtime_freeze(rt);
- check_invariants(rt); if (pit_runtime_print_error(rt)) exit(1);
- setbuf(stdout, NULL);
- printf("> ");
- while ((buf[len++] = (char) getchar()) != EOF) {
- if (len >= (i64) bufcap) {
- bufcap *= 2;
- buf = realloc(buf, bufcap);
- }
- pit_value res;
- pit_lexer lex;
- pit_parser parse;
- bool eof = false;
- pit_value p = PIT_NIL;
- i64 depth = 0;
- bool lex_error = false;
- pit_lex_token tok = PIT_LEX_TOKEN_EOF;
- if (buf[len - 1] != '\n') continue;
- pit_lex_bytes(&lex, buf, len);
- while (!lex_error && (tok = pit_lex_next(&lex)) != PIT_LEX_TOKEN_EOF) {
- switch (tok) {
- case PIT_LEX_TOKEN_ERROR: lex_error = true; break;
- case PIT_LEX_TOKEN_LPAREN: depth += 1; break;
- case PIT_LEX_TOKEN_RPAREN: depth -= 1; break;
- default: break;
- }
- }
- if (lex_error || depth > 0) continue;
- buf[len - 1] = 0;
- pit_lex_bytes(&lex, buf, len);
- pit_parser_from_lexer(&parse, &lex);
- while (p = pit_parse(rt, &parse, &eof), !eof) {
- check_invariants(rt);
- res = pit_eval(rt, p);
- check_invariants(rt);
- }
- if (pit_runtime_print_error(rt)) {
- rt->error = PIT_NIL;
- printf("> ");
- } else {
- char dumpbuf[1024] = {0};
- pit_dump(rt, dumpbuf, sizeof(dumpbuf) - 1, res, true);
- pit_collect_garbage(rt);
- printf("%s\n> ", dumpbuf);
- }
- len = 0;
- }
- if (len >= (i64) sizeof(buf)) {
- fprintf(stderr, "expression exceeded REPL buffer size\n");
- } else {
- printf("bye!\n");
- }
- free(buf);
+ bool eof = false;
+ pit_value p = pit_parse(rt, &parse, &eof);
+ pit_value res = pit_eval(rt, p);
+ pit_dump(rt, (char *) out, out_len, res, false);
+ return 0;
}