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