import mem:* import io:* import str:* import vec:* import vec_literals:* import util:* import map:* import rc:* import fungll:* adt KPValue_int { True, // 101 1 0 False, // 100 1 0 Env: *KPEnv, // 011 1 0 Combiner: KPCombiner, // 010 1 0 BuiltinCombiner: KPBuiltinCombiner, // ''' ' ' String: str, // 001 1 0 Symbol: str, // 000 1 0 Int: int, // 0 0 Array: rc>, //<10sizebits> 1 // same encoding, but encodes 0-length null ptr Nil // 00000000000 1 } obj KPEnv (Object) { var data: map var outer: *KPEnv fun construct(): *KPEnv { return construct(null()) } fun construct(outer: *KPEnv): *KPEnv { data.construct() this->outer = outer return this } fun copy_construct(old: *KPEnv): void { data.copy_construct(&old->data) outer = old->outer } fun destruct(): void { data.destruct() outer = null() } fun operator=(other:ref KPEnv):void { destruct() copy_construct(&other) } fun operator<(other: ref KPEnv):bool { if data.keys < other.data.keys || data.values < other.data.values { return true; } if (outer != null()) && ((other.outer == null()) || (*outer < *other.outer)) { return true; } return false; } fun set(key: str, val: KPValue) { data.set(key, val) } fun remove(key: str) { data.remove(key) } fun find(key: str): *KPEnv { if (data.contains_key(key)) { return this } else if (outer != null()) { return outer->find(key) } else { return null() } } fun get(key: *char): KPResult { return get(str(key)) } fun get(key: ref str): KPResult { var env = find(key) if (env != null()) { return KPResult::Ok(env->data.get(key)) } else { println(key + " wasn't found in:") println(to_string()) return KPResult::Err(kpString(str("'") + key + "' not found")) } } fun to_string(): str { var to_ret = str() to_string(str("\t"), to_ret) return to_ret } fun to_string(tabs: ref str, s: ref str) { for (var i = 0; i < data.keys.size; i++;) { s += tabs + data.keys[i] + ": " + pr_str(data.values[i], true) + "\n" /*s += tabs + data.keys[i] + "\n"*/ } if outer != null() { outer->to_string(tabs + "\t", s) } } } obj KPBuiltinCombiner (Object) { var name: str var wrap_level: int var tco_eval: bool var fp: fun(vec, *KPEnv): pair<*KPEnv, KPResult> fun construct(name: ref str, wrap_level: int, tco_eval: bool, fp: fun(vec, *KPEnv): pair<*KPEnv, KPResult>): *KPBuiltinCombiner { this->name.copy_construct(&name) this->wrap_level = wrap_level this->tco_eval = tco_eval this->fp = fp return this } fun copy_construct(old: *KPBuiltinCombiner): void { this->fp = old->fp this->wrap_level = old->wrap_level this->tco_eval = old->tco_eval this->name.copy_construct(&old->name) } fun destruct(): void { this->name.destruct() } fun operator=(other:ref KPBuiltinCombiner):void { destruct() copy_construct(&other) } fun operator==(other: ref KPBuiltinCombiner):bool { return name == other.name } fun operator<(other: ref KPBuiltinCombiner):bool { return name < other.name } fun call(params: vec, dynamic_env: KPValue): pair<*KPEnv, KPResult> { if !dynamic_env.is_env() { return make_pair(null(), 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 make_pair(null(), intermediate); } params[i] = get_value(intermediate); } } return fp(params, dynamic_env.get_env()) } } fun make_builtin_combiner(name: str, wrap_level: int, tco_eval: bool, f: fun(vec, *KPEnv): pair<*KPEnv,KPResult>): KPValue { var to_ret.construct(name, wrap_level, tco_eval, f): KPBuiltinCombiner return nmMV(KPValue_int::BuiltinCombiner(to_ret)) } obj KPCombiner (Object) { var env: *KPEnv var dynamic_env_name: str var uses_dynamic_env: bool var wrap_level: int var parameters: vec var is_variadic: bool var body: *KPValue fun construct(env: *KPEnv, dynamic_env_name: str, uses_dynamic_env: bool, parameters: vec, is_variadic: bool, body: KPValue): *KPCombiner { this->env = env this->dynamic_env_name.copy_construct(&dynamic_env_name) this->uses_dynamic_env = uses_dynamic_env this->wrap_level = 0 this->parameters.copy_construct(¶meters) this->is_variadic = is_variadic this->body = new() this->body->copy_construct(&body) return this } fun copy_construct(old: *KPCombiner): void { this->env = old->env this->dynamic_env_name.copy_construct(&old->dynamic_env_name) this->uses_dynamic_env = old->uses_dynamic_env this->wrap_level = old->wrap_level this->parameters.copy_construct(&old->parameters) this->is_variadic = old->is_variadic this->body = new() this->body->copy_construct(old->body) } fun destruct(): void { this->env = null() dynamic_env_name.destruct() parameters.destruct() delete(body) body = null() } fun operator=(other:ref KPCombiner):void { destruct() copy_construct(&other) } fun operator==(other: ref KPCombiner):bool { // not sure about env return env == other.env && dynamic_env_name == other.dynamic_env_name && uses_dynamic_env == other.uses_dynamic_env && wrap_level == other.wrap_level && parameters == other.parameters && is_variadic == other.is_variadic && body->equals(*other.body) } fun operator<(other: ref KPCombiner):bool { // not sure about env return *env < *other.env || dynamic_env_name < other.dynamic_env_name || uses_dynamic_env < other.uses_dynamic_env || wrap_level < other.wrap_level || parameters < other.parameters || is_variadic < other.is_variadic || body->lt(*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(kpArray(params), true) + ", function body is " + pr_str(*body, true)))) } var new_env = new()->construct(env) for (var i = 0; i < parameters.size; i++;) { if is_variadic && i == parameters.size - 1 { new_env->set(parameters[i], kpArray(params.slice(i, -1))) } else { new_env->set(parameters[i], params[i]) } } if uses_dynamic_env { new_env->set(dynamic_env_name, dynamic_env) } /*println("Calling with\n" + new_env->to_string())*/ return make_pair(new_env, KPResult::Ok(*body)) } } obj KPValue (Object) { var internal: KPValue_int var meta: *KPValue fun construct(): *KPValue { internal.copy_construct(&KPValue_int::Nil()); meta = null() } fun construct(i: ref KPValue_int, m: *KPValue): *KPValue { internal.copy_construct(&i); meta = m } fun copy_construct(other: *KPValue): void { internal.copy_construct(&other->internal); /*meta = other->meta*/ if other->meta != null() { meta = new() meta->copy_construct(other->meta) } else { meta = null() } } fun operator=(other: ref KPValue): void { destruct() copy_construct(&other) } fun destruct(): void { if meta != null() delete(meta) internal.destruct() } fun equals(other: ref KPValue): bool { match (internal) { KPValue_int::Array(d) { match (other.internal) { KPValue_int::Array(db) { if d.get().size != db.get().size { return false } for (var i = 0; i < d.get().size; i++;) { if !d.get()[i].equals(db.get()[i]) { return false } } return true } } } KPValue_int::String(d) { match (other.internal) { KPValue_int::String(db) { return d == db; } } } KPValue_int::Int(d) { match (other.internal) { KPValue_int::Int(db) { return d == db; } } } KPValue_int::Symbol(d) { match (other.internal) { KPValue_int::Symbol(db) { return d == db; } } } KPValue_int::Combiner(d){ match (other.internal) { KPValue_int::Combiner(db) { return d == db; } } } KPValue_int::BuiltinCombiner(d) { match (other.internal) { KPValue_int::BuiltinCombiner(db) { return d == db; } } } KPValue_int::Env(e) { match (other.internal) { KPValue_int::Env(eb) { return e == eb; } } } KPValue_int::True() { match (other.internal) { KPValue_int::True() { return true; } } } KPValue_int::False() { match (other.internal) { KPValue_int::False() { return true; } } } KPValue_int::Nil() { match (other.internal) { KPValue_int::Nil() { return true; } } } } return false } fun variant(): int { match (internal) { KPValue_int::Array(d) { return 0; } KPValue_int::String(d) { return 1; } KPValue_int::Int(d) { return 2; } KPValue_int::Symbol(d) { return 3; } KPValue_int::Combiner(d) { return 4; } KPValue_int::BuiltinCombiner(d) { return 5; } KPValue_int::Env(e) { return 6; } KPValue_int::True() { return 7; } KPValue_int::False() { return 8; } KPValue_int::Nil() { return 9; } } } fun operator<(other: ref KPValue):bool { return this->lt(other) } fun lt(other: ref KPValue): bool { var our_variant = variant() var their_variant = other.variant() if our_variant < their_variant { return true; } else if our_variant > their_variant { return false; } match (internal) { KPValue_int::Array(d) { match (other.internal) { KPValue_int::Array(db) { return d.get() < db.get(); } } } KPValue_int::String(d) { match (other.internal) { KPValue_int::String(db) { return d < db; } } } KPValue_int::Int(d) { match (other.internal) { KPValue_int::Int(db) { return d < db; } } } KPValue_int::Symbol(d) { match (other.internal) { KPValue_int::Symbol(db) { return d < db; } } } KPValue_int::Combiner(d){ match (other.internal) { KPValue_int::Combiner(db) { return d < db; } } } KPValue_int::BuiltinCombiner(d) { match (other.internal) { KPValue_int::BuiltinCombiner(db) { return d < db; } } } KPValue_int::Env(e) { match (other.internal) { KPValue_int::Env(eb) { return e < eb; } } } KPValue_int::True() { match (other.internal) { KPValue_int::True() { return false; } } } KPValue_int::False() { match (other.internal) { KPValue_int::False() { return false; } } } KPValue_int::Nil() { match (other.internal) { KPValue_int::Nil() { return false; } } } } return false } fun deep_clone(): KPValue { match (internal) { KPValue_int::Array(v) { return kpArray(v.get()) } KPValue_int::Env(e) { var newenv = new() newenv->copy_construct(e) return kpEnv(e) } } return *this } fun is_combiner(): bool { match (internal) { KPValue_int::Combiner(f) { return true } KPValue_int::BuiltinCombiner(f) { return true } } return false } fun is_env(): bool { match (internal) { KPValue_int::Env(e) { return true } } return false } fun get_env(): *KPEnv { match (internal) { KPValue_int::Env(e) { return e } } error("Tried to get env on not an env" + pr_str(*this, true)) } fun is_array(): bool { match (internal) { KPValue_int::Array(v) { return true } } return false } fun get_array_rc(): rc> { match (internal) { KPValue_int::Array(v) { return v } } error("Tried to get vec on not a vec" + pr_str(*this, true)) } fun is_symbol(): bool { match (internal) { KPValue_int::Symbol(s) { return true } } return false } fun is_symbol(text: *char): bool { match (internal) { KPValue_int::Symbol(s) { return s == text } } return false } fun get_symbol_text(): str { match (internal) { KPValue_int::Symbol(s) { return s } } error("get_symbol_text on not symbol") } fun is_string(): bool { match (internal) { KPValue_int::String(s) { return true } } return false } fun get_string(): str { match (internal) { KPValue_int::String(s) { return s } } error("get_string on not a string") } fun is_int(): bool { match (internal) { KPValue_int::Int(i) { return true } } return false } fun get_int(): int { match (internal) { KPValue_int::Int(i) { return i } } error("get_int on not an int") } fun is_nil(): bool { match (internal) { KPValue_int::Nil() { return true } } return false } fun is_bool(): bool { match (internal) { KPValue_int::True() { return true } KPValue_int::False() { return true } } return false } fun is_truthy(): bool { match (internal) { KPValue_int::False() { return false } KPValue_int::Nil() { return false } } return true } fun is_pair(): bool { return is_array() && get_array_rc().get().size > 0 } } fun nmMV(i: ref KPValue_int): KPValue { var to_ret.construct(i, null()): KPValue return to_ret } fun kpTrue(): KPValue { return nmMV(KPValue_int::True()) } fun kpFalse(): KPValue { return nmMV(KPValue_int::False()) } fun kpBool(b: bool): KPValue { if b { return nmMV(KPValue_int::True()) } else { return nmMV(KPValue_int::False()) } } fun kpString(s: ref str): KPValue { return nmMV(KPValue_int::String(s)) } fun kpSymbol(s: *char): KPValue { return kpSymbol(str(s)) } fun kpSymbol(s: ref str): KPValue { return nmMV(KPValue_int::Symbol(s)) } fun kpInt(i: int): KPValue { return nmMV(KPValue_int::Int(i)) } fun kpArray(v: ref vec): KPValue { var rcd.construct(v): rc> return nmMV(KPValue_int::Array(rcd)) } fun kpNil(): KPValue { return nmMV(KPValue_int::Nil()) } fun kpEnv(e: *KPEnv): KPValue { return nmMV(KPValue_int::Env(e)) } fun read_str(grammar: ref Grammer, s: str): pair { var BSR = fungll(grammar, grammar.start_symbol, s) var longest = -1 for (var i = 0; i < BSR.data.size; i++;) { if BSR.data[i].nonterminal == grammar.start_symbol && BSR.data[i].left == 0 && BSR.data[i].idx_into_rule == grammar.nonterminals[(-1*BSR.data[i].nonterminal)-1][BSR.data[i].rule_idx].size && BSR.data[i].right > longest { longest = BSR.data[i].right } } if longest >= 0 { println("trying to parse: " + s) println(str("length of BSR is: ") + BSR.size()) for (var i = 0; i < BSR.data.size; i++;) { println(str() + i + ": " + grammar.to_string(BSR.data[i])) } return make_pair(longest, grammar.eval_BSR(s.slice(0, longest), BSR)) } else { println("trying to parse: " + s) println(str("length of BSR is: ") + BSR.size()) for (var i = 0; i < BSR.data.size; i++;) { println(str() + i + ": " + grammar.to_string(BSR.data[i])) } println("Parse failed") return make_pair(-1, KPResult::Err(kpString(str("failed to parse")))) } } adt KPResult { Ok: KPValue, Err: KPValue } fun is_err(r: KPResult): bool { match (r) { KPResult::Err(e) { return true } } return false } fun get_err(r: KPResult): KPValue { match (r) { KPResult::Err(e) { return e } } error("get-err-not-error") } fun get_value(r: KPResult): KPValue { match (r) { KPResult::Ok(v) { return v } } error("get-value-is-error") } fun pr_str(v: KPValue, print_readably: bool): str { match (v.internal) { KPValue_int::Array(l) { var to_ret = str("( ") for (var i = 0; i < l.get().size; i++;) { if (i != 0) { to_ret += " " } to_ret += pr_str(l.get()[i], print_readably) } return to_ret + " )" } KPValue_int::Int(i) { return to_string(i) } KPValue_int::String(s) { if print_readably { var to_ret = str("\"") //" for (var i = 0; i < s.length(); i++;) { if s[i] == '\n' { to_ret += '\\' to_ret += 'n' } else if s[i] == '\\' || s[i] == '"' { to_ret += '\\' to_ret += s[i] } else { to_ret += s[i] } } return to_ret + "\"" //" } else { return s } } KPValue_int::Symbol(s) { if print_readably { return "'" + s } else { return s } } KPValue_int::BuiltinCombiner(f) { return "builtin_combiner_" + f.name + "(wrap_level: " + f.wrap_level + ")" } KPValue_int::Combiner(f) { return str("combiner(wrap_level: ") + f.wrap_level + ")" } KPValue_int::Env(e) { return str("environment") } KPValue_int::True() { return str("true") } KPValue_int::False() { return str("false") } KPValue_int::Nil() { return str("nil") } } error("can't print") } fun READ(grammar: ref Grammer, s: str): KPResult { var to_ret = read_str(grammar, s) if to_ret.first != s.length() { if is_err(to_ret.second) { return to_ret.second } else { println("parsed to var: " + pr_str(get_value(to_ret.second), true)) } error("parsed some, but not all, remaining: " + s.slice(to_ret.first, -1)) } return to_ret.second } fun EVAL(env: *KPEnv, ast: KPValue): KPResult { // for tco while (true) { match (ast.internal) { KPValue_int::Array(l) { if (l.get().size == 0) { return KPResult::Err(kpString(str("Eval a zero length array"))) } else { var combiner = EVAL(env, l.get()[0]) if is_err(combiner) { return combiner } /*println("About to call combiner evaled from " + pr_str(l.get()[0], true))*/ match (get_value(combiner).internal) { KPValue_int::BuiltinCombiner(f) { var call_pair = f.call(l.get().slice(1,-1), kpEnv(env)); if is_err(call_pair.second) || !f.tco_eval { return call_pair.second } // tco_eval is true, so do tco env = call_pair.first ast = get_value(call_pair.second) continue } KPValue_int::Combiner(f) { var call_pair = f.prep_call(l.get().slice(1, -1), kpEnv(env)) if is_err(call_pair.second) { return call_pair.second } env = call_pair.first ast = get_value(call_pair.second) continue } } return KPResult::Err(kpString(str("trying to call not a combiner: ") + pr_str(l.get()[0], true))) } } KPValue_int::Symbol(s) { return env->get(s) } } // everything else is self-evaluating return KPResult::Ok(ast) } } fun function_call(f: KPValue, params: ref vec, env: KPValue): KPResult { return EVAL(env.get_env(), kpArray(vec(f) + params)) } fun rep(grammar: ref Grammer, env: *KPEnv, a: str): str { var read = READ(grammar, a) if is_err(read) { return pr_str(get_err(read), true) } else { var evaled = EVAL(env, get_value(read)) if is_err(evaled) { return str("Exception: ") + pr_str(get_err(evaled), true) } else { return pr_str(get_value(evaled), 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++;) { to_ret += pr_str(params[i], print_readably) if i != params.size-1 { to_ret += sep } } return KPResult::Ok(kpString(to_ret)) } fun unwrap(f: KPValue): KPResult { match (f.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(f, true))) } var tmp_idx: int = 0 fun new_tmp(): str { tmp_idx += 1 return str("x") + tmp_idx } fun main(argc: int, argv: **char): int { var grammar.construct(): Grammer var ret_nil_term: fun(ref KPValue, ref str, int, int): KPResult = fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult { return KPResult::Ok(kpNil()); } var ret_nil_sym: fun(ref KPValue, ref vec): KPResult = fun(_: ref KPValue, x: ref vec): KPResult { return KPResult::Ok(kpNil()); } var ret_0_sym: fun(ref KPValue, ref vec): KPResult = fun(_: ref KPValue, x: ref vec): KPResult { return x[0]; } var ret_1_sym: fun(ref KPValue, ref vec): KPResult = fun(_: ref KPValue, x: ref vec): KPResult { return x[1]; } var WS = grammar.add_new_nonterminal("WS", vec(grammar.add_terminal("( | | |(;[ -~]* ))+", kpNil(), ret_nil_term)), kpNil(), ret_nil_sym) var optional_WS = grammar.add_new_nonterminal("optional_WS", vec(), kpNil(), ret_nil_sym) grammar.add_to_nonterminal(optional_WS, vec(WS), kpNil(), ret_nil_sym) var atom = grammar.add_new_nonterminal("atom", vec(grammar.add_terminal("-?[0-9]+", kpNil(), fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult { return KPResult::Ok(kpInt(string_to_num(input.slice(l,r)))); })), kpNil(), ret_0_sym) grammar.add_to_nonterminal(atom, vec(grammar.add_terminal("\"([#-[]| |[]-~]|(\\\\\\\\)|(\\\\n)|(\\\\t)|(\\*)|(\\\\0)| |[ -!]|(\\\\\"))*\"", kpNil(), fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult { //" var to_ret = str() for (var i = l+1; i < r-1; i++;) { if input[i] == '\\' { if input[i+1] == 'n' { to_ret += '\n' } else if input[i+1] == 't' { to_ret += '\t' } else if input[i+1] == '0' { to_ret += '\0' } else if input[i+1] == '\\' || input[i+1] == '"' { to_ret += input[i+1] } else { return KPResult::Err(kpString(str("bad string escape: ") + input[i+1])) } // skip i++ } else { to_ret += input[i] } } return KPResult::Ok(kpString(to_ret)); })), kpNil(), ret_0_sym) grammar.add_to_nonterminal(atom, vec(grammar.add_terminal("-|(([a-z]|[A-Z]|_|\\*|/|\\?|\\+|!|=|&|\\||<|>|%)([a-z]|[A-Z]|_|[0-9]|\\*|\\?|\\+|-|!|=|&|\\||<|>|%|\\.)*)", kpNil(), fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult { var s = input.slice(l,r) if s == "true" { return KPResult::Ok(kpTrue()); } else if s == "false" { return KPResult::Ok(kpFalse()); } else if s == "nil" { return KPResult::Ok(kpNil()); } else { return KPResult::Ok(kpSymbol(input.slice(l,r))); } })), kpNil(), ret_0_sym) var form = grammar.add_new_nonterminal("form", vec(atom), kpNil(), ret_0_sym) var space_forms = grammar.add_new_nonterminal("space_forms", vec(), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { return KPResult::Ok(kpArray(vec())) }) grammar.add_to_nonterminal(space_forms, vec(form), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { if is_err(x[0]) { return x[0] } return KPResult::Ok(kpArray(vec(get_value(x[0])))) }) grammar.add_to_nonterminal(space_forms, vec(form, WS, space_forms), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { if is_err(x[0]) { return x[0] } if is_err(x[2]) { return x[2] } return KPResult::Ok(kpArray(vec(get_value(x[0])) + get_value(x[2]).get_array_rc().get())) }) var call_form = grammar.add_new_nonterminal("call_form", vec(grammar.add_terminal("\\(", kpNil(), ret_nil_term), optional_WS, grammar.add_terminal("\\)", kpNil(), ret_nil_term)), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { return KPResult::Ok(kpArray(vec())); }) grammar.add_to_nonterminal(call_form, vec(grammar.add_terminal("\\(", kpNil(), ret_nil_term), optional_WS, space_forms, optional_WS, grammar.add_terminal("\\)", kpNil(), ret_nil_term)), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { return x[2]; }) grammar.add_to_nonterminal(form, vec(call_form), kpNil(), fun(_: ref KPValue, x: ref vec): KPResult { return x[0]; }) var start_symbol = grammar.add_new_nonterminal("start_symbol", vec(optional_WS, form, optional_WS), kpNil(), ret_1_sym) grammar.set_start_symbol(start_symbol) //grammar.set_start_symbol(form) var env = new()->construct() env->set(str("vau"), make_builtin_combiner(str("vau"), 0, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var param_symbols = vec() if params.size != 2 && params.size != 3 { return make_pair(null(), KPResult::Err(kpString(str("bad number of params to vau: ") + params.size))) } var uses_dynamic_env = params.size == 3 var offset = 0 var dynamic_env_name = str() if uses_dynamic_env { if !params[0].is_symbol() { return make_pair(null(), KPResult::Err(kpString(str("first param to vau is not symbol ") + pr_str(params[0], true)))) } dynamic_env_name = params[0].get_symbol_text() offset = 1 } var is_variadic = false var parameters = vec() if !params[offset+0].is_array() { return make_pair(null(), KPResult::Err(kpString(str("second param to vau is not array")))) } var parameter_objects = params[offset+0].get_array_rc() for (var i = 0; i < parameter_objects.get().size; i++;) { if !parameter_objects.get()[i].is_symbol() { return make_pair(null(), KPResult::Err(kpString(str("second param to vau has a not symbol member: ") + pr_str(parameter_objects.get()[i], true)))) } var parameter = parameter_objects.get()[i].get_symbol_text() if parameter == "&" { is_variadic = true } else { parameters.add(parameter) } } var to_ret.construct(dynamic_env, dynamic_env_name, uses_dynamic_env, parameters, is_variadic, params[offset+1]) : KPCombiner return make_pair(null(), KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret)))) })); // Uses TCO env->set(str("eval"), make_builtin_combiner(str("eval"), 1, true, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size == 1 { return make_pair(dynamic_env, KPResult::Ok(params[0])) } else if params.size == 2 { if !params[1].is_env() { return make_pair(null(), KPResult::Err(kpString(str("second param to eval is not an environment") + pr_str(params[1], true)))) } return make_pair(params[1].get_env(), KPResult::Ok(params[0])) } return make_pair(null(), KPResult::Err(kpString(str("wrong number of params to eval")))) })); // cond uses TCO env->set(str("cond"), make_builtin_combiner(str("cond"), 0, true, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if (params.size % 2) != 0 { return make_pair(null(), KPResult::Err(kpString(str("Need even number of params to cond, have: ") + params.size + " last is " + pr_str(params[params.size-1], true)))) } for (var i = 0; i < params.size; i+=2;) { var ip = EVAL(dynamic_env, params[i]) if is_err(ip) { return make_pair(null(), ip) } if get_value(ip).is_truthy() { // will be evaluated above because tco is true return make_pair(dynamic_env, KPResult::Ok(params[i+1])) } } var it = str() for (var i = 0; i < params.size; i+=1;) { it += pr_str(params[i], true) + " " } return make_pair(null(), KPResult::Err(kpString(str("None of cond branches were true: ") + it))) })); env->set(str("symbol?"), make_builtin_combiner(str("symbol?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to symbol?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_symbol()))) })); env->set(str("int?"), make_builtin_combiner(str("int?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to int?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_int()))) })); env->set(str("string?"), make_builtin_combiner(str("string?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to string?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_string()))) })); env->set(str("combiner?"), make_builtin_combiner(str("combiner?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to combiner?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_combiner()))) })); env->set(str("env?"), make_builtin_combiner(str("env?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to env?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_env()))) })); env->set(str("nil?"), make_builtin_combiner(str("nil?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to nil?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_nil()))) })); env->set(str("bool?"), make_builtin_combiner(str("bool?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to bool?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_bool()))) })); env->set(str("array?"), make_builtin_combiner(str("array?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to array?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_array()))) })); env->set(str("str-to-symbol"), make_builtin_combiner(str("str-to-symbol"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to str-to-symbol")))) } if !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("Called str-to-symbol with not a symbol")))) } return make_pair(null(), KPResult::Ok(kpSymbol(params[0].get_string()))) })); env->set(str("get-text"), make_builtin_combiner(str("get-text"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to get-text")))) } if !params[0].is_symbol() { return make_pair(null(), KPResult::Err(kpString(str("Called get-text with not a symbol")))) } return make_pair(null(), KPResult::Ok(kpString(params[0].get_symbol_text()))) })); env->set(str("array"), make_builtin_combiner(str("array"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { return make_pair(null(), KPResult::Ok(kpArray(params))) })); env->set(str("len"), make_builtin_combiner(str("len"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to len")))) } if !params[0].is_array() && !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("Called len with not an array/string ") + pr_str(params[0], true) + "\nenv was\n" + dynamic_env->to_string()))) } if params[0].is_array() { return make_pair(null(), KPResult::Ok(kpInt(params[0].get_array_rc().get().size))) } else { return make_pair(null(), KPResult::Ok(kpInt(params[0].get_string().length()))) } })); env->set(str("idx"), make_builtin_combiner(str("idx"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 2 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to idx")))) } if !params[0].is_array() && !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("Param 1 to idx is not string or array") + pr_str(params[0], true) + " " + "\nenv was\n" + dynamic_env->to_string()))); } if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("Param 2 to idx is not int ") + pr_str(params[1], true)))); } var index = params[1].get_int() var size = 0 if params[0].is_array() { size = params[0].get_array_rc().get().size } else { size = params[0].get_string().length() } if index < 0 { index += size } if index < 0 || index >= size { return make_pair(null(), KPResult::Err(kpString(str("idx out of bounds, tried to get index ") + index + " in " + pr_str(params[0], true)))) } if params[0].is_array() { return make_pair(null(), KPResult::Ok(params[0].get_array_rc().get()[index])) } else { return make_pair(null(), KPResult::Ok(kpInt((params[0].get_string()[index]) cast int))) } })); env->set(str("slice"), make_builtin_combiner(str("slice"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 3 { return make_pair(null(), KPResult::Err(kpString(str("Need 3 params to slice")))) } if !params[0].is_array() && !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("first param to slice is not string or array")))); } if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("second param to slice is not int")))); } var start = params[1].get_int(); if !params[2].is_int() { return make_pair(null(), KPResult::Err(kpString(str("third param to slice is not int ") + pr_str(params[2], true)))); } var end = params[2].get_int(); if params[0].is_array() { return make_pair(null(), KPResult::Ok(kpArray(params[0].get_array_rc().get().slice(start, end)))) } else { return make_pair(null(), KPResult::Ok(kpString(params[0].get_string().slice(start, end)))) } })); env->set(str("concat"), make_builtin_combiner(str("concat"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var to_ret = vec() for (var i = 0; i < params.size; i++;) { if !params[i].is_array() { return make_pair(null(), KPResult::Err(kpString(str("param to concat is not an array")))); } to_ret += params[i].get_array_rc().get() } return make_pair(null(), KPResult::Ok(kpArray(to_ret))); })); env->set(str("+"), make_builtin_combiner(str("+"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var to_ret = 0 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { KPValue_int::Int(v) { to_ret += v continue } } return make_pair(null(), KPResult::Err(kpString(str("called + with not an int: ") + pr_str(params[i], false)))) } return make_pair(null(), KPResult::Ok(kpInt(to_ret))) })); env->set(str("-"), make_builtin_combiner(str("-"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var to_ret = 0 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { KPValue_int::Int(v) { if i == 0 && params.size > 1 { to_ret += v } else { to_ret -= v } continue } } return make_pair(null(), KPResult::Err(kpString(str("called - with not an int: ") + pr_str(params[i], false)))) } return make_pair(null(), KPResult::Ok(kpInt(to_ret))) })); env->set(str("*"), make_builtin_combiner(str("*"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var to_ret = 1 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { KPValue_int::Int(v) { to_ret *= v continue } } return make_pair(null(), KPResult::Err(kpString(str("called * with not an int: ") + pr_str(params[i], false)))) } return make_pair(null(), KPResult::Ok(kpInt(to_ret))) })); env->set(str("/"), make_builtin_combiner(str("/"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var to_ret = 1 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { KPValue_int::Int(v) { if i == 0 { to_ret *= v } else { to_ret /= v } continue } } return make_pair(null(), KPResult::Err(kpString(str("called / with not an int: ") + pr_str(params[i], false)))) } return make_pair(null(), KPResult::Ok(kpInt(to_ret))) })); env->set(str("%"), make_builtin_combiner(str("%"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var to_ret = 1 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { KPValue_int::Int(v) { if i == 0 { to_ret *= v } else { to_ret = to_ret % v } continue } } return make_pair(null(), KPResult::Err(kpString(str("called % with not an int: ") + pr_str(params[i], false)))) } return make_pair(null(), KPResult::Ok(kpInt(to_ret))) })); env->set(str("&"), make_builtin_combiner(str("&"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 2 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to &")))) } if !params[0].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called & with first not an int")))); } if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called & with second not an int")))); } return make_pair(null(), KPResult::Ok(kpInt(params[0].get_int() & params[1].get_int()))) })); env->set(str("|"), make_builtin_combiner(str("|"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 2 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to |")))) } if !params[0].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called | with first not an int")))); } if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called | with second not an int")))); } return make_pair(null(), KPResult::Ok(kpInt(params[0].get_int() | params[1].get_int()))) })); env->set(str("<<"), make_builtin_combiner(str("<<"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 2 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to <<")))) } if !params[0].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called << with first not an int")))); } if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called << with second not an int")))); } return make_pair(null(), KPResult::Ok(kpInt(params[0].get_int() << params[1].get_int()))) })); env->set(str(">>"), make_builtin_combiner(str(">>"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 2 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 params to >>")))) } if !params[0].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called >> with first not an int")))); } if !params[1].is_int() { return make_pair(null(), KPResult::Err(kpString(str("called >> with second not an int")))); } return make_pair(null(), KPResult::Ok(kpInt(params[0].get_int() >> params[1].get_int()))) })); env->set(str("="), make_builtin_combiner(str("="), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size <= 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to =")))) } for (var i = 0; i < params.size - 1; i++;) { if !(params[i].equals(params[i+1])) { return make_pair(null(), KPResult::Ok(kpBool(false))) } } return make_pair(null(), KPResult::Ok(kpBool(true))) })); env->set(str("!="), make_builtin_combiner(str("!="), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size <= 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to !=")))) } for (var i = 0; i < params.size - 1; i++;) { if (params[i].equals(params[i+1])) { return make_pair(null(), KPResult::Ok(kpBool(false))) } } return make_pair(null(), KPResult::Ok(kpBool(true))) })); env->set(str("<"), make_builtin_combiner(str("<"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size <= 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to <")))) } for (var i = 0; i < params.size - 1; i++;) { if !(params[i].lt(params[i+1])) { return make_pair(null(), KPResult::Ok(kpBool(false))) } } return make_pair(null(), KPResult::Ok(kpBool(true))) })); env->set(str("<="), make_builtin_combiner(str("<="), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size <= 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to <=")))) } for (var i = 0; i < params.size - 1; i++;) { if !(params[i].lt(params[i+1])) && !(params[i].equals(params[i+1])) { return make_pair(null(), KPResult::Ok(kpBool(false))) } } return make_pair(null(), KPResult::Ok(kpBool(true))) })); env->set(str(">"), make_builtin_combiner(str(">"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size <= 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to >")))) } for (var i = 0; i < params.size - 1; i++;) { if params[i].lt(params[i+1]) || params[i].equals(params[i+1]) { return make_pair(null(), KPResult::Ok(kpBool(false))) } } return make_pair(null(), KPResult::Ok(kpBool(true))) })); env->set(str(">="), make_builtin_combiner(str(">="), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size <= 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 2 or more params to >=")))) } for (var i = 0; i < params.size - 1; i++;) { if params[i].lt(params[i+1]) { return make_pair(null(), KPResult::Ok(kpBool(false))) } } return make_pair(null(), KPResult::Ok(kpBool(true))) })); env->set(str("and"), make_builtin_combiner(str("and"), 0, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) if is_err(ip) { return make_pair(null(), ip); } var ipv = get_value(ip) if !ipv.is_truthy() || i == params.size - 1 { return make_pair(null(), ip) } } return make_pair(null(), KPResult::Ok(kpFalse())) })); env->set(str("or"), make_builtin_combiner(str("or"), 0, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { for (var i = 0; i < params.size; i++;) { var ip = EVAL(dynamic_env, params[i]) if is_err(ip) { return make_pair(null(), ip); } var ipv = get_value(ip) if ipv.is_truthy() || i == params.size - 1 { return make_pair(null(), ip) } } return make_pair(null(), KPResult::Ok(kpFalse())) })); env->set(str("pr-str"), make_builtin_combiner(str("pr-str"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { return make_pair(null(), str_wrapper(params, dynamic_env, " ", true)) })); env->set(str("str"), make_builtin_combiner(str("str"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { return make_pair(null(), str_wrapper(params, dynamic_env, "", false)) })); env->set(str("prn"), make_builtin_combiner(str("prn"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var to_print = str_wrapper(params, dynamic_env, " ", true) if is_err(to_print) { return make_pair(null(), to_print); } println(get_value(to_print).get_string()) return make_pair(null(), KPResult::Ok(kpNil())) })); env->set(str("println"), make_builtin_combiner(str("println"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { var to_print = str_wrapper(params, dynamic_env, " ", false) if is_err(to_print) { return make_pair(null(), to_print); } println(get_value(to_print).get_string()) return make_pair(null(), KPResult::Ok(kpNil())) })); env->set(str("meta"), make_builtin_combiner(str("meta"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("meta called with not one argument")))) } else { if params[0].meta != null() { return make_pair(null(), KPResult::Ok(*params[0].meta)) } else { return make_pair(null(), KPResult::Ok(kpNil())) } } })); env->set(str("with-meta"), make_builtin_combiner(str("with-meta"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 2 { return make_pair(null(), KPResult::Err(kpString(str("with-meta called with not two arguments")))) } else { var new_meta = new() new_meta->copy_construct(¶ms[1]) var new_value = params[0].deep_clone(); new_value.meta = new_meta return make_pair(null(), KPResult::Ok(new_value)) } })); env->set(str("wrap"), make_builtin_combiner(str("wrap"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), 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 make_pair(null(), KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret)))) } KPValue_int::BuiltinCombiner(c) { var to_ret = c; to_ret.wrap_level++ return make_pair(null(), KPResult::Ok(nmMV(KPValue_int::BuiltinCombiner(to_ret)))) } } return make_pair(null(), KPResult::Err(kpString(str("wrap called with not combiner ") + pr_str(params[0], true)))) })); env->set(str("unwrap"), make_builtin_combiner(str("unwrap"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("unwrap called with not one argument")))) } return make_pair(null(), unwrap(params[0])) })); env->set(str("error"), make_builtin_combiner(str("error"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("error called with not one argument")))) } return make_pair(null(), KPResult::Err(params[0])) })); env->set(str("recover"), make_builtin_combiner(str("recover"), 0, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 3 { return make_pair(null(), KPResult::Err(kpString(str("recover called with not three arguments")))) } var data = EVAL(dynamic_env, params[0]) if is_err(data) { if !params[1].is_symbol() { return make_pair(null(), KPResult::Err(kpString(str("recover called with not symbol as middle")))) } var new_env = new()->construct(dynamic_env) new_env->set(params[1].get_symbol_text(), get_err(data)) return make_pair(null(), EVAL(new_env, params[2])) } return make_pair(null(), data) })); var add_grammer_rule_helper: fun(ref Grammer, str, vec, KPValue, fun(ref KPValue, ref vec): KPResult): KPResult = fun(grammar: ref Grammer, nonterminal_str: str, rule: vec, data: KPValue, f: fun(ref KPValue, ref vec): KPResult): KPResult { var int_rule = vec() for (var i = 0; i < rule.size; i++;) { if rule[i].is_int() { int_rule.add(rule[i].get_int()) } else if rule[i].is_symbol() { var sub_nonterminal_idx = grammar.nonterminal_names.find(rule[i].get_symbol_text()) if sub_nonterminal_idx == -1 { return KPResult::Err(kpString(str("Couldn't find nonterminal: ") + rule[i].get_symbol_text())) } var sub_nonterminal = -1*(sub_nonterminal_idx+1) int_rule.add(sub_nonterminal) } else if rule[i].is_string() { int_rule.add(grammar.add_terminal(rule[i].get_string(), kpNil(), fun(f: ref KPValue, input: ref str, l: int, r: int): KPResult { return KPResult::Ok(kpString(input.slice(l,r))) })) } else if rule[i].is_array() { // A sequence! var sub_rule_names = nonterminal_str + "_seq_" + new_tmp() var inner_rule = add_grammer_rule_helper(grammar, sub_rule_names, rule[i].get_array_rc().get(), kpNil(), fun(_: ref KPValue, seq: ref vec): KPResult { var to_ret = vec() for (var i = 0; i < seq.size; i++;) { if is_err(seq[i]) { return seq[i] } to_ret.add(get_value(seq[i])) } return KPResult::Ok(kpArray(to_ret)) }) if is_err(inner_rule) { return inner_rule } int_rule.add(get_value(inner_rule).get_int()) } else { match (rule[i].internal) { KPValue_int::BuiltinCombiner(f) { if f.name == "+" || f.name == "*" { if int_rule.size == 0 { return KPResult::Err(kpString(str("add_grammar_rule has + or * in first position, with nothing to repeat"))) } var current = int_rule.last() var sub_rule_names = nonterminal_str + "_" + new_tmp() var new = grammar.add_to_or_create_nonterminal(sub_rule_names + "_one_or_more", vec(current), kpNil(), fun(f: ref KPValue, x: ref vec): KPResult { if is_err(x[0]) { return x[0]; } return KPResult::Ok(kpArray(vec(get_value(x[0])))) }) grammar.add_to_nonterminal(new, vec(current, new), kpNil(), fun(f: ref KPValue, x: ref vec): KPResult { if is_err(x[0]) { return x[0]; } if is_err(x[1]) { return x[1]; } return KPResult::Ok(kpArray(vec(get_value(x[0])) + get_value(x[1]).get_array_rc().get())) }) if f.name == "*" { new = grammar.add_to_or_create_nonterminal(sub_rule_names + "_zero_or_more", vec(new), kpNil(), fun(f: ref KPValue, x: ref vec): KPResult { if is_err(x[0]) { return x[0]; } return KPResult::Ok(get_value(x[0])) }) grammar.add_to_nonterminal(new, vec(), kpNil(), fun(f: ref KPValue, x: ref vec): KPResult { return KPResult::Ok(kpArray(vec())) }) } int_rule.last() = new continue } } } return KPResult::Err(kpString(str("add_grammar_rule called with not symbol, int, or string in rule"))) } } return KPResult::Ok(kpInt(grammar.add_to_or_create_nonterminal(nonterminal_str, int_rule, data, f))) } env->set(str("read-string"), make_builtin_combiner(str("read-string"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 && params.size != 3 { return make_pair(null(), KPResult::Err(kpString(str("read-string with not a single string, or string, grammer array, and start_symbol")))) } else { if !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("read-string with not a single string")))) } if params.size == 1 { return make_pair(null(), READ(grammar, params[0].get_string())) } else { if !params[1].is_array() { return make_pair(null(), KPResult::Err(kpString(str("read-string with second param not an array")))) } var grammar.construct(): Grammer var gram_arr = params[1].get_array_rc().get() for (var i = 0; i < gram_arr.size; i++;) { if !gram_arr[i].is_array() { return make_pair(null(), KPResult::Err(kpString(str("read-string with second param not containing a sub array at index: ") + i))) } var inner_arr = gram_arr[i].get_array_rc().get() if !inner_arr[0].is_symbol() { return make_pair(null(), KPResult::Err(kpString(str("read-string with second param not containing a sub array : ") + i + " index 0 not symbol"))) } var nonterminal_str = inner_arr[0].get_symbol_text() if !inner_arr[1].is_array() { return make_pair(null(), KPResult::Err(kpString(str("read-string with second param not containing a sub array : ") + i + " index 1 not array"))) } var rule = inner_arr[1].get_array_rc().get() var result = add_grammer_rule_helper(grammar, nonterminal_str, rule, inner_arr[2], fun(f: ref KPValue, x: ref vec): KPResult { var params = vec() for (var j = 0; j < x.size; j++;) { if is_err(x[j]) { return x[j] } params.add(get_value(x[j])) } var unwrapped_f = unwrap(f) if is_err(unwrapped_f) { return unwrapped_f } return function_call(get_value(unwrapped_f), params, kpEnv(null())) }) if is_err(result) { return make_pair(null(), result) } } if !params[2].is_symbol() { return make_pair(null(), KPResult::Err(kpString(str("read-string with third param not a symbol")))) } var start_symbol_idx = grammar.nonterminal_names.find(params[2].get_symbol_text()) if start_symbol_idx == -1 { return make_pair(null(), KPResult::Err(kpString(str("Couldn't find nonterminal to make start symbol: ") + params[2].get_symbol_text()))) } grammar.set_start_symbol((-1*start_symbol_idx)-1) println("Doing actual reading with new grammer of " + params[0].get_string()) println("With grammer:\n" + grammar.to_string()) return make_pair(null(), READ(grammar, params[0].get_string())) } } })); env->set(str("slurp"), make_builtin_combiner(str("slurp"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("slurp with not a single string")))) } else { if !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("slurp with not a single string")))) } if !file_exists(params[0].get_string()) { return make_pair(null(), KPResult::Err(kpString(str("slurp with bad path ") + params[0].get_string()))) } return make_pair(null(), KPResult::Ok(kpString(read_file(params[0].get_string())))) } })); env->set(str("get_line"), make_builtin_combiner(str("get_line"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("get_line with not a single string")))) } else { if !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("get_line with not a single string")))) } return make_pair(null(), KPResult::Ok(kpString(get_line(params[0].get_string(), 1024)))) } })); env->set(str("write_file"), make_builtin_combiner(str("write_file"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 2 { return make_pair(null(), KPResult::Err(kpString(str("write_file with not a two params")))) } else { if !params[0].is_string() { return make_pair(null(), KPResult::Err(kpString(str("write_file with first param not a (path) string")))) } if params[1].is_string() { write_file(params[0].get_string(), params[1].get_string()) } else if params[1].is_array() { var arc = params[1].get_array_rc() var size = arc.get().size var out_vec = vec() for (var i = 0; i < size; i++;) { if !arc.get()[i].is_int() { return make_pair(null(), KPResult::Err(kpString(str("write_file with vec member ") + i + "(" + pr_str(arc.get()[i], true) + ") isn't int"))) } var int_out = arc.get()[i].get_int() if int_out < 0 || int_out > 255 { return make_pair(null(), KPResult::Err(kpString(str("write_file with vec member ") + i + "(" + int_out + ") is out of 0-255 byte range " + int_out))) } out_vec.add((int_out) cast char) } write_file_binary(params[0].get_string(), out_vec) } else { return make_pair(null(), KPResult::Err(kpString(str("write_file with second param not a string or array")))) } return make_pair(null(), KPResult::Ok(kpNil())) } })); env->set(str("empty_env"), kpEnv(new()->construct())) // Launch into new kraken for interface and self-hosting features var params = vec() for (var i = 0; i < argc; i++;) { params.add(kpString(str(argv[i]))) } env->set(str("*ARGV*"), kpArray(params)) println(rep(grammar, env, str("(eval (read-string (slurp \"./prelude.kp\")))"))) return 0 }