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.
@@ -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
@@ -0,0 +1,5 @@
1
+ # Copyright (C) 2017- Shigeru Chiba. All rights reserved.
2
+
3
+ module Yadriggy
4
+ VERSION = "1.0.0"
5
+ end
@@ -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: []