nydp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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