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,86 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
require 'yadriggy/c/c'
|
4
|
+
require 'yadriggy/c/config'
|
5
|
+
|
6
|
+
module Yadriggy
|
7
|
+
module C
|
8
|
+
class Program
|
9
|
+
include Yadriggy::C::CType
|
10
|
+
|
11
|
+
# Compiles this class and makes a module including the
|
12
|
+
# compiled methods.
|
13
|
+
#
|
14
|
+
# @param [String] module_name the name of the module where
|
15
|
+
# methods are attached. If it is not nil, a Ruby script
|
16
|
+
# is generated. When it is executed later, the methods are
|
17
|
+
# attached to the module with `module_name`.
|
18
|
+
# The name of the generated Ruby script is `#{lib_name}.rb`.
|
19
|
+
# @param [String] lib_name the name of the generated library.
|
20
|
+
# @param [String] dir the directory name where generated files
|
21
|
+
# are stored.
|
22
|
+
# @return [Module] the module where methods are attached.
|
23
|
+
# Note that the name of this module is nil.
|
24
|
+
# It is not `method_name`.
|
25
|
+
def self.compile(module_name=nil, lib_name=nil, dir: Config::WorkDir)
|
26
|
+
obj = self.new
|
27
|
+
Yadriggy::C.compile(obj, lib_name, dir, module_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Prints arguments. This method is available from C code.
|
31
|
+
# It takes arguments as `printf` in C. For example,
|
32
|
+
# `printf('value %d', 7)` is a valid call.
|
33
|
+
# Note that the argument types are not checked.
|
34
|
+
def printf(s) ! Void
|
35
|
+
typedecl s: String, foreign: Void
|
36
|
+
puts s
|
37
|
+
end
|
38
|
+
|
39
|
+
# Gets the current time in micro sec.
|
40
|
+
# @return [Time] the current time. In C, an integer is returned.
|
41
|
+
def current_time() ! Int
|
42
|
+
typedecl native: "struct timespec time;\n\
|
43
|
+
clock_gettime(CLOCK_MONOTONIC, &time);\n\
|
44
|
+
return time.tv_sec * 1000000 + time.tv_nsec / 1000;"
|
45
|
+
Time.now * 1000000
|
46
|
+
end
|
47
|
+
|
48
|
+
# Square root function with single precision.
|
49
|
+
def sqrtf(f)
|
50
|
+
typedecl f: Float, foreign: Float
|
51
|
+
Math.sqrt(f)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Square root function.
|
55
|
+
def sqrt(f)
|
56
|
+
typedecl f: Float, foreign: Float
|
57
|
+
Math.sqrt(f)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Exponential function with single precision.
|
61
|
+
def expf(f)
|
62
|
+
typedecl f: Float, foreign: Float
|
63
|
+
Math.exp(f)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Exponential function.
|
67
|
+
def exp(f)
|
68
|
+
typedecl f: Float, foreign: Float
|
69
|
+
Math.exp(f)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Logarithm function with single precision.
|
73
|
+
def logf(f)
|
74
|
+
typedecl f: Float, foreign: Float
|
75
|
+
Math.log(f)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Logarithm function.
|
79
|
+
def log(f)
|
80
|
+
typedecl f: Float, foreign: Float
|
81
|
+
Math.log(f)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/yadriggy/c1.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
require 'yadriggy/ast'
|
4
|
+
|
5
|
+
module Yadriggy
|
6
|
+
|
7
|
+
# Exception thrown by a checker.
|
8
|
+
class CheckError < RuntimeError
|
9
|
+
end
|
10
|
+
|
11
|
+
# AST checker.
|
12
|
+
# It visits the AST nodes and does various checks like type checking.
|
13
|
+
class Checker
|
14
|
+
include Yadriggy
|
15
|
+
|
16
|
+
# Defines the rule for a node type.
|
17
|
+
#
|
18
|
+
# @param [Class] node_type the type of the AST node.
|
19
|
+
# @yield The block is executed for the node with `node_type`.
|
20
|
+
# @return [void]
|
21
|
+
def self.rule(node_type, &proc)
|
22
|
+
init_class if @rules.nil?
|
23
|
+
@rules[node_type] = proc
|
24
|
+
@rule_declarators[node_type] = self
|
25
|
+
end
|
26
|
+
|
27
|
+
# @private
|
28
|
+
# Initializes this class if necessary.
|
29
|
+
def self.check_init_class
|
30
|
+
init_class if @rules.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
# @private
|
34
|
+
# @return [Array<Hash>] all the rules defined so far.
|
35
|
+
def self.all_rules
|
36
|
+
[@rules, @rule_declarators]
|
37
|
+
end
|
38
|
+
|
39
|
+
private_class_method def self.init_class
|
40
|
+
@rules = {}
|
41
|
+
@rule_declarators = {}
|
42
|
+
unless self.superclass == Object
|
43
|
+
all = self.superclass.all_rules
|
44
|
+
unless all[0].nil?
|
45
|
+
@rules = all[0].clone
|
46
|
+
@rule_declarators = all[1].clone
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @private
|
52
|
+
# internal-use only. Don't call this.
|
53
|
+
# @return [Pair<Proc,Class>] a rule and the class declaring it, or nil.
|
54
|
+
#
|
55
|
+
def self.find_rule_entry(ast)
|
56
|
+
find_rule_entry2(ast.class, ast.usertype)
|
57
|
+
end
|
58
|
+
|
59
|
+
private_class_method def self.find_rule_entry2(ast_class, utype)
|
60
|
+
unless utype.nil?
|
61
|
+
rule = @rules[utype]
|
62
|
+
return [rule, @rule_declarators[utype]] unless rule.nil?
|
63
|
+
end
|
64
|
+
|
65
|
+
rule = @rules[ast_class]
|
66
|
+
if rule.nil?
|
67
|
+
if ast_class.superclass.nil?
|
68
|
+
nil
|
69
|
+
else
|
70
|
+
find_rule_entry2(ast_class.superclass, utype)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
[rule, @rule_declarators[ast_class]]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Initializes the object.
|
78
|
+
def initialize
|
79
|
+
self.class.check_init_class
|
80
|
+
@error = nil
|
81
|
+
@check_list = []
|
82
|
+
@current_ast = nil
|
83
|
+
@current_env = nil
|
84
|
+
@rule_declarator = nil
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [String] an error message when the last invocation of check()
|
88
|
+
# returns nil.
|
89
|
+
def error
|
90
|
+
@error || ''
|
91
|
+
end
|
92
|
+
|
93
|
+
# Applies rules to the given AST.
|
94
|
+
# It returns the result of the rule-application or throws
|
95
|
+
# a CheckError.
|
96
|
+
# This is the entry point of the checker. It may also
|
97
|
+
# check the other ASTs invoked in the given AST.
|
98
|
+
#
|
99
|
+
# @param [ASTree|ASTnode] an_ast the AST.
|
100
|
+
# @return [Object]
|
101
|
+
def check_all(an_ast)
|
102
|
+
return nil if an_ast.nil?
|
103
|
+
an_ast = an_ast.tree if an_ast.is_a?(ASTree)
|
104
|
+
t = check(an_ast, make_base_env(an_ast.get_context_class))
|
105
|
+
until (checked = @check_list.pop).nil?
|
106
|
+
@current_ast = checked[0]
|
107
|
+
@current_env = checked[1]
|
108
|
+
checked[2].call
|
109
|
+
end
|
110
|
+
t
|
111
|
+
end
|
112
|
+
|
113
|
+
# Makes a new base environment with the given context class.
|
114
|
+
# @param [Module] klass the context class.
|
115
|
+
def make_base_env(klass)
|
116
|
+
klass
|
117
|
+
end
|
118
|
+
|
119
|
+
# Applies rules to the given AST.
|
120
|
+
#
|
121
|
+
# It assumes that ast is processed by Syntax and it has usertype method.
|
122
|
+
# An exception is thrown when the checking fails.
|
123
|
+
# ast may be nil.
|
124
|
+
#
|
125
|
+
# The environment given to this method can be accessed in the rules
|
126
|
+
# through ast_env(). It is optional and can be any object.
|
127
|
+
# The initial one is made by make_base_env().
|
128
|
+
#
|
129
|
+
# @return [Object]
|
130
|
+
def check(an_ast, ast_env=nil)
|
131
|
+
if an_ast.nil?
|
132
|
+
nil
|
133
|
+
else
|
134
|
+
rule = self.class.find_rule_entry(an_ast)
|
135
|
+
apply_typing_rule(rule, an_ast, ast_env)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# @private
|
140
|
+
# internal use only
|
141
|
+
def apply_typing_rule(rule, an_ast, ast_tenv)
|
142
|
+
if rule.nil?
|
143
|
+
error_found!(an_ast, "no typing rule for #{an_ast.class}")
|
144
|
+
else
|
145
|
+
old_ast = @current_ast
|
146
|
+
old_tenv = @current_env
|
147
|
+
old_declarator = @rule_declarator
|
148
|
+
@current_ast = an_ast
|
149
|
+
@current_env = ast_tenv unless ast_tenv.nil?
|
150
|
+
@rule_declarator = rule[1]
|
151
|
+
t = instance_exec(&rule[0])
|
152
|
+
@rule_declarator = old_declarator
|
153
|
+
@current_env = old_tenv
|
154
|
+
@current_ast = old_ast
|
155
|
+
return t
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Applies the rule supplied by the superclass.
|
160
|
+
# @param [ASTnode] an_ast an AST.
|
161
|
+
# @param [Object] envi an environment object.
|
162
|
+
# @return [Type] the type of the given AST.
|
163
|
+
def proceed(an_ast, envi=nil)
|
164
|
+
rule = if @rule_declarator&.superclass == Object
|
165
|
+
nil
|
166
|
+
else
|
167
|
+
@rule_declarator&.superclass.find_rule_entry(an_ast)
|
168
|
+
end
|
169
|
+
if rule.nil?
|
170
|
+
error_found!(an_ast, 'no more rule. we cannot proceed')
|
171
|
+
else
|
172
|
+
apply_typing_rule(rule, an_ast, envi)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [ASTnode] the current abstract syntax tree.
|
177
|
+
def ast
|
178
|
+
@current_ast
|
179
|
+
end
|
180
|
+
|
181
|
+
# @return [Object] the current environment.
|
182
|
+
def ast_env
|
183
|
+
@current_env
|
184
|
+
end
|
185
|
+
|
186
|
+
# Later invokes the block, which performs checking.
|
187
|
+
# The method immediately returns.
|
188
|
+
# This is used for avoiding infinite regression during the checking.
|
189
|
+
# @yield The block is later executed for checking.
|
190
|
+
# @return [void]
|
191
|
+
def check_later(&proc)
|
192
|
+
cur_ast = @current_ast
|
193
|
+
cur_env = @current_env
|
194
|
+
@check_list << [cur_ast, cur_env, proc]
|
195
|
+
end
|
196
|
+
|
197
|
+
# @private
|
198
|
+
def error_found!(an_ast, msg='')
|
199
|
+
loc = if an_ast.is_a?(ASTnode)
|
200
|
+
an_ast.source_location_string
|
201
|
+
else
|
202
|
+
''
|
203
|
+
end
|
204
|
+
@error = "#{loc} DSL #{error_group} error. #{msg}"
|
205
|
+
binding.pry if Yadriggy.debug > 1
|
206
|
+
raise CheckError.new(@error)
|
207
|
+
end
|
208
|
+
|
209
|
+
# @private
|
210
|
+
def error_group
|
211
|
+
''
|
212
|
+
end
|
213
|
+
|
214
|
+
init_class
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
module Yadriggy
|
4
|
+
|
5
|
+
# abstract evaluator (using visitor pattern)
|
6
|
+
#
|
7
|
+
class Eval
|
8
|
+
def evaluate(expr)
|
9
|
+
if expr.nil?
|
10
|
+
nil_value(nil)
|
11
|
+
else
|
12
|
+
expr.accept(self)
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
# A root.
|
18
|
+
#
|
19
|
+
def astree(expr)
|
20
|
+
evaluate(expr.tree)
|
21
|
+
end
|
22
|
+
|
23
|
+
def nil_value(expr)
|
24
|
+
raise NotImplementedError.new('nil_value')
|
25
|
+
end
|
26
|
+
|
27
|
+
def name(expr)
|
28
|
+
raise NotImplementedError.new('name')
|
29
|
+
end
|
30
|
+
|
31
|
+
def identifier_or_call(expr)
|
32
|
+
name(expr)
|
33
|
+
end
|
34
|
+
|
35
|
+
def identifier(expr)
|
36
|
+
identifier_or_call(expr)
|
37
|
+
end
|
38
|
+
|
39
|
+
def reserved(expr)
|
40
|
+
name(expr)
|
41
|
+
end
|
42
|
+
|
43
|
+
def const(expr)
|
44
|
+
name(expr)
|
45
|
+
end
|
46
|
+
|
47
|
+
def label(expr)
|
48
|
+
name(expr)
|
49
|
+
end
|
50
|
+
|
51
|
+
def symbol(expr)
|
52
|
+
raise NotImplementedError.new('symbol')
|
53
|
+
end
|
54
|
+
|
55
|
+
def global_variable(expr)
|
56
|
+
name(expr)
|
57
|
+
end
|
58
|
+
|
59
|
+
def instance_variable(expr)
|
60
|
+
name(expr)
|
61
|
+
end
|
62
|
+
|
63
|
+
def variable_call(expr)
|
64
|
+
identifier_or_call(expr)
|
65
|
+
end
|
66
|
+
|
67
|
+
def super_method(expr)
|
68
|
+
raise NotImplementedError.new('super_method')
|
69
|
+
end
|
70
|
+
|
71
|
+
def number(expr)
|
72
|
+
raise NotImplementedError.new('number')
|
73
|
+
end
|
74
|
+
|
75
|
+
# expressions, or progn in Lisp.
|
76
|
+
#
|
77
|
+
def exprs(expr)
|
78
|
+
raise NotImplementedError.new('exprs')
|
79
|
+
end
|
80
|
+
|
81
|
+
def paren(expr)
|
82
|
+
raise NotImplementedError.new('paren')
|
83
|
+
end
|
84
|
+
|
85
|
+
def array(expr)
|
86
|
+
raise NotImplementedError.new('array')
|
87
|
+
end
|
88
|
+
|
89
|
+
def string_interpolation(expr)
|
90
|
+
raise NotImplementedError.new('string_interpolation')
|
91
|
+
end
|
92
|
+
|
93
|
+
def string_literal(expr)
|
94
|
+
raise NotImplementedError.new('string_literal')
|
95
|
+
end
|
96
|
+
|
97
|
+
def const_path_ref(expr)
|
98
|
+
raise NotImplementedError.new('const_path_ref')
|
99
|
+
end
|
100
|
+
|
101
|
+
def const_path_field(expr)
|
102
|
+
const_path_ref(expr)
|
103
|
+
end
|
104
|
+
|
105
|
+
def unary(expr)
|
106
|
+
raise NotImplementedError.new('unary')
|
107
|
+
end
|
108
|
+
|
109
|
+
def binary(expr)
|
110
|
+
raise NotImplementedError.new('binary')
|
111
|
+
end
|
112
|
+
|
113
|
+
def dots(expr)
|
114
|
+
binary(expr)
|
115
|
+
end
|
116
|
+
|
117
|
+
def assign(expr)
|
118
|
+
binary(expr)
|
119
|
+
end
|
120
|
+
|
121
|
+
def array_ref(expr)
|
122
|
+
raise NotImplementedError.new('array')
|
123
|
+
end
|
124
|
+
|
125
|
+
def array_ref_field(expr)
|
126
|
+
array_ref(expr)
|
127
|
+
end
|
128
|
+
|
129
|
+
def hash(expr)
|
130
|
+
raise NotImplementedError.new('hash')
|
131
|
+
end
|
132
|
+
|
133
|
+
def call(expr)
|
134
|
+
raise NotImplementedError.new('call')
|
135
|
+
end
|
136
|
+
|
137
|
+
def command(expr)
|
138
|
+
call(expr)
|
139
|
+
end
|
140
|
+
|
141
|
+
def conditional(expr)
|
142
|
+
raise NotImplementedError.new('conditional')
|
143
|
+
end
|
144
|
+
|
145
|
+
def loop(expr)
|
146
|
+
raise NotImplementedError.new('loop')
|
147
|
+
end
|
148
|
+
|
149
|
+
def for_loop(expr)
|
150
|
+
raise NotImplementedError.new('for_loop')
|
151
|
+
end
|
152
|
+
|
153
|
+
def break_out(expr)
|
154
|
+
raise NotImplementedError.new('break_out')
|
155
|
+
end
|
156
|
+
|
157
|
+
def return_values(expr)
|
158
|
+
raise NotImplementedError.new('return_values')
|
159
|
+
end
|
160
|
+
|
161
|
+
def block(expr)
|
162
|
+
raise NotImplementedError.new('block')
|
163
|
+
end
|
164
|
+
|
165
|
+
def lambda_expr(expr)
|
166
|
+
block(expr)
|
167
|
+
end
|
168
|
+
|
169
|
+
def being_end(expr)
|
170
|
+
raise NotImplementedError.new('begin_end')
|
171
|
+
end
|
172
|
+
|
173
|
+
# def
|
174
|
+
#
|
175
|
+
def define(expr)
|
176
|
+
raise NotImplementedError.new('define')
|
177
|
+
end
|
178
|
+
|
179
|
+
def rescue_end(expr)
|
180
|
+
raise NotImplementedError.new('rescue_end')
|
181
|
+
end
|
182
|
+
|
183
|
+
def module_def(expr)
|
184
|
+
raise NotImplementedError.new('module_def')
|
185
|
+
end
|
186
|
+
|
187
|
+
def class_def(expr)
|
188
|
+
raise NotImplementedError.new('class_def')
|
189
|
+
end
|
190
|
+
|
191
|
+
def singular_class_def(expr)
|
192
|
+
raise NotImplementedError.new('singular_class_def')
|
193
|
+
end
|
194
|
+
|
195
|
+
def program(expr)
|
196
|
+
raise NotImplementedError.new('program')
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|