nydp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +58 -0
  7. data/Rakefile +1 -0
  8. data/bin/nydp +5 -0
  9. data/bin/nydp-tests +5 -0
  10. data/lib/lisp/boot.nydp +219 -0
  11. data/lib/lisp/test-runner.nydp +39 -0
  12. data/lib/lisp/tests/foundation-test.nydp +28 -0
  13. data/lib/nydp.rb +143 -0
  14. data/lib/nydp/assignment.rb +40 -0
  15. data/lib/nydp/builtin.rb +8 -0
  16. data/lib/nydp/builtin/apply.rb +16 -0
  17. data/lib/nydp/builtin/car.rb +5 -0
  18. data/lib/nydp/builtin/cdr.rb +5 -0
  19. data/lib/nydp/builtin/cdr_set.rb +8 -0
  20. data/lib/nydp/builtin/comment.rb +5 -0
  21. data/lib/nydp/builtin/cons.rb +16 -0
  22. data/lib/nydp/builtin/divide.rb +13 -0
  23. data/lib/nydp/builtin/error.rb +6 -0
  24. data/lib/nydp/builtin/eval.rb +14 -0
  25. data/lib/nydp/builtin/greater_than.rb +10 -0
  26. data/lib/nydp/builtin/hash.rb +30 -0
  27. data/lib/nydp/builtin/inspect.rb +5 -0
  28. data/lib/nydp/builtin/is_equal.rb +5 -0
  29. data/lib/nydp/builtin/less_than.rb +10 -0
  30. data/lib/nydp/builtin/millisecs.rb +7 -0
  31. data/lib/nydp/builtin/minus.rb +13 -0
  32. data/lib/nydp/builtin/plus.rb +28 -0
  33. data/lib/nydp/builtin/pre_compile.rb +5 -0
  34. data/lib/nydp/builtin/puts.rb +7 -0
  35. data/lib/nydp/builtin/quit.rb +5 -0
  36. data/lib/nydp/builtin/random_string.rb +11 -0
  37. data/lib/nydp/builtin/times.rb +13 -0
  38. data/lib/nydp/builtin/to_string.rb +12 -0
  39. data/lib/nydp/builtin/to_sym.rb +21 -0
  40. data/lib/nydp/builtin/vm_info.rb +13 -0
  41. data/lib/nydp/closure.rb +17 -0
  42. data/lib/nydp/compiler.rb +49 -0
  43. data/lib/nydp/cond.rb +56 -0
  44. data/lib/nydp/context_symbol.rb +22 -0
  45. data/lib/nydp/error.rb +4 -0
  46. data/lib/nydp/function_invocation.rb +52 -0
  47. data/lib/nydp/helper.rb +32 -0
  48. data/lib/nydp/interpreted_function.rb +79 -0
  49. data/lib/nydp/lexical_context.rb +38 -0
  50. data/lib/nydp/literal.rb +40 -0
  51. data/lib/nydp/pair.rb +112 -0
  52. data/lib/nydp/parser.rb +123 -0
  53. data/lib/nydp/string_atom.rb +24 -0
  54. data/lib/nydp/string_token.rb +21 -0
  55. data/lib/nydp/symbol.rb +47 -0
  56. data/lib/nydp/symbol_lookup.rb +43 -0
  57. data/lib/nydp/tokeniser.rb +80 -0
  58. data/lib/nydp/truth.rb +37 -0
  59. data/lib/nydp/version.rb +3 -0
  60. data/lib/nydp/vm.rb +76 -0
  61. data/nydp.gemspec +27 -0
  62. data/spec/boot_spec.rb +119 -0
  63. data/spec/embedded_spec.rb +106 -0
  64. data/spec/nypd_spec.rb +127 -0
  65. data/spec/pair_spec.rb +102 -0
  66. data/spec/parser_spec.rb +191 -0
  67. data/spec/spec_helper.rb +10 -0
  68. data/spec/symbol_spec.rb +32 -0
  69. metadata +176 -0
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ describe Nydp::Parser do
4
+
5
+ let(:ns) { { } }
6
+ let(:aa) { Nydp::Symbol.mk :aa, ns }
7
+ let(:a) { Nydp::Symbol.mk :a, ns }
8
+ let(:b) { Nydp::Symbol.mk :b, ns }
9
+ let(:c) { Nydp::Symbol.mk :c, ns }
10
+ let(:d) { Nydp::Symbol.mk :d, ns }
11
+ let(:zz) { Nydp::Symbol.mk :zz, ns }
12
+ let(:foo) { Nydp::Symbol.mk :foo, ns }
13
+ let(:bar) { Nydp::Symbol.mk :bar, ns }
14
+ let(:zab) { Nydp::Symbol.mk :zab, ns }
15
+ let(:quote) { Nydp::Symbol.mk :quote, ns }
16
+ let(:quasiquote) { Nydp::Symbol.mk :quasiquote, ns }
17
+ let(:unquote) { Nydp::Symbol.mk :unquote, ns }
18
+ let(:unquote_splicing) { Nydp::Symbol.mk :"unquote-splicing", ns }
19
+ let(:comment) { Nydp::Symbol.mk :comment, ns }
20
+ let(:dotsyn) { Nydp::Symbol.mk :"dot-syntax", ns }
21
+ let(:cocosyn) { Nydp::Symbol.mk :"colon-colon-syntax", ns }
22
+ let(:colosyn) { Nydp::Symbol.mk :"colon-syntax", ns }
23
+
24
+ def sym name
25
+ Nydp::Symbol.mk name.to_sym, ns
26
+ end
27
+
28
+ def parse_string txt, open_delim, close_delim
29
+ Nydp::Parser.new(ns).string(Nydp::Tokeniser.new(txt), open_delim, close_delim)
30
+ end
31
+
32
+ def pair_list xs, last=Nydp.NIL
33
+ Nydp::Pair.from_list xs, last
34
+ end
35
+
36
+ it "should parse empty string" do
37
+ expected = pair_list([sym('string-pieces'), Nydp::StringFragmentCloseToken.new('','$%')])
38
+ actual = parse_string "%", '$', /%/
39
+ expect(actual).to eq ''
40
+ end
41
+
42
+ it "should parse external text" do
43
+ actual = parse_string "a fluffy bunny!", 'EAT ', /!/
44
+ expect(actual) .to eq "a fluffy bunny"
45
+ expect(actual.inspect).to eq "EAT a fluffy bunny!"
46
+ end
47
+
48
+ it "should parse a string delimited by eof" do
49
+ expected = pair_list([sym('string-pieces'), Nydp::StringFragmentCloseToken.new('a fluffy bunny!','a fluffy bunny!')])
50
+ actual = parse_string "a fluffy bunny!", '', :eof
51
+ expect(actual) .to eq "a fluffy bunny!"
52
+ expect(actual.inspect).to eq "a fluffy bunny!"
53
+ end
54
+
55
+ it "should parse a string with embedded code, delimited by eof" do
56
+ x1 = sym('string-pieces')
57
+ x2 = Nydp::StringFragmentToken.new('a fluffy bunny! ',':a fluffy bunny! %%')
58
+ x3 = sym('expr')
59
+ x4 = Nydp::StringFragmentCloseToken.new(' a purple cow!',' a purple cow!')
60
+
61
+ expected = pair_list([x1,x2,x3,x4])
62
+ actual = parse_string "a fluffy bunny! %%expr a purple cow!", ':', :eof
63
+ expect(actual).to eq expected
64
+ end
65
+
66
+ it "should parse a string with embedded code containing a nested string, delimited by eof" do
67
+ n1 = sym(:foo)
68
+ n2 = sym(:bar)
69
+ n3 = 'an embedded bunny :)'
70
+ n4 = sym(:zop)
71
+
72
+ x1 = sym('string-pieces')
73
+ x2 = Nydp::StringFragmentToken.new('a fluffy bunny! ','------->a fluffy bunny! %%')
74
+ x3 = pair_list [n1, n2, n3, n4]
75
+ x4 = Nydp::StringFragmentCloseToken.new(' a purple cow!',' a purple cow!')
76
+
77
+ expected = pair_list([x1,x2,x3,x4])
78
+ actual = parse_string "a fluffy bunny! %%(foo bar \"an embedded bunny :)\" zop) a purple cow!", '------->', :eof
79
+ expect(actual).to eq expected
80
+ end
81
+
82
+ it "should parse a string with embedded code containing a nested string containing more embedded code, delimited by eof" do
83
+ e1 = sym(:describe)
84
+ e2 = sym(:bunny)
85
+
86
+ s1 = sym('string-pieces')
87
+ s2 = Nydp::StringFragmentToken.new('a rather ','"a rather %%')
88
+ s3 = pair_list [e1, e2]
89
+ s4 = Nydp::StringFragmentCloseToken.new(' bunny :)',' bunny :)"')
90
+
91
+ n1 = sym(:foo)
92
+ n2 = sym(:bar)
93
+ n3 = pair_list [s1, s2, s3, s4]
94
+ n4 = sym(:zop)
95
+
96
+ x1 = sym('string-pieces')
97
+ x2 = Nydp::StringFragmentToken.new('a fluffy bunny! ','------->a fluffy bunny! %%')
98
+ x3 = pair_list [n1, n2, n3, n4]
99
+ x4 = Nydp::StringFragmentCloseToken.new(' a purple cow!',' a purple cow!')
100
+
101
+ expected = pair_list([x1,x2,x3,x4])
102
+ actual = parse_string "a fluffy bunny! %%(foo bar \"a rather %%(describe bunny) bunny :)\" zop) a purple cow!", '------->', :eof
103
+ expect(actual).to eq expected
104
+ end
105
+
106
+ end
@@ -0,0 +1,127 @@
1
+ require 'spec_helper'
2
+
3
+ describe Nydp do
4
+ let(:root_ns) { { } }
5
+ let(:parser) { Nydp::Parser.new(root_ns) }
6
+ let(:vm) { Nydp::VM.new }
7
+
8
+ def sym name
9
+ Nydp::Symbol.mk name.to_sym, root_ns
10
+ end
11
+
12
+ def parse txt
13
+ tokens = Nydp::Tokeniser.new txt
14
+ expressions = []
15
+ expr = parser.expression(tokens)
16
+ while (expr != nil)
17
+ expressions << expr
18
+ expr = parser.expression(tokens)
19
+ end
20
+ expressions
21
+ end
22
+
23
+ def run txt
24
+ Nydp.setup root_ns
25
+ expressions = parse(txt)
26
+ result = nil
27
+ expressions.each do |expr|
28
+ result = Nydp.compile_and_eval vm, expr
29
+ end
30
+ result
31
+ end
32
+
33
+ it "should make a symbol from a string" do
34
+ expect(run '(sym "the-family")').to eq sym(:"the-family")
35
+ end
36
+
37
+ it "should sum integers" do
38
+ expect(run "(+ 1 2)").to eq 3
39
+ end
40
+
41
+ it "should add strings" do
42
+ expect(run '(+ "hello" " " "world")').to eq "hello world"
43
+ end
44
+
45
+ it "should add Pairs" do
46
+ expect(run "(+ '(a b) '(c d))").to eq Nydp::Pair.from_list([sym(:a), sym(:b), sym(:c), sym(:d)])
47
+ end
48
+
49
+ it "should add Pairs without recursing" do
50
+ alist = Nydp::Pair.from_list([sym(:a), sym(:a)])
51
+ blist = Nydp::Pair.from_list([sym(:b), sym(:b)])
52
+ clist = Nydp::Pair.from_list([sym(:c), sym(:c)])
53
+ dlist = Nydp::Pair.from_list([sym(:d), sym(:d)])
54
+ expect(run "(+ '((a a) (b b)) '((c c) (d d)))").to eq Nydp::Pair.from_list([alist, blist, clist, dlist])
55
+ end
56
+
57
+ it "should diff integers" do
58
+ expect(run "(- 144 121)").to eq 23
59
+ end
60
+
61
+ it "should multiply integers" do
62
+ expect(run "(* 7 11)").to eq 77
63
+ end
64
+
65
+ it "should convert items to strings" do
66
+ expect(run "(to-string 3.1415)").to eq "3.1415"
67
+ end
68
+
69
+ it "should compare integers" do
70
+ expect(run "(> 13 17)").to eq Nydp.NIL
71
+ expect(run "(> 29 23)").to eq Nydp.T
72
+ expect(run "(< 13 17)").to eq Nydp.T
73
+ expect(run "(< 29 23)").to eq Nydp.NIL
74
+ end
75
+
76
+ it "should execute an inline list function" do
77
+ expected = Nydp::Pair.from_list (1..3).to_a
78
+ expect(run "((fn a a) 1 2 3)").to eq expected
79
+ end
80
+
81
+ it "should execute an inline sum function" do
82
+ expect(run "((fn (a b) (+ a b)) 9 16)").to eq 25
83
+ end
84
+
85
+ it "should assign a function to a global variable and execute it" do
86
+ f1 = "(fn (a b) (+ a b))"
87
+ f2 = "(assign f1 #{f1})"
88
+ f3 = "(f1 36 64)"
89
+ result = run "#{f2} #{f3}"
90
+ expect(result).to eq 100
91
+ end
92
+
93
+ it "should call functions in a chain" do
94
+ f1 = "(fn (a b) (+ a b))"
95
+ f2 = "(assign f1 #{f1})"
96
+ f3 = "(fn (x y) (* x y))"
97
+ f4 = "(assign f3 #{f3})"
98
+ f5 = "(f1 (f3 6 6) (f3 8 8))"
99
+ result = run "#{f2} #{f4} #{f5}"
100
+ expect(result).to eq 100
101
+ end
102
+
103
+ it "should recurse without consuming extra memory" do
104
+ program = "(assign f1 (fn (x acc) (cond (< x 1) (vm-info) (f1 (- x 1) (+ x acc))))) (f1 1000)"
105
+ expected = parse "((contexts . 0) (instructions . 0) (args . 0))"
106
+ expect(run program).to eq expected.first
107
+ end
108
+
109
+ describe :cond do
110
+ it "should execute false conditionals" do
111
+ cond = "(cond (> 31 37) 'foo 'bar)"
112
+ expect(run cond).to eq sym(:bar)
113
+ end
114
+
115
+ it "should execute conditionals" do
116
+ cond = "(cond (> 37 31) 'foo 'bar)"
117
+ expect(run cond).to eq sym(:foo)
118
+ end
119
+ end
120
+
121
+ describe "eval" do
122
+ it "should eval the given expression and return the result" do
123
+ code = "(eval '(+ 2 (* 3 5)))"
124
+ expect(run code).to eq 17
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,102 @@
1
+ require "spec_helper"
2
+
3
+ describe Nydp::Pair do
4
+ let(:ns) { { } }
5
+ let(:a) { Nydp::Symbol.mk :a, ns }
6
+ let(:b) { Nydp::Symbol.mk :b, ns }
7
+ let(:c) { Nydp::Symbol.mk :c, ns }
8
+ let(:d) { Nydp::Symbol.mk :d, ns }
9
+ let(:foo) { Nydp::Symbol.mk :foo, ns }
10
+ let(:dot) { Nydp::Symbol.mk ".".to_sym, ns }
11
+
12
+ describe :== do
13
+ it "should be true for two empty lists" do
14
+ expect(Nydp::Pair.new(NIL, NIL)).to eq Nydp::Pair.new(NIL, NIL)
15
+ end
16
+
17
+ it "should be true for nested empty lists" do
18
+ e1 = Nydp::Pair.new(Nydp.NIL, Nydp.NIL)
19
+ e2 = Nydp::Pair.new(Nydp.NIL, Nydp.NIL)
20
+ e3 = Nydp::Pair.new(Nydp.NIL, Nydp.NIL)
21
+ e4 = Nydp::Pair.new(Nydp.NIL, Nydp.NIL)
22
+ expect(Nydp::Pair.new(e1, e2)).to eq Nydp::Pair.new(e3, e4)
23
+ end
24
+
25
+ it "should define #== to return true for an identical list" do
26
+ p1 = Nydp::Pair.from_list [:a, :b, :c, :d]
27
+ p2 = Nydp::Pair.from_list [:a, :b, :c, :d]
28
+ expect(p1).to eq p2
29
+ end
30
+
31
+ it "should define #== to return true for identical improper lists" do
32
+ p1 = Nydp::Pair.from_list [:a, :b, :c, :d], 4
33
+ p2 = Nydp::Pair.from_list [:a, :b, :c, :d], 4
34
+ expect(p1).to eq p2
35
+ end
36
+
37
+ it "should define #== to return false for a non-identical list" do
38
+ p1 = Nydp::Pair.from_list [:a, :b, :c, :d]
39
+ p2 = Nydp::Pair.from_list [:a, :b, :c, 22]
40
+ expect(p1).not_to eq p2
41
+ end
42
+
43
+ it "should define #== to return false for lists which differ only in their terminating element" do
44
+ p1 = Nydp::Pair.from_list [:a, :b, :c], :d
45
+ p2 = Nydp::Pair.from_list [:a, :b, :c], 22
46
+ expect(p1).not_to eq p2
47
+ end
48
+ end
49
+
50
+ it "should create a new pair" do
51
+ p = Nydp::Pair.mk :a, :b
52
+ expect(p.car).to eq :a
53
+ expect(p.cdr).to eq :b
54
+ end
55
+
56
+ it "should convert a ruby list" do
57
+ p = Nydp::Pair.from_list [:a, :b, :c, :d]
58
+ expect(p.car).to eq :a
59
+ p = p.cdr
60
+ expect(p.car).to eq :b
61
+ p = p.cdr
62
+ expect(p.car).to eq :c
63
+ p = p.cdr
64
+ expect(p.car).to eq :d
65
+ p = p.cdr
66
+ expect(p.car).to eq Nydp.NIL
67
+ expect(p.cdr).to eq Nydp.NIL
68
+ p = p.cdr
69
+ expect(p.car).to eq Nydp.NIL
70
+ expect(p.cdr).to eq Nydp.NIL
71
+ end
72
+
73
+ it "should have size zero when empty" do
74
+ expect(Nydp::Pair.from_list([]).size).to eq 0
75
+ end
76
+
77
+ it "should report the number of elements is contains" do
78
+ expect(Nydp::Pair.from_list([:a, :b, :c]).size).to eq 3
79
+ end
80
+
81
+ it "should report the number of elements in an improper list, excluding last item" do
82
+ expect(Nydp::Pair.from_list([:a, :b, :c, :d], :foo).size).to eq 4
83
+ end
84
+
85
+ it "should represent itself as a string" do
86
+ expect(Nydp::Pair.from_list([a, b, c, d]).to_s).to eq "(a b c d)"
87
+ end
88
+
89
+ it "should represent an improper list as a string" do
90
+ expect(Nydp::Pair.from_list([a, b, c, d], foo).to_s).to eq "(a b c d . foo)"
91
+ end
92
+
93
+ it "should parse a list" do
94
+ p = Nydp::Pair.from_list [a, b, c, d]
95
+ expect(Nydp::Pair.parse_list([a, b, c, d])).to eq p
96
+ end
97
+
98
+ it "should parse a list" do
99
+ p = Nydp::Pair.from_list [a, b, c, d], foo
100
+ expect(Nydp::Pair.parse_list([a, b, c, d, dot, foo])).to eq p
101
+ end
102
+ end
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+
3
+ describe Nydp::Parser do
4
+
5
+ let(:ns) { { } }
6
+ let(:aa) { Nydp::Symbol.mk :aa, ns }
7
+ let(:a) { Nydp::Symbol.mk :a, ns }
8
+ let(:b) { Nydp::Symbol.mk :b, ns }
9
+ let(:c) { Nydp::Symbol.mk :c, ns }
10
+ let(:d) { Nydp::Symbol.mk :d, ns }
11
+ let(:zz) { Nydp::Symbol.mk :zz, ns }
12
+ let(:foo) { Nydp::Symbol.mk :foo, ns }
13
+ let(:bar) { Nydp::Symbol.mk :bar, ns }
14
+ let(:zab) { Nydp::Symbol.mk :zab, ns }
15
+ let(:quote) { Nydp::Symbol.mk :quote, ns }
16
+ let(:quasiquote) { Nydp::Symbol.mk :quasiquote, ns }
17
+ let(:unquote) { Nydp::Symbol.mk :unquote, ns }
18
+ let(:unquote_splicing) { Nydp::Symbol.mk :"unquote-splicing", ns }
19
+ let(:comment) { Nydp::Symbol.mk :comment, ns }
20
+ let(:dotsyn) { Nydp::Symbol.mk :"dot-syntax", ns }
21
+ let(:cocosyn) { Nydp::Symbol.mk :"colon-colon-syntax", ns }
22
+ let(:colosyn) { Nydp::Symbol.mk :"colon-syntax", ns }
23
+
24
+ def sym name
25
+ Nydp::Symbol.mk name.to_sym, ns
26
+ end
27
+
28
+ def parse txt
29
+ Nydp::Parser.new(ns).expression(Nydp::Tokeniser.new txt)
30
+ end
31
+
32
+ def pair_list xs, last=Nydp.NIL
33
+ Nydp::Pair.from_list xs, last
34
+ end
35
+
36
+ it "should return a stream of tokens" do
37
+ t = Nydp::Tokeniser.new ""
38
+ expect(t.next_token).to eq nil
39
+ end
40
+
41
+ it "should return another stream of tokens" do
42
+ t = Nydp::Tokeniser.new "(a b c 1 2 3)"
43
+ tt = []
44
+ tok = t.next_token
45
+ while tok
46
+ tt << tok
47
+ tok = t.next_token
48
+ end
49
+ expect(tt).to eq [[:left_paren, ""], [:symbol, "a"], [:symbol, "b"], [:symbol, "c"], [:number, 1.0], [:number, 2.0], [:number, 3.0], [:right_paren]]
50
+ end
51
+
52
+ it "should parse an empty expression" do
53
+ expect(parse "").to be_nil
54
+ end
55
+
56
+ it "should parse an empty expression" do
57
+ expect(parse "()").to eq Nydp.NIL
58
+ end
59
+
60
+ it "should parse a lisp expression" do
61
+ expect(parse "(foo bar)").to eq pair_list([foo, bar])
62
+ end
63
+
64
+ it "should parse numbers expression" do
65
+ expect(parse "(1 2 3)").to eq pair_list([1, 2, 3])
66
+ end
67
+
68
+ it "should parse an improper list" do
69
+ expect(parse "(1 2 3 . 4)").to eq pair_list([1, 2, 3], 4)
70
+ end
71
+
72
+ it "should parse a string" do
73
+ s1 = sym 'string-pieces'
74
+ s2 = Nydp::StringFragmentCloseToken.new "hello there", '"hello there"'
75
+
76
+ x1 = 1
77
+ x2 = "hello there"
78
+ x3 = 3
79
+
80
+ expected = pair_list [x1, x2, x3]
81
+
82
+ expect(parse '(1 "hello there" 3)').to eq expected
83
+ end
84
+
85
+ it "should parse a string" do
86
+ x1 = sym 'join'
87
+ x2 = " - "
88
+ x3 = 1
89
+ x4 = 2
90
+ x5 = 3
91
+
92
+ expected = pair_list [x1, x2, x3, x4, x5]
93
+
94
+ expect(parse '(join " - " 1 2 3)').to eq expected
95
+ end
96
+
97
+ it "should not get confused by embedded lisp in a string" do
98
+ s1 = sym 'string-pieces'
99
+ s2 = Nydp::StringFragmentCloseToken.new "hello (1 2 3) there", '"hello (1 2 3) there"'
100
+
101
+ x1 = 1
102
+ x2 = "hello (1 2 3) there"
103
+ x3 = 3
104
+
105
+ expected = pair_list [x1, x2, x3]
106
+
107
+ expect(parse '(1 "hello (1 2 3) there" 3)').to eq expected
108
+ end
109
+
110
+ it "should handle escaped quotes inside a string" do
111
+ s1 = sym 'string-pieces'
112
+ s2 = Nydp::StringFragmentCloseToken.new "hello there \"jimmy\"", '"hello there \"jimmy\""'
113
+
114
+ x1 = 1
115
+ x2 = "hello there \"jimmy\""
116
+ x3 = 3
117
+
118
+ expected = pair_list [x1, x2, x3]
119
+
120
+ expect(parse '(1 "hello there \"jimmy\"" 3)').to eq expected
121
+ end
122
+
123
+ it "should parse a plain symbol" do
124
+ expect(parse "foo").to eq foo
125
+ end
126
+
127
+ it "should parse a dotted symbol" do
128
+ expect(parse "foo.bar").to eq pair_list([dotsyn, foo, bar])
129
+ end
130
+
131
+ it "should parse a colon-colon symbol" do
132
+ expect(parse "foo::bar").to eq pair_list([cocosyn, foo, bar])
133
+ end
134
+
135
+ it "should parse a colon-symbol within a colon-colon within a dotted symbol" do
136
+ expect(parse "aa.foo:foo::bar:bar.zz").to eq pair_list([dotsyn, aa, pair_list([cocosyn, pair_list([colosyn, foo, foo]), pair_list([colosyn, bar, bar])]), zz])
137
+ end
138
+
139
+ it "should quote symbols" do
140
+ expect(parse "'foo").to eq pair_list([quote, foo])
141
+ end
142
+
143
+ it "should quote-unquote symbols" do
144
+ expect(parse "',foo").to eq pair_list([quote, pair_list([unquote, foo])])
145
+ end
146
+
147
+ it "should quote lists" do
148
+ expect(parse "'(foo)").to eq pair_list([quote, pair_list([foo])])
149
+ end
150
+
151
+ it "should unquote atoms" do
152
+ expect(parse ",foo").to eq pair_list([unquote, foo])
153
+ end
154
+
155
+ it "should unquote lists" do
156
+ expect(parse ",(bar)").to eq pair_list([unquote, pair_list([bar])])
157
+ end
158
+
159
+ it "should unquote-splicing atoms" do
160
+ expect(parse ",@foo").to eq pair_list([unquote_splicing, foo])
161
+ end
162
+
163
+ it "should unquote-splicing lists" do
164
+ expect(parse ",@(bar)").to eq pair_list([unquote_splicing, pair_list([bar])])
165
+ end
166
+
167
+ it "should quasiquote atoms" do
168
+ expect(parse "`foo").to eq pair_list([quasiquote, foo])
169
+ end
170
+
171
+ it "should quasiquote lists" do
172
+ expect(parse "`(bar)").to eq pair_list([quasiquote, pair_list([bar])])
173
+ end
174
+
175
+ it "should parse nested lists" do
176
+ expect(parse "(a b (c) d)").to eq pair_list([a, b, pair_list([c]), d])
177
+ end
178
+
179
+ it "should even parse comments" do
180
+ txt = "(def foo (bar)
181
+ ; here's a comment
182
+ (zab))
183
+ "
184
+ c1 = pair_list([comment, "here's a comment"])
185
+ fbar = pair_list([bar])
186
+ fzab = pair_list([Nydp::Symbol.mk(:zab, ns)])
187
+ fdef = Nydp::Symbol.mk(:def, ns)
188
+ expr = pair_list([fdef, foo, fbar, c1, fzab])
189
+ expect(parse txt).to eq expr
190
+ end
191
+ end