nydp 0.3.0 → 0.4.0

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