Files
kraken/k_prime.krak

1545 lines
68 KiB
Plaintext

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<vec<KPValue>>, //<10sizebits> 1
// same encoding, but encodes 0-length null ptr
Nil // 00000000000 1
}
obj KPEnv (Object) {
var data: map<str, KPValue>
var outer: *KPEnv
fun construct(): *KPEnv {
return construct(null<KPEnv>())
}
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<KPEnv>()
}
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<KPEnv>()) && ((other.outer == null<KPEnv>()) || (*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<KPEnv>()) {
return outer->find(key)
} else {
return null<KPEnv>()
}
}
fun get(key: *char): KPResult {
return get(str(key))
}
fun get(key: ref str): KPResult {
var env = find(key)
if (env != null<KPEnv>()) {
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<KPEnv>() {
outer->to_string(tabs + "\t", s)
}
}
}
obj KPBuiltinCombiner (Object) {
var name: str
var wrap_level: int
var tco_eval: bool
var fp: fun(vec<KPValue>, *KPEnv): pair<*KPEnv, KPResult>
fun construct(name: ref str, wrap_level: int, tco_eval: bool, fp: fun(vec<KPValue>, *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<KPValue>, dynamic_env: KPValue): pair<*KPEnv, KPResult> {
if !dynamic_env.is_env() {
return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<KPValue>, *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<str>
var is_variadic: bool
var body: *KPValue
fun construct(env: *KPEnv, dynamic_env_name: str, uses_dynamic_env: bool, parameters: vec<str>, 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(&parameters)
this->is_variadic = is_variadic
this->body = new<KPValue>()
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<KPValue>()
this->body->copy_construct(old->body)
}
fun destruct(): void {
this->env = null<KPEnv>()
dynamic_env_name.destruct()
parameters.destruct()
delete(body)
body = null<KPValue>()
}
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<KPValue>, dynamic_env: KPValue): pair<*KPEnv, KPResult> {
for (var l = 0; l < wrap_level; l++;) {
if !dynamic_env.is_env() {
return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), 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<KPEnv>()->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<KPValue>()
}
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<KPValue>() {
meta = new<KPValue>()
meta->copy_construct(other->meta)
} else {
meta = null<KPValue>()
}
}
fun operator=(other: ref KPValue): void {
destruct()
copy_construct(&other)
}
fun destruct(): void {
if meta != null<KPValue>()
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<KPEnv>()
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<vec<KPValue>> {
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>()): 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>): KPValue {
var rcd.construct(v): rc<vec<KPValue>>
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<KPResult,KPValue>, s: str): pair<int, KPResult> {
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<KPResult, KPValue>, 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<KPValue>, env: KPValue): KPResult {
return EVAL(env.get_env(), kpArray(vec(f) + params))
}
fun rep(grammar: ref Grammer<KPResult, KPValue>, 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<KPValue>, 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<KPResult, KPValue>
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>): KPResult = fun(_: ref KPValue, x: ref vec<KPResult>): KPResult { return KPResult::Ok(kpNil()); }
var ret_0_sym: fun(ref KPValue, ref vec<KPResult>): KPResult = fun(_: ref KPValue, x: ref vec<KPResult>): KPResult { return x[0]; }
var ret_1_sym: fun(ref KPValue, ref vec<KPResult>): KPResult = fun(_: ref KPValue, x: ref vec<KPResult>): 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<int>(), 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<int>(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<int>(), kpNil(), fun(_: ref KPValue, x: ref vec<KPResult>): KPResult {
return KPResult::Ok(kpArray(vec<KPValue>()))
})
grammar.add_to_nonterminal(space_forms, vec(form), kpNil(), fun(_: ref KPValue, x: ref vec<KPResult>): 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>): 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>): KPResult { return KPResult::Ok(kpArray(vec<KPValue>())); })
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>): KPResult { return x[2]; })
grammar.add_to_nonterminal(form, vec(call_form), kpNil(), fun(_: ref KPValue, x: ref vec<KPResult>): 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<KPEnv>()->construct()
env->set(str("vau"), make_builtin_combiner(str("vau"), 0, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
var param_symbols = vec<str>()
if params.size != 2 && params.size != 3 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<str>()
if !params[offset+0].is_array() {
return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret))))
}));
// Uses TCO
env->set(str("eval"), make_builtin_combiner(str("eval"), 1, true, fun(params: vec<KPValue>, 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<KPEnv>(), 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<KPEnv>(), 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<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if (params.size % 2) != 0 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), 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<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to symbol?"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].is_symbol())))
}));
env->set(str("int?"), make_builtin_combiner(str("int?"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to int?"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].is_int())))
}));
env->set(str("string?"), make_builtin_combiner(str("string?"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to string?"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].is_string())))
}));
env->set(str("combiner?"), make_builtin_combiner(str("combiner?"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to combiner?"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].is_combiner())))
}));
env->set(str("env?"), make_builtin_combiner(str("env?"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to env?"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].is_env())))
}));
env->set(str("nil?"), make_builtin_combiner(str("nil?"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to nil?"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].is_nil())))
}));
env->set(str("bool?"), make_builtin_combiner(str("bool?"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to bool?"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].is_bool())))
}));
env->set(str("array?"), make_builtin_combiner(str("array?"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to array?"))))
}
return make_pair(null<KPEnv>(), 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<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to str-to-symbol"))))
}
if !params[0].is_string() {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Called str-to-symbol with not a symbol"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpSymbol(params[0].get_string())))
}));
env->set(str("get-text"), make_builtin_combiner(str("get-text"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to get-text"))))
}
if !params[0].is_symbol() {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Called get-text with not a symbol"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpString(params[0].get_symbol_text())))
}));
env->set(str("array"), make_builtin_combiner(str("array"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
return make_pair(null<KPEnv>(), KPResult::Ok(kpArray(params)))
}));
env->set(str("len"), make_builtin_combiner(str("len"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 1 param to len"))))
}
if !params[0].is_array() && !params[0].is_string() {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Ok(kpInt(params[0].get_array_rc().get().size)))
} else {
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_string().length())))
}
}));
env->set(str("idx"), make_builtin_combiner(str("idx"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to idx"))))
}
if !params[0].is_array() && !params[0].is_string() { return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), KPResult::Ok(params[0].get_array_rc().get()[index]))
} else {
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt((params[0].get_string()[index]) cast int)))
}
}));
env->set(str("slice"), make_builtin_combiner(str("slice"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 3 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 3 params to slice"))))
}
if !params[0].is_array() && !params[0].is_string() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("first param to slice is not string or array")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), KPResult::Ok(kpArray(params[0].get_array_rc().get().slice(start, end))))
} else {
return make_pair(null<KPEnv>(), KPResult::Ok(kpString(params[0].get_string().slice(start, end))))
}
}));
env->set(str("concat"), make_builtin_combiner(str("concat"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
var to_ret = vec<KPValue>()
for (var i = 0; i < params.size; i++;) {
if !params[i].is_array() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("param to concat is not an array")))); }
to_ret += params[i].get_array_rc().get()
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpArray(to_ret)));
}));
env->set(str("+"), make_builtin_combiner(str("+"), 1, false, fun(params: vec<KPValue>, 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<KPEnv>(), KPResult::Err(kpString(str("called + with not an int: ") + pr_str(params[i], false))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(to_ret)))
}));
env->set(str("-"), make_builtin_combiner(str("-"), 1, false, fun(params: vec<KPValue>, 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<KPEnv>(), KPResult::Err(kpString(str("called - with not an int: ") + pr_str(params[i], false))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(to_ret)))
}));
env->set(str("*"), make_builtin_combiner(str("*"), 1, false, fun(params: vec<KPValue>, 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<KPEnv>(), KPResult::Err(kpString(str("called * with not an int: ") + pr_str(params[i], false))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(to_ret)))
}));
env->set(str("/"), make_builtin_combiner(str("/"), 1, false, fun(params: vec<KPValue>, 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<KPEnv>(), KPResult::Err(kpString(str("called / with not an int: ") + pr_str(params[i], false))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(to_ret)))
}));
env->set(str("%"), make_builtin_combiner(str("%"), 1, false, fun(params: vec<KPValue>, 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<KPEnv>(), KPResult::Err(kpString(str("called % with not an int: ") + pr_str(params[i], false))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(to_ret)))
}));
env->set(str("&"), make_builtin_combiner(str("&"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to &"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called & with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called & with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_int() & params[1].get_int())))
}));
env->set(str("|"), make_builtin_combiner(str("|"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to |"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called | with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called | with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_int() | params[1].get_int())))
}));
env->set(str("<<"), make_builtin_combiner(str("<<"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to <<"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called << with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called << with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_int() << params[1].get_int())))
}));
env->set(str(">>"), make_builtin_combiner(str(">>"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to >>"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called >> with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called >> with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_int() >> params[1].get_int())))
}));
env->set(str("="), make_builtin_combiner(str("="), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size <= 1 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str("!="), make_builtin_combiner(str("!="), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size <= 1 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str("<"), make_builtin_combiner(str("<"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size <= 1 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str("<="), make_builtin_combiner(str("<="), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size <= 1 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str(">"), make_builtin_combiner(str(">"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size <= 1 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str(">="), make_builtin_combiner(str(">="), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size <= 1 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str("and"), make_builtin_combiner(str("and"), 0, false, fun(params: vec<KPValue>, 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<KPEnv>(), ip); }
var ipv = get_value(ip)
if !ipv.is_truthy() || i == params.size - 1 {
return make_pair(null<KPEnv>(), ip)
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpFalse()))
}));
env->set(str("or"), make_builtin_combiner(str("or"), 0, false, fun(params: vec<KPValue>, 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<KPEnv>(), ip); }
var ipv = get_value(ip)
if ipv.is_truthy() || i == params.size - 1 {
return make_pair(null<KPEnv>(), ip)
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpFalse()))
}));
env->set(str("pr-str"), make_builtin_combiner(str("pr-str"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
return make_pair(null<KPEnv>(), str_wrapper(params, dynamic_env, " ", true))
}));
env->set(str("str"), make_builtin_combiner(str("str"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
return make_pair(null<KPEnv>(), str_wrapper(params, dynamic_env, "", false))
}));
env->set(str("prn"), make_builtin_combiner(str("prn"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
var to_print = str_wrapper(params, dynamic_env, " ", true)
if is_err(to_print) { return make_pair(null<KPEnv>(), to_print); }
println(get_value(to_print).get_string())
return make_pair(null<KPEnv>(), KPResult::Ok(kpNil()))
}));
env->set(str("println"), make_builtin_combiner(str("println"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
var to_print = str_wrapper(params, dynamic_env, " ", false)
if is_err(to_print) { return make_pair(null<KPEnv>(), to_print); }
println(get_value(to_print).get_string())
return make_pair(null<KPEnv>(), KPResult::Ok(kpNil()))
}));
env->set(str("meta"), make_builtin_combiner(str("meta"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("meta called with not one argument"))))
} else {
if params[0].meta != null<KPValue>() {
return make_pair(null<KPEnv>(), KPResult::Ok(*params[0].meta))
} else {
return make_pair(null<KPEnv>(), KPResult::Ok(kpNil()))
}
}
}));
env->set(str("with-meta"), make_builtin_combiner(str("with-meta"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("with-meta called with not two arguments"))))
} else {
var new_meta = new<KPValue>()
new_meta->copy_construct(&params[1])
var new_value = params[0].deep_clone();
new_value.meta = new_meta
return make_pair(null<KPEnv>(), KPResult::Ok(new_value))
}
}));
env->set(str("wrap"), make_builtin_combiner(str("wrap"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret))))
}
KPValue_int::BuiltinCombiner(c) {
var to_ret = c;
to_ret.wrap_level++
return make_pair(null<KPEnv>(), KPResult::Ok(nmMV(KPValue_int::BuiltinCombiner(to_ret))))
}
}
return make_pair(null<KPEnv>(), 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<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("unwrap called with not one argument"))))
}
return make_pair(null<KPEnv>(), unwrap(params[0]))
}));
env->set(str("error"), make_builtin_combiner(str("error"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("error called with not one argument"))))
}
return make_pair(null<KPEnv>(), KPResult::Err(params[0]))
}));
env->set(str("recover"), make_builtin_combiner(str("recover"), 0, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 3 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Err(kpString(str("recover called with not symbol as middle"))))
}
var new_env = new<KPEnv>()->construct(dynamic_env)
new_env->set(params[1].get_symbol_text(), get_err(data))
return make_pair(null<KPEnv>(), EVAL(new_env, params[2]))
}
return make_pair(null<KPEnv>(), data)
}));
var add_grammer_rule_helper: fun(ref Grammer<KPResult, KPValue>, str, vec<KPValue>, KPValue, fun(ref KPValue, ref vec<KPResult>): KPResult): KPResult = fun(grammar: ref Grammer<KPResult, KPValue>, nonterminal_str: str, rule: vec<KPValue>, data: KPValue, f: fun(ref KPValue, ref vec<KPResult>): KPResult): KPResult {
var int_rule = vec<int>()
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>): KPResult {
var to_ret = vec<KPValue>()
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>): 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>): 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>): KPResult {
if is_err(x[0]) { return x[0]; }
return KPResult::Ok(get_value(x[0]))
})
grammar.add_to_nonterminal(new, vec<int>(), kpNil(), fun(f: ref KPValue, x: ref vec<KPResult>): KPResult {
return KPResult::Ok(kpArray(vec<KPValue>()))
})
}
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<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 && params.size != 3 {
return make_pair(null<KPEnv>(), 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<KPEnv>(), KPResult::Err(kpString(str("read-string with not a single string"))))
}
if params.size == 1 {
return make_pair(null<KPEnv>(), READ(grammar, params[0].get_string()))
} else {
if !params[1].is_array() {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("read-string with second param not an array"))))
}
var grammar.construct(): Grammer<KPResult, KPValue>
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<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), 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>): KPResult {
var params = vec<KPValue>()
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<KPEnv>()))
})
if is_err(result) {
return make_pair(null<KPEnv>(), result)
}
}
if !params[2].is_symbol() {
return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), READ(grammar, params[0].get_string()))
}
}
}));
env->set(str("slurp"), make_builtin_combiner(str("slurp"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("slurp with not a single string"))))
} else {
if !params[0].is_string() {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("slurp with not a single string"))))
}
if !file_exists(params[0].get_string()) {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("slurp with bad path ") + params[0].get_string())))
}
return make_pair(null<KPEnv>(), 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<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("get_line with not a single string"))))
} else {
if !params[0].is_string() {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("get_line with not a single string"))))
}
return make_pair(null<KPEnv>(), 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<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("write_file with not a two params"))))
} else {
if !params[0].is_string() {
return make_pair(null<KPEnv>(), 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<char>()
for (var i = 0; i < size; i++;) {
if !arc.get()[i].is_int() {
return make_pair(null<KPEnv>(), 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<KPEnv>(), 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<KPEnv>(), KPResult::Err(kpString(str("write_file with second param not a string or array"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpNil()))
}
}));
env->set(str("empty_env"), kpEnv(new<KPEnv>()->construct()))
// Launch into new kraken for interface and self-hosting features
var params = vec<KPValue>()
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
}