1516 lines
60 KiB
Plaintext
1516 lines
60 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
|
|
|
|
Vector: 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 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 fp: fun(vec<KPValue>, *KPEnv): KPResult
|
|
fun construct(name: ref str, wrap_level: int, fp: fun(vec<KPValue>, *KPEnv): KPResult): *KPBuiltinCombiner {
|
|
this->name.copy_construct(&name)
|
|
this->wrap_level = wrap_level
|
|
this->fp = fp
|
|
return this
|
|
}
|
|
fun copy_construct(old: *KPBuiltinCombiner): void {
|
|
this->fp = old->fp
|
|
this->wrap_level = old->wrap_level
|
|
this->name.copy_construct(&old->name)
|
|
}
|
|
fun destruct(): void {
|
|
this->name.destruct()
|
|
}
|
|
fun operator=(other:ref KPBuiltinCombiner):void {
|
|
destruct()
|
|
copy_construct(&other)
|
|
}
|
|
fun operator==(other: ref KPBuiltinCombiner):bool {
|
|
return false
|
|
}
|
|
fun call(params: vec<KPValue>, dynamic_env: KPValue): KPResult {
|
|
if !dynamic_env.is_env() {
|
|
return KPResult::Err(kpString(pr_str(dynamic_env, true) + " is not an env"))
|
|
}
|
|
for (var l = 0; l < wrap_level; l++;) {
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var intermediate = EVAL(dynamic_env.get_env(), params[i]);
|
|
if is_err(intermediate) {
|
|
return intermediate;
|
|
}
|
|
params[i] = get_value(intermediate);
|
|
}
|
|
}
|
|
return fp(params, dynamic_env.get_env())
|
|
}
|
|
}
|
|
fun make_builtin_combiner(name: str, wrap_level: int, f: fun(vec<KPValue>, *KPEnv): KPResult): KPValue {
|
|
var to_ret.construct(name, wrap_level, f): KPBuiltinCombiner
|
|
return nmMV(KPValue_int::BuiltinCombiner(to_ret))
|
|
}
|
|
obj KPCombiner (Object) {
|
|
var env: *KPEnv
|
|
var dynamic_env_name: str
|
|
var wrap_level: int
|
|
var parameters: vec<str>
|
|
var is_variadic: bool
|
|
var body: *KPValue
|
|
fun construct(env: *KPEnv, dynamic_env_name: str, parameters: vec<str>, is_variadic: bool, body: KPValue): *KPCombiner {
|
|
this->env = env
|
|
this->dynamic_env_name.copy_construct(&dynamic_env_name)
|
|
this->wrap_level = 0
|
|
this->parameters.copy_construct(¶meters)
|
|
this->is_variadic = is_variadic
|
|
this->body = new<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->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 && wrap_level == other.wrap_level && parameters == other.parameters && is_variadic == other.is_variadic && body->equals(*other.body)
|
|
}
|
|
// no call b/c need to do in EVAL for TCO
|
|
fun prep_call(params: ref vec<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(kpVector(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], kpVector(params.slice(i, -1)))
|
|
} else {
|
|
new_env->set(parameters[i], params[i])
|
|
}
|
|
}
|
|
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::Vector(d) { match (other.internal) {
|
|
KPValue_int::Vector(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 deep_clone(): KPValue {
|
|
match (internal) {
|
|
KPValue_int::Vector(v) {
|
|
return kpVector(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_vector(): bool {
|
|
match (internal) {
|
|
KPValue_int::Vector(v) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
fun get_vector_rc(): rc<vec<KPValue>> {
|
|
match (internal) {
|
|
KPValue_int::Vector(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_truthy(): bool {
|
|
match (internal) {
|
|
KPValue_int::False() {
|
|
return false
|
|
}
|
|
KPValue_int::Nil() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
fun is_pair(): bool {
|
|
return is_vector() && get_vector_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 kpVector(v: ref vec<KPValue>): KPValue {
|
|
var rcd.construct(v): rc<vec<KPValue>>
|
|
return nmMV(KPValue_int::Vector(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 {
|
|
longest = BSR.data[i].right
|
|
}
|
|
}
|
|
if longest >= 0 {
|
|
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::Vector(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")
|
|
}
|
|
return to_ret.second
|
|
}
|
|
|
|
fun EVAL(env: *KPEnv, ast: KPValue): KPResult {
|
|
// for tco
|
|
while (true) {
|
|
match (ast.internal) {
|
|
KPValue_int::Vector(l) {
|
|
if (l.get().size == 0) {
|
|
return KPResult::Err(kpString(str("Eval a zero length vector")))
|
|
} 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) {
|
|
return f.call(l.get().slice(1,-1), kpEnv(env))
|
|
}
|
|
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(), kpVector(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++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
to_ret += pr_str(get_value(ip), print_readably)
|
|
if i != params.size-1 {
|
|
to_ret += sep
|
|
}
|
|
}
|
|
return KPResult::Ok(kpString(to_ret))
|
|
}
|
|
|
|
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 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] == '\\' || input[i+1] == '"' {
|
|
to_ret += input[i+1]
|
|
} else {
|
|
return KPResult::Err(kpString(str("bad string escape")))
|
|
}
|
|
// 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(kpVector(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(kpVector(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(kpVector(vec(get_value(x[0])) + get_value(x[2]).get_vector_rc().get()))
|
|
})
|
|
|
|
grammar.add_to_nonterminal(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(kpVector(vec<KPValue>())); })
|
|
grammar.add_to_nonterminal(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.set_start_symbol(form)
|
|
|
|
|
|
var env = new<KPEnv>()->construct()
|
|
|
|
env->set(str("vau"), make_builtin_combiner(str("vau"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var param_symbols = vec<str>()
|
|
if params.size != 3 {
|
|
return KPResult::Err(kpString(str("bad number of params to vau")))
|
|
}
|
|
if !params[0].is_symbol() {
|
|
return KPResult::Err(kpString(str("first param to vau is not symbol")))
|
|
}
|
|
var dynamic_env_name = params[0].get_symbol_text()
|
|
var is_variadic = false
|
|
var parameters = vec<str>()
|
|
if !params[1].is_vector() {
|
|
return KPResult::Err(kpString(str("second param to vau is not vector")))
|
|
}
|
|
var parameter_objects = params[1].get_vector_rc()
|
|
for (var i = 0; i < parameter_objects.get().size; i++;) {
|
|
if !parameter_objects.get()[i].is_symbol() {
|
|
return KPResult::Err(kpString(str("second param to vau has a not symbol member")))
|
|
}
|
|
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, parameters, is_variadic, params[2]) : KPCombiner
|
|
return KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret)))
|
|
}));
|
|
env->set(str("eval"), make_builtin_combiner(str("eval"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var evaled_params = vec<KPValue>()
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) {
|
|
return ip
|
|
}
|
|
evaled_params.add(get_value(ip))
|
|
}
|
|
if evaled_params.size == 1 {
|
|
return EVAL(dynamic_env, evaled_params[0])
|
|
} else if params.size == 2 {
|
|
if !evaled_params[1].is_env() {
|
|
return KPResult::Err(kpString(str("second param to eval is not an environment")))
|
|
}
|
|
return EVAL(evaled_params[1].get_env(), evaled_params[0])
|
|
}
|
|
return KPResult::Err(kpString(str("wrong number of params to eval")))
|
|
}));
|
|
|
|
env->set(str("set!"), make_builtin_combiner(str("set!"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("not 2 params to set!")))
|
|
}
|
|
if !params[0].is_symbol() {
|
|
return KPResult::Err(kpString(str("first parameter to set! is not a symbol")))
|
|
}
|
|
var data = EVAL(dynamic_env, params[1])
|
|
if is_err(data) {
|
|
return data
|
|
}
|
|
dynamic_env->set(params[0].get_symbol_text(), get_value(data))
|
|
return KPResult::Ok(kpNil())
|
|
}));
|
|
|
|
env->set(str("cond"), make_builtin_combiner(str("cond"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if (params.size % 2) != 0 {
|
|
return KPResult::Err(kpString(str("Need even number of params to cond")))
|
|
}
|
|
for (var i = 0; i < params.size; i+=2;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) {
|
|
return ip
|
|
}
|
|
if get_value(ip).is_truthy() {
|
|
return EVAL(dynamic_env, params[i+1])
|
|
}
|
|
}
|
|
return KPResult::Ok(kpNil())
|
|
}));
|
|
|
|
env->set(str("symbol?"), make_builtin_combiner(str("symbol?"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("Need 1 param to symbol?")))
|
|
}
|
|
var ip = EVAL(dynamic_env, params[0])
|
|
if is_err(ip) {
|
|
return ip
|
|
}
|
|
return KPResult::Ok(kpBool(get_value(ip).is_symbol()))
|
|
}));
|
|
|
|
env->set(str("get-text"), make_builtin_combiner(str("get-text"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("Need 1 param to get-text")))
|
|
}
|
|
var ip = EVAL(dynamic_env, params[0])
|
|
if is_err(ip) {
|
|
return ip
|
|
}
|
|
var iv = get_value(ip)
|
|
if !iv.is_symbol() {
|
|
return KPResult::Err(kpString(str("Called get-text with not a symbol")))
|
|
}
|
|
return KPResult::Ok(kpString(iv.get_symbol_text()))
|
|
}));
|
|
|
|
env->set(str("vector"), make_builtin_combiner(str("vector"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var evaled_params = vec<KPValue>()
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) {
|
|
return ip
|
|
}
|
|
evaled_params.add(get_value(ip))
|
|
}
|
|
return KPResult::Ok(kpVector(evaled_params))
|
|
}));
|
|
env->set(str("vector?"), make_builtin_combiner(str("vector?"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("Need 1 param to vector?")))
|
|
}
|
|
var ip = EVAL(dynamic_env, params[0])
|
|
if is_err(ip) {
|
|
return ip
|
|
}
|
|
return KPResult::Ok(kpBool(get_value(ip).is_vector()))
|
|
}));
|
|
env->set(str("len"), make_builtin_combiner(str("len"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("Need 1 param to len")))
|
|
}
|
|
var v = EVAL(dynamic_env, params[0]);
|
|
if is_err(v) { return v; }
|
|
return KPResult::Ok(kpInt(get_value(v).get_vector_rc().get().size))
|
|
}));
|
|
env->set(str("idx"), make_builtin_combiner(str("idx"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("Need 2 params to idx")))
|
|
}
|
|
var v = EVAL(dynamic_env, params[0]);
|
|
if is_err(v) { return v; }
|
|
var vv = get_value(v)
|
|
if !vv.is_vector() { return KPResult::Err(kpString(str("Param 1 to idx is not vector"))); }
|
|
var i = EVAL(dynamic_env, params[1]);
|
|
if is_err(i) { return i; }
|
|
var iv = get_value(i)
|
|
if !iv.is_int() { return KPResult::Err(kpString(str("Param 2 to idx is not int"))); }
|
|
|
|
return KPResult::Ok(vv.get_vector_rc().get()[iv.get_int()])
|
|
}));
|
|
env->set(str("set-idx!"), make_builtin_combiner(str("set-idx!"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 3 {
|
|
return KPResult::Err(kpString(str("Need 3 params to set-idx!")))
|
|
}
|
|
var v = EVAL(dynamic_env, params[0]);
|
|
if is_err(v) { return v; }
|
|
var vv = get_value(v)
|
|
if !vv.is_vector() { return KPResult::Err(kpString(str("Param 1 to set-idx! is not vector"))); }
|
|
var i = EVAL(dynamic_env, params[1]);
|
|
if is_err(i) { return i; }
|
|
var iv = get_value(i)
|
|
if !iv.is_int() { return KPResult::Err(kpString(str("Param 2 to set-idx! is not int"))); }
|
|
|
|
var r = EVAL(dynamic_env, params[2]);
|
|
if is_err(r) { return r; }
|
|
var rv = get_value(r)
|
|
|
|
vv.get_vector_rc().get()[iv.get_int()] = rv;
|
|
|
|
return KPResult::Ok(kpNil())
|
|
}));
|
|
env->set(str("concat"), make_builtin_combiner(str("concat"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var to_ret = vec<KPValue>()
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) {
|
|
return ip
|
|
}
|
|
var v = get_value(ip)
|
|
if !v.is_vector() { return KPResult::Err(kpString(str("Param ") + i + " to concat is not vector: " + pr_str(v, false))); }
|
|
to_ret += v.get_vector_rc().get()
|
|
}
|
|
return KPResult::Ok(kpVector(to_ret))
|
|
}));
|
|
env->set(str("slice"), make_builtin_combiner(str("slice"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 3 {
|
|
return KPResult::Err(kpString(str("Need 3 params to slice")))
|
|
}
|
|
var lr = EVAL(dynamic_env, params[0]);
|
|
if is_err(lr) { return lr; }
|
|
var lv = get_value(lr);
|
|
if !lv.is_vector() { return KPResult::Err(kpString(str("first param to slice is not vector"))); }
|
|
var startr = EVAL(dynamic_env, params[1]);
|
|
if is_err(startr) { return startr; }
|
|
var startv = get_value(startr);
|
|
if !startv.is_int() { return KPResult::Err(kpString(str("second param to slice is not int"))); }
|
|
var start = startv.get_int();
|
|
var endr = EVAL(dynamic_env, params[2]);
|
|
if is_err(endr) { return endr; }
|
|
var endv = get_value(endr);
|
|
if !endv.is_int() { return KPResult::Err(kpString(str("third param to slice is not int"))); }
|
|
var end = endv.get_int();
|
|
|
|
|
|
return KPResult::Ok(kpVector(lv.get_vector_rc().get().slice(start, end)))
|
|
}));
|
|
|
|
env->set(str("+"), make_builtin_combiner(str("+"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var to_ret = 0
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
match (get_value(ip).internal) {
|
|
KPValue_int::Int(v) {
|
|
to_ret += v
|
|
continue
|
|
}
|
|
}
|
|
return KPResult::Err(kpString(str("called + with not an int: ") + pr_str(get_value(ip), false)))
|
|
}
|
|
return KPResult::Ok(kpInt(to_ret))
|
|
}));
|
|
env->set(str("-"), make_builtin_combiner(str("-"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var to_ret = 0
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
match (get_value(ip).internal) {
|
|
KPValue_int::Int(v) {
|
|
if i == 0 {
|
|
to_ret += v
|
|
} else {
|
|
to_ret -= v
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
return KPResult::Err(kpString(str("called - with not an int: ") + pr_str(get_value(ip), false)))
|
|
}
|
|
return KPResult::Ok(kpInt(to_ret))
|
|
}));
|
|
env->set(str("*"), make_builtin_combiner(str("*"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var to_ret = 1
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
match (get_value(ip).internal) {
|
|
KPValue_int::Int(v) {
|
|
to_ret *= v
|
|
continue
|
|
}
|
|
}
|
|
return KPResult::Err(kpString(str("called * with not an int: ") + pr_str(get_value(ip), false)))
|
|
}
|
|
return KPResult::Ok(kpInt(to_ret))
|
|
}));
|
|
env->set(str("/"), make_builtin_combiner(str("/"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var to_ret = 1
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
match (get_value(ip).internal) {
|
|
KPValue_int::Int(v) {
|
|
if i == 0 {
|
|
to_ret *= v
|
|
} else {
|
|
to_ret /= v
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
return KPResult::Err(kpString(str("called / with not an int: ") + pr_str(get_value(ip), false)))
|
|
}
|
|
return KPResult::Ok(kpInt(to_ret))
|
|
}));
|
|
env->set(str("%"), make_builtin_combiner(str("%"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var to_ret = 1
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
match (get_value(ip).internal) {
|
|
KPValue_int::Int(v) {
|
|
if i == 0 {
|
|
to_ret *= v
|
|
} else {
|
|
to_ret = to_ret % v
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
return KPResult::Err(kpString(str("called % with not an int: ") + pr_str(get_value(ip), false)))
|
|
}
|
|
return KPResult::Ok(kpInt(to_ret))
|
|
}));
|
|
|
|
env->set(str("="), make_builtin_combiner(str("="), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("Need 2 params to =")))
|
|
}
|
|
var a = EVAL(dynamic_env, params[0]);
|
|
if is_err(a) { return a; }
|
|
var b = EVAL(dynamic_env, params[1]);
|
|
if is_err(b) { return b; }
|
|
return KPResult::Ok(kpBool(get_value(a).equals(get_value(b))))
|
|
}));
|
|
env->set(str("!="), make_builtin_combiner(str("!="), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("Need 2 params to !=")))
|
|
}
|
|
var a = EVAL(dynamic_env, params[0]);
|
|
if is_err(a) { return a; }
|
|
var b = EVAL(dynamic_env, params[1]);
|
|
if is_err(b) { return b; }
|
|
return KPResult::Ok(kpBool(!get_value(a).equals(get_value(b))))
|
|
}));
|
|
env->set(str("<"), make_builtin_combiner(str("<"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("Need 2 params to <")))
|
|
}
|
|
var a = EVAL(dynamic_env, params[0]);
|
|
if is_err(a) { return a; }
|
|
var av = get_value(a)
|
|
if !av.is_int() { return KPResult::Err(kpString(str("called < with first not an int"))); }
|
|
var b = EVAL(dynamic_env, params[1]);
|
|
if is_err(b) { return b; }
|
|
var bv = get_value(b)
|
|
if !bv.is_int() { return KPResult::Err(kpString(str("called < with second not an int"))); }
|
|
return KPResult::Ok(kpBool(av.get_int() < bv.get_int()))
|
|
}));
|
|
env->set(str("<="), make_builtin_combiner(str("<="), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("Need 2 params to <=")))
|
|
}
|
|
var a = EVAL(dynamic_env, params[0]);
|
|
if is_err(a) { return a; }
|
|
var av = get_value(a)
|
|
if !av.is_int() { return KPResult::Err(kpString(str("called <= with first not an int"))); }
|
|
var b = EVAL(dynamic_env, params[1]);
|
|
if is_err(b) { return b; }
|
|
var bv = get_value(b)
|
|
if !bv.is_int() { return KPResult::Err(kpString(str("called <= with second not an int"))); }
|
|
return KPResult::Ok(kpBool(av.get_int() <= bv.get_int()))
|
|
}));
|
|
env->set(str(">"), make_builtin_combiner(str(">"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("Need 2 params to >")))
|
|
}
|
|
var a = EVAL(dynamic_env, params[0]);
|
|
if is_err(a) { return a; }
|
|
var av = get_value(a)
|
|
if !av.is_int() { return KPResult::Err(kpString(str("called > with first not an int"))); }
|
|
var b = EVAL(dynamic_env, params[1]);
|
|
if is_err(b) { return b; }
|
|
var bv = get_value(b)
|
|
if !bv.is_int() { return KPResult::Err(kpString(str("called > with second not an int"))); }
|
|
return KPResult::Ok(kpBool(av.get_int() > bv.get_int()))
|
|
}));
|
|
env->set(str(">="), make_builtin_combiner(str(">="), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("Need 2 params to >=")))
|
|
}
|
|
var a = EVAL(dynamic_env, params[0]);
|
|
if is_err(a) { return a; }
|
|
var av = get_value(a)
|
|
if !av.is_int() { return KPResult::Err(kpString(str("called >= with first not an int"))); }
|
|
var b = EVAL(dynamic_env, params[1]);
|
|
if is_err(b) { return b; }
|
|
var bv = get_value(b)
|
|
if !bv.is_int() { return KPResult::Err(kpString(str("called >= with second not an int"))); }
|
|
return KPResult::Ok(kpBool(av.get_int() >= bv.get_int()))
|
|
}));
|
|
|
|
env->set(str("and"), make_builtin_combiner(str("and"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
var ipv = get_value(ip)
|
|
if !ipv.is_truthy() || i == params.size - 1 {
|
|
return ip
|
|
}
|
|
}
|
|
return KPResult::Ok(kpFalse())
|
|
}));
|
|
env->set(str("or"), make_builtin_combiner(str("or"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
var ipv = get_value(ip)
|
|
if ipv.is_truthy() || i == params.size - 1 {
|
|
return ip
|
|
}
|
|
}
|
|
return KPResult::Ok(kpFalse())
|
|
}));
|
|
|
|
env->set(str("pr-str"), make_builtin_combiner(str("pr-str"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
return str_wrapper(params, dynamic_env, " ", true)
|
|
}));
|
|
env->set(str("str"), make_builtin_combiner(str("str"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
return str_wrapper(params, dynamic_env, "", false)
|
|
}));
|
|
env->set(str("prn"), make_builtin_combiner(str("prn"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var to_print = str_wrapper(params, dynamic_env, " ", true)
|
|
if is_err(to_print) { return to_print; }
|
|
println(get_value(to_print).get_string())
|
|
return KPResult::Ok(kpNil())
|
|
}));
|
|
env->set(str("println"), make_builtin_combiner(str("println"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var to_print = str_wrapper(params, dynamic_env, " ", false)
|
|
if is_err(to_print) { return to_print; }
|
|
println(get_value(to_print).get_string())
|
|
return KPResult::Ok(kpNil())
|
|
}));
|
|
|
|
env->set(str("meta"), make_builtin_combiner(str("meta"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("meta called with not one argument")))
|
|
} else {
|
|
var or = EVAL(dynamic_env, params[0])
|
|
if is_err(or) { return or; }
|
|
var o = get_value(or)
|
|
if o.meta != null<KPValue>() {
|
|
return KPResult::Ok(*o.meta)
|
|
} else {
|
|
return KPResult::Ok(kpNil())
|
|
}
|
|
}
|
|
}));
|
|
env->set(str("with-meta"), make_builtin_combiner(str("with-meta"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("with-meta called with not two arguments")))
|
|
} else {
|
|
var or = EVAL(dynamic_env, params[0])
|
|
if is_err(or) { return or; }
|
|
var mr = EVAL(dynamic_env, params[1])
|
|
if is_err(mr) { return mr; }
|
|
var new_meta = new<KPValue>()
|
|
new_meta->copy_construct(&get_value(mr))
|
|
var new_value = get_value(or).deep_clone();
|
|
new_value.meta = new_meta
|
|
return KPResult::Ok(new_value)
|
|
}
|
|
}));
|
|
|
|
// self-modifying grammar
|
|
env->set(str("add_terminal"), make_builtin_combiner(str("add_terminal"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("add_terminal called with wrong number (not 2) params")))
|
|
} else {
|
|
var namer = EVAL(dynamic_env, params[0]);
|
|
if is_err(namer) { return namer; }
|
|
var namev = get_value(namer)
|
|
if !namev.is_string() {
|
|
return KPResult::Err(kpString(str("add_terminal called with wrong number (not 2) params")))
|
|
}
|
|
var funcr = EVAL(dynamic_env, params[1]);
|
|
if is_err(funcr) { return funcr; }
|
|
return KPResult::Ok(kpInt(grammar.add_terminal(namev.get_string(), get_value(funcr), fun(f: ref KPValue, input: ref str, l: int, r: int): KPResult {
|
|
return function_call(f, vec(kpString(input.slice(l,r))), kpNil())
|
|
})))
|
|
}
|
|
}));
|
|
var add_grammer_rule_helper: fun(str, vec<KPValue>, KPValue, fun(ref KPValue, ref vec<KPResult>): KPResult): KPResult = fun(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_vector() {
|
|
// A sequence!
|
|
var sub_rule_names = nonterminal_str + "_seq_" + new_tmp()
|
|
var inner_rule = add_grammer_rule_helper(sub_rule_names, rule[i].get_vector_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(kpVector(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(kpVector(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(kpVector(vec(get_value(x[0])) + get_value(x[1]).get_vector_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(kpVector(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("add_grammar_rule"), make_builtin_combiner(str("add_grammar_rule"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
var params_evaled = vec<KPValue>()
|
|
for (var i = 0; i < params.size; i++;) {
|
|
var ip = EVAL(dynamic_env, params[i])
|
|
if is_err(ip) { return ip; }
|
|
params_evaled.add(get_value(ip))
|
|
}
|
|
if params_evaled.size != 3 || !params_evaled[0].is_symbol() || !params_evaled[1].is_vector() {
|
|
return KPResult::Err(kpString(str("add_grammar_rule called with wrong number or type of params_evaled")))
|
|
} else {
|
|
var nonterminal_str = params_evaled[0].get_symbol_text()
|
|
var rule = params_evaled[1].get_vector_rc().get()
|
|
return add_grammer_rule_helper(nonterminal_str, rule, params_evaled[2], fun(f: ref KPValue, x: ref vec<KPResult>): KPResult {
|
|
var params = vec<KPValue>()
|
|
for (var i = 0; i < x.size; i++;) {
|
|
if is_err(x[i]) {
|
|
return x[i]
|
|
}
|
|
// Have to let our params be evald
|
|
|
|
var our_quote.construct(null<KPEnv>(), str("doesn't matter"), vec(str("x")), false, kpSymbol("x")) : KPCombiner
|
|
params.add(kpVector(vec(nmMV(KPValue_int::Combiner(our_quote)), get_value(x[i]))))
|
|
}
|
|
return function_call(f, params, kpEnv(null<KPEnv>()))
|
|
})
|
|
}
|
|
}));
|
|
var ERS = fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("eval-read-string with not a single string and env")))
|
|
} else {
|
|
var ip = EVAL(dynamic_env, params[0])
|
|
if is_err(ip) { return ip; }
|
|
var ipv = get_value(ip)
|
|
if !ipv.is_string() {
|
|
return KPResult::Err(kpString(str("first param to eval-read-string s not a string")))
|
|
}
|
|
var input = ipv.get_string()
|
|
var ep = EVAL(dynamic_env, params[1])
|
|
if is_err(ep) { return ep; }
|
|
var epv = get_value(ep)
|
|
if !epv.is_env() {
|
|
return KPResult::Err(kpString(str("second param to eval-read-string is not a env")))
|
|
}
|
|
var eval_env = epv.get_env()
|
|
var i = 0
|
|
var current_ret = KPResult::Ok(kpNil())
|
|
if i < input.length() {
|
|
// initial handle whitespace
|
|
var BSR = fungll(grammar, optional_WS, input.slice(i, -1))
|
|
var longest = -1
|
|
for (var j = 0; j < BSR.data.size; j++;) {
|
|
if BSR.data[j].nonterminal == optional_WS && BSR.data[j].left == 0 {
|
|
if BSR.data[j].right > longest {
|
|
longest = BSR.data[j].right
|
|
}
|
|
}
|
|
}
|
|
if longest > 0 {
|
|
i += longest
|
|
}
|
|
}
|
|
while i < input.length() {
|
|
var r = read_str(grammar, input.slice(i, -1))
|
|
i += r.first
|
|
if is_err(r.second) {
|
|
return r.second
|
|
}
|
|
current_ret = EVAL(eval_env, get_value(r.second))
|
|
if is_err(current_ret) {
|
|
return current_ret
|
|
}
|
|
// handle whitespace again
|
|
var BSR = fungll(grammar, optional_WS, input.slice(i, -1))
|
|
var longest = -1
|
|
for (var j = 0; j < BSR.data.size; j++;) {
|
|
if BSR.data[j].nonterminal == optional_WS && BSR.data[j].left == 0 {
|
|
if BSR.data[j].right > longest {
|
|
longest = BSR.data[j].right
|
|
}
|
|
}
|
|
}
|
|
if longest > 0 {
|
|
i += longest
|
|
}
|
|
}
|
|
return current_ret
|
|
}
|
|
}
|
|
env->set(str("eval-read-string"), make_builtin_combiner(str("eval-read-string"), 0, ERS));
|
|
|
|
env->set(str("read-string"), make_builtin_combiner(str("read-string"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("read-string with not a single string")))
|
|
} else {
|
|
var ip = EVAL(dynamic_env, params[0])
|
|
if is_err(ip) { return ip; }
|
|
var ipv = get_value(ip)
|
|
if !ipv.is_string() {
|
|
return KPResult::Err(kpString(str("read-string with not a single string")))
|
|
}
|
|
return READ(grammar, ipv.get_string())
|
|
}
|
|
}));
|
|
env->set(str("slurp"), make_builtin_combiner(str("slurp"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("slurp with not a single string")))
|
|
} else {
|
|
var ip = EVAL(dynamic_env, params[0])
|
|
if is_err(ip) { return ip; }
|
|
var ipv = get_value(ip)
|
|
if !ipv.is_string() {
|
|
return KPResult::Err(kpString(str("read-string with not a single string")))
|
|
}
|
|
if !file_exists(ipv.get_string()) {
|
|
return KPResult::Err(kpString(str("read-string with bad path ") + ipv.get_string()))
|
|
}
|
|
return KPResult::Ok(kpString(read_file(ipv.get_string())))
|
|
}
|
|
}));
|
|
env->set(str("wrap"), make_builtin_combiner(str("wrap"), 1, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("wrap called with not one argument")))
|
|
}
|
|
match (params[0].internal) {
|
|
KPValue_int::Combiner(c) {
|
|
var to_ret = c;
|
|
to_ret.wrap_level++
|
|
return KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret)))
|
|
}
|
|
KPValue_int::BuiltinCombiner(c) {
|
|
var to_ret = c;
|
|
to_ret.wrap_level++
|
|
return KPResult::Ok(nmMV(KPValue_int::BuiltinCombiner(to_ret)))
|
|
}
|
|
}
|
|
return KPResult::Err(kpString(str("wrap called with not combiner ") + pr_str(params[0], true)))
|
|
}));
|
|
env->set(str("unwrap"), make_builtin_combiner(str("unwrap"), 1, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 1 {
|
|
return KPResult::Err(kpString(str("unwrap called with not one argument")))
|
|
}
|
|
match (params[0].internal) {
|
|
KPValue_int::Combiner(c) {
|
|
if c.wrap_level <= 0 {
|
|
return KPResult::Err(kpString(str("unwrap called with combiner at wrap_level <= 0")))
|
|
}
|
|
var to_ret = c;
|
|
to_ret.wrap_level--
|
|
return KPResult::Ok(nmMV(KPValue_int::Combiner(to_ret)))
|
|
}
|
|
KPValue_int::BuiltinCombiner(c) {
|
|
if c.wrap_level <= 0 {
|
|
return KPResult::Err(kpString(str("unwrap called with combiner at wrap_level <= 0")))
|
|
}
|
|
var to_ret = c;
|
|
to_ret.wrap_level--
|
|
return KPResult::Ok(nmMV(KPValue_int::BuiltinCombiner(to_ret)))
|
|
}
|
|
}
|
|
return KPResult::Err(kpString(str("unwrap called with not combiner ") + pr_str(params[0], true)))
|
|
}));
|
|
env->set(str("map"), make_builtin_combiner(str("map"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("map called with not two arguments")))
|
|
} else {
|
|
var fr = EVAL(dynamic_env, params[0])
|
|
if is_err(fr) { return fr; }
|
|
var f = get_value(fr)
|
|
if !f.is_combiner() {
|
|
return KPResult::Err(kpString(str("map called with not combiner")))
|
|
}
|
|
var lr = EVAL(dynamic_env, params[1])
|
|
if is_err(lr) { return lr; }
|
|
var l = get_value(lr)
|
|
|
|
var to_ret = vec<KPValue>()
|
|
for (var i = 0; i < l.get_vector_rc().get().size; i++;) {
|
|
// need to swap to this being derived and not have this obnoxious
|
|
// uneval
|
|
var result = function_call(f, vec(kpVector(vec(get_value(env->get("quote")), l.get_vector_rc().get().get(i)))), kpEnv(dynamic_env))
|
|
if is_err(result) {
|
|
return result
|
|
}
|
|
to_ret.add(get_value(result))
|
|
}
|
|
return KPResult::Ok(kpVector(to_ret))
|
|
}
|
|
}));
|
|
env->set(str("filter"), make_builtin_combiner(str("filter"), 0, fun(params: vec<KPValue>, dynamic_env: *KPEnv): KPResult {
|
|
if params.size != 2 {
|
|
return KPResult::Err(kpString(str("filter called with not one argument")))
|
|
} else {
|
|
var fr = EVAL(dynamic_env, params[0])
|
|
if is_err(fr) { return fr; }
|
|
var f = get_value(fr)
|
|
if !f.is_combiner() {
|
|
return KPResult::Err(kpString(str("filter called with not combiner")))
|
|
}
|
|
|
|
var lr = EVAL(dynamic_env, params[1])
|
|
if is_err(lr) { return lr; }
|
|
var l = get_value(lr)
|
|
|
|
var to_ret = vec<KPValue>()
|
|
for (var i = 0; i < l.get_vector_rc().get().size; i++;) {
|
|
var result = function_call(f, vec(l.get_vector_rc().get().get(i)), kpEnv(dynamic_env))
|
|
if is_err(result) {
|
|
return result
|
|
}
|
|
if get_value(result).is_truthy() {
|
|
to_ret.add(l.get_vector_rc().get().get(i))
|
|
}
|
|
}
|
|
return KPResult::Ok(kpVector(to_ret))
|
|
}
|
|
}));
|
|
|
|
// a tiny bit of self-implementation fun
|
|
println(rep(grammar, env, str("(set! load-file (vau de (f) (eval-read-string (slurp (eval f de)) de)))")))
|
|
|
|
if argc == 3 && str(argv[1]) == "-C" {
|
|
env->set(str("*ARGV*"), kpNil())
|
|
var evaled = ERS(vec(kpString(str(argv[2])), kpEnv(env)), env)
|
|
if is_err(evaled) {
|
|
printlnerr(str("Exception: ") + pr_str(get_err(evaled), true))
|
|
} else {
|
|
println("Result: " + pr_str(get_value(evaled), true))
|
|
}
|
|
} else if argc >= 2 {
|
|
var params = vec<KPValue>()
|
|
for (var i = 2; i < argc; i++;) {
|
|
params.add(kpString(str(argv[i])))
|
|
}
|
|
env->set(str("*ARGV*"), kpVector(params))
|
|
var eval_result_str = rep(grammar, env, str("(load-file \"") + argv[1] + "\")")
|
|
println(eval_result_str)
|
|
if eval_result_str.length() >= 11 && eval_result_str.slice(0,11) == "Exception: " {
|
|
error("aborting compile")
|
|
}
|
|
// check for compile
|
|
var main = env->get(str("main"))
|
|
if !is_err(main) {
|
|
println("Starting compile!")
|
|
error("Compiler not implemented")
|
|
} else {
|
|
println("No main function to compile, exiting")
|
|
}
|
|
} else {
|
|
while (true) {
|
|
var line = get_line(str("user> "), 1024)
|
|
if (line == "***EOF***")
|
|
break
|
|
println(rep(grammar, env, line))
|
|
}
|
|
}
|
|
}
|