2020-05-09 11:52:32 -04:00
import mem:*
2020-03-28 00:23:01 -04:00
import io:*
import str:*
import vec:*
import vec_literals:*
import util:*
import map:*
2020-05-10 00:17:30 -04:00
import rc:*
2020-03-28 00:23:01 -04:00
import fungll:*
2020-05-09 11:52:32 -04:00
adt MalValue_int {
True, // 1 11 1 0
False, // 0 11 1 0
Function: MalFunction, // 10 1 0
BuiltinFunction: MalBuiltinFunction, // '' ' '
String: str, // 01 1 0
Symbol: str, // 00 1 0
Int: int, // 0 0
2020-05-09 23:59:46 -04:00
Vector: rc<vec<MalValue>>, //<10sizebits> 1
2020-05-09 11:52:32 -04:00
// same encoding, but encodes 0-length null ptr
Nil // 00000000000 1
}
fun nmMV(i: ref MalValue_int): MalValue {
var to_ret.construct(i, null<MalValue>()): MalValue
return to_ret
}
fun malTrue(): MalValue {
return nmMV(MalValue_int::True())
}
fun malFalse(): MalValue {
return nmMV(MalValue_int::False())
}
fun bool_to_MalValue(b: bool): MalValue {
if b {
return nmMV(MalValue_int::True())
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return nmMV(MalValue_int::False())
2020-03-28 00:23:01 -04:00
}
}
2020-05-09 11:52:32 -04:00
fun malString(s: ref str): MalValue {
return nmMV(MalValue_int::String(s))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun malSymbol(s: ref str): MalValue {
return nmMV(MalValue_int::Symbol(s))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun malInt(i: int): MalValue {
return nmMV(MalValue_int::Int(i))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun malVector(v: ref vec<MalValue>): MalValue {
2020-05-09 23:59:46 -04:00
var rcd.construct(v): rc<vec<MalValue>>
return nmMV(MalValue_int::Vector(rcd))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun malNil(): MalValue {
return nmMV(MalValue_int::Nil())
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
obj MalValue (Object) {
var internal: MalValue_int
var meta: *MalValue
fun construct(): *MalValue {
internal.copy_construct(&MalValue_int::Nil());
meta = null<MalValue>()
}
fun construct(i: ref MalValue_int, m: *MalValue): *MalValue {
internal.copy_construct(&i);
meta = m
}
fun copy_construct(other: *MalValue): void {
internal.copy_construct(&other->internal);
/*meta = other->meta*/
if other->meta != null<MalValue>() {
meta = new<MalValue>()
meta->copy_construct(other->meta)
} else {
meta = null<MalValue>()
2020-03-28 00:23:01 -04:00
}
}
2020-05-09 23:59:46 -04:00
fun operator=(other: ref MalValue): void {
destruct()
copy_construct(&other)
}
2020-05-09 11:52:32 -04:00
fun destruct(): void {
if meta != null<MalValue>()
delete(meta)
2020-05-09 23:59:46 -04:00
internal.destruct()
2020-05-09 11:52:32 -04:00
}
fun equals(other: ref MalValue): bool {
match (internal) {
MalValue_int::Vector(d) { match (other.internal) {
MalValue_int::Vector(db) {
2020-05-09 23:59:46 -04:00
if d.get().size != db.get().size {
2020-05-09 11:52:32 -04:00
return false
}
2020-05-09 23:59:46 -04:00
for (var i = 0; i < d.get().size; i++;) {
if !d.get()[i].equals(db.get()[i]) {
2020-05-09 11:52:32 -04:00
return false
}
}
return true
}
} }
MalValue_int::String(d) { match (other.internal) { MalValue_int::String(db) { return d == db; } } }
MalValue_int::Int(d) { match (other.internal) { MalValue_int::Int(db) { return d == db; } } }
MalValue_int::Symbol(d) { match (other.internal) { MalValue_int::Symbol(db) { return d == db; } } }
MalValue_int::Function(d){ match (other.internal) { MalValue_int::Function(db) { return d == db; } } }
MalValue_int::BuiltinFunction(d) { match (other.internal) { MalValue_int::BuiltinFunction(db) { return d == db; } } }
MalValue_int::True() { match (other.internal) { MalValue_int::True() { return true; } } }
MalValue_int::False() { match (other.internal) { MalValue_int::False() { return true; } } }
MalValue_int::Nil() { match (other.internal) { MalValue_int::Nil() { return true; } } }
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return false
}
2020-05-10 00:17:30 -04:00
fun deep_clone(): MalValue {
match (internal) {
MalValue_int::Vector(v) {
return malVector(v.get())
}
}
return *this
}
2020-05-12 00:32:12 -04:00
fun is_function(): bool {
match (internal) {
MalValue_int::Function(f) {
return true
}
MalValue_int::BuiltinFunction(f) {
return true
}
}
return false
}
2020-05-09 11:52:32 -04:00
fun is_vector(): bool {
match (internal) {
MalValue_int::Vector(v) {
return true
}
2020-05-09 23:59:46 -04:00
/*MalValue_int::Nil() {*/
/*return true*/
/*}*/
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return false
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
fun get_vector_rc(): rc<vec<MalValue>> {
2020-05-09 11:52:32 -04:00
match (internal) {
MalValue_int::Vector(v) {
return v
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
error("Tried to get vec on not a vec" + pr_str(*this, true))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun is_symbol(): bool {
match (internal) {
MalValue_int::Symbol(s) {
return true
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return false
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun is_symbol(text: *char): bool {
match (internal) {
MalValue_int::Symbol(s) {
return s == text
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return false
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun get_symbol_text(): str {
match (internal) {
MalValue_int::Symbol(s) {
return s
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
error("get_symbol_text on not symbol")
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun is_string(): bool {
match (internal) {
MalValue_int::String(s) {
return true
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return false
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun get_string(): str {
match (internal) {
MalValue_int::String(s) {
return s
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
error("get_string on not a string")
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun is_int(): bool {
match (internal) {
MalValue_int::Int(i) {
return true
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return false
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun get_int(): int {
match (internal) {
MalValue_int::Int(i) {
return i
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
error("get_int on not an int")
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun is_nil(): bool {
match (internal) {
MalValue_int::Nil() {
return true
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return false
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
fun is_truthy(): bool {
match (internal) {
MalValue_int::False() {
return false
}
MalValue_int::Nil() {
return false
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return true
}
fun is_pair(): bool {
2020-05-09 23:59:46 -04:00
return is_vector() && get_vector_rc().get().size > 0
2020-03-28 00:23:01 -04:00
}
}
2020-05-09 11:52:32 -04:00
fun read_str(grammer: ref Grammer<MalResult,MalValue>, s: str): pair<int, MalResult> {
var BSR = fungll(grammer, grammer.start_symbol, s)
var longest = -1
for (var i = 0; i < BSR.data.size; i++;) {
if BSR.data[i].nonterminal == grammer.start_symbol && BSR.data[i].left == 0 && BSR.data[i].idx_into_rule == grammer.nonterminals[(-1*BSR.data[i].nonterminal)-1][BSR.data[i].rule_idx].size {
longest = BSR.data[i].right
2020-03-28 00:23:01 -04:00
}
}
2020-05-09 11:52:32 -04:00
if longest >= 0 {
return make_pair(longest, grammer.eval_BSR(s.slice(0, longest), BSR))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
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 + ": " + grammer.to_string(BSR.data[i]))
}
println("Parse failed")
return make_pair(-1, MalResult::Err(malString(str("failed to parse"))))
2020-03-28 00:23:01 -04:00
}
}
fun is_macro_call(ast: MalValue, env: *Env): bool {
2020-05-09 11:52:32 -04:00
if !ast.is_vector() {
2020-03-28 00:23:01 -04:00
return false
}
2020-05-09 23:59:46 -04:00
var l = ast.get_vector_rc()
if l.get().size == 0 || !l.get()[0].is_symbol() {
2020-03-28 00:23:01 -04:00
return false
}
2020-05-09 23:59:46 -04:00
var res = env->get(l.get()[0].get_symbol_text())
2020-03-28 00:23:01 -04:00
if is_err(res) {
return false
}
var v = get_value(res)
2020-05-09 11:52:32 -04:00
match (v.internal) {
MalValue_int::Function(f) {
2020-03-28 00:23:01 -04:00
return f.is_macro
}
}
return false
}
fun macroexpand(ast: MalValue, env: *Env): MalResult {
while is_macro_call(ast, env) {
2020-05-09 23:59:46 -04:00
var l = ast.get_vector_rc()
var v = get_value(env->get(l.get()[0].get_symbol_text()))
2020-05-09 11:52:32 -04:00
match (v.internal) {
MalValue_int::Function(f) {
2020-05-09 23:59:46 -04:00
var params = l.get().slice(1,-1)
2020-03-28 00:23:01 -04:00
if (!f.is_variadic && f.parameters.size != params.size) || (f.is_variadic && f.parameters.size > params.size + 1) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("macro called with the wrong number of parameters")))
2020-03-28 00:23:01 -04:00
}
env = new<Env>()->construct(f.env)
for (var i = 0; i < f.parameters.size; i++;) {
if f.is_variadic && i == f.parameters.size - 1 {
2020-05-09 11:52:32 -04:00
env->set(f.parameters[i], malVector(params.slice(i, -1)))
2020-03-28 00:23:01 -04:00
} else {
env->set(f.parameters[i], params[i])
}
}
var tmp = *f.body
var tmp2 = EVAL(env, tmp)
if is_err(tmp2) {
return tmp2
}
ast = get_value(tmp2)
}
}
}
return MalResult::Ok(ast)
}
fun quasiquote(ast: MalValue): MalValue {
2020-05-09 11:52:32 -04:00
if !ast.is_pair() {
return malVector(vec(malSymbol(str("quote")), ast))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
var ast_list = ast.get_vector_rc()
if ast_list.get()[0].is_symbol("unquote") {
return ast_list.get()[1]
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
if ast_list.get()[0].is_pair() && ast_list.get()[0].get_vector_rc().get()[0].is_symbol("splice-unquote") {
return malVector(vec(malSymbol(str("concat")), ast_list.get()[0].get_vector_rc().get()[1], quasiquote(malVector(ast_list.get().slice(1,-1)))))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
return malVector(vec(malSymbol(str("cons")), quasiquote(ast_list.get()[0]), quasiquote(malVector(ast_list.get().slice(1,-1)))))
2020-03-28 00:23:01 -04:00
}
}
}
}
obj Env (Object) {
var data: map<str, MalValue>
var outer: *Env
fun construct(): *Env {
return construct(null<Env>())
}
fun construct(outer: *Env): *Env {
data.construct()
this->outer = outer
return this
}
fun copy_construct(old: *Env): void {
data.copy_construct(&old->data)
outer = old->outer
}
fun destruct(): void {
data.destruct()
outer = null<Env>()
}
fun operator=(other:ref Env):void {
destruct()
copy_construct(&other)
}
fun set(key: str, val: MalValue) {
data.set(key, val)
}
2020-04-17 10:31:38 -04:00
fun remove(key: str) {
data.remove(key)
}
2020-03-28 00:23:01 -04:00
fun find(key: str): *Env {
if (data.contains_key(key)) {
return this
} else if (outer != null<Env>()) {
return outer->find(key)
} else {
return null<Env>()
}
}
fun get(key: str): MalResult {
var env = find(key)
if (env != null<Env>()) {
return MalResult::Ok(env->data.get(key))
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("'") + key + "' not found"))
2020-03-28 00:23:01 -04:00
}
}
2020-04-19 21:52:21 -04:00
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] + ": " + data.values[i] + "\n"*/
s += tabs + data.keys[i] + "\n"
}
if outer != null<Env>() {
outer->to_string(tabs + "\t", s)
}
}
2020-03-28 00:23:01 -04:00
}
obj MalBuiltinFunction (Object) {
2020-05-10 21:33:47 -04:00
var name: str
2020-03-28 00:23:01 -04:00
var fp: fun(vec<MalValue>): MalResult
2020-05-10 21:33:47 -04:00
fun construct(name: ref str, fp: fun(vec<MalValue>): MalResult): *MalBuiltinFunction {
this->name.copy_construct(&name)
2020-03-28 00:23:01 -04:00
this->fp = fp
return this
}
fun copy_construct(old: *MalBuiltinFunction): void {
this->fp = old->fp
2020-05-10 21:33:47 -04:00
this->name.copy_construct(&old->name)
2020-03-28 00:23:01 -04:00
}
fun destruct(): void {
2020-05-10 21:33:47 -04:00
this->name.destruct()
2020-03-28 00:23:01 -04:00
}
fun operator=(other:ref MalBuiltinFunction):void {
destruct()
copy_construct(&other)
}
fun operator==(other: ref MalBuiltinFunction):bool {
return false
}
fun call(params: vec<MalValue>): MalResult {
return fp(params)
}
}
2020-05-10 21:33:47 -04:00
fun make_builtin_function(name: str, f: fun(vec<MalValue>): MalResult): MalValue {
var to_ret.construct(name, f): MalBuiltinFunction
2020-05-09 11:52:32 -04:00
return nmMV(MalValue_int::BuiltinFunction(to_ret))
2020-03-28 00:23:01 -04:00
}
obj MalFunction (Object) {
var env: *Env
var parameters: vec<str>
var is_variadic: bool
var is_macro: bool
var body: *MalValue
fun construct(env: *Env, parameters: vec<str>, is_variadic: bool, is_macro: bool, body: MalValue): *MalFunction {
this->env = env
this->parameters.copy_construct(¶meters)
this->is_variadic = is_variadic
this->is_macro = is_macro
this->body = new<MalValue>()
this->body->copy_construct(&body)
return this
}
fun copy_construct(old: *MalFunction): void {
this->env = old->env
this->parameters.copy_construct(&old->parameters)
this->is_variadic = old->is_variadic
this->is_macro = old->is_macro
this->body = new<MalValue>()
this->body->copy_construct(old->body)
}
fun destruct(): void {
this->env = null<Env>()
parameters.destruct()
delete(body)
body = null<MalValue>()
}
fun operator=(other:ref MalFunction):void {
destruct()
copy_construct(&other)
}
fun operator==(other: ref MalFunction):bool {
// not sure about env
2020-05-09 11:52:32 -04:00
return env == other.env && parameters == other.parameters && is_variadic == other.is_variadic && is_macro == other.is_macro && body->equals(*other.body)
2020-03-28 00:23:01 -04:00
}
// no call b/c need to do in EVAL for TCO
2020-05-09 23:59:46 -04:00
fun prep_call(params: ref vec<MalValue>): pair<*Env, MalResult> {
2020-03-28 00:23:01 -04:00
// tco
if (!is_variadic && parameters.size != params.size) || (is_variadic && parameters.size > params.size + 1) {
2020-05-09 11:52:32 -04:00
return make_pair(null<Env>(), MalResult::Err(malString(str("function called with the wrong number of parameters: ") + params.size + " but expecting " + parameters.size + ": [ " + str(",").join(parameters) + "], was: " + pr_str(malVector(params), true) + ", function body is " + pr_str(*body, true))))
2020-03-28 00:23:01 -04:00
}
var new_env = new<Env>()->construct(env)
for (var i = 0; i < parameters.size; i++;) {
if is_variadic && i == parameters.size - 1 {
2020-05-09 11:52:32 -04:00
new_env->set(parameters[i], malVector(params.slice(i, -1)))
2020-03-28 00:23:01 -04:00
} else {
new_env->set(parameters[i], params[i])
}
}
return make_pair(new_env, MalResult::Ok(*body))
}
}
2020-05-09 23:59:46 -04:00
fun function_call(f: MalValue, params: ref vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
match (f.internal) {
MalValue_int::BuiltinFunction(f) {
2020-03-28 00:23:01 -04:00
return f.call(params)
}
2020-05-09 11:52:32 -04:00
MalValue_int::Function(f) {
2020-03-28 00:23:01 -04:00
var call_pair = f.prep_call(params)
if is_err(call_pair.second) {
return call_pair.second
}
return EVAL(call_pair.first, get_value(call_pair.second))
}
}
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("trying to apply not a function: ") + pr_str(f ,true)))
2020-03-28 00:23:01 -04:00
}
adt MalResult {
Ok: MalValue,
Err: MalValue
}
fun is_err(r: MalResult): bool {
match (r) {
MalResult::Err(e) {
return true
}
}
return false
}
fun get_err(r: MalResult): MalValue {
match (r) {
MalResult::Err(e) {
return e
}
}
2020-05-12 00:32:12 -04:00
/*return malSymbol(str("get-err-not-error"))*/
error("get-err-not-error")
2020-03-28 00:23:01 -04:00
}
fun get_value(r: MalResult): MalValue {
match (r) {
MalResult::Ok(v) {
return v
}
}
2020-05-12 00:32:12 -04:00
/*return malSymbol(str("get-value-is-error"))*/
error("get-value-is-error")
2020-03-28 00:23:01 -04:00
}
fun pr_str(v: MalValue, print_readably: bool): str {
2020-05-09 11:52:32 -04:00
match (v.internal) {
MalValue_int::Vector(l) {
2020-05-10 00:17:30 -04:00
var to_ret = str("( ")
2020-05-09 23:59:46 -04:00
for (var i = 0; i < l.get().size; i++;) {
2020-03-28 00:23:01 -04:00
if (i != 0) {
to_ret += " "
}
2020-05-09 23:59:46 -04:00
to_ret += pr_str(l.get()[i], print_readably)
2020-03-28 00:23:01 -04:00
}
2020-05-10 00:17:30 -04:00
return to_ret + " )"
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::Int(i) {
2020-03-28 00:23:01 -04:00
return to_string(i)
}
2020-05-09 11:52:32 -04:00
MalValue_int::String(s) {
2020-03-28 00:23:01 -04:00
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
}
}
2020-05-09 11:52:32 -04:00
MalValue_int::Symbol(s) {
if print_readably {
return "'" + s
} else {
return s
}
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::BuiltinFunction(f) {
2020-03-28 00:23:01 -04:00
return str("builtin function")
}
2020-05-09 11:52:32 -04:00
MalValue_int::Function(f) {
2020-03-28 00:23:01 -04:00
return str("function")
}
2020-05-09 11:52:32 -04:00
MalValue_int::True() {
2020-03-28 00:23:01 -04:00
return str("true")
}
2020-05-09 11:52:32 -04:00
MalValue_int::False() {
2020-03-28 00:23:01 -04:00
return str("false")
}
2020-05-09 11:52:32 -04:00
MalValue_int::Nil() {
2020-03-28 00:23:01 -04:00
return str("nil")
}
}
error("can't print")
}
2020-03-29 22:07:55 -04:00
fun READ(grammer: ref Grammer<MalResult, MalValue>, s: str): MalResult {
2020-03-30 19:51:01 -04:00
var to_ret = read_str(grammer, 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
2020-03-28 00:23:01 -04:00
}
fun eval_ast(env: *Env, ast: MalValue): MalResult {
2020-05-09 11:52:32 -04:00
match (ast.internal) {
MalValue_int::Vector(l) {
2020-03-28 00:23:01 -04:00
var to_ret = vec<MalValue>()
2020-05-09 23:59:46 -04:00
for (var i = 0; i < l.get().size; i++;) {
var mid = EVAL(env, l.get()[i])
2020-03-28 00:23:01 -04:00
if is_err(mid) {
return mid
}
to_ret.add(get_value(mid))
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malVector(to_ret))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::Symbol(s) {
2020-03-28 00:23:01 -04:00
return env->get(s)
}
}
return MalResult::Ok(ast)
}
fun EVAL(env: *Env, ast: MalValue): MalResult {
// for tco
while (true) {
var expanded = macroexpand(ast, env)
if (is_err(expanded)) {
return expanded
}
ast = get_value(expanded)
2020-05-09 11:52:32 -04:00
if !ast.is_vector() {
2020-03-28 00:23:01 -04:00
return eval_ast(env, ast)
}
2020-05-09 11:52:32 -04:00
match (ast.internal) {
MalValue_int::Vector(l) {
2020-05-09 23:59:46 -04:00
if (l.get().size == 0) {
2020-03-28 00:23:01 -04:00
return MalResult::Ok(ast)
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("def!")) {
if (l.get().size != 3) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("def! without exaclty key and value")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
if (!l.get()[1].is_symbol()) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("def! not on symbol")))
2020-03-28 00:23:01 -04:00
}
2020-04-19 21:52:21 -04:00
if env->outer != null<Env>() {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("def! not at top level")))
2020-04-19 21:52:21 -04:00
}
2020-05-09 23:59:46 -04:00
var value = EVAL(env, l.get()[2])
2020-03-28 00:23:01 -04:00
if (is_err(value)) {
return value
}
2020-05-09 23:59:46 -04:00
env->set(l.get()[1].get_symbol_text(), get_value(value))
2020-03-28 00:23:01 -04:00
return value
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("defmacro!")) {
if (l.get().size != 3) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("defmacro! without exaclty key and value")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
if (!l.get()[1].is_symbol()) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("defmacro! not on symbol")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
var value = EVAL(env, l.get()[2])
2020-03-28 00:23:01 -04:00
if (is_err(value)) {
return value
}
var v = get_value(value)
2020-05-09 11:52:32 -04:00
match (v.internal) {
MalValue_int::Function(f) {
2020-03-28 00:23:01 -04:00
f.is_macro = true
2020-05-09 23:59:46 -04:00
env->set(l.get()[1].get_symbol_text(), nmMV(MalValue_int::Function(f)))
2020-03-28 00:23:01 -04:00
return value
}
}
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("defmacro! on not a function")))
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("let*")) {
if (l.get().size != 3) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("let* without list of bindings & end value")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
if (!l.get()[1].is_vector()) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("let* without list of bindings")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
var bindings = l.get()[1].get_vector_rc()
if (bindings.get().size & 1 != 0) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("let* list of bindings has odd number of entries")))
2020-03-28 00:23:01 -04:00
}
var new_env = new<Env>()->construct(env)
2020-05-09 23:59:46 -04:00
for (var i = 0; i < bindings.get().size; i+=2;) {
if (!bindings.get()[i].is_symbol()) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("let* var name not symbol")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
var to_set_value = EVAL(new_env, bindings.get()[i+1])
2020-03-28 00:23:01 -04:00
if (is_err(to_set_value)) {
return to_set_value
}
2020-05-09 23:59:46 -04:00
new_env->set(bindings.get()[i].get_symbol_text(), get_value(to_set_value))
2020-03-28 00:23:01 -04:00
}
// tco
env = new_env
2020-05-09 23:59:46 -04:00
var tmp = l.get()[2]
2020-03-28 00:23:01 -04:00
ast = tmp
continue
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("do")) {
for (var i = 1; i < l.get().size-1; i++;) {
var mid = EVAL(env, l.get()[i])
2020-03-28 00:23:01 -04:00
if is_err(mid) {
return mid
}
}
// tco
2020-05-09 23:59:46 -04:00
var tmp = l.get()[l.get().size-1]
2020-03-28 00:23:01 -04:00
ast = tmp
continue
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("if")) {
if l.get().size != 3 && l.get().size != 4 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("if needs 2 or 3 children")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
var cond = EVAL(env, l.get()[1])
2020-03-28 00:23:01 -04:00
if is_err(cond) {
return cond
}
// tco
2020-05-09 11:52:32 -04:00
if get_value(cond).is_truthy() {
2020-05-09 23:59:46 -04:00
var tmp = l.get()[2]
2020-03-28 00:23:01 -04:00
ast = tmp
2020-05-09 23:59:46 -04:00
} else if l.get().size == 4 {
var tmp = l.get()[3]
2020-03-28 00:23:01 -04:00
ast = tmp
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malNil())
2020-03-28 00:23:01 -04:00
}
continue
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("fn*")) {
if l.get().size != 3 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("fn* needs 2 children")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
if (!l.get()[1].is_vector()) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("fn* without list of parameters")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
var parameters = l.get()[1].get_vector_rc()
2020-03-28 00:23:01 -04:00
var parameters_str = vec<str>()
var is_variadic = false
2020-05-09 23:59:46 -04:00
for (var i = 0; i < parameters.get().size; i++;) {
if (!parameters.get()[i].is_symbol()) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("fn* parameter name not symbol")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
var symbol_text = parameters.get()[i].get_symbol_text()
2020-03-28 00:23:01 -04:00
if symbol_text == "&" {
2020-05-09 23:59:46 -04:00
if i != parameters.get().size - 2 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("fn* has wrong number of arguments after &")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
if (!parameters.get()[i+1].is_symbol()) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("fn* parameter name not symbol")))
2020-03-28 00:23:01 -04:00
}
is_variadic = true
i++
2020-05-09 23:59:46 -04:00
symbol_text = parameters.get()[i].get_symbol_text()
2020-03-28 00:23:01 -04:00
}
parameters_str.add(symbol_text)
}
2020-05-09 23:59:46 -04:00
var to_ret.construct(env, parameters_str, is_variadic, false, l.get()[2]): MalFunction
2020-05-09 11:52:32 -04:00
return MalResult::Ok(nmMV(MalValue_int::Function(to_ret)))
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("quote")) {
if l.get().size == 1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("quote with no arguments")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
return MalResult::Ok(l.get()[1])
} else if (l.get()[0].is_symbol("quasiquote")) {
if l.get().size == 1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("quasiquote with no arguments")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
var tmp = quasiquote(l.get()[1])
2020-03-28 00:23:01 -04:00
ast = tmp
continue
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("macroexpand")) {
if l.get().size == 1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("macroexpand with no arguments")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
return macroexpand(l.get()[1], env)
} else if (l.get()[0].is_symbol("try*")) {
if l.get().size != 2 && (l.get().size != 3 || !l.get()[2].is_vector()) {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("try* wrong arguments")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
var A = EVAL(env, l.get()[1])
if l.get().size == 3 && is_err(A) {
var catch = l.get()[2].get_vector_rc()
if catch.get().size != 3 || !catch.get()[0].is_symbol("catch*") || !catch.get()[1].is_symbol() {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("catch* block malformed")))
2020-03-28 00:23:01 -04:00
}
var new_env = new<Env>()->construct(env)
2020-05-09 23:59:46 -04:00
env->set(catch.get()[1].get_symbol_text(), get_err(A))
return EVAL(new_env, catch.get()[2])
2020-03-28 00:23:01 -04:00
} else {
return A
}
} else {
var mid = eval_ast(env, ast)
if is_err(mid) {
return mid
}
2020-05-09 23:59:46 -04:00
var to_call = get_value(mid).get_vector_rc()
match (to_call.get()[0].internal) {
2020-05-09 11:52:32 -04:00
MalValue_int::BuiltinFunction(f) {
2020-05-09 23:59:46 -04:00
return f.call(to_call.get().slice(1,-1))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::Function(f) {
2020-05-09 23:59:46 -04:00
var params = to_call.get().slice(1,-1)
var call_pair = f.prep_call(to_call.get().slice(1, -1))
2020-03-28 00:23:01 -04:00
if is_err(call_pair.second) {
return call_pair.second
}
env = call_pair.first
ast = get_value(call_pair.second)
continue
}
}
2020-05-09 23:59:46 -04:00
return MalResult::Err(malString(str("trying to call not a function:") + pr_str(to_call.get()[0], true)))
2020-03-28 00:23:01 -04:00
}
}
}
return eval_ast(env, ast)
}
}
2020-03-29 22:07:55 -04:00
fun rep(grammer: ref Grammer<MalResult, MalValue>, env: *Env, a: str): str {
2020-03-29 20:42:51 -04:00
var read = READ(grammer, a)
2020-03-28 00:23:01 -04:00
if is_err(read) {
2020-04-12 15:52:45 -04:00
return pr_str(get_err(read), true)
2020-03-28 00:23:01 -04:00
} else {
var evaled = EVAL(env, get_value(read))
if is_err(evaled) {
2020-04-12 15:52:45 -04:00
return str("Exception: ") + pr_str(get_err(evaled), true)
2020-03-28 00:23:01 -04:00
} else {
2020-04-12 15:52:45 -04:00
return pr_str(get_value(evaled), true)
2020-03-28 00:23:01 -04:00
}
}
}
2020-05-09 23:59:46 -04:00
fun print_wrapper(params: ref vec<MalValue>, sep: *char, print_readably: bool): str {
2020-03-28 00:23:01 -04:00
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 to_ret
}
fun main(argc: int, argv: **char): int {
2020-03-29 20:42:51 -04:00
2020-03-29 22:07:55 -04:00
var grammer.construct(): Grammer<MalResult, MalValue>
2020-03-29 20:42:51 -04:00
2020-05-09 11:52:32 -04:00
var ret_nil_term: fun(ref MalValue, ref str, int, int): MalResult = fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult { return MalResult::Ok(malNil()); }
var ret_nil_sym: fun(ref MalValue, ref vec<MalResult>): MalResult = fun(_: ref MalValue, x: ref vec<MalResult>): MalResult { return MalResult::Ok(malNil()); }
2020-03-29 22:07:55 -04:00
var ret_0_sym: fun(ref MalValue, ref vec<MalResult>): MalResult = fun(_: ref MalValue, x: ref vec<MalResult>): MalResult { return x[0]; }
2020-03-29 20:42:51 -04:00
2020-03-31 15:15:45 -04:00
var WS = grammer.add_new_nonterminal("WS", vec(grammer.add_terminal("( | |
2020-03-29 20:42:51 -04:00
|(;[ -~]*
2020-05-09 11:52:32 -04:00
))+", malNil(), ret_nil_term)), malNil(), ret_nil_sym)
var optional_WS = grammer.add_new_nonterminal("optional_WS", vec<int>(), malNil(), ret_nil_sym)
grammer.add_to_nonterminal(optional_WS, vec(WS), malNil(), ret_nil_sym)
2020-03-29 20:42:51 -04:00
2020-05-09 11:52:32 -04:00
var atom = grammer.add_new_nonterminal("atom", vec(grammer.add_terminal("-?[0-9]+", malNil(), fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult { return MalResult::Ok(malInt(string_to_num<int>(input.slice(l,r)))); })), malNil(), ret_0_sym)
2020-03-29 20:42:51 -04:00
grammer.add_to_nonterminal(atom, vec(grammer.add_terminal("\"([#-[]| |[]-~]|(\\\\)|(\\n)|(\\t)|(\\\*)|(\\0)|
2020-05-09 11:52:32 -04:00
|[ -!]|(\\\\\"))*\"", malNil(), fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult { //"
2020-03-29 20:42:51 -04:00
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 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("bad string escape")))
2020-03-29 20:42:51 -04:00
}
// skip
i++
} else {
to_ret += input[i]
}
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malString(to_ret));
})), malNil(), ret_0_sym)
grammer.add_to_nonterminal(atom, vec(grammer.add_terminal("-|(([a-z]|[A-Z]|_|\\*|/|\\?|\\+|!|=|&|<|>)([a-z]|[A-Z]|_|[0-9]|\\*|\\?|\\+|-|!|=|&|<|>)*)", malNil(), fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult {
2020-03-29 20:56:27 -04:00
var s = input.slice(l,r)
if s == "true" {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malTrue());
2020-03-29 20:56:27 -04:00
} else if s == "false" {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malFalse());
2020-03-29 20:56:27 -04:00
} else if s == "nil" {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malNil());
2020-03-29 20:56:27 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malSymbol(input.slice(l,r)));
2020-03-29 20:56:27 -04:00
}
2020-05-09 11:52:32 -04:00
})), malNil(), ret_0_sym)
2020-03-29 20:42:51 -04:00
2020-05-09 11:52:32 -04:00
var form = grammer.add_new_nonterminal("form", vec(atom), malNil(), ret_0_sym)
var space_forms = grammer.add_new_nonterminal("space_forms", vec<int>(), malNil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult {
return MalResult::Ok(malVector(vec<MalValue>()))
2020-04-02 14:47:50 -04:00
})
2020-05-09 11:52:32 -04:00
grammer.add_to_nonterminal(space_forms, vec(form), malNil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult {
2020-03-29 20:42:51 -04:00
if is_err(x[0]) {
return x[0]
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malVector(vec(get_value(x[0]))))
2020-03-29 20:42:51 -04:00
})
2020-05-09 11:52:32 -04:00
grammer.add_to_nonterminal(space_forms, vec(form, WS, space_forms), malNil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult {
2020-03-29 20:42:51 -04:00
if is_err(x[0]) {
return x[0]
}
2020-05-09 11:52:32 -04:00
if is_err(x[2]) {
return x[2]
2020-03-29 20:42:51 -04:00
}
2020-05-09 23:59:46 -04:00
return MalResult::Ok(malVector(vec(get_value(x[0])) + get_value(x[2]).get_vector_rc().get()))
2020-03-29 20:42:51 -04:00
})
2020-05-09 11:52:32 -04:00
grammer.add_to_nonterminal(form, vec(grammer.add_terminal("\\(", malNil(), ret_nil_term),
2020-04-10 22:46:53 -04:00
optional_WS,
2020-05-09 11:52:32 -04:00
grammer.add_terminal("\\)", malNil(), ret_nil_term)), malNil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult { return MalResult::Ok(malVector(vec<MalValue>())); })
grammer.add_to_nonterminal(form, vec(grammer.add_terminal("\\(", malNil(), ret_nil_term),
2020-03-29 20:42:51 -04:00
optional_WS,
space_forms,
optional_WS,
2020-05-09 11:52:32 -04:00
grammer.add_terminal("\\)", malNil(), ret_nil_term)), malNil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult { return x[2]; })
2020-03-29 20:42:51 -04:00
grammer.set_start_symbol(form)
2020-03-28 00:23:01 -04:00
var env = new<Env>()->construct()
2020-05-10 21:33:47 -04:00
env->set(str("+"), make_builtin_function(str("+"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
var to_ret = 0
for (var i = 0; i < params.size; i++;) {
2020-05-09 11:52:32 -04:00
match (params[i].internal) {
MalValue_int::Int(v) {
2020-03-28 00:23:01 -04:00
to_ret += v
continue
}
}
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("called + with not an int: ") + pr_str(params[i], false)))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malInt(to_ret))
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("-"), make_builtin_function(str("-"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
var to_ret = 0
for (var i = 0; i < params.size; i++;) {
2020-05-09 11:52:32 -04:00
match (params[i].internal) {
MalValue_int::Int(v) {
2020-03-28 00:23:01 -04:00
if (i == 0) {
to_ret += v
} else {
to_ret -= v
}
continue
}
}
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("called - with not an int: ") + pr_str(params[i], false)))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malInt(to_ret))
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("*"), make_builtin_function(str("*"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
var to_ret = 1
for (var i = 0; i < params.size; i++;) {
2020-05-09 11:52:32 -04:00
match (params[i].internal) {
MalValue_int::Int(v) {
2020-03-28 00:23:01 -04:00
to_ret *= v
continue
}
}
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("called * with not an int: ") + pr_str(params[i], false)))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malInt(to_ret))
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("/"), make_builtin_function(str("/"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
var to_ret = 1
for (var i = 0; i < params.size; i++;) {
2020-05-09 11:52:32 -04:00
match (params[i].internal) {
MalValue_int::Int(v) {
2020-03-28 00:23:01 -04:00
if (i == 0) {
to_ret *= v
} else {
to_ret /= v
}
continue
}
}
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("called / with not an int: ") + pr_str(params[i], false)))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malInt(to_ret))
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("="), make_builtin_function(str("="), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
if params.size != 2 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("= with not two parameters")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].equals(params[1])))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("<"), make_builtin_function(str("<"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 || !params[0].is_int() || !params[1].is_int() {
return MalResult::Err(malString(str("< with not two numbers")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].get_int() < params[1].get_int()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("<="), make_builtin_function(str("<="), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 || !params[0].is_int() || !params[1].is_int() {
return MalResult::Err(malString(str("<= with not two numbers")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].get_int() <= params[1].get_int()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str(">"), make_builtin_function(str(">"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 || !params[0].is_int() || !params[1].is_int() {
return MalResult::Err(malString(str("> with not two numbers")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].get_int() > params[1].get_int()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str(">="), make_builtin_function(str(">="), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 || !params[0].is_int() || !params[1].is_int() {
return MalResult::Err(malString(str(">= with not two numbers")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].get_int() >= params[1].get_int()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("str"), make_builtin_function(str("str"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malString(print_wrapper(params, "", false)))
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("prn"), make_builtin_function(str("prn"), fun(params: vec<MalValue>): MalResult {
2020-04-22 21:10:46 -04:00
if params.size == 0 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("Called prn with 0 parameters")))
2020-04-22 21:10:46 -04:00
}
println(pr_str(params[0], true))
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malNil())
2020-04-22 21:10:46 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("pr-str"), make_builtin_function(str("pr-str"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malString(print_wrapper(params, " ", true)))
2020-04-22 21:10:46 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("prn"), make_builtin_function(str("prn"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
println(print_wrapper(params, " ", true))
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malNil())
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("println"), make_builtin_function(str("println"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
println(print_wrapper(params, " ", false))
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malNil())
2020-04-22 21:10:46 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("empty?"), make_builtin_function(str("empty?"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size == 0 || !params[0].is_vector() {
return MalResult::Err(malString(str("first parameter of empty? is not a list")))
2020-04-22 21:10:46 -04:00
} else {
2020-05-09 23:59:46 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].get_vector_rc().get().size == 0))
2020-04-22 21:10:46 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("count"), make_builtin_function(str("count"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size == 0 || !params[0].is_vector() {
return MalResult::Err(malString(str("first parameter of count is not a list")))
2020-04-22 21:10:46 -04:00
} else {
2020-05-09 23:59:46 -04:00
return MalResult::Ok(malInt(params[0].get_vector_rc().get().size))
2020-04-22 21:10:46 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("read-string"), make_builtin_function(str("read-string"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 1 || !params[0].is_string() {
return MalResult::Err(malString(str("read-string with not a single string")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return READ(grammer, params[0].get_string())
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("slurp"), make_builtin_function(str("slurp"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 1 || !params[0].is_string() {
return MalResult::Err(malString(str("slurp with not a single string")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malString(read_file(params[0].get_string())))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("eval"), make_builtin_function(str("eval"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
if params.size != 1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("eval with wrong number of params")))
2020-03-28 00:23:01 -04:00
} else {
return EVAL(env, params[0])
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("cons"), make_builtin_function(str("cons"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 || !params[1].is_vector() {
return MalResult::Err(malString(str("cons called with wrong number of params or second not an list/vec")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
return MalResult::Ok(malVector(vec(params[0]) + params[1].get_vector_rc().get()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("concat"), make_builtin_function(str("concat"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
var to_ret = vec<MalValue>()
for (var i = 0; i < params.size; i++;) {
2020-05-09 11:52:32 -04:00
if !params[i].is_vector() {
return MalResult::Err(malString(str("concat called with not an list")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
to_ret += params[i].get_vector_rc().get()
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malVector(to_ret))
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("nth"), make_builtin_function(str("nth"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 || !params[0].is_vector() || !params[1].is_int() {
return MalResult::Err(malString(str("nth called with wrong number or type of params")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
var list = params[0].get_vector_rc()
2020-05-09 11:52:32 -04:00
var idx = params[1].get_int()
2020-05-09 23:59:46 -04:00
if idx >= list.get().size {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("nth idx out of range")))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
return MalResult::Ok(list.get()[idx])
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("set-nth!"), make_builtin_function(str("set-nth!"), fun(params: vec<MalValue>): MalResult {
2020-05-10 00:17:30 -04:00
if params.size != 3 || !params[0].is_vector() || !params[1].is_int() {
return MalResult::Err(malString(str("set-nth! called with wrong number or type of params")))
} else {
var list = params[0].get_vector_rc()
var idx = params[1].get_int()
if idx >= list.get().size {
return MalResult::Err(malString(str("set-nth! idx out of range")))
}
list.get()[idx] = params[2];
return MalResult::Ok(malNil())
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("first"), make_builtin_function(str("first"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 1 || !params[0].is_vector() {
return MalResult::Err(malString(str("first called with wrong number or type of params") + pr_str(params[0], true)))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
var list = params[0].get_vector_rc()
if list.get().size == 0 {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malNil())
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
return MalResult::Ok(list.get()[0])
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("rest"), make_builtin_function(str("rest"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 1 || !params[0].is_vector() {
return MalResult::Err(malString(str("rest called with wrong number or type of params")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
var list = params[0].get_vector_rc()
if list.get().size == 0 {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malVector(vec<MalValue>()))
2020-03-28 00:23:01 -04:00
}
2020-05-09 23:59:46 -04:00
return MalResult::Ok(malVector(list.get().slice(1,-1)))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("throw"), make_builtin_function(str("throw"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
if params.size != 1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("throw called with wrong number or type of params")))
2020-03-28 00:23:01 -04:00
} else {
return MalResult::Err(params[0])
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("apply"), make_builtin_function(str("apply"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size < 2 || !params[params.size-1].is_vector() {
return MalResult::Err(malString(str("apply called with wrong number or type of params")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
var inner_params = params.slice(1,-2) + params[params.size-1].get_vector_rc().get()
2020-03-28 00:23:01 -04:00
return function_call(params[0], inner_params)
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("map"), make_builtin_function(str("map"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 || !params[1].is_vector() {
return MalResult::Err(malString(str("map called with wrong number or type of params")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 23:59:46 -04:00
var l = params[1].get_vector_rc()
2020-03-28 00:23:01 -04:00
var to_ret = vec<MalValue>()
2020-05-09 23:59:46 -04:00
for (var i = 0; i < l.get().size; i++;) {
var mid = function_call(params[0], vec(l.get()[i]))
2020-03-28 00:23:01 -04:00
if is_err(mid) {
return mid
}
to_ret.add(get_value(mid))
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malVector(to_ret))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("symbol?"), make_builtin_function(str("symbol?"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
if params.size != 1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("symbol? called with wrong number of params")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].is_symbol()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("symbol"), make_builtin_function(str("symbol"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 1 || !params[0].is_string() {
return MalResult::Err(malString(str("symbol called with wrong number or type of params")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malSymbol(params[0].get_string()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("vector"), make_builtin_function(str("vector"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malVector(params))
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("vector?"), make_builtin_function(str("vector?"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
if params.size != 1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("vector? called with wrong number of params")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].is_vector()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("sequential?"), make_builtin_function(str("sequential?"), fun(params: vec<MalValue>): MalResult {
2020-03-28 00:23:01 -04:00
if params.size != 1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("sequential? called with wrong number of params")))
} else if params[0].is_nil() {
return MalResult::Ok(malFalse())
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(bool_to_MalValue(params[0].is_vector()))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("readline"), make_builtin_function(str("readline"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 1 || !params[0].is_string() {
return MalResult::Err(malString(str("readline called with wrong number or type of params")))
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
var entered = get_line(params[0].get_string(), 1024)
2020-03-28 00:23:01 -04:00
if entered == "***EOF***" {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malNil())
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malString(entered))
2020-03-28 00:23:01 -04:00
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("meta"), make_builtin_function(str("meta"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 1 {
return MalResult::Err(malString(str("meta called with not one argument")))
} else {
if params[0].meta != null<MalValue>() {
return MalResult::Ok(*params[0].meta)
} else {
return MalResult::Ok(malNil())
}
}
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("with-meta"), make_builtin_function(str("with-meta"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 {
return MalResult::Err(malString(str("with-meta called with not two arguments")))
} else {
var new_meta = new<MalValue>()
new_meta->copy_construct(¶ms[1])
2020-05-10 00:17:30 -04:00
var new_value = params[0].deep_clone();
new_value.meta = new_meta
return MalResult::Ok(new_value)
2020-05-09 11:52:32 -04:00
}
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("fn?"), make_builtin_function(str("fn?"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("not implemented")))
2020-03-28 00:23:01 -04:00
}));
2020-05-10 21:33:47 -04:00
env->set(str("string?"), make_builtin_function(str("string?"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("not implemented")))
2020-03-28 00:23:01 -04:00
}));
2020-03-29 22:07:55 -04:00
// self-modifying grammer
2020-05-10 21:33:47 -04:00
env->set(str("add_terminal"), make_builtin_function(str("add_terminal"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 2 || !params[0].is_string() {
return MalResult::Err(malString(str("add_terminal called with wrong number or type of params")))
2020-03-29 22:07:55 -04:00
} else {
2020-05-09 11:52:32 -04:00
return MalResult::Ok(malInt(grammer.add_terminal(params[0].get_string(), params[1], fun(f: ref MalValue, input: ref str, l: int, r: int): MalResult {
return function_call(f, vec(malString(input.slice(l,r))))
2020-03-29 22:07:55 -04:00
})))
}
}));
2020-05-10 21:33:47 -04:00
env->set(str("add_grammer_rule"), make_builtin_function(str("add_grammer_rule"), fun(params: vec<MalValue>): MalResult {
2020-05-09 11:52:32 -04:00
if params.size != 3 || !params[0].is_symbol() || !params[1].is_vector() {
return MalResult::Err(malString(str("add_grammer_rule called with wrong number or type of params")))
2020-03-29 22:07:55 -04:00
} else {
2020-05-09 11:52:32 -04:00
var nonterminal_str = params[0].get_symbol_text()
2020-05-09 23:59:46 -04:00
var rule = params[1].get_vector_rc().get()
2020-03-29 22:07:55 -04:00
var int_rule = vec<int>()
for (var i = 0; i < rule.size; i++;) {
2020-05-09 11:52:32 -04:00
if rule[i].is_int() {
int_rule.add(rule[i].get_int())
} else if rule[i].is_symbol() {
var sub_nonterminal_idx = grammer.nonterminal_names.find(rule[i].get_symbol_text())
2020-03-31 15:15:45 -04:00
if sub_nonterminal_idx == -1 {
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("Couldn't find nonterminal: ") + rule[i].get_symbol_text()))
2020-03-31 15:15:45 -04:00
}
var sub_nonterminal = -1*(sub_nonterminal_idx+1)
int_rule.add(sub_nonterminal)
2020-05-09 11:52:32 -04:00
} else if rule[i].is_string() {
int_rule.add(grammer.add_terminal(rule[i].get_string(), malNil(), fun(f: ref MalValue, input: ref str, l: int, r: int): MalResult {
return MalResult::Ok(malString(input.slice(l,r)))
2020-03-31 15:15:45 -04:00
}))
} else {
2020-05-12 00:32:12 -04:00
match (rule[i].internal) {
MalValue_int::BuiltinFunction(f) {
if f.name == "+" || f.name == "*" {
if int_rule.size == 0 {
return MalResult::Err(malString(str("add_grammer_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 = grammer.add_to_or_create_nonterminal(sub_rule_names + "_one_or_more", vec(current), malNil(), fun(f: ref MalValue, x: ref vec<MalResult>): MalResult {
if is_err(x[0]) { return x[0]; }
return MalResult::Ok(malVector(vec(get_value(x[0]))))
})
grammer.add_to_nonterminal(new, vec(current, new), malNil(), fun(f: ref MalValue, x: ref vec<MalResult>): MalResult {
if is_err(x[0]) { return x[0]; }
if is_err(x[1]) { return x[1]; }
return MalResult::Ok(malVector(vec(get_value(x[0])) + get_value(x[1]).get_vector_rc().get()))
})
if f.name == "*" {
new = grammer.add_to_or_create_nonterminal(sub_rule_names + "_zero_or_more", vec(new), malNil(), fun(f: ref MalValue, x: ref vec<MalResult>): MalResult {
if is_err(x[0]) { return x[0]; }
return MalResult::Ok(get_value(x[0]))
})
grammer.add_to_nonterminal(new, vec<int>(), malNil(), fun(f: ref MalValue, x: ref vec<MalResult>): MalResult {
return MalResult::Ok(malVector(vec<MalValue>()))
})
}
int_rule.last() = new
continue
}
}
}
2020-05-09 11:52:32 -04:00
return MalResult::Err(malString(str("add_grammer_rule called with not symbol, int, or string in rule")))
2020-03-29 22:07:55 -04:00
}
}
2020-03-31 15:15:45 -04:00
grammer.add_to_or_create_nonterminal(nonterminal_str, int_rule, params[2], fun(f: ref MalValue, x: ref vec<MalResult>): MalResult {
var params = vec<MalValue>()
for (var i = 0; i < x.size; i++;) {
if is_err(x[i]) {
return x[i]
}
params.add(get_value(x[i]))
2020-03-29 22:07:55 -04:00
}
2020-05-12 09:33:33 -04:00
return function_call(f, params)
2020-03-31 15:15:45 -04:00
})
2020-05-12 00:32:12 -04:00
return MalResult::Ok(malNil())
2020-03-30 19:51:01 -04:00
}
}));
2020-05-09 11:52:32 -04:00
var ERS = fun(params: vec<MalValue>): MalResult {
if params.size != 1 || !params[0].is_string() {
return MalResult::Err(malString(str("eval-read-string called with wrong number or type of params")))
2020-03-30 19:51:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
var input = params[0].get_string()
2020-03-30 19:51:01 -04:00
var i = 0
2020-05-09 11:52:32 -04:00
var current_ret = MalResult::Ok(malNil())
2020-03-31 15:46:03 -04:00
if i < input.length() {
// initial handle whitespace
var BSR = fungll(grammer, 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
}
}
2020-03-30 19:51:01 -04:00
while i < input.length() {
var r = read_str(grammer, input.slice(i, -1))
i += r.first
if is_err(r.second) {
return r.second
}
current_ret = EVAL(env, get_value(r.second))
2020-03-31 15:15:45 -04:00
if is_err(current_ret) {
return current_ret
}
2020-03-31 15:46:03 -04:00
// handle whitespace again
2020-03-30 19:51:01 -04:00
var BSR = fungll(grammer, 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 {
2020-03-31 15:46:03 -04:00
if BSR.data[j].right > longest {
longest = BSR.data[j].right
}
2020-03-30 19:51:01 -04:00
}
}
if longest > 0 {
i += longest
}
}
return current_ret
}
2020-05-09 11:52:32 -04:00
}
2020-05-10 21:33:47 -04:00
env->set(str("eval-read-string"), make_builtin_function(str("eval-read-string"), ERS));
2020-03-31 15:15:45 -04:00
// reader macros
2020-05-12 09:33:33 -04:00
rep(grammer, env, str("(add_grammer_rule (quote atom) (vector \"'\" (quote form)) (fn* (_ x) (quasiquote (quote (unquote x)))))")) //'
rep(grammer, env, str("(add_grammer_rule 'form (vector \"\\\\[\" 'optional_WS \"\\\\]\") (fn* (& _) '(vector)))")) //'
rep(grammer, env, str("(add_grammer_rule 'form (vector \"\\\\[\" 'optional_WS 'space_forms 'optional_WS \"\\\\]\") (fn* (_ _ x _ _) (quasiquote (vector (splice-unquote x)))))")) //'
2020-04-12 15:52:45 -04:00
// now we can use ' for the rest
2020-05-12 09:33:33 -04:00
rep(grammer, env, str("(add_grammer_rule 'atom [\"`\" 'form] (fn* (_ x) (quasiquote (quasiquote (unquote x)))))"))
rep(grammer, env, str("(add_grammer_rule 'atom [\"~\" 'form] (fn* (_ x) (vector (quote unquote) x)))"))
2020-03-31 15:15:45 -04:00
// the standard appears to be for splice-unquote to be <symbol-for-unqoute><symbol-for-deref>, but unquote deref is a reasonable
// sequence of characters and causes ambigious parses! So I chose the other common unquote symbol to be splice-unquote
2020-05-12 09:33:33 -04:00
rep(grammer, env, str("(add_grammer_rule 'atom [\",\" 'form] (fn* (_ x) (vector (quote splice-unquote) x)))"))
rep(grammer, env, str("(add_grammer_rule 'atom [\"@\" 'form] (fn* (_ x) `(deref ~x)))")) //"
2020-03-31 15:15:45 -04:00
2020-03-29 20:42:51 -04:00
rep(grammer, env, str("(def! not (fn* (a) (if a false true)))"))
2020-03-30 19:51:01 -04:00
rep(grammer, env, str("(def! load-file (fn* (f) (eval-read-string (slurp f))))"))
2020-05-10 21:33:47 -04:00
rep(grammer, env, str("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (vector 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"))
2020-03-29 20:42:51 -04:00
rep(grammer, env, str("(def! nil? (fn* (a) (= nil a)))"))
2020-03-28 00:23:01 -04:00
var params = vec<MalValue>()
2020-05-09 11:52:32 -04:00
if argc == 3 && str(argv[1]) == "-C" {
env->set(str("*ARGV*"), malNil())
var evaled = ERS(vec(malString(str(argv[2]))))
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 {
2020-03-28 00:23:01 -04:00
for (var i = 2; i < argc; i++;) {
2020-05-09 11:52:32 -04:00
params.add(malString(str(argv[i])))
2020-03-28 00:23:01 -04:00
}
2020-05-09 11:52:32 -04:00
env->set(str("*ARGV*"), malVector(params))
2020-05-10 21:33:47 -04:00
var eval_result_str = rep(grammer, env, str("(load-file \"") + argv[1] + "\")")
println(eval_result_str)
2020-05-12 00:32:12 -04:00
if eval_result_str.length() >= 11 && eval_result_str.slice(0,11) == "Exception: " {
2020-05-10 21:33:47 -04:00
error("aborting compile")
}
2020-04-12 15:52:45 -04:00
// check for compile
var main = env->get(str("main"))
if !is_err(main) {
println("Starting compile!")
2020-05-09 11:52:32 -04:00
match (get_value(main).internal) {
MalValue_int::Function(f) {
2020-04-23 13:04:27 -04:00
var top_decs = str("#include <stdlib.h>\n#include <stdio.h>\n#include <stddef.h>\n#include <string.h>\n#include <setjmp.h>\n")
top_decs += """
jmp_buf *current_exception_handler;
size_t current_exception_value;
void error(char* message) {fprintf(stderr, "%s", message); exit(1);}
2020-04-19 01:25:20 -04:00
void check_num_params(size_t a, size_t b, char* function) { if (a!=b) {fprintf(stderr, "%s: expected num params to be %d\n", function, b); exit(1);}}
2020-05-11 23:20:54 -04:00
void check_num_params_at_least(size_t a, size_t b, char* function) { if (a<b) {fprintf(stderr, "%s: expected num params to be at least %d\n", function, b); exit(1);}}
2020-04-19 01:25:20 -04:00
void check_int(size_t p, char* function) { if ((p&0x7)!=0) {fprintf(stderr, "%s: expected param to be int\n", function); exit(1);}}
2020-05-09 13:30:38 -04:00
void check_vector(size_t p, char* function) { if ((p&0x7)!=0x2) {fprintf(stderr, "%s: expected param to be vector\n", function); exit(1);}}
2020-04-19 01:25:20 -04:00
void check_function(size_t p, char* message) { if ((p&0x7)!=0x6) {fprintf(stderr, "%s: expected a function\n", message); exit(1);}}
typedef struct {
size_t (*func)(size_t*,size_t,size_t*);
size_t* data;
} closure;
size_t _plus_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "+"); check_int(args[0], "+"); check_int(args[1], "+");
return (size_t)(((((ptrdiff_t)args[0]) >> 3) + (((ptrdiff_t)args[1]) >> 3)) << 3);
}"""
2020-04-14 23:34:23 -04:00
var top_defs = str("closure _plus_closure = { _plus_impl, NULL};\n")
2020-04-19 01:25:20 -04:00
top_defs += """size_t _minus_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "-"); check_int(args[0], "-"); check_int(args[1], "-");
return (size_t)(((((ptrdiff_t)args[0]) >> 3) - (((ptrdiff_t)args[1]) >> 3)) << 3);
}
closure _minus_closure =(closure){ _minus_impl, NULL};
size_t _mult_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "*"); check_int(args[0], "*"); check_int(args[1], "*");
return (size_t)(((((ptrdiff_t)args[0]) >> 3) * (((ptrdiff_t)args[1]) >> 3)) << 3);
}
closure _mult_closure = (closure){ _mult_impl, NULL};
size_t _div_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "/"); check_int(args[0], "/"); check_int(args[1], "/");
return (size_t)(((((ptrdiff_t)args[0]) >> 3) / (((ptrdiff_t)args[1]) >> 3)) << 3);
}
closure _div_closure = (closure){ _div_impl, NULL};
size_t _eq_impl(size_t* _, size_t num, size_t* args) {
2020-05-11 01:08:13 -04:00
check_num_params(num, 2, "=");
if (args[0] == args[1]) {
return 0x9F;
} else if ((args[0]&0x7) != (args[1]&0x7)) {
return 0x1F;
} else if ((args[0]&0x3) == 0x05) {
// string compare
char* str1 = (char*)(((size_t*)(args[0]>>3))+1);
char* str2 = (char*)(((size_t*)(args[1]>>3))+1);
if (strcmp(str1,str2) == 0) {
return 0x9F;
} else {
return 0x1F;
}
} else if ((args[0]&0x7) == 0x05) {
// symbol compare
char* sym1 = (char*)(((size_t*)(args[0]>>3))+1);
char* sym2 = (char*)(((size_t*)(args[1]>>3))+1);
if (strcmp(sym1,sym2) == 0) {
return 0x9F;
} else {
return 0x1F;
}
} else {
return 0x1F;
}
2020-04-19 01:25:20 -04:00
}
closure _eq_closure = (closure){ _eq_impl, NULL};
size_t _lt_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "<"); check_int(args[0], "<"); check_int(args[1], "<");
if (args[0] < args[1]) { return 0x9F; } else { return 0x1F; }
}
closure _lt_closure = (closure){ _lt_impl, NULL};
size_t _lte_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "<="); check_int(args[0], "<="); check_int(args[1], "<=");
if (args[0] <= args[1]) { return 0x9F; } else { return 0x1F; }
}
closure _lte_closure = (closure){ _lte_impl, NULL};
size_t _gt_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, ">"); check_int(args[0], ">"); check_int(args[1], ">");
if (args[0] > args[1]) { return 0x9F; } else { return 0x1F; }
}
closure _gt_closure = (closure){ _gt_impl, NULL};
size_t _gte_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, ">="); check_int(args[0], ">="); check_int(args[1], ">=");
if (args[0] >= args[1]) { return 0x9F; } else { return 0x1F; }
}
closure _gte_closure = (closure){ _gte_impl, NULL};
size_t _print_impl(size_t* _, size_t num, size_t* args) {
for (int _idx = 0; _idx < num; _idx++) {
if ((args[_idx] & 0xFF) == 0x2F) printf("nil");
else if ((args[_idx] & 0xFF) == 0x9F) printf("true");
else if ((args[_idx] & 0xFF) == 0x1F) printf("false");
else if ((args[_idx] & 0xFF) == 0x0F) printf("Char?");
else if ((args[_idx] & 0x07) == 0x06) printf("function");
2020-04-22 21:10:46 -04:00
else if ((args[_idx] & 0x07) == 0x05) printf("'%s", ((char*)(args[_idx]>>3))+sizeof(size_t));
2020-05-09 11:52:32 -04:00
else if ((args[_idx] & 0x07) == 0x03) printf("%s", ((char*)(args[_idx]>>3))+sizeof(size_t));
2020-04-22 21:10:46 -04:00
else if ((args[_idx] & 0x07) == 0x02) {
2020-05-09 11:52:32 -04:00
printf("( ");
2020-04-22 21:10:46 -04:00
size_t* vec = (size_t*)(args[_idx]>>3);
2020-05-09 13:30:38 -04:00
for (int i = 0; i < vec[1]; i++) {
_print_impl(NULL, 1, vec+i+2);
2020-04-22 21:10:46 -04:00
printf(" ");
}
2020-05-09 11:52:32 -04:00
printf(")");
2020-04-22 21:10:46 -04:00
} else if ((args[_idx] & 0x07) == 0x00) printf("%d", args[_idx]>>3);
2020-04-19 01:25:20 -04:00
else printf("can't print");
}
return 0x2F;
}
closure _print_closure = (closure){ _print_impl, NULL};
size_t _println_impl(size_t* _, size_t num, size_t* args) {
_print_impl(_, num, args);
printf("\n");
return 0x2F;
}
2020-04-19 21:52:21 -04:00
closure _println_closure = (closure){ _println_impl, NULL};
2020-04-20 01:16:34 -04:00
size_t _vector_impl(size_t* _, size_t num, size_t* args) {
2020-05-09 13:30:38 -04:00
size_t *vec = malloc(sizeof(size_t)*(num + 2));
vec[0] = 0x2F;
vec[1] = num;
2020-04-20 01:16:34 -04:00
for (int i = 0; i < num; i++)
2020-05-09 13:30:38 -04:00
vec[i+2] = args[i];
2020-04-20 01:16:34 -04:00
return ((((size_t)vec)<<3)|0x2);
}
closure _vector_closure = (closure){ _vector_impl, NULL};
size_t _nth_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "nth");
check_int(args[1], "nth");
2020-05-09 13:30:38 -04:00
if ((args[0] & 0x7) == 0x2) {
2020-04-20 01:16:34 -04:00
size_t* vec = (size_t*)(args[0]>>3);
2020-05-09 13:30:38 -04:00
if (((ptrdiff_t)(args[1]>>3)) < 0 || (args[1]>>3) >= vec[1]) {
2020-04-20 01:16:34 -04:00
error("nth idx out of range\n");
}
2020-05-09 13:30:38 -04:00
return vec[(args[1]>>3)+2];
2020-04-20 01:16:34 -04:00
} else {
2020-05-09 13:30:38 -04:00
error("Passed not a vector to nth\n");
2020-04-20 01:16:34 -04:00
}
return 0x2F;
}
closure _nth_closure = (closure){ _nth_impl, NULL};
2020-05-10 00:17:30 -04:00
size_t _set_nth_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 3, "set-nth!");
check_int(args[1], "set-nth!");
if ((args[0] & 0x7) == 0x2) {
size_t* vec = (size_t*)(args[0]>>3);
if (((ptrdiff_t)(args[1]>>3)) < 0 || (args[1]>>3) >= vec[1]) {
error("nth idx out of range\n");
}
vec[(args[1]>>3)+2] = args[2];
return 0x2F;
} else {
error("Passed not a vector to set-nth!\n");
}
}
closure _set_nth_closure = (closure){ _set_nth_impl, NULL};
2020-05-10 21:33:47 -04:00
size_t _cons_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "cons");
check_vector(args[1], "cons");
size_t* old_vec = (size_t*)(args[1]>>3);
size_t new_size = old_vec[1] + 1;
size_t *vec = malloc(sizeof(size_t)*(new_size + 2));
vec[0] = 0x2F;
vec[1] = new_size;
vec[2] = args[0];
for (int i = 0; i < old_vec[1]; i++)
vec[i+3] = old_vec[i+2];
return ((((size_t)vec)<<3)|0x2);
}
closure _cons_closure = (closure){ _cons_impl, NULL};
size_t _concat_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "concat");
check_vector(args[0], "concat");
check_vector(args[1], "concat");
size_t* vec1 = (size_t*)(args[0]>>3);
size_t* vec2 = (size_t*)(args[1]>>3);
size_t new_size = vec1[1] + vec2[1];
size_t *vec = malloc(sizeof(size_t)*(new_size + 2));
vec[0] = 0x2F;
vec[1] = new_size;
for (int i = 0; i < vec1[1]; i++)
vec[i+2] = vec1[i+2];
for (int i = 0; i < vec2[1]; i++)
vec[vec1[1]+i+2] = vec1[i+2];
return ((((size_t)vec)<<3)|0x2);
}
closure _concat_closure = (closure){ _concat_impl, NULL};
2020-05-09 13:30:38 -04:00
size_t _with_meta_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 2, "with-meta");
check_vector(args[0], "with-meta");
size_t* og_vec = (size_t*)(args[0]>>3);
size_t *vec = malloc(sizeof(size_t)*(og_vec[1] + 2));
vec[0] = args[1];
vec[1] = og_vec[1];
for (int i = 0; i < og_vec[1]; i++)
vec[i+2] = og_vec[i+2];
return ((((size_t)vec)<<3)|0x2);
}
closure _with_meta_closure = (closure){ _with_meta_impl, NULL};
size_t _meta_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 1, "meta");
check_vector(args[0], "meta");
return ((size_t*)(args[0]>>3))[0];
}
closure _meta_closure = (closure){ _meta_impl, NULL};
2020-04-23 13:04:27 -04:00
size_t _throw_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 1, "throw");
current_exception_value = args[0];
longjmp(*current_exception_handler, 1);
}
closure _throw_closure = (closure){ _throw_impl, NULL};
2020-05-11 01:08:13 -04:00
size_t _apply_impl(size_t* _, size_t num, size_t* args) {
if (num < 2) {fprintf(stderr, "apply: expected num params to be >= 2\n"); exit(1);}
check_function(args[0], "apply");
check_vector(args[num-1], "apply");
closure* func = (closure*)(args[0]>>3);
size_t* args_vec = (size_t*)(args[num-1]>>3);
size_t num_params = (num-2) + args_vec[1];
size_t* params = malloc(sizeof(size_t)*num_params);
for (int i = 0; i < (num-2); i++) {
params[i] = args[i+1];
}
for (int i = 0; i < args_vec[1]; i++) {
params[(num-2)+i] = args_vec[i+2];
}
size_t to_ret = func->func(func->data, num_params, params);
free(params);
return to_ret;
}
closure _apply_closure = (closure){ _apply_impl, NULL};
size_t _count_impl(size_t* _, size_t num, size_t* args) {
check_num_params(num, 1, "count");
check_vector(args[0], "count");
size_t* args_vec = (size_t*)(args[0]>>3);
return (args_vec[1] << 3);
}
closure _count_closure = (closure){ _count_impl, NULL};
2020-04-19 21:52:21 -04:00
""" //"
2020-04-14 23:34:23 -04:00
var main_s = str("int main(int argc, char** argv) {\n")
2020-04-17 10:31:38 -04:00
var main_body = str()
var inner_main = compile(&top_decs, &top_defs, &main_s, &main_body, f.env, *f.body)
main_s += main_body;
2020-04-14 23:59:52 -04:00
main_s += "size_t main_to_ret = " + inner_main + ";\n"
main_s += "check_int(main_to_ret, \"main return\");\n"
main_s += "return (main_to_ret)>>3;\n}\n"
2020-04-14 23:34:23 -04:00
write_file(str(argv[1]) + ".c", top_decs + top_defs + main_s)
2020-04-12 15:52:45 -04:00
println("Finished compile")
return 0
}
}
error("Main not a k' function")
} else {
println("No main function to compile, exiting")
}
2020-03-28 00:23:01 -04:00
} else {
2020-05-09 11:52:32 -04:00
env->set(str("*ARGV*"), malVector(params))
2020-03-29 20:42:51 -04:00
rep(grammer, env, str("(println (str \"Mal [\" *host-language* \"]\"))"))
2020-03-28 00:23:01 -04:00
while (true) {
var line = get_line(str("user> "), 1024)
if (line == "***EOF***")
break
2020-03-29 20:42:51 -04:00
println(rep(grammer, env, line))
2020-03-28 00:23:01 -04:00
}
}
}
2020-04-14 23:34:23 -04:00
var tmp_idx: int = 0
fun new_tmp(): str {
tmp_idx += 1
return str("x") + tmp_idx
}
2020-04-19 21:52:21 -04:00
fun find_closed_vars(defined: set<str>, env: *Env, ast: MalValue): set<str> {
2020-05-09 11:52:32 -04:00
match (ast.internal) {
MalValue_int::Vector(l) {
2020-05-11 23:20:54 -04:00
/*println("Find closed vars list")*/
2020-05-09 23:59:46 -04:00
if (l.get().size == 0) {
2020-04-19 21:52:21 -04:00
return set<str>()
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("def!")) {
2020-05-11 23:20:54 -04:00
/*println("Find closed vars in def!")*/
2020-05-09 23:59:46 -04:00
defined.add(l.get()[1].get_symbol_text())
2020-04-19 21:52:21 -04:00
/*return find_closed_vars(defined, env, l[2])*/
2020-05-09 23:59:46 -04:00
var to_ret = find_closed_vars(defined, env, l.get()[2])
2020-05-11 23:20:54 -04:00
/*println("end Find closed vars in def!")*/
2020-04-19 21:52:21 -04:00
return to_ret
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("let*")) {
var bindings = l.get()[1].get_vector_rc()
2020-04-19 21:52:21 -04:00
var to_ret = set<str>()
var new_env = new<Env>()->construct(env)
2020-05-09 23:59:46 -04:00
for (var i = 0; i < bindings.get().size; i+=2;) {
defined.add(bindings.get()[i].get_symbol_text())
new_env->set(bindings.get()[i].get_symbol_text(), malNil())
to_ret += find_closed_vars(defined, new_env, bindings.get()[i+1])
2020-04-19 21:52:21 -04:00
}
2020-05-09 23:59:46 -04:00
return to_ret + find_closed_vars(defined, new_env, l.get()[2])
} else if l.get()[0].is_symbol("do") || l.get()[0].is_symbol("if") {
2020-04-19 21:52:21 -04:00
var to_ret = set<str>()
2020-05-09 23:59:46 -04:00
for (var i = 1; i < l.get().size; i++;) {
to_ret += find_closed_vars(defined, env, l.get()[i])
2020-04-19 21:52:21 -04:00
}
return to_ret
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("fn*")) {
2020-05-11 23:20:54 -04:00
/*println("Find closed vars fn*")*/
2020-04-19 21:52:21 -04:00
var f = EVAL(env, ast)
/*return find_closed_vars(defined, env, get_value(f))*/
var to_ret = find_closed_vars(defined, env, get_value(f))
2020-05-11 23:20:54 -04:00
/*println("end find closed vars fn*")*/
2020-04-19 21:52:21 -04:00
return to_ret
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("quote")) {
2020-04-19 21:52:21 -04:00
return set<str>()
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("quasiquote")) {
return find_closed_vars(defined, env, quasiquote(l.get()[1]))
} else if (l.get()[0].is_symbol("macroexpand")) {
2020-04-19 21:52:21 -04:00
error("macroexpand doesn't make sense while finding closed vars")
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("try*")) {
2020-04-19 21:52:21 -04:00
error("finding closed vars in try* unimplemented")
} else {
var to_ret = set<str>()
2020-05-09 23:59:46 -04:00
for (var i = 0; i < l.get().size; i++;) {
to_ret += find_closed_vars(defined, env, l.get()[i])
2020-04-19 21:52:21 -04:00
}
return to_ret
}
2020-05-11 23:20:54 -04:00
/*println("end list")*/
2020-04-19 21:52:21 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::Symbol(s) {
2020-04-19 21:52:21 -04:00
if !defined.contains(s) {
var scope = env->find(s)
2020-05-10 19:29:28 -04:00
// null scope should mean top level var
2020-04-19 21:52:21 -04:00
if scope == null<Env>() {
2020-05-10 19:29:28 -04:00
/*error("Can't find " + s + " in env when trying to find closed_vars\n" + env->to_string())*/
return set<str>()
2020-04-19 21:52:21 -04:00
}
// don't do for top level vars
if scope->outer != null<Env>() {
return set(s)
}
}
return set<str>()
}
2020-05-09 11:52:32 -04:00
MalValue_int::Int(i) {
2020-04-19 21:52:21 -04:00
return set<str>()
}
2020-05-09 11:52:32 -04:00
MalValue_int::Nil() {
2020-04-19 21:52:21 -04:00
return set<str>()
}
2020-05-09 11:52:32 -04:00
MalValue_int::True() {
2020-04-19 21:52:21 -04:00
return set<str>()
}
2020-05-09 11:52:32 -04:00
MalValue_int::False() {
2020-04-19 21:52:21 -04:00
return set<str>()
}
2020-05-09 11:52:32 -04:00
MalValue_int::String(s) {
2020-04-25 13:05:56 -04:00
return set<str>()
}
2020-05-09 11:52:32 -04:00
MalValue_int::Function(f) {
2020-04-19 21:52:21 -04:00
var new_env = new<Env>()->construct(env)
for (var i = 0; i < f.parameters.size; i++;) {
2020-05-09 11:52:32 -04:00
new_env->set(f.parameters[i], malNil())
2020-04-19 21:52:21 -04:00
}
2020-05-11 23:20:54 -04:00
/*println("Find closed vars going inside function:\n" + new_env->to_string())*/
2020-04-19 21:52:21 -04:00
/*return find_closed_vars(defined.union(from_vector(f.parameters)), new_env, *f.body)*/
var to_ret = find_closed_vars(defined.union(from_vector(f.parameters)), new_env, *f.body)
2020-05-11 23:20:54 -04:00
/*println("coming out of function")*/
2020-04-19 21:52:21 -04:00
return to_ret
}
}
2020-04-25 13:05:56 -04:00
error("Can't get closure_vars for " + pr_str(ast, true))
2020-04-19 21:52:21 -04:00
}
2020-05-10 21:33:47 -04:00
fun c_legal(s: ref str): str {
var to_ret = str()
for (var i = 0; i < s.length(); i++;) {
if s[i] == '!' {
to_ret += "_bang_"
} else if s[i] == '-' {
to_ret += "_dash_"
} else if s[i] == '+' {
to_ret += "_plus_"
} else if s[i] == '*' {
to_ret += "_star_"
} else if s[i] == '/' {
to_ret += "_div_"
} else if s[i] == '=' {
to_ret += "_eq_"
2020-05-11 01:08:13 -04:00
} else if s[i] == '>' {
to_ret += "_gt_"
} else if s[i] == '<' {
to_ret += "_lt_"
2020-05-10 21:33:47 -04:00
} else {
to_ret += s[i]
}
}
return to_ret
}
2020-04-20 01:22:45 -04:00
fun compile_value(top_decs: *str, top_defs: *str, main_init: *str, defs: *str, env: *Env, ast: MalValue, quoted: bool): str {
2020-05-09 11:52:32 -04:00
match (ast.internal) {
MalValue_int::Nil() {
2020-04-22 21:10:46 -04:00
return str("0x2F")
2020-04-14 23:34:23 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::True() {
2020-04-22 21:10:46 -04:00
return str("0x9F")
}
2020-05-09 11:52:32 -04:00
MalValue_int::False() {
2020-04-22 21:10:46 -04:00
return str("0x1F")
}
2020-05-10 21:33:47 -04:00
MalValue_int::BuiltinFunction(f) {
if (f.name == "+") {
return str("((((size_t)&_plus_closure)<<3)|0x6)")
} else if (f.name == "-") {
return str("((((size_t)&_minus_closure)<<3)|0x6)")
} else if (f.name == "*") {
return str("((((size_t)&_mult_closure)<<3)|0x6)")
} else if (f.name == "/") {
return str("((((size_t)&_div_closure)<<3)|0x6)")
} else if (f.name == "=") {
return str("((((size_t)&_eq_closure)<<3)|0x6)")
} else if (f.name == "<") {
return str("((((size_t)&_lt_closure)<<3)|0x6)")
} else if (f.name == "<=") {
return str("((((size_t)&_lte_closure)<<3)|0x6)")
} else if (f.name == ">") {
return str("((((size_t)&_gt_closure)<<3)|0x6)")
} else if (f.name == ">=") {
return str("((((size_t)&_gte_closure)<<3)|0x6)")
} else if (f.name == "print") {
return str("((((size_t)&_print_closure)<<3)|0x6)")
} else if (f.name == "println") {
return str("((((size_t)&_println_closure)<<3)|0x6)")
} else if (f.name == "vector") {
return str("((((size_t)&_vector_closure)<<3)|0x6)")
} else if (f.name == "nth") {
return str("((((size_t)&_nth_closure)<<3)|0x6)")
} else if (f.name == "set-nth!") {
return str("((((size_t)&_set_nth_closure)<<3)|0x6)")
} else if (f.name == "throw") {
return str("((((size_t)&_throw_closure)<<3)|0x6)")
} else if (f.name == "with-meta") {
return str("((((size_t)&_with_meta_closure)<<3)|0x6)")
} else if (f.name == "meta") {
return str("((((size_t)&_meta_closure)<<3)|0x6)")
} else if (f.name == "cons") {
return str("((((size_t)&_cons_closure)<<3)|0x6)")
} else if (f.name == "concat") {
return str("((((size_t)&_concat_closure)<<3)|0x6)")
2020-05-11 01:08:13 -04:00
} else if (f.name == "apply") {
return str("((((size_t)&_apply_closure)<<3)|0x6)")
} else if (f.name == "count") {
return str("((((size_t)&_count_closure)<<3)|0x6)")
2020-05-10 21:33:47 -04:00
}
error("cannot yet compile builtin function: " + f.name)
}
2020-05-09 11:52:32 -04:00
MalValue_int::Function(f) {
2020-04-22 21:10:46 -04:00
var fun_name = "fun_" + new_tmp()
*top_decs += "size_t " + fun_name + "(size_t*, size_t, size_t*);\n"
var function = "size_t " + fun_name + "(size_t* closed_vars, size_t num, size_t* args) {\n"
2020-05-11 01:08:13 -04:00
if f.is_variadic {
function += str("check_num_params_at_least(num, ") + (f.parameters.size-1) + ", \"lambda\");\n"
} else {
function += str("check_num_params(num, ") + f.parameters.size + ", \"lambda\");\n"
}
2020-04-22 21:10:46 -04:00
var new_env = new<Env>()->construct(env)
for (var i = 0; i < f.parameters.size; i++;) {
2020-05-11 01:08:13 -04:00
if f.is_variadic && i == f.parameters.size-1 {
function += "size_t* " + f.parameters[i] + "_raw = malloc(sizeof(size_t)*(2+(num-" + (f.parameters.size-1) + ")));\n"
function += f.parameters[i] + "_raw[0] = 0x2F;\n"
function += f.parameters[i] + "_raw[1] = (num-" + (f.parameters.size-1) + ");\n"
function += str() + "for (int i = 0; i < (num-" + (f.parameters.size-1) + "); i++) {\n"
2020-05-11 23:20:54 -04:00
function += f.parameters[i] + "_raw[i+2] = args[i+" + (f.parameters.size-1) + "];\n"
2020-05-11 01:08:13 -04:00
function += "}\n"
function += "size_t " + f.parameters[i] + " = ((((size_t)" + f.parameters[i] + "_raw)<<3)|0x2);\n"
} else {
function += "size_t " + f.parameters[i] + " = args[" + i + "];\n"
}
2020-05-09 11:52:32 -04:00
new_env->set(f.parameters[i], malNil())
2020-04-22 21:10:46 -04:00
}
var closed_vars = find_closed_vars(set<str>(), new_env, ast)
for (var i = 0; i < closed_vars.data.size; i++;) {
function += "size_t " + closed_vars.data[i] + " = closed_vars[" + i + "];\n"
}
var inner_value = compile(top_decs, top_defs, main_init, &function, new_env, *f.body)
function += "return " + inner_value + ";\n}\n"
*top_defs += function
*defs += "closure* " + fun_name + "_closure = malloc(sizeof(closure));\n"
*defs += fun_name + "_closure->func = " + fun_name + ";\n"
if closed_vars.data.size > 0 {
*defs += fun_name + "_closure->data = malloc(sizeof(size_t)*" + closed_vars.data.size + ");\n"
for (var i = 0; i < closed_vars.data.size; i++;) {
*defs += fun_name + "_closure->data[" + i + "] = " + closed_vars.data[i] + ";\n"
2020-04-20 01:22:45 -04:00
}
2020-04-22 21:10:46 -04:00
} else {
*defs += fun_name + "_closure->data = NULL;\n"
2020-04-20 01:16:34 -04:00
}
2020-04-22 21:10:46 -04:00
return "((((size_t)"+fun_name+"_closure)<<3)|0x6)"
2020-04-14 23:34:23 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::Symbol(s) {
2020-04-20 01:22:45 -04:00
if quoted {
2020-04-22 21:10:46 -04:00
var val_name = "sym_" + new_tmp()
*defs += "size_t *" + val_name + " = malloc(sizeof(size_t)+sizeof(char)*" + (s.length()+1) +");\n"
*defs += "*" + val_name + " = " + s.length() + ";\n"
*defs += "strcpy(((char*)(" + val_name + "+1)), \"" + s + "\");\n"
return "((((size_t)" + val_name + ")<<3)|0x5)"
2020-04-13 23:42:32 -04:00
} else {
2020-05-10 21:33:47 -04:00
var c_legal_s = c_legal(s)
2020-04-17 10:31:38 -04:00
var e = env->find(s);
if e != null<Env>() && e->outer == null<Env>() {
2020-05-11 23:20:54 -04:00
/*println(s + " found in outer-est scope!")*/
2020-04-18 13:36:46 -04:00
var v = e->get(s)
e->remove(s)
2020-04-17 10:31:38 -04:00
var x = str()
2020-05-10 00:50:46 -04:00
var value = compile_value(top_decs, top_defs, main_init, &x, e, get_value(v), true)
2020-05-10 21:33:47 -04:00
*top_decs += "size_t " + c_legal_s + ";\n"
2020-04-17 10:31:38 -04:00
*main_init += x
2020-05-10 21:33:47 -04:00
*main_init += c_legal_s + " = " + value + ";\n"
2020-04-17 10:31:38 -04:00
}
2020-05-10 21:33:47 -04:00
return c_legal_s
2020-04-13 23:42:32 -04:00
}
2020-04-12 15:52:45 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::String(s) {
2020-04-22 21:10:46 -04:00
var val_name = "str_" + new_tmp()
*defs += "size_t *" + val_name + " = malloc(sizeof(size_t)+sizeof(char)*" + (s.length()+1) +");\n"
*defs += "*" + val_name + " = " + s.length() + ";\n"
*defs += "strcpy(((char*)(" + val_name + "+1)), \"" + s + "\");\n"
return "((((size_t)" + val_name + ")<<3)|0x3)"
2020-04-13 22:55:25 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::Vector(l) {
2020-05-09 23:59:46 -04:00
var call_str = str("_vector_impl(NULL, ") + l.get().size + ", (size_t[]){ "
for (var i = 0; i < l.get().size; i++;) {
2020-04-22 21:10:46 -04:00
if i != 0 {
call_str += ", "
}
if quoted {
2020-05-09 23:59:46 -04:00
call_str += compile_value(top_decs, top_defs, main_init, defs, env, l.get()[i], true)
2020-04-22 21:10:46 -04:00
} else {
2020-05-09 23:59:46 -04:00
call_str += compile(top_decs, top_defs, main_init, defs, env, l.get()[i])
2020-04-22 21:10:46 -04:00
}
2020-04-19 21:52:21 -04:00
}
2020-05-10 00:50:46 -04:00
call_str += "})"
if ast.meta != null<MalValue>() {
var meta_value = compile_value(top_decs, top_defs, main_init, defs, env, *ast.meta, true)
var for_meta = "for_meta_" + new_tmp()
*defs += "size_t " + for_meta + " = " + call_str + ";\n"
*defs += "((size_t*)(" + for_meta + ">>3))[0] = " + meta_value + ";\n"
return for_meta
} else {
return call_str
}
2020-04-22 21:10:46 -04:00
}
2020-05-09 11:52:32 -04:00
MalValue_int::Int(i) {
2020-04-22 21:10:46 -04:00
return to_string(i<<3)
2020-04-17 10:31:38 -04:00
}
2020-04-12 15:52:45 -04:00
}
error("could not compile value: " + pr_str(ast, true))
}
2020-04-17 10:31:38 -04:00
fun compile(top_decs: *str, top_defs: *str, main_init: *str, defs: *str, env: *Env, ast: MalValue): str {
2020-04-12 15:52:45 -04:00
var expanded = macroexpand(ast, env)
if (is_err(expanded)) {
error("compile error in macroexpand: " + pr_str(get_err(expanded), true))
}
ast = get_value(expanded)
2020-05-09 11:52:32 -04:00
if !ast.is_vector() {
2020-04-20 01:22:45 -04:00
return compile_value(top_decs, top_defs, main_init, defs, env, ast, false)
2020-04-12 15:52:45 -04:00
}
2020-05-09 11:52:32 -04:00
match (ast.internal) {
MalValue_int::Vector(l) {
2020-05-09 23:59:46 -04:00
if (l.get().size == 0) {
2020-04-20 01:22:45 -04:00
return compile_value(top_decs, top_defs, main_init, defs, env, ast, false)
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("def!")) {
if (l.get().size != 3) {
2020-04-12 15:52:45 -04:00
error("def! without exaclty key and value")
}
2020-05-09 23:59:46 -04:00
if (!l.get()[1].is_symbol()) {
2020-04-12 15:52:45 -04:00
error("def! not on symbol")
}
2020-04-19 21:52:21 -04:00
if env->outer != null<Env>() {
error("def! not at top level")
}
2020-05-09 23:59:46 -04:00
var to_set_name = l.get()[1].get_symbol_text()
var to_set_value = compile(top_decs, top_defs, main_init, defs, env, l.get()[2])
2020-04-13 22:45:40 -04:00
*defs += "size_t " + to_set_name + " = " + to_set_value + ";\n"
2020-04-12 15:52:45 -04:00
return to_set_name
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("defmacro!")) {
2020-04-12 15:52:45 -04:00
error("defmacro! doesn't make sense in compiled code")
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("let*")) {
if (l.get().size != 3) {
2020-04-12 15:52:45 -04:00
error("let* without list of bindings & end value")
}
2020-05-09 23:59:46 -04:00
if (!l.get()[1].is_vector()) {
2020-04-12 15:52:45 -04:00
error("let* without list of bindings")
}
2020-05-09 23:59:46 -04:00
var bindings = l.get()[1].get_vector_rc()
if (bindings.get().size & 1 != 0) {
2020-04-12 15:52:45 -04:00
error("let* list of bindings has odd number of entries")
}
2020-04-13 22:45:40 -04:00
var let_val = new_tmp()
*defs += "size_t " + let_val + ";\n{\n"
2020-04-12 15:52:45 -04:00
var new_env = new<Env>()->construct(env)
2020-05-09 23:59:46 -04:00
for (var i = 0; i < bindings.get().size; i+=2;) {
if (!bindings.get()[i].is_symbol()) {
2020-04-12 15:52:45 -04:00
error("let* var name not symbol")
}
2020-05-09 23:59:46 -04:00
var to_set_value = compile(top_decs, top_defs, main_init, defs, new_env, bindings.get()[i+1])
*defs += "size_t " + bindings.get()[i].get_symbol_text() + " = " + to_set_value + ";\n"
new_env->set(bindings.get()[i].get_symbol_text(), malNil())
2020-04-12 15:52:45 -04:00
}
2020-05-09 23:59:46 -04:00
*defs += let_val + " = " + compile(top_decs, top_defs, main_init, defs, new_env, l.get()[2]) + ";\n}\n"
2020-04-13 22:45:40 -04:00
return let_val
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("do")) {
for (var i = 1; i < l.get().size-1; i++;) {
var value_possible_side_effect = compile(top_decs, top_defs, main_init, defs, env, l.get()[i])
2020-04-18 13:36:46 -04:00
*defs += value_possible_side_effect + ";\n"
2020-04-12 15:52:45 -04:00
}
2020-05-09 23:59:46 -04:00
return compile(top_decs, top_defs, main_init, defs, env, l.get()[l.get().size-1])
} else if (l.get()[0].is_symbol("if")) {
if l.get().size != 3 && l.get().size != 4 {
2020-04-12 15:52:45 -04:00
error("if needs 2 or 3 children")
}
2020-05-09 23:59:46 -04:00
var cond = compile(top_decs, top_defs, main_init, defs, env, l.get()[1])
2020-04-13 22:45:40 -04:00
var tmp_name = new_tmp()
2020-04-13 22:55:25 -04:00
*defs += "size_t " + tmp_name + "; if (" + cond + " != 0x1F) {\n"
2020-05-09 23:59:46 -04:00
var then = compile(top_decs, top_defs, main_init, defs, env, l.get()[2])
2020-04-12 15:52:45 -04:00
*defs += tmp_name + " = " + then + ";\n} else {\n"
2020-05-09 23:59:46 -04:00
var else_ = compile(top_decs, top_defs, main_init, defs, env, l.get()[3])
2020-04-13 22:55:25 -04:00
*defs += tmp_name + " = " + else_ + ";\n}\n"
2020-04-12 15:52:45 -04:00
return tmp_name
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("fn*")) {
2020-04-17 10:31:38 -04:00
var f = EVAL(env, ast)
2020-04-20 01:22:45 -04:00
return compile_value(top_decs, top_defs, main_init, defs, env, get_value(f), false)
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("quote")) {
if l.get().size == 1 {
2020-04-12 15:52:45 -04:00
error("compile quote with no arguments")
}
2020-05-09 23:59:46 -04:00
return compile_value(top_decs, top_defs, main_init, defs, env, l.get()[1], true)
} else if (l.get()[0].is_symbol("quasiquote")) {
if l.get().size == 1 {
2020-04-12 15:52:45 -04:00
error("compile quasiquote with no arguments")
}
2020-05-09 23:59:46 -04:00
return compile(top_decs, top_defs, main_init, defs, env, quasiquote(l.get()[1]))
} else if (l.get()[0].is_symbol("macroexpand")) {
2020-04-12 15:52:45 -04:00
error("macroexpand doesn't make sense while compiling")
2020-05-09 23:59:46 -04:00
} else if (l.get()[0].is_symbol("try*")) {
2020-04-23 13:04:27 -04:00
var tmp_name = new_tmp()
var tmp_exception_name = new_tmp()
var tmp_new_exception_name = new_tmp()
*defs += "size_t " + tmp_name + " = 0;\n"
*defs += "jmp_buf *" + tmp_exception_name + " = current_exception_handler;\n"
*defs += "jmp_buf " + tmp_new_exception_name + ";\n"
*defs += "current_exception_handler = &" + tmp_new_exception_name + ";\n"
*defs += "if (!setjmp(*current_exception_handler)) {\n"
2020-05-09 23:59:46 -04:00
*defs += tmp_name + " = " + compile(top_decs, top_defs, main_init, defs, env, l.get()[1]) + ";\n"
2020-04-23 13:04:27 -04:00
*defs += "} else {\n"
2020-05-09 23:59:46 -04:00
if l.get().size == 3 {
var catch = l.get()[2].get_vector_rc()
if catch.get().size != 3 || !catch.get()[0].is_symbol("catch*") || !catch.get()[1].is_symbol() {
2020-04-23 13:04:27 -04:00
error("catch* block malformed")
}
var new_env = new<Env>()->construct(env)
2020-05-09 23:59:46 -04:00
new_env->set(catch.get()[1].get_symbol_text(), malNil())
*defs += "size_t " + catch.get()[1].get_symbol_text() + " = current_exception_value;\n"
*defs += tmp_name + " = " + compile(top_decs, top_defs, main_init, defs, new_env, catch.get()[2]) + ";\n"
2020-04-23 13:04:27 -04:00
} else {
*defs += tmp_name + " = current_exception_value;\n";
}
*defs += "}\n"
*defs += "current_exception_handler = " + tmp_exception_name + ";\n"
return tmp_name
2020-04-12 15:52:45 -04:00
} else {
var to_call = vec<str>()
2020-05-09 23:59:46 -04:00
for (var i = 0; i < l.get().size; i++;) {
to_call.add(compile(top_decs, top_defs, main_init, defs, env, l.get()[i]))
2020-04-12 15:52:45 -04:00
}
2020-04-13 23:42:32 -04:00
var func_name = new_tmp()
2020-04-14 14:35:01 -04:00
*defs += "size_t " + func_name + "_r = " + to_call[0] + ";\n"
2020-04-14 23:53:12 -04:00
*defs += "check_function(" + func_name + "_r, \"trying to call\");\n";
2020-04-14 14:35:01 -04:00
*defs += "closure* " + func_name + " = (closure*)(" + func_name + "_r>>3);\n"
2020-04-13 23:42:32 -04:00
var params_name = new_tmp()
2020-04-14 23:34:23 -04:00
*defs += "size_t " + params_name + "_params[] = {"+str(", ").join(to_call.slice(1,-1))+"};\n"
2020-05-09 23:59:46 -04:00
return func_name + "->func(" + func_name + "->data, " + to_string(l.get().size-1) + ", " + params_name + "_params)"
2020-04-12 15:52:45 -04:00
}
}
}
2020-04-20 01:22:45 -04:00
return compile_value(top_decs, top_defs, main_init, defs, env, ast, false)
2020-04-12 15:52:45 -04:00
}