From 0d07d2299590154408650f1430c18dda78338f18 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 6 Sep 2020 12:19:19 -0400 Subject: [PATCH] Move to wrap and unwrap --- bf.kp | 3 + k_prime.krak | 198 ++++++++++++++++-------- prelude.kp => k_prime_stdlib/prelude.kp | 18 ++- method.kp | 90 +++++------ quick_test.krak | 15 -- quick_test2.krak | 20 --- quick_test3.krak | 12 -- test_function_value.krak | 10 -- 8 files changed, 181 insertions(+), 185 deletions(-) rename prelude.kp => k_prime_stdlib/prelude.kp (73%) delete mode 100644 quick_test.krak delete mode 100644 quick_test2.krak delete mode 100644 quick_test3.krak delete mode 100644 test_function_value.krak diff --git a/bf.kp b/bf.kp index f310173..cf84bb6 100644 --- a/bf.kp +++ b/bf.kp @@ -1,3 +1,6 @@ + +(load-file "./k_prime_stdlib/prelude.kp") + ; We don't have atoms built in, mutable vectors ; are our base building block. In order to make the ; following BF implementation nice, let's add atoms! diff --git a/k_prime.krak b/k_prime.krak index 9f531f5..0e4030b 100644 --- a/k_prime.krak +++ b/k_prime.krak @@ -91,14 +91,17 @@ obj KPEnv (Object) { } obj KPBuiltinCombiner (Object) { var name: str + var wrap_level: int var fp: fun(vec, *KPEnv): KPResult - fun construct(name: ref str, fp: fun(vec, *KPEnv): KPResult): *KPBuiltinCombiner { + fun construct(name: ref str, wrap_level: int, fp: fun(vec, *KPEnv): KPResult): *KPBuiltinCombiner { this->name.copy_construct(&name) + this->wrap_level = wrap_level this->fp = fp return this } fun copy_construct(old: *KPBuiltinCombiner): void { this->fp = old->fp + this->wrap_level = old->wrap_level this->name.copy_construct(&old->name) } fun destruct(): void { @@ -115,22 +118,33 @@ obj KPBuiltinCombiner (Object) { if !dynamic_env.is_env() { return KPResult::Err(kpString(pr_str(dynamic_env, true) + " is not an env")) } + for (var l = 0; l < wrap_level; l++;) { + for (var i = 0; i < params.size; i++;) { + var intermediate = EVAL(dynamic_env.get_env(), params[i]); + if is_err(intermediate) { + return intermediate; + } + params[i] = get_value(intermediate); + } + } return fp(params, dynamic_env.get_env()) } } -fun make_builtin_combiner(name: str, f: fun(vec, *KPEnv): KPResult): KPValue { - var to_ret.construct(name, f): KPBuiltinCombiner +fun make_builtin_combiner(name: str, wrap_level: int, f: fun(vec, *KPEnv): KPResult): KPValue { + var to_ret.construct(name, wrap_level, f): KPBuiltinCombiner return nmMV(KPValue_int::BuiltinCombiner(to_ret)) } obj KPCombiner (Object) { var env: *KPEnv var dynamic_env_name: str + var wrap_level: int var parameters: vec var is_variadic: bool var body: *KPValue fun construct(env: *KPEnv, dynamic_env_name: str, parameters: vec, is_variadic: bool, body: KPValue): *KPCombiner { this->env = env this->dynamic_env_name.copy_construct(&dynamic_env_name) + this->wrap_level = 0 this->parameters.copy_construct(¶meters) this->is_variadic = is_variadic this->body = new() @@ -140,6 +154,7 @@ obj KPCombiner (Object) { fun copy_construct(old: *KPCombiner): void { this->env = old->env this->dynamic_env_name.copy_construct(&old->dynamic_env_name) + this->wrap_level = old->wrap_level this->parameters.copy_construct(&old->parameters) this->is_variadic = old->is_variadic this->body = new() @@ -158,10 +173,22 @@ obj KPCombiner (Object) { } fun operator==(other: ref KPCombiner):bool { // not sure about env - return env == other.env && dynamic_env_name == other.dynamic_env_name && parameters == other.parameters && is_variadic == other.is_variadic && body->equals(*other.body) + return env == other.env && dynamic_env_name == other.dynamic_env_name && wrap_level == other.wrap_level && parameters == other.parameters && is_variadic == other.is_variadic && body->equals(*other.body) } // no call b/c need to do in EVAL for TCO fun prep_call(params: ref vec, dynamic_env: KPValue): pair<*KPEnv, KPResult> { + for (var l = 0; l < wrap_level; l++;) { + if !dynamic_env.is_env() { + return make_pair(null(), KPResult::Err(kpString(str("called combiner with wrap_level") + wrap_level + "with bad dynamic_env " + pr_str(dynamic_env, true)))); + } + for (var i = 0; i < params.size; i++;) { + var intermediate = EVAL(dynamic_env.get_env(), params[i]); + if is_err(intermediate) { + return make_pair(null(), intermediate); + } + params[i] = get_value(intermediate); + } + } // tco if (!is_variadic && parameters.size != params.size) || (is_variadic && parameters.size > params.size + 1) { return make_pair(null(), KPResult::Err(kpString(str("combiner called with the wrong number of parameters: ") + params.size + " but expecting " + parameters.size + ": [ " + str(",").join(parameters) + "], was: " + pr_str(kpVector(params), true) + ", function body is " + pr_str(*body, true)))) @@ -506,10 +533,10 @@ fun pr_str(v: KPValue, print_readably: bool): str { } } KPValue_int::BuiltinCombiner(f) { - return "builtin_combiner_" + f.name + return "builtin_combiner_" + f.name + "(wrap_level: " + f.wrap_level + ")" } KPValue_int::Combiner(f) { - return str("combiner") + return str("combiner(wrap_level: ") + f.wrap_level + ")" } KPValue_int::Env(e) { return str("environment") @@ -579,6 +606,10 @@ fun EVAL(env: *KPEnv, ast: KPValue): KPResult { } } +fun function_call(f: KPValue, params: ref vec, env: KPValue): KPResult { + return EVAL(env.get_env(), kpVector(vec(f) + params)) +} + fun rep(grammar: ref Grammer, env: *KPEnv, a: str): str { var read = READ(grammar, a) if is_err(read) { @@ -593,22 +624,6 @@ fun rep(grammar: ref Grammer, env: *KPEnv, a: str): str { } } -fun function_call(f: KPValue, params: ref vec, env: KPValue): KPResult { - match (f.internal) { - KPValue_int::BuiltinCombiner(f) { - return f.call(params, env) - } - KPValue_int::Combiner(f) { - var call_pair = f.prep_call(params, env) - if is_err(call_pair.second) { - return call_pair.second - } - return EVAL(call_pair.first, get_value(call_pair.second)) - } - } - return KPResult::Err(kpString(str("trying to apply not a combiner: ") + pr_str(f ,true))) -} - fun str_wrapper(params: ref vec, dynamic_env: *KPEnv, sep: *char, print_readably: bool): KPResult { var to_ret = str() for (var i = 0; i < params.size; i++;) { @@ -709,7 +724,7 @@ fun main(argc: int, argv: **char): int { var env = new()->construct() - env->set(str("vau"), make_builtin_combiner(str("vau"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("vau"), make_builtin_combiner(str("vau"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var param_symbols = vec() if params.size != 3 { return KPResult::Err(kpString(str("bad number of params to vau"))) @@ -738,7 +753,7 @@ fun main(argc: int, argv: **char): int { var to_ret.construct(dynamic_env, dynamic_env_name, parameters, is_variadic, params[2]) : KPCombiner return KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret))) })); - env->set(str("eval"), make_builtin_combiner(str("eval"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("eval"), make_builtin_combiner(str("eval"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var evaled_params = vec() for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -758,7 +773,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Err(kpString(str("wrong number of params to eval"))) })); - env->set(str("set!"), make_builtin_combiner(str("set!"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("set!"), make_builtin_combiner(str("set!"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("not 2 params to set!"))) } @@ -773,7 +788,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpNil()) })); - env->set(str("cond"), make_builtin_combiner(str("cond"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("cond"), make_builtin_combiner(str("cond"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if (params.size % 2) != 0 { return KPResult::Err(kpString(str("Need even number of params to cond"))) } @@ -789,7 +804,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpNil()) })); - env->set(str("symbol?"), make_builtin_combiner(str("symbol?"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("symbol?"), make_builtin_combiner(str("symbol?"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 1 { return KPResult::Err(kpString(str("Need 1 param to symbol?"))) } @@ -800,7 +815,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpBool(get_value(ip).is_symbol())) })); - env->set(str("get-text"), make_builtin_combiner(str("get-text"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("get-text"), make_builtin_combiner(str("get-text"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 1 { return KPResult::Err(kpString(str("Need 1 param to get-text"))) } @@ -815,7 +830,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpString(iv.get_symbol_text())) })); - env->set(str("vector"), make_builtin_combiner(str("vector"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("vector"), make_builtin_combiner(str("vector"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var evaled_params = vec() for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -826,7 +841,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpVector(evaled_params)) })); - env->set(str("vector?"), make_builtin_combiner(str("vector?"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("vector?"), make_builtin_combiner(str("vector?"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 1 { return KPResult::Err(kpString(str("Need 1 param to vector?"))) } @@ -836,7 +851,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpBool(get_value(ip).is_vector())) })); - env->set(str("len"), make_builtin_combiner(str("len"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("len"), make_builtin_combiner(str("len"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 1 { return KPResult::Err(kpString(str("Need 1 param to len"))) } @@ -844,7 +859,7 @@ fun main(argc: int, argv: **char): int { if is_err(v) { return v; } return KPResult::Ok(kpInt(get_value(v).get_vector_rc().get().size)) })); - env->set(str("idx"), make_builtin_combiner(str("idx"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("idx"), make_builtin_combiner(str("idx"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("Need 2 params to idx"))) } @@ -859,7 +874,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(vv.get_vector_rc().get()[iv.get_int()]) })); - env->set(str("set-idx!"), make_builtin_combiner(str("set-idx!"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("set-idx!"), make_builtin_combiner(str("set-idx!"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 3 { return KPResult::Err(kpString(str("Need 3 params to set-idx!"))) } @@ -880,7 +895,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpNil()) })); - env->set(str("concat"), make_builtin_combiner(str("concat"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("concat"), make_builtin_combiner(str("concat"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var to_ret = vec() for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -893,7 +908,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpVector(to_ret)) })); - env->set(str("slice"), make_builtin_combiner(str("slice"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("slice"), make_builtin_combiner(str("slice"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 3 { return KPResult::Err(kpString(str("Need 3 params to slice"))) } @@ -916,7 +931,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpVector(lv.get_vector_rc().get().slice(start, end))) })); - env->set(str("+"), make_builtin_combiner(str("+"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("+"), make_builtin_combiner(str("+"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var to_ret = 0 for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -931,7 +946,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpInt(to_ret)) })); - env->set(str("-"), make_builtin_combiner(str("-"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("-"), make_builtin_combiner(str("-"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var to_ret = 0 for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -950,7 +965,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpInt(to_ret)) })); - env->set(str("*"), make_builtin_combiner(str("*"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("*"), make_builtin_combiner(str("*"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var to_ret = 1 for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -965,7 +980,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpInt(to_ret)) })); - env->set(str("/"), make_builtin_combiner(str("/"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("/"), make_builtin_combiner(str("/"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var to_ret = 1 for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -984,7 +999,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpInt(to_ret)) })); - env->set(str("%"), make_builtin_combiner(str("%"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("%"), make_builtin_combiner(str("%"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var to_ret = 1 for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -1004,7 +1019,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpInt(to_ret)) })); - env->set(str("="), make_builtin_combiner(str("="), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("="), make_builtin_combiner(str("="), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("Need 2 params to ="))) } @@ -1014,7 +1029,7 @@ fun main(argc: int, argv: **char): int { if is_err(b) { return b; } return KPResult::Ok(kpBool(get_value(a).equals(get_value(b)))) })); - env->set(str("!="), make_builtin_combiner(str("!="), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("!="), make_builtin_combiner(str("!="), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("Need 2 params to !="))) } @@ -1024,7 +1039,7 @@ fun main(argc: int, argv: **char): int { if is_err(b) { return b; } return KPResult::Ok(kpBool(!get_value(a).equals(get_value(b)))) })); - env->set(str("<"), make_builtin_combiner(str("<"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("<"), make_builtin_combiner(str("<"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("Need 2 params to <"))) } @@ -1038,7 +1053,7 @@ fun main(argc: int, argv: **char): int { if !bv.is_int() { return KPResult::Err(kpString(str("called < with second not an int"))); } return KPResult::Ok(kpBool(av.get_int() < bv.get_int())) })); - env->set(str("<="), make_builtin_combiner(str("<="), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("<="), make_builtin_combiner(str("<="), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("Need 2 params to <="))) } @@ -1052,7 +1067,7 @@ fun main(argc: int, argv: **char): int { if !bv.is_int() { return KPResult::Err(kpString(str("called <= with second not an int"))); } return KPResult::Ok(kpBool(av.get_int() <= bv.get_int())) })); - env->set(str(">"), make_builtin_combiner(str(">"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str(">"), make_builtin_combiner(str(">"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("Need 2 params to >"))) } @@ -1066,7 +1081,7 @@ fun main(argc: int, argv: **char): int { if !bv.is_int() { return KPResult::Err(kpString(str("called > with second not an int"))); } return KPResult::Ok(kpBool(av.get_int() > bv.get_int())) })); - env->set(str(">="), make_builtin_combiner(str(">="), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str(">="), make_builtin_combiner(str(">="), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("Need 2 params to >="))) } @@ -1081,7 +1096,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpBool(av.get_int() >= bv.get_int())) })); - env->set(str("and"), make_builtin_combiner(str("and"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("and"), make_builtin_combiner(str("and"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) if is_err(ip) { return ip; } @@ -1092,7 +1107,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpFalse()) })); - env->set(str("or"), make_builtin_combiner(str("or"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("or"), make_builtin_combiner(str("or"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) if is_err(ip) { return ip; } @@ -1104,26 +1119,26 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpFalse()) })); - env->set(str("pr-str"), make_builtin_combiner(str("pr-str"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("pr-str"), make_builtin_combiner(str("pr-str"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { return str_wrapper(params, dynamic_env, " ", true) })); - env->set(str("str"), make_builtin_combiner(str("str"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("str"), make_builtin_combiner(str("str"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { return str_wrapper(params, dynamic_env, "", false) })); - env->set(str("prn"), make_builtin_combiner(str("prn"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("prn"), make_builtin_combiner(str("prn"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var to_print = str_wrapper(params, dynamic_env, " ", true) if is_err(to_print) { return to_print; } println(get_value(to_print).get_string()) return KPResult::Ok(kpNil()) })); - env->set(str("println"), make_builtin_combiner(str("println"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("println"), make_builtin_combiner(str("println"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var to_print = str_wrapper(params, dynamic_env, " ", false) if is_err(to_print) { return to_print; } println(get_value(to_print).get_string()) return KPResult::Ok(kpNil()) })); - env->set(str("meta"), make_builtin_combiner(str("meta"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("meta"), make_builtin_combiner(str("meta"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 1 { return KPResult::Err(kpString(str("meta called with not one argument"))) } else { @@ -1137,7 +1152,7 @@ fun main(argc: int, argv: **char): int { } } })); - env->set(str("with-meta"), make_builtin_combiner(str("with-meta"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("with-meta"), make_builtin_combiner(str("with-meta"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("with-meta called with not two arguments"))) } else { @@ -1154,7 +1169,7 @@ fun main(argc: int, argv: **char): int { })); // self-modifying grammar - env->set(str("add_terminal"), make_builtin_combiner(str("add_terminal"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("add_terminal"), make_builtin_combiner(str("add_terminal"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("add_terminal called with wrong number (not 2) params"))) } else { @@ -1241,7 +1256,7 @@ fun main(argc: int, argv: **char): int { } return KPResult::Ok(kpInt(grammar.add_to_or_create_nonterminal(nonterminal_str, int_rule, data, f))) } - env->set(str("add_grammar_rule"), make_builtin_combiner(str("add_grammar_rule"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("add_grammar_rule"), make_builtin_combiner(str("add_grammar_rule"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { var params_evaled = vec() for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) @@ -1330,9 +1345,9 @@ fun main(argc: int, argv: **char): int { return current_ret } } - env->set(str("eval-read-string"), make_builtin_combiner(str("eval-read-string"), ERS)); + env->set(str("eval-read-string"), make_builtin_combiner(str("eval-read-string"), 0, ERS)); - env->set(str("read-string"), make_builtin_combiner(str("read-string"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("read-string"), make_builtin_combiner(str("read-string"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 1 { return KPResult::Err(kpString(str("read-string with not a single string"))) } else { @@ -1345,7 +1360,7 @@ fun main(argc: int, argv: **char): int { return READ(grammar, ipv.get_string()) } })); - env->set(str("slurp"), make_builtin_combiner(str("slurp"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("slurp"), make_builtin_combiner(str("slurp"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 1 { return KPResult::Err(kpString(str("slurp with not a single string"))) } else { @@ -1355,12 +1370,57 @@ fun main(argc: int, argv: **char): int { if !ipv.is_string() { return KPResult::Err(kpString(str("read-string with not a single string"))) } + if !file_exists(ipv.get_string()) { + return KPResult::Err(kpString(str("read-string with bad path ") + ipv.get_string())) + } return KPResult::Ok(kpString(read_file(ipv.get_string()))) } })); - env->set(str("map"), make_builtin_combiner(str("map"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("wrap"), make_builtin_combiner(str("wrap"), 1, fun(params: vec, dynamic_env: *KPEnv): KPResult { + if params.size != 1 { + return KPResult::Err(kpString(str("wrap called with not one argument"))) + } + match (params[0].internal) { + KPValue_int::Combiner(c) { + var to_ret = c; + to_ret.wrap_level++ + return KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret))) + } + KPValue_int::BuiltinCombiner(c) { + var to_ret = c; + to_ret.wrap_level++ + return KPResult::Ok(nmMV(KPValue_int::BuiltinCombiner(to_ret))) + } + } + return KPResult::Err(kpString(str("wrap called with not combiner ") + pr_str(params[0], true))) + })); + env->set(str("unwrap"), make_builtin_combiner(str("unwrap"), 1, fun(params: vec, dynamic_env: *KPEnv): KPResult { + if params.size != 1 { + return KPResult::Err(kpString(str("unwrap called with not one argument"))) + } + match (params[0].internal) { + KPValue_int::Combiner(c) { + if c.wrap_level <= 0 { + return KPResult::Err(kpString(str("unwrap called with combiner at wrap_level <= 0"))) + } + var to_ret = c; + to_ret.wrap_level-- + return KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret))) + } + KPValue_int::BuiltinCombiner(c) { + if c.wrap_level <= 0 { + return KPResult::Err(kpString(str("unwrap called with combiner at wrap_level <= 0"))) + } + var to_ret = c; + to_ret.wrap_level-- + return KPResult::Ok(nmMV(KPValue_int::BuiltinCombiner(to_ret))) + } + } + return KPResult::Err(kpString(str("unwrap called with not combiner ") + pr_str(params[0], true))) + })); + env->set(str("map"), make_builtin_combiner(str("map"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { - return KPResult::Err(kpString(str("map called with not one argument"))) + return KPResult::Err(kpString(str("map called with not two arguments"))) } else { var fr = EVAL(dynamic_env, params[0]) if is_err(fr) { return fr; } @@ -1368,7 +1428,6 @@ fun main(argc: int, argv: **char): int { if !f.is_combiner() { return KPResult::Err(kpString(str("map called with not combiner"))) } - var lr = EVAL(dynamic_env, params[1]) if is_err(lr) { return lr; } var l = get_value(lr) @@ -1386,7 +1445,7 @@ fun main(argc: int, argv: **char): int { return KPResult::Ok(kpVector(to_ret)) } })); - env->set(str("filter"), make_builtin_combiner(str("filter"), fun(params: vec, dynamic_env: *KPEnv): KPResult { + env->set(str("filter"), make_builtin_combiner(str("filter"), 0, fun(params: vec, dynamic_env: *KPEnv): KPResult { if params.size != 2 { return KPResult::Err(kpString(str("filter called with not one argument"))) } else { @@ -1415,14 +1474,17 @@ fun main(argc: int, argv: **char): int { } })); - // more self-implementation fun + // a tiny bit of self-implementation fun println(rep(grammar, env, str("(set! load-file (vau de (f) (eval-read-string (slurp (eval f de)) de)))"))) - println(rep(grammar, env, str("(load-file \"prelude.kp\")"))) - - if argc == 3 && str(argv[1]) == "-C" { - error("-C not implemented") + env->set(str("*ARGV*"), kpNil()) + var evaled = ERS(vec(kpString(str(argv[2])), kpEnv(env)), env) + if is_err(evaled) { + printlnerr(str("Exception: ") + pr_str(get_err(evaled), true)) + } else { + println("Result: " + pr_str(get_value(evaled), true)) + } } else if argc >= 2 { var params = vec() for (var i = 2; i < argc; i++;) { diff --git a/prelude.kp b/k_prime_stdlib/prelude.kp similarity index 73% rename from prelude.kp rename to k_prime_stdlib/prelude.kp index b63f00e..9bd82d9 100644 --- a/prelude.kp +++ b/k_prime_stdlib/prelude.kp @@ -5,18 +5,20 @@ (add_grammar_rule (quote form) (quote ( "'" optional_WS form )) (vau de (_ _ f) (vector quote (eval f de)))) (add_grammar_rule 'form '( "\\[" optional_WS space_forms optional_WS "\\]" ) (vau de (_ _ fs _ _) (concat (vector vector) (eval fs de)))) -(set! apply (vau de (f p ede) (eval (concat [(eval f de)] (eval p de)) (eval ede de)))) +(set! vapply (vau de (f p ede) (eval (concat [(eval f de)] (eval p de)) (eval ede de)))) (set! let1 (vau de (s v b) (eval [[vau '_ [s] b] (eval v de)] de))) -(set! let (vau de (vs b) (cond (= (len vs) 0) (eval b de) true (apply let1 [(idx vs 0) (idx vs 1) [let (slice vs 2 -1) b]] de)))) -(set! lambda (vau se (p b) (let1 f (eval [vau '_ p b] se) (vau de (& op) (apply f (map (vau dde (ip) (eval (eval ip dde) de)) op) se))))) +(set! let (vau de (vs b) (cond (= (len vs) 0) (eval b de) true (vapply let1 [(idx vs 0) (idx vs 1) [let (slice vs 2 -1) b]] de)))) +;(set! lambda (vau se (p b) (let1 f (eval [vau '_ p b] se) (vau de (& op) (vapply f (map (vau dde (ip) (eval (eval ip dde) de)) op) se))))) +(set! lambda (vau se (p b) (wrap (eval [vau '_ p b] se)))) (set! fun (vau se (n p b) (eval [set! n [lambda p b]] se))) +(fun lapply (f p) (eval (concat [(unwrap f)] p) (current-env))) +(fun do (& params) (cond + (= 0 (len params)) nil + true (idx params (- (len params) 1)))) (set! if (vau de (con than & else) (cond (eval con de) (eval than de) (> (len else) 0) (eval (idx else 0) de) true nil))) -(fun do (& params) (cond - (= 0 (len params)) nil - true (idx params (- (len params) 1)))) (fun print_through (x) (let (_ (println x)) x)) (fun is_pair? (x) (and (vector? x) (> (len x) 0))) @@ -27,9 +29,9 @@ (eval (idx x 1) de) true (cond (and (is_pair? (idx x 0)) (symbol? (idx (idx x 0) 0)) (= (get-text (idx (idx x 0) 0)) "splice-unquote")) - (concat (eval (idx (idx x 0) 1) de) (apply quasiquote [(slice x 1 -1)] de)) + (concat (eval (idx (idx x 0) 1) de) (vapply quasiquote [(slice x 1 -1)] de)) true - (concat [(apply quasiquote [(idx x 0)] de)] (apply quasiquote [(slice x 1 -1)] de)))) + (concat [(vapply quasiquote [(idx x 0)] de)] (vapply quasiquote [(slice x 1 -1)] de)))) true x))) (add_grammar_rule 'form '("`" optional_WS form) (lambda (_ _ f) ['quasiquote f])) diff --git a/method.kp b/method.kp index 901f080..04ab648 100644 --- a/method.kp +++ b/method.kp @@ -1,58 +1,44 @@ +; Load prelude so we get fun, lambda, if, quoting, etc +(load-file "./k_prime_stdlib/prelude.kp") +; First quick lookup function, since maps are not built in +(fun get-value-helper (dict key i) (if (>= i (len dict)) + nil + (if (= key (idx dict i)) + (idx dict (+ i 1)) + (get-value-helper dict key (+ i 2))))) +(fun get-value (dict key) (get-value-helper dict key 0)) -(def! get-value-helper (fn* (dict key idx) (if (>= idx (count dict)) nil (if (= key (nth dict idx)) (nth dict (+ idx 1)) (get-value-helper dict key (+ idx 2)))))) -(def! get-value (fn* (dict key) (get-value-helper dict key 0))) -(def! method-call (fn* (object method & arguments) (let* (method_fn (get-value (meta object) method)) +; Our actual method call function +(fun method-call (object method & arguments) (let (method_fn (get-value (meta object) method)) (if (= method_fn nil) (println "no method " method) - (apply method_fn object arguments))))) -; method call syntax -(add_grammar_rule 'form [ 'form "\\." 'atom 'optional_WS "\\(" 'optional_WS 'space_forms 'optional_WS "\\)" ] (fn* (o _ m _ _ _ p _ _) `(method-call ~o '~m ,p))) -; object syntax -(def! flatten (fn* (l) (let* - (flatten-helper (fn* (l a f) (if (> (count l) 0) - (f (rest l) (concat a (first l)) f) - a))) - (flatten-helper l [] flatten-helper)))) -(add_grammar_rule 'form [ "obj" 'optional_WS 'atom 'optional_WS "{" 'optional_WS 'form 'optional_WS [ 'atom 'optional_WS 'form 'optional_WS ] + "}" ] (fn* (_ _ name _ _ _ constructor _ methods _) - (let* (processed_methods (flatten (map (fn* (m) [`'~(nth m 0) (nth m 2)]) methods))) - `(def! ~name (fn* (& args) (with-meta (apply ~constructor args) [ ,processed_methods ] )))))) -obj my_constructor { - (fn* () [17]) - inc (fn* (o) (set-nth! o 0 (+ (nth o 0) 1))) - dec (fn* (o) (set-nth! o 0 (- (nth o 0) 1))) - set (fn* (o n) (set-nth! o 0 n)) - get (fn* (o) (nth o 0)) -} + (do (println "applying" method_fn (concat [object] arguments) ) (lapply method_fn (concat [object] arguments)))))) +; Some nice syntactic sugar for method calls +(add_grammar_rule 'form ['form "\\." 'atom 'optional_WS "\\(" 'optional_WS 'space_forms 'optional_WS "\\)"] + (lambda (o _ m _ _ _ p _ _) `(method-call ~o '~m ,p))) -(println "pre construct") -(def! actual_obj (my_constructor)) -(println "constructed" actual_obj) - -(println "here" actual_obj) -(println "here" (meta actual_obj)) - -(def! main (fn* () (do - (println "actual_obj" actual_obj) - (method-call actual_obj 'inc) - (println "actual_obj" actual_obj) - (println "with get: " (method-call actual_obj 'get)) - (println "actual_obj" actual_obj) - (method-call actual_obj 'dec) - (method-call actual_obj 'dec) - (println "actual_obj" actual_obj) - (println "setting old style 654") - (method-call actual_obj 'set 654) - (println "actual_obj" actual_obj) - (println "Ok, doing with new method call syntax") - actual_obj.inc() - (println "actual_obj" actual_obj) - (println "setting new style 1337") - actual_obj.set(1337) - (println "actual_obj" actual_obj) - (println "with get " actual_obj.get()) - 0))) +; Ok, let's create our object by hand for this example +(set! actual_obj (with-meta [0] [ + 'inc (lambda (o) (set-idx! o 0 (+ (idx o 0) 1))) + 'dec (lambda (o) (set-idx! o 0 (- (idx o 0) 1))) + 'set (lambda (o n) (set-idx! o 0 n)) + 'get (lambda (o) (idx o 0)) + ])) (do - (println "interp-main") - (main) - (println "done interp-main") + (println (meta actual_obj)) + ; Use our new sugar + actual_obj.set(1337) + actual_obj.inc() + (println "get: " actual_obj.get()) + actual_obj.dec() + (println "get: " actual_obj.get()) + + ; Use methods directly + (method-call actual_obj 'set 654) + (method-call actual_obj 'inc) + (println "get: " (method-call actual_obj 'get)) + (method-call actual_obj 'dec) + (method-call actual_obj 'dec) + (println "get: " (method-call actual_obj 'get)) + nil) diff --git a/quick_test.krak b/quick_test.krak deleted file mode 100644 index 39f792a..0000000 --- a/quick_test.krak +++ /dev/null @@ -1,15 +0,0 @@ - -fun first():int { return 12; } - -fun test(f: run():int):int { - return test2(fun():int { return f();}) -} - -fun test2(f: fun():int):int { - return f() -} - -fun main():int { - /*return test(first)*/ - return 0 -} diff --git a/quick_test2.krak b/quick_test2.krak deleted file mode 100644 index 35ec354..0000000 --- a/quick_test2.krak +++ /dev/null @@ -1,20 +0,0 @@ - -obj a { - var i: int - fun other() { - i = 1 - } - fun wasthatakey() { - fun() { - other() - /*i = 1*/ - }() - } -} - -fun main():int { - var b: a - b.wasthatakey() - return 0 -} - diff --git a/quick_test3.krak b/quick_test3.krak deleted file mode 100644 index f71a132..0000000 --- a/quick_test3.krak +++ /dev/null @@ -1,12 +0,0 @@ - - -fun main():int { - var I = 0 - fun() { - fun() { - I = 1 - }() - }() - return 0 -} - diff --git a/test_function_value.krak b/test_function_value.krak deleted file mode 100644 index 5c0e5d0..0000000 --- a/test_function_value.krak +++ /dev/null @@ -1,10 +0,0 @@ -fun call(f: fun(int, int):int):int { - return f(1,2) -} -fun main(argc: int, argv: **char): int { - var y = 20 - var a = fun(i: int, x: int): int { return i+x+y; } - /*return a(12, 11)*/ - return call(a) -} -