diff --git a/lib/bus_scheme/eval.rb b/lib/bus_scheme/eval.rb index 816d115..69f6daf 100644 --- a/lib/bus_scheme/eval.rb +++ b/lib/bus_scheme/eval.rb @@ -55,4 +55,16 @@ def stacktrace def stack @@stack end + + # TODO: unquote-splicing + def quasiquote(arg) + if !arg.is_a? Cons or arg.empty? + arg + elsif arg.is_a? Cons and arg.car == 'unquote'.sym + eval(arg.cadr) + else + Cons.new(quasiquote(arg.car), + quasiquote(arg.cdr)) + end + end end diff --git a/lib/bus_scheme/primitives.rb b/lib/bus_scheme/primitives.rb index 9357c15..c8a7e33 100644 --- a/lib/bus_scheme/primitives.rb +++ b/lib/bus_scheme/primitives.rb @@ -43,11 +43,8 @@ def self.special_form(identifier, value) define 'exit', primitive { exit } define 'quit', BusScheme['exit'.sym] - - # TODO: write - special_form 'quasiquote', primitive { } - special_form 'unquote', primitive { } - special_form 'unquote-splicing', primitive { } + special_form 'quasiquote', primitive { |arg| quasiquote(arg) } + special_form 'qq', BusScheme['quasiquote'.sym] # Primitives that can't be defined in terms of other forms: special_form 'quote', primitive { |arg| arg } diff --git a/test/test_eval.rb b/test/test_eval.rb index 0dd1bfe..ce55661 100644 --- a/test/test_eval.rb +++ b/test/test_eval.rb @@ -87,6 +87,11 @@ def test_evals_string_ending_in_comment ;; should be four" end + def test_quasi_quote + assert_evals_to([:hey.sym, :there.sym, "dude"].to_list, + '(qq (hey there (unquote (+ "du" "de"))))') + end + # def test_tail_call_optimization # Timeout.timeout(1) do # assert_nothing_raised { eval "((lambda (x) (x x)) (lambda (x) (x x)))" }