def read_atom(reader): token = reader.peek() try: val = int(token) return mal_types.MalNumber(val) except ValueError: pass if token in _quote_mapping: reader.next() return mal_types.MalList( [mal_types.MalSymbol(_quote_mapping[token]), read_form(reader)]) elif token == '^': reader.next() meta_data = read_form(reader) reader.next() lst = read_form(reader) return mal_types.MalList( [mal_types.MalSymbol("with-meta"), lst, meta_data]) elif token.startswith('"') and token.endswith('"'): return mal_types.MalString( bytes(token[1:-1], "utf-8").decode("unicode_escape")) elif token.startswith(":"): return mal_types.MalKeyword(token) elif token in ('true', 'false'): if token == 'true': return mal_types.MalBool(True) return mal_types.MalBool(False) elif token == 'nil': return mal_types.MalNil() return mal_types.MalSymbol(token) # symbol?
def seq(x): if not x.data: return mal_types.MalNil() elif isinstance(x, mal_types.MalList): return x elif isinstance(x, mal_types.MalVector): return mal_types.MalList(x.data) elif isinstance(x, mal_types.MalString): return mal_types.MalList([mal_types.MalString(i) for i in x.data])
def quasiquote(ast): if not is_pair(ast): return mal_types.MalList([mal_types.MalSymbol('quote'), ast]) elif ast[0].data == 'unquote': return ast[1] elif isinstance(ast[0], mal_types.list_types) and \ isinstance(ast[0][0], mal_types.MalSymbol) and \ ast[0][0].data == 'splice-unquote': return mal_types.MalList([mal_types.MalSymbol('concat'), ast[0][1], quasiquote(ast[1:])]) else: return mal_types.MalList([mal_types.MalSymbol('cons'), quasiquote(ast[0]), quasiquote(ast[1:])])
def cons(obj, lst): rv = mal_types.MalList([obj]) if isinstance(lst, list): #fixme rv.data.extend(lst) else: # rv.data.extend(lst.data) return rv
def conj(collection, *elements): if isinstance(collection, mal_types.MalList): lst = collection.data for i in elements: lst.insert(0, i) return mal_types.MalList(lst) if isinstance(collection, mal_types.MalVector): lst = collection.data for i in elements: lst.append(i) return mal_types.MalVector(lst)
def read_atom(reader: Reader): atom = reader.peek() special_chars = { "'": "quote", "`": "quasiquote", "~": "unquote", "~@": "splice-unquote", "@": "deref" } if atom[0] == '"': if not is_proper_quote(atom): return "EOF" return '"' + escape(atom[1:-1]) + '"' if is_integer(atom): return int(atom) if atom in special_chars: reader.next() res_lst = mal_types.MalList("(") res_lst.append(special_chars[atom]) res_lst.append(read_form(reader)) return res_lst if atom == "^": res_lst = mal_types.MalList("(") res_lst.append("with-meta") reader.next() second = read_form(reader) reader.next() first = read_form(reader) res_lst.append(first) res_lst.append(second) return res_lst if atom == "true": return True if atom == "false": return False if atom == "nil": return None else: return atom
def main(): rep("(def! not (fn* (a) (if a false true)))") rep('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))') rep("""(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw "odd number of forms to cond")) (cons'cond (rest (rest xs)))))))""") rep("""(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))""") repl_env.set("*ARGV*", mal_types.MalList([mal_types.MalString(i) for i in sys.argv[2:]])) if sys.argv[1:]: rep('(load-file "{}")'.format(sys.argv[1])) exit() while True: try: print(rep(input("user> "))) except mal_types.MalException as e: # raise e print(e) except Exception as e: # raise e print(e)
def main(): rep("(def! not (fn* (a) (if a false true)))") rep('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))' ) repl_env.set( "*ARGV*", mal_types.MalList([mal_types.MalString(i) for i in sys.argv[2:]])) if sys.argv[1:]: rep('(load-file "{}")'.format(sys.argv[1])) exit() while True: try: print(rep(input("user> "))) except mal_types.MalException as e: # raise e print(e) except Exception as e: # raise e print(e)
def read_list(reader: Reader, opener): res = mal_types.MalList(opener) try: for i in reader: next_atom = read_form(reader) if next_atom == res.closer: break res.append(next_atom) if opener == "{": for i in range(0, len(res), 2): res.dict[res[i]] = res[i + 1] res.clear() for x in sorted(res.dict): res.append(x) res.append(res.dict[x]) except IndexError: raise EOFError return res
def concat(*lsts): rv = mal_types.MalList() for l in lsts: rv.data.extend(l) return rv
def map_(f, lst): #print('**MAP', type(f), f, lst) return mal_types.MalList([f(i) for i in lst])
def rest(lst): if isinstance(lst, mal_types.MalNil): return mal_types.MalList() return mal_types.MalList(lst[1:])
return mal_types.MalBool(True) return mal_types.MalBool(False) ns = { '+': lambda a, b: mal_types.MalNumber( a.data + b.data), # fixme: operate and return maltypes directly '-': lambda a, b: mal_types.MalNumber(a.data - b.data), '*': lambda a, b: mal_types.MalNumber(a.data * b.data), '/': lambda a, b: mal_types.MalNumber((a.data / b.data)), "list": lambda *x: mal_types.MalList(list(x)), "list?": is_list, "vector": vector, "vector?": is_vector, "hash-map": hash_map, "map?": is_hash_map, "assoc": assoc, "dissoc": dissoc, "get":