nydp 0.0.12 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|