shen-ruby 0.10.0 → 0.11.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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.travis.yml +9 -3
  4. data/Gemfile +1 -4
  5. data/HISTORY.md +16 -0
  6. data/MIT_LICENSE.txt +1 -1
  7. data/README.md +25 -26
  8. data/Rakefile +3 -11
  9. data/bin/shen_test_suite.rb +15 -3
  10. data/bin/srrepl +6 -8
  11. data/lib/shen_ruby.rb +6 -1
  12. data/lib/shen_ruby/converters.rb +23 -0
  13. data/lib/shen_ruby/version.rb +1 -1
  14. data/shen-ruby.gemspec +4 -1
  15. data/shen/lib/shen_ruby/shen.rb +49 -33
  16. data/shen/release/benchmarks/N_queens.shen +45 -45
  17. data/shen/release/benchmarks/README.shen +14 -14
  18. data/shen/release/benchmarks/benchmarks.shen +52 -52
  19. data/shen/release/benchmarks/einstein.shen +32 -32
  20. data/shen/release/benchmarks/interpreter.shen +219 -219
  21. data/shen/release/benchmarks/jnk.shen +193 -193
  22. data/shen/release/benchmarks/powerset.shen +10 -10
  23. data/shen/release/benchmarks/prime.shen +10 -10
  24. data/shen/release/benchmarks/short.shen +129 -129
  25. data/shen/release/k_lambda/core.kl +181 -181
  26. data/shen/release/k_lambda/declarations.kl +131 -131
  27. data/shen/release/k_lambda/load.kl +84 -84
  28. data/shen/release/k_lambda/macros.kl +112 -112
  29. data/shen/release/k_lambda/prolog.kl +252 -252
  30. data/shen/release/k_lambda/reader.kl +222 -222
  31. data/shen/release/k_lambda/sequent.kl +166 -166
  32. data/shen/release/k_lambda/sys.kl +271 -271
  33. data/shen/release/k_lambda/t-star.kl +139 -139
  34. data/shen/release/k_lambda/toplevel.kl +135 -135
  35. data/shen/release/k_lambda/track.kl +103 -103
  36. data/shen/release/k_lambda/types.kl +324 -324
  37. data/shen/release/k_lambda/writer.kl +105 -105
  38. data/shen/release/k_lambda/yacc.kl +113 -113
  39. data/shen/release/test_programs/Chap13/problems.txt +26 -26
  40. data/shen/release/test_programs/README.shen +52 -52
  41. data/shen/release/test_programs/TinyLispFunctions.txt +15 -15
  42. data/shen/release/test_programs/TinyTypes.shen +55 -55
  43. data/shen/release/test_programs/binary.shen +24 -24
  44. data/shen/release/test_programs/bubble_version_1.shen +28 -28
  45. data/shen/release/test_programs/bubble_version_2.shen +22 -22
  46. data/shen/release/test_programs/calculator.shen +21 -21
  47. data/shen/release/test_programs/cartprod.shen +23 -23
  48. data/shen/release/test_programs/change.shen +25 -25
  49. data/shen/release/test_programs/classes-defaults.shen +94 -94
  50. data/shen/release/test_programs/classes-inheritance.shen +100 -100
  51. data/shen/release/test_programs/classes-typed.shen +74 -74
  52. data/shen/release/test_programs/classes-untyped.shen +46 -46
  53. data/shen/release/test_programs/depth_.shen +14 -14
  54. data/shen/release/test_programs/einstein.shen +34 -34
  55. data/shen/release/test_programs/fruit_machine.shen +46 -46
  56. data/shen/release/test_programs/interpreter.shen +217 -217
  57. data/shen/release/test_programs/metaprog.shen +85 -85
  58. data/shen/release/test_programs/minim.shen +192 -192
  59. data/shen/release/test_programs/mutual.shen +11 -11
  60. data/shen/release/test_programs/n_queens.shen +45 -45
  61. data/shen/release/test_programs/newton_version_1.shen +33 -33
  62. data/shen/release/test_programs/newton_version_2.shen +24 -24
  63. data/shen/release/test_programs/parse.prl +14 -14
  64. data/shen/release/test_programs/parser.shen +51 -51
  65. data/shen/release/test_programs/powerset.shen +10 -10
  66. data/shen/release/test_programs/prime.shen +10 -10
  67. data/shen/release/test_programs/prolog.shen +78 -78
  68. data/shen/release/test_programs/proof_assistant.shen +80 -80
  69. data/shen/release/test_programs/proplog_version_1.shen +25 -25
  70. data/shen/release/test_programs/proplog_version_2.shen +27 -27
  71. data/shen/release/test_programs/qmachine.shen +66 -66
  72. data/shen/release/test_programs/red-black.shen +54 -54
  73. data/shen/release/test_programs/search.shen +55 -55
  74. data/shen/release/test_programs/semantic_net.shen +44 -44
  75. data/shen/release/test_programs/spreadsheet.shen +34 -34
  76. data/shen/release/test_programs/stack.shen +27 -27
  77. data/shen/release/test_programs/streams.shen +20 -20
  78. data/shen/release/test_programs/strings.shen +57 -57
  79. data/shen/release/test_programs/structures-typed.shen +71 -71
  80. data/shen/release/test_programs/structures-untyped.shen +41 -41
  81. data/shen/release/test_programs/tests.shen +232 -232
  82. data/shen/release/test_programs/types.shen +11 -11
  83. data/shen/release/test_programs/whist.shen +239 -239
  84. data/shen/release/test_programs/yacc.shen +132 -132
  85. data/spec/shen_ruby/converters_spec.rb +48 -0
  86. data/spec/spec_helper.rb +1 -2
  87. metadata +55 -60
  88. data/k_lambda_spec/atom_spec.rb +0 -85
  89. data/k_lambda_spec/primitives/arithmetic_spec.rb +0 -175
  90. data/k_lambda_spec/primitives/assignments_spec.rb +0 -44
  91. data/k_lambda_spec/primitives/boolean_operations_spec.rb +0 -136
  92. data/k_lambda_spec/primitives/generic_functions_spec.rb +0 -120
  93. data/k_lambda_spec/primitives/lists_spec.rb +0 -40
  94. data/k_lambda_spec/primitives/strings_spec.rb +0 -77
  95. data/k_lambda_spec/primitives/symbols_spec.rb +0 -24
  96. data/k_lambda_spec/primitives/vectors_spec.rb +0 -92
  97. data/k_lambda_spec/spec_helper.rb +0 -29
  98. data/k_lambda_spec/support/shared_examples.rb +0 -124
  99. data/k_lambda_spec/tail_recursion_spec.rb +0 -30
  100. data/lib/kl.rb +0 -7
  101. data/lib/kl/absvector.rb +0 -12
  102. data/lib/kl/compiler.rb +0 -360
  103. data/lib/kl/cons.rb +0 -51
  104. data/lib/kl/empty_list.rb +0 -12
  105. data/lib/kl/environment.rb +0 -163
  106. data/lib/kl/error.rb +0 -4
  107. data/lib/kl/internal_error.rb +0 -7
  108. data/lib/kl/lexer.rb +0 -186
  109. data/lib/kl/primitives/arithmetic.rb +0 -60
  110. data/lib/kl/primitives/assignments.rb +0 -15
  111. data/lib/kl/primitives/booleans.rb +0 -21
  112. data/lib/kl/primitives/error_handling.rb +0 -13
  113. data/lib/kl/primitives/extensions.rb +0 -12
  114. data/lib/kl/primitives/generic_functions.rb +0 -29
  115. data/lib/kl/primitives/lists.rb +0 -23
  116. data/lib/kl/primitives/streams.rb +0 -28
  117. data/lib/kl/primitives/strings.rb +0 -63
  118. data/lib/kl/primitives/symbols.rb +0 -18
  119. data/lib/kl/primitives/time.rb +0 -17
  120. data/lib/kl/primitives/vectors.rb +0 -36
  121. data/lib/kl/reader.rb +0 -46
  122. data/spec/kl/cons_spec.rb +0 -12
  123. data/spec/kl/environment_spec.rb +0 -282
  124. data/spec/kl/interop_spec.rb +0 -68
  125. data/spec/kl/lexer_spec.rb +0 -149
  126. data/spec/kl/primitives/generic_functions_spec.rb +0 -29
  127. data/spec/kl/primitives/symbols_spec.rb +0 -21
  128. data/spec/kl/reader_spec.rb +0 -42
data/lib/kl/compiler.rb DELETED
@@ -1,360 +0,0 @@
1
- module Kl
2
- module Compiler
3
- # The K Lambda primitives are all Ruby functions and never use
4
- # trampolines. They are all regarded as System Functions and
5
- # therefore are not allowed to be redefined by the user at
6
- # run time. Therefore, if all of their arguments have been
7
- # supplied, it is safe to directly invoke them rather than going
8
- # incurring the overhead of using __apply. This table holds the
9
- # arities of the primitives and is used to determine whether
10
- # direct invocation is possible.
11
- # Kl::Primitives::Extensions is purposely omitted from this list
12
- # so that it may be overridden by Shen.
13
- PRIMITIVE_ARITIES = {}
14
- [Kl::Primitives::Arithmetic, Kl::Primitives::Assignments,
15
- Kl::Primitives::Booleans, Kl::Primitives::ErrorHandling,
16
- Kl::Primitives::GenericFunctions, Kl::Primitives::Lists,
17
- Kl::Primitives::Streams, Kl::Primitives::Strings,
18
- Kl::Primitives::Symbols, Kl::Primitives::Time,
19
- Kl::Primitives::Vectors].each do |prim_mod|
20
- prim_mod.instance_methods.each do |name|
21
- PRIMITIVE_ARITIES[name] = prim_mod.instance_method(name).arity
22
- end
23
- end
24
-
25
- class << self
26
- def compile(form, lexical_vars, in_tail_pos)
27
- case form
28
- when Symbol
29
- if lexical_vars.has_key?(form)
30
- lexical_vars[form]
31
- else
32
- escape_symbol(form)
33
- end
34
- when String
35
- # Emit non-interpolating strings
36
- "'" + escape_string(form) + "'"
37
- when Kl::Cons
38
- compile_form(form, lexical_vars, in_tail_pos)
39
- when Kl::EmptyList
40
- "::Kl::EmptyList.instance"
41
- when Numeric
42
- form.to_s
43
- when true
44
- 'true'
45
- when false
46
- 'false'
47
- else
48
- raise Kl::InternalError, "unexpected form: #{form}"
49
- end
50
- end
51
-
52
- private
53
- def compile_form(form, lexical_vars, in_tail_pos)
54
- case form.hd
55
- when :defun
56
- compile_defun(form, lexical_vars)
57
- when :lambda
58
- compile_lambda(form, lexical_vars)
59
- when :let
60
- compile_let(form, lexical_vars, in_tail_pos)
61
- when :freeze
62
- compile_freeze(form, lexical_vars, in_tail_pos)
63
- when :type
64
- compile_type(form, lexical_vars, in_tail_pos)
65
- when :if
66
- compile_if(form, lexical_vars, in_tail_pos)
67
- when :and
68
- compile_and(form, lexical_vars, in_tail_pos)
69
- when :or
70
- compile_or(form, lexical_vars, in_tail_pos)
71
- when :cond
72
- compile_cond(form, lexical_vars, in_tail_pos)
73
- when :do
74
- compile_do(form, lexical_vars, in_tail_pos)
75
- when :"trap-error"
76
- compile_trap_error(form, lexical_vars, in_tail_pos)
77
- # cons, hd, tl, and cons? are crucial to performance and are inlined
78
- # when all of their arguments are available.
79
- when :cons
80
- compile_cons(form, lexical_vars, in_tail_pos)
81
- when :"cons?"
82
- compile_consp(form, lexical_vars, in_tail_pos)
83
- else
84
- compile_application(form, lexical_vars, in_tail_pos)
85
- end
86
- end
87
-
88
- # (defun NAME ARGS BODY)
89
- def compile_defun(form, lexical_vars)
90
- name, arglist, body = destructure_form(form, 3)
91
- unless name.kind_of? Symbol
92
- raise Kl::Error, "#{name} is not a symbol"
93
- end
94
- unless [Kl::Cons, Kl::EmptyList].include? arglist.class
95
- raise Kl::Error, "#{arglist} is not a list"
96
- end
97
- arglist.each do |arg|
98
- unless arg.kind_of? Symbol
99
- raise Kl::Error, "#{arg} is not a symbol"
100
- end
101
- end
102
- if PRIMITIVE_ARITIES.has_key?(name)
103
- raise Kl::Error, "#{name} is primitive and may not be redefined"
104
- end
105
-
106
- extended_vars = add_vars(lexical_vars, arglist.to_a)
107
-
108
- fn_name = escape_symbol(name)
109
- fn_args = arglist.map { |arg| extended_vars[arg] }.join(",")
110
- fn_body = compile(body, extended_vars, true)
111
-
112
- "(@functions[#{fn_name}] = ::Kernel.lambda { |#{fn_args}| #{fn_body}}; #{fn_name})"
113
- end
114
-
115
- # (lambda VAR BODY)
116
- def compile_lambda(form, lexical_vars)
117
- var, body = destructure_form(form, 2)
118
- unless var.kind_of? Symbol
119
- raise Kl::Error, "#{var} is not a symbol"
120
- end
121
-
122
- extended_vars = add_var(lexical_vars, var)
123
- fn_arg = extended_vars[var]
124
- fn_body = compile(body, extended_vars, true)
125
-
126
- "::Kernel.lambda { |#{fn_arg}| #{fn_body}}"
127
- end
128
-
129
- # (let VAR EXPR BODY)
130
- def compile_let(form, lexical_vars, in_tail_pos)
131
- var, expr, body = destructure_form(form, 3)
132
- unless var.kind_of? Symbol
133
- raise Kl::Error, 'first argument to let must be a symbol'
134
- end
135
-
136
- extended_vars = add_var(lexical_vars, var)
137
- bound_var = extended_vars[var]
138
- # The bound expression is evaluated in the original lexical scope
139
- bound_expr = compile(expr, lexical_vars, false)
140
- let_body = compile(body, extended_vars, in_tail_pos)
141
-
142
- "(#{bound_var} = #{bound_expr}; #{let_body})"
143
- end
144
-
145
- # (freeze EXPR)
146
- def compile_freeze(form, lexical_vars, in_tail_pos)
147
- if form.count == 2
148
- expr = destructure_form(form, 1).first
149
-
150
- body = compile(expr, lexical_vars, true)
151
-
152
- "::Kernel.lambda { #{body} }"
153
- else
154
- # Partial application falls back to normal application
155
- compile_application(form, lexical_vars, in_tail_pos)
156
- end
157
- end
158
-
159
- # (type EXPR T)
160
- def compile_type(form, lexical_vars, in_tail_pos)
161
- # Just ignore the type information for now
162
- expr, _ = destructure_form(form, 2)
163
- compile(expr, lexical_vars, in_tail_pos)
164
- end
165
-
166
- # (if TEST_EXPR TRUE_EXPR FALSE_EXPR)
167
- def compile_if(form, lexical_vars, in_tail_pos)
168
- if form.count == 4
169
- test_expr, on_true_expr, on_false_expr = destructure_form(form, 3)
170
-
171
- test_clause = compile(test_expr, lexical_vars, false)
172
- true_clause = compile(on_true_expr, lexical_vars, in_tail_pos)
173
- false_clause = compile(on_false_expr, lexical_vars, in_tail_pos)
174
-
175
- "(#{test_clause} ? #{true_clause} : #{false_clause})"
176
- else
177
- # Partial application falls back to normal application
178
- compile_application(form, lexical_vars, in_tail_pos)
179
- end
180
- end
181
-
182
- # (and EXPR1 EXPR2)
183
- def compile_and(form, lexical_vars, in_tail_pos)
184
- if form.count == 3
185
- # This is the special form case
186
- expr1, expr2 = destructure_form(form, 2)
187
- compile_if(Kl::Cons.list([:if, expr1, expr2, false]),
188
- lexical_vars, in_tail_pos)
189
- else
190
- # Partial application falls back to normal application
191
- compile_application(form, lexical_vars, in_tail_pos)
192
- end
193
- end
194
-
195
- # (or EXPR1 EXPR2)
196
- def compile_or(form, lexical_vars, in_tail_pos)
197
- if form.count == 3
198
- expr1, expr2 = destructure_form(form, 2)
199
- compile_if(Kl::Cons.list([:if, expr1, true, expr2]),
200
- lexical_vars, in_tail_pos)
201
- else
202
- # Partial application falls back to normal application
203
- compile_application(form, lexical_vars, in_tail_pos)
204
- end
205
- end
206
-
207
- def compile_cond(form, lexical_vars, in_tail_pos)
208
- clauses = form.tl
209
- if clauses.kind_of? Kl::EmptyList
210
- 'raise(::Kl::Error, "condition failure")'
211
- else
212
- clause = clauses.hd
213
- test_expr = clause.hd
214
- true_expr = clause.tl.hd
215
- false_expr = Kl::Cons.new(:cond, clauses.tl)
216
- compile_if(Kl::Cons.list([:if, test_expr, true_expr, false_expr]),
217
- lexical_vars,
218
- in_tail_pos)
219
- end
220
- end
221
-
222
- # (do EXPR1 EXPR2)
223
- # 'do' is not a K Lambda primitive, and is defined in the Shen sources as
224
- # a function that receives two arguments, and returns the last one.
225
- # 'do' being a function means that the compiler will not see EXPR2 as
226
- # being in tail-position, inhibiting TCO.
227
- # To work around this, calls to 'do' are compiled to a sequence of
228
- # expressions instead of calls to a 'do' function, by doing this, EXPR2
229
- # has the potential to be in tail position and optimized as such.
230
- def compile_do(form, lexical_vars, in_tail_pos)
231
- if form.count == 3
232
- expr1, expr2 = destructure_form(form, 2)
233
- body1 = compile(expr1, lexical_vars, false)
234
- body2 = compile(expr2, lexical_vars, in_tail_pos)
235
- "(#{body1}; #{body2})"
236
- else
237
- # Partial application falls back to normal application
238
- compile_application(form, lexical_vars, in_tail_pos)
239
- end
240
- end
241
-
242
- # (trap-error EXPR ERR_HANDLER)
243
- def compile_trap_error(form, lexical_vars, in_tail_pos)
244
- expr, err_handler = destructure_form(form, 2)
245
-
246
- # TODO: TCO for try and catch clauses
247
- try_clause = compile(expr, lexical_vars, false)
248
- extended_vars = add_var(lexical_vars, :err)
249
- err_var = extended_vars[:err]
250
- catch_clause = compile_application(
251
- Kl::Cons.list([err_handler, :err]),
252
- extended_vars,
253
- false)
254
-
255
- "(begin; #{try_clause}; rescue ::Kl::Error => #{err_var}; " +
256
- "#{catch_clause}; end)"
257
- end
258
-
259
- # Inlined version of (cons HD TL)
260
- def compile_cons(form, lexical_vars, in_tail_pos)
261
- if form.count == 3
262
- hd, tl = destructure_form(form, 2)
263
- hd_expr = compile(hd, lexical_vars, false)
264
- tl_expr = compile(tl, lexical_vars, false)
265
- "::Kl::Cons.new(#{hd_expr}, #{tl_expr})"
266
- else
267
- compile_application(form, lexical_vars, in_tail_pos)
268
- end
269
- end
270
-
271
- # Inlined version of (cons? X)
272
- def compile_consp(form, lexical_vars, in_tail_pos)
273
- if form.count == 2
274
- expr = compile(form.tl.hd, lexical_vars, false)
275
- "(#{expr}).kind_of?(::Kl::Cons)"
276
- else
277
- compile_application(form, lexical_vars, in_tail_pos)
278
- end
279
- end
280
-
281
- # Normal function application
282
- def compile_application(form, lexical_vars, in_tail_pos)
283
- f = form.hd
284
- args = form.tl
285
-
286
- if PRIMITIVE_ARITIES[f] == args.count
287
- # This is a non-partial primitive application. No need for __apply
288
- # or trampolines.
289
- send_args = form.map {|f| compile(f, lexical_vars, false)}.join(',')
290
- "send(#{send_args})"
291
- else
292
- rator = compile(f, lexical_vars, false)
293
- rands = args.map { |arg| compile(arg, lexical_vars, false) }.join(',')
294
-
295
- if in_tail_pos
296
- tfn = gen_sym
297
- targs = gen_sym
298
-
299
- "(
300
- #{tfn} = #{rator};
301
- #{targs} = [#{rands}];
302
- @tramp_fn = #{tfn};
303
- @tramp_args = #{targs}
304
- )"
305
- else
306
- "__apply(#{rator}, [#{rands}])"
307
- end
308
- end
309
- end
310
-
311
- # Escape single quotes and backslashes
312
- def escape_string(str)
313
- new_str = ""
314
- str.each_char do |c|
315
- if c == "'"
316
- new_str << "\\"
317
- new_str << "'"
318
- elsif c == '\\'
319
- new_str << '\\'
320
- new_str << '\\'
321
- else
322
- new_str << c
323
- end
324
- end
325
- new_str
326
- end
327
-
328
- def escape_symbol(sym)
329
- ':"' + sym.to_s + '"'
330
- end
331
-
332
- def destructure_form(form, expected_arg_count)
333
- array = form.to_a
334
- unless array.length == expected_arg_count + 1
335
- raise Kl::Error, "#{form.first} expects #{expected_arg_count} " +
336
- "arguments but was given #{array.length - 1}"
337
- end
338
- array[1..-1]
339
- end
340
-
341
- def add_var(scope, var)
342
- add_vars(scope, [var])
343
- end
344
-
345
- def add_vars(scope, vars)
346
- scope.dup.tap do |new_scope|
347
- vars.each do |var|
348
- new_scope[var] = gen_sym
349
- end
350
- end
351
- end
352
-
353
- def gen_sym
354
- @sym_count ||= 0
355
- @sym_count += 1
356
- "__kl_VAR_#{@sym_count}"
357
- end
358
- end
359
- end
360
- end
data/lib/kl/cons.rb DELETED
@@ -1,51 +0,0 @@
1
- require 'kl/empty_list'
2
-
3
- module Kl
4
- class Cons
5
- include Enumerable
6
-
7
- attr_reader :hd, :tl
8
-
9
- def initialize(hd, tl)
10
- @hd = hd
11
- @tl = tl
12
- end
13
-
14
- def ==(other)
15
- other.kind_of?(Kl::Cons) && hd == other.hd && tl == other.tl
16
- end
17
-
18
- def each
19
- cell = self
20
- while !cell.kind_of? Kl::EmptyList
21
- yield cell.hd
22
- cell = cell.tl
23
- end
24
- end
25
-
26
- class << self
27
- def list(array)
28
- if array.empty?
29
- Kl::EmptyList.instance
30
- else
31
- index = array.size - 1
32
- head = new(array[index], Kl::EmptyList.instance)
33
- index = index - 1
34
- while index >= 0
35
- head = new(array[index], head)
36
- index = index - 1
37
- end
38
- head
39
- end
40
- end
41
-
42
- def list_to_string(f)
43
- if f.kind_of? Kl::Cons
44
- '(' + f.map {|x| list_to_string(x)}.join(' ') + ')'
45
- else
46
- f.to_s
47
- end
48
- end
49
- end
50
- end
51
- end
data/lib/kl/empty_list.rb DELETED
@@ -1,12 +0,0 @@
1
- require 'singleton'
2
-
3
- module Kl
4
- class EmptyList
5
- include Singleton
6
- include Enumerable
7
-
8
- def each
9
- # no-op
10
- end
11
- end
12
- end
@@ -1,163 +0,0 @@
1
- require 'kl/primitives/booleans'
2
- require 'kl/primitives/symbols'
3
- require 'kl/primitives/strings'
4
- require 'kl/primitives/assignments'
5
- require 'kl/primitives/error_handling'
6
- require 'kl/primitives/lists'
7
- require 'kl/primitives/generic_functions'
8
- require 'kl/primitives/vectors'
9
- require 'kl/primitives/streams'
10
- require 'kl/primitives/time'
11
- require 'kl/primitives/arithmetic'
12
- require 'kl/primitives/extensions'
13
- require 'kl/compiler'
14
-
15
- module Kl
16
- class Environment
17
- include ::Kl::Primitives::Booleans
18
- include ::Kl::Primitives::Symbols
19
- include ::Kl::Primitives::Strings
20
- include ::Kl::Primitives::Assignments
21
- include ::Kl::Primitives::ErrorHandling
22
- include ::Kl::Primitives::Lists
23
- include ::Kl::Primitives::GenericFunctions
24
- include ::Kl::Primitives::Vectors
25
- include ::Kl::Primitives::Streams
26
- include ::Kl::Primitives::Time
27
- include ::Kl::Primitives::Arithmetic
28
- include ::Kl::Primitives::Extensions
29
-
30
- def initialize
31
- @dump_code = false
32
- @tramp_fn = @tramp_args = nil
33
- @variables = Hash.new do |_, k|
34
- raise Kl::Error, "#{k} is not a symbol" unless k.kind_of? Symbol
35
- raise Kl::Error, "variable #{k} has no value"
36
- end
37
- @functions = Hash.new do |h, k|
38
- if respond_to? k
39
- fn = method(k).to_proc
40
- h[k] = fn
41
- else
42
- raise Kl::Error, "The function #{k} is undefined"
43
- end
44
- end
45
- @eigenklass = class << self; self; end
46
- end
47
-
48
- # Trampoline-aware function application
49
- def __apply(fn, args)
50
- while fn
51
- @tramp_fn = nil
52
- fn = @functions[fn] if fn.kind_of? Symbol
53
- arity = fn.arity
54
- if arity == args.size || arity == -1
55
- result = fn.call(*args)
56
- elsif arity > args.size
57
- # Partial application
58
- result = fn.curry.call(*args)
59
- else
60
- # Uncurrying. Apply fn to its expected number of arguments
61
- # and hope that the result is a function that can be applied
62
- # to the remainder.
63
- fn = __apply(fn, args[0, arity])
64
- unless fn.kind_of?(Proc) || fn.kind_of?(Symbol)
65
- raise ::Kl::Error,
66
- "The value #{str(fn)} is neither a function nor a symbol."
67
- end
68
- args = args[arity..-1]
69
- next
70
- end
71
-
72
- if fn = @tramp_fn
73
- # Bounce on the trampoline
74
- args = @tramp_args
75
- @tramp_args = nil
76
- end
77
- end
78
- result
79
- rescue SystemStackError
80
- raise ::Kl::Error, 'maximum stack depth exceeded'
81
- end
82
-
83
- def __eval(form)
84
- if @dump_code
85
- puts "=" * 70
86
- puts "Compiling:"
87
- puts Kl::Cons.list_to_string(form)
88
- puts '-----'
89
- end
90
- code = ::Kl::Compiler.compile(form, {}, true)
91
- if @dump_code
92
- puts code
93
- puts "=" * 70
94
- end
95
- @tramp_fn = nil
96
- result = instance_eval(code)
97
- # Handle top-level trampolines
98
- if @tramp_fn
99
- fn = @tramp_fn
100
- args = @tramp_args
101
- @tramp_fn = nil
102
- @tramp_args = nil
103
- __apply(fn, args)
104
- else
105
- result
106
- end
107
- end
108
-
109
- def method_missing(f, *args)
110
- if @functions.has_key?(f)
111
- fn = @functions[f]
112
- else
113
- coerced_f = Kl::Environment.ruby_to_kl(f)
114
- if @functions.has_key?(coerced_f)
115
- fn = @functions[coerced_f]
116
- else
117
- super
118
- end
119
- end
120
- coerced_args = args.map { |arg| Kl::Environment.ruby_to_kl(arg)}
121
- Kl::Environment.kl_to_ruby(__apply(fn, coerced_args))
122
- end
123
-
124
- def respond_to?(f)
125
- @functions.has_key?(f) ||
126
- @functions.has_key?(Kl::Environment.ruby_to_kl(f)) ||
127
- super
128
- end
129
-
130
- class << self
131
- def load_file(env, path)
132
- File.open(path, 'r') do |file|
133
- reader = Kl::Reader.new(file)
134
- while form = reader.next
135
- env.__eval(form)
136
- end
137
- end
138
- end
139
-
140
- # Coerce Ruby types and conventions to K Lambda
141
- def kl_to_ruby(x)
142
- if x.kind_of? Kl::Cons
143
- x.to_a.map { |y| kl_to_ruby(y) }
144
- elsif x.kind_of? Symbol
145
- x.to_s.gsub(/-/, '_').to_sym
146
- else
147
- x
148
- end
149
- end
150
-
151
- # Coerce K Lambda types and conventions to Ruby
152
- def ruby_to_kl(x)
153
- if x.kind_of? Array
154
- Kl::Cons.list(x.map {|x| ruby_to_kl(x)})
155
- elsif x.kind_of? Symbol
156
- x.to_s.gsub(/_/, '-').to_sym
157
- else
158
- x
159
- end
160
- end
161
- end
162
- end
163
- end