nydp 0.4.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +44 -0
  3. data/lib/lisp/core-010-precompile.nydp +13 -16
  4. data/lib/lisp/core-012-utils.nydp +3 -2
  5. data/lib/lisp/core-015-documentation.nydp +54 -23
  6. data/lib/lisp/core-017-builtin-dox.nydp +14 -12
  7. data/lib/lisp/core-020-utils.nydp +5 -5
  8. data/lib/lisp/core-030-syntax.nydp +166 -72
  9. data/lib/lisp/core-035-flow-control.nydp +38 -11
  10. data/lib/lisp/core-037-list-utils.nydp +12 -0
  11. data/lib/lisp/core-039-module.nydp +24 -0
  12. data/lib/lisp/core-040-utils.nydp +32 -12
  13. data/lib/lisp/core-041-string-utils.nydp +25 -1
  14. data/lib/lisp/core-042-date-utils.nydp +21 -1
  15. data/lib/lisp/core-043-list-utils.nydp +96 -64
  16. data/lib/lisp/core-070-prefix-list.nydp +1 -1
  17. data/lib/lisp/core-080-pretty-print.nydp +57 -17
  18. data/lib/lisp/core-090-hook.nydp +35 -1
  19. data/lib/lisp/core-100-utils.nydp +82 -2
  20. data/lib/lisp/core-110-hash-utils.nydp +56 -2
  21. data/lib/lisp/core-120-settings.nydp +16 -5
  22. data/lib/lisp/core-130-validations.nydp +51 -0
  23. data/lib/lisp/core-900-benchmarking.nydp +78 -20
  24. data/lib/lisp/tests/accum-examples.nydp +28 -1
  25. data/lib/lisp/tests/aif-examples.nydp +8 -3
  26. data/lib/lisp/tests/andify-examples.nydp +7 -0
  27. data/lib/lisp/tests/at-syntax-examples.nydp +17 -0
  28. data/lib/lisp/tests/best-examples.nydp +9 -0
  29. data/lib/lisp/tests/builtin-tests.nydp +19 -0
  30. data/lib/lisp/tests/case-examples.nydp +14 -0
  31. data/lib/lisp/tests/date-examples.nydp +54 -1
  32. data/lib/lisp/tests/destructuring-examples.nydp +46 -14
  33. data/lib/lisp/tests/detect-examples.nydp +12 -0
  34. data/lib/lisp/tests/dp-examples.nydp +24 -0
  35. data/lib/lisp/tests/each-tests.nydp +5 -0
  36. data/lib/lisp/tests/empty-examples.nydp +1 -1
  37. data/lib/lisp/tests/error-tests.nydp +4 -4
  38. data/lib/lisp/tests/explain-mac-examples.nydp +1 -1
  39. data/lib/lisp/tests/filter-forms-examples.nydp +15 -0
  40. data/lib/lisp/tests/hash-examples.nydp +25 -1
  41. data/lib/lisp/tests/list-grep-examples.nydp +40 -0
  42. data/lib/lisp/tests/list-tests.nydp +58 -1
  43. data/lib/lisp/tests/map-hash-examples.nydp +11 -0
  44. data/lib/lisp/tests/module-examples.nydp +10 -0
  45. data/lib/lisp/tests/multi-assign-examples.nydp +6 -0
  46. data/lib/lisp/tests/parser-tests.nydp +25 -0
  47. data/lib/lisp/tests/pretty-print-tests.nydp +17 -14
  48. data/lib/lisp/tests/set-difference-examples.nydp +8 -0
  49. data/lib/lisp/tests/settings-examples.nydp +17 -1
  50. data/lib/lisp/tests/string-tests.nydp +70 -1
  51. data/lib/lisp/tests/syntax-tests.nydp +5 -1
  52. data/lib/lisp/tests/to-integer-examples.nydp +16 -0
  53. data/lib/lisp/tests/validation-examples.nydp +15 -0
  54. data/lib/nydp.rb +10 -3
  55. data/lib/nydp/assignment.rb +10 -3
  56. data/lib/nydp/builtin.rb +1 -1
  57. data/lib/nydp/builtin/abs.rb +8 -0
  58. data/lib/nydp/builtin/date.rb +15 -1
  59. data/lib/nydp/builtin/error.rb +1 -1
  60. data/lib/nydp/builtin/hash.rb +24 -1
  61. data/lib/nydp/builtin/inspect.rb +1 -1
  62. data/lib/nydp/builtin/plus.rb +10 -2
  63. data/lib/nydp/builtin/random_string.rb +2 -2
  64. data/lib/nydp/builtin/{car.rb → regexp.rb} +2 -2
  65. data/lib/nydp/builtin/ruby_wrap.rb +72 -0
  66. data/lib/nydp/builtin/string_match.rb +2 -2
  67. data/lib/nydp/builtin/string_pad_left.rb +7 -0
  68. data/lib/nydp/builtin/string_pad_right.rb +7 -0
  69. data/lib/nydp/builtin/string_replace.rb +3 -3
  70. data/lib/nydp/builtin/string_split.rb +4 -3
  71. data/lib/nydp/builtin/to_integer.rb +23 -0
  72. data/lib/nydp/builtin/to_string.rb +2 -9
  73. data/lib/nydp/builtin/type_of.rb +9 -6
  74. data/lib/nydp/closure.rb +0 -3
  75. data/lib/nydp/cond.rb +23 -1
  76. data/lib/nydp/context_symbol.rb +14 -6
  77. data/lib/nydp/core.rb +36 -28
  78. data/lib/nydp/core_ext.rb +21 -5
  79. data/lib/nydp/date.rb +26 -18
  80. data/lib/nydp/function_invocation.rb +34 -26
  81. data/lib/nydp/helper.rb +35 -3
  82. data/lib/nydp/interpreted_function.rb +68 -40
  83. data/lib/nydp/literal.rb +1 -1
  84. data/lib/nydp/pair.rb +22 -5
  85. data/lib/nydp/parser.rb +11 -7
  86. data/lib/nydp/string_atom.rb +3 -4
  87. data/lib/nydp/symbol_lookup.rb +7 -7
  88. data/lib/nydp/tokeniser.rb +2 -2
  89. data/lib/nydp/truth.rb +10 -10
  90. data/lib/nydp/version.rb +1 -1
  91. data/lib/nydp/vm.rb +7 -0
  92. data/nydp.gemspec +2 -4
  93. data/spec/date_spec.rb +93 -0
  94. data/spec/embedded_spec.rb +12 -12
  95. data/spec/foreign_hash_spec.rb +14 -2
  96. data/spec/hash_non_hash_behaviour_spec.rb +7 -7
  97. data/spec/hash_spec.rb +24 -2
  98. data/spec/nydp_spec.rb +14 -2
  99. data/spec/pair_spec.rb +3 -1
  100. data/spec/parser_spec.rb +31 -20
  101. data/spec/rand_spec.rb +3 -3
  102. data/spec/spec_helper.rb +10 -1
  103. metadata +24 -37
  104. data/lib/nydp/builtin/cdr.rb +0 -7
  105. data/lib/nydp/builtin/cons.rb +0 -9
@@ -10,7 +10,11 @@
10
10
  ("dislikes no-prefix"
11
11
  (on-err (joinstr "\n" errors)
12
12
  (pre-compile '(:foo 1 2 3)))
13
- "\"Irregular ': syntax: got (|| foo) : not prefix-syntax : in :foo\""))
13
+ "expanding
14
+ (colon-syntax || foo)
15
+ with
16
+ (fn names ((orf (hash-get colon-syntax-overrides car [0#0#0]names) default-colon-syntax) [0#0#0]names))
17
+ Irregular ': syntax: got (|| foo) : not prefix-syntax : in :foo"))
14
18
 
15
19
  (examples-for prefix-list
16
20
  ("one argument"
@@ -0,0 +1,16 @@
1
+ (examples-for to-integer
2
+ ("converts a string"
3
+ (to-integer "1234")
4
+ 1234)
5
+
6
+ ("converts a date"
7
+ (to-integer (date 2004 3 12))
8
+ 1079046000)
9
+
10
+ ("converts a time"
11
+ (to-integer (time 2004 3 12 18 45))
12
+ 1079113500)
13
+
14
+ ("returns nonsense for non-integer"
15
+ (to-integer { foo 'bar })
16
+ 0))
@@ -0,0 +1,15 @@
1
+ (validate/def string test-0 (if (< (len string) 6) (mf "length" "should be more than 6")))
2
+ (validate/def string test-0 (if (> (len string) 10) (mf "length" "should be less than 10")))
3
+
4
+ (examples-for validate
5
+ ("returns a message about a string being too short"
6
+ (to-string:validate "foo" 'test-0)
7
+ "{\"length\"=>(\"should be more than 6\")}")
8
+
9
+ ("returns a message about a string being too long"
10
+ (to-string:validate "foo bar toto titi" 'test-0)
11
+ "{\"length\"=>(\"should be less than 10\")}")
12
+
13
+ ("returns an empty hash"
14
+ (to-string:validate "foo bar" 'test-0)
15
+ "{}"))
data/lib/nydp.rb CHANGED
@@ -2,6 +2,10 @@ require 'date'
2
2
  require 'set'
3
3
 
4
4
  module Nydp
5
+ class << self
6
+ attr_accessor :logger # not used by this gem but very useful in your app
7
+ end
8
+
5
9
  class Namespace < Hash
6
10
  end
7
11
 
@@ -11,6 +15,9 @@ module Nydp
11
15
  function = Symbol.mk(function_name.to_sym, ns).value
12
16
  function.invoke vm, r2n(args)
13
17
  vm.thread
18
+ rescue StandardError => e
19
+ friendly_args = args.map { |a| a.respond_to?(:_nydp_compact_inspect) ? a._nydp_compact_inspect : a }
20
+ raise Nydp::Error.new("Invoking #{function_name}\nwith args #{friendly_args.inspect}")
14
21
  end
15
22
 
16
23
  def self.reader txt ; Nydp::StringReader.new txt ; end
@@ -48,9 +55,9 @@ module Nydp
48
55
 
49
56
  def self.repl options={ }
50
57
  toplevel do
51
- silent = options.delete :silent
52
- ns = options.delete :ns
53
- launch_time = Time.now
58
+ launch_time = Time.now
59
+ silent = options.delete :silent
60
+ ns = options.delete :ns
54
61
  last_script_time = Time.now
55
62
  puts "welcome to nydp #{options.inspect}" unless silent
56
63
  reader = Nydp::ReadlineReader.new $stdin, "nydp > "
@@ -8,6 +8,8 @@ module Nydp
8
8
 
9
9
  def execute vm
10
10
  @name.assign vm.peek_arg, vm.current_context
11
+ rescue
12
+ raise "assigning #{@name.inspect}"
11
13
  end
12
14
 
13
15
  def to_s
@@ -26,9 +28,12 @@ module Nydp
26
28
  end
27
29
 
28
30
  def initialize name, value, value_src
29
- @value_src = value_src
30
- n = AssignmentInstruction.new name
31
- @instructions = cons(value, cons(n))
31
+ @name, @value, @value_src = name, value, value_src
32
+ @instructions = cons(value, cons(AssignmentInstruction.new(name)))
33
+ end
34
+
35
+ def lexical_reach n
36
+ [@name.lexical_reach(n), @value.lexical_reach(n)].max
32
37
  end
33
38
 
34
39
  def to_s
@@ -39,6 +44,8 @@ module Nydp
39
44
 
40
45
  def execute vm
41
46
  vm.push_ctx_instructions @instructions
47
+ rescue
48
+ raise "assigning #{@value.inspect} to #{@name.inspect}"
42
49
  end
43
50
  end
44
51
  end
data/lib/nydp/builtin.rb CHANGED
@@ -32,13 +32,13 @@ module Nydp::Builtin
32
32
  handle_error e, arg_0, arg_1, arg_2
33
33
  end
34
34
 
35
+ # called from 'apply (among others)
35
36
  def invoke vm, args
36
37
  builtin_invoke vm, args
37
38
  rescue StandardError => e
38
39
  handle_error e, *(args.to_a)
39
40
  end
40
41
 
41
-
42
42
  def handle_error e, *args
43
43
  case e
44
44
  when Nydp::Error
@@ -0,0 +1,8 @@
1
+ class Nydp::Builtin::Abs
2
+ include Nydp::Builtin::Base, Singleton
3
+
4
+ def invoke_2 vm, a0 ; vm.push_arg(a0.abs) ; end
5
+ def builtin_invoke vm, args ; invoke_2 vm, args.car ; end
6
+
7
+ def name ; "mod" ; end
8
+ end
@@ -1,13 +1,27 @@
1
1
  class Nydp::Builtin::Date
2
2
  include Nydp::Helper, Nydp::Builtin::Base, Singleton
3
3
 
4
+ def builtin_invoke vm, args
5
+ case args.size
6
+ when 0 ; builtin_invoke_1 vm
7
+ when 1 ; builtin_invoke_2 vm, args.car
8
+ when 2 ; builtin_invoke_3 vm, args.car, args.cdr.car
9
+ when 3 ; builtin_invoke_4 vm, args.car, args.cdr.car, args.cdr.cdr.car
10
+ end
11
+ end
12
+
4
13
  def builtin_invoke_1 vm
5
14
  vm.push_arg(Nydp::Date.new Date.today)
6
15
  end
7
16
 
8
17
  # it's a Time object (or any object that responds to #to_date)
9
18
  def builtin_invoke_2 vm, arg
10
- vm.push_arg(Nydp::Date.new arg.to_date)
19
+ arg = if arg.respond_to?(:to_date)
20
+ arg.to_date
21
+ elsif arg.is_a?(String)
22
+ ::Date.parse(arg)
23
+ end
24
+ vm.push_arg(Nydp::Date.new arg)
11
25
  end
12
26
 
13
27
  def builtin_invoke_3 vm, a0, a1
@@ -4,6 +4,6 @@ class Nydp::Builtin::Error
4
4
  # override #invoke on nydp/builtin/base because
5
5
  # we don't want to inherit error handling
6
6
  def builtin_invoke vm, args
7
- raise Nydp::Error.new(args.to_a.map(&:inspect).join("\n"), vm.last_error)
7
+ raise Nydp::Error.new(args.to_a.map(&:to_s).join("\n"), vm.last_error)
8
8
  end
9
9
  end
@@ -2,8 +2,18 @@ require "nydp/hash"
2
2
 
3
3
  class Nydp::Builtin::Hash
4
4
  include Nydp::Helper, Nydp::Builtin::Base, Singleton
5
+
5
6
  def builtin_invoke vm, args
6
- vm.push_arg(Nydp::Hash.new)
7
+ vm.push_arg(build_hash Nydp::Hash.new, args)
8
+ end
9
+
10
+ def build_hash h, args
11
+ return h if Nydp::NIL.is? args
12
+ k = args.car
13
+ rest = args.cdr
14
+ v = rest.car
15
+ h[k] = v
16
+ build_hash h, rest.cdr
7
17
  end
8
18
  end
9
19
 
@@ -56,3 +66,16 @@ class Nydp::Builtin::HashMerge
56
66
  vm.push_arg hash_0.merge hash_1
57
67
  end
58
68
  end
69
+
70
+ class Nydp::Builtin::HashSlice
71
+ include Nydp::Helper, Nydp::Builtin::Base, Singleton
72
+
73
+ def builtin_invoke vm, args
74
+ old = args.car
75
+ h = old.class.new
76
+ slice = args.cdr.car
77
+ slice = slice.map { |k| n2r k } unless old.is_a? Nydp::Hash
78
+ slice.each { |k| h[k] = old[k] if old.key?(k) }
79
+ vm.push_arg h
80
+ end
81
+ end
@@ -2,6 +2,6 @@ class Nydp::Builtin::Inspect
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- vm.push_arg Nydp::StringAtom.new(args.car.inspect)
5
+ vm.push_arg args.car.inspect
6
6
  end
7
7
  end
@@ -10,13 +10,21 @@ class Nydp::Builtin::Plus
10
10
  vm.push_arg case args.car
11
11
  when Nydp::Pair
12
12
  sum(args, Nydp::NIL)
13
- when String, Nydp::StringAtom
14
- sum(args, Nydp::StringAtom.new(""))
13
+ when String
14
+ string_concat("", args)
15
15
  else
16
16
  sum(args.cdr, args.car)
17
17
  end
18
18
  end
19
19
 
20
+ def string_concat init, others
21
+ while others && !Nydp::NIL.is?(others)
22
+ init << others.car.to_s
23
+ others = others.cdr
24
+ end
25
+ init
26
+ end
27
+
20
28
  def sum args, accum
21
29
  while args && !Nydp::NIL.is?(args)
22
30
  accum += args.car
@@ -5,7 +5,7 @@ class Nydp::Builtin::RandomString
5
5
 
6
6
  def builtin_invoke vm, args
7
7
  length = args.car unless Nydp::NIL.is?(args)
8
- s = (0...(length || 10)).map { RANDOM_CHARS[rand(RANDOM_CHARS.size)] }.join
9
- vm.push_arg Nydp::StringAtom.new s
8
+ s = (0...(length || 10)).inject("") {|a,i| a << RANDOM_CHARS[rand(RANDOM_CHARS.size)] }
9
+ vm.push_arg s
10
10
  end
11
11
  end
@@ -1,7 +1,7 @@
1
- class Nydp::Builtin::Car
1
+ class Nydp::Builtin::Regexp
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- vm.push_arg args.car.car
5
+ vm.push_arg Regexp.compile(args.car.to_s)
6
6
  end
7
7
  end
@@ -0,0 +1,72 @@
1
+ class Nydp::Builtin::RubyWrap
2
+ @@builtins = { }
3
+
4
+ def self.builtins
5
+ @@builtins
6
+ end
7
+
8
+ class Coder < Struct.new(:name, :size, :code, :helpers)
9
+ def msize ; size + 1 ; end
10
+
11
+ def arg_mapper
12
+ case size
13
+ when 0 ; ""
14
+ when 1 ; ", a0"
15
+ when 2 ; ", a0, a1"
16
+ when 3 ; ", a0, a1, a2"
17
+ when 4 ; ", a0, a1, a2, a3"
18
+ when 5 ; ", a0, a1, a2, a3, a4"
19
+ else ; raise "maximum 5 arguments!"
20
+ end
21
+ end
22
+
23
+ def to_ruby
24
+ generic_code = code.
25
+ gsub(/a0/, "args.car").
26
+ gsub(/a1/, "args.cdr.car").
27
+ gsub(/a2/, "args.cdr.cdr.car").
28
+ gsub(/a3/, "args.cdr.cdr.cdr.car").
29
+ gsub(/a4/, "args.cdr.cdr.cdr.cdr.car")
30
+ <<CODE
31
+ class #{name}
32
+ include Nydp::Builtin::Base, Singleton#{helpers}
33
+
34
+ def builtin_invoke_#{msize} vm#{ arg_mapper }
35
+ vm.push_arg(#{code})
36
+ end
37
+
38
+ def builtin_invoke vm, args
39
+ vm.push_arg(#{generic_code})
40
+ end
41
+ end
42
+ CODE
43
+ end
44
+ end
45
+
46
+ def self.const_missing const
47
+ coder = @@builtins[const]
48
+ coder ? class_eval(coder.to_ruby) : super
49
+ const_get const
50
+ end
51
+
52
+ class WrapperBuilder
53
+ def initialize default_helpers
54
+ @default_helpers = default_helpers.to_s.strip != "" ? ", #{default_helpers}" : ""
55
+ end
56
+
57
+ def build name, args, code, helpers=""
58
+ extra_helpers = helpers.to_s.strip != "" ? ", #{helpers}" : ""
59
+ Nydp::Builtin::RubyWrap.builtins[name.to_sym] = Coder.new(name.to_sym, args, code, "#{@default_helpers}#{extra_helpers}")
60
+ end
61
+ end
62
+
63
+ def self.builder includes
64
+ WrapperBuilder.new(includes)
65
+ end
66
+
67
+ core_builder = builder ""
68
+ core_builder.build(:Cons, 2, %{ Nydp::Pair.new(a0, a1) } )
69
+ core_builder.build(:Car , 1, %{ a0.car } )
70
+ core_builder.build(:Cdr , 1, %{ a0.cdr } )
71
+ core_builder.build(:Log , 1, %{ r2n Nydp.logger.info(a0.to_s) } )
72
+ end
@@ -10,8 +10,8 @@ class Nydp::Builtin::StringMatch
10
10
 
11
11
  if match
12
12
  result = Nydp::Hash.new
13
- result[kmatch] = Nydp::StringAtom.new match.to_s
14
- result[kcaptures] = Nydp::Pair.from_list match.captures.map { |cap| Nydp::StringAtom.new cap.to_s }
13
+ result[kmatch] = match.to_s
14
+ result[kcaptures] = Nydp::Pair.from_list match.captures.map { |cap| cap.to_s }
15
15
  else
16
16
  result = Nydp::NIL
17
17
  end
@@ -0,0 +1,7 @@
1
+ class Nydp::Builtin::StringPadLeft
2
+ include Nydp::Builtin::Base, Singleton
3
+
4
+ def builtin_invoke_4 vm, str, len, padding
5
+ vm.push_arg str.to_s.rjust(len, padding.to_s)
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Nydp::Builtin::StringPadRight
2
+ include Nydp::Builtin::Base, Singleton
3
+
4
+ def builtin_invoke_4 vm, str, len, padding
5
+ vm.push_arg str.to_s.ljust(len, padding.to_s)
6
+ end
7
+ end
@@ -2,11 +2,11 @@ class Nydp::Builtin::StringReplace
2
2
  include Nydp::Builtin::Base, Singleton
3
3
 
4
4
  def builtin_invoke vm, args
5
- to_remove = Regexp.new args.car.to_s
6
- to_insert = args.cdr.car.to_s
5
+ to_remove = Regexp.new args.car.to_ruby
6
+ to_insert = args.cdr.car.to_ruby
7
7
  target = args.cdr.cdr.car.to_s
8
8
  result = target.to_s.gsub to_remove, to_insert
9
9
 
10
- vm.push_arg Nydp::StringAtom.new result
10
+ vm.push_arg result
11
11
  end
12
12
  end
@@ -3,10 +3,11 @@ class Nydp::Builtin::StringSplit
3
3
 
4
4
  def builtin_invoke vm, args
5
5
  target = args.car.to_s
6
- separator = args.cdr.car.to_s
6
+ separator = args.cdr.car
7
+ separator = separator.to_s unless separator.is_a? Regexp
8
+
7
9
  result = target.split separator, -1
8
- list = result.map { |s| Nydp::StringAtom.new s }
9
10
 
10
- vm.push_arg Nydp::Pair.from_list list
11
+ vm.push_arg Nydp::Pair.from_list result
11
12
  end
12
13
  end
@@ -0,0 +1,23 @@
1
+ module Nydp::Builtin
2
+ class ToInteger
3
+ include Nydp::Builtin::Base, Singleton
4
+
5
+ def builtin_invoke_2 vm, arg
6
+ arg = n2r arg
7
+
8
+ i = if arg.respond_to? :to_i
9
+ arg.to_i
10
+ elsif arg.respond_to? :to_time
11
+ arg.to_time.to_i
12
+ else
13
+ arg.to_s.to_i
14
+ end
15
+
16
+ vm.push_arg r2n i
17
+ end
18
+
19
+ def builtin_invoke vm, args
20
+ builtin_invoke_2 vm, args.car
21
+ end
22
+ end
23
+ end
@@ -3,14 +3,7 @@ module Nydp::Builtin
3
3
  include Nydp::Builtin::Base, Singleton
4
4
 
5
5
  def builtin_invoke vm, args
6
- arg = args.car
7
- val = case arg.class
8
- when Nydp::StringAtom
9
- arg
10
- else
11
- Nydp::StringAtom.new arg.to_s
12
- end
13
- vm.push_arg val
6
+ vm.push_arg args.car.to_s
14
7
  end
15
8
  end
16
9
 
@@ -20,7 +13,7 @@ module Nydp::Builtin
20
13
  def builtin_invoke vm, args
21
14
  arg = args.car
22
15
  val = case arg
23
- when Nydp::StringAtom
16
+ when String
24
17
  arg.length
25
18
  else
26
19
  0