diff --git a/bf.kp b/bf.kp index 6cb76b5..1b5ac17 100644 --- a/bf.kp +++ b/bf.kp @@ -47,3 +47,6 @@ (do ,(nth xs 4) (deref output)))))) (println (bf { ,>+++[<.>-] } [1337])) + +(def! main (fn* [argv] 2)) +;(def! main (fn* [] (+ 13 1))) diff --git a/k_prime.krak b/k_prime.krak index 915c70f..5648463 100644 --- a/k_prime.krak +++ b/k_prime.krak @@ -28,17 +28,20 @@ fun read_str(grammer: ref Grammer, s: str): pair, - Vector: vec, - 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, // 010 + List: vec, // 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, 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): MalResult { return MalResult::Err(MalValue::String(str("not implemented"))) })); - env->set(str("number?"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("seq"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); - env->set(str("conj"), make_builtin_function(fun(params: vec): MalResult { - return MalResult::Err(MalValue::String(str("not implemented"))) - })); // self-modifying grammer env->set(str("add_terminal"), make_builtin_function(fun(params: vec): 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 , 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() 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()*/ + /*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()*/ + /*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()->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()*/ + /*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()->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() + 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) +}