codegen: emit C instead of bytecode — El is now natively compiled
Rewrites codegen.el to produce C source instead of JSON bytecode, eliminating the ELVM interpreter as a runtime dependency. - All El values use el_val_t (int64_t) as the universal type; integers are stored directly, strings/pointers via uintptr_t cast - String literals wrapped with EL_STR(), arithmetic works natively - fn declarations become C functions returning el_val_t - let bindings become el_val_t local variables - if/else, while, for all map to native C control flow - String + String uses el_str_concat(); numeric + uses C + - strip_outer_parens() prevents double-paren warnings in if/while - compiler.el updated to describe C output and correct CLI usage Adds el-compiler/runtime/ with: - el_runtime.h: declares all builtins using el_val_t - el_runtime.c: implements I/O, strings, math, list, map, fs, JSON; HTTP builtins are stubs (return empty string) pending libcurl Compile El programs with: cc -I<runtime-dir> -o hello hello.c el_runtime.c
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* el_runtime.c — El language C runtime implementation
|
||||
*
|
||||
* All functions use el_val_t (= int64_t) as the universal value type.
|
||||
* Strings are transported as their pointer address cast to int64_t.
|
||||
* On any 64-bit system sizeof(pointer) <= sizeof(int64_t), so this is safe.
|
||||
*
|
||||
* Compile with:
|
||||
* cc -std=c11 -I<runtime-dir> -o <prog> <prog>.c el_runtime.c
|
||||
*/
|
||||
|
||||
#include "el_runtime.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* ── Internal allocators ─────────────────────────────────────────────────── */
|
||||
|
||||
static char* el_strdup(const char* s) {
|
||||
if (!s) return strdup("");
|
||||
return strdup(s);
|
||||
}
|
||||
|
||||
static char* el_strbuf(size_t n) {
|
||||
char* p = malloc(n + 1);
|
||||
if (!p) { fputs("el_runtime: out of memory\n", stderr); exit(1); }
|
||||
p[0] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Wrap an allocated C string as el_val_t */
|
||||
static el_val_t el_wrap_str(char* s) {
|
||||
return EL_STR(s);
|
||||
}
|
||||
|
||||
/* ── I/O ──────────────────────────────────────────────────────────────────── */
|
||||
|
||||
void println(el_val_t s) {
|
||||
const char* str = EL_CSTR(s);
|
||||
if (str) puts(str);
|
||||
else puts("");
|
||||
}
|
||||
|
||||
void print(el_val_t s) {
|
||||
const char* str = EL_CSTR(s);
|
||||
if (str) fputs(str, stdout);
|
||||
}
|
||||
|
||||
el_val_t readline(void) {
|
||||
char buf[4096];
|
||||
if (!fgets(buf, sizeof(buf), stdin)) return el_wrap_str(el_strdup(""));
|
||||
size_t len = strlen(buf);
|
||||
if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0';
|
||||
return el_wrap_str(el_strdup(buf));
|
||||
}
|
||||
|
||||
/* ── String builtins ─────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t el_str_concat(el_val_t av, el_val_t bv) {
|
||||
const char* a = EL_CSTR(av);
|
||||
const char* b = EL_CSTR(bv);
|
||||
if (!a) a = "";
|
||||
if (!b) b = "";
|
||||
size_t la = strlen(a);
|
||||
size_t lb = strlen(b);
|
||||
char* out = el_strbuf(la + lb);
|
||||
memcpy(out, a, la);
|
||||
memcpy(out + la, b, lb);
|
||||
out[la + lb] = '\0';
|
||||
return el_wrap_str(out);
|
||||
}
|
||||
|
||||
el_val_t str_eq(el_val_t av, el_val_t bv) {
|
||||
const char* a = EL_CSTR(av);
|
||||
const char* b = EL_CSTR(bv);
|
||||
if (!a || !b) return (el_val_t)(a == b);
|
||||
return (el_val_t)(strcmp(a, b) == 0);
|
||||
}
|
||||
|
||||
el_val_t str_starts_with(el_val_t sv, el_val_t prefv) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
const char* prefix = EL_CSTR(prefv);
|
||||
if (!s || !prefix) return 0;
|
||||
size_t lp = strlen(prefix);
|
||||
return (el_val_t)(strncmp(s, prefix, lp) == 0);
|
||||
}
|
||||
|
||||
el_val_t str_ends_with(el_val_t sv, el_val_t sufv) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
const char* suffix = EL_CSTR(sufv);
|
||||
if (!s || !suffix) return 0;
|
||||
size_t ls = strlen(s);
|
||||
size_t lsuf = strlen(suffix);
|
||||
if (lsuf > ls) return 0;
|
||||
return (el_val_t)(strcmp(s + ls - lsuf, suffix) == 0);
|
||||
}
|
||||
|
||||
el_val_t str_len(el_val_t sv) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
if (!s) return 0;
|
||||
return (el_val_t)strlen(s);
|
||||
}
|
||||
|
||||
el_val_t str_concat(el_val_t a, el_val_t b) {
|
||||
return el_str_concat(a, b);
|
||||
}
|
||||
|
||||
el_val_t int_to_str(el_val_t n) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%lld", (long long)n);
|
||||
return el_wrap_str(el_strdup(buf));
|
||||
}
|
||||
|
||||
el_val_t str_to_int(el_val_t sv) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
if (!s) return 0;
|
||||
return (el_val_t)atoll(s);
|
||||
}
|
||||
|
||||
el_val_t str_slice(el_val_t sv, el_val_t start, el_val_t end) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
if (!s) return el_wrap_str(el_strdup(""));
|
||||
int64_t len = (int64_t)strlen(s);
|
||||
if (start < 0) start = 0;
|
||||
if (end > len) end = len;
|
||||
if (start >= end) return el_wrap_str(el_strdup(""));
|
||||
int64_t sz = end - start;
|
||||
char* out = el_strbuf((size_t)sz);
|
||||
memcpy(out, s + start, (size_t)sz);
|
||||
out[sz] = '\0';
|
||||
return el_wrap_str(out);
|
||||
}
|
||||
|
||||
el_val_t str_contains(el_val_t sv, el_val_t subv) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
const char* sub = EL_CSTR(subv);
|
||||
if (!s || !sub) return 0;
|
||||
return (el_val_t)(strstr(s, sub) != NULL);
|
||||
}
|
||||
|
||||
el_val_t str_replace(el_val_t sv, el_val_t fromv, el_val_t tov) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
const char* from = EL_CSTR(fromv);
|
||||
const char* to = EL_CSTR(tov);
|
||||
if (!s || !from || !to) return el_wrap_str(el_strdup(s ? s : ""));
|
||||
size_t ls = strlen(s);
|
||||
size_t lf = strlen(from);
|
||||
size_t lt = strlen(to);
|
||||
if (lf == 0) return el_wrap_str(el_strdup(s));
|
||||
size_t count = 0;
|
||||
const char* p = s;
|
||||
while ((p = strstr(p, from)) != NULL) { count++; p += lf; }
|
||||
size_t out_sz = ls + count * lt + 1;
|
||||
char* out = el_strbuf(out_sz);
|
||||
char* dst = out;
|
||||
p = s;
|
||||
const char* found;
|
||||
while ((found = strstr(p, from)) != NULL) {
|
||||
size_t chunk = (size_t)(found - p);
|
||||
memcpy(dst, p, chunk); dst += chunk;
|
||||
memcpy(dst, to, lt); dst += lt;
|
||||
p = found + lf;
|
||||
}
|
||||
strcpy(dst, p);
|
||||
return el_wrap_str(out);
|
||||
}
|
||||
|
||||
el_val_t str_to_upper(el_val_t sv) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
if (!s) return el_wrap_str(el_strdup(""));
|
||||
size_t n = strlen(s);
|
||||
char* out = el_strbuf(n);
|
||||
for (size_t i = 0; i < n; i++) out[i] = (char)toupper((unsigned char)s[i]);
|
||||
out[n] = '\0';
|
||||
return el_wrap_str(out);
|
||||
}
|
||||
|
||||
el_val_t str_to_lower(el_val_t sv) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
if (!s) return el_wrap_str(el_strdup(""));
|
||||
size_t n = strlen(s);
|
||||
char* out = el_strbuf(n);
|
||||
for (size_t i = 0; i < n; i++) out[i] = (char)tolower((unsigned char)s[i]);
|
||||
out[n] = '\0';
|
||||
return el_wrap_str(out);
|
||||
}
|
||||
|
||||
el_val_t str_trim(el_val_t sv) {
|
||||
const char* s = EL_CSTR(sv);
|
||||
if (!s) return el_wrap_str(el_strdup(""));
|
||||
while (*s && isspace((unsigned char)*s)) s++;
|
||||
size_t n = strlen(s);
|
||||
while (n > 0 && isspace((unsigned char)s[n - 1])) n--;
|
||||
char* out = el_strbuf(n);
|
||||
memcpy(out, s, n);
|
||||
out[n] = '\0';
|
||||
return el_wrap_str(out);
|
||||
}
|
||||
|
||||
/* ── Math ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t el_abs(el_val_t n) { return n < 0 ? -n : n; }
|
||||
el_val_t el_max(el_val_t a, el_val_t b) { return a > b ? a : b; }
|
||||
el_val_t el_min(el_val_t a, el_val_t b) { return a < b ? a : b; }
|
||||
|
||||
/* ── List ────────────────────────────────────────────────────────────────── */
|
||||
/*
|
||||
* Dynamic array header:
|
||||
* int64_t capacity
|
||||
* int64_t length
|
||||
* el_val_t elems[]
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int64_t capacity;
|
||||
int64_t length;
|
||||
el_val_t elems[1];
|
||||
} ElList;
|
||||
|
||||
static ElList* list_alloc(int64_t cap) {
|
||||
ElList* lst = malloc(sizeof(ElList) + (size_t)(cap > 1 ? cap - 1 : 0) * sizeof(el_val_t));
|
||||
if (!lst) { fputs("el_runtime: out of memory\n", stderr); exit(1); }
|
||||
lst->capacity = cap;
|
||||
lst->length = 0;
|
||||
return lst;
|
||||
}
|
||||
|
||||
el_val_t el_list_empty(void) {
|
||||
return EL_STR(list_alloc(4));
|
||||
}
|
||||
|
||||
el_val_t el_list_new(el_val_t count, ...) {
|
||||
ElList* lst = list_alloc(count > 0 ? count : 4);
|
||||
va_list ap;
|
||||
va_start(ap, count);
|
||||
for (int64_t i = 0; i < count; i++) {
|
||||
lst->elems[i] = va_arg(ap, el_val_t);
|
||||
}
|
||||
va_end(ap);
|
||||
lst->length = count;
|
||||
return EL_STR(lst);
|
||||
}
|
||||
|
||||
el_val_t el_list_len(el_val_t listv) {
|
||||
ElList* lst = (ElList*)(uintptr_t)listv;
|
||||
if (!lst) return 0;
|
||||
return lst->length;
|
||||
}
|
||||
|
||||
el_val_t el_list_get(el_val_t listv, el_val_t index) {
|
||||
ElList* lst = (ElList*)(uintptr_t)listv;
|
||||
if (!lst) return 0;
|
||||
if (index < 0 || index >= lst->length) return 0;
|
||||
return lst->elems[index];
|
||||
}
|
||||
|
||||
el_val_t el_list_append(el_val_t listv, el_val_t elem) {
|
||||
ElList* lst = (ElList*)(uintptr_t)listv;
|
||||
if (!lst) { lst = list_alloc(4); }
|
||||
if (lst->length >= lst->capacity) {
|
||||
int64_t new_cap = lst->capacity * 2;
|
||||
lst = realloc(lst, sizeof(ElList) + (size_t)(new_cap - 1) * sizeof(el_val_t));
|
||||
if (!lst) { fputs("el_runtime: out of memory\n", stderr); exit(1); }
|
||||
lst->capacity = new_cap;
|
||||
}
|
||||
lst->elems[lst->length++] = elem;
|
||||
return EL_STR(lst);
|
||||
}
|
||||
|
||||
/* ── Map ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
typedef struct {
|
||||
int64_t count;
|
||||
el_val_t* keys;
|
||||
el_val_t* values;
|
||||
} ElMap;
|
||||
|
||||
el_val_t el_map_new(el_val_t pair_count, ...) {
|
||||
ElMap* m = malloc(sizeof(ElMap));
|
||||
if (!m) { fputs("el_runtime: out of memory\n", stderr); exit(1); }
|
||||
m->count = pair_count;
|
||||
m->keys = malloc(sizeof(el_val_t) * (size_t)(pair_count > 0 ? pair_count : 1));
|
||||
m->values = malloc(sizeof(el_val_t) * (size_t)(pair_count > 0 ? pair_count : 1));
|
||||
va_list ap;
|
||||
va_start(ap, pair_count);
|
||||
for (int64_t i = 0; i < pair_count; i++) {
|
||||
m->keys[i] = va_arg(ap, el_val_t);
|
||||
m->values[i] = va_arg(ap, el_val_t);
|
||||
}
|
||||
va_end(ap);
|
||||
return EL_STR(m);
|
||||
}
|
||||
|
||||
static ElMap* as_map(el_val_t v) { return (ElMap*)(uintptr_t)v; }
|
||||
|
||||
el_val_t el_map_get(el_val_t mapv, el_val_t keyv) {
|
||||
ElMap* m = as_map(mapv);
|
||||
const char* key = EL_CSTR(keyv);
|
||||
if (!m || !key) return 0;
|
||||
for (int64_t i = 0; i < m->count; i++) {
|
||||
const char* k = EL_CSTR(m->keys[i]);
|
||||
if (k && strcmp(k, key) == 0) return m->values[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
el_val_t el_get_field(el_val_t mapv, el_val_t keyv) {
|
||||
return el_map_get(mapv, keyv);
|
||||
}
|
||||
|
||||
el_val_t el_map_set(el_val_t mapv, el_val_t keyv, el_val_t value) {
|
||||
ElMap* m = as_map(mapv);
|
||||
const char* key = EL_CSTR(keyv);
|
||||
if (!m) return 0;
|
||||
for (int64_t i = 0; i < m->count; i++) {
|
||||
const char* k = EL_CSTR(m->keys[i]);
|
||||
if (k && strcmp(k, key) == 0) { m->values[i] = value; return mapv; }
|
||||
}
|
||||
int64_t nc = m->count + 1;
|
||||
m->keys = realloc(m->keys, sizeof(el_val_t) * (size_t)nc);
|
||||
m->values = realloc(m->values, sizeof(el_val_t) * (size_t)nc);
|
||||
m->keys[m->count] = keyv;
|
||||
m->values[m->count] = value;
|
||||
m->count = nc;
|
||||
return mapv;
|
||||
}
|
||||
|
||||
/* ── HTTP stubs ──────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t http_get(el_val_t url) {
|
||||
(void)url;
|
||||
return el_wrap_str(el_strdup(""));
|
||||
}
|
||||
|
||||
el_val_t http_post(el_val_t url, el_val_t body) {
|
||||
(void)url; (void)body;
|
||||
return el_wrap_str(el_strdup(""));
|
||||
}
|
||||
|
||||
void http_serve(el_val_t port, el_val_t handler) {
|
||||
(void)port; (void)handler;
|
||||
}
|
||||
|
||||
/* ── Filesystem ──────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t fs_read(el_val_t pathv) {
|
||||
const char* path = EL_CSTR(pathv);
|
||||
if (!path) return el_wrap_str(el_strdup(""));
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (!f) return el_wrap_str(el_strdup(""));
|
||||
fseek(f, 0, SEEK_END);
|
||||
long sz = ftell(f);
|
||||
rewind(f);
|
||||
char* buf = el_strbuf((size_t)sz);
|
||||
size_t got = fread(buf, 1, (size_t)sz, f);
|
||||
buf[got] = '\0';
|
||||
fclose(f);
|
||||
return el_wrap_str(buf);
|
||||
}
|
||||
|
||||
el_val_t fs_write(el_val_t pathv, el_val_t contentv) {
|
||||
const char* path = EL_CSTR(pathv);
|
||||
const char* content = EL_CSTR(contentv);
|
||||
if (!path || !content) return 0;
|
||||
FILE* f = fopen(path, "wb");
|
||||
if (!f) return 0;
|
||||
size_t n = strlen(content);
|
||||
size_t written = fwrite(content, 1, n, f);
|
||||
fclose(f);
|
||||
return written == n ? 1 : 0;
|
||||
}
|
||||
|
||||
/* ── JSON ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t json_get(el_val_t jsonv, el_val_t keyv) {
|
||||
const char* json = EL_CSTR(jsonv);
|
||||
const char* key = EL_CSTR(keyv);
|
||||
if (!json || !key) return el_wrap_str(el_strdup(""));
|
||||
size_t klen = strlen(key);
|
||||
char* pattern = el_strbuf(klen + 4);
|
||||
snprintf(pattern, klen + 5, "\"%s\":", key);
|
||||
const char* p = strstr(json, pattern);
|
||||
free(pattern);
|
||||
if (!p) return el_wrap_str(el_strdup(""));
|
||||
p += strlen(key) + 3; /* skip "key": */
|
||||
while (*p == ' ' || *p == '\t' || *p == '\n') p++;
|
||||
if (*p == '"') {
|
||||
p++;
|
||||
const char* start = p;
|
||||
while (*p && !(*p == '"' && *(p-1) != '\\')) p++;
|
||||
size_t len = (size_t)(p - start);
|
||||
char* out = el_strbuf(len);
|
||||
memcpy(out, start, len);
|
||||
out[len] = '\0';
|
||||
return el_wrap_str(out);
|
||||
}
|
||||
const char* start = p;
|
||||
while (*p && *p != ',' && *p != '}' && *p != ']' && *p != '\n') p++;
|
||||
size_t len = (size_t)(p - start);
|
||||
char* out = el_strbuf(len);
|
||||
memcpy(out, start, len);
|
||||
out[len] = '\0';
|
||||
return el_wrap_str(out);
|
||||
}
|
||||
|
||||
/* ── Process ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
void exit_program(el_val_t code) {
|
||||
exit((int)code);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* el_runtime.h — El language C runtime header
|
||||
*
|
||||
* Declares all built-in functions available to compiled El programs.
|
||||
* Include this in every generated .c file.
|
||||
*
|
||||
* Value model:
|
||||
* All El values are represented as el_val_t (= int64_t).
|
||||
* On 64-bit systems a pointer fits in int64_t.
|
||||
* String values are cast: (el_val_t)(uintptr_t)"hello"
|
||||
* Integer values are stored directly.
|
||||
* This lets arithmetic work naturally while still passing strings around.
|
||||
*
|
||||
* Type conventions (El -> C):
|
||||
* String -> el_val_t (holds const char* via uintptr_t cast)
|
||||
* Int -> el_val_t
|
||||
* Bool -> el_val_t (0 = false, nonzero = true)
|
||||
* Any -> el_val_t
|
||||
* Void -> void
|
||||
*
|
||||
* Macros for convenience:
|
||||
* EL_STR(s) cast string literal to el_val_t
|
||||
* EL_CSTR(v) cast el_val_t back to const char*
|
||||
* EL_INT(v) identity — el_val_t is already int64_t
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef int64_t el_val_t;
|
||||
|
||||
#define EL_STR(s) ((el_val_t)(uintptr_t)(s))
|
||||
#define EL_CSTR(v) ((const char*)(uintptr_t)(v))
|
||||
#define EL_INT(v) (v)
|
||||
#define EL_NULL ((el_val_t)0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ── I/O ──────────────────────────────────────────────────────────────────── */
|
||||
|
||||
void println(el_val_t s);
|
||||
void print(el_val_t s);
|
||||
el_val_t readline(void);
|
||||
|
||||
/* ── String builtins ─────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t el_str_concat(el_val_t a, el_val_t b);
|
||||
el_val_t str_eq(el_val_t a, el_val_t b);
|
||||
el_val_t str_starts_with(el_val_t s, el_val_t prefix);
|
||||
el_val_t str_ends_with(el_val_t s, el_val_t suffix);
|
||||
el_val_t str_len(el_val_t s);
|
||||
el_val_t str_concat(el_val_t a, el_val_t b);
|
||||
el_val_t int_to_str(el_val_t n);
|
||||
el_val_t str_to_int(el_val_t s);
|
||||
el_val_t str_slice(el_val_t s, el_val_t start, el_val_t end);
|
||||
el_val_t str_contains(el_val_t s, el_val_t sub);
|
||||
el_val_t str_replace(el_val_t s, el_val_t from, el_val_t to);
|
||||
el_val_t str_to_upper(el_val_t s);
|
||||
el_val_t str_to_lower(el_val_t s);
|
||||
el_val_t str_trim(el_val_t s);
|
||||
|
||||
/* ── Math ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t el_abs(el_val_t n);
|
||||
el_val_t el_max(el_val_t a, el_val_t b);
|
||||
el_val_t el_min(el_val_t a, el_val_t b);
|
||||
|
||||
/* ── List ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t el_list_new(el_val_t count, ...);
|
||||
el_val_t el_list_len(el_val_t list);
|
||||
el_val_t el_list_get(el_val_t list, el_val_t index);
|
||||
el_val_t el_list_append(el_val_t list, el_val_t elem);
|
||||
el_val_t el_list_empty(void);
|
||||
|
||||
/* ── Map ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t el_map_new(el_val_t pair_count, ...);
|
||||
el_val_t el_get_field(el_val_t map, el_val_t key);
|
||||
el_val_t el_map_get(el_val_t map, el_val_t key);
|
||||
el_val_t el_map_set(el_val_t map, el_val_t key, el_val_t value);
|
||||
|
||||
/* ── HTTP ─────────────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t http_get(el_val_t url);
|
||||
el_val_t http_post(el_val_t url, el_val_t body);
|
||||
void http_serve(el_val_t port, el_val_t handler);
|
||||
|
||||
/* ── Filesystem ──────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t fs_read(el_val_t path);
|
||||
el_val_t fs_write(el_val_t path, el_val_t content);
|
||||
|
||||
/* ── JSON ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t json_get(el_val_t json, el_val_t key);
|
||||
|
||||
/* ── Process ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
void exit_program(el_val_t code);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+416
-508
File diff suppressed because it is too large
Load Diff
+10
-10
@@ -4,14 +4,14 @@
|
||||
// This is the bootstrap entry point: compiled once by the Rust el-compiler,
|
||||
// then self-hosted from that point forward.
|
||||
//
|
||||
// The returned JSON is an array of bytecode instruction objects matching
|
||||
// the serde serialisation format of el-compiler's Bytecode enum.
|
||||
// The returned string is C source code. Compile the output with:
|
||||
// cc -o <prog> <prog>.c el_runtime.c
|
||||
|
||||
import "lexer.el"
|
||||
import "parser.el"
|
||||
import "codegen.el"
|
||||
|
||||
// compile — full pipeline: source string -> JSON bytecode string
|
||||
// compile — full pipeline: source string -> C source string
|
||||
fn compile(source: String) -> String {
|
||||
let tokens: [Map<String, Any>] = lex(source)
|
||||
let stmts: [Map<String, Any>] = parse(tokens)
|
||||
@@ -20,23 +20,23 @@ fn compile(source: String) -> String {
|
||||
|
||||
// main — CLI entry point for self-hosted compilation.
|
||||
//
|
||||
// Called by: elvm el-compiler.elc <source.el> <output.elc>
|
||||
// Called by: elc <source.el> <output.c>
|
||||
//
|
||||
// Reads pre-resolved El source from args()[0], compiles it to JSON bytecode,
|
||||
// and writes the result to args()[1]. The output is raw JSON (accepted by
|
||||
// both elvm and el exec without an ELVM container header).
|
||||
// Reads El source from args()[0], compiles it to C source, and writes the
|
||||
// result to args()[1]. Then run:
|
||||
// cc -o <prog> <output.c> el_runtime.c
|
||||
fn main() -> Void {
|
||||
let argv: [String] = args()
|
||||
let argc: Int = native_list_len(argv)
|
||||
if argc < 2 {
|
||||
println("el-compiler: usage: elvm el-compiler.elc <source.el> <output.elc>")
|
||||
println("el-compiler: usage: elc <source.el> <output.c>")
|
||||
exit(1)
|
||||
}
|
||||
let src_path: String = native_list_get(argv, 0)
|
||||
let out_path: String = native_list_get(argv, 1)
|
||||
let source: String = fs_read(src_path)
|
||||
let bytecode_json: String = compile(source)
|
||||
let ok: Bool = fs_write(out_path, bytecode_json)
|
||||
let c_source: String = compile(source)
|
||||
let ok: Bool = fs_write(out_path, c_source)
|
||||
if ok {
|
||||
exit(0)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user