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,277 @@
|
|
1
|
+
# Copyright (C) 2017- Shigeru Chiba. All rights reserved.
|
2
|
+
|
3
|
+
require 'yadriggy/syntax'
|
4
|
+
require 'yadriggy/checker'
|
5
|
+
require 'yadriggy/type'
|
6
|
+
|
7
|
+
module Yadriggy
|
8
|
+
|
9
|
+
# Type checker for ASTree
|
10
|
+
#
|
11
|
+
# A type object used by TypeChecker can be an instance of any subclass
|
12
|
+
# of Type. It does not have to necessarily be an object representing
|
13
|
+
# a "type".
|
14
|
+
#
|
15
|
+
class TypeChecker < Checker
|
16
|
+
|
17
|
+
# TypeEnv (type environment) holds bindings between names and types.
|
18
|
+
#
|
19
|
+
# If you define a subclass of {TypeEnv}, override {#new_tenv} and
|
20
|
+
# {#new_base_tenv}. {TypeChecker#make_base_env} has to be overridden
|
21
|
+
# as well.
|
22
|
+
#
|
23
|
+
class TypeEnv
|
24
|
+
# @param [TypeEnv|nil] parent the parent environment.
|
25
|
+
def initialize(parent=nil)
|
26
|
+
@parent = parent
|
27
|
+
@names = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Executes `block` for each name in this environment.
|
31
|
+
# It passes the name-type pair as parameters to the block.
|
32
|
+
#
|
33
|
+
# @yield [name, type] gives a `Symbol` (name) and a `Type`.
|
34
|
+
def each(&block)
|
35
|
+
@names.each(&block)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Makes a new type environment where all the bindings
|
39
|
+
# are copied from the current type environment.
|
40
|
+
#
|
41
|
+
def new_tenv
|
42
|
+
TypeEnv.new(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Makes a new type environment. klass is set to the context class
|
46
|
+
# of that new environment.
|
47
|
+
#
|
48
|
+
# @param [Module] klass the context class. If it is `nil`, then
|
49
|
+
# `self`'s context class is passed.
|
50
|
+
def new_base_tenv(klass=nil)
|
51
|
+
BaseTypeEnv.new(klass.nil? ? context : klass)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Binds name to type.
|
55
|
+
#
|
56
|
+
# @param [Name|String|Symbol|nil] name the name.
|
57
|
+
# @param [Type] type the type.
|
58
|
+
# @return [Type] the type.
|
59
|
+
def bind_name(name, type)
|
60
|
+
@names[name.to_sym] = type unless name.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
# Gets the type bound to `name`, or nil if `name` is not bound to
|
64
|
+
# any type.
|
65
|
+
#
|
66
|
+
# @param [Name|String|Symbol] name the name.
|
67
|
+
# @return [Type|nil] the type bound to `name`.
|
68
|
+
def bound_name?(name)
|
69
|
+
type = @names[name.to_sym]
|
70
|
+
if type.nil?
|
71
|
+
@parent&.bound_name?(name)
|
72
|
+
else
|
73
|
+
type
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Gets context class (enclosing class) or nil.
|
78
|
+
#
|
79
|
+
# @return [Module|nil] the context class.
|
80
|
+
def context
|
81
|
+
@parent&.context
|
82
|
+
end
|
83
|
+
|
84
|
+
# @private
|
85
|
+
class BaseTypeEnv < TypeEnv
|
86
|
+
def initialize(clazz)
|
87
|
+
super(nil)
|
88
|
+
@clazz = clazz
|
89
|
+
end
|
90
|
+
|
91
|
+
def context
|
92
|
+
@clazz
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end # of TypeEnv
|
96
|
+
|
97
|
+
# A type environement that collects free variables.
|
98
|
+
# {#bound_name?} records the given symbol as a free variable name
|
99
|
+
# when it obtains the type of that symbol from its parent type
|
100
|
+
# environment.
|
101
|
+
#
|
102
|
+
class FreeVarFinder < TypeEnv
|
103
|
+
# Obtains collected free variables.
|
104
|
+
# @return [Hash<Symbol,Type>] a map from variable names to their types.
|
105
|
+
attr_reader :free_variables
|
106
|
+
|
107
|
+
def initialize(parent)
|
108
|
+
super
|
109
|
+
@free_variables = {}
|
110
|
+
end
|
111
|
+
|
112
|
+
def bound_name?(name)
|
113
|
+
type = @names[name.to_sym]
|
114
|
+
if type.nil?
|
115
|
+
t = @parent&.bound_name?(name)
|
116
|
+
@free_variables[name.to_sym] = t unless t.nil?
|
117
|
+
t
|
118
|
+
else
|
119
|
+
type
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Type definition. It expresses a class (or singular class)
|
125
|
+
# definition. It maps an instance variable name or a method
|
126
|
+
# name to its type.
|
127
|
+
#
|
128
|
+
# @see TypeChecker#typedef
|
129
|
+
# @see TypeChecker#add_typedef
|
130
|
+
class TypeDef
|
131
|
+
def initialize()
|
132
|
+
@names = {}
|
133
|
+
end
|
134
|
+
|
135
|
+
# Gets the type of an instance variable or a method.
|
136
|
+
# @param [String|Symbol] name its name.
|
137
|
+
# `name` can be any object with `to_sym`.
|
138
|
+
# @return [Type|nil] its type.
|
139
|
+
def [](name)
|
140
|
+
@names[name.to_sym]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Adds an instance variable or a method.
|
144
|
+
# @param [String|Symbol] name its name.
|
145
|
+
# `name` can be any object with `to_sym`.
|
146
|
+
# @param [Type] type its type.
|
147
|
+
# @return [Type] the added type.
|
148
|
+
def []=(name, type)
|
149
|
+
@names[name.to_sym] = type
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def initialize
|
154
|
+
super
|
155
|
+
@typetable = {}
|
156
|
+
@typedefs = {}
|
157
|
+
end
|
158
|
+
|
159
|
+
# Gets the current type environment.
|
160
|
+
#
|
161
|
+
def type_env
|
162
|
+
@current_env
|
163
|
+
end
|
164
|
+
|
165
|
+
# Obtains the type definition associated with `key`.
|
166
|
+
# Here, a type definition is a mapping from instance variables
|
167
|
+
# or methods to their types. It is defined per class or
|
168
|
+
# individual instance object.
|
169
|
+
# If `key` is `nil`, `nil` is returned.
|
170
|
+
#
|
171
|
+
# @param [Module|Object|nil] key a class or an instance.
|
172
|
+
# @return [TypeDef|nil] the type definition.
|
173
|
+
def typedef(key)
|
174
|
+
if key.nil?
|
175
|
+
nil
|
176
|
+
else
|
177
|
+
@typedefs[key]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Adds a type definition if it does not exist.
|
182
|
+
# Here, a type definition is a mapping from instance variables
|
183
|
+
# or methods to their types. It is defined per class or
|
184
|
+
# individual instance object.
|
185
|
+
#
|
186
|
+
# @param [Module|Object] key a class or an instance.
|
187
|
+
# @return [TypeDef] the type definition for the class
|
188
|
+
# or instance given by `key`.
|
189
|
+
def add_typedef(key)
|
190
|
+
@typedefs[key] || @typedefs[key] = TypeDef.new
|
191
|
+
end
|
192
|
+
|
193
|
+
# Applies typing rules to the given AST.
|
194
|
+
# It returns the type of the AST or throws
|
195
|
+
# a CheckError.
|
196
|
+
# This is the entry point of the type checker. It may also
|
197
|
+
# type the other ASTs invoked in the given AST.
|
198
|
+
#
|
199
|
+
# It assumes that the AST is processed by Syntax and it has
|
200
|
+
# usertype method.
|
201
|
+
#
|
202
|
+
# This is an alias of check_all() but it memoizes the results.
|
203
|
+
#
|
204
|
+
def typecheck(an_ast)
|
205
|
+
check_all(an_ast)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Makes a new base type environment with the given context class.
|
209
|
+
#
|
210
|
+
def make_base_env(klass)
|
211
|
+
TypeEnv::BaseTypeEnv.new(klass)
|
212
|
+
end
|
213
|
+
|
214
|
+
# @private
|
215
|
+
# Internal-use only. Don't use this method. Use type().
|
216
|
+
#
|
217
|
+
def check(an_ast, ast_tenv=nil)
|
218
|
+
type(an_ast, ast_tenv)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Applies typing rules to determine the type of the given AST.
|
222
|
+
# This method is effective in {.rule}.
|
223
|
+
#
|
224
|
+
# It assumes that the AST is processed by Syntax and it has
|
225
|
+
# usertype method. An exception is thrown when type checking
|
226
|
+
# fails.
|
227
|
+
#
|
228
|
+
# @param [ASTnode|nil] an_ast an AST or nil.
|
229
|
+
# @param [TypeEnv|nil] ast_tenv a type environment or nil.
|
230
|
+
# @return [Type] the type of the given AST. It memoizes the results.
|
231
|
+
def type(an_ast, ast_tenv=nil)
|
232
|
+
if an_ast.nil?
|
233
|
+
DynType
|
234
|
+
else
|
235
|
+
ast_type = @typetable[an_ast]
|
236
|
+
return ast_type unless ast_type.nil?
|
237
|
+
|
238
|
+
rule = self.class.find_rule_entry(an_ast)
|
239
|
+
t = apply_typing_rule(rule, an_ast, ast_tenv)
|
240
|
+
@typetable[an_ast] = t
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Sets the type of an AST to the given type.
|
245
|
+
#
|
246
|
+
# @param [ASTnode|nil] an_ast an AST.
|
247
|
+
# @param [Type] a_type a type.
|
248
|
+
# @param [Type|nil] the given type `a_type`.
|
249
|
+
def type_as(an_ast, a_type)
|
250
|
+
if an_ast.nil?
|
251
|
+
DynType
|
252
|
+
else
|
253
|
+
@typetable[an_ast] = a_type
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def type_assert(is_valid, errmsg='')
|
258
|
+
error_found!(@current_ast, errmsg) unless is_valid
|
259
|
+
end
|
260
|
+
|
261
|
+
def type_assert_false(is_invalid, errmsg='')
|
262
|
+
error_found!(@current_ast, errmsg) if is_invalid
|
263
|
+
end
|
264
|
+
|
265
|
+
# Later invokes proc, which performs type checking.
|
266
|
+
# This is used for avoiding infinite regression when
|
267
|
+
# determining the type of ASTs.
|
268
|
+
#
|
269
|
+
def type_assert_later(&proc)
|
270
|
+
check_later(&proc)
|
271
|
+
end
|
272
|
+
|
273
|
+
def error_group
|
274
|
+
'type'
|
275
|
+
end
|
276
|
+
end # of TypeChecker
|
277
|
+
end
|
data/yadriggy.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'yadriggy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "yadriggy"
|
8
|
+
spec.version = Yadriggy::VERSION
|
9
|
+
spec.authors = ["Shigeru Chiba"]
|
10
|
+
# spec.email = ["?"]
|
11
|
+
|
12
|
+
spec.summary = %q{library for building a DSL embedded in Ruby.}
|
13
|
+
|
14
|
+
spec.description = %q{Yadriggy builds the abstract syntax tree (AST) of a method, checks its syntax and types, and runs it. When checking the syntax and types, it is treated as the code written in a domain specific language (DSL). It also provide a simple DSL for computation offloading from Ruby to C.}
|
15
|
+
|
16
|
+
spec.homepage = "https://github.com/csg-tokyo/yadriggy"
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(test|spec|features|examples)/})
|
21
|
+
end
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_dependency "ffi"
|
27
|
+
spec.add_dependency "pry"
|
28
|
+
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
30
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
31
|
+
# spec.add_development_dependency "minitest", "~> 5.0"
|
32
|
+
spec.add_development_dependency "test-unit", "~> 3.2.5"
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yadriggy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shigeru Chiba
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-07-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.13'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.13'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: test-unit
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.2.5
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.2.5
|
83
|
+
description: Yadriggy builds the abstract syntax tree (AST) of a method, checks its
|
84
|
+
syntax and types, and runs it. When checking the syntax and types, it is treated
|
85
|
+
as the code written in a domain specific language (DSL). It also provide a simple
|
86
|
+
DSL for computation offloading from Ruby to C.
|
87
|
+
email:
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- lib/yadriggy.rb
|
98
|
+
- lib/yadriggy/algebra.rb
|
99
|
+
- lib/yadriggy/ast.rb
|
100
|
+
- lib/yadriggy/ast_location.rb
|
101
|
+
- lib/yadriggy/ast_value.rb
|
102
|
+
- lib/yadriggy/c.rb
|
103
|
+
- lib/yadriggy/c/c.rb
|
104
|
+
- lib/yadriggy/c/codegen.rb
|
105
|
+
- lib/yadriggy/c/config.rb
|
106
|
+
- lib/yadriggy/c/ctype.rb
|
107
|
+
- lib/yadriggy/c/ctypecheck.rb
|
108
|
+
- lib/yadriggy/c/ffi.rb
|
109
|
+
- lib/yadriggy/c/opencl.rb
|
110
|
+
- lib/yadriggy/c/program.rb
|
111
|
+
- lib/yadriggy/c1.rb
|
112
|
+
- lib/yadriggy/checker.rb
|
113
|
+
- lib/yadriggy/eval.rb
|
114
|
+
- lib/yadriggy/eval_all.rb
|
115
|
+
- lib/yadriggy/pretty_print.rb
|
116
|
+
- lib/yadriggy/printer.rb
|
117
|
+
- lib/yadriggy/ruby_typecheck.rb
|
118
|
+
- lib/yadriggy/ruby_typeinfer.rb
|
119
|
+
- lib/yadriggy/source_code.rb
|
120
|
+
- lib/yadriggy/syntax.rb
|
121
|
+
- lib/yadriggy/type.rb
|
122
|
+
- lib/yadriggy/typecheck.rb
|
123
|
+
- lib/yadriggy/version.rb
|
124
|
+
- yadriggy.gemspec
|
125
|
+
homepage: https://github.com/csg-tokyo/yadriggy
|
126
|
+
licenses:
|
127
|
+
- MIT
|
128
|
+
metadata: {}
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
requirements: []
|
144
|
+
rubyforge_project:
|
145
|
+
rubygems_version: 2.6.14
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: library for building a DSL embedded in Ruby.
|
149
|
+
test_files: []
|