Change quasiquote algorithm
[jackhill/mal.git] / impls / gnu-smalltalk / stepA_mal.st
index 6461c42..4394d52 100644 (file)
@@ -46,36 +46,44 @@ Object subclass: MAL [
         ^aClass new: items
     ]
 
+    MAL class >> starts_with: ast sym: sym  [
+        | a a0 |
+        ast type = #list ifFalse: [ ^false. ].
+        a := ast value.
+        a isEmpty ifTrue: [ ^false. ].
+        a0 := a first.
+        ^a0 type = #symbol and: [ a0 value = sym ].
+    ]
+
     MAL class >> quasiquote: ast [
-        | result a a0 a0_ a0_0 rest |
-        ast isPair ifFalse: [
+        | result acc |
+        (ast type = #symbol or: [ ast type = #map ]) ifTrue: [
             result := {MALSymbol new: #quote. ast}.
             ^MALList new: (OrderedCollection from: result)
         ].
+        (ast type = #list or: [ ast type = #vector ]) ifFalse: [
+            ^ast
+        ].
 
-        a := ast value.
-        a0 := a first.
-
-        (a0 type = #symbol and: [ a0 value = #unquote ]) ifTrue: [ ^a second ].
-
-        a0 isPair ifTrue: [
-            a0_ := a0 value.
-            a0_0 := a0_ first.
-
-            (a0_0 type = #symbol and:
-             [ a0_0 value = #'splice-unquote' ]) ifTrue: [
-                rest := MALList new: a allButFirst.
-                result := {MALSymbol new: #concat.
-                           a0_ second.
-                           self quasiquote: rest}.
-                ^MALList new: (OrderedCollection from: result)
-            ]
+        (self starts_with: ast sym: #unquote) ifTrue: [
+            ^ast value second
         ].
 
-        rest := MALList new: a allButFirst.
-        result := {MALSymbol new: #cons. self quasiquote: a0.
-                   self quasiquote: rest}.
-        ^MALList new: (OrderedCollection from: result)
+        result := {}.
+        acc := MALList new: (OrderedCollection from: result).
+        ast value reverseDo: [ : elt |
+            (self starts_with: elt sym: #'splice-unquote') ifTrue: [
+                result := {MALSymbol new: #concat. elt value second. acc}
+            ] ifFalse: [
+                result := {MALSymbol new: #cons. self quasiquote: elt. acc}
+            ].
+            acc := MALList new: (OrderedCollection from: result)
+        ].
+        ast type = #vector ifTrue: [
+            result := {MALSymbol new: #vec. acc}.
+            acc := MALList new: (OrderedCollection from: result)
+        ].
+        ^acc
     ]
 
     MAL class >> isMacroCall: ast env: env [
@@ -210,6 +218,11 @@ Object subclass: MAL [
                     ^a1
                 ].
 
+                a0_ = #quasiquoteexpand ifTrue: [
+                    a1 := ast second.
+                    ^self quasiquote: a1.
+                ].
+
                 a0_ = #quasiquote ifTrue: [
                     | result |
                     a1 := ast second.