yadriggy 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +108 -0
- data/Rakefile +10 -0
- data/lib/yadriggy.rb +32 -0
- data/lib/yadriggy/algebra.rb +497 -0
- data/lib/yadriggy/ast.rb +1839 -0
- data/lib/yadriggy/ast_location.rb +73 -0
- data/lib/yadriggy/ast_value.rb +428 -0
- data/lib/yadriggy/c.rb +11 -0
- data/lib/yadriggy/c/c.rb +220 -0
- data/lib/yadriggy/c/codegen.rb +481 -0
- data/lib/yadriggy/c/config.rb +51 -0
- data/lib/yadriggy/c/ctype.rb +118 -0
- data/lib/yadriggy/c/ctypecheck.rb +449 -0
- data/lib/yadriggy/c/ffi.rb +301 -0
- data/lib/yadriggy/c/opencl.rb +458 -0
- data/lib/yadriggy/c/program.rb +86 -0
- data/lib/yadriggy/c1.rb +10 -0
- data/lib/yadriggy/checker.rb +216 -0
- data/lib/yadriggy/eval.rb +200 -0
- data/lib/yadriggy/eval_all.rb +159 -0
- data/lib/yadriggy/pretty_print.rb +492 -0
- data/lib/yadriggy/printer.rb +82 -0
- data/lib/yadriggy/ruby_typecheck.rb +468 -0
- data/lib/yadriggy/ruby_typeinfer.rb +335 -0
- data/lib/yadriggy/source_code.rb +168 -0
- data/lib/yadriggy/syntax.rb +524 -0
- data/lib/yadriggy/type.rb +754 -0
- data/lib/yadriggy/typecheck.rb +277 -0
- data/lib/yadriggy/version.rb +5 -0
- data/yadriggy.gemspec +33 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: aa5e75505e86183390b717e3559e79528a06dab1
|
4
|
+
data.tar.gz: 6103b4d010e666693876526d6e425ae1bccf6a21
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cc3de4fdd6886598cefb8cfac86c8423cd5dda187d124b94495feae4bfd998d60f0f4d269cb659026bfa62625199ab284de67ec3690cc497004f0f7ff0fb0679
|
7
|
+
data.tar.gz: cd047b260fe5e66c1775f1532a51cfaf321304b309187ac7214d3d5f5110b05eead8f8806f91a6a810e84a4a361fd76778b36164eff4dbc9cee395c61f120522
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018- Shigeru Chiba
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# Yadriggy
|
2
|
+
|
3
|
+
Yadriggy (mistletoe in Japanese) is a library for building a
|
4
|
+
domain-specific language (DSL) embedded in Ruby. It was developed for
|
5
|
+
a particular kind of embedded DSLs, which we call hemiparasitic DSLs.
|
6
|
+
These DSLs borrow the syntax from the host language, Ruby, and the
|
7
|
+
code written in the DSLs is embedded in normal Ruby code. However,
|
8
|
+
the execution of the DSL code is independent of Ruby. Its semantics
|
9
|
+
can be totally different from Ruby and the code can be run out of the
|
10
|
+
Ruby VM. Hemiparasitic DSLs look like Ruby but they are different
|
11
|
+
languages except their syntax.
|
12
|
+
They parasitize Ruby by borrowing the syntax but their parasitism is
|
13
|
+
hemi; their execution engines are their own.
|
14
|
+
|
15
|
+
For details, the documentation is available from [Wiki](https://github.com/csg-tokyo/yadriggy/wiki).
|
16
|
+
|
17
|
+
## Hemiparasitic DSLs
|
18
|
+
|
19
|
+
A typical example of hemiparasitic DSL is computation offloading from
|
20
|
+
Ruby. For example, Yadriggy provides a simple DSL to offload
|
21
|
+
from Ruby to native C language.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'yadriggy/c'
|
25
|
+
|
26
|
+
include Yadriggy::C::CType
|
27
|
+
|
28
|
+
def fib(n) ! Integer
|
29
|
+
typedecl n: Integer
|
30
|
+
if n > 1
|
31
|
+
return fib(n - 1) + fib(n - 2)
|
32
|
+
else
|
33
|
+
return 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
puts Yadriggy::C.run { return fib(32) }
|
38
|
+
```
|
39
|
+
|
40
|
+
When this code is run, the block given to `Yadriggy::C.run` is
|
41
|
+
translated into C code with the definition of `fib` method.
|
42
|
+
Then the C code is compiled into a dynamic library, loaded the
|
43
|
+
library through ruby-ffi, and executed. Since the block given to
|
44
|
+
`run` calls `fib`, the definition of `fib` is also translated
|
45
|
+
into C.
|
46
|
+
|
47
|
+
An external variable is accessible from the compiled block:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
n = 32
|
51
|
+
puts Yadriggy::C.run { return fib(n) }
|
52
|
+
```
|
53
|
+
|
54
|
+
The argument to `fib` is take from the variable `n` that exists
|
55
|
+
outside of the block. `n` is passed to the compiled block by _copying_.
|
56
|
+
It is not passed by _reference_. Thus, when a new value is assigned to
|
57
|
+
`n` within the compiled block, it is not visible from the Ruby code.
|
58
|
+
The variable `n` in the Ruby code keeps the old value.
|
59
|
+
|
60
|
+
Note that the definition of `fib` contains type declarations
|
61
|
+
since this DSL is not Ruby.
|
62
|
+
A hemiparasitic DSL looks like Ruby but it is a different language.
|
63
|
+
`! Integer` following `def fib(n)` specifies the return type.
|
64
|
+
`typedecl` specifies the types of the parameters (and local variables
|
65
|
+
if any). In this DSL, most types have to be statically given
|
66
|
+
although the DSL performs simple type inference and some types
|
67
|
+
can be omitted.
|
68
|
+
|
69
|
+
## Library
|
70
|
+
|
71
|
+
Yadriggy provides a method for obtaining the abstract syntax tree (AST)
|
72
|
+
of the given method, lambda, or Proc.
|
73
|
+
It also provides a syntax checker that determines whether or not an AST
|
74
|
+
satisfies the syntax described in the BNF-like language, which is
|
75
|
+
a DSL embedded in Ruby by Yadriggy.
|
76
|
+
|
77
|
+
You can even obtain the AST of a piece of source code:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
require 'yadriggy'
|
81
|
+
ast = Yadriggy.reify {|a| a + 1 }
|
82
|
+
```
|
83
|
+
|
84
|
+
`reify` returns the AST of the given block `{|a| a + 1 }`.
|
85
|
+
It takes not only a block but also a `Method` or `Proc` object.
|
86
|
+
|
87
|
+
The idea of `reify` was proposed in the following paper:
|
88
|
+
|
89
|
+
- Shigeru Chiba, YungYu Zhuang, Maximilian Scherr, "Deeply Reifying Running Code for Constructing a Domain-Specific Language", PPPJ'16, Article No. 1, ACM, August 2016.
|
90
|
+
|
91
|
+
## Installation
|
92
|
+
|
93
|
+
To install, run:
|
94
|
+
|
95
|
+
$ gem install yadriggy
|
96
|
+
|
97
|
+
or, download this repository and run:
|
98
|
+
|
99
|
+
$ bundle exec rake install
|
100
|
+
|
101
|
+
## Contributing
|
102
|
+
|
103
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/csg-tokyo/yadriggy.
|
104
|
+
|
105
|
+
|
106
|
+
## License
|
107
|
+
|
108
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/lib/yadriggy.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
require 'yadriggy/version'
|
4
|
+
|
5
|
+
require 'yadriggy/source_code'
|
6
|
+
require 'yadriggy/ast'
|
7
|
+
require 'yadriggy/ast_value'
|
8
|
+
require 'yadriggy/ast_location'
|
9
|
+
require 'yadriggy/eval'
|
10
|
+
require 'yadriggy/eval_all'
|
11
|
+
require 'yadriggy/algebra'
|
12
|
+
require 'yadriggy/syntax'
|
13
|
+
require 'yadriggy/checker'
|
14
|
+
require 'yadriggy/typecheck'
|
15
|
+
require 'yadriggy/ruby_typecheck'
|
16
|
+
require 'yadriggy/ruby_typeinfer'
|
17
|
+
require 'yadriggy/printer'
|
18
|
+
require 'yadriggy/pretty_print'
|
19
|
+
|
20
|
+
module Yadriggy
|
21
|
+
@@debug = 0
|
22
|
+
|
23
|
+
# Current debug level (0, 1, or 2).
|
24
|
+
# @return [Integer] the current level.
|
25
|
+
def self.debug() @@debug end
|
26
|
+
|
27
|
+
# Sets the current debug level.
|
28
|
+
# @param [Integer] level.
|
29
|
+
def self.debug=(level)
|
30
|
+
@@debug = level
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,497 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
require 'yadriggy/eval'
|
4
|
+
|
5
|
+
module Yadriggy
|
6
|
+
|
7
|
+
# An interface inspired by object algebra (and tag-less final)
|
8
|
+
#
|
9
|
+
class Algebra
|
10
|
+
|
11
|
+
def initialize(expr)
|
12
|
+
EvalAlgebra.new(self).evaluate(expr)
|
13
|
+
end
|
14
|
+
|
15
|
+
def nil_value()
|
16
|
+
raise NotImplementedError.new('nil_value')
|
17
|
+
end
|
18
|
+
|
19
|
+
def name(name, line_no, column)
|
20
|
+
raise NotImplementedError.new('name')
|
21
|
+
end
|
22
|
+
|
23
|
+
def identifier_or_call(name, line_no, column)
|
24
|
+
name(name, line_no, column)
|
25
|
+
end
|
26
|
+
|
27
|
+
def identifier(name, line_no, column)
|
28
|
+
identifier_or_call(name, line_no, column)
|
29
|
+
end
|
30
|
+
|
31
|
+
def reserved(name, line_no, column)
|
32
|
+
name(name, line_no, column)
|
33
|
+
end
|
34
|
+
|
35
|
+
def const(name, line_no, column)
|
36
|
+
name(name, line_no, column)
|
37
|
+
end
|
38
|
+
|
39
|
+
def label(name, line_no, column)
|
40
|
+
name(name, line_no, column)
|
41
|
+
end
|
42
|
+
|
43
|
+
def symbol(name, line_no, column)
|
44
|
+
raise NotImplementedError.new('symbol')
|
45
|
+
end
|
46
|
+
|
47
|
+
def global_variable(name, line_no, column)
|
48
|
+
name(name, line_no, column)
|
49
|
+
end
|
50
|
+
|
51
|
+
def instance_variable(name, line_no, column)
|
52
|
+
name(name, line_no, column)
|
53
|
+
end
|
54
|
+
|
55
|
+
def variable_call(name, line_no, column)
|
56
|
+
identifier_or_call(name, line_no, column)
|
57
|
+
end
|
58
|
+
|
59
|
+
def super_method(expr)
|
60
|
+
raise NotImplementedError.new('super_method')
|
61
|
+
end
|
62
|
+
|
63
|
+
def number(value, line_no, column)
|
64
|
+
raise NotImplementedError.new('number')
|
65
|
+
end
|
66
|
+
|
67
|
+
# exprs() sequentially processes each expression in a series
|
68
|
+
# of expressions.
|
69
|
+
# So, for example, { e1, e2, ..., e_n } is
|
70
|
+
# processed by exprs(.. exprs(exprs(nil, e1), e2).., e_n).
|
71
|
+
# In other words, it is by
|
72
|
+
# [e1, e2, ..., e_n].inject(nil) {|r,e| exprs(r, evaluate(e))}.
|
73
|
+
#
|
74
|
+
# RESULT specifies the result of the previous expression.
|
75
|
+
# It is nil if EXPR is the first expression.
|
76
|
+
#
|
77
|
+
def exprs(result, expr)
|
78
|
+
raise NotImplementedError.new('exprs')
|
79
|
+
end
|
80
|
+
|
81
|
+
# CONTENTS is an array of the results of evaluating
|
82
|
+
# each component.
|
83
|
+
#
|
84
|
+
def string_interpolation(contents)
|
85
|
+
raise NotImplementedError.new('string_interpolation')
|
86
|
+
end
|
87
|
+
|
88
|
+
def string_literal(value, line_no, column)
|
89
|
+
raise NotImplementedError.new('string_literal')
|
90
|
+
end
|
91
|
+
|
92
|
+
# A constant value in a scope, such as Foo::Bar.
|
93
|
+
#
|
94
|
+
def const_path_ref(scope, name)
|
95
|
+
raise NotImplementedError.new('const_path_ref')
|
96
|
+
end
|
97
|
+
|
98
|
+
# A constant value in a scope as a L-value.
|
99
|
+
#
|
100
|
+
def const_path_field(scope, name)
|
101
|
+
const_path_ref(scope, name)
|
102
|
+
end
|
103
|
+
|
104
|
+
def unary(op, expr)
|
105
|
+
raise NotImplementedError.new('unary')
|
106
|
+
end
|
107
|
+
|
108
|
+
def binary(left, op, right)
|
109
|
+
raise NotImplementedError.new('binary')
|
110
|
+
end
|
111
|
+
|
112
|
+
def dots(left, op, right)
|
113
|
+
binary(left, op, right)
|
114
|
+
end
|
115
|
+
|
116
|
+
def assign(left, op, right)
|
117
|
+
binary(left, op, right)
|
118
|
+
end
|
119
|
+
|
120
|
+
def array_ref(array, index)
|
121
|
+
raise NotImplementedError.new('array')
|
122
|
+
end
|
123
|
+
|
124
|
+
# Array reference as L-value
|
125
|
+
#
|
126
|
+
def array_ref_field(array, index)
|
127
|
+
array_ref(array, index)
|
128
|
+
end
|
129
|
+
|
130
|
+
# An expression surrounded with ().
|
131
|
+
#
|
132
|
+
def paren(element)
|
133
|
+
raise NotImplementedError.new('paren')
|
134
|
+
end
|
135
|
+
|
136
|
+
# An array literal.
|
137
|
+
# ELEMENTS is an array.
|
138
|
+
#
|
139
|
+
def array(elements)
|
140
|
+
raise NotImplementedError.new('array')
|
141
|
+
end
|
142
|
+
|
143
|
+
# PAIRS is an array of pairs. Each pair is
|
144
|
+
# an array where the first element is a key
|
145
|
+
# and the second element is a value.
|
146
|
+
#
|
147
|
+
def hash(pairs)
|
148
|
+
raise NotImplementedError.new('hash')
|
149
|
+
end
|
150
|
+
|
151
|
+
# Method call.
|
152
|
+
# ARGS is an array. BLOCK is a thunk.
|
153
|
+
#
|
154
|
+
def call(receiver, op, name, args, block_arg, block)
|
155
|
+
raise NotImplementedError.new('call')
|
156
|
+
end
|
157
|
+
|
158
|
+
# Method call without parentheses.
|
159
|
+
# ARGS is an array. BLOCK is a thunk.
|
160
|
+
#
|
161
|
+
def command(receiver, op, name, args, block_arg, block)
|
162
|
+
call(receiver, op, name, args, block_arg, block)
|
163
|
+
end
|
164
|
+
|
165
|
+
# if, unless, modifier if/unless, and ternary if (?:)
|
166
|
+
# THEN_EXPRS is a thunk.
|
167
|
+
# ALL_ELSIF is an array of pairs of elsif condition and its body.
|
168
|
+
# Both are thunks.
|
169
|
+
# ELSE_EXPRS is a thiuk or nil.
|
170
|
+
#
|
171
|
+
def conditional(op, cond, then_exprs, all_elsif, else_exprs)
|
172
|
+
raise NotImplementedError.new('conditional')
|
173
|
+
end
|
174
|
+
|
175
|
+
# while, until, and modifier while/until.
|
176
|
+
# COND and BODY are thunks.
|
177
|
+
#
|
178
|
+
def loop(op, cond, body)
|
179
|
+
raise NotImplementedError.new('loop')
|
180
|
+
end
|
181
|
+
|
182
|
+
# for loop.
|
183
|
+
# BODY is a thunk.
|
184
|
+
#
|
185
|
+
def for_loop(var, set, body)
|
186
|
+
raise NotImplementedError.new('for_loop')
|
187
|
+
end
|
188
|
+
|
189
|
+
# break, next, redo, retry.
|
190
|
+
#
|
191
|
+
def break_out(op, values)
|
192
|
+
raise NotImplementedError.new('break_out')
|
193
|
+
end
|
194
|
+
|
195
|
+
# An expression with return.
|
196
|
+
#
|
197
|
+
def return_values(values)
|
198
|
+
raise NotImplementedError.new('return_values')
|
199
|
+
end
|
200
|
+
|
201
|
+
# A block.
|
202
|
+
# BODY is a thunk.
|
203
|
+
#
|
204
|
+
def block(params, optionals, rest_params, params_after_rest, keywords,
|
205
|
+
rest_of_keywords, block_param, body)
|
206
|
+
raise NotImplementedError.new('block')
|
207
|
+
end
|
208
|
+
|
209
|
+
# A lambda expression.
|
210
|
+
# BODY is a thunk.
|
211
|
+
#
|
212
|
+
def lambda_expr(params, optionals, rest_params, params_after_rest,
|
213
|
+
keywords, rest_of_keywords, block_param, body)
|
214
|
+
block(params, optionals, rest_params, params_after_rest,
|
215
|
+
keywords, rest_of_keywords, block_param, body)
|
216
|
+
end
|
217
|
+
|
218
|
+
# rescue-else-ensure-end.
|
219
|
+
# BODY, NESTED_RESCUE, ELSE_CLAUSE, and ENSURE_CLAUSE are
|
220
|
+
# thunks.
|
221
|
+
#
|
222
|
+
def rescue_end(types, parameter, body, nested_rescue,
|
223
|
+
else_clause, ensure_clause)
|
224
|
+
raise NotImplementedError.new('rescue_end')
|
225
|
+
end
|
226
|
+
|
227
|
+
def begin_end(body, rescue_clause)
|
228
|
+
raise NotImplementedError.new('begin_end')
|
229
|
+
end
|
230
|
+
|
231
|
+
# def.
|
232
|
+
#
|
233
|
+
# BODY and RESCUE_CLAUSE are thunks.
|
234
|
+
#
|
235
|
+
def define(name, params, optionals, rest_of_params, params_after_rest,
|
236
|
+
keywords, rest_of_keywords, block_param,
|
237
|
+
body, rescue_clause)
|
238
|
+
raise NotImplementedError.new('define')
|
239
|
+
end
|
240
|
+
|
241
|
+
def module_def(name, body, rescue_clause)
|
242
|
+
raise NotImplementedError.new('module_def')
|
243
|
+
end
|
244
|
+
|
245
|
+
def class_def(name, superclass, body, rescue_clause)
|
246
|
+
raise NotImplementedError.new('class_def')
|
247
|
+
end
|
248
|
+
|
249
|
+
def singular_class_def(name, body, rescue_clause)
|
250
|
+
raise NotImplementedError.new('singular_class_def')
|
251
|
+
end
|
252
|
+
|
253
|
+
# A whole program.
|
254
|
+
#
|
255
|
+
# ELEMENTS is the result of processing the program elements.
|
256
|
+
#
|
257
|
+
def program(elements)
|
258
|
+
raise NotImplementedError.new('program')
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# evaluator for Algebra
|
263
|
+
#
|
264
|
+
class EvalAlgebra < Eval
|
265
|
+
def initialize(algebra)
|
266
|
+
@algebra = algebra
|
267
|
+
end
|
268
|
+
|
269
|
+
def nil_value(expr)
|
270
|
+
@algebra.nil_value
|
271
|
+
end
|
272
|
+
|
273
|
+
def name(expr)
|
274
|
+
raise 'should never happen'
|
275
|
+
end
|
276
|
+
|
277
|
+
def identifier(expr)
|
278
|
+
@algebra.identifier(expr.name, expr.line_no, expr.column)
|
279
|
+
end
|
280
|
+
|
281
|
+
def reserved(expr)
|
282
|
+
@algebra.reserved(expr.name, expr.line_no, expr.column)
|
283
|
+
end
|
284
|
+
|
285
|
+
def const(expr)
|
286
|
+
@algebra.const(expr.name, expr.line_no, expr.column)
|
287
|
+
end
|
288
|
+
|
289
|
+
def label(expr)
|
290
|
+
@algebra.label(expr.name, expr.line_no, expr.column)
|
291
|
+
end
|
292
|
+
|
293
|
+
def symbol(expr)
|
294
|
+
@algebra.symbol(expr.name, expr.line_no, expr.column)
|
295
|
+
end
|
296
|
+
|
297
|
+
def global_variable(expr)
|
298
|
+
@algebra.global_variable(expr.name, expr.line_no, expr.column)
|
299
|
+
end
|
300
|
+
|
301
|
+
def instance_variable(expr)
|
302
|
+
@algebra.instance_variable(expr.name, expr.line_no, expr.column)
|
303
|
+
end
|
304
|
+
|
305
|
+
def variable_call(expr)
|
306
|
+
@algebra.variable_call(expr.name, expr.line_no, expr.column)
|
307
|
+
end
|
308
|
+
|
309
|
+
def super_method(expr) @algebra.super_method end
|
310
|
+
|
311
|
+
def number(expr)
|
312
|
+
@algebra.number(expr.value, expr.line_no, expr.column)
|
313
|
+
end
|
314
|
+
|
315
|
+
def exprs(expr)
|
316
|
+
expr.expressions.inject(nil) do |result, e|
|
317
|
+
@algebra.exprs(result, evaluate(e))
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def paren(expr)
|
322
|
+
@algebra.paren(evaluate(expr.expression))
|
323
|
+
end
|
324
|
+
|
325
|
+
def array(expr)
|
326
|
+
@algebra.array(expr.elements.map {|e| evaluate(e)})
|
327
|
+
end
|
328
|
+
|
329
|
+
def string_interpolation(expr)
|
330
|
+
@algebra.string_interpolation(expr.contents.map {|e| evaluate(e) })
|
331
|
+
end
|
332
|
+
|
333
|
+
def string_literal(expr)
|
334
|
+
@algebra.string_literal(expr.value, expr.line_no, expr.column)
|
335
|
+
end
|
336
|
+
|
337
|
+
def const_path_ref(expr)
|
338
|
+
@algebra.const_path_ref(expr.scope, expr.name)
|
339
|
+
end
|
340
|
+
|
341
|
+
def const_path_field(expr)
|
342
|
+
@algebra.const_path_field(expr.scope, expr.name)
|
343
|
+
end
|
344
|
+
|
345
|
+
def unary(expr)
|
346
|
+
@algebra.unary(expr.op, evaluate(expr.expr))
|
347
|
+
end
|
348
|
+
|
349
|
+
def binary(expr)
|
350
|
+
@algebra.binary(evaluate(expr.left), expr.op, evaluate(expr.right))
|
351
|
+
end
|
352
|
+
|
353
|
+
def dots(expr)
|
354
|
+
@algebra.dots(evaluate(expr.left), expr.op, evaluate(expr.right))
|
355
|
+
end
|
356
|
+
|
357
|
+
def assign(expr)
|
358
|
+
@algebra.assign(evaluate(expr.left), expr.op, evaluate(expr.right))
|
359
|
+
end
|
360
|
+
|
361
|
+
def array_ref(expr)
|
362
|
+
@algebra.array_ref(evaluate(expr.array),
|
363
|
+
expr.indexes.map {|e| evaluate(e) })
|
364
|
+
end
|
365
|
+
|
366
|
+
def array_ref_field(expr)
|
367
|
+
@algebra.array_ref_field(evaluate(expr.array),
|
368
|
+
expr.indexes.map {|e| evaluate(e) })
|
369
|
+
end
|
370
|
+
|
371
|
+
def hash(expr)
|
372
|
+
@algebra.hash(expr.pairs.map {|p| p.map {|e| evaluate(e) }})
|
373
|
+
end
|
374
|
+
|
375
|
+
def call(expr)
|
376
|
+
@algebra.call(evaluate(expr.receiver), expr.op, expr.name,
|
377
|
+
expr.args.map {|e| evaluate(e) },
|
378
|
+
evaluate(expr.block_arg),
|
379
|
+
lambda { evaluate(expr.block) })
|
380
|
+
end
|
381
|
+
|
382
|
+
def command(expr)
|
383
|
+
@algebra.command(evaluate(expr.receiver), expr.op, expr.name,
|
384
|
+
expr.args.map {|e| evaluate(e) },
|
385
|
+
evaluate(expr.block_arg),
|
386
|
+
lambda { evaluate(expr.block) })
|
387
|
+
end
|
388
|
+
|
389
|
+
def conditional(expr)
|
390
|
+
@algebra.conditional(expr.op, evaluate(expr.cond),
|
391
|
+
lambda { evaluate(expr.then) },
|
392
|
+
expr.all_elsif.map do |e|
|
393
|
+
[lambda { evaluate(e[0]) },
|
394
|
+
lambda { evaluate(e[1]) }]
|
395
|
+
end,
|
396
|
+
if expr.else.nil?
|
397
|
+
nil
|
398
|
+
else
|
399
|
+
lambda { evaluate(expr.else) }
|
400
|
+
end)
|
401
|
+
end
|
402
|
+
|
403
|
+
def loop(expr)
|
404
|
+
@algebra.loop(expr.op, lambda { evaluate(expr.cond) },
|
405
|
+
lambda { evaluate(expr.body) })
|
406
|
+
end
|
407
|
+
|
408
|
+
def for_loop(expr)
|
409
|
+
@algebra.for_loop(expr.vars, evaluate(expr.set),
|
410
|
+
lambda { evaluate(expr.body) })
|
411
|
+
end
|
412
|
+
|
413
|
+
def break_out(expr)
|
414
|
+
@algebra.break_out(expr.op, expr.values.map {|e| evaluate(e) })
|
415
|
+
end
|
416
|
+
|
417
|
+
def return_values(expr)
|
418
|
+
@algebra.return_values(expr.values.map {|e| evaluate(e) })
|
419
|
+
end
|
420
|
+
|
421
|
+
def block(expr)
|
422
|
+
@algebra.block(expr.params, expr.optionals, expr.rest_of_params,
|
423
|
+
expr.params_after_rest, expr.keywords,
|
424
|
+
expr.rest_of_keywords,
|
425
|
+
expr.block_param, lambda { evaluate(expr.body) })
|
426
|
+
end
|
427
|
+
|
428
|
+
def lambda_expr(expr)
|
429
|
+
@algebra.lambda_expr(expr.params, expr.optionals, expr.rest_of_params,
|
430
|
+
expr.params_after_rest, expr.keywords,
|
431
|
+
expr.rest_of_keywords,
|
432
|
+
expr.block_param, lambda { evaluate(expr.body) })
|
433
|
+
end
|
434
|
+
|
435
|
+
def rescue_end(expr)
|
436
|
+
@algebra.rescue_end(expr.types, expr.parameter,
|
437
|
+
lambda { evaluate(expr.body) },
|
438
|
+
lambda { evaluate(expr.nested_rescue) },
|
439
|
+
lambda { evaluate(expr.else) },
|
440
|
+
lambda { evaluate(expr.ensure) })
|
441
|
+
end
|
442
|
+
|
443
|
+
def begin_end(expr)
|
444
|
+
@algebra.begin_end(lambda { evaluate(expr.body) },
|
445
|
+
if expr.rescue.nil?
|
446
|
+
nil
|
447
|
+
else
|
448
|
+
lambda { evaluate(expr.rescue) }
|
449
|
+
end)
|
450
|
+
end
|
451
|
+
|
452
|
+
def define(expr)
|
453
|
+
@algebra.define(expr.name, expr.params, expr.optionals,
|
454
|
+
expr.rest_of_params, expr.params_after_rest,
|
455
|
+
expr.keywords, expr.rest_of_keywords,
|
456
|
+
expr.block_param, lambda { evaluate(expr.body) },
|
457
|
+
if expr.rescue.nil?
|
458
|
+
nil
|
459
|
+
else
|
460
|
+
lambda { evaluate(expr.rescue) }
|
461
|
+
end)
|
462
|
+
end
|
463
|
+
|
464
|
+
def module_def(expr)
|
465
|
+
@algebra.module_def(expr.name, lambda { evaluate(expr.body) },
|
466
|
+
if expr.rescue.nil?
|
467
|
+
nil
|
468
|
+
else
|
469
|
+
lambda { evaluate(expr.rescue) }
|
470
|
+
end)
|
471
|
+
end
|
472
|
+
|
473
|
+
def class_def(expr)
|
474
|
+
@algebra.class_def(expr.name, expr.superclass,
|
475
|
+
lambda { evaluate(expr.body) },
|
476
|
+
if expr.rescue.nil?
|
477
|
+
nil
|
478
|
+
else
|
479
|
+
lambda { evaluate(expr.rescue) }
|
480
|
+
end)
|
481
|
+
end
|
482
|
+
|
483
|
+
def singular_class_def(expr)
|
484
|
+
@algebra.singular_class_def(expr.name,
|
485
|
+
lambda { evaluate(expr.body) },
|
486
|
+
if expr.rescue.nil?
|
487
|
+
nil
|
488
|
+
else
|
489
|
+
lambda { evaluate(expr.rescue) }
|
490
|
+
end)
|
491
|
+
end
|
492
|
+
|
493
|
+
def program(expr)
|
494
|
+
@algebra.program(evaluate(expr.elements))
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|