Change quasiquote algorithm
[jackhill/mal.git] / impls / fantom / src / step7_quote / fan / main.fan
index a61976f..080591c 100644 (file)
@@ -2,20 +2,43 @@ using mallib
 
 class Main
 {
+
+  static MalList qq_loop(MalVal elt, MalList acc)
+  {
+    lst := elt as MalList
+    if (lst?.count == 2 && (lst[0] as MalSymbol)?.value == "splice-unquote")
+      return MalList(MalVal[MalSymbol("concat"), lst[1], acc])
+    else
+      return MalList(MalVal[MalSymbol("cons"), quasiquote(elt), acc])
+  }
+
+  static MalList qq_foldr(MalSeq xs)
+  {
+    acc := MalList([,])
+    for (i:=xs.count-1; 0<=i; i-=1)
+      acc = qq_loop(xs[i], acc)
+    return acc
+  }
+
   static MalVal quasiquote(MalVal ast)
   {
-    if (!MalTypes.isPair(ast))
-      return MalList(MalVal[MalSymbol("quote"), ast])
-    astSeq := ast as MalSeq
-    if ((astSeq[0] as MalSymbol)?.value == "unquote")
-      return astSeq[1]
-    if (MalTypes.isPair(astSeq[0]))
+    switch (ast.typeof)
     {
-      ast0Seq := astSeq[0] as MalSeq
-      if ((ast0Seq[0] as MalSymbol)?.value == "splice-unquote")
-        return MalList(MalVal[MalSymbol("concat"), ast0Seq[1], quasiquote(astSeq.drop(1))])
+      case MalList#:
+        lst := ast as MalList
+        if (lst.count == 2 && (lst[0] as MalSymbol)?.value == "unquote")
+          return  lst[1]
+        else
+          return qq_foldr((MalSeq)ast)
+      case MalVector#:
+        return MalList(MalVal[MalSymbol("vec"), qq_foldr((MalSeq)ast)])
+      case MalSymbol#:
+        return MalList(MalVal[MalSymbol("quote"), ast])
+      case MalHashMap#:
+        return MalList(MalVal[MalSymbol("quote"), ast])
+      default:
+        return ast
     }
-    return MalList(MalVal[MalSymbol("cons"), quasiquote(astSeq[0]), quasiquote(astSeq.drop(1))])
   }
 
   static MalVal READ(Str s)
@@ -64,6 +87,8 @@ class Main
           // TCO
         case "quote":
           return astList[1]
+        case "quasiquoteexpand":
+          return quasiquote(astList[1])
         case "quasiquote":
           ast = quasiquote(astList[1])
           // TCO