read_str str
end
- macro is_pair(list)
- {{list}}.is_a?(Array) && !{{list}}.empty?
+ def starts_with(list, symbol)
+ if list.size == 2
+ head = list.first.unwrap
+ head.is_a? Mal::Symbol && head.str == symbol
+ end
end
- def quasiquote(ast)
- list = ast.unwrap
-
- unless is_pair(list)
- return Mal::Type.new(
- Mal::List.new << gen_type(Mal::Symbol, "quote") << ast
- )
+ def quasiquote_elts(list)
+ acc = Mal::Type.new(Mal::List.new)
+ list.reverse.each do |elt|
+ elt_val = elt.unwrap
+ if elt_val.is_a? Mal::List && starts_with(elt_val, "splice-unquote")
+ acc = Mal::Type.new(
+ Mal::List.new << gen_type(Mal::Symbol, "concat") << elt_val[1] << acc
+ )
+ else
+ acc = Mal::Type.new(
+ Mal::List.new << gen_type(Mal::Symbol, "cons") << quasiquote(elt) << acc
+ )
+ end
end
+ acc
+ end
- head = list.first.unwrap
-
- case
- # ("unquote" ...)
- when head.is_a?(Mal::Symbol) && head.str == "unquote"
- list[1]
- # (("splice-unquote" ...) ...)
- when is_pair(head) && (arg0 = head.first.unwrap).is_a?(Mal::Symbol) && arg0.str == "splice-unquote"
- tail = Mal::Type.new list[1..-1].each_with_object(Mal::List.new) { |e, l| l << e }
+ def quasiquote(ast)
+ ast_val = ast.unwrap
+ case ast_val
+ when Mal::List
+ if starts_with(ast_val,"unquote")
+ ast_val[1]
+ else
+ quasiquote_elts(ast_val)
+ end
+ when Mal::Vector
Mal::Type.new(
- Mal::List.new << gen_type(Mal::Symbol, "concat") << head[1] << quasiquote(tail)
+ Mal::List.new << gen_type(Mal::Symbol, "vec") << quasiquote_elts(ast_val)
)
- else
- tail = Mal::Type.new list[1..-1].each_with_object(Mal::List.new) { |e, l| l << e }
- Mal::Type.new(
- Mal::List.new << gen_type(Mal::Symbol, "cons") << quasiquote(list.first) << quasiquote(tail)
+ when Mal::HashMap, Mal::Symbol
+ Mal::Type.new (
+ Mal::List.new << gen_type(Mal::Symbol, "quote") << ast
)
+ else
+ ast
end
end
Mal::Closure.new(list[2], params, env, func_of(env, params, list[2]))
when "quote"
list[1]
+ when "quasiquoteexpand"
+ quasiquote list[1]
when "quasiquote"
ast = quasiquote list[1]
next # TCO