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:
+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