nydp 0.3.0 → 0.4.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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.zeiger.yml +28 -0
  3. data/lib/lisp/core-000.nydp +1 -1
  4. data/lib/lisp/core-015-documentation.nydp +6 -9
  5. data/lib/lisp/core-017-builtin-dox.nydp +33 -0
  6. data/lib/lisp/core-025-warnings.nydp +15 -0
  7. data/lib/lisp/core-030-syntax.nydp +38 -2
  8. data/lib/lisp/core-035-flow-control.nydp +2 -2
  9. data/lib/lisp/core-037-list-utils.nydp +7 -5
  10. data/lib/lisp/core-040-utils.nydp +15 -4
  11. data/lib/lisp/core-043-list-utils.nydp +1 -0
  12. data/lib/lisp/core-045-dox-utils.nydp +6 -0
  13. data/lib/lisp/core-050-test-runner.nydp +9 -9
  14. data/lib/lisp/core-070-prefix-list.nydp +2 -2
  15. data/lib/lisp/core-090-hook.nydp +24 -0
  16. data/lib/lisp/core-100-utils.nydp +38 -10
  17. data/lib/lisp/tests/ampersand-syntax-examples.nydp +26 -0
  18. data/lib/lisp/tests/boot-tests.nydp +1 -1
  19. data/lib/lisp/tests/collect-tests.nydp +4 -0
  20. data/lib/lisp/tests/destructuring-examples.nydp +18 -1
  21. data/lib/lisp/tests/fill-bucket-examples.nydp +46 -2
  22. data/lib/lisp/tests/floor-examples.nydp +58 -0
  23. data/lib/lisp/tests/k-examples.nydp +5 -0
  24. data/lib/lisp/tests/power-examples.nydp +16 -0
  25. data/lib/lisp/tests/string-tests.nydp +8 -0
  26. data/lib/lisp/tests/syntax-tests.nydp +6 -0
  27. data/lib/lisp/tests/zip-examples.nydp +16 -0
  28. data/lib/nydp.rb +6 -2
  29. data/lib/nydp/assignment.rb +1 -2
  30. data/lib/nydp/builtin/ensuring.rb +1 -2
  31. data/lib/nydp/builtin/greater_than.rb +2 -2
  32. data/lib/nydp/builtin/handle_error.rb +1 -2
  33. data/lib/nydp/builtin/less_than.rb +2 -2
  34. data/lib/nydp/builtin/math_ceiling.rb +7 -0
  35. data/lib/nydp/builtin/math_floor.rb +7 -0
  36. data/lib/nydp/builtin/math_power.rb +7 -0
  37. data/lib/nydp/builtin/math_round.rb +7 -0
  38. data/lib/nydp/builtin/parse.rb +2 -2
  39. data/lib/nydp/builtin/parse_in_string.rb +3 -3
  40. data/lib/nydp/builtin/pre_compile.rb +0 -1
  41. data/lib/nydp/compiler.rb +1 -1
  42. data/lib/nydp/cond.rb +3 -6
  43. data/lib/nydp/context_symbol.rb +40 -32
  44. data/lib/nydp/core.rb +8 -2
  45. data/lib/nydp/function_invocation.rb +3 -5
  46. data/lib/nydp/image_store.rb +21 -0
  47. data/lib/nydp/interpreted_function.rb +8 -12
  48. data/lib/nydp/lexical_context_builder.rb +19 -35
  49. data/lib/nydp/pair.rb +2 -1
  50. data/lib/nydp/parser.rb +4 -0
  51. data/lib/nydp/plugin.rb +15 -8
  52. data/lib/nydp/runner.rb +3 -3
  53. data/lib/nydp/symbol.rb +3 -1
  54. data/lib/nydp/symbol_lookup.rb +2 -2
  55. data/lib/nydp/truth.rb +2 -2
  56. data/lib/nydp/version.rb +1 -1
  57. data/lib/nydp/vm.rb +47 -27
  58. data/spec/date_spec.rb +2 -2
  59. data/spec/embedded_spec.rb +16 -16
  60. data/spec/error_spec.rb +1 -1
  61. data/spec/nydp_spec.rb +13 -4
  62. data/spec/parser_spec.rb +63 -16
  63. data/spec/spec_helper.rb +1 -2
  64. data/spec/string_atom_spec.rb +2 -2
  65. data/spec/symbol_spec.rb +2 -2
  66. data/spec/tokeniser_spec.rb +101 -0
  67. metadata +16 -2
@@ -0,0 +1,26 @@
1
+ (examples-for ampersand-syntax
2
+ ("shortcut for hash-get"
3
+ (&key { key 'value })
4
+ value)
5
+
6
+ ("acts as function"
7
+ (map &key (list { key 1 } { key 2 } { key 3 }))
8
+ (1 2 3))
9
+
10
+ ("assigns to key"
11
+ (let h { key 12 }
12
+ (= (&key h) 13)
13
+ h.key)
14
+ 13)
15
+
16
+ ("assigns to key.subkey"
17
+ (let h { key { subkey 41 } }
18
+ (= (&key.subkey h) 42)
19
+ h.key.subkey)
20
+ 42)
21
+
22
+ ("even works with 'push"
23
+ (let h { key { subkey '(1 2 3) } }
24
+ (push 99 (&key.subkey h))
25
+ h.key.subkey)
26
+ (99 1 2 3)))
@@ -7,7 +7,7 @@
7
7
  (mac make-make-op (opname op)
8
8
  `(mac ,opname (name n . body)
9
9
  `(mac ,name (x)
10
- `(,',',op ,,n ,x))))
10
+ `(',',,op ,,n ,x))))
11
11
 
12
12
  (make-make-op make-mult *)
13
13
  (make-make-op make-plus +)
@@ -22,6 +22,10 @@
22
22
  (collect (fn (x) (eq? (len x) 2)) '("aa" "bbb" "cc" "ddd" . "ee"))
23
23
  ("aa" "cc" . "ee"))
24
24
 
25
+ ("preserves structure of improper list: returns just the lastcdr"
26
+ (collect (fn (x) (eq? (len x) 2)) '("aaa" "bbb" "ccc" "ddd" . "ee"))
27
+ "ee")
28
+
25
29
  ("returns nil if it's an atom and doesn't match"
26
30
  (collect (fn (x) (eq? (len x) 20))
27
31
  "zz")
@@ -16,7 +16,7 @@
16
16
  (b c) (nth 1 xxx)
17
17
  (d (e f)) (nth 2 xxx)
18
18
  g (nth 3 xxx)
19
- h (lastcdr xxx))))
19
+ h (nthcdr 4 xxx))))
20
20
 
21
21
  (examples-for destructure/build
22
22
  ("with no args"
@@ -56,6 +56,23 @@
56
56
  (nth 0 destructure-2)
57
57
  (nth 1 destructure-2))) (nth 0 destructure-1) (nth 1 destructure-1))))
58
58
 
59
+ ("nested improper arguments"
60
+ (let (a (b c . d) e) (list "A" (list "B" "C" "D0" "D1" "D2") "E")
61
+ (string-pieces a b c d e))
62
+ "ABCD0D1D2E")
63
+
64
+ ; a lot of ceremony here to suppress side-effects of compiling really crap code and just get the warnings
65
+ ("warns about arg names shadowing macro names"
66
+ (do (without-hooks 'warnings/new
67
+ λ(on-err nil
68
+ (pre-compile '(fun (aif (and or) . when)
69
+ "ignore"))))
70
+ warnings/list)
71
+ ((arg-shadows-macro "arg " when " shadows macro " when " in arg list " (aif (and or) . when))
72
+ (arg-shadows-macro "arg " or " shadows macro " or " in arg list " (aif (and or) . when))
73
+ (arg-shadows-macro "arg " and " shadows macro " and " in arg list " (aif (and or) . when))
74
+ (arg-shadows-macro "arg " aif " shadows macro " aif " in arg list " (aif (and or) . when))))
75
+
59
76
  ("implicit in 'let and 'with"
60
77
  (with ((a b) (list "h" "e")
61
78
  (c (d e f)) (list "l" (list "l" "o" " ")))
@@ -1,6 +1,6 @@
1
1
  (examples-for fill-bucket
2
2
  ("fills a bucket with 12 characters"
3
- (fill-bucket '("1" "2345" "67" "890" "1" "2345" "678")
3
+ (bucket/fill '("1" "2345" "67" "890" "1" "2345" "678")
4
4
  nil
5
5
  len
6
6
  0
@@ -10,7 +10,7 @@
10
10
  ("2345" "678")))
11
11
 
12
12
  ("fills a bucket up to 100"
13
- (fill-bucket '(1 2 3 4 5 6 7 8 9 10)
13
+ (bucket/fill '(1 2 3 4 5 6 7 8 9 10)
14
14
  nil
15
15
  λx(* x x)
16
16
  0
@@ -18,3 +18,47 @@
18
18
  ((1 2 3 4 5 6)
19
19
  91
20
20
  (7 8 9 10))))
21
+
22
+ (examples-for fill-buckets
23
+ ("returns an empty list for no items"
24
+ (let pages (fill-buckets '() 30 nil λx(* x x) 'line-items)
25
+ (= pages (fill-buckets '() 30 pages len 'history ))
26
+ (= pages (fill-buckets '() 30 pages (k 1) 'payments ))
27
+ (rev:map λb(list 'size b.bucket-size 'line-items b.line-items 'history b.history 'payments b.payments)
28
+ pages))
29
+ ())
30
+
31
+ ("returns a single bucket for few items"
32
+ (let pages (fill-buckets '() 30 nil λx(* x x) 'line-items)
33
+ (= pages (fill-buckets '("aa" "bbbb" "c" "ddddd" "eeee") 30 pages len 'history ))
34
+ (= pages (fill-buckets '() 30 pages (k 1) 'payments ))
35
+ (rev:map λb(list 'size b.bucket-size 'line-items b.line-items 'history b.history 'payments b.payments)
36
+ pages))
37
+ ((size 16 line-items nil history ("aa" "bbbb" "c" "ddddd" "eeee") payments nil)))
38
+
39
+ ("returns a single overfilled bucket for an oversized item"
40
+ (let pages (fill-buckets '("aa34567890123456" "eeee") 12 nil len 'history )
41
+ (rev:map λb(list 'size b.bucket-size b.history)
42
+ pages))
43
+ ((size 16 ("aa34567890123456"))
44
+ (size 4 ("eeee"))))
45
+
46
+ ("accumulates subsequent items in subsequent buckets"
47
+ (let pages (fill-buckets '(1 2 2 4 3 3 1) 30 nil λx(* x x) 'line-items)
48
+ (= pages (fill-buckets '() 30 pages len 'history ))
49
+ (= pages (fill-buckets '(pay pay pay pay) 30 pages (k 3) 'payments ))
50
+ (rev:map λb(list 'size b.bucket-size 'line-items b.line-items 'history b.history 'payments b.payments)
51
+ pages))
52
+ ((size 25 line-items (1 2 2 4) history nil payments nil)
53
+ (size 28 line-items (3 3 1) history nil payments (pay pay pay))
54
+ (size 3 line-items nil history nil payments (pay))))
55
+
56
+ ("use fill-buckets for complex pagination where you have several sets of elements, each element having a different size"
57
+ (let pages (fill-buckets '(1 2 2 4 3 3 1) 30 nil λx(* x x) 'line-items)
58
+ (= pages (fill-buckets '("aa" "bbbb" "c" "ddddd" "eeee") 30 pages len 'history ))
59
+ (= pages (fill-buckets '(pay pay pay pay) 30 pages (k 1) 'payments ))
60
+ (rev:map λb(list 'size b.bucket-size 'line-items b.line-items 'history b.history 'payments b.payments)
61
+ pages))
62
+ ((size 25 line-items (1 2 2 4) history nil payments nil)
63
+ (size 26 line-items (3 3 1) history ("aa" "bbbb" "c") payments nil)
64
+ (size 13 line-items nil history ("ddddd" "eeee") payments (pay pay pay pay)))))
@@ -0,0 +1,58 @@
1
+ (examples-for ⌊
2
+ ("rounds the given to the nearest integer below"
3
+ (⌊ 12.5)
4
+ 12)
5
+
6
+ ("rounds the given to the nearest integer below"
7
+ (⌊ 32.32)
8
+ 32)
9
+
10
+ ("rounds the given to the nearest integer below negatively"
11
+ (⌊ -32.32)
12
+ -33)
13
+
14
+ ("alias for 'math-floor"
15
+ (math-floor 3.1415)
16
+ 3))
17
+
18
+ (examples-for ⌈
19
+ ("rounds the given to the nearest integer above"
20
+ (⌈ 25.25)
21
+ 26)
22
+
23
+ ("rounds the given to the nearest integer above"
24
+ (⌈ 12.5)
25
+ 13)
26
+
27
+ ("rounds the given to the nearest integer above negatively"
28
+ (⌈ -25.25)
29
+ -25)
30
+
31
+ ("alias for 'math-ceiling"
32
+ (math-ceiling 3.1415)
33
+ 4))
34
+
35
+ (examples-for round
36
+ ("rounds the given to the nearest integer"
37
+ (math-round 3.1415)
38
+ 3)
39
+
40
+ ("rounds the given to the nearest integer"
41
+ (math-round -3.1415)
42
+ -3)
43
+
44
+ ("rounds the given to the nearest negative integer"
45
+ (math-round -3.999)
46
+ -4)
47
+
48
+ ("rounds the given to the nearest integer"
49
+ (math-round 3.999)
50
+ 4)
51
+
52
+ ("rounds half-away from zero"
53
+ (math-round 12.5)
54
+ 13)
55
+
56
+ ("rounds negatively half-away from zero"
57
+ (math-round -1.5)
58
+ -2))
@@ -0,0 +1,5 @@
1
+ (examples-for k
2
+ ("returns a constant function"
3
+ (let f (k 1)
4
+ (list (f) (f) (f) (f)))
5
+ (1 1 1 1)))
@@ -0,0 +1,16 @@
1
+ (examples-for **
2
+ ("2 ** 10"
3
+ (** 2 10)
4
+ 1024)
5
+
6
+ ("10 ** 3"
7
+ (** 10 3)
8
+ 1000)
9
+
10
+ ("1024 ** 0.5"
11
+ (** 1024 0.5)
12
+ 32)
13
+
14
+ ("16 ** 1.5"
15
+ (** 16 1.5)
16
+ 64))
@@ -3,6 +3,10 @@
3
3
  (string-split "a and b and c and d" " and ")
4
4
  ("a" "b" "c" "d"))
5
5
 
6
+ ("with no delimiter argument, returns chars in string"
7
+ (collect !empty? (string-split "word"))
8
+ ("w" "o" "r" "d"))
9
+
6
10
  ("returns empty leading, internal, and trailing segments"
7
11
  (string-split "and" "and")
8
12
  ("" ""))
@@ -21,6 +25,10 @@
21
25
  "a x b x c x d"))
22
26
 
23
27
  (examples-for string-match
28
+ ("no match returns nil"
29
+ (string-match "this that another" "XXXX")
30
+ nil)
31
+
24
32
  ("match with regexp"
25
33
  (let m (string-match "a and b and c and d" "and")
26
34
  (list m.match m.captures))
@@ -23,6 +23,12 @@
23
23
  '(a b c d e f))
24
24
  "a:b:c:d:e:f")
25
25
 
26
+ ("with no args"
27
+ (let x 15
28
+ (let y λ(* x x)
29
+ (y)))
30
+ 225)
31
+
26
32
  ("with two args, to be sure"
27
33
  (λpq(+ p (* p q)) 3 5)
28
34
  18))
@@ -0,0 +1,16 @@
1
+ (examples-for zip
2
+ ("joins two lists"
3
+ (zip '(a b c) '(1 2 3))
4
+ ((a 1) (b 2) (c 3)))
5
+
6
+ ("joins more lists"
7
+ (zip '(a b) '(1 2) '(p q) '(41 42 43) '(x y zip))
8
+ ((a 1 p 41 x) (b 2 q 42 y)))
9
+
10
+ ("resulting list is as long as first list"
11
+ (zip '(a b) '(1 2 3 4 5 6) nil)
12
+ ((a 1 nil) (b 2 nil)))
13
+
14
+ ("resulting list is nil if first list is nil"
15
+ (zip nil '(1 2 3 4 5) '(p q r))
16
+ nil))
@@ -5,6 +5,7 @@ module Nydp
5
5
  class Namespace < Hash
6
6
  end
7
7
 
8
+ # TODO: write VM #apply_function so we have fewer calls to VM.new
8
9
  def self.apply_function ns, function_name, *args
9
10
  function = r2n(function_name.to_sym, ns).value
10
11
  args = r2n args, ns
@@ -18,6 +19,8 @@ module Nydp
18
19
  def self.eval_src ns, src_txt, name=nil ; eval_with Nydp::Runner, ns, src_txt, name ; end
19
20
  def self.eval_with runner, ns, src_txt, name ; runner.new(VM.new(ns), ns, reader(src_txt), nil, name).run ; end
20
21
  def self.ms t1, t0 ; ((t1 - t0) * 1000).to_i ; end
22
+ def self.new_tokeniser reader ; Nydp::Tokeniser.new reader ; end
23
+ def self.new_parser ns ; Nydp::Parser.new(ns) ; end
21
24
 
22
25
  def self.indent_message indent, msg
23
26
  msg.split(/\n/).map { |line| "#{indent}#{line}" }.join("\n")
@@ -47,12 +50,13 @@ module Nydp
47
50
 
48
51
  def self.repl options={ }
49
52
  toplevel do
50
- silent = options[:silent]
53
+ silent = options.delete :silent
54
+ ns = options.delete :ns
51
55
  launch_time = Time.now
52
56
  last_script_time = Time.now
53
57
  puts "welcome to nydp #{options.inspect}" unless silent
54
58
  reader = Nydp::ReadlineReader.new $stdin, "nydp > "
55
- ns = build_nydp do |script|
59
+ ns ||= build_nydp do |script|
56
60
  this_script_time = Time.now
57
61
  puts "script #{script} time #{ms this_script_time, last_script_time}ms" if options[:verbose]
58
62
  last_script_time = this_script_time
@@ -38,8 +38,7 @@ module Nydp
38
38
  def inspect; to_s ; end
39
39
 
40
40
  def execute vm
41
- vm.instructions.push @instructions
42
- vm.contexts.push vm.current_context
41
+ vm.push_ctx_instructions @instructions
43
42
  end
44
43
  end
45
44
  end
@@ -21,8 +21,7 @@ class Nydp::Builtin::Ensuring
21
21
  fn_tricky = args.cdr.car
22
22
 
23
23
  protection_instructions = Nydp::Pair.from_list [InvokeProtection.new(fn_ensure), Nydp::PopArg]
24
- vm.instructions.push protection_instructions
25
- vm.contexts.push vm.current_context
24
+ vm.push_ctx_instructions protection_instructions
26
25
 
27
26
  fn_tricky.invoke vm, Nydp::NIL
28
27
  end
@@ -2,11 +2,11 @@ class Nydp::Builtin::GreaterThan
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- vm.push_arg (greater_than(args.car, args.cdr) ? Nydp::T : Nydp::NIL)
5
+ vm.push_arg(greater_than(args.car, args.cdr) || Nydp::NIL)
6
6
  end
7
7
 
8
8
  def greater_than arg, args
9
- return true if Nydp::NIL.is? args
9
+ return arg if Nydp::NIL.is? args
10
10
  (arg > args.car) && greater_than(args.car, args.cdr)
11
11
  end
12
12
 
@@ -39,8 +39,7 @@ class Nydp::Builtin::HandleError
39
39
  fn_tricky = args.cdr.car
40
40
 
41
41
  catcher_instructions = Nydp::Pair.from_list [CatchError.new(fn_handle, vm.args.size)]
42
- vm.instructions.push catcher_instructions
43
- vm.contexts.push vm.current_context
42
+ vm.push_ctx_instructions catcher_instructions
44
43
 
45
44
  fn_tricky.invoke vm, Nydp::NIL
46
45
  end
@@ -2,11 +2,11 @@ class Nydp::Builtin::LessThan
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- vm.push_arg (less_than(args.car, args.cdr) ? Nydp::T : Nydp::NIL)
5
+ vm.push_arg(less_than(args.car, args.cdr) || Nydp::NIL)
6
6
  end
7
7
 
8
8
  def less_than arg, args
9
- return true if Nydp::NIL.is? args
9
+ return arg if Nydp::NIL.is? args
10
10
  (arg < args.car) && less_than(args.car, args.cdr)
11
11
  end
12
12
 
@@ -0,0 +1,7 @@
1
+ class Nydp::Builtin::MathCeiling
2
+ include Nydp::Builtin::Base, Singleton
3
+
4
+ def builtin_invoke vm, args
5
+ vm.push_arg(args.car.ceil)
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Nydp::Builtin::MathFloor
2
+ include Nydp::Builtin::Base, Singleton
3
+
4
+ def builtin_invoke vm, args
5
+ vm.push_arg(args.car.floor)
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Nydp::Builtin::MathPower
2
+ include Nydp::Builtin::Base, Singleton
3
+
4
+ def builtin_invoke vm, args
5
+ vm.push_arg(args.car ** args.cdr.car)
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Nydp::Builtin::MathRound
2
+ include Nydp::Builtin::Base, Singleton
3
+
4
+ def builtin_invoke vm, args
5
+ vm.push_arg(args.car.round)
6
+ end
7
+ end
@@ -2,8 +2,8 @@ class Nydp::Builtin::Parse
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- parser = Nydp::Parser.new(vm.ns)
6
- tokens = Nydp::Tokeniser.new Nydp::StringReader.new args.car.to_s
5
+ parser = Nydp.new_parser(vm.ns)
6
+ tokens = Nydp.new_tokeniser Nydp::StringReader.new args.car.to_s
7
7
  exprs = []
8
8
  while !tokens.finished
9
9
  expr = parser.expression(tokens)
@@ -2,10 +2,10 @@ class Nydp::Builtin::ParseInString
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- parser = Nydp::Parser.new(vm.ns)
5
+ parser = Nydp.new_parser(vm.ns)
6
6
  parsable = args.car.to_s
7
- tokens = Nydp::Tokeniser.new Nydp::StringReader.new parsable
8
- expr = parser.string(tokens, "", :eof)
7
+ tokens = Nydp.new_tokeniser Nydp::StringReader.new parsable
8
+ expr = parser.embedded(tokens)
9
9
  vm.push_arg expr
10
10
  rescue StandardError => e
11
11
  new_msg = "parse error: #{e.message.inspect} in\n#{Nydp.indent_text parsable}"
@@ -2,7 +2,6 @@ class Nydp::Builtin::PreCompile
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- raise Nydp:Error.new("pre-compile: expects one arg, got #{args.inspect}") unless Nydp::NIL == args.cdr
6
5
  vm.push_arg args.car
7
6
  end
8
7
  end