Working on C generator for k_prime, can compile single number return

This commit is contained in:
Nathan Braswell
2020-04-12 15:52:45 -04:00
parent cb54429d1a
commit 813d31cb2b
2 changed files with 224 additions and 31 deletions

3
bf.kp
View File

@@ -47,3 +47,6 @@
(do ,(nth xs 4) (deref output))))))
(println (bf { ,>+++[<.>-] } [1337]))
(def! main (fn* [argv] 2))
;(def! main (fn* [] (+ 13 1)))

View File

@@ -28,17 +28,20 @@ fun read_str(grammer: ref Grammer<MalResult,MalValue>, s: str): pair<int, MalRes
}
}
adt MalValue {
Nil,
True,
False,
Int: int,
String: str,
Symbol: str,
List: vec<MalValue>,
Vector: vec<MalValue>,
Function: MalFunction,
BuiltinFunction: MalBuiltinFunction,
Atom: *MalValue
Nil, // 0 0101 111
True, // 1 0011 111
False, // 0 0011 111
// 0 0001 111 don't yet have a character
Function: MalFunction, // 110
BuiltinFunction: MalBuiltinFunction, // '''
Symbol: str, // 101
Atom: *MalValue, // 100
String: str, // 011
Vector: vec<MalValue>, // 010
List: vec<MalValue>, // 001
Int: int // 000
}
fun equals_MalValue(a: MalValue, b: MalValue): bool {
match (a) {
@@ -804,20 +807,16 @@ fun EVAL(env: *Env, ast: MalValue): MalResult {
}
}
fun PRINT(v: MalValue): str {
return pr_str(v, true)
}
fun rep(grammer: ref Grammer<MalResult, MalValue>, env: *Env, a: str): str {
var read = READ(grammer, a)
if is_err(read) {
return PRINT(get_err(read))
return pr_str(get_err(read), true)
} else {
var evaled = EVAL(env, get_value(read))
if is_err(evaled) {
return str("Exception: ") + PRINT(get_err(evaled))
return str("Exception: ") + pr_str(get_err(evaled), true)
} else {
return PRINT(get_value(evaled))
return pr_str(get_value(evaled), true)
}
}
}
@@ -1267,15 +1266,6 @@ fun main(argc: int, argv: **char): int {
env->set(str("string?"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
return MalResult::Err(MalValue::String(str("not implemented")))
}));
env->set(str("number?"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
return MalResult::Err(MalValue::String(str("not implemented")))
}));
env->set(str("seq"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
return MalResult::Err(MalValue::String(str("not implemented")))
}));
env->set(str("conj"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
return MalResult::Err(MalValue::String(str("not implemented")))
}));
// self-modifying grammer
env->set(str("add_terminal"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 2 || !is_string(params[0]) {
@@ -1379,21 +1369,18 @@ fun main(argc: int, argv: **char): int {
}));
// reader macros
rep(grammer, env, str("(add_grammer_rule (quote atom) [\"'\" (quote form)] (fn* (xs) (quasiquote (quote (unquote (nth xs 1))))))")) //'
// now we can use ' for the rest
rep(grammer, env, str("(add_grammer_rule 'atom [\"`\" 'form] (fn* (xs) (quasiquote (quasiquote (unquote (nth xs 1))))))"))
rep(grammer, env, str("(add_grammer_rule 'atom [\"~\" 'form] (fn* (xs) (list (quote unquote) (nth xs 1))))"))
// the standard appears to be for splice-unquote to be <symbol-for-unqoute><symbol-for-deref>, but unquote deref is a reasonable
// sequence of characters and causes ambigious parses! So I chose the other common unquote symbol to be splice-unquote
rep(grammer, env, str("(add_grammer_rule 'atom [\",\" 'form] (fn* (xs) (list (quote splice-unquote) (nth xs 1))))"))
// let's use the new reader macros in another reader macro
rep(grammer, env, str("(add_grammer_rule 'atom [\"@\" 'form] (fn* (xs) `(deref ~(nth xs 1))))")) //"
rep(grammer, env, str("(def! not (fn* (a) (if a false true)))"))
rep(grammer, env, str("(def! load-file (fn* (f) (eval-read-string (slurp f))))"))
rep(grammer, env, str("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"))
rep(grammer, env, str("(def! nil? (fn* (a) (= nil a)))"))
rep(grammer, env, str("(def! true? (fn* (a) (= true a)))"))
rep(grammer, env, str("(def! false? (fn* (a) (= false a)))"))
rep(grammer, env, str("(def! *host-language* \"kraken\")"))
var params = vec<MalValue>()
if argc > 1 {
for (var i = 2; i < argc; i++;) {
@@ -1401,6 +1388,24 @@ fun main(argc: int, argv: **char): int {
}
env->set(str("*ARGV*"), MalValue::List(params))
println(rep(grammer, env, str("(load-file \"") + argv[1] + "\")"))
// check for compile
var main = env->get(str("main"))
if !is_err(main) {
println("Starting compile!")
match (get_value(main)) {
MalValue::Function(f) {
var main_s = str("int main(int argc, char** argv) {\n")
var inner_main = compile(&main_s, env, *f.body)
main_s += "return (" + inner_main + ")>>3;\n}\n"
write_file(str(argv[1]) + ".c", main_s)
println("Finished compile")
return 0
}
}
error("Main not a k' function")
} else {
println("No main function to compile, exiting")
}
} else {
env->set(str("*ARGV*"), MalValue::List(params))
rep(grammer, env, str("(println (str \"Mal [\" *host-language* \"]\"))"))
@@ -1412,3 +1417,188 @@ fun main(argc: int, argv: **char): int {
}
}
}
fun compile_value(defs: *str, env: *Env, ast: MalValue): str {
match (ast) {
/*MalValue::List(l) {*/
/*var to_ret = vec<MalValue>()*/
/*for (var i = 0; i < l.size; i++;) {*/
/*var mid = EVAL(env, l[i])*/
/*if is_err(mid) {*/
/*return mid*/
/*}*/
/*to_ret.add(get_value(mid))*/
/*}*/
/*return MalResult::Ok(MalValue::List(to_ret))*/
/*}*/
/*MalValue::Vector(l) {*/
/*var to_ret = vec<MalValue>()*/
/*for (var i = 0; i < l.size; i++;) {*/
/*var mid = EVAL(env, l[i])*/
/*if is_err(mid) {*/
/*return mid*/
/*}*/
/*to_ret.add(get_value(mid))*/
/*}*/
/*return MalResult::Ok(MalValue::Vector(to_ret))*/
/*}*/
MalValue::Symbol(s) {
/*return env->get(s)*/
return s
}
MalValue::Int(i) {
return to_string(i<<3)
}
}
/*return MalResult::Ok(ast)*/
error("could not compile value: " + pr_str(ast, true))
}
fun compile(defs: *str, env: *Env, ast: MalValue): str {
var expanded = macroexpand(ast, env)
if (is_err(expanded)) {
error("compile error in macroexpand: " + pr_str(get_err(expanded), true))
}
ast = get_value(expanded)
if !is_list(ast) {
return compile_value(defs, env, ast)
}
match (ast) {
MalValue::List(l) {
if (l.size == 0) {
return compile_value(defs, env, ast)
} else if (is_symbol(l[0], "def!")) {
if (l.size != 3) {
error("def! without exaclty key and value")
}
if (!is_symbol(l[1])) {
error("def! not on symbol")
}
var to_set_name = get_symbol_text(l[1])
var to_set_value = compile(defs, env, l[2])
*defs += "usize " + to_set_name + " = " + to_set_value + ";\n"
return to_set_name
} else if (is_symbol(l[0], "defmacro!")) {
error("defmacro! doesn't make sense in compiled code")
} else if (is_symbol(l[0], "let*")) {
if (l.size != 3) {
error("let* without list of bindings & end value")
}
if (!is_list_or_vec(l[1])) {
error("let* without list of bindings")
}
var bindings = get_list_or_vec(l[1])
if (bindings.size & 1 != 0) {
error("let* list of bindings has odd number of entries")
}
var new_env = new<Env>()->construct(env)
for (var i = 0; i < bindings.size; i+=2;) {
if (!is_symbol(bindings[i])) {
error("let* var name not symbol")
}
var to_set_value = compile(defs, new_env, bindings[i+1])
*defs += "usize " + get_symbol_text(bindings[i]) + " = " + to_set_value + ";\n"
/*var to_set_value = EVAL(new_env, bindings[i+1])*/
/*new_env->set(get_symbol_text(bindings[i]), get_value(to_set_value))*/
}
// tco
return compile(defs, new_env, l[2])
} else if (is_symbol(l[0], "do")) {
for (var i = 1; i < l.size-1; i++;) {
var _ = compile(defs, env, l[i])
*defs += ";\n"
}
return compile(defs, env, l[l.size-1])
} else if (is_symbol(l[0], "if")) {
if l.size != 3 && l.size != 4 {
error("if needs 2 or 3 children")
}
var cond = compile(defs, env, l[1])
var tmp_name = str("tmp")
*defs += "usize " + tmp_name + "; if (" + cond + ") {\n"
var then = compile(defs, env, l[2])
*defs += tmp_name + " = " + then + ";\n} else {\n"
var else_ = compile(defs, env, l[3])
*defs += tmp_name + " = " + else_ + ";\n}"
return tmp_name
} else if (is_symbol(l[0], "fn*")) {
error("compile fn* unimplemented")
/*if l.size != 3 {*/
/*return MalResult::Err(MalValue::String(str("fn* needs 2 children")))*/
/*}*/
/*if (!is_list_or_vec(l[1])) {*/
/*return MalResult::Err(MalValue::String(str("fn* without list of parameters")))*/
/*}*/
/*var parameters = get_list_or_vec(l[1])*/
/*var parameters_str = vec<str>()*/
/*var is_variadic = false*/
/*for (var i = 0; i < parameters.size; i++;) {*/
/*if (!is_symbol(parameters[i])) {*/
/*return MalResult::Err(MalValue::String(str("fn* parameter name not symbol")))*/
/*}*/
/*var symbol_text = get_symbol_text(parameters[i])*/
/*if symbol_text == "&" {*/
/*if i != parameters.size - 2 {*/
/*return MalResult::Err(MalValue::String(str("fn* has wrong number of arguments after &")))*/
/*}*/
/*if (!is_symbol(parameters[i+1])) {*/
/*return MalResult::Err(MalValue::String(str("fn* parameter name not symbol")))*/
/*}*/
/*is_variadic = true*/
/*i++*/
/*symbol_text = get_symbol_text(parameters[i])*/
/*}*/
/*parameters_str.add(symbol_text)*/
/*}*/
/*var to_ret.construct(env, parameters_str, is_variadic, false, l[2]): MalFunction*/
/*return MalResult::Ok(MalValue::Function(to_ret))*/
} else if (is_symbol(l[0], "quote")) {
if l.size == 1 {
error("compile quote with no arguments")
}
/*return MalResult::Ok(l[1])*/
return compile_value(defs, env, l[1])
} else if (is_symbol(l[0], "quasiquote")) {
if l.size == 1 {
error("compile quasiquote with no arguments")
/*return MalResult::Err(MalValue::String(str("quasiquote with no arguments")))*/
}
return compile(defs, env, quasiquote(l[1]))
/*var tmp = quasiquote(l[1])*/
/*ast = tmp*/
/*continue*/
} else if (is_symbol(l[0], "macroexpand")) {
error("macroexpand doesn't make sense while compiling")
/*if l.size == 1 {*/
/*return MalResult::Err(MalValue::String(str("macroexpand with no arguments")))*/
/*}*/
/*return macroexpand(l[1], env)*/
} else if (is_symbol(l[0], "try*")) {
error("compile try* unimplemented")
/*if l.size != 2 && (l.size != 3 || !is_list(l[2])) {*/
/*return MalResult::Err(MalValue::String(str("try* wrong arguments")))*/
/*}*/
/*var A = EVAL(env, l[1])*/
/*if l.size == 3 && is_err(A) {*/
/*var catch = get_list(l[2])*/
/*if catch.size != 3 || !is_symbol(catch[0], "catch*") || !is_symbol(catch[1]) {*/
/*return MalResult::Err(MalValue::String(str("catch* block malformed")))*/
/*}*/
/*var new_env = new<Env>()->construct(env)*/
/*env->set(get_symbol_text(catch[1]), get_err(A))*/
/*return EVAL(new_env, catch[2])*/
/*} else {*/
/*return A*/
/*}*/
} else {
error("Compiling function calls not implemented")
var to_call = vec<str>()
for (var i = 0; i < l.size; i++;) {
to_call.add(compile_value(defs, env, l[i]))
}
return to_call[0] + "(" + str(", ").join(to_call.slice(1,-1)) + ")"
}
}
}
return compile_value(defs, env, ast)
}