Working on C generator for k_prime, can compile single number return
This commit is contained in:
3
bf.kp
3
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)))
|
||||
|
||||
252
k_prime.krak
252
k_prime.krak
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user