Remove keywords and maps from k_prime to make it leaner

This commit is contained in:
Nathan Braswell
2020-04-12 00:25:11 -04:00
parent c4078aa5e1
commit cb54429d1a
2 changed files with 29 additions and 272 deletions

33
bf.kp
View File

@@ -1,34 +1,33 @@
; Now we have native BF support
(def! with_update (fn* [arr idx val]
(if
(= idx 0)
(cons val (rest arr))
(cons (first arr) (with_update (rest arr) (- idx 1) val)))))
(if (= idx 0)
(cons val (rest arr))
(cons (first arr) (with_update (rest arr) (- idx 1) val)))))
(add_grammer_rule :bfs_atom ["<"] (fn* [xs] (list 'left)))
(add_grammer_rule :bfs_atom [">"] (fn* [xs] (list 'right)))
(add_grammer_rule :bfs_atom ["\\+"] (fn* [xs] (list 'plus)))
(add_grammer_rule :bfs_atom ["-"] (fn* [xs] (list 'minus)))
(add_grammer_rule :bfs_atom [","] (fn* [xs] (list 'in)))
(add_grammer_rule :bfs_atom ["."] (fn* [xs] (list 'out)))
(add_grammer_rule 'bfs_atom ["<"] (fn* [xs] (list 'left)))
(add_grammer_rule 'bfs_atom [">"] (fn* [xs] (list 'right)))
(add_grammer_rule 'bfs_atom ["\\+"] (fn* [xs] (list 'plus)))
(add_grammer_rule 'bfs_atom ["-"] (fn* [xs] (list 'minus)))
(add_grammer_rule 'bfs_atom [","] (fn* [xs] (list 'in)))
(add_grammer_rule 'bfs_atom ["."] (fn* [xs] (list 'out)))
(add_grammer_rule :non_empty_bfs_list [:bfs_atom] (fn* [xs] (list (nth xs 0))))
(add_grammer_rule :non_empty_bfs_list [:bfs_atom :optional_WS :non_empty_bfs_list] (fn* [xs] (cons (nth xs 0) (nth xs 2))))
(add_grammer_rule 'non_empty_bfs_list ['bfs_atom] (fn* [xs] (list (nth xs 0))))
(add_grammer_rule 'non_empty_bfs_list ['bfs_atom 'optional_WS 'non_empty_bfs_list] (fn* [xs] (cons (nth xs 0) (nth xs 2))))
(add_grammer_rule :bfs_list [] (fn* [xs] xs))
(add_grammer_rule :bfs_list [:non_empty_bfs_list] (fn* [xs] (nth xs 0)))
(add_grammer_rule 'bfs_list [] (fn* [xs] xs))
(add_grammer_rule 'bfs_list ['non_empty_bfs_list] (fn* [xs] (nth xs 0)))
(add_grammer_rule :bfs_atom ["\\[" :bfs_list "]"] (fn* [xs]
(add_grammer_rule 'bfs_atom ["\\[" 'bfs_list "]"] (fn* [xs]
`(let* (f (fn* []
(if (= 0 (nth (deref arr) (deref ptr)))
nil
(do ,(nth xs 1) (f)))))
(f))))
(add_grammer_rule :bfs [:bfs_list] (fn* [xs] (nth xs 0)))
(add_grammer_rule 'bfs ['bfs_list] (fn* [xs] (nth xs 0)))
(add_grammer_rule :form ["bf" :optional_WS "{" :optional_WS :bfs :optional_WS "}"]
(add_grammer_rule 'form ["bf" 'optional_WS "{" 'optional_WS 'bfs 'optional_WS "}"]
(fn* [xs]
`(fn* [input]
(let* (

View File

@@ -7,38 +7,6 @@ import map:*
import fungll:*
fun create_map(values: vec<MalValue>): MalResult {
var to_ret = map<MalValue,MalValue>()
if values.size & 1 == 1 {
return MalResult::Err(MalValue::String(str("odd number of keys/values")))
}
for (var i = 0; i < values.size; i+=2;) {
to_ret.set(values[i], values[i+1])
}
return MalResult::Ok(MalValue::Map(to_ret))
}
fun is_map(m: MalValue): bool {
match (m) {
MalValue::Map(m) {
return true
}
MalValue::Nil() {
return true
}
}
return false
}
fun get_map(m: MalValue): map<MalValue, MalValue> {
match (m) {
MalValue::Map(m) {
return m
}
MalValue::Nil() {
return map<MalValue, MalValue>()
}
}
error("can't get_map not a map")
}
fun read_str(grammer: ref Grammer<MalResult,MalValue>, s: str): pair<int, MalResult> {
var BSR = fungll(grammer, grammer.start_symbol, s)
var longest = -1
@@ -56,7 +24,6 @@ fun read_str(grammer: ref Grammer<MalResult,MalValue>, s: str): pair<int, MalRes
println(str() + i + ": " + grammer.to_string(BSR.data[i]))
}
println("Parse failed")
/*error("faileD")*/
return make_pair(-1, MalResult::Err(MalValue::String(str("failed to parse"))))
}
}
@@ -67,10 +34,8 @@ adt MalValue {
Int: int,
String: str,
Symbol: str,
Keyword: str,
List: vec<MalValue>,
Vector: vec<MalValue>,
Map: map<MalValue, MalValue>,
Function: MalFunction,
BuiltinFunction: MalBuiltinFunction,
Atom: *MalValue
@@ -125,21 +90,9 @@ fun equals_MalValue(a: MalValue, b: MalValue): bool {
return true
}
} }
MalValue::Map(d) { match (b) { MalValue::Map(db) {
if d.size() != db.size() {
return false
}
for (var i = 0; i < d.keys.size; i++;) {
if !db.contains_key(d.keys[i]) || !equals_MalValue(d.values[i], db[d.keys[i]]) {
return false
}
}
return true
} } }
MalValue::String(d) { match (b) { MalValue::String(db) { return d == db; } } }
MalValue::Int(d) { match (b) { MalValue::Int(db) { return d == db; } } }
MalValue::Symbol(d) { match (b) { MalValue::Symbol(db) { return d == db; } } }
MalValue::Keyword(d) { match (b) { MalValue::Keyword(db) { return d == db; } } }
MalValue::Function(d) { match (b) { MalValue::Function(db) { return d == db; } } }
MalValue::BuiltinFunction(d) { match (b) { MalValue::BuiltinFunction(db) { return d == db; } } }
MalValue::Atom(d) { match (b) { MalValue::Atom(db) { return d == db; } } }
@@ -149,36 +102,6 @@ fun equals_MalValue(a: MalValue, b: MalValue): bool {
}
return false
}
fun is_keyword(v: MalValue): bool {
match (v) {
MalValue::Keyword(k) {
return true
}
}
return false
}
fun is_keyword_or_string(v: MalValue): bool {
match (v) {
MalValue::Keyword(k) {
return true
}
MalValue::String(s) {
return true
}
}
return false
}
fun get_keyword_or_string_text(v: MalValue): str {
match (v) {
MalValue::Keyword(k) {
return k
}
MalValue::String(s) {
return s
}
}
error("Tried to get_keyword_or_string_text on not a keyword or string!")
}
fun is_list(v: MalValue): bool {
match (v) {
MalValue::List(l) {
@@ -593,18 +516,6 @@ fun pr_str(v: MalValue, print_readably: bool): str {
}
return to_ret + "]"
}
MalValue::Map(m) {
var to_ret = str("{")
for (var i = 0; i < m.keys.size; i++;) {
if (i != 0) {
to_ret += " "
}
to_ret += pr_str(m.keys[i], print_readably)
to_ret += str(" ")
to_ret += pr_str(m.values[i], print_readably)
}
return to_ret + "}"
}
MalValue::Int(i) {
return to_string(i)
}
@@ -630,9 +541,6 @@ fun pr_str(v: MalValue, print_readably: bool): str {
MalValue::Symbol(s) {
return s
}
MalValue::Keyword(k) {
return str(":") + k
}
MalValue::BuiltinFunction(f) {
return str("builtin function")
}
@@ -692,17 +600,6 @@ fun eval_ast(env: *Env, ast: MalValue): MalResult {
}
return MalResult::Ok(MalValue::Vector(to_ret))
}
MalValue::Map(l) {
var to_ret = map<MalValue, MalValue>()
for (var i = 0; i < l.keys.size; i++;) {
var mid = EVAL(env, l.values[i])
if is_err(mid) {
return mid
}
to_ret.set(l.keys[i], get_value(mid))
}
return MalResult::Ok(MalValue::Map(to_ret))
}
MalValue::Symbol(s) {
return env->get(s)
}
@@ -951,7 +848,7 @@ fun main(argc: int, argv: **char): int {
var atom = grammer.add_new_nonterminal("atom", vec(grammer.add_terminal("-?[0-9]+", MalValue::Nil(), fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult { return MalResult::Ok(MalValue::Int(string_to_num<int>(input.slice(l,r)))); })), MalValue::Nil(), ret_0_sym)
grammer.add_to_nonterminal(atom, vec(grammer.add_terminal("\"([#-[]| |[]-~]|(\\\\)|(\\n)|(\\t)|(\\\*)|(\\0)|
|[ -!]|(\\\\\"))*\"", MalValue::Nil(), fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult {
|[ -!]|(\\\\\"))*\"", MalValue::Nil(), 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] == '\\' {
@@ -968,9 +865,8 @@ fun main(argc: int, argv: **char): int {
to_ret += input[i]
}
}
/*return MalResult::Ok(MalValue::String(input.slice(l+1,r-1)));*/
return MalResult::Ok(MalValue::String(to_ret));
})), MalValue::Nil(), ret_0_sym) //"
})), MalValue::Nil(), ret_0_sym)
grammer.add_to_nonterminal(atom, vec(grammer.add_terminal("-|(([a-z]|[A-Z]|_|\\*|/|\\?|\\+|!|=|&|<|>)([a-z]|[A-Z]|_|[0-9]|\\*|\\?|\\+|-|!|=|&|<|>)*)", MalValue::Nil(), fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult {
var s = input.slice(l,r)
if s == "true" {
@@ -983,7 +879,6 @@ fun main(argc: int, argv: **char): int {
return MalResult::Ok(MalValue::Symbol(input.slice(l,r)));
}
})), MalValue::Nil(), ret_0_sym)
grammer.add_to_nonterminal(atom, vec(grammer.add_terminal(":([a-z]|[A-Z]|_)([a-z]|[A-Z]|_|[0-9])*", MalValue::Nil(), fun(_: ref MalValue, input: ref str, l: int, r: int): MalResult { return MalResult::Ok(MalValue::Keyword(input.slice(l,r))); })), MalValue::Nil(), ret_0_sym)
var form = grammer.add_new_nonterminal("form", vec(atom), MalValue::Nil(), ret_0_sym)
var space_forms = grammer.add_new_nonterminal("space_forms", vec<int>(), MalValue::Nil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult {
@@ -1024,46 +919,6 @@ fun main(argc: int, argv: **char): int {
return MalResult::Ok(MalValue::Vector(get_list(get_value(x[2]))))
})
var doubled_space_forms = grammer.add_new_nonterminal("doubled_space_forms", vec<int>(), MalValue::Nil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult {
return MalResult::Ok(MalValue::List(vec<MalValue>()))
})
grammer.add_to_nonterminal(doubled_space_forms, vec(form, WS, form), MalValue::Nil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult {
if is_err(x[0]) {
return x[0]
}
if is_err(x[2]) {
return x[2]
}
return MalResult::Ok(MalValue::List(vec(get_value(x[0]), get_value(x[2]))))
})
grammer.add_to_nonterminal(doubled_space_forms, vec(form, WS, form, WS, doubled_space_forms), MalValue::Nil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult {
if is_err(x[0]) {
return x[0]
}
if is_err(x[2]) {
return x[2]
}
if is_err(x[4]) {
return x[4]
}
return MalResult::Ok(MalValue::List(vec(get_value(x[0]), get_value(x[2])) + get_list(get_value(x[4]))))
})
grammer.add_to_nonterminal(form, vec(grammer.add_terminal("{", MalValue::Nil(), ret_nil_term),
optional_WS,
doubled_space_forms,
optional_WS,
grammer.add_terminal("}", MalValue::Nil(), ret_nil_term)), MalValue::Nil(), fun(_: ref MalValue, x: ref vec<MalResult>): MalResult {
if is_err(x[2]) {
return x[2]
}
var to_ret = map<MalValue,MalValue>()
var values = get_list(get_value(x[2]))
for (var i = 0; i < values.size; i+=2;) {
to_ret.set(values[i], values[i+1])
}
return MalResult::Ok(MalValue::Map(to_ret))
})
grammer.set_start_symbol(form)
@@ -1370,20 +1225,6 @@ fun main(argc: int, argv: **char): int {
return MalResult::Ok(MalValue::Symbol(get_string(params[0])))
}
}));
env->set(str("keyword?"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 1 {
return MalResult::Err(MalValue::String(str("keyword? called with wrong number of params")))
} else {
return MalResult::Ok(bool_to_MalValue(is_keyword(params[0])))
}
}));
env->set(str("keyword"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 1 || !is_keyword_or_string(params[0]) {
return MalResult::Err(MalValue::String(str("keyword called with wrong number or type of params")))
} else {
return MalResult::Ok(MalValue::Keyword(get_keyword_or_string_text(params[0])))
}
}));
env->set(str("vector"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
return MalResult::Ok(MalValue::Vector(params))
}));
@@ -1403,89 +1244,6 @@ fun main(argc: int, argv: **char): int {
return MalResult::Ok(bool_to_MalValue(is_list_or_vec(params[0])))
}
}));
env->set(str("hash-map"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
return create_map(params)
}));
env->set(str("map?"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 1 {
return MalResult::Err(MalValue::String(str("map? called with wrong number of params")))
} else {
return MalResult::Ok(bool_to_MalValue(is_map(params[0])))
}
}));
env->set(str("assoc"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size & 1 != 1 || !is_map(params[0]) {
return MalResult::Err(MalValue::String(str("assoc? called with wrong number or type of params")))
} else {
var base = get_map(params[0])
var new = create_map(params.slice(1,-1))
if is_err(new) {
return new
}
var new_map = get_map(get_value(new))
for (var i = 0; i < new_map.keys.size; i++;) {
base.set(new_map.keys[i], new_map.values[i])
}
return MalResult::Ok(MalValue::Map(base))
}
}));
env->set(str("dissoc"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size < 2 || !is_map(params[0]) {
return MalResult::Err(MalValue::String(str("dissoc? called with wrong number or type of params")))
} else {
var base = get_map(params[0])
var remove = vec<MalValue>()
if params.size != 2 || !is_list(params[1]) {
remove = params.slice(1,-1)
} else {
remove = get_list(params[1])
}
for (var i = 0; i < remove.size; i++;) {
if base.contains_key(remove[i]) {
base.remove(remove[i])
}
}
return MalResult::Ok(MalValue::Map(base))
}
}));
env->set(str("get"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 2 || !is_map(params[0]) || !is_keyword_or_string(params[1]) {
return MalResult::Err(MalValue::String(str("get called with wrong number or type of params")))
} else {
var base = get_map(params[0])
if base.contains_key(params[1]) {
return MalResult::Ok(base.get(params[1]))
} else {
return MalResult::Ok(MalValue::Nil())
}
}
}));
env->set(str("contains?"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 2 || !is_map(params[0]) || !is_keyword_or_string(params[1]) {
return MalResult::Err(MalValue::String(str("contains? called with wrong number or type of params")))
} else {
var base = get_map(params[0])
if base.contains_key(params[1]) {
return MalResult::Ok(MalValue::True())
} else {
return MalResult::Ok(MalValue::False())
}
}
}));
env->set(str("keys"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 1 || !is_map(params[0]) {
return MalResult::Err(MalValue::String(str("keys called with wrong number or type of params")))
} else {
return MalResult::Ok(MalValue::List(get_map(params[0]).keys))
}
}));
env->set(str("vals"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 1 || !is_map(params[0]) {
return MalResult::Err(MalValue::String(str("vals called with wrong number or type of params")))
} else {
return MalResult::Ok(MalValue::List(get_map(params[0]).values))
}
}));
env->set(str("readline"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 1 || !is_string(params[0]) {
return MalResult::Err(MalValue::String(str("readline called with wrong number or type of params")))
@@ -1529,19 +1287,19 @@ fun main(argc: int, argv: **char): int {
}
}));
env->set(str("add_grammer_rule"), make_builtin_function(fun(params: vec<MalValue>): MalResult {
if params.size != 3 || !is_keyword(params[0]) || !is_vector(params[1]) {
if params.size != 3 || !is_symbol(params[0]) || !is_vector(params[1]) {
return MalResult::Err(MalValue::String(str("add_grammer_rule called with wrong number or type of params")))
} else {
var nonterminal_str = get_keyword_or_string_text(params[0]).slice(1,-1)
var nonterminal_str = get_symbol_text(params[0])
var rule = get_list_or_vec(params[1])
var int_rule = vec<int>()
for (var i = 0; i < rule.size; i++;) {
if is_int(rule[i]) {
int_rule.add(get_int(rule[i]))
} else if is_keyword(rule[i]) {
var sub_nonterminal_idx = grammer.nonterminal_names.find(get_keyword_or_string_text(rule[i]).slice(1,-1))
} else if is_symbol(rule[i]) {
var sub_nonterminal_idx = grammer.nonterminal_names.find(get_symbol_text(rule[i]))
if sub_nonterminal_idx == -1 {
return MalResult::Err(MalValue::String(str("Couldn't find nonterminal: ") + get_keyword_or_string_text(rule[i]).slice(1,-1)))
return MalResult::Err(MalValue::String(str("Couldn't find nonterminal: ") + get_symbol_text(rule[i])))
}
var sub_nonterminal = -1*(sub_nonterminal_idx+1)
int_rule.add(sub_nonterminal)
@@ -1550,7 +1308,7 @@ fun main(argc: int, argv: **char): int {
return MalResult::Ok(MalValue::String(input.slice(l,r)))
}))
} else {
return MalResult::Err(MalValue::String(str("add_grammer_rule called with not keyword, int, or string in rule")))
return MalResult::Err(MalValue::String(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>): MalResult {
@@ -1620,14 +1378,14 @@ fun main(argc: int, argv: **char): int {
}
}));
// reader macros
rep(grammer, env, str("(add_grammer_rule :atom [\"'\" :form] (fn* (xs) (quasiquote (quote (unquote (nth xs 1))))))")) //'
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) (list (quote unquote) (nth xs 1))))"))
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 'atom [\"`\" 'form] (fn* (xs) (quasiquote (quasiquote (unquote (nth xs 1))))))"))
rep(grammer, env, str("(add_grammer_rule 'atom [\"~\" 'form] (fn* (xs) (list (quote unquote) (nth xs 1))))"))
// 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
rep(grammer, env, str("(add_grammer_rule :atom [\",\" :form] (fn* (xs) (list (quote splice-unquote) (nth xs 1))))"))
rep(grammer, env, str("(add_grammer_rule 'atom [\",\" 'form] (fn* (xs) (list (quote splice-unquote) (nth xs 1))))"))
// let's use the new reader macros in another reader macro
rep(grammer, env, str("(add_grammer_rule :atom [\"@\" :form] (fn* (xs) `(deref ~(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))))"))