nydp 0.0.12 → 0.1.0
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.
- checksums.yaml +4 -4
- data/lib/lisp/core-01-precompile.nydp +1 -1
- data/lib/lisp/core-02-utils.nydp +3 -5
- data/lib/lisp/core-03-syntax.nydp +0 -2
- data/lib/lisp/core-04-utils.nydp +26 -7
- data/lib/lisp/core-05-test-runner.nydp +1 -0
- data/lib/lisp/core-07-prefix-list.nydp +26 -0
- data/lib/lisp/tests/boot-tests.nydp +29 -0
- data/lib/lisp/tests/each-tests.nydp +5 -0
- data/lib/lisp/tests/foundation-test.nydp +10 -0
- data/lib/lisp/tests/parser-tests.nydp +32 -0
- data/lib/lisp/tests/syntax-tests.nydp +16 -0
- data/lib/nydp/builtin/hash.rb +16 -9
- data/lib/nydp/builtin/parse_in_string.rb +5 -1
- data/lib/nydp/lexical_context.rb +1 -5
- data/lib/nydp/parser.rb +4 -1
- data/lib/nydp/version.rb +1 -1
- data/spec/hash_spec.rb +54 -3
- data/spec/parser_spec.rb +5 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebd833948c836f583d77adc0028df3838bd30ed3
|
4
|
+
data.tar.gz: 85458c42aa0466e0802771a3a62b3593cc26d25d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b0981f75b8ecf590694377973f0bc9b013250cd54ad0278d0b79cfba43cc6c8f870f4842238e1df43448fdcfad15a2cb7634c2b30c141b60dbb1bca87a610ee
|
7
|
+
data.tar.gz: cd44bec0ad3c3fe9b1bfc8c38937ac5850de8529b0f74004378bbbae3dbe376d9e39c02ea5db3c1383888b26bcf8f6fea34fc50adf634a1e8a3ef134587d598a
|
data/lib/lisp/core-02-utils.nydp
CHANGED
data/lib/lisp/core-04-utils.nydp
CHANGED
@@ -1,10 +1,3 @@
|
|
1
|
-
; -*- lisp -*-
|
2
|
-
|
3
|
-
(def each (f acc things)
|
4
|
-
(if things
|
5
|
-
(each f (f acc (car things)) (cdr things))
|
6
|
-
acc))
|
7
|
-
|
8
1
|
(def eachr (f things)
|
9
2
|
(when things
|
10
3
|
(eachr f (cdr things))
|
@@ -46,6 +39,15 @@
|
|
46
39
|
(def string-pieces pieces
|
47
40
|
(joinstr "" pieces))
|
48
41
|
|
42
|
+
(def detect (f things)
|
43
|
+
(if (pair? things)
|
44
|
+
(let it (car things)
|
45
|
+
(or
|
46
|
+
(and (f it) it)
|
47
|
+
(detect f (cdr things))))
|
48
|
+
(f things)
|
49
|
+
things))
|
50
|
+
|
49
51
|
(def nth (n things)
|
50
52
|
(if (eq? n 0)
|
51
53
|
(car things)
|
@@ -122,3 +124,20 @@
|
|
122
124
|
`(map (fn (,x) ,expr) ,things))
|
123
125
|
|
124
126
|
(def empty? (things) (eq? (len things) 0))
|
127
|
+
|
128
|
+
(mac each (var things code)
|
129
|
+
(w/uniq (xs c)
|
130
|
+
`((rfn ,c (,xs)
|
131
|
+
(if (pair? ,xs)
|
132
|
+
(do
|
133
|
+
(let ,var (car ,xs) ,code)
|
134
|
+
(,c (cdr ,xs)))))
|
135
|
+
,things)))
|
136
|
+
|
137
|
+
(def reduce (f things)
|
138
|
+
((rfn rd (acc list)
|
139
|
+
(if (pair? list)
|
140
|
+
(rd (f acc (car list))
|
141
|
+
(cdr list))
|
142
|
+
acc))
|
143
|
+
(car things) (cdr things)))
|
@@ -21,6 +21,7 @@
|
|
21
21
|
(def execute-test (desc test passf failf verbose)
|
22
22
|
(if (eq? 'suite (car test))
|
23
23
|
(execute-tests (+ desc " - " (cadr test)) (cddr test) passf failf verbose)
|
24
|
+
(!eq? 'comment (car test))
|
24
25
|
(execute-single-test desc test passf failf verbose)))
|
25
26
|
|
26
27
|
(def execute-single-test (desc test passf failf verbose)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
(assign prefix-list-prefixes ())
|
3
|
+
|
4
|
+
(def prefix-match-fn (txt)
|
5
|
+
(fn (rule) (string-match txt (car rule))))
|
6
|
+
|
7
|
+
(def find-prefix-rule (prefix)
|
8
|
+
(cdr:detect (prefix-match-fn prefix)
|
9
|
+
prefix-list-prefixes))
|
10
|
+
|
11
|
+
(mac prefix-list (prefix list)
|
12
|
+
(let handler (find-prefix-rule prefix)
|
13
|
+
(and handler (handler prefix list))))
|
14
|
+
|
15
|
+
(mac define-prefix-list-macro (regex prefix-var list-var . body)
|
16
|
+
`(push (cons ,regex (fn (,prefix-var ,list-var) ,@body))
|
17
|
+
prefix-list-prefixes))
|
18
|
+
|
19
|
+
;;
|
20
|
+
;; so you can write (map λa(upcase a.name) people)
|
21
|
+
;;
|
22
|
+
;; instead of (map (fn (a) (upcase a.name)) people)
|
23
|
+
;;
|
24
|
+
(define-prefix-list-macro "^λ.+" vars expr
|
25
|
+
(let var-list (map sym (cdr:string-split vars))
|
26
|
+
`(fn ,var-list ,expr)))
|
@@ -138,6 +138,35 @@
|
|
138
138
|
(mapx '(1 2 3 4) n (* n 2))
|
139
139
|
(2 4 6 8))))
|
140
140
|
|
141
|
+
(suite "reduce"
|
142
|
+
("it applies a function cumulatively over a list"
|
143
|
+
(reduce + '(1 2 3))
|
144
|
+
6))
|
145
|
+
|
146
|
+
(suite "detect"
|
147
|
+
("returns first matching item in a list"
|
148
|
+
(detect (fn (x) (eq? (len x) 2))
|
149
|
+
(list "foo" "bar" "xx" "pp"))
|
150
|
+
"xx")
|
151
|
+
|
152
|
+
("returns nil when nothing matches"
|
153
|
+
(detect (fn (x) (eq? (len x) 20))
|
154
|
+
(list "foo" "bar" "xx" "pp"))
|
155
|
+
nil)
|
156
|
+
|
157
|
+
;; kind of pointless
|
158
|
+
("returns nil if nil is the matching item"
|
159
|
+
(detect no (list "foo" "bar" nil "pp"))
|
160
|
+
nil)
|
161
|
+
|
162
|
+
("returns item if it's an atom and matches"
|
163
|
+
(detect (fn (x) (eq? (len x) 2)) "zz")
|
164
|
+
"zz")
|
165
|
+
|
166
|
+
("returns nil if it's an atom and doesn't match"
|
167
|
+
(detect (fn (x) (eq? (len x) 20))
|
168
|
+
"zz")
|
169
|
+
nil))
|
141
170
|
|
142
171
|
(suite "pre-compile"
|
143
172
|
(suite "bang-syntax"
|
@@ -25,6 +25,11 @@
|
|
25
25
|
(list m.match m.captures))
|
26
26
|
("and" nil))
|
27
27
|
|
28
|
+
("no match with regexp"
|
29
|
+
(let m (string-match "a and b and c and d" "not-in-string")
|
30
|
+
(list m.match m.captures))
|
31
|
+
(nil nil))
|
32
|
+
|
28
33
|
("match with regexp and capturing groups"
|
29
34
|
(let m (string-match " foo\b bar" "(^\\s+)")
|
30
35
|
(list m.match m.captures))
|
@@ -92,6 +97,11 @@
|
|
92
97
|
(pre-compile '(= this 'that))
|
93
98
|
(assign this 'that)))
|
94
99
|
|
100
|
+
(suite "argument default value"
|
101
|
+
("is nil"
|
102
|
+
( (fn (x y z) (list x y (car z))) 'a 'b )
|
103
|
+
(a b nil)))
|
104
|
+
|
95
105
|
(suite "hash"
|
96
106
|
("hash-lookup"
|
97
107
|
(pre-compile 'a.b.c)
|
@@ -12,6 +12,27 @@
|
|
12
12
|
(parse "{foo bar 1 2 3}")
|
13
13
|
((brace-list foo bar 1 2 3))))
|
14
14
|
|
15
|
+
(suite "prefix-list"
|
16
|
+
("parse quasiquote"
|
17
|
+
(parse "`(1 2 3)")
|
18
|
+
((quasiquote (1 2 3))))
|
19
|
+
|
20
|
+
("parse unquote unquote-splicing"
|
21
|
+
(parse ",,@(1 2 3)")
|
22
|
+
((unquote (unquote-splicing (1 2 3)))))
|
23
|
+
|
24
|
+
("parse unquote"
|
25
|
+
(parse ",(1 2 3)")
|
26
|
+
((unquote (1 2 3))))
|
27
|
+
|
28
|
+
("parse custom prefix-lists"
|
29
|
+
(parse "x(1 2 3)")
|
30
|
+
((prefix-list "x" (1 2 3))))
|
31
|
+
|
32
|
+
("parse custom prefix-lists with a special-syntax prefix"
|
33
|
+
(parse "x.y(1 2 3)")
|
34
|
+
((prefix-list "x.y" (1 2 3)))))
|
35
|
+
|
15
36
|
(suite "parse"
|
16
37
|
("parses an empty symbol"
|
17
38
|
(parse "||")
|
@@ -21,6 +42,14 @@
|
|
21
42
|
(parse "this:that")
|
22
43
|
((colon-syntax this that)) )
|
23
44
|
|
45
|
+
("parses a percent-syntax symbol"
|
46
|
+
(parse "this%that")
|
47
|
+
((percent-syntax this that)) )
|
48
|
+
|
49
|
+
("parses a percent-prefix-syntax symbol"
|
50
|
+
(parse "%this-and-that")
|
51
|
+
((percent-syntax || this-and-that)) )
|
52
|
+
|
24
53
|
("parses a dot-syntax symbol"
|
25
54
|
(parse "this.that.zozo")
|
26
55
|
((dot-syntax this that zozo)) )
|
@@ -74,4 +103,7 @@
|
|
74
103
|
(len (parse-in-string (joinstr "" (list "hello " '~ " world"))))
|
75
104
|
13)
|
76
105
|
|
106
|
+
("reports parse errors gracefully"
|
107
|
+
(on-err "CAUGHT: ~err" (parse-in-string (joinstr "" "blah ~~(\"stri...")))
|
108
|
+
"CAUGHT: parse error: \"unterminated string\" in\n blah ~~(\"stri..." )
|
77
109
|
)))
|
@@ -0,0 +1,16 @@
|
|
1
|
+
(register-test
|
2
|
+
'(suite "syntax tests"
|
3
|
+
(suite "lambda shortcut"
|
4
|
+
("one argument"
|
5
|
+
(map λa(len a.name)
|
6
|
+
(list { name "bob" } { name "willy" } { name "pteradactyl" }))
|
7
|
+
(3 5 11))
|
8
|
+
|
9
|
+
("with two args"
|
10
|
+
(reduce λxy(joinstr ":" x y)
|
11
|
+
'(a b c d e f))
|
12
|
+
"a:b:c:d:e:f")
|
13
|
+
|
14
|
+
("with two args, to be sure"
|
15
|
+
(λpq(+ p (* p q)) 3 5)
|
16
|
+
18))))
|
data/lib/nydp/builtin/hash.rb
CHANGED
@@ -12,20 +12,27 @@ class Nydp::Builtin::HashGet
|
|
12
12
|
attr_accessor :ns
|
13
13
|
def initialize ns ; @ns = ns; end
|
14
14
|
def builtin_invoke vm, args
|
15
|
-
|
15
|
+
hsh = args.car
|
16
16
|
key = args.cdr.car
|
17
|
-
case
|
17
|
+
case hsh
|
18
18
|
when Nydp::Hash
|
19
|
-
vm.push_arg(
|
19
|
+
vm.push_arg(hsh[key] || Nydp.NIL)
|
20
20
|
when NilClass, Nydp.NIL
|
21
21
|
vm.push_arg Nydp.NIL
|
22
22
|
else
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
v = hsh.respond_to?(:[]) ? hsh[n2r key] : ruby_call(hsh, key)
|
24
|
+
vm.push_arg(r2n v, ns)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def ruby_call obj, method_name
|
29
|
+
if obj.respond_to? :_nydp_safe_methods
|
30
|
+
m = n2r(method_name).to_s.to_sym
|
31
|
+
allowed = obj._nydp_safe_methods
|
32
|
+
|
33
|
+
obj.send n2r(m) if allowed.include?(m)
|
34
|
+
else
|
35
|
+
raise "hash-get: Not a hash: #{obj.class.name}"
|
29
36
|
end
|
30
37
|
end
|
31
38
|
end
|
@@ -6,8 +6,12 @@ class Nydp::Builtin::ParseInString
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def builtin_invoke vm, args
|
9
|
-
|
9
|
+
parsable = args.car.to_s
|
10
|
+
tokens = Nydp::Tokeniser.new Nydp::StringReader.new parsable
|
10
11
|
expr = @parser.string(tokens, "", :eof)
|
11
12
|
vm.push_arg expr
|
13
|
+
rescue Exception => e
|
14
|
+
new_msg = "parse error: #{e.message.inspect} in\n#{Nydp.indent_text parsable}"
|
15
|
+
raise Nydp::Error.new new_msg
|
12
16
|
end
|
13
17
|
end
|
data/lib/nydp/lexical_context.rb
CHANGED
data/lib/nydp/parser.rb
CHANGED
@@ -31,7 +31,8 @@ module Nydp
|
|
31
31
|
when /^(.*),@$/
|
32
32
|
prefix_list $1, Pair.from_list([sym(:"unquote-splicing"), list])
|
33
33
|
else
|
34
|
-
|
34
|
+
pfx = Nydp::StringAtom.new prefix
|
35
|
+
Pair.from_list([sym(:"prefix-list"), pfx, list])
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
@@ -41,6 +42,7 @@ module Nydp
|
|
41
42
|
|
42
43
|
SYMBOL_OPERATORS =
|
43
44
|
[
|
45
|
+
[ /%/, "percent-syntax" ],
|
44
46
|
[ /\!/, "bang-syntax" ],
|
45
47
|
[ /&/, "ampersand-syntax" ],
|
46
48
|
[ /\./, "dot-syntax" ],
|
@@ -119,6 +121,7 @@ module Nydp
|
|
119
121
|
def string token_stream, open_delimiter, close_delimiter
|
120
122
|
fragments = [sym(:"string-pieces")]
|
121
123
|
string_token = token_stream.next_string_fragment(open_delimiter, close_delimiter, INTERPOLATION_SIGN, INTERPOLATION_ESCAPES)
|
124
|
+
raise "unterminated string" if string_token.nil?
|
122
125
|
fragments << Nydp::StringAtom.new(string_token.string, string_token)
|
123
126
|
while !(string_token.is_a? StringFragmentCloseToken)
|
124
127
|
fragments << expression(token_stream)
|
data/lib/nydp/version.rb
CHANGED
data/spec/hash_spec.rb
CHANGED
@@ -2,6 +2,19 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Nydp::Hash do
|
4
4
|
|
5
|
+
class TestThing
|
6
|
+
attr_accessor :a, :b, :c
|
7
|
+
def initialize a, b, c
|
8
|
+
@a, @b, @c = a, b, c
|
9
|
+
end
|
10
|
+
|
11
|
+
def inspect
|
12
|
+
"(TestThing #{a.inspect} #{b.inspect})"
|
13
|
+
end
|
14
|
+
|
15
|
+
def _nydp_safe_methods ; %i{ a b } ; end
|
16
|
+
end
|
17
|
+
|
5
18
|
let(:vm) { Nydp::VM.new }
|
6
19
|
|
7
20
|
describe "#to_ruby" do
|
@@ -181,6 +194,44 @@ describe Nydp::Hash do
|
|
181
194
|
end
|
182
195
|
end
|
183
196
|
|
197
|
+
describe "friendly non-hashes" do
|
198
|
+
let(:ahash) { TestThing.new 123, "hello there", "private" }
|
199
|
+
|
200
|
+
describe "hash get" do
|
201
|
+
it "returns a plain number" do
|
202
|
+
k = Nydp::Symbol.mk "a", ns
|
203
|
+
args = [ ahash, k ]
|
204
|
+
|
205
|
+
Nydp::Builtin::HashGet.new(ns).invoke vm, pair_list(args)
|
206
|
+
expect(vm.pop_arg).to eq 123
|
207
|
+
end
|
208
|
+
|
209
|
+
it "converts ruby value to nydp value" do
|
210
|
+
k = Nydp::Symbol.mk "b", ns
|
211
|
+
args = [ ahash, k ]
|
212
|
+
|
213
|
+
Nydp::Builtin::HashGet.new(ns).invoke vm, pair_list(args)
|
214
|
+
expect(vm.pop_arg).to eq Nydp::StringAtom.new("hello there")
|
215
|
+
end
|
216
|
+
|
217
|
+
it "converts string keys to method names" do
|
218
|
+
k = Nydp::StringAtom.new "b"
|
219
|
+
args = [ ahash, k ]
|
220
|
+
|
221
|
+
Nydp::Builtin::HashGet.new(ns).invoke vm, pair_list(args)
|
222
|
+
expect(vm.pop_arg).to eq Nydp::StringAtom.new("hello there")
|
223
|
+
end
|
224
|
+
|
225
|
+
it "returns nil for unavailable methods" do
|
226
|
+
k = Nydp::Symbol.mk "c", ns
|
227
|
+
args = [ ahash, k ]
|
228
|
+
|
229
|
+
Nydp::Builtin::HashGet.new(ns).invoke vm, pair_list(args)
|
230
|
+
expect(vm.pop_arg).to eq Nydp.NIL
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
184
235
|
describe "non-hash" do
|
185
236
|
let(:ahash) { Nydp::StringAtom.new "this here ain't no hash, hombre" }
|
186
237
|
|
@@ -206,8 +257,8 @@ raised
|
|
206
257
|
|
207
258
|
describe "hash get" do
|
208
259
|
it "converts ruby value to nydp value" do
|
209
|
-
k
|
210
|
-
args
|
260
|
+
k = Nydp::Symbol.mk "keysym", ns
|
261
|
+
args = [ ahash, k ]
|
211
262
|
|
212
263
|
begin
|
213
264
|
Nydp::Builtin::HashGet.new(ns).invoke vm, pair_list(args)
|
@@ -215,7 +266,7 @@ raised
|
|
215
266
|
error = e
|
216
267
|
end
|
217
268
|
|
218
|
-
expect(error.message.gsub(/at \/.*:in `
|
269
|
+
expect(error.message.gsub(/at \/.*:in `ruby_call'/, '<error info>')).to eq "Called builtin/hash-get
|
219
270
|
with args (\"this here ain't no hash, hombre\" keysym)
|
220
271
|
raised
|
221
272
|
hash-get: Not a hash: Nydp::StringAtom
|
data/spec/parser_spec.rb
CHANGED
@@ -13,6 +13,7 @@ describe Nydp::Parser do
|
|
13
13
|
let(:quote) { Nydp::Symbol.mk :quote, ns }
|
14
14
|
let(:quasiquote) { Nydp::Symbol.mk :quasiquote, ns }
|
15
15
|
let(:unquote) { Nydp::Symbol.mk :unquote, ns }
|
16
|
+
let(:prefix_list) { Nydp::Symbol.mk :"prefix-list", ns }
|
16
17
|
let(:unquote_splicing) { Nydp::Symbol.mk :"unquote-splicing", ns }
|
17
18
|
let(:comment) { Nydp::Symbol.mk :comment, ns }
|
18
19
|
let(:dotsyn) { Nydp::Symbol.mk :"dot-syntax", ns }
|
@@ -214,6 +215,10 @@ describe Nydp::Parser do
|
|
214
215
|
expect(parse ",(bar)").to eq pair_list([unquote, pair_list([bar])])
|
215
216
|
end
|
216
217
|
|
218
|
+
it "retains otherwise unidentified list prefixes" do
|
219
|
+
expect(parse "%wong(bar)").to eq pair_list([prefix_list, "%wong", pair_list([bar])])
|
220
|
+
end
|
221
|
+
|
217
222
|
it "should do some complicated unquote stuff with lists" do
|
218
223
|
expect(parse("`(a b `(c d ,(+ 1 2) ,,(+ 3 4)))").inspect).to eq "(quasiquote (a b (quasiquote (c d (unquote (+ 1 2)) (unquote (unquote (+ 3 4)))))))"
|
219
224
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nydp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Conan Dalton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09
|
11
|
+
date: 2015-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -91,13 +91,16 @@ files:
|
|
91
91
|
- lib/lisp/core-04-utils.nydp
|
92
92
|
- lib/lisp/core-05-test-runner.nydp
|
93
93
|
- lib/lisp/core-06-benchmarking.nydp
|
94
|
+
- lib/lisp/core-07-prefix-list.nydp
|
94
95
|
- lib/lisp/tests/boot-tests.nydp
|
95
96
|
- lib/lisp/tests/builtin-tests.nydp
|
96
97
|
- lib/lisp/tests/dynamic-scope-test.nydp
|
98
|
+
- lib/lisp/tests/each-tests.nydp
|
97
99
|
- lib/lisp/tests/error-tests.nydp
|
98
100
|
- lib/lisp/tests/foundation-test.nydp
|
99
101
|
- lib/lisp/tests/invocation-tests.nydp
|
100
102
|
- lib/lisp/tests/parser-tests.nydp
|
103
|
+
- lib/lisp/tests/syntax-tests.nydp
|
101
104
|
- lib/nydp.rb
|
102
105
|
- lib/nydp/assignment.rb
|
103
106
|
- lib/nydp/builtin.rb
|