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)
// TCO
case "quote":
return astList[1]
+ case "quasiquoteexpand":
+ return quasiquote(astList[1])
case "quasiquote":
ast = quasiquote(astList[1])
// TCO