Fix second-order self-hosting.
[jackhill/mal.git] / rpython / core.py
index 4f1d92d..5e7a12f 100644 (file)
@@ -26,6 +26,7 @@ def throw(args):
 def nil_Q(args): return wrap_tf(types._nil_Q(args[0]))
 def true_Q(args): return wrap_tf(types._true_Q(args[0]))
 def false_Q(args): return wrap_tf(types._false_Q(args[0]))
+def string_Q(args): return wrap_tf(types._string_Q(args[0]))
 def symbol(args):
     a0 = args[0]
     if isinstance(a0, MalStr):
@@ -37,6 +38,9 @@ def symbol(args):
 def symbol_Q(args): return wrap_tf(types._symbol_Q(args[0]))
 def keyword(args): return types._keyword(args[0])
 def keyword_Q(args): return wrap_tf(types._keyword_Q(args[0]))
+def number_Q(args): return wrap_tf(types._int_Q(args[0]))
+def function_Q(args): return wrap_tf(types._function_Q(args[0]) and not args[0].ismacro)
+def macro_Q(args): return wrap_tf(types._function_Q(args[0]) and args[0].ismacro)
 
 
 # String functions
@@ -269,21 +273,6 @@ def rest(args):
     if len(a0) == 0: return MalList([])
     else:            return a0.rest()
 
-# retains metadata
-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 apply(args):
     f, fargs = args[0], args.rest()
     last_arg = fargs.values[-1]
@@ -301,6 +290,37 @@ def mapf(args):
         res.append(f.apply(MalList([a])))
     return MalList(res)
 
+# retains metadata
+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")
 
 # Metadata functions
 def with_meta(args):
@@ -353,10 +373,14 @@ ns = {
         'nil?': nil_Q,
         'true?': true_Q,
         'false?': false_Q,
+        'string?': string_Q,
         'symbol': symbol,
         'symbol?': symbol_Q,
         'keyword': keyword,
         'keyword?': keyword_Q,
+        'number?': number_Q,
+        'fn?': function_Q,
+        'macro?': macro_Q,
 
         'pr-str': pr_str,
         'str': do_str,
@@ -396,10 +420,12 @@ ns = {
         'rest': rest,
         'empty?': empty_Q,
         'count': count,
-        'conj': conj,
         'apply': apply,
         'map': mapf,
 
+        'conj': conj,
+        'seq': seq,
+
         'with-meta': with_meta,
         'meta': meta,
         'atom': do_atom,