import mem:* import io:* import str:* import vec:* import vec_literals:* import util:* import map:* import rc:* import fungll:* 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 Vector: rc>, //<10sizebits> 1 // 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 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()) } else { return nmMV(MalValue_int::False()) } } fun malString(s: ref str): MalValue { return nmMV(MalValue_int::String(s)) } fun malSymbol(s: ref str): MalValue { return nmMV(MalValue_int::Symbol(s)) } fun malInt(i: int): MalValue { return nmMV(MalValue_int::Int(i)) } fun malVector(v: ref vec): MalValue { var rcd.construct(v): rc> return nmMV(MalValue_int::Vector(rcd)) } fun malNil(): MalValue { return nmMV(MalValue_int::Nil()) } obj MalValue (Object) { var internal: MalValue_int var meta: *MalValue fun construct(): *MalValue { internal.copy_construct(&MalValue_int::Nil()); meta = null() } 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() { meta = new() meta->copy_construct(other->meta) } else { meta = null() } } fun operator=(other: ref MalValue): void { destruct() copy_construct(&other) } fun destruct(): void { if meta != null() delete(meta) internal.destruct() } fun equals(other: ref MalValue): bool { match (internal) { MalValue_int::Vector(d) { match (other.internal) { MalValue_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 } } } 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; } } } } return false } fun deep_clone(): MalValue { match (internal) { MalValue_int::Vector(v) { return malVector(v.get()) } } return *this } fun is_vector(): bool { match (internal) { MalValue_int::Vector(v) { return true } /*MalValue_int::Nil() {*/ /*return true*/ /*}*/ } return false } fun get_vector_rc(): rc> { match (internal) { MalValue_int::Vector(v) { return v } } error("Tried to get vec on not a vec" + pr_str(*this, true)) } fun is_symbol(): bool { match (internal) { MalValue_int::Symbol(s) { return true } } return false } fun is_symbol(text: *char): bool { match (internal) { MalValue_int::Symbol(s) { return s == text } } return false } fun get_symbol_text(): str { match (internal) { MalValue_int::Symbol(s) { return s } } error("get_symbol_text on not symbol") } fun is_string(): bool { match (internal) { MalValue_int::String(s) { return true } } return false } fun get_string(): str { match (internal) { MalValue_int::String(s) { return s } } error("get_string on not a string") } fun is_int(): bool { match (internal) { MalValue_int::Int(i) { return true } } return false } fun get_int(): int { match (internal) { MalValue_int::Int(i) { return i } } error("get_int on not an int") } fun is_nil(): bool { match (internal) { MalValue_int::Nil() { return true } } return false } fun is_truthy(): bool { match (internal) { MalValue_int::False() { return false } MalValue_int::Nil() { return false } } return true } fun is_pair(): bool { return is_vector() && get_vector_rc().get().size > 0 } } fun read_str(grammer: ref Grammer, s: str): pair { 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 } } if longest >= 0 { return make_pair(longest, grammer.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 + ": " + grammer.to_string(BSR.data[i])) } println("Parse failed") return make_pair(-1, MalResult::Err(malString(str("failed to parse")))) } } fun is_macro_call(ast: MalValue, env: *Env): bool { if !ast.is_vector() { return false } var l = ast.get_vector_rc() if l.get().size == 0 || !l.get()[0].is_symbol() { return false } var res = env->get(l.get()[0].get_symbol_text()) if is_err(res) { return false } var v = get_value(res) match (v.internal) { MalValue_int::Function(f) { return f.is_macro } } return false } fun macroexpand(ast: MalValue, env: *Env): MalResult { while is_macro_call(ast, env) { var l = ast.get_vector_rc() var v = get_value(env->get(l.get()[0].get_symbol_text())) match (v.internal) { MalValue_int::Function(f) { var params = l.get().slice(1,-1) if (!f.is_variadic && f.parameters.size != params.size) || (f.is_variadic && f.parameters.size > params.size + 1) { return MalResult::Err(malString(str("macro called with the wrong number of parameters"))) } env = new()->construct(f.env) for (var i = 0; i < f.parameters.size; i++;) { if f.is_variadic && i == f.parameters.size - 1 { env->set(f.parameters[i], malVector(params.slice(i, -1))) } 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 { if !ast.is_pair() { return malVector(vec(malSymbol(str("quote")), ast)) } else { var ast_list = ast.get_vector_rc() if ast_list.get()[0].is_symbol("unquote") { return ast_list.get()[1] } else { 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))))) } else { return malVector(vec(malSymbol(str("cons")), quasiquote(ast_list.get()[0]), quasiquote(malVector(ast_list.get().slice(1,-1))))) } } } } obj Env (Object) { var data: map var outer: *Env fun construct(): *Env { return construct(null()) } 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() } fun operator=(other:ref Env):void { destruct() copy_construct(&other) } fun set(key: str, val: MalValue) { data.set(key, val) } fun remove(key: str) { data.remove(key) } fun find(key: str): *Env { if (data.contains_key(key)) { return this } else if (outer != null()) { return outer->find(key) } else { return null() } } fun get(key: str): MalResult { var env = find(key) if (env != null()) { return MalResult::Ok(env->data.get(key)) } else { return MalResult::Err(malString(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] + ": " + data.values[i] + "\n"*/ s += tabs + data.keys[i] + "\n" } if outer != null() { outer->to_string(tabs + "\t", s) } } } obj MalBuiltinFunction (Object) { var name: str var fp: fun(vec): MalResult fun construct(name: ref str, fp: fun(vec): MalResult): *MalBuiltinFunction { this->name.copy_construct(&name) this->fp = fp return this } fun copy_construct(old: *MalBuiltinFunction): void { this->fp = old->fp this->name.copy_construct(&old->name) } fun destruct(): void { this->name.destruct() } fun operator=(other:ref MalBuiltinFunction):void { destruct() copy_construct(&other) } fun operator==(other: ref MalBuiltinFunction):bool { return false } fun call(params: vec): MalResult { return fp(params) } } fun make_builtin_function(name: str, f: fun(vec): MalResult): MalValue { var to_ret.construct(name, f): MalBuiltinFunction return nmMV(MalValue_int::BuiltinFunction(to_ret)) } obj MalFunction (Object) { var env: *Env var parameters: vec var is_variadic: bool var is_macro: bool var body: *MalValue fun construct(env: *Env, parameters: vec, 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() 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() this->body->copy_construct(old->body) } fun destruct(): void { this->env = null() parameters.destruct() delete(body) body = null() } fun operator=(other:ref MalFunction):void { destruct() copy_construct(&other) } fun operator==(other: ref MalFunction):bool { // not sure about env return env == other.env && parameters == other.parameters && is_variadic == other.is_variadic && is_macro == other.is_macro && body->equals(*other.body) } // no call b/c need to do in EVAL for TCO fun prep_call(params: ref vec): pair<*Env, MalResult> { // tco if (!is_variadic && parameters.size != params.size) || (is_variadic && parameters.size > params.size + 1) { return make_pair(null(), 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)))) } var new_env = new()->construct(env) for (var i = 0; i < parameters.size; i++;) { if is_variadic && i == parameters.size - 1 { new_env->set(parameters[i], malVector(params.slice(i, -1))) } else { new_env->set(parameters[i], params[i]) } } return make_pair(new_env, MalResult::Ok(*body)) } } fun function_call(f: MalValue, params: ref vec): MalResult { match (f.internal) { MalValue_int::BuiltinFunction(f) { return f.call(params) } MalValue_int::Function(f) { 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)) } } return MalResult::Err(malString(str("trying to apply not a function: ") + pr_str(f ,true))) } 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 } } return malString(str("not error")) } fun get_value(r: MalResult): MalValue { match (r) { MalResult::Ok(v) { return v } } return malSymbol(str("error")) } fun pr_str(v: MalValue, print_readably: bool): str { match (v.internal) { MalValue_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 + " )" } MalValue_int::Int(i) { return to_string(i) } MalValue_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 } } MalValue_int::Symbol(s) { if print_readably { return "'" + s } else { return s } } MalValue_int::BuiltinFunction(f) { return str("builtin function") } MalValue_int::Function(f) { return str("function") } MalValue_int::True() { return str("true") } MalValue_int::False() { return str("false") } MalValue_int::Nil() { return str("nil") } } error("can't print") } fun READ(grammer: ref Grammer, s: str): MalResult { 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 } fun eval_ast(env: *Env, ast: MalValue): MalResult { match (ast.internal) { MalValue_int::Vector(l) { var to_ret = vec() for (var i = 0; i < l.get().size; i++;) { var mid = EVAL(env, l.get()[i]) if is_err(mid) { return mid } to_ret.add(get_value(mid)) } return MalResult::Ok(malVector(to_ret)) } MalValue_int::Symbol(s) { 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) if !ast.is_vector() { return eval_ast(env, ast) } match (ast.internal) { MalValue_int::Vector(l) { if (l.get().size == 0) { return MalResult::Ok(ast) } else if (l.get()[0].is_symbol("def!")) { if (l.get().size != 3) { return MalResult::Err(malString(str("def! without exaclty key and value"))) } if (!l.get()[1].is_symbol()) { return MalResult::Err(malString(str("def! not on symbol"))) } if env->outer != null() { return MalResult::Err(malString(str("def! not at top level"))) } var value = EVAL(env, l.get()[2]) if (is_err(value)) { return value } env->set(l.get()[1].get_symbol_text(), get_value(value)) return value } else if (l.get()[0].is_symbol("defmacro!")) { if (l.get().size != 3) { return MalResult::Err(malString(str("defmacro! without exaclty key and value"))) } if (!l.get()[1].is_symbol()) { return MalResult::Err(malString(str("defmacro! not on symbol"))) } var value = EVAL(env, l.get()[2]) if (is_err(value)) { return value } var v = get_value(value) match (v.internal) { MalValue_int::Function(f) { f.is_macro = true env->set(l.get()[1].get_symbol_text(), nmMV(MalValue_int::Function(f))) return value } } return MalResult::Err(malString(str("defmacro! on not a function"))) } else if (l.get()[0].is_symbol("let*")) { if (l.get().size != 3) { return MalResult::Err(malString(str("let* without list of bindings & end value"))) } if (!l.get()[1].is_vector()) { return MalResult::Err(malString(str("let* without list of bindings"))) } var bindings = l.get()[1].get_vector_rc() if (bindings.get().size & 1 != 0) { return MalResult::Err(malString(str("let* list of bindings has odd number of entries"))) } var new_env = new()->construct(env) for (var i = 0; i < bindings.get().size; i+=2;) { if (!bindings.get()[i].is_symbol()) { return MalResult::Err(malString(str("let* var name not symbol"))) } var to_set_value = EVAL(new_env, bindings.get()[i+1]) if (is_err(to_set_value)) { return to_set_value } new_env->set(bindings.get()[i].get_symbol_text(), get_value(to_set_value)) } // tco env = new_env var tmp = l.get()[2] ast = tmp continue } 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]) if is_err(mid) { return mid } } // tco var tmp = l.get()[l.get().size-1] ast = tmp continue } else if (l.get()[0].is_symbol("if")) { if l.get().size != 3 && l.get().size != 4 { return MalResult::Err(malString(str("if needs 2 or 3 children"))) } var cond = EVAL(env, l.get()[1]) if is_err(cond) { return cond } // tco if get_value(cond).is_truthy() { var tmp = l.get()[2] ast = tmp } else if l.get().size == 4 { var tmp = l.get()[3] ast = tmp } else { return MalResult::Ok(malNil()) } continue } else if (l.get()[0].is_symbol("fn*")) { if l.get().size != 3 { return MalResult::Err(malString(str("fn* needs 2 children"))) } if (!l.get()[1].is_vector()) { return MalResult::Err(malString(str("fn* without list of parameters"))) } var parameters = l.get()[1].get_vector_rc() var parameters_str = vec() var is_variadic = false for (var i = 0; i < parameters.get().size; i++;) { if (!parameters.get()[i].is_symbol()) { return MalResult::Err(malString(str("fn* parameter name not symbol"))) } var symbol_text = parameters.get()[i].get_symbol_text() if symbol_text == "&" { if i != parameters.get().size - 2 { return MalResult::Err(malString(str("fn* has wrong number of arguments after &"))) } if (!parameters.get()[i+1].is_symbol()) { return MalResult::Err(malString(str("fn* parameter name not symbol"))) } is_variadic = true i++ symbol_text = parameters.get()[i].get_symbol_text() } parameters_str.add(symbol_text) } var to_ret.construct(env, parameters_str, is_variadic, false, l.get()[2]): MalFunction return MalResult::Ok(nmMV(MalValue_int::Function(to_ret))) } else if (l.get()[0].is_symbol("quote")) { if l.get().size == 1 { return MalResult::Err(malString(str("quote with no arguments"))) } return MalResult::Ok(l.get()[1]) } else if (l.get()[0].is_symbol("quasiquote")) { if l.get().size == 1 { return MalResult::Err(malString(str("quasiquote with no arguments"))) } var tmp = quasiquote(l.get()[1]) ast = tmp continue } else if (l.get()[0].is_symbol("macroexpand")) { if l.get().size == 1 { return MalResult::Err(malString(str("macroexpand with no arguments"))) } 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()) { return MalResult::Err(malString(str("try* wrong arguments"))) } 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() { return MalResult::Err(malString(str("catch* block malformed"))) } var new_env = new()->construct(env) env->set(catch.get()[1].get_symbol_text(), get_err(A)) return EVAL(new_env, catch.get()[2]) } else { return A } } else { var mid = eval_ast(env, ast) if is_err(mid) { return mid } var to_call = get_value(mid).get_vector_rc() match (to_call.get()[0].internal) { MalValue_int::BuiltinFunction(f) { return f.call(to_call.get().slice(1,-1)) } MalValue_int::Function(f) { var params = to_call.get().slice(1,-1) var call_pair = f.prep_call(to_call.get().slice(1, -1)) if is_err(call_pair.second) { return call_pair.second } env = call_pair.first ast = get_value(call_pair.second) continue } } return MalResult::Err(malString(str("trying to call not a function:") + pr_str(to_call.get()[0], true))) } } } return eval_ast(env, ast) } } fun rep(grammer: ref Grammer, env: *Env, a: str): str { var read = READ(grammer, 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 print_wrapper(params: ref vec, sep: *char, print_readably: bool): str { 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 { var grammer.construct(): Grammer 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 = fun(_: ref MalValue, x: ref vec): MalResult { return MalResult::Ok(malNil()); } var ret_0_sym: fun(ref MalValue, ref vec): MalResult = fun(_: ref MalValue, x: ref vec): MalResult { return x[0]; } var WS = grammer.add_new_nonterminal("WS", vec(grammer.add_terminal("( | | |(;[ -~]* ))+", malNil(), ret_nil_term)), malNil(), ret_nil_sym) var optional_WS = grammer.add_new_nonterminal("optional_WS", vec(), malNil(), ret_nil_sym) grammer.add_to_nonterminal(optional_WS, vec(WS), malNil(), ret_nil_sym) 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(input.slice(l,r)))); })), malNil(), ret_0_sym) grammer.add_to_nonterminal(atom, vec(grammer.add_terminal("\"([#-[]| |[]-~]|(\\\\)|(\\n)|(\\t)|(\\\*)|(\\0)| |[ -!]|(\\\\\"))*\"", malNil(), fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult { //" 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 MalResult::Err(malString(str("bad string escape"))) } // skip i++ } else { to_ret += input[i] } } 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 { var s = input.slice(l,r) if s == "true" { return MalResult::Ok(malTrue()); } else if s == "false" { return MalResult::Ok(malFalse()); } else if s == "nil" { return MalResult::Ok(malNil()); } else { return MalResult::Ok(malSymbol(input.slice(l,r))); } })), malNil(), ret_0_sym) var form = grammer.add_new_nonterminal("form", vec(atom), malNil(), ret_0_sym) var space_forms = grammer.add_new_nonterminal("space_forms", vec(), malNil(), fun(_: ref MalValue, x: ref vec): MalResult { return MalResult::Ok(malVector(vec())) }) grammer.add_to_nonterminal(space_forms, vec(form), malNil(), fun(_: ref MalValue, x: ref vec): MalResult { if is_err(x[0]) { return x[0] } return MalResult::Ok(malVector(vec(get_value(x[0])))) }) grammer.add_to_nonterminal(space_forms, vec(form, WS, space_forms), malNil(), fun(_: ref MalValue, x: ref vec): MalResult { if is_err(x[0]) { return x[0] } if is_err(x[2]) { return x[2] } return MalResult::Ok(malVector(vec(get_value(x[0])) + get_value(x[2]).get_vector_rc().get())) }) grammer.add_to_nonterminal(form, vec(grammer.add_terminal("\\(", malNil(), ret_nil_term), optional_WS, grammer.add_terminal("\\)", malNil(), ret_nil_term)), malNil(), fun(_: ref MalValue, x: ref vec): MalResult { return MalResult::Ok(malVector(vec())); }) grammer.add_to_nonterminal(form, vec(grammer.add_terminal("\\(", malNil(), ret_nil_term), optional_WS, space_forms, optional_WS, grammer.add_terminal("\\)", malNil(), ret_nil_term)), malNil(), fun(_: ref MalValue, x: ref vec): MalResult { return x[2]; }) grammer.set_start_symbol(form) var env = new()->construct() env->set(str("+"), make_builtin_function(str("+"), fun(params: vec): MalResult { var to_ret = 0 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { MalValue_int::Int(v) { to_ret += v continue } } return MalResult::Err(malString(str("called + with not an int: ") + pr_str(params[i], false))) } return MalResult::Ok(malInt(to_ret)) })); env->set(str("-"), make_builtin_function(str("-"), fun(params: vec): MalResult { var to_ret = 0 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { MalValue_int::Int(v) { if (i == 0) { to_ret += v } else { to_ret -= v } continue } } return MalResult::Err(malString(str("called - with not an int: ") + pr_str(params[i], false))) } return MalResult::Ok(malInt(to_ret)) })); env->set(str("*"), make_builtin_function(str("*"), fun(params: vec): MalResult { var to_ret = 1 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { MalValue_int::Int(v) { to_ret *= v continue } } return MalResult::Err(malString(str("called * with not an int: ") + pr_str(params[i], false))) } return MalResult::Ok(malInt(to_ret)) })); env->set(str("/"), make_builtin_function(str("/"), fun(params: vec): MalResult { var to_ret = 1 for (var i = 0; i < params.size; i++;) { match (params[i].internal) { MalValue_int::Int(v) { if (i == 0) { to_ret *= v } else { to_ret /= v } continue } } return MalResult::Err(malString(str("called / with not an int: ") + pr_str(params[i], false))) } return MalResult::Ok(malInt(to_ret)) })); env->set(str("="), make_builtin_function(str("="), fun(params: vec): MalResult { if params.size != 2 { return MalResult::Err(malString(str("= with not two parameters"))) } else { return MalResult::Ok(bool_to_MalValue(params[0].equals(params[1]))) } })); env->set(str("<"), make_builtin_function(str("<"), fun(params: vec): MalResult { if params.size != 2 || !params[0].is_int() || !params[1].is_int() { return MalResult::Err(malString(str("< with not two numbers"))) } else { return MalResult::Ok(bool_to_MalValue(params[0].get_int() < params[1].get_int())) } })); env->set(str("<="), make_builtin_function(str("<="), fun(params: vec): MalResult { if params.size != 2 || !params[0].is_int() || !params[1].is_int() { return MalResult::Err(malString(str("<= with not two numbers"))) } else { return MalResult::Ok(bool_to_MalValue(params[0].get_int() <= params[1].get_int())) } })); env->set(str(">"), make_builtin_function(str(">"), fun(params: vec): MalResult { if params.size != 2 || !params[0].is_int() || !params[1].is_int() { return MalResult::Err(malString(str("> with not two numbers"))) } else { return MalResult::Ok(bool_to_MalValue(params[0].get_int() > params[1].get_int())) } })); env->set(str(">="), make_builtin_function(str(">="), fun(params: vec): MalResult { if params.size != 2 || !params[0].is_int() || !params[1].is_int() { return MalResult::Err(malString(str(">= with not two numbers"))) } else { return MalResult::Ok(bool_to_MalValue(params[0].get_int() >= params[1].get_int())) } })); env->set(str("str"), make_builtin_function(str("str"), fun(params: vec): MalResult { return MalResult::Ok(malString(print_wrapper(params, "", false))) })); env->set(str("prn"), make_builtin_function(str("prn"), fun(params: vec): MalResult { if params.size == 0 { return MalResult::Err(malString(str("Called prn with 0 parameters"))) } println(pr_str(params[0], true)) return MalResult::Ok(malNil()) })); env->set(str("pr-str"), make_builtin_function(str("pr-str"), fun(params: vec): MalResult { return MalResult::Ok(malString(print_wrapper(params, " ", true))) })); env->set(str("prn"), make_builtin_function(str("prn"), fun(params: vec): MalResult { println(print_wrapper(params, " ", true)) return MalResult::Ok(malNil()) })); env->set(str("println"), make_builtin_function(str("println"), fun(params: vec): MalResult { println(print_wrapper(params, " ", false)) return MalResult::Ok(malNil()) })); env->set(str("empty?"), make_builtin_function(str("empty?"), fun(params: vec): MalResult { if params.size == 0 || !params[0].is_vector() { return MalResult::Err(malString(str("first parameter of empty? is not a list"))) } else { return MalResult::Ok(bool_to_MalValue(params[0].get_vector_rc().get().size == 0)) } })); env->set(str("count"), make_builtin_function(str("count"), fun(params: vec): MalResult { if params.size == 0 || !params[0].is_vector() { return MalResult::Err(malString(str("first parameter of count is not a list"))) } else { return MalResult::Ok(malInt(params[0].get_vector_rc().get().size)) } })); env->set(str("read-string"), make_builtin_function(str("read-string"), fun(params: vec): MalResult { if params.size != 1 || !params[0].is_string() { return MalResult::Err(malString(str("read-string with not a single string"))) } else { return READ(grammer, params[0].get_string()) } })); env->set(str("slurp"), make_builtin_function(str("slurp"), fun(params: vec): MalResult { if params.size != 1 || !params[0].is_string() { return MalResult::Err(malString(str("slurp with not a single string"))) } else { return MalResult::Ok(malString(read_file(params[0].get_string()))) } })); env->set(str("eval"), make_builtin_function(str("eval"), fun(params: vec): MalResult { if params.size != 1 { return MalResult::Err(malString(str("eval with wrong number of params"))) } else { return EVAL(env, params[0]) } })); env->set(str("cons"), make_builtin_function(str("cons"), fun(params: vec): MalResult { 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"))) } else { return MalResult::Ok(malVector(vec(params[0]) + params[1].get_vector_rc().get())) } })); env->set(str("concat"), make_builtin_function(str("concat"), fun(params: vec): MalResult { var to_ret = vec() for (var i = 0; i < params.size; i++;) { if !params[i].is_vector() { return MalResult::Err(malString(str("concat called with not an list"))) } to_ret += params[i].get_vector_rc().get() } return MalResult::Ok(malVector(to_ret)) })); env->set(str("nth"), make_builtin_function(str("nth"), fun(params: vec): MalResult { 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"))) } else { var list = params[0].get_vector_rc() var idx = params[1].get_int() if idx >= list.get().size { return MalResult::Err(malString(str("nth idx out of range"))) } return MalResult::Ok(list.get()[idx]) } })); env->set(str("set-nth!"), make_builtin_function(str("set-nth!"), fun(params: vec): MalResult { 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()) } })); env->set(str("first"), make_builtin_function(str("first"), fun(params: vec): MalResult { 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))) } else { var list = params[0].get_vector_rc() if list.get().size == 0 { return MalResult::Ok(malNil()) } return MalResult::Ok(list.get()[0]) } })); env->set(str("rest"), make_builtin_function(str("rest"), fun(params: vec): MalResult { if params.size != 1 || !params[0].is_vector() { return MalResult::Err(malString(str("rest called with wrong number or type of params"))) } else { var list = params[0].get_vector_rc() if list.get().size == 0 { return MalResult::Ok(malVector(vec())) } return MalResult::Ok(malVector(list.get().slice(1,-1))) } })); env->set(str("throw"), make_builtin_function(str("throw"), fun(params: vec): MalResult { if params.size != 1 { return MalResult::Err(malString(str("throw called with wrong number or type of params"))) } else { return MalResult::Err(params[0]) } })); env->set(str("apply"), make_builtin_function(str("apply"), fun(params: vec): MalResult { if params.size < 2 || !params[params.size-1].is_vector() { return MalResult::Err(malString(str("apply called with wrong number or type of params"))) } else { var inner_params = params.slice(1,-2) + params[params.size-1].get_vector_rc().get() return function_call(params[0], inner_params) } })); env->set(str("map"), make_builtin_function(str("map"), fun(params: vec): MalResult { if params.size != 2 || !params[1].is_vector() { return MalResult::Err(malString(str("map called with wrong number or type of params"))) } else { var l = params[1].get_vector_rc() var to_ret = vec() for (var i = 0; i < l.get().size; i++;) { var mid = function_call(params[0], vec(l.get()[i])) if is_err(mid) { return mid } to_ret.add(get_value(mid)) } return MalResult::Ok(malVector(to_ret)) } })); env->set(str("symbol?"), make_builtin_function(str("symbol?"), fun(params: vec): MalResult { if params.size != 1 { return MalResult::Err(malString(str("symbol? called with wrong number of params"))) } else { return MalResult::Ok(bool_to_MalValue(params[0].is_symbol())) } })); env->set(str("symbol"), make_builtin_function(str("symbol"), fun(params: vec): MalResult { if params.size != 1 || !params[0].is_string() { return MalResult::Err(malString(str("symbol called with wrong number or type of params"))) } else { return MalResult::Ok(malSymbol(params[0].get_string())) } })); env->set(str("vector"), make_builtin_function(str("vector"), fun(params: vec): MalResult { return MalResult::Ok(malVector(params)) })); env->set(str("vector?"), make_builtin_function(str("vector?"), fun(params: vec): MalResult { if params.size != 1 { return MalResult::Err(malString(str("vector? called with wrong number of params"))) } else { return MalResult::Ok(bool_to_MalValue(params[0].is_vector())) } })); env->set(str("sequential?"), make_builtin_function(str("sequential?"), fun(params: vec): MalResult { if params.size != 1 { return MalResult::Err(malString(str("sequential? called with wrong number of params"))) } else if params[0].is_nil() { return MalResult::Ok(malFalse()) } else { return MalResult::Ok(bool_to_MalValue(params[0].is_vector())) } })); env->set(str("readline"), make_builtin_function(str("readline"), fun(params: vec): MalResult { if params.size != 1 || !params[0].is_string() { return MalResult::Err(malString(str("readline called with wrong number or type of params"))) } else { var entered = get_line(params[0].get_string(), 1024) if entered == "***EOF***" { return MalResult::Ok(malNil()) } return MalResult::Ok(malString(entered)) } })); env->set(str("meta"), make_builtin_function(str("meta"), fun(params: vec): MalResult { if params.size != 1 { return MalResult::Err(malString(str("meta called with not one argument"))) } else { if params[0].meta != null() { return MalResult::Ok(*params[0].meta) } else { return MalResult::Ok(malNil()) } } })); env->set(str("with-meta"), make_builtin_function(str("with-meta"), fun(params: vec): MalResult { if params.size != 2 { return MalResult::Err(malString(str("with-meta called with not two arguments"))) } else { var new_meta = new() new_meta->copy_construct(¶ms[1]) var new_value = params[0].deep_clone(); new_value.meta = new_meta return MalResult::Ok(new_value) } })); env->set(str("fn?"), make_builtin_function(str("fn?"), fun(params: vec): MalResult { return MalResult::Err(malString(str("not implemented"))) })); env->set(str("string?"), make_builtin_function(str("string?"), fun(params: vec): MalResult { return MalResult::Err(malString(str("not implemented"))) })); // self-modifying grammer env->set(str("add_terminal"), make_builtin_function(str("add_terminal"), fun(params: vec): MalResult { if params.size != 2 || !params[0].is_string() { return MalResult::Err(malString(str("add_terminal called with wrong number or type of params"))) } else { 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)))) }))) } })); env->set(str("add_grammer_rule"), make_builtin_function(str("add_grammer_rule"), fun(params: vec): MalResult { 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"))) } else { var nonterminal_str = params[0].get_symbol_text() var rule = params[1].get_vector_rc().get() var int_rule = vec() for (var i = 0; i < rule.size; i++;) { if rule[i].is_int() { int_rule.add(rule[i].get_int()) } else if rule[i].is_symbol() { var sub_nonterminal_idx = grammer.nonterminal_names.find(rule[i].get_symbol_text()) if sub_nonterminal_idx == -1 { return MalResult::Err(malString(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(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))) })) } else { return MalResult::Err(malString(str("add_grammer_rule called with not symbol, int, or string in rule"))) } } grammer.add_to_or_create_nonterminal(nonterminal_str, int_rule, params[2], fun(f: ref MalValue, x: ref vec): MalResult { var params = vec() for (var i = 0; i < x.size; i++;) { if is_err(x[i]) { return x[i] } params.add(get_value(x[i])) } return function_call(f, vec(malVector(params))) }) } })); var ERS = fun(params: vec): 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"))) } else { var input = params[0].get_string() var i = 0 var current_ret = MalResult::Ok(malNil()) 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 } } 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)) if is_err(current_ret) { return current_ret } // handle whitespace again 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 } } return current_ret } } env->set(str("eval-read-string"), make_builtin_function(str("eval-read-string"), ERS)); // reader macros /*rep(grammer, env, str("(add_grammer_rule (quote atom) [\"'\" (quote form)] (fn* (xs) (quasiquote (quote (unquote (nth xs 1))))))")) //'*/ rep(grammer, env, str("(add_grammer_rule (quote atom) (vector \"'\" (quote form)) (fn* (xs) (quasiquote (quote (unquote (nth xs 1))))))")) //' /*rep(grammer, env, str("(add_grammer_rule 'form (vector \"\\\\[\\\\]\") (fn* (xs) '(vector)))")) //'*/ rep(grammer, env, str("(add_grammer_rule 'form (vector \"\\\\[\" 'optional_WS \"\\\\]\") (fn* (xs) '(vector)))")) //' rep(grammer, env, str("(add_grammer_rule 'form (vector \"\\\\[\" 'optional_WS 'space_forms 'optional_WS \"\\\\]\") (fn* (xs) (quasiquote (vector (splice-unquote (nth xs 2))))))")) //' // now we can use ' for the rest rep(grammer, env, str("(add_grammer_rule 'atom [\"`\" 'form] (fn* (xs) (quasiquote (quasiquote (unquote (nth xs 1))))))")) rep(grammer, env, str("(add_grammer_rule 'atom [\"~\" 'form] (fn* (xs) (vector (quote unquote) (nth xs 1))))")) // the standard appears to be for splice-unquote to be , 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 rep(grammer, env, str("(add_grammer_rule 'atom [\",\" 'form] (fn* (xs) (vector (quote splice-unquote) (nth xs 1))))")) rep(grammer, env, str("(add_grammer_rule 'atom [\"@\" 'form] (fn* (xs) `(deref ~(nth xs 1))))")) //" rep(grammer, env, str("(def! not (fn* (a) (if a false true)))")) rep(grammer, env, str("(def! load-file (fn* (f) (eval-read-string (slurp f))))")) 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)))))))")) rep(grammer, env, str("(def! nil? (fn* (a) (= nil a)))")) var params = vec() 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 { for (var i = 2; i < argc; i++;) { params.add(malString(str(argv[i]))) } env->set(str("*ARGV*"), malVector(params)) var eval_result_str = rep(grammer, env, str("(load-file \"") + argv[1] + "\")") println(eval_result_str) if 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!") match (get_value(main).internal) { MalValue_int::Function(f) { var top_decs = str("#include \n#include \n#include \n#include \n#include \n") top_decs += """ jmp_buf *current_exception_handler; size_t current_exception_value; void error(char* message) {fprintf(stderr, "%s", message); exit(1);} 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);}} void check_int(size_t p, char* function) { if ((p&0x7)!=0) {fprintf(stderr, "%s: expected param to be int\n", function); exit(1);}} void check_vector(size_t p, char* function) { if ((p&0x7)!=0x2) {fprintf(stderr, "%s: expected param to be vector\n", function); exit(1);}} 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); }""" var top_defs = str("closure _plus_closure = { _plus_impl, NULL};\n") 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) { check_num_params(num, 2, "="); if (args[0] == args[1]) { return 0x9F; } else { return 0x1F; } } 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"); else if ((args[_idx] & 0x07) == 0x05) printf("'%s", ((char*)(args[_idx]>>3))+sizeof(size_t)); else if ((args[_idx] & 0x07) == 0x03) printf("%s", ((char*)(args[_idx]>>3))+sizeof(size_t)); else if ((args[_idx] & 0x07) == 0x02) { printf("( "); size_t* vec = (size_t*)(args[_idx]>>3); for (int i = 0; i < vec[1]; i++) { _print_impl(NULL, 1, vec+i+2); printf(" "); } printf(")"); } else if ((args[_idx] & 0x07) == 0x00) printf("%d", args[_idx]>>3); 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; } closure _println_closure = (closure){ _println_impl, NULL}; size_t _vector_impl(size_t* _, size_t num, size_t* args) { size_t *vec = malloc(sizeof(size_t)*(num + 2)); vec[0] = 0x2F; vec[1] = num; for (int i = 0; i < num; i++) vec[i+2] = args[i]; 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"); 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"); } return vec[(args[1]>>3)+2]; } else { error("Passed not a vector to nth\n"); } return 0x2F; } closure _nth_closure = (closure){ _nth_impl, NULL}; 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}; 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}; 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}; 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}; """ //" var main_s = str("int main(int argc, char** argv) {\n") var main_body = str() var inner_main = compile(&top_decs, &top_defs, &main_s, &main_body, f.env, *f.body) main_s += main_body; 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" write_file(str(argv[1]) + ".c", top_decs + top_defs + main_s) println("Finished compile") return 0 } } error("Main not a k' function") } else { println("No main function to compile, exiting") } } else { env->set(str("*ARGV*"), malVector(params)) rep(grammer, env, str("(println (str \"Mal [\" *host-language* \"]\"))")) while (true) { var line = get_line(str("user> "), 1024) if (line == "***EOF***") break println(rep(grammer, env, line)) } } } var tmp_idx: int = 0 fun new_tmp(): str { tmp_idx += 1 return str("x") + tmp_idx } fun find_closed_vars(defined: set, env: *Env, ast: MalValue): set { match (ast.internal) { MalValue_int::Vector(l) { println("Find closed vars list") if (l.get().size == 0) { return set() } else if (l.get()[0].is_symbol("def!")) { println("Find closed vars in def!") defined.add(l.get()[1].get_symbol_text()) /*return find_closed_vars(defined, env, l[2])*/ var to_ret = find_closed_vars(defined, env, l.get()[2]) println("end Find closed vars in def!") return to_ret } else if (l.get()[0].is_symbol("let*")) { var bindings = l.get()[1].get_vector_rc() var to_ret = set() var new_env = new()->construct(env) 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]) } 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") { var to_ret = set() for (var i = 1; i < l.get().size; i++;) { to_ret += find_closed_vars(defined, env, l.get()[i]) } return to_ret } else if (l.get()[0].is_symbol("fn*")) { println("Find closed vars fn*") 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)) println("end find closed vars fn*") return to_ret } else if (l.get()[0].is_symbol("quote")) { return set() } 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")) { error("macroexpand doesn't make sense while finding closed vars") } else if (l.get()[0].is_symbol("try*")) { error("finding closed vars in try* unimplemented") } else { var to_ret = set() for (var i = 0; i < l.get().size; i++;) { to_ret += find_closed_vars(defined, env, l.get()[i]) } return to_ret } println("end list") } MalValue_int::Symbol(s) { if !defined.contains(s) { var scope = env->find(s) // null scope should mean top level var if scope == null() { /*error("Can't find " + s + " in env when trying to find closed_vars\n" + env->to_string())*/ return set() } // don't do for top level vars if scope->outer != null() { return set(s) } } return set() } MalValue_int::Int(i) { return set() } MalValue_int::Nil() { return set() } MalValue_int::True() { return set() } MalValue_int::False() { return set() } MalValue_int::String(s) { return set() } MalValue_int::Function(f) { var new_env = new()->construct(env) for (var i = 0; i < f.parameters.size; i++;) { new_env->set(f.parameters[i], malNil()) } println("Find closed vars going inside function:\n" + new_env->to_string()) /*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) println("coming out of function") return to_ret } } error("Can't get closure_vars for " + pr_str(ast, true)) } 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_" } else { to_ret += s[i] } } return to_ret } fun compile_value(top_decs: *str, top_defs: *str, main_init: *str, defs: *str, env: *Env, ast: MalValue, quoted: bool): str { match (ast.internal) { MalValue_int::Nil() { return str("0x2F") } MalValue_int::True() { return str("0x9F") } MalValue_int::False() { return str("0x1F") } 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)") } error("cannot yet compile builtin function: " + f.name) } MalValue_int::Function(f) { 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" function += str("check_num_params(num, ") + f.parameters.size + ", \"lambda\");\n" var new_env = new()->construct(env) for (var i = 0; i < f.parameters.size; i++;) { function += "size_t " + f.parameters[i] + " = args[" + i + "];\n" new_env->set(f.parameters[i], malNil()) } var closed_vars = find_closed_vars(set(), 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" } } else { *defs += fun_name + "_closure->data = NULL;\n" } return "((((size_t)"+fun_name+"_closure)<<3)|0x6)" } MalValue_int::Symbol(s) { if quoted { 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)" } else { var c_legal_s = c_legal(s) var e = env->find(s); if e != null() && e->outer == null() { println(s + " found in outer-est scope!") var v = e->get(s) e->remove(s) var x = str() var value = compile_value(top_decs, top_defs, main_init, &x, e, get_value(v), true) *top_decs += "size_t " + c_legal_s + ";\n" *main_init += x *main_init += c_legal_s + " = " + value + ";\n" } return c_legal_s } } MalValue_int::String(s) { 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)" } MalValue_int::Vector(l) { var call_str = str("_vector_impl(NULL, ") + l.get().size + ", (size_t[]){ " for (var i = 0; i < l.get().size; i++;) { if i != 0 { call_str += ", " } if quoted { call_str += compile_value(top_decs, top_defs, main_init, defs, env, l.get()[i], true) } else { call_str += compile(top_decs, top_defs, main_init, defs, env, l.get()[i]) } } call_str += "})" if ast.meta != null() { 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 } } MalValue_int::Int(i) { return to_string(i<<3) } } error("could not compile value: " + pr_str(ast, true)) } fun compile(top_decs: *str, top_defs: *str, main_init: *str, defs: *str, env: *Env, ast: MalValue): str { var expanded = macroexpand(ast, env) if (is_err(expanded)) { error("compile error in macroexpand: " + pr_str(get_err(expanded), true)) } ast = get_value(expanded) if !ast.is_vector() { return compile_value(top_decs, top_defs, main_init, defs, env, ast, false) } match (ast.internal) { MalValue_int::Vector(l) { if (l.get().size == 0) { return compile_value(top_decs, top_defs, main_init, defs, env, ast, false) } else if (l.get()[0].is_symbol("def!")) { if (l.get().size != 3) { error("def! without exaclty key and value") } if (!l.get()[1].is_symbol()) { error("def! not on symbol") } if env->outer != null() { error("def! not at top level") } 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]) *defs += "size_t " + to_set_name + " = " + to_set_value + ";\n" return to_set_name } else if (l.get()[0].is_symbol("defmacro!")) { error("defmacro! doesn't make sense in compiled code") } else if (l.get()[0].is_symbol("let*")) { if (l.get().size != 3) { error("let* without list of bindings & end value") } if (!l.get()[1].is_vector()) { error("let* without list of bindings") } var bindings = l.get()[1].get_vector_rc() if (bindings.get().size & 1 != 0) { error("let* list of bindings has odd number of entries") } var let_val = new_tmp() *defs += "size_t " + let_val + ";\n{\n" var new_env = new()->construct(env) for (var i = 0; i < bindings.get().size; i+=2;) { if (!bindings.get()[i].is_symbol()) { error("let* var name not symbol") } 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()) } *defs += let_val + " = " + compile(top_decs, top_defs, main_init, defs, new_env, l.get()[2]) + ";\n}\n" return let_val } 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]) *defs += value_possible_side_effect + ";\n" } 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 { error("if needs 2 or 3 children") } var cond = compile(top_decs, top_defs, main_init, defs, env, l.get()[1]) var tmp_name = new_tmp() *defs += "size_t " + tmp_name + "; if (" + cond + " != 0x1F) {\n" var then = compile(top_decs, top_defs, main_init, defs, env, l.get()[2]) *defs += tmp_name + " = " + then + ";\n} else {\n" var else_ = compile(top_decs, top_defs, main_init, defs, env, l.get()[3]) *defs += tmp_name + " = " + else_ + ";\n}\n" return tmp_name } else if (l.get()[0].is_symbol("fn*")) { var f = EVAL(env, ast) return compile_value(top_decs, top_defs, main_init, defs, env, get_value(f), false) } else if (l.get()[0].is_symbol("quote")) { if l.get().size == 1 { error("compile quote with no arguments") } 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 { error("compile quasiquote with no arguments") } return compile(top_decs, top_defs, main_init, defs, env, quasiquote(l.get()[1])) } else if (l.get()[0].is_symbol("macroexpand")) { error("macroexpand doesn't make sense while compiling") } else if (l.get()[0].is_symbol("try*")) { 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" *defs += tmp_name + " = " + compile(top_decs, top_defs, main_init, defs, env, l.get()[1]) + ";\n" *defs += "} else {\n" 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() { error("catch* block malformed") } var new_env = new()->construct(env) 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" } else { *defs += tmp_name + " = current_exception_value;\n"; } *defs += "}\n" *defs += "current_exception_handler = " + tmp_exception_name + ";\n" return tmp_name } else { var to_call = vec() for (var i = 0; i < l.get().size; i++;) { to_call.add(compile(top_decs, top_defs, main_init, defs, env, l.get()[i])) } var func_name = new_tmp() *defs += "size_t " + func_name + "_r = " + to_call[0] + ";\n" *defs += "check_function(" + func_name + "_r, \"trying to call\");\n"; *defs += "closure* " + func_name + " = (closure*)(" + func_name + "_r>>3);\n" var params_name = new_tmp() *defs += "size_t " + params_name + "_params[] = {"+str(", ").join(to_call.slice(1,-1))+"};\n" return func_name + "->func(" + func_name + "->data, " + to_string(l.get().size-1) + ", " + params_name + "_params)" } } } return compile_value(top_decs, top_defs, main_init, defs, env, ast, false) }