nydp 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) 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 +21 -6
  5. data/lib/lisp/core-015-documentation.nydp +58 -24
  6. data/lib/lisp/core-017-builtin-dox.nydp +49 -42
  7. data/lib/lisp/core-020-utils.nydp +5 -5
  8. data/lib/lisp/core-030-syntax.nydp +191 -96
  9. data/lib/lisp/core-035-flow-control.nydp +41 -14
  10. data/lib/lisp/core-037-list-utils.nydp +36 -14
  11. data/lib/lisp/core-039-module.nydp +24 -0
  12. data/lib/lisp/core-040-utils.nydp +51 -23
  13. data/lib/lisp/core-041-string-utils.nydp +37 -9
  14. data/lib/lisp/core-042-date-utils.nydp +21 -1
  15. data/lib/lisp/core-043-list-utils.nydp +99 -73
  16. data/lib/lisp/core-045-dox-utils.nydp +5 -0
  17. data/lib/lisp/core-070-prefix-list.nydp +1 -1
  18. data/lib/lisp/core-080-pretty-print.nydp +57 -17
  19. data/lib/lisp/core-090-hook.nydp +35 -1
  20. data/lib/lisp/core-100-utils.nydp +110 -15
  21. data/lib/lisp/core-110-hash-utils.nydp +61 -0
  22. data/lib/lisp/core-120-settings.nydp +46 -0
  23. data/lib/lisp/core-130-validations.nydp +51 -0
  24. data/lib/lisp/{core-060-benchmarking.nydp → core-900-benchmarking.nydp} +107 -19
  25. data/lib/lisp/tests/accum-examples.nydp +28 -1
  26. data/lib/lisp/tests/aif-examples.nydp +8 -3
  27. data/lib/lisp/tests/andify-examples.nydp +7 -0
  28. data/lib/lisp/tests/at-syntax-examples.nydp +17 -0
  29. data/lib/lisp/tests/best-examples.nydp +9 -0
  30. data/lib/lisp/tests/builtin-tests.nydp +19 -0
  31. data/lib/lisp/tests/case-examples.nydp +14 -0
  32. data/lib/lisp/tests/cdr-set-examples.nydp +6 -0
  33. data/lib/lisp/tests/date-examples.nydp +56 -1
  34. data/lib/lisp/tests/destructuring-examples.nydp +46 -14
  35. data/lib/lisp/tests/detect-examples.nydp +12 -0
  36. data/lib/lisp/tests/dp-examples.nydp +24 -0
  37. data/lib/lisp/tests/each-tests.nydp +5 -0
  38. data/lib/lisp/tests/empty-examples.nydp +1 -1
  39. data/lib/lisp/tests/error-tests.nydp +4 -4
  40. data/lib/lisp/tests/explain-mac-examples.nydp +1 -1
  41. data/lib/lisp/tests/filter-forms-examples.nydp +15 -0
  42. data/lib/lisp/tests/foundation-test.nydp +12 -0
  43. data/lib/lisp/tests/hash-examples.nydp +26 -2
  44. data/lib/lisp/tests/list-grep-examples.nydp +40 -0
  45. data/lib/lisp/tests/list-tests.nydp +58 -1
  46. data/lib/lisp/tests/map-hash-examples.nydp +11 -0
  47. data/lib/lisp/tests/module-examples.nydp +10 -0
  48. data/lib/lisp/tests/multi-assign-examples.nydp +6 -0
  49. data/lib/lisp/tests/parser-tests.nydp +25 -0
  50. data/lib/lisp/tests/pretty-print-tests.nydp +17 -14
  51. data/lib/lisp/tests/set-difference-examples.nydp +8 -0
  52. data/lib/lisp/tests/set-intersection-examples.nydp +16 -0
  53. data/lib/lisp/tests/set-union-examples.nydp +8 -0
  54. data/lib/lisp/tests/settings-examples.nydp +40 -0
  55. data/lib/lisp/tests/sort-examples.nydp +8 -0
  56. data/lib/lisp/tests/string-tests.nydp +65 -1
  57. data/lib/lisp/tests/syntax-tests.nydp +5 -1
  58. data/lib/lisp/tests/to-integer-examples.nydp +16 -0
  59. data/lib/lisp/tests/validation-examples.nydp +15 -0
  60. data/lib/lisp/tests/zap-examples.nydp +12 -0
  61. data/lib/nydp.rb +13 -7
  62. data/lib/nydp/assignment.rb +10 -3
  63. data/lib/nydp/builtin.rb +1 -1
  64. data/lib/nydp/builtin/abs.rb +8 -0
  65. data/lib/nydp/builtin/cdr_set.rb +1 -6
  66. data/lib/nydp/builtin/date.rb +15 -1
  67. data/lib/nydp/builtin/error.rb +1 -1
  68. data/lib/nydp/builtin/handle_error.rb +1 -1
  69. data/lib/nydp/builtin/hash.rb +27 -45
  70. data/lib/nydp/builtin/inspect.rb +1 -1
  71. data/lib/nydp/builtin/plus.rb +10 -2
  72. data/lib/nydp/builtin/random_string.rb +2 -2
  73. data/lib/nydp/builtin/{car.rb → regexp.rb} +2 -2
  74. data/lib/nydp/builtin/ruby_wrap.rb +72 -0
  75. data/lib/nydp/builtin/string_match.rb +2 -2
  76. data/lib/nydp/builtin/string_pad_left.rb +7 -0
  77. data/lib/nydp/builtin/string_pad_right.rb +7 -0
  78. data/lib/nydp/builtin/string_replace.rb +1 -1
  79. data/lib/nydp/builtin/string_split.rb +4 -3
  80. data/lib/nydp/builtin/to_integer.rb +23 -0
  81. data/lib/nydp/builtin/to_string.rb +2 -9
  82. data/lib/nydp/builtin/type_of.rb +9 -6
  83. data/lib/nydp/closure.rb +0 -3
  84. data/lib/nydp/cond.rb +23 -1
  85. data/lib/nydp/context_symbol.rb +14 -6
  86. data/lib/nydp/core.rb +36 -28
  87. data/lib/nydp/core_ext.rb +54 -0
  88. data/lib/nydp/date.rb +37 -31
  89. data/lib/nydp/function_invocation.rb +34 -26
  90. data/lib/nydp/hash.rb +5 -6
  91. data/lib/nydp/helper.rb +41 -25
  92. data/lib/nydp/interpreted_function.rb +68 -40
  93. data/lib/nydp/literal.rb +1 -1
  94. data/lib/nydp/pair.rb +22 -5
  95. data/lib/nydp/parser.rb +11 -7
  96. data/lib/nydp/string_atom.rb +16 -22
  97. data/lib/nydp/symbol.rb +40 -27
  98. data/lib/nydp/symbol_lookup.rb +7 -7
  99. data/lib/nydp/tokeniser.rb +2 -2
  100. data/lib/nydp/truth.rb +17 -10
  101. data/lib/nydp/version.rb +1 -1
  102. data/lib/nydp/vm.rb +7 -2
  103. data/nydp.gemspec +2 -4
  104. data/spec/date_spec.rb +115 -22
  105. data/spec/embedded_spec.rb +12 -12
  106. data/spec/foreign_hash_spec.rb +14 -2
  107. data/spec/hash_non_hash_behaviour_spec.rb +7 -7
  108. data/spec/hash_spec.rb +24 -2
  109. data/spec/nydp_spec.rb +14 -2
  110. data/spec/pair_spec.rb +3 -1
  111. data/spec/parser_spec.rb +31 -20
  112. data/spec/rand_spec.rb +3 -3
  113. data/spec/spec_helper.rb +13 -1
  114. data/spec/symbol_spec.rb +31 -0
  115. data/spec/time_spec.rb +1 -1
  116. metadata +31 -38
  117. data/lib/nydp/builtin/cdr.rb +0 -7
  118. data/lib/nydp/builtin/cons.rb +0 -9
@@ -0,0 +1,54 @@
1
+ class Object
2
+ def _nydp_get a ; raise "_nydp_get : not gettable: #{a.inspect} on #{self.class.name}" ; end
3
+ def _nydp_set a, v ; raise "_nydp_get : not settable: #{a.inspect} on #{self.class.name}" ; end
4
+ def _nydp_keys ; [] ; end
5
+ def _nydp_wrapper ; self ; end
6
+ def lexical_reach n ; n ; end
7
+ end
8
+
9
+ class Method
10
+ include Nydp::Converter
11
+ def invoke_1 vm ; vm.push_arg call._nydp_wrapper ; end
12
+ def invoke_2 vm, a0 ; vm.push_arg call(n2r(a0))._nydp_wrapper ; end
13
+ def invoke_3 vm, a0, a1 ; vm.push_arg call(n2r(a0), n2r(a1))._nydp_wrapper ; end
14
+ def invoke_4 vm, a0, a1, a2 ; vm.push_arg call(n2r(a0), n2r(a1), n2r(a2))._nydp_wrapper ; end
15
+ def invoke vm, args ; vm.push_arg call(*(args.map { |a| n2r a}))._nydp_wrapper ; end
16
+ end
17
+
18
+ class NilClass
19
+ def _nydp_wrapper ; Nydp::NIL ; end
20
+ end
21
+
22
+ class FalseClass
23
+ def _nydp_wrapper ; Nydp::NIL ; end
24
+ end
25
+
26
+ class TrueClass
27
+ def _nydp_wrapper ; Nydp::T ; end
28
+ end
29
+
30
+ class ::Symbol
31
+ def _nydp_wrapper ; Nydp::FrozenSymbol.mk(self) ; end
32
+ end
33
+
34
+ class ::Date
35
+ def _nydp_wrapper ; Nydp::Date.new self ; end
36
+ end
37
+
38
+ class ::Array
39
+ def _nydp_wrapper ; Nydp::Pair.from_list map &:_nydp_wrapper ; end
40
+ end
41
+
42
+ class ::String
43
+ # def _nydp_wrapper ; Nydp::StringAtom.new self ; end
44
+ def as_method_name ; self.gsub(/-/, '_').to_sym ; end
45
+ def nydp_type ; :string ; end
46
+ def to_ruby ; self ; end
47
+ end
48
+
49
+ class ::Hash
50
+ include Nydp::Helper
51
+ def _nydp_get a ; self[n2r a] ; end
52
+ def _nydp_set a, v ; self[n2r a] = n2r(v) ; end
53
+ def _nydp_keys ; keys ; end
54
+ end
data/lib/nydp/date.rb CHANGED
@@ -16,23 +16,22 @@ module Nydp
16
16
  end
17
17
  end
18
18
 
19
- def initialize ruby_date
20
- @ruby_date = ruby_date
21
- end
19
+ def initialize ruby_date ; @ruby_date = ruby_date ; end
22
20
 
23
- def to_s ; ruby_date.to_s ; end
24
- def to_ruby ; ruby_date ; end
25
- def inspect ; ruby_date.inspect ; end
26
- def nydp_type ; :date ; end
27
- def + int ; r2n(ruby_date + int , nil) ; end
28
- def > other ; is_date?(other) && ruby_date > other.ruby_date ; end
29
- def < other ; is_date?(other) && ruby_date < other.ruby_date ; end
30
- def == other ; is_date?(other) && ruby_date == other.ruby_date ; end
31
- def <=> other ; is_date?(other) && ruby_date <=> other.ruby_date ; end
32
- def eql? d ; self == d ; end
33
- def hash ; ruby_date.hash ; end
34
- def is_date? other ; other.is_a? Nydp::Date ; end
35
- def - other ; r2n(ruby_date - (is_date?(other) ? other.ruby_date : other), nil) ; end
21
+ def to_date ; ruby_date ; end
22
+ def to_s ; ruby_date.to_s ; end
23
+ def to_ruby ; ruby_date ; end
24
+ def inspect ; ruby_date.inspect ; end
25
+ def nydp_type ; :date ; end
26
+ def > other ; is_date?(other) && ruby_date > other.ruby_date ; end
27
+ def < other ; is_date?(other) && ruby_date < other.ruby_date ; end
28
+ def == other ; is_date?(other) && ruby_date == other.ruby_date ; end
29
+ def <=> other ; is_date?(other) && ruby_date <=> other.ruby_date ; end
30
+ def eql? d ; self == d ; end
31
+ def hash ; ruby_date.hash ; end
32
+ def is_date? other ; other.is_a? Nydp::Date ; end
33
+ def - other ; r2n(ruby_date - (is_date?(other) ? other.ruby_date : other)) ; end
34
+ def + int ; int.is_a?(Integer) ? r2n(ruby_date + int) : r2n(change(*int.to_ruby)) ; end
36
35
 
37
36
  @@pass_through = %i{ monday? tuesday? wednesday? thursday? friday? saturday? sunday? }
38
37
  @@keys = Set.new %i{
@@ -40,7 +39,7 @@ module Nydp
40
39
  last_year next_year beginning_of_year end_of_year
41
40
  last_month next_month beginning_of_month end_of_month
42
41
  last_week next_week beginning_of_week end_of_week
43
- yesterday tomorrow
42
+ yesterday tomorrow age
44
43
  } + @@pass_through
45
44
 
46
45
  def year y, m, d, w ; y ; end
@@ -48,15 +47,15 @@ module Nydp
48
47
  def day y, m, d, w ; d ; end
49
48
  def week_day y, m, d, w ; w ; end
50
49
 
51
- def last_year y, m, d, w ; build(y - 1, m, d) ; end
50
+ def last_year y, m, d, w ; ruby_date.prev_year ; end
52
51
  def next_year y, m, d, w ; ruby_date.next_year ; end
53
52
  def beginning_of_year y, m, d, w ; build(y, 1, 1) ; end
54
53
  def end_of_year y, m, d, w ; build(y, 12, 31) ; end
55
54
 
56
- def last_month y, m, d, w ; build(y, m - 1, d) ; end
55
+ def last_month y, m, d, w ; ruby_date.prev_month ; end
57
56
  def next_month y, m, d, w ; ruby_date.next_month ; end
58
57
  def beginning_of_month y, m, d, w ; build(y, m, 1) ; end
59
- def end_of_month y, m, d, w ; build(y, m, 31) ; end
58
+ def end_of_month y, m, d, w ; beginning_of_month(*splat(ruby_date.next_month)) - 1 ; end
60
59
 
61
60
  def last_week y, m, d, w ; ruby_date - 7 ; end
62
61
  def next_week y, m, d, w ; ruby_date + 7 ; end
@@ -66,21 +65,28 @@ module Nydp
66
65
  def yesterday y, m, d, w ; ruby_date - 1 ; end
67
66
  def tomorrow y, m, d, w ; ruby_date + 1 ; end
68
67
 
68
+ def age y,m,d,w # args not used
69
+ interval = (::Date.today - ruby_date) / 365.0
70
+ age_in_years = interval.to_i
71
+ extra_months = (12 * (interval - age_in_years)).to_i
72
+ { years: age_in_years, months: extra_months }
73
+ end
74
+
69
75
  @@pass_through.each do |n|
70
76
  class_eval "def #{n} * ; ruby_date.#{n} ; end"
71
77
  end
72
78
 
73
- def keys ; @@keys ; end
74
- def dispatch key, y, m, d, w ; self.send(key, y, m, d, w) if keys.include?(key) ; end
75
-
76
- def [] key
77
- key = key.to_s.gsub(/-/, '_').to_sym
78
- y = ruby_date.year
79
- m = ruby_date.month
80
- d = ruby_date.day
81
- w = ruby_date.wday
82
-
83
- r2n(dispatch(key, y, m, d, w), nil)
79
+ def _nydp_keys ; @@keys.to_a ; end
80
+ def dispatch key, y, m, d, w ; self.send(key, y, m, d, w) if _nydp_keys.include?(key) ; end
81
+ def splat date ; [date.year, date.month, date.day, date.wday] ; end
82
+ def lookup key, date ; r2n(dispatch(key.to_s.gsub(/-/, '_').to_sym, *splat(date))) ; end
83
+ def _nydp_get key ; lookup key, ruby_date ; end
84
+ def change amount, attr
85
+ if attr == :day ; (ruby_date + amount)
86
+ elsif attr == :week ; (ruby_date + (7 * amount))
87
+ elsif attr == :month ; (ruby_date >> amount)
88
+ elsif attr == :year ; (ruby_date >> (12 * amount))
89
+ end
84
90
  end
85
91
  end
86
92
  end
@@ -13,9 +13,8 @@ module Nydp
13
13
 
14
14
  class Base
15
15
  include Helper
16
- def initialize source_expression, sig=nil
17
- @source_expression = source_expression
18
- @sig = sig
16
+ def initialize expr, source, sig=nil
17
+ @expr, @source, @sig = expr, source, sig
19
18
  end
20
19
 
21
20
  def handle e, f, invoker, *args
@@ -24,7 +23,7 @@ module Nydp
24
23
  raise
25
24
  else
26
25
  if e.is_a?(NoMethodError) && !f.respond_to?(invoker)
27
- raise InvocationFailed.new("#{f.inspect} is not a function: args were #{args.inspect}")
26
+ raise InvocationFailed.new("#{f.inspect} is not a function: args were #{args.inspect} in #{source.inspect}")
28
27
  else
29
28
  msg = args.map { |a| " #{a.inspect}"}.join("\n")
30
29
  msg = "failed to execute invocation #{f.inspect}\n#{msg}"
@@ -35,9 +34,14 @@ module Nydp
35
34
  end
36
35
  end
37
36
 
38
- def inspect ; source.inspect ; end
39
- def source ; @source_expression ; end
40
- def to_s ; source.to_s ; end
37
+ # TODO: speed up compilation by writing custom #lexical_reach for sig-based subclasses (when you know which elements of #expr are lexical symbols)
38
+ def lexical_reach n
39
+ @expr.map { |x| x.lexical_reach n}.max
40
+ end
41
+
42
+ def inspect ; @expr.map { |x| x.inspect }.join(' ') ; end
43
+ def source ; @source ; end
44
+ def to_s ; source.to_s ; end
41
45
  end
42
46
 
43
47
  class Invocation_1 < Invocation::Base
@@ -87,8 +91,8 @@ module Nydp
87
91
  end
88
92
 
89
93
  class Invocation_N < Invocation::Base
90
- def initialize arg_count, source_expression
91
- super source_expression
94
+ def initialize arg_count, expr, source
95
+ super expr, source
92
96
  @arg_count = arg_count
93
97
  end
94
98
 
@@ -107,7 +111,7 @@ module Nydp
107
111
  class Invocation_LEX < Invocation::Base
108
112
  SIGS << self.name
109
113
  def initialize expr, src
110
- super src
114
+ super expr, src
111
115
  @sym = expr.car
112
116
  end
113
117
 
@@ -122,7 +126,7 @@ module Nydp
122
126
  class Invocation_SYM < Invocation::Base
123
127
  SIGS << self.name
124
128
  def initialize expr, src
125
- super src
129
+ super expr, src
126
130
  @sym = expr.car
127
131
  end
128
132
 
@@ -137,7 +141,7 @@ module Nydp
137
141
  class Invocation_LEX_LEX < Invocation::Base
138
142
  SIGS << self.name
139
143
  def initialize expr, src
140
- super src
144
+ super expr, src
141
145
  @lex0 = expr.car
142
146
  @lex1 = expr.cdr.car
143
147
  end
@@ -155,7 +159,7 @@ module Nydp
155
159
  class Invocation_SYM_LEX < Invocation::Base
156
160
  SIGS << self.name
157
161
  def initialize expr, src
158
- super src
162
+ super expr, src
159
163
  @sym = expr.car
160
164
  @lex = expr.cdr.car
161
165
  end
@@ -172,7 +176,7 @@ module Nydp
172
176
  class Invocation_SYM_LIT < Invocation::Base
173
177
  SIGS << self.name
174
178
  def initialize expr, src
175
- super src
179
+ super expr, src
176
180
  @sym = expr.car
177
181
  @lit = expr.cdr.car.expression
178
182
  end
@@ -188,7 +192,7 @@ module Nydp
188
192
  class Invocation_LEX_LEX_LEX < Invocation::Base
189
193
  SIGS << self.name
190
194
  def initialize expr, src
191
- super src
195
+ super expr, src
192
196
  @lex_0 = expr.car
193
197
  @lex_1 = expr.cdr.car
194
198
  @lex_2 = expr.cdr.cdr.car
@@ -208,7 +212,7 @@ module Nydp
208
212
  class Invocation_SYM_LEX_LEX < Invocation::Base
209
213
  SIGS << self.name
210
214
  def initialize expr, src
211
- super src
215
+ super expr, src
212
216
  @sym = expr.car
213
217
  @lex_0 = expr.cdr.car
214
218
  @lex_1 = expr.cdr.cdr.car
@@ -227,7 +231,7 @@ module Nydp
227
231
  class Invocation_SYM_LEX_LEX_LEX < Invocation::Base
228
232
  SIGS << self.name
229
233
  def initialize expr, src
230
- super src
234
+ super expr, src
231
235
  @sym = expr.car
232
236
  @lex_0 = expr.cdr.car
233
237
  @lex_1 = expr.cdr.cdr.car
@@ -248,7 +252,7 @@ module Nydp
248
252
  class Invocation_SYM_LEX_LIT_LEX < Invocation::Base
249
253
  SIGS << self.name
250
254
  def initialize expr, src
251
- super src
255
+ super expr, src
252
256
  @sym = expr.car
253
257
  @lex_0 = expr.cdr.car
254
258
  @lit_1 = expr.cdr.cdr.car.expression
@@ -268,7 +272,7 @@ module Nydp
268
272
  class Invocation_SYM_LIT_LEX < Invocation::Base
269
273
  SIGS << self.name
270
274
  def initialize expr, src
271
- super src
275
+ super expr, src
272
276
  @sym = expr.car
273
277
  @lit_0 = expr.cdr.car.expression
274
278
  @lex_1 = expr.cdr.cdr.car
@@ -288,6 +292,10 @@ module Nydp
288
292
  extend Helper
289
293
  attr_accessor :function_instruction, :argument_instructions
290
294
 
295
+ def lexical_reach n
296
+ function_instruction.car.lexical_reach(n)
297
+ end
298
+
291
299
  def self.build expression, bindings
292
300
  compiled = Compiler.compile_each(expression, bindings)
293
301
  invocation_sig = compiled.map { |x| sig x }.join("_")
@@ -303,15 +311,15 @@ module Nydp
303
311
 
304
312
  invocation = cons case expression.size
305
313
  when 1
306
- Invocation::Invocation_1.new(expression)
314
+ Invocation::Invocation_1.new(compiled, expression)
307
315
  when 2
308
- Invocation::Invocation_2.new(expression)
316
+ Invocation::Invocation_2.new(compiled, expression)
309
317
  when 3
310
- Invocation::Invocation_3.new(expression)
318
+ Invocation::Invocation_3.new(compiled, expression)
311
319
  when 4
312
- Invocation::Invocation_4.new(expression)
320
+ Invocation::Invocation_4.new(compiled, expression)
313
321
  else
314
- Invocation::Invocation_N.new(expression.size, expression)
322
+ Invocation::Invocation_N.new(expression.size, compiled, expression)
315
323
  end
316
324
  new invocation, compiled, expression, cname
317
325
  end
@@ -327,7 +335,7 @@ module Nydp
327
335
  vm.push_ctx_instructions argument_instructions
328
336
  end
329
337
 
330
- def inspect ; @source.inspect ; end
331
- def to_s ; @source.to_s ; end
338
+ def inspect ; @function_instruction.inspect ; end
339
+ def to_s ; @source.to_s ; end
332
340
  end
333
341
  end
data/lib/nydp/hash.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  class Nydp::Hash < ::Hash
2
2
  include Nydp::Helper
3
3
 
4
- def nydp_type ; :hash ; end
5
- def to_ruby
6
- h = Hash.new
7
- self.each { |k,v| h[n2r k] = n2r v }
8
- h
9
- end
4
+ def nydp_type ; :hash ; end
5
+ def to_ruby ; each_with_object({}) {|(k,v),h| h[n2r k] = n2r v} ; end
6
+ def _nydp_get a ; self[a] ; end
7
+ def _nydp_set a, v ; self[a] = v ; end
8
+ def _nydp_keys ; keys ; end
10
9
  end
data/lib/nydp/helper.rb CHANGED
@@ -1,34 +1,50 @@
1
1
  module Nydp
2
- R2NHELPERS = {
3
- ::Symbol => ->(obj, ns) { Nydp::Symbol.mk(obj, ns) },
4
- Array => ->(obj, ns) { Nydp::Pair.from_list obj.map { |o| Nydp.r2n o, ns } },
5
- String => ->(obj, ns) { Nydp::StringAtom.new obj.to_s },
6
- NilClass => ->(obj, ns) { Nydp::NIL },
7
- FalseClass => ->(obj, ns) { Nydp::NIL },
8
- TrueClass => ->(obj, ns) { Nydp::T },
9
- ::Date => ->(obj, ns) { Nydp::Date.new obj },
10
- }
11
-
12
- def self.n2r nydp
13
- nydp.respond_to?(:to_ruby) ? nydp.to_ruby : nydp
2
+ module AutoWrap
3
+ # include this and be sure to either override #_nydp_ok? or #_nydp_whitelist
4
+ # #_nydp_whitelist should return a list of accessor (zero-arg) methods which are safe for nydp to invoke
5
+ # #_nydp_procify should return a list of methods that can be exposed to script code.
6
+ #
7
+ # class Blub
8
+ # _nydp_procs << :blubme
9
+ # def blubme where, when
10
+ # puts "blubme #{where}, #{when}"
11
+ # end
12
+ # end
13
+ #
14
+ # in nydp, if blub is an instance of Blub:
15
+ #
16
+ # (blub.blubme "here" "now")
17
+ #
18
+ # prints
19
+ #
20
+ # blubme here, now
21
+ #
22
+ def _nydp_wrapper ; self ; end
23
+ def _nydp_ok? method ; _nydp_whitelist.include? method ; end
24
+ def _nydp_procify? method ; _nydp_procs.include? method ; end # override to allow returning Method instances for given method name
25
+ def _nydp_get key ; _nydp_safe_send(key.to_s.as_method_name) ; end
26
+ def to_ruby ; self ; end
27
+ def _nydp_safe_send meth, *args
28
+ return send meth, *args if _nydp_ok?(meth)
29
+ return method(meth) if _nydp_procify?(meth)
30
+ end
14
31
  end
15
32
 
16
- def self.r2n ruby_obj, ns
17
- return ruby_obj._nydp_wrapper(ns) if ruby_obj.respond_to? :_nydp_wrapper
18
-
19
- rklass = ruby_obj.class
20
- R2NHELPERS.each do |hklass, proc|
21
- if rklass <= hklass
22
- return proc.call ruby_obj, ns
23
- end
24
- end
33
+ class Struct < ::Struct
34
+ include AutoWrap
35
+ def _nydp_whitelist ; members ; end
36
+ def _nydp_procs ; [] ; end
37
+ end
25
38
 
26
- ruby_obj
39
+ module Converter
40
+ def n2r o ; o.respond_to?(:to_ruby) ? o.to_ruby : o ; end
41
+ def r2n o, ns=nil ; o._nydp_wrapper ; end
27
42
  end
28
43
 
44
+ extend Converter
45
+
29
46
  module Helper
30
- def n2r obj ; Nydp.n2r obj ; end
31
- def r2n obj, ns ; Nydp.r2n obj, ns ; end
47
+ include Converter
32
48
 
33
49
  def sig klass
34
50
  case klass
@@ -67,7 +83,7 @@ module Nydp
67
83
 
68
84
  def literal? expr
69
85
  case expr
70
- when String, Float, Integer, Fixnum, Nydp::Symbol, Nydp::StringAtom, Nydp::Truth, Nydp::Nil
86
+ when String, Float, Integer, Integer, Nydp::Symbol, Nydp::Truth, Nydp::Nil
71
87
  true
72
88
  else
73
89
  false
@@ -5,8 +5,8 @@ require 'nydp/closure'
5
5
  module Nydp
6
6
  class PopArg
7
7
  def self.execute vm ; vm.args.pop ; end
8
- def self.to_s ; "" ; end
9
- def self.inspect ; "#pop_arg" ; end
8
+ def self.to_s ; "" ; end
9
+ def self.inspect ; "#pop_arg" ; end
10
10
  end
11
11
 
12
12
  class InterpretedFunction
@@ -16,42 +16,22 @@ module Nydp
16
16
 
17
17
  attr_accessor :arg_names, :body, :context_builder
18
18
 
19
- def invoke_1 vm, parent_context
20
- vm.push_instructions self.body, set_args_0(parent_context)
21
- end
22
-
23
- def invoke_2 vm, parent_context, arg
24
- vm.push_instructions self.body, set_args_1(parent_context, arg)
25
- end
26
-
27
- def invoke_3 vm, parent_context, arg_0, arg_1
28
- vm.push_instructions self.body, set_args_2(parent_context, arg_0, arg_1)
29
- end
30
-
31
- def invoke_4 vm, parent_context, arg_0, arg_1, arg_2
32
- vm.push_instructions self.body, set_args_3(parent_context, arg_0, arg_1, arg_2)
33
- end
34
-
35
- def invoke vm, parent_context, arg_values
36
- vm.push_instructions self.body, set_args(parent_context, arg_values)
37
- end
38
-
39
- def setup_context context, names, values
40
- if pair? names
41
- context.set names.car, values.car
42
- setup_context context, names.cdr, values.cdr
43
- elsif NIL != names
44
- context.set names, values
45
- end
19
+ def lexical_reach n
20
+ body.map { |b| b.lexical_reach(n - 1) }.max
46
21
  end
47
22
 
48
23
  def self.build arg_list, body, bindings
49
24
  my_params = { }
50
25
  index_parameters arg_list, my_params
51
- ifn = Nydp::InterpretedFunction.new
26
+ body = compile_body body, cons(my_params, bindings), []
27
+ reach = body.map { |b| b.lexical_reach(-1) }.max
28
+
29
+ ifn_klass = reach >= 0 ? InterpretedFunctionWithClosure : InterpretedFunctionWithoutClosure
30
+ ifn = ifn_klass.new
52
31
  ifn.arg_names = arg_list
32
+ ifn.body = body
33
+
53
34
  ifn.extend Nydp::LexicalContextBuilder.select arg_list
54
- ifn.body = compile_body body, cons(my_params, bindings), []
55
35
  ifn
56
36
  end
57
37
 
@@ -62,6 +42,11 @@ module Nydp
62
42
  if Nydp::NIL.is? rest
63
43
  return Pair.from_list(instructions)
64
44
  else
45
+ # PopArg is necessary because each expression pushes an arg onto the arg stack.
46
+ # we only need to keep the arg pushed by the last expression in a function
47
+ # so we need the following line in order to remove unwanted args from the stack.
48
+ # Each expression at some executes vm.push_arg(thing)
49
+ # TODO find a more intelligent way to do this, eg change the meaning of vm or of push_arg in the expression vm.push_arg(thing)
65
50
  instructions << PopArg
66
51
  compile_body rest, bindings, instructions
67
52
  end
@@ -76,19 +61,62 @@ module Nydp
76
61
  end
77
62
  end
78
63
 
79
- def execute vm
80
- # TODO do not create a new Closure if this function does not refer to it
81
- # - including top-level function definitions
82
- # - and any other function that does not refer to any lexically-bound outer variable
83
- # - for example (fn (x) (* x x)) in (map λx(* x x) things) does not need a closure, because
84
- # the function does not refer to any lexical variable outside itself.
85
- vm.push_arg Closure.new(self, vm.current_context)
86
- end
87
-
88
64
  def nydp_type ; "fn" ; end
89
65
  def inspect ; to_s ; end
90
66
  def to_s
91
67
  "(fn #{arg_names.inspect} #{body.map { |b| b.inspect}.join(' ')})"
92
68
  end
93
69
  end
70
+
71
+ class InterpretedFunctionWithClosure < InterpretedFunction
72
+ def invoke_1 vm, ctx
73
+ vm.push_instructions self.body, set_args_0(ctx)
74
+ end
75
+
76
+ def invoke_2 vm, ctx, arg
77
+ vm.push_instructions self.body, set_args_1(ctx, arg)
78
+ end
79
+
80
+ def invoke_3 vm, ctx, arg_0, arg_1
81
+ vm.push_instructions self.body, set_args_2(ctx, arg_0, arg_1)
82
+ end
83
+
84
+ def invoke_4 vm, ctx, arg_0, arg_1, arg_2
85
+ vm.push_instructions self.body, set_args_3(ctx, arg_0, arg_1, arg_2)
86
+ end
87
+
88
+ def invoke vm, ctx, arg_values
89
+ vm.push_instructions self.body, set_args(ctx, arg_values)
90
+ end
91
+
92
+ def execute vm
93
+ vm.push_arg Closure.new(self, vm.current_context)
94
+ end
95
+ end
96
+
97
+ class InterpretedFunctionWithoutClosure < InterpretedFunction
98
+ def invoke_1 vm
99
+ vm.push_instructions self.body, set_args_0(vm.current_context)
100
+ end
101
+
102
+ def invoke_2 vm, arg
103
+ vm.push_instructions self.body, set_args_1(vm.current_context, arg)
104
+ end
105
+
106
+ def invoke_3 vm, arg_0, arg_1
107
+ vm.push_instructions self.body, set_args_2(vm.current_context, arg_0, arg_1)
108
+ end
109
+
110
+ def invoke_4 vm, arg_0, arg_1, arg_2
111
+ vm.push_instructions self.body, set_args_3(vm.current_context, arg_0, arg_1, arg_2)
112
+ end
113
+
114
+ def invoke vm, arg_values
115
+ vm.push_instructions self.body, set_args(vm.current_context, arg_values)
116
+ end
117
+
118
+ def execute vm
119
+ vm.push_arg self
120
+ end
121
+ end
94
122
  end