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
@@ -0,0 +1,73 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
require 'yadriggy/eval_all'
|
4
|
+
|
5
|
+
# Yadriggy is a platform for building embedded DSLs.
|
6
|
+
#
|
7
|
+
# It means mistletoe in Japanese.
|
8
|
+
#
|
9
|
+
module Yadriggy
|
10
|
+
class ASTnode
|
11
|
+
|
12
|
+
# @return [String] the human-readable location of this AST node.
|
13
|
+
def source_location_string
|
14
|
+
loc = source_location
|
15
|
+
"#{loc[0]}:#{loc[1]}"
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [Array] a tuple of the file name, the line number,
|
19
|
+
# and the column of this AST node.
|
20
|
+
def source_location
|
21
|
+
g = GetLocation.new
|
22
|
+
g.evaluate(self)
|
23
|
+
if g.unknown? && !self.parent.nil?
|
24
|
+
self.parent.source_location
|
25
|
+
else
|
26
|
+
g.result(root.file_name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# @private
|
31
|
+
class GetLocation < EvalAll
|
32
|
+
def initialize
|
33
|
+
@unknown = true
|
34
|
+
@line_no = 0
|
35
|
+
@column = 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def unknown?() @unknown end
|
39
|
+
|
40
|
+
def result(file_name)
|
41
|
+
[file_name, @line_no, @column]
|
42
|
+
end
|
43
|
+
|
44
|
+
def name(expr)
|
45
|
+
super
|
46
|
+
if @unknown
|
47
|
+
@unknown = false
|
48
|
+
@line_no = expr.line_no
|
49
|
+
@column = expr.column
|
50
|
+
else
|
51
|
+
if expr.line_no < @line_no
|
52
|
+
@line_no = expr.line_no
|
53
|
+
@column = expr.column
|
54
|
+
elsif expr.line_no == @line_no && expr.column < @column
|
55
|
+
@column = expr.column
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def symbol(expr)
|
61
|
+
name(expr)
|
62
|
+
end
|
63
|
+
|
64
|
+
def number(expr)
|
65
|
+
name(expr)
|
66
|
+
end
|
67
|
+
|
68
|
+
def string_literal(expr)
|
69
|
+
name(expr)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,428 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
module Yadriggy
|
4
|
+
# Undefined value.
|
5
|
+
Undef = :undef
|
6
|
+
|
7
|
+
class ASTnode
|
8
|
+
# The value of the name represented by this AST node
|
9
|
+
# if the value is immutable. Otherwise, {Yadriggy::Undef}.
|
10
|
+
#
|
11
|
+
def const_value() Undef end
|
12
|
+
|
13
|
+
# The immutable value of the name represented by this AST node
|
14
|
+
# when it is evaluated in the context of `clazz`.
|
15
|
+
# If the value is mutable, {Yadriggy::Undef}.
|
16
|
+
#
|
17
|
+
# @param [Module] clazz the context.
|
18
|
+
def const_value_in_class(clazz) const_value end
|
19
|
+
|
20
|
+
# The runtime value of the variable, method name, etc.
|
21
|
+
# represented by this AST node.
|
22
|
+
# The default behavior returns {Yadriggy::Undef}.
|
23
|
+
# Subclasses override this method.
|
24
|
+
#
|
25
|
+
def value() Undef end
|
26
|
+
|
27
|
+
# The runtime value of this AST node
|
28
|
+
# when it is evaluated in the context of `clazz`.
|
29
|
+
#
|
30
|
+
# @param [Module] clazz the context.
|
31
|
+
def value_in_class(clazz) value end
|
32
|
+
|
33
|
+
# Gets the class including this AST node.
|
34
|
+
# @return [Module] the context.
|
35
|
+
def get_context_class
|
36
|
+
c = root.context
|
37
|
+
if c.is_a?(Proc)
|
38
|
+
c.binding.receiver.class
|
39
|
+
else # c is Method or UnboundMethod
|
40
|
+
c.owner
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Gets the receiver object.
|
45
|
+
# @return [Object] the receiver object that this proc or method
|
46
|
+
# is bound to.
|
47
|
+
def get_receiver_object
|
48
|
+
c = root.context
|
49
|
+
if c.is_a?(Proc)
|
50
|
+
c.binding.receiver
|
51
|
+
elsif c.is_a?(Method)
|
52
|
+
c.receiver
|
53
|
+
else
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Checks whether the object is a `Proc` or a method.
|
59
|
+
# @param [Object] p the tested object.
|
60
|
+
# @return [Booelan] true if `p` is a `Proc`, `Method`, or lambda object.
|
61
|
+
def is_proc?(p)
|
62
|
+
p.is_a?(Proc) || p.is_a?(Method)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Identifier
|
67
|
+
def value()
|
68
|
+
c = root.context
|
69
|
+
if c.is_a?(Proc)
|
70
|
+
if c.binding.local_variable_defined?(name)
|
71
|
+
c.binding.local_variable_get(name)
|
72
|
+
else
|
73
|
+
Undef
|
74
|
+
end
|
75
|
+
else # c is Method or UnboundMethod
|
76
|
+
Undef
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class VariableCall
|
82
|
+
# Gets an ASTree object representing the method body
|
83
|
+
# invoked by this AST node.
|
84
|
+
# Undef may be returned if the method is not found.
|
85
|
+
#
|
86
|
+
def value()
|
87
|
+
mth = invoked_method
|
88
|
+
if mth == Undef
|
89
|
+
Undef
|
90
|
+
else
|
91
|
+
root.reify(mth) || Undef
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns Undef because const_value is supposed to return
|
96
|
+
# the resulting value of executing this variable call.
|
97
|
+
#
|
98
|
+
def const_value() Undef end
|
99
|
+
|
100
|
+
# Gets a Method object called by this AST node.
|
101
|
+
# If this AST node belongs to UnboundMethod,
|
102
|
+
# Undef will be returned.
|
103
|
+
#
|
104
|
+
def invoked_method()
|
105
|
+
obj = get_receiver_object
|
106
|
+
if obj.nil?
|
107
|
+
Undef
|
108
|
+
else
|
109
|
+
begin
|
110
|
+
obj.method(@name)
|
111
|
+
rescue NameError
|
112
|
+
Undef
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Gets the resulting value of the invocation of this method.
|
118
|
+
#
|
119
|
+
def do_invocation()
|
120
|
+
obj = get_receiver_object
|
121
|
+
if obj.nil?
|
122
|
+
Undef
|
123
|
+
else
|
124
|
+
begin
|
125
|
+
obj.send(@name)
|
126
|
+
rescue NameError
|
127
|
+
Undef
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class Label
|
134
|
+
# Gets the name of this label.
|
135
|
+
#
|
136
|
+
def value() @name end
|
137
|
+
|
138
|
+
# Gets the name of this label.
|
139
|
+
#
|
140
|
+
def const_value() @name end
|
141
|
+
end
|
142
|
+
|
143
|
+
class Const
|
144
|
+
def value()
|
145
|
+
value_in_class(get_context_class)
|
146
|
+
end
|
147
|
+
|
148
|
+
def const_value() value end
|
149
|
+
|
150
|
+
def value_in_class(clazz)
|
151
|
+
if clazz.const_defined?(@name)
|
152
|
+
clazz.const_get(@name)
|
153
|
+
else
|
154
|
+
Undef
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def const_value_in_class(clazz)
|
159
|
+
value_in_class(clazz)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class Reserved
|
164
|
+
# Gets self, true, or false. Otherwise, Undef.
|
165
|
+
#
|
166
|
+
def value()
|
167
|
+
if @name == 'self'
|
168
|
+
get_receiver_object || Undef
|
169
|
+
elsif @name == 'true'
|
170
|
+
true
|
171
|
+
elsif @name == 'false'
|
172
|
+
false
|
173
|
+
else
|
174
|
+
Undef
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def const_value() value end
|
179
|
+
end
|
180
|
+
|
181
|
+
class GlobalVariable
|
182
|
+
# The current value of this global variable.
|
183
|
+
#
|
184
|
+
def value()
|
185
|
+
eval(@name)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
class InstanceVariable
|
190
|
+
def value()
|
191
|
+
if name.start_with?("@@")
|
192
|
+
clazz = get_context_class
|
193
|
+
if clazz.class_variable_defined?(name)
|
194
|
+
return clazz.class_variable_get(name)
|
195
|
+
end
|
196
|
+
elsif name.start_with?("@")
|
197
|
+
obj = get_receiver_object
|
198
|
+
if obj&.instance_variable_defined?(name)
|
199
|
+
return obj.instance_variable_get(name)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
Undef
|
204
|
+
end
|
205
|
+
|
206
|
+
def value_in_class(clazz)
|
207
|
+
if name.start_with?("@@")
|
208
|
+
if clazz.class_variable_defined?(name)
|
209
|
+
return clazz.class_variable_get(name)
|
210
|
+
else
|
211
|
+
Undef
|
212
|
+
end
|
213
|
+
else
|
214
|
+
value
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def const_value()
|
219
|
+
if name.start_with?("@@")
|
220
|
+
clazz = get_context_class
|
221
|
+
if clazz.frozen? && clazz.class_variable_defined?(name)
|
222
|
+
return clazz.class_variable_get(name)
|
223
|
+
end
|
224
|
+
elsif name.start_with?("@")
|
225
|
+
obj = get_receiver_object
|
226
|
+
if obj.frozen? && obj&.instance_variable_defined?(name)
|
227
|
+
return obj.instance_variable_get(name)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
Undef
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
class Super
|
236
|
+
# Gets an ASTree object representing the method body
|
237
|
+
# invoked by this call to super.
|
238
|
+
# Undef may be returned if the method is not found.
|
239
|
+
#
|
240
|
+
def value()
|
241
|
+
mth = invoked_method
|
242
|
+
if mth == Undef
|
243
|
+
Undef
|
244
|
+
else
|
245
|
+
root.reify(mth) || Undef
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Gets the super method (Method or UnboundMethod object) or nil.
|
250
|
+
# If this AST node is not a part of method body,
|
251
|
+
# Undef is returned.
|
252
|
+
#
|
253
|
+
def invoked_method()
|
254
|
+
mthd = root.context
|
255
|
+
if mthd.is_a?(Method) || mthd.is_a?(UnboundMethod)
|
256
|
+
mthd.super_method
|
257
|
+
else
|
258
|
+
Undef
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
class Number
|
264
|
+
# This is defined by attr_reader.
|
265
|
+
# def value() @value end
|
266
|
+
|
267
|
+
def const_value() value end
|
268
|
+
end
|
269
|
+
|
270
|
+
class ArrayLiteral
|
271
|
+
def value()
|
272
|
+
elements.map {|e| e.value }
|
273
|
+
end
|
274
|
+
|
275
|
+
def value_in_class(klass)
|
276
|
+
elements.map {|e| e.value_in_class(klass) }
|
277
|
+
end
|
278
|
+
|
279
|
+
def const_value()
|
280
|
+
elements.map {|e| e.const_value }
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
class StringLiteral
|
285
|
+
# This is defined by attr_reader.
|
286
|
+
# def value() @value end
|
287
|
+
|
288
|
+
def const_value() value end
|
289
|
+
end
|
290
|
+
|
291
|
+
class SymbolLiteral
|
292
|
+
# Gets the symbol represented by this node.
|
293
|
+
def value()
|
294
|
+
name.to_sym
|
295
|
+
end
|
296
|
+
|
297
|
+
def const_value() value end
|
298
|
+
end
|
299
|
+
|
300
|
+
class ConstPathRef
|
301
|
+
def value()
|
302
|
+
value_in_class(get_context_class)
|
303
|
+
end
|
304
|
+
|
305
|
+
def value_in_class(klass)
|
306
|
+
if scope.nil?
|
307
|
+
clazz = Object
|
308
|
+
else
|
309
|
+
clazz = scope.value_in_class(klass)
|
310
|
+
return Undef if clazz == Undef
|
311
|
+
end
|
312
|
+
|
313
|
+
unless clazz.is_a?(Module)
|
314
|
+
raise "unknown scope #{scope.class.name} #{clazz&.to_s || 'nil'}"
|
315
|
+
end
|
316
|
+
|
317
|
+
name.value_in_class(clazz)
|
318
|
+
end
|
319
|
+
|
320
|
+
def const_value() value end
|
321
|
+
|
322
|
+
def const_value_in_class(clazz)
|
323
|
+
value_in_class(clazz)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
class Unary
|
328
|
+
def value()
|
329
|
+
send_op_to_value(@expr.value)
|
330
|
+
end
|
331
|
+
|
332
|
+
def value_in_class(klass)
|
333
|
+
send_op_to_value(@expr.value_in_class(klass))
|
334
|
+
end
|
335
|
+
|
336
|
+
def const_value()
|
337
|
+
send_op_to_value(@expr.const_value)
|
338
|
+
end
|
339
|
+
|
340
|
+
def const_value_in_class(klass)
|
341
|
+
send_op_to_value(@expr.const_value_in_class(klass))
|
342
|
+
end
|
343
|
+
|
344
|
+
private
|
345
|
+
def send_op_to_value(v)
|
346
|
+
if v == Undef || is_proc?(v) || !v.class.public_method_defined?(@op)
|
347
|
+
Undef
|
348
|
+
else
|
349
|
+
v.send(@op)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
class Binary
|
355
|
+
def value()
|
356
|
+
send_op_to_value(@left.value, @right.value)
|
357
|
+
end
|
358
|
+
|
359
|
+
def value_in_class(klass)
|
360
|
+
send_op_to_value(@expr.value_in_class(klass),
|
361
|
+
@right.value_in_class(klass))
|
362
|
+
end
|
363
|
+
|
364
|
+
def const_value()
|
365
|
+
send_op_to_value(@left.const_value, @right.const_value)
|
366
|
+
end
|
367
|
+
|
368
|
+
def const_value_in_class(klass)
|
369
|
+
send_op_to_value(@expr.const_value_in_class(klass),
|
370
|
+
@right.const_value_in_class(klass))
|
371
|
+
end
|
372
|
+
|
373
|
+
private
|
374
|
+
def send_op_to_value(v, w)
|
375
|
+
if v == Undef || w == Undef || is_proc?(v) || is_proc?(w) ||
|
376
|
+
!v.class.public_method_defined?(@op)
|
377
|
+
Undef
|
378
|
+
else
|
379
|
+
v.send(@op, w)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
class Assign
|
385
|
+
def value() Undef end
|
386
|
+
|
387
|
+
def value_in_class(klass) Undef end
|
388
|
+
|
389
|
+
def const_value() Undef end
|
390
|
+
|
391
|
+
def const_value_in_class(klass) Undef end
|
392
|
+
end
|
393
|
+
|
394
|
+
class Call
|
395
|
+
# Gets the invoked method or Undef.
|
396
|
+
#
|
397
|
+
def value()
|
398
|
+
if @receiver.nil?
|
399
|
+
lookup_method(get_receiver_object)
|
400
|
+
else
|
401
|
+
lookup_method(@receiver.value)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def value_in_class(klass)
|
406
|
+
if @receiver.nil?
|
407
|
+
lookup_method(get_receiver_object)
|
408
|
+
else
|
409
|
+
lookup_method(@receiver.value_in_class(klass))
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
private
|
414
|
+
def lookup_method(obj)
|
415
|
+
if obj.nil? || obj == Undef
|
416
|
+
Undef
|
417
|
+
else
|
418
|
+
begin
|
419
|
+
obj.method(@name.name)
|
420
|
+
rescue NameError
|
421
|
+
Undef
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|