def concat(args): new_lst = [] for l in args.values: if not isinstance(l, MalList): throw_str("concat called with non-list/non-vector") new_lst = new_lst + l.values return MalList(new_lst)
def read_atom(reader): if IS_RPYTHON: int_re = '-?[0-9]+$' float_re = '-?[0-9][0-9.]*$' else: int_re = re.compile('-?[0-9]+$') float_re = re.compile('-?[0-9][0-9.]*$') token = reader.next() if re.match(int_re, token): return MalInt(int(token)) ## elif re.match(float_re, token): return int(token) elif token[0] == '"': end = len(token)-1 if end == 1: return MalStr(u"") elif end < 1 or token[end] != '"': types.throw_str("expected '\"', got EOF") else: s = unicode(token[1:end]) s = types._replace(u'\\\\', u"\u029e", s) s = types._replace(u'\\"', u'"', s) s = types._replace(u'\\n', u"\n", s) s = types._replace(u"\u029e", u"\\", s) return MalStr(s) elif token[0] == ':': return _keywordu(unicode(token[1:])) elif token == "nil": return types.nil elif token == "true": return types.true elif token == "false": return types.false else: return MalSym(unicode(token))
def divide(args): a, b = args[0], args[1] if not isinstance(a, MalInt) or not isinstance(b, MalInt): throw_str("/ called on non-integer") if b.value == 0: throw_str("divide by zero") return MalInt(int(a.value/b.value))
def apply(args): f, fargs = args[0], args.rest() last_arg = fargs.values[-1] if not isinstance(last_arg, MalList): throw_str("map called with non-list") all_args = fargs.values[0:-1] + last_arg.values return f.apply(MalList(all_args))
def empty_Q(args): seq = args[0] if isinstance(seq, MalList): return wrap_tf(len(seq) == 0) elif seq is nil: return true else: throw_str("empty? called on non-sequence")
def symbol(args): a0 = args[0] if isinstance(a0, MalStr): return types._symbol(a0.value) elif isinstance(a0, MalSym): return a0 else: throw_str("symbol called on non-string/non-symbol")
def rest(args): a0 = args[0] if a0 is nil: return MalList([]) elif not isinstance(a0, MalList): throw_str("rest called with non-list/non-vector") if len(a0) == 0: return MalList([]) else: return a0.rest()
def first(args): a0 = args[0] if a0 is nil: return nil elif not isinstance(a0, MalList): throw_str("first called with non-list/non-vector") if len(a0) == 0: return nil else: return a0[0]
def mapf(args): f, lst = args[0], args[1] if not isinstance(lst, MalList): throw_str("map called with non-list") res = [] for a in lst.values: res.append(f.apply(MalList([a]))) return MalList(res)
def count(args): seq = args[0] if isinstance(seq, MalList): return MalInt(len(seq)) elif seq is nil: return MalInt(0) else: throw_str("count called on non-sequence")
def with_meta(args): obj, meta = args[0], args[1] if isinstance(obj, MalMeta): new_obj = types._clone(obj) new_obj.meta = meta return new_obj else: throw_str("with-meta not supported on type")
def do_readline(args): prompt = args[0] if not isinstance(prompt, MalStr): throw_str("readline prompt is not a string") try: return MalStr(unicode(mal_readline.readline(str(prompt.value)))) except EOFError: return nil
def swap_BANG(args): atm, f, fargs = args[0], args[1], args.slice(2) if not isinstance(atm, MalAtom): throw_str("swap! called on non-atom") if not isinstance(f, MalFunc): throw_str("swap! called with non-function") all_args = [atm.value] + fargs.values atm.value = f.apply(MalList(all_args)) return atm.value
def dissoc(args): src_hm, keys = args[0], args.rest() new_dct = src_hm.dct.copy() for k in keys.values: if not isinstance(k, MalStr): throw_str("dissoc called with non-string/non-keyword key") if k.value in new_dct: del new_dct[k.value] return MalHashMap(new_dct)
def assoc(args): src_hm, key_vals = args[0], args.rest() new_dct = src_hm.dct.copy() for i in range(0,len(key_vals),2): k = key_vals[i] if not isinstance(k, MalStr): throw_str("assoc called with non-string/non-keyword key") new_dct[k.value] = key_vals[i+1] return MalHashMap(new_dct)
def read_sequence(reader, start='(', end=')'): ast = [] token = reader.next() if token != start: types.throw_str("expected '" + start + "'") token = reader.peek() while token != end: if not token: types.throw_str("expected '" + end + "', got EOF") ast.append(read_form(reader)) token = reader.peek() reader.next() return ast
def conj(args): lst, args = args[0], args.rest() new_lst = None if types._list_Q(lst): vals = args.values[:] vals.reverse() new_lst = MalList(vals + lst.values) elif types._vector_Q(lst): new_lst = MalVector(lst.values + list(args.values)) else: throw_str("conj on non-list/non-vector") new_lst.meta = lst.meta return new_lst
def seq(args): a0 = args[0] if isinstance(a0, MalVector): if len(a0) == 0: return nil return MalList(a0.values) elif isinstance(a0, MalList): if len(a0) == 0: return nil return a0 elif types._string_Q(a0): assert isinstance(a0, MalStr) if len(a0) == 0: return nil return MalList([MalStr(unicode(c)) for c in a0.value]) elif a0 is nil: return nil else: throw_str("seq: called on non-sequence")
def __init__(self, outer=None, binds=None, exprs=None): self.data = {} self.outer = outer or None if binds: assert isinstance(binds, MalList) and isinstance(exprs, MalList) for i in range(len(binds)): bind = binds[i] if not isinstance(bind, MalSym): throw_str("env bind value is not a symbol") if bind.value == u"&": bind = binds[i + 1] if not isinstance(bind, MalSym): throw_str("env bind value is not a symbol") self.data[bind.value] = exprs.slice(i) break else: self.data[bind.value] = exprs[i]
def nth(args): lst, idx = args[0], args[1] if not isinstance(lst, MalList): throw_str("nth called with non-list/non-vector") if not isinstance(idx, MalInt): throw_str("nth called with non-int index") if idx.value < len(lst): return lst[idx.value] else: throw_str("nth: index out of range")
def read_form(reader): token = reader.peek() # reader macros/transforms if token[0] == ';': reader.next() return None elif token == '\'': reader.next() return _list(MalSym(u'quote'), read_form(reader)) elif token == '`': reader.next() return _list(MalSym(u'quasiquote'), read_form(reader)) elif token == '~': reader.next() return _list(MalSym(u'unquote'), read_form(reader)) elif token == '~@': reader.next() return _list(MalSym(u'splice-unquote'), read_form(reader)) elif token == '^': reader.next() meta = read_form(reader) return _list(MalSym(u'with-meta'), read_form(reader), meta) elif token == '@': reader.next() return _list(MalSym(u'deref'), read_form(reader)) # list elif token == ')': types.throw_str("unexpected ')'") elif token == '(': return read_list(reader) # vector elif token == ']': types.throw_str("unexpected ']'") elif token == '[': return read_vector(reader) # hash-map elif token == '}': types.throw_str("unexpected '}'") elif token == '{': return read_hash_map(reader) # atom else: return read_atom(reader)
def get(args): obj, key = args[0], args[1] if obj is nil: return nil elif isinstance(obj, MalHashMap): if not isinstance(key, MalStr): throw_str("get called on hash-map with non-string/non-keyword key") if obj and key.value in obj.dct: return obj.dct[key.value] else: return nil elif isinstance(obj, MalList): if not isinstance(key, MalInt): throw_str("get called on list/vector with non-string/non-keyword key") return obj.values[key.value] else: throw_str("get called on invalid type")
def read_form(reader): token = reader.peek() # reader macros/transforms if token[0] == ';': reader.next() return None elif token == '\'': reader.next() return _list(MalSym(u'quote'), read_form(reader)) elif token == '`': reader.next() return _list(MalSym(u'quasiquote'), read_form(reader)) elif token == '~': reader.next() return _list(MalSym(u'unquote'), read_form(reader)) elif token == '~@': reader.next() return _list(MalSym(u'splice-unquote'), read_form(reader)) elif token == '^': reader.next() meta = read_form(reader) return _list(MalSym(u'with-meta'), read_form(reader), meta) elif token == '@': reader.next() return _list(MalSym(u'deref'), read_form(reader)) # list elif token == ')': types.throw_str("unexpected ')'") elif token == '(': return read_list(reader) # vector elif token == ']': types.throw_str("unexpected ']'"); elif token == '[': return read_vector(reader); # hash-map elif token == '}': types.throw_str("unexpected '}'"); elif token == '{': return read_hash_map(reader); # atom else: return read_atom(reader);
def lte(args): a, b = args[0], args[1] if not isinstance(a, MalInt) or not isinstance(b, MalInt): throw_str("<= called on non-integer") return wrap_tf(a.value <= b.value)
def slurp(args): a0 = args[0] if not isinstance(a0, MalStr): throw_str("slurp with non-string filename") return MalStr(unicode(open(str(a0.value)).read()))
def read_str(args): a0 = args[0] if not isinstance(a0, MalStr): throw_str("read-string of non-string") return reader.read_str(str(a0.value))
def contains_Q(args): hm, key = args[0], args[1] if not isinstance(key, MalStr): throw_str("contains? called on hash-map with non-string/non-keyword key") return wrap_tf(key.value in hm.dct)
def reset_BANG(args): atm, val = args[0], args[1] if not isinstance(atm, MalAtom): throw_str("reset! called on non-atom") atm.value = val return atm.value
def deref(args): atm = args[0] if not isinstance(atm, MalAtom): throw_str("deref called on non-atom") return atm.value
def meta(args): obj = args[0] if isinstance(obj, MalMeta): return obj.meta else: throw_str("meta not supported on type")
def cons(args): x, seq = args[0], args[1] if not isinstance(seq, MalList): throw_str("cons called with non-list/non-vector") return MalList([x] + seq.values)