trxl 0.1.5 → 0.1.8
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.
- data/README +17 -7
- data/VERSION +1 -1
- data/lib/trxl.rb +1 -1
- data/lib/trxl/trxl.rb +181 -135
- data/lib/trxl/trxl_grammar.rb +1354 -1078
- data/lib/trxl/trxl_grammar.treetop +103 -82
- data/spec/trxl/conditionals_spec.rb +32 -18
- data/spec/trxl/ranges_spec.rb +13 -30
- data/spec/trxl/require_spec.rb +11 -11
- data/spec/trxl/stdlib_spec.rb +243 -52
- data/spec/trxl/strings_spec.rb +20 -0
- data/trxl.gemspec +34 -57
- metadata +40 -37
- data/.gitignore +0 -24
data/README
CHANGED
@@ -20,11 +20,19 @@
|
|
20
20
|
6) Built in functions:
|
21
21
|
HELP,ENV,SIZE,SPLIT,ROUND,MIN,MAX
|
22
22
|
SUM,MULT,AVG, PRINT, PRINT_LINE
|
23
|
-
TO_INT, TO_FLOAT, TO_ARRAY
|
23
|
+
TO_INT, TO_FLOAT, TO_ARRAY, AVG_SUM
|
24
|
+
MATCHING_IDS, VALUES_OF_TYPE
|
24
25
|
-----------------------------------------
|
25
26
|
7) Standard library functions:
|
26
|
-
|
27
|
-
|
27
|
+
foreach_in, inject, map, select
|
28
|
+
reject, in_groups_of, sum_of_type
|
29
|
+
avg_sum_of_type, avg_range_sum_of_type
|
30
|
+
total_range_sum_of_type, ratio
|
31
|
+
year_from_date, month_from_date,
|
32
|
+
hash_values, hash_value_sum,
|
33
|
+
avg_hash_value_sum, hash_range_values,
|
34
|
+
hash_range_value_sum,
|
35
|
+
avg_hash_range_value_sum
|
28
36
|
-----------------------------------------
|
29
37
|
8) Access the current environment:
|
30
38
|
ENV; (your output may differ)
|
@@ -129,10 +137,12 @@
|
|
129
137
|
17) case expressions:
|
130
138
|
foo = fun(x) {
|
131
139
|
case x
|
132
|
-
when
|
133
|
-
when
|
134
|
-
when
|
135
|
-
|
140
|
+
when NULL then NULL
|
141
|
+
when 0 then 0
|
142
|
+
when 1 then 1
|
143
|
+
when 2 then 2
|
144
|
+
else
|
145
|
+
3
|
136
146
|
end
|
137
147
|
}
|
138
148
|
foo(1);
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.8
|
data/lib/trxl.rb
CHANGED
data/lib/trxl/trxl.rb
CHANGED
@@ -1,65 +1,54 @@
|
|
1
|
-
|
2
|
-
# this is done independent of RAILS_ROOT to allow easy
|
3
|
-
# speccing outside of rails context
|
4
|
-
# TODO once stable, replace this with a simple require
|
1
|
+
module Trxl
|
5
2
|
|
3
|
+
class TrxlException < Exception; end
|
4
|
+
class InternalError < TrxlException; end
|
5
|
+
class FatalParseError < TrxlException; end
|
6
|
+
class DivisionByZeroError < FatalParseError; end
|
7
|
+
class MissingFormulaException < TrxlException; end
|
8
|
+
class MissingVariableException < TrxlException; end
|
9
|
+
class InvalidOperationException < TrxlException; end
|
10
|
+
class InvalidArgumentException < TrxlException; end
|
11
|
+
class WrongNumberOfArgumentsException < TrxlException; end
|
12
|
+
class MissingLibraryException < TrxlException; end
|
13
|
+
class NotImplementedException < TrxlException; end
|
14
|
+
class ExitScopeNotAllowedException < TrxlException; end
|
6
15
|
|
7
|
-
# reopen treetop generated module
|
8
|
-
module Trxl
|
9
|
-
|
10
|
-
class TrxlException < Exception; end
|
11
|
-
class InternalError < TrxlException; end
|
12
|
-
class FatalParseError < TrxlException; end
|
13
|
-
class DivisionByZeroError < FatalParseError; end
|
14
|
-
class MissingFormulaException < TrxlException; end
|
15
|
-
class MissingVariableException < TrxlException; end
|
16
|
-
class InvalidOperationException < TrxlException; end
|
17
|
-
class InvalidArgumentException < TrxlException; end
|
18
|
-
class WrongNumberOfArgumentsException < TrxlException; end
|
19
|
-
|
20
|
-
class MissingLibraryException < TrxlException; end
|
21
|
-
class NotImplementedException < TrxlException; end
|
22
|
-
|
23
|
-
class ExitScopeNotAllowedException < TrxlException; end
|
24
|
-
|
25
16
|
class Assignment < Treetop::Runtime::SyntaxNode; end
|
26
|
-
class Variable
|
27
|
-
|
28
|
-
|
29
|
-
|
17
|
+
class Variable < Treetop::Runtime::SyntaxNode; end
|
18
|
+
|
30
19
|
class Environment
|
31
|
-
|
20
|
+
|
32
21
|
# called when parsing starts
|
33
22
|
def initialize(local_env = {})
|
34
23
|
@stack = [ local_env ]
|
35
24
|
end
|
36
|
-
|
25
|
+
|
37
26
|
def enter_scope
|
38
27
|
push #peek.dup
|
39
28
|
end
|
40
|
-
|
29
|
+
|
41
30
|
def exit_scope
|
42
31
|
pop
|
43
32
|
end
|
44
|
-
|
33
|
+
|
45
34
|
def local
|
46
35
|
peek
|
47
36
|
end
|
48
|
-
|
49
|
-
|
37
|
+
|
38
|
+
|
50
39
|
def depth
|
51
40
|
@stack.size
|
52
41
|
end
|
53
|
-
|
42
|
+
|
54
43
|
def merge(other_env)
|
55
44
|
self.class.new(local.merge(other_env))
|
56
45
|
end
|
57
|
-
|
46
|
+
|
58
47
|
def merge!(other_env)
|
59
48
|
local.merge!(other_env); self
|
60
49
|
end
|
61
|
-
|
62
|
-
|
50
|
+
|
51
|
+
|
63
52
|
def [](variable)
|
64
53
|
var = variable.to_sym
|
65
54
|
@stack.each do |env|
|
@@ -76,52 +65,52 @@ module Trxl
|
|
76
65
|
# search all scopes
|
77
66
|
@stack.each do |env|
|
78
67
|
if env.has_key?(var)
|
79
|
-
return env[var] = value
|
68
|
+
return env[var] = value
|
80
69
|
end
|
81
70
|
end
|
82
71
|
# not found, assign it in local scope
|
83
72
|
local[var] = value
|
84
73
|
end
|
85
|
-
|
74
|
+
|
86
75
|
def to_s
|
87
76
|
@stack.inject([]) do |stack, env|
|
88
77
|
stack << env.inspect
|
89
78
|
end.join(',')
|
90
79
|
end
|
91
|
-
|
80
|
+
|
92
81
|
def empty?
|
93
82
|
@stack.size == 1 ? peek.empty? : @stack.all? { |h| h.empty? }
|
94
83
|
end
|
95
|
-
|
84
|
+
|
96
85
|
def has_key?(key)
|
97
86
|
@stack.any? { |env| env.has_key?(key.to_sym) }
|
98
87
|
end
|
99
|
-
|
88
|
+
|
100
89
|
def select(&block)
|
101
90
|
@stack.inject([]) do |memo, env|
|
102
91
|
memo << env.select(&block)
|
103
92
|
end[0]
|
104
93
|
end
|
105
|
-
|
94
|
+
|
106
95
|
def add_library(name)
|
107
96
|
(@libraries || []) << name.to_sym
|
108
97
|
end
|
109
|
-
|
98
|
+
|
110
99
|
def library_included?(name)
|
111
100
|
@libraries ? @libraries.include?(name.to_sym) : false
|
112
101
|
end
|
113
|
-
|
102
|
+
|
114
103
|
def libraries
|
115
104
|
@libraries.dup # don't allow modifications outside
|
116
105
|
end
|
117
|
-
|
106
|
+
|
118
107
|
protected
|
119
|
-
|
108
|
+
|
120
109
|
# called when a new scope is entered
|
121
110
|
def push(local_env = {})
|
122
111
|
@stack.insert(0, local_env)
|
123
112
|
end
|
124
|
-
|
113
|
+
|
125
114
|
# called when a scope is left
|
126
115
|
def pop
|
127
116
|
if depth > 1
|
@@ -130,16 +119,16 @@ module Trxl
|
|
130
119
|
raise Trxl::ExitScopeNotAllowedException, "cannot pop toplevel environment"
|
131
120
|
end
|
132
121
|
end
|
133
|
-
|
122
|
+
|
134
123
|
# always the local environment
|
135
124
|
def peek
|
136
125
|
@stack[0]
|
137
126
|
end
|
138
|
-
|
127
|
+
|
139
128
|
end
|
140
|
-
|
129
|
+
|
141
130
|
class Function < Treetop::Runtime::SyntaxNode
|
142
|
-
|
131
|
+
|
143
132
|
class Closure
|
144
133
|
attr_reader :env, :function
|
145
134
|
|
@@ -168,37 +157,37 @@ module Trxl
|
|
168
157
|
text_value #eval(env).to_s(env)
|
169
158
|
end
|
170
159
|
end
|
171
|
-
|
160
|
+
|
172
161
|
class BinaryOperation < Treetop::Runtime::SyntaxNode
|
173
|
-
|
162
|
+
|
174
163
|
def eval(env = Environment.new)
|
175
164
|
apply(operand_1.eval(env), operand_2.eval(env))
|
176
165
|
end
|
177
|
-
|
166
|
+
|
178
167
|
def apply(a, b)
|
179
168
|
operator.apply(a, b)
|
180
169
|
end
|
181
|
-
|
170
|
+
|
182
171
|
def to_s(env = Environment.new)
|
183
172
|
"#{operand_1.to_s(env)} #{operator.text_value} #{operand_2.to_s(env)}"
|
184
173
|
end
|
185
|
-
|
174
|
+
|
186
175
|
end
|
187
|
-
|
176
|
+
|
188
177
|
module BinaryOperatorSupport
|
189
178
|
|
190
179
|
def lhs_nil_allowed?
|
191
180
|
raise InternalError, "Implement BinaryOperaterSupport#lhs_nil_allowed?"
|
192
181
|
end
|
193
|
-
|
182
|
+
|
194
183
|
def rhs_nil_allowed?
|
195
184
|
raise InternalError, "Implement BinaryOperaterSupport#rhs_nil_allowed?"
|
196
185
|
end
|
197
|
-
|
186
|
+
|
198
187
|
def nils_allowed?
|
199
188
|
lhs_nil_allowed? && rhs_nil_allowed?
|
200
189
|
end
|
201
|
-
|
190
|
+
|
202
191
|
def apply(a, b)
|
203
192
|
if a.nil?
|
204
193
|
if b.nil?
|
@@ -224,9 +213,9 @@ module Trxl
|
|
224
213
|
else
|
225
214
|
perform_apply(a, b)
|
226
215
|
end
|
227
|
-
end
|
216
|
+
end
|
228
217
|
end
|
229
|
-
|
218
|
+
|
230
219
|
def perform_apply(a, b)
|
231
220
|
if a.respond_to?(ruby_operator)
|
232
221
|
a.send(ruby_operator, b)
|
@@ -236,52 +225,52 @@ module Trxl
|
|
236
225
|
eval "#{_a} #{ruby_operator} #{_b}"
|
237
226
|
end
|
238
227
|
end
|
239
|
-
|
228
|
+
|
240
229
|
def ruby_operator
|
241
230
|
text_value
|
242
231
|
end
|
243
|
-
|
232
|
+
|
244
233
|
end
|
245
|
-
|
234
|
+
|
246
235
|
class NilRejectingOperator < Treetop::Runtime::SyntaxNode
|
247
|
-
|
236
|
+
|
248
237
|
include BinaryOperatorSupport
|
249
|
-
|
238
|
+
|
250
239
|
def lhs_nil_allowed?
|
251
240
|
false
|
252
241
|
end
|
253
|
-
|
242
|
+
|
254
243
|
def rhs_nil_allowed?
|
255
244
|
false
|
256
245
|
end
|
257
|
-
|
246
|
+
|
258
247
|
end
|
259
|
-
|
248
|
+
|
260
249
|
class NilAcceptingOperator < Treetop::Runtime::SyntaxNode
|
261
|
-
|
250
|
+
|
262
251
|
include BinaryOperatorSupport
|
263
|
-
|
252
|
+
|
264
253
|
def lhs_nil_allowed?
|
265
254
|
true
|
266
255
|
end
|
267
|
-
|
256
|
+
|
268
257
|
def rhs_nil_allowed?
|
269
258
|
true
|
270
259
|
end
|
271
|
-
|
260
|
+
|
272
261
|
end
|
273
|
-
|
274
|
-
|
262
|
+
|
263
|
+
|
275
264
|
class OffsetAccessExpression < Treetop::Runtime::SyntaxNode
|
276
|
-
|
265
|
+
|
277
266
|
def left_associative_apply(ruby_object, offsets)
|
278
267
|
offsets.inject(ruby_object) { |obj, offset| obj = obj[offset] }
|
279
268
|
end
|
280
|
-
|
269
|
+
|
281
270
|
end
|
282
|
-
|
271
|
+
|
283
272
|
class RequireDirective < Treetop::Runtime::SyntaxNode
|
284
|
-
|
273
|
+
|
285
274
|
def eval(env = Environment.new)
|
286
275
|
library = ((l = load_library(env))[-1..-1]) == ';' ? "#{l} ENV" : "#{l}; ENV"
|
287
276
|
unless env.library_included?(identifier(env))
|
@@ -290,12 +279,12 @@ module Trxl
|
|
290
279
|
end
|
291
280
|
env
|
292
281
|
end
|
293
|
-
|
282
|
+
|
294
283
|
def identifier(env = Environment.new)
|
295
284
|
@identifier ||= string_literal.eval(env)
|
296
285
|
end
|
297
|
-
|
298
|
-
# override this in subclasses
|
286
|
+
|
287
|
+
# override this in subclasses
|
299
288
|
def load_library(env = Environment.new)
|
300
289
|
path = identifier(env).split('/')
|
301
290
|
if path[0] == ('stdlib')
|
@@ -317,28 +306,25 @@ module Trxl
|
|
317
306
|
raise NotImplementedException, "Only require 'stdlib' is supported"
|
318
307
|
end
|
319
308
|
end
|
320
|
-
|
309
|
+
|
321
310
|
def optimize_stdlib_access?
|
322
311
|
true
|
323
312
|
end
|
324
|
-
|
313
|
+
|
325
314
|
end
|
326
|
-
|
327
|
-
|
328
|
-
# This module exists only for performance reason.
|
329
|
-
# Loading the stdlib directly from a ruby object,
|
330
|
-
# should be much faster than loading it from a file.
|
331
|
-
|
315
|
+
|
332
316
|
module StdLib
|
333
|
-
|
317
|
+
|
334
318
|
FOREACH_IN = <<-PROGRAM
|
335
319
|
foreach_in = fun(enumerable, body) {
|
336
|
-
|
320
|
+
if(SIZE(enumerable) > 0)
|
321
|
+
__foreach_in__(enumerable, body, 0)
|
322
|
+
end
|
337
323
|
};
|
338
|
-
|
324
|
+
__foreach_in__ = fun(enumerable, body, index) {
|
339
325
|
if(index < SIZE(enumerable) - 1)
|
340
326
|
body(enumerable[index]);
|
341
|
-
|
327
|
+
__foreach_in__(enumerable, body, index + 1)
|
342
328
|
else
|
343
329
|
body(enumerable[index])
|
344
330
|
end
|
@@ -347,11 +333,15 @@ module Trxl
|
|
347
333
|
|
348
334
|
INJECT = <<-PROGRAM
|
349
335
|
inject = fun(memo, enumerable, body) {
|
350
|
-
|
336
|
+
if(SIZE(enumerable) > 0)
|
337
|
+
__inject__(memo, enumerable, body, 0)
|
338
|
+
else
|
339
|
+
memo
|
340
|
+
end
|
351
341
|
};
|
352
|
-
|
342
|
+
__inject__ = fun(memo, enumerable, body, index) {
|
353
343
|
if(index < SIZE(enumerable) - 1)
|
354
|
-
|
344
|
+
__inject__(body(memo, enumerable[index]), enumerable, body, index + 1)
|
355
345
|
else
|
356
346
|
body(memo, enumerable[index])
|
357
347
|
end
|
@@ -361,44 +351,44 @@ module Trxl
|
|
361
351
|
MAP = <<-PROGRAM
|
362
352
|
require 'stdlib/inject';
|
363
353
|
map = fun(enumerable, body) {
|
364
|
-
|
365
|
-
inject([], enumerable, fun(memo, e) { memo <<
|
354
|
+
__body__ = body; # WORK AROUND a bug in Trxl::Environment
|
355
|
+
inject([], enumerable, fun(memo, e) { memo << __body__(e); });
|
366
356
|
};
|
367
357
|
PROGRAM
|
368
358
|
|
369
359
|
SELECT = <<-PROGRAM
|
370
360
|
require 'stdlib/inject';
|
371
361
|
select = fun(enumerable, body) {
|
372
|
-
|
373
|
-
inject([], enumerable, fun(selected, value) {
|
374
|
-
if(
|
362
|
+
__body__ = body; # WORK AROUND a bug in Trxl::Environment
|
363
|
+
inject([], enumerable, fun(selected, value) {
|
364
|
+
if(__body__(value))
|
375
365
|
selected << value
|
376
366
|
else
|
377
367
|
selected
|
378
|
-
end
|
368
|
+
end
|
379
369
|
});
|
380
370
|
};
|
381
371
|
PROGRAM
|
382
|
-
|
372
|
+
|
383
373
|
REJECT = <<-REJECT
|
384
374
|
require 'stdlib/inject';
|
385
375
|
reject = fun(enumerable, filter) {
|
386
|
-
|
376
|
+
__filter__ = filter; # WORKAROUND for a bug in Trxl::Environment
|
387
377
|
inject([], enumerable, fun(rejected, value) {
|
388
|
-
if(
|
378
|
+
if(__filter__(value))
|
389
379
|
rejected
|
390
380
|
else
|
391
381
|
rejected << value
|
392
|
-
end
|
382
|
+
end
|
393
383
|
})
|
394
384
|
};
|
395
385
|
REJECT
|
396
|
-
|
386
|
+
|
397
387
|
IN_GROUPS_OF = <<-IN_GROUPS_OF
|
398
388
|
require 'stdlib/foreach_in';
|
399
389
|
require 'stdlib/inject';
|
400
390
|
in_groups_of = fun(size_of_group, enumerable, group_function) {
|
401
|
-
count = 0; groups = []; cur_group = [];
|
391
|
+
count = 0; groups = []; cur_group = [];
|
402
392
|
foreach_in(enumerable, fun(element) {
|
403
393
|
if(count < size_of_group)
|
404
394
|
cur_group << element;
|
@@ -418,7 +408,54 @@ module Trxl
|
|
418
408
|
});
|
419
409
|
};
|
420
410
|
IN_GROUPS_OF
|
421
|
-
|
411
|
+
|
412
|
+
HASH_VALUES = <<-HASH_VALUES
|
413
|
+
require 'stdlib/map';
|
414
|
+
hash_values = fun(hash) {
|
415
|
+
map(TO_ARRAY(hash), fun(pair) { pair[1] });
|
416
|
+
};
|
417
|
+
HASH_VALUES
|
418
|
+
|
419
|
+
HASH_VALUE_SUM = <<-VALUE_SUM
|
420
|
+
require 'stdlib/hash_values';
|
421
|
+
hash_value_sum = fun(hash) {
|
422
|
+
SUM(hash_values(hash))
|
423
|
+
};
|
424
|
+
VALUE_SUM
|
425
|
+
|
426
|
+
AVG_HASH_VALUE_SUM = <<-AVG_HASH_VALUE_SUM
|
427
|
+
require 'stdlib/hash_values';
|
428
|
+
avg_hash_value_sum = fun(hash) {
|
429
|
+
AVG_SUM(hash_values(hash))
|
430
|
+
};
|
431
|
+
AVG_HASH_VALUE_SUM
|
432
|
+
|
433
|
+
HASH_RANGE_VALUES = <<-HASH_RANGE_VALUES
|
434
|
+
require 'stdlib/foreach_in';
|
435
|
+
require 'stdlib/hash_values';
|
436
|
+
hash_range_values = fun(hash_range) {
|
437
|
+
inject([], hash_range, fun(values, hash_variable) {
|
438
|
+
values << hash_values(ENV[hash_variable]);
|
439
|
+
});
|
440
|
+
};
|
441
|
+
HASH_RANGE_VALUES
|
442
|
+
|
443
|
+
HASH_RANGE_VALUE_SUM = <<-HASH_RANGE_VALUE_SUM
|
444
|
+
require 'stdlib/hash_range_values';
|
445
|
+
hash_range_value_sum = fun(hash_range) {
|
446
|
+
SUM(hash_range_values(hash_range))
|
447
|
+
};
|
448
|
+
HASH_RANGE_VALUE_SUM
|
449
|
+
|
450
|
+
AVG_HASH_RANGE_VALUE_SUM = <<-AVG_HASH_RANGE_VALUE_SUM
|
451
|
+
require 'stdlib/hash_range_values';
|
452
|
+
avg_hash_range_value_sum = fun(hash_range) {
|
453
|
+
inject(0, hash_range_values(hash_range), fun(sum, bucket) {
|
454
|
+
sum + AVG_SUM(bucket);
|
455
|
+
});
|
456
|
+
};
|
457
|
+
AVG_HASH_RANGE_VALUE_SUM
|
458
|
+
|
422
459
|
SUM_OF_TYPE = <<-SUM_OF_TYPE
|
423
460
|
sum_of_type = fun(type, all_types, all_values) {
|
424
461
|
SUM(VALUES_OF_TYPE(type, all_types, all_values));
|
@@ -435,22 +472,31 @@ module Trxl
|
|
435
472
|
require 'stdlib/inject';
|
436
473
|
require 'stdlib/avg_sum_of_type';
|
437
474
|
avg_range_sum_of_type = fun(type, all_types, variable_range) {
|
438
|
-
inject(0, variable_range, fun(sum, variable) {
|
439
|
-
sum + avg_sum_of_type(type, all_types, ENV[variable])
|
475
|
+
inject(0, variable_range, fun(sum, variable) {
|
476
|
+
sum + avg_sum_of_type(type, all_types, ENV[variable])
|
440
477
|
});
|
441
478
|
};
|
442
479
|
AVG_RANGE_SUM_OF_TYPE
|
443
|
-
|
480
|
+
|
444
481
|
TOTAL_RANGE_SUM_OF_TYPE = <<-TOTAL_RANGE_SUM_OF_TYPE
|
445
482
|
require 'stdlib/inject';
|
446
483
|
require 'stdlib/sum_of_type';
|
447
484
|
total_range_sum_of_type = fun(type, all_types, variable_range) {
|
448
|
-
inject(0, variable_range, fun(sum, variable) {
|
449
|
-
sum + sum_of_type(type, all_types, ENV[variable])
|
485
|
+
inject(0, variable_range, fun(sum, variable) {
|
486
|
+
sum + sum_of_type(type, all_types, ENV[variable])
|
450
487
|
});
|
451
488
|
};
|
452
489
|
TOTAL_RANGE_SUM_OF_TYPE
|
453
490
|
|
491
|
+
AVG_RANGE_SUM = <<-AVG_RANGE_SUM
|
492
|
+
require 'stdlib/inject';
|
493
|
+
avg_range_sum = fun(variable_range) {
|
494
|
+
inject(0, variable_range, fun(sum, variable) {
|
495
|
+
sum + AVG_SUM(ENV[variable])
|
496
|
+
});
|
497
|
+
};
|
498
|
+
AVG_RANGE_SUM
|
499
|
+
|
454
500
|
YEAR_FROM_DATE = <<-YEAR_FROM_DATE
|
455
501
|
year_from_date = fun(date) {
|
456
502
|
date = SPLIT(date, '/');
|
@@ -469,7 +515,7 @@ module Trxl
|
|
469
515
|
require 'stdlib/month_from_date';
|
470
516
|
require 'stdlib/year_from_date';
|
471
517
|
DATES
|
472
|
-
|
518
|
+
|
473
519
|
RATIO = <<-RATIO
|
474
520
|
require 'stdlib/foreach_in';
|
475
521
|
ratio = fun(enumerable, true_condition, base_condition) {
|
@@ -492,14 +538,14 @@ module Trxl
|
|
492
538
|
RATIO
|
493
539
|
|
494
540
|
end
|
495
|
-
|
496
|
-
|
541
|
+
|
542
|
+
|
497
543
|
class Calculator
|
498
|
-
|
499
|
-
extend StdLib
|
500
|
-
|
544
|
+
|
545
|
+
extend StdLib
|
546
|
+
|
501
547
|
class << self
|
502
|
-
|
548
|
+
|
503
549
|
def stdlib(function = nil)
|
504
550
|
if function
|
505
551
|
Kernel.eval("Trxl::StdLib::#{function.to_s.upcase}").strip
|
@@ -509,7 +555,7 @@ module Trxl
|
|
509
555
|
end.strip
|
510
556
|
end
|
511
557
|
end
|
512
|
-
|
558
|
+
|
513
559
|
end
|
514
560
|
|
515
561
|
def initialize
|
@@ -523,19 +569,19 @@ module Trxl
|
|
523
569
|
ast
|
524
570
|
else
|
525
571
|
failure_idx = @parser.failure_index
|
526
|
-
|
572
|
+
|
527
573
|
# extract code snippet where parse error happened
|
528
574
|
start = ((idx = failure_idx - 12) < 0 ? 0 : idx)
|
529
575
|
stop = ((idx = failure_idx + 12) > code.size ? code.size : idx)
|
530
576
|
local_code = code.slice(start..stop).to_s.gsub(/\n|\r/, "")
|
531
|
-
|
577
|
+
|
532
578
|
msg = "Parse Error at index #{failure_idx} (showing excerpt):\n"
|
533
579
|
msg << "... #{local_code} ...\n"
|
534
|
-
|
580
|
+
|
535
581
|
# mark the exact offset where the parse error happened
|
536
582
|
offset = (start == 0) ? failure_idx + 4 : 16
|
537
583
|
offset.times { msg << ' '}; msg << "^\n"
|
538
|
-
|
584
|
+
|
539
585
|
if verbose
|
540
586
|
# show the originial trxl program
|
541
587
|
msg << "Original Code:\n#{code}\n\n"
|
@@ -559,27 +605,27 @@ module Trxl
|
|
559
605
|
end
|
560
606
|
|
561
607
|
end
|
562
|
-
|
608
|
+
|
563
609
|
class Interpreter
|
564
|
-
|
610
|
+
|
565
611
|
attr_accessor :parser, :program, :env
|
566
|
-
|
612
|
+
|
567
613
|
def initialize
|
568
614
|
@parser = Calculator.new
|
569
615
|
@program = []
|
570
616
|
@env = env
|
571
617
|
end
|
572
|
-
|
618
|
+
|
573
619
|
def stash(loc)
|
574
620
|
@program << loc
|
575
621
|
end
|
576
|
-
|
622
|
+
|
577
623
|
def eval(env = [])
|
578
624
|
@parser.eval(@program.join(' '), env)
|
579
625
|
end
|
580
|
-
|
626
|
+
|
581
627
|
end
|
582
|
-
|
628
|
+
|
583
629
|
end
|
584
630
|
|
585
631
|
|