yadriggy 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +3 -0
- data/README.md +12 -9
- data/Rakefile +5 -0
- data/lib/yadriggy.rb +1 -1
- data/lib/yadriggy/algebra.rb +31 -3
- data/lib/yadriggy/assert.rb +8 -8
- data/lib/yadriggy/ast.rb +71 -15
- data/lib/yadriggy/ast_location.rb +1 -1
- data/lib/yadriggy/c/c.rb +5 -5
- data/lib/yadriggy/c/codegen.rb +12 -27
- data/lib/yadriggy/c/config.rb +1 -1
- data/lib/yadriggy/c/ctype.rb +5 -5
- data/lib/yadriggy/c/ctypecheck.rb +6 -6
- data/lib/yadriggy/c/ffi.rb +8 -8
- data/lib/yadriggy/checker.rb +60 -26
- data/lib/yadriggy/eval.rb +5 -1
- data/lib/yadriggy/eval_all.rb +13 -0
- data/lib/yadriggy/pretty_print.rb +14 -6
- data/lib/yadriggy/py.rb +11 -0
- data/lib/yadriggy/py/codegen.rb +457 -0
- data/lib/yadriggy/py/import.rb +90 -0
- data/lib/yadriggy/py/py_typechecker.rb +62 -0
- data/lib/yadriggy/py/python.rb +130 -0
- data/lib/yadriggy/ruby_typecheck.rb +96 -45
- data/lib/yadriggy/ruby_typeinfer.rb +60 -25
- data/lib/yadriggy/source_code.rb +27 -17
- data/lib/yadriggy/syntax.rb +23 -8
- data/lib/yadriggy/type.rb +38 -38
- data/lib/yadriggy/typecheck.rb +18 -5
- data/lib/yadriggy/version.rb +1 -1
- data/yadriggy.gemspec +2 -1
- metadata +24 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f73ad8ceb3807a109ddbd4c11ddafee6f1854c32
|
4
|
+
data.tar.gz: 307556c77ee0760ddde8e55cece63d6975505ace
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0922e73e77795a2d351887d3e9a11760b4e4ec5f8fb8535a440ef6cca8c707f0ad402805aec919a8f52f58fa1ae17c7c877549a6ee44119b0b0bf73cfce8ee0
|
7
|
+
data.tar.gz: 66d4ad0cdef21663929443687fb5d3e3f3b1f57a86c00fd35f38cd1b70f691a98f9a44515da17fb222c116072ea36152a7827f042695599c66e47e9fd2f74a5f
|
data/.yardopts
ADDED
data/README.md
CHANGED
@@ -2,22 +2,23 @@
|
|
2
2
|
|
3
3
|
Yadriggy (mistletoe in Japanese) is a library for building a
|
4
4
|
domain-specific language (DSL) embedded in Ruby. It was developed for
|
5
|
-
a particular kind of embedded DSLs
|
5
|
+
a particular kind of embedded DSLs.
|
6
6
|
These DSLs borrow the syntax from the host language, Ruby, and the
|
7
7
|
code written in the DSLs is embedded in normal Ruby code. However,
|
8
8
|
the execution of the DSL code is independent of Ruby. Its semantics
|
9
9
|
can be totally different from Ruby and the code can be run out of the
|
10
|
-
Ruby VM.
|
10
|
+
Ruby VM. These DSLs look like Ruby but they are different
|
11
11
|
languages except their syntax.
|
12
|
-
They
|
13
|
-
|
12
|
+
They are embedded in Ruby by borrowing the syntax but their embedding is
|
13
|
+
outward; their execution engines are their own.
|
14
14
|
|
15
15
|
For details, the documentation is available from [Wiki](https://github.com/csg-tokyo/yadriggy/wiki).
|
16
16
|
|
17
|
-
##
|
17
|
+
## An example
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
Computation offloading from Ruby is a typical example of the DSLs
|
20
|
+
implemented by Yadriggy.
|
21
|
+
For example, Yadriggy provides a simple DSL to offload
|
21
22
|
from Ruby to native C language.
|
22
23
|
|
23
24
|
```ruby
|
@@ -30,7 +31,7 @@ def fib(n) ! Integer
|
|
30
31
|
if n > 1
|
31
32
|
return fib(n - 1) + fib(n - 2)
|
32
33
|
else
|
33
|
-
return
|
34
|
+
return n
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
@@ -59,7 +60,7 @@ The variable `n` in the Ruby code keeps the old value.
|
|
59
60
|
|
60
61
|
Note that the definition of `fib` contains type declarations
|
61
62
|
since this DSL is not Ruby.
|
62
|
-
|
63
|
+
This DSL looks like Ruby but it is a different language.
|
63
64
|
`! Integer` following `def fib(n)` specifies the return type.
|
64
65
|
`typedecl` specifies the types of the parameters (and local variables
|
65
66
|
if any). In this DSL, most types have to be statically given
|
@@ -84,6 +85,8 @@ ast = Yadriggy.reify {|a| a + 1 }
|
|
84
85
|
`reify` returns the AST of the given block `{|a| a + 1 }`.
|
85
86
|
It takes not only a block but also a `Method` or `Proc` object.
|
86
87
|
|
88
|
+
Yadriggy works with Pry and IRuby unless a syntax error occurs.
|
89
|
+
|
87
90
|
The idea of `reify` was proposed in the following paper:
|
88
91
|
|
89
92
|
- Shigeru Chiba, YungYu Zhuang, Maximilian Scherr, "Deeply Reifying Running Code for Constructing a Domain-Specific Language", PPPJ'16, Article No. 1, ACM, August 2016.
|
data/Rakefile
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rake/testtask"
|
3
|
+
require "yard"
|
3
4
|
|
4
5
|
Rake::TestTask.new(:test) do |t|
|
5
6
|
t.libs << "test"
|
@@ -7,4 +8,8 @@ Rake::TestTask.new(:test) do |t|
|
|
7
8
|
t.test_files = FileList['test/**/*_test.rb']
|
8
9
|
end
|
9
10
|
|
11
|
+
YARD::Rake::YardocTask.new do |t|
|
12
|
+
t.options = ['-m markdown', '--no-private']
|
13
|
+
end
|
14
|
+
|
10
15
|
task :default => :test
|
data/lib/yadriggy.rb
CHANGED
data/lib/yadriggy/algebra.rb
CHANGED
@@ -113,8 +113,15 @@ module Yadriggy
|
|
113
113
|
binary(left, op, right)
|
114
114
|
end
|
115
115
|
|
116
|
+
# @param [Object|Array] left the left value.
|
117
|
+
# @param [Symbol] op the operator.
|
118
|
+
# @param [Object|Array] right the right value.
|
116
119
|
def assign(left, op, right)
|
117
|
-
|
120
|
+
if left.is_a?(Array) || right.is_a?(Array)
|
121
|
+
raise NotImplementedError.new('multiple assignment')
|
122
|
+
else
|
123
|
+
binary(left, op, right)
|
124
|
+
end
|
118
125
|
end
|
119
126
|
|
120
127
|
def array_ref(array, index)
|
@@ -259,13 +266,24 @@ module Yadriggy
|
|
259
266
|
end
|
260
267
|
end
|
261
268
|
|
262
|
-
#
|
269
|
+
# Evaluator for Algebra
|
263
270
|
#
|
264
271
|
class EvalAlgebra < Eval
|
272
|
+
# Initializes.
|
273
|
+
#
|
274
|
+
# @param [Algebra] algebra
|
265
275
|
def initialize(algebra)
|
266
276
|
@algebra = algebra
|
267
277
|
end
|
268
278
|
|
279
|
+
def evaluate(expr)
|
280
|
+
if expr.nil?
|
281
|
+
nil_value(nil)
|
282
|
+
else
|
283
|
+
expr.accept(self)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
269
287
|
def nil_value(expr)
|
270
288
|
@algebra.nil_value
|
271
289
|
end
|
@@ -355,7 +373,17 @@ module Yadriggy
|
|
355
373
|
end
|
356
374
|
|
357
375
|
def assign(expr)
|
358
|
-
|
376
|
+
right = if expr.right.is_a?(Array)
|
377
|
+
expr.right.map {|e| evaluate(e) }
|
378
|
+
else
|
379
|
+
evaluate(expr.right)
|
380
|
+
end
|
381
|
+
left = if expr.left.is_a?(Array)
|
382
|
+
expr.left.map {|e| evaluate(e) }
|
383
|
+
else
|
384
|
+
evaluate(expr.left)
|
385
|
+
end
|
386
|
+
@algebra.assign(left, expr.op, right)
|
359
387
|
end
|
360
388
|
|
361
389
|
def array_ref(expr)
|
data/lib/yadriggy/assert.rb
CHANGED
@@ -22,7 +22,7 @@ module Yadriggy
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
# @private
|
25
|
+
# @api private
|
26
26
|
def self.puts_reason(reason, evar=nil)
|
27
27
|
puts '--- Yadriggy::Assert ---'
|
28
28
|
print evar.cause.class.name, ': ' if evar&.cause
|
@@ -52,13 +52,13 @@ module Yadriggy
|
|
52
52
|
|
53
53
|
# Reason that an assertion fails.
|
54
54
|
class Reason
|
55
|
-
# @private
|
55
|
+
# @api private
|
56
56
|
def setup(ast, results)
|
57
57
|
@ast = ast
|
58
58
|
@results = results
|
59
59
|
end
|
60
60
|
|
61
|
-
# Gets the AST of the block given to {
|
61
|
+
# Gets the AST of the block given to {Yadriggy::Assert::assertion}.
|
62
62
|
# @return [ASTnode] an abstract syntax tree.
|
63
63
|
def ast() @ast end
|
64
64
|
|
@@ -85,7 +85,7 @@ module Yadriggy
|
|
85
85
|
output.reverse!
|
86
86
|
end
|
87
87
|
|
88
|
-
# @private
|
88
|
+
# @api private
|
89
89
|
# @return [String] the new header.
|
90
90
|
def show2(ast, header, output)
|
91
91
|
if ast.is_a?(Paren)
|
@@ -136,7 +136,7 @@ module Yadriggy
|
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
|
-
# @private
|
139
|
+
# @api private
|
140
140
|
# Obtains the text representation of the given value.
|
141
141
|
def str_rep(v)
|
142
142
|
max = 70
|
@@ -149,7 +149,7 @@ module Yadriggy
|
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
|
-
# Exception thrown by {#assertion}.
|
152
|
+
# Exception thrown by {Yadriggy::Assert#assertion}.
|
153
153
|
#
|
154
154
|
class AssertFailure < StandardError
|
155
155
|
def initialize(reason, msg=nil, cause=nil)
|
@@ -167,7 +167,7 @@ module Yadriggy
|
|
167
167
|
def reason() @reason end
|
168
168
|
end
|
169
169
|
|
170
|
-
# @private
|
170
|
+
# @api private
|
171
171
|
# Executes the given AST and records the result.
|
172
172
|
# @param [ASTnode] ast the given AST.
|
173
173
|
# @param [Binding] blk_binding the binding for executing the AST.
|
@@ -210,7 +210,7 @@ module Yadriggy
|
|
210
210
|
end
|
211
211
|
end
|
212
212
|
|
213
|
-
# @private
|
213
|
+
# @api private
|
214
214
|
# Eval the AST by the RubyVM
|
215
215
|
# @return [Pair<String,Object>] an array. The first element is the source code
|
216
216
|
# and the second element is the resulting value.
|
data/lib/yadriggy/ast.rb
CHANGED
@@ -16,11 +16,13 @@ module Yadriggy
|
|
16
16
|
# the recorded ASTs are shared among {ASTree} objects.
|
17
17
|
# Every call to {Yadriggy#reify} on {Yadriggy} makes a new table. Hence,
|
18
18
|
#
|
19
|
-
#
|
19
|
+
# ```
|
20
|
+
# ast1 = Yadriggy.reify(proc1)
|
20
21
|
# ast2 = ast.reify(proc2)
|
21
|
-
# a1 = Yadriggy.reify(proc1)
|
22
|
+
# a1 = Yadriggy.reify(proc1) # a1 != ast1
|
22
23
|
# a2 = a1.reify(proc2) # a2 != ast2
|
23
|
-
# b2 = a1.reify(proc2) # b2 == a2
|
24
|
+
# b2 = a1.reify(proc2) # b2 == a2
|
25
|
+
# ```
|
24
26
|
#
|
25
27
|
# Although `ast1` and `a1`, and `ast2` and `a2` are different copies
|
26
28
|
# of the AST of the same proc, `a2` and `b2` refer to the same AST.
|
@@ -136,7 +138,7 @@ module Yadriggy
|
|
136
138
|
end
|
137
139
|
end
|
138
140
|
|
139
|
-
# Reserved words such self, true, and false.
|
141
|
+
# Reserved words such as self, nil, true, and false.
|
140
142
|
#
|
141
143
|
class Reserved < Name
|
142
144
|
def self.tag() :@kw end
|
@@ -324,7 +326,12 @@ module Yadriggy
|
|
324
326
|
|
325
327
|
def initialize(sexp)
|
326
328
|
if sexp[0] == :dyna_symbol
|
327
|
-
|
329
|
+
sexp2 = if sexp[1][0] == :string_content
|
330
|
+
sexp[1][1]
|
331
|
+
else
|
332
|
+
sexp[1][0]
|
333
|
+
end
|
334
|
+
init(has_tag?(sexp2, :@tstring_content))
|
328
335
|
elsif sexp[0] == :symbol_literal
|
329
336
|
init(has_tag?(sexp[1], :symbol)[1])
|
330
337
|
else
|
@@ -399,7 +406,8 @@ module Yadriggy
|
|
399
406
|
def self.tag() :paren end
|
400
407
|
|
401
408
|
def initialize(sexp)
|
402
|
-
|
409
|
+
e = if sexp[1][0].is_a?(Array) then sexp[1][0] else sexp[1] end
|
410
|
+
@expression = to_node(e)
|
403
411
|
add_child(@expression)
|
404
412
|
end
|
405
413
|
|
@@ -424,6 +432,10 @@ module Yadriggy
|
|
424
432
|
def initialize(sexp)
|
425
433
|
if sexp[1].nil?
|
426
434
|
@elements = []
|
435
|
+
elsif is_percent_literal(sexp[1])
|
436
|
+
@elements = sexp[1].map do |e|
|
437
|
+
StringInterpolation.new([:string_literal, [:string_content] + e])
|
438
|
+
end
|
427
439
|
else
|
428
440
|
@elements = to_nodes(sexp[1])
|
429
441
|
end
|
@@ -436,6 +448,15 @@ module Yadriggy
|
|
436
448
|
def accept(evaluator)
|
437
449
|
evaluator.array(self)
|
438
450
|
end
|
451
|
+
|
452
|
+
private
|
453
|
+
|
454
|
+
def is_percent_literal(sexp)
|
455
|
+
sexp.is_a?(Array) && sexp.size > 0 &&
|
456
|
+
sexp.all? do |e|
|
457
|
+
e.is_a?(Array) && e.all? {|ee| ee.is_a?(Array) }
|
458
|
+
end
|
459
|
+
end
|
439
460
|
end
|
440
461
|
|
441
462
|
# String interpolation.
|
@@ -673,25 +694,33 @@ module Yadriggy
|
|
673
694
|
end
|
674
695
|
|
675
696
|
# Assignment such as `=` and `+=`.
|
697
|
+
# `Assign#left` and `Assign#right` return an `ASTnode`,
|
698
|
+
# or an array of `ASTnode` if the node represents multiple
|
699
|
+
# assignment.
|
676
700
|
#
|
677
701
|
class Assign < Binary
|
678
|
-
def self.tags() [:assign, :opassign] end
|
702
|
+
def self.tags() [:assign, :opassign, :massign] end
|
679
703
|
|
680
704
|
def initialize(sexp)
|
681
705
|
case sexp[0]
|
682
706
|
when :assign
|
683
707
|
@left = to_node(sexp[1])
|
708
|
+
add_child(@left)
|
684
709
|
@op = :'='
|
685
|
-
|
710
|
+
init_right(sexp[2])
|
686
711
|
when :opassign
|
687
712
|
@left = to_node(sexp[1])
|
713
|
+
add_child(@left)
|
688
714
|
@op = has_tag?(sexp[2], :@op)[1].to_sym
|
689
|
-
|
715
|
+
init_right(sexp[3])
|
716
|
+
when :massign
|
717
|
+
@left = to_nodes(sexp[1])
|
718
|
+
add_children(@left)
|
719
|
+
@op = :'='
|
720
|
+
init_right(sexp[2])
|
690
721
|
else
|
691
722
|
raise "unknown assignment " + sexp[0].to_s
|
692
723
|
end
|
693
|
-
add_child(@left)
|
694
|
-
add_child(@right)
|
695
724
|
end
|
696
725
|
|
697
726
|
# A method for Visitor pattern.
|
@@ -700,6 +729,19 @@ module Yadriggy
|
|
700
729
|
def accept(evaluator)
|
701
730
|
evaluator.assign(self)
|
702
731
|
end
|
732
|
+
|
733
|
+
private
|
734
|
+
|
735
|
+
# @api private
|
736
|
+
def init_right(right_operand)
|
737
|
+
if right_operand[0] == :mrhs_new_from_args
|
738
|
+
@right = to_nodes(right_operand[1]) + [to_node(right_operand[2])]
|
739
|
+
add_children(@right)
|
740
|
+
else
|
741
|
+
@right = to_node(right_operand)
|
742
|
+
add_child(@right)
|
743
|
+
end
|
744
|
+
end
|
703
745
|
end
|
704
746
|
|
705
747
|
# Hash table.
|
@@ -792,7 +834,7 @@ module Yadriggy
|
|
792
834
|
parent, link_from_children)
|
793
835
|
end
|
794
836
|
|
795
|
-
# @private
|
837
|
+
# @api private
|
796
838
|
def initialize2(recv, op, name, args, barg, blk,
|
797
839
|
parent, link_from_children)
|
798
840
|
@receiver = recv
|
@@ -826,6 +868,12 @@ module Yadriggy
|
|
826
868
|
marg = sexp[1]
|
827
869
|
if marg[0] == :method_add_arg
|
828
870
|
initialize_method_arg(marg[1], marg[2])
|
871
|
+
elsif marg[0] == :command
|
872
|
+
initialize_call([:call, nil, nil, marg[1]])
|
873
|
+
initialize_args(marg[2]) if marg.length > 2
|
874
|
+
elsif marg[0] == :command_call
|
875
|
+
initialize_call([:call, marg[1], marg[2], marg[3]])
|
876
|
+
initialize_args(marg[4]) if marg.length > 4
|
829
877
|
else
|
830
878
|
initialize_method_arg(marg, [])
|
831
879
|
end
|
@@ -865,13 +913,21 @@ module Yadriggy
|
|
865
913
|
def initialize_call(sexp)
|
866
914
|
@receiver = to_node(sexp[1])
|
867
915
|
@op = sexp[2] # :"." or :"::" or nil.
|
868
|
-
@name =
|
916
|
+
@name = if sexp[3] == :call
|
917
|
+
nil
|
918
|
+
else
|
919
|
+
@name = to_node(has_tag?(sexp[3], :@ident))
|
920
|
+
end
|
869
921
|
add_child(@receiver)
|
870
922
|
add_child(@name)
|
871
923
|
end
|
872
924
|
|
873
925
|
def initialize_args(args_block)
|
874
|
-
args =
|
926
|
+
args = if args_block[0] == :args_add_block
|
927
|
+
args_block[1]
|
928
|
+
else
|
929
|
+
args_block
|
930
|
+
end
|
875
931
|
args2 = initialize_star_arg(args)
|
876
932
|
@args = to_nodes(args2)
|
877
933
|
@block_arg = if args_block[2]
|
@@ -1652,7 +1708,7 @@ module Yadriggy
|
|
1652
1708
|
end
|
1653
1709
|
end
|
1654
1710
|
|
1655
|
-
# @private
|
1711
|
+
# @api private
|
1656
1712
|
# A table of reified abstract syntax trees.
|
1657
1713
|
# It is used for guaranteeing the uniqueness
|
1658
1714
|
# of ASTree objects.
|
data/lib/yadriggy/c/c.rb
CHANGED
@@ -95,7 +95,7 @@ module Yadriggy
|
|
95
95
|
mod
|
96
96
|
end
|
97
97
|
|
98
|
-
# @private
|
98
|
+
# @api private
|
99
99
|
# @return [Pair<Module,Array<String>>]
|
100
100
|
def self.compile0(obj, lib_name, dir, module_name,
|
101
101
|
typechecker_class, gen_class)
|
@@ -109,7 +109,7 @@ module Yadriggy
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
-
# @private
|
112
|
+
# @api private
|
113
113
|
# @return [Pair<Module,Array<String>>]
|
114
114
|
def self.compile1(obj, lib_name, dir, module_name,
|
115
115
|
typechecker_class, gen_class)
|
@@ -141,7 +141,7 @@ module Yadriggy
|
|
141
141
|
attach_funcs(pub_methods, checker, gen, module_name, lib_name, dir)
|
142
142
|
end
|
143
143
|
|
144
|
-
# @private
|
144
|
+
# @api private
|
145
145
|
# @return [Array<ASTree>] the ASTs of compiled methods.
|
146
146
|
def self.compiled_methods(checker, method_objs)
|
147
147
|
ast = nil
|
@@ -165,7 +165,7 @@ module Yadriggy
|
|
165
165
|
return pub_methods
|
166
166
|
end
|
167
167
|
|
168
|
-
# @private
|
168
|
+
# @api private
|
169
169
|
def self.generate_funcs(ast, gen, printer)
|
170
170
|
gen.name_global_variables
|
171
171
|
gen.headers
|
@@ -185,7 +185,7 @@ module Yadriggy
|
|
185
185
|
raise BuildError.new(gen.error_messages) if gen.errors?
|
186
186
|
end
|
187
187
|
|
188
|
-
# @private
|
188
|
+
# @api private
|
189
189
|
# @return [Pair<Module,Array<String>>] the module where the methods
|
190
190
|
# are attached. The second element is method names.
|
191
191
|
def self.attach_funcs(pub_methods, checker, gen, module_name,
|