Module: Yadriggy::C
- Defined in:
- lib/yadriggy/c.rb,
lib/yadriggy/c/c.rb,
lib/yadriggy/c/ffi.rb,
lib/yadriggy/c/ctype.rb,
lib/yadriggy/c/config.rb,
lib/yadriggy/c/opencl.rb,
lib/yadriggy/c/codegen.rb,
lib/yadriggy/c/program.rb,
lib/yadriggy/c/ctypecheck.rb
Overview
C language embedded in Ruby
Defined Under Namespace
Modules: CFI, CType, Config Classes: ArrayType, BuildError, ClangTypeChecker, CodeGen, FFIArray, Float32Array, FloatArray, ForeignMethodType, IntArray, NativeMethodType, OclCodeGen, OclTypeChecker, Program, WithReturnType
Class Method Summary collapse
-
.attach(module_obj, func_names, method_types, lib_name, dir = './') ⇒ Module
Attaches functions to a module.
-
.attach_funcs(pub_methods, checker, gen, module_name, lib_name, dir) ⇒ Pair<Module,Array<String>>
The module where the methods are attached.
-
.compile(obj, lib_name = nil, dir = Config::WorkDir, module_name = nil) ⇒ Module
Compiles methods into binary code.
- .compile0(obj, lib_name, dir, module_name, typechecker_class, gen_class) ⇒ Pair<Module,Array<String>>
- .compile1(obj, lib_name, dir, module_name, typechecker_class, gen_class) ⇒ Pair<Module,Array<String>>
-
.compiled_methods(checker, method_objs) ⇒ Array<ASTree>
The ASTs of compiled methods.
- .generate_funcs(ast, gen, printer) ⇒ Object
- .invoke(module_obj, func_name, args) ⇒ Object
- .invoke_float(module_obj, func_name, args) ⇒ Object
- .invoke_float32(module_obj, func_name, args) ⇒ Object
- .invoke_int(module_obj, func_name, args) ⇒ Object
- .invoker_name(mtype) ⇒ Object
-
.make_attach_file(module_name, func_names, method_types, lib_name, dir = './') ⇒ String
Generates a Ruby source file.
-
.ocl_compile(obj, lib_name = nil, dir = Config::WorkDir, module_name = nil) ⇒ Object
Compiles OpenCL methods into binary code.
-
.run(lib_name = nil, *args, dir: Config::WorkDir, &block) ⇒ Object
Compiles and runs a block.
-
.syntax ⇒ Syntax
The syntax.
Class Method Details
.attach(module_obj, func_names, method_types, lib_name, dir = './') ⇒ Module
Attaches functions to a module. The functions are retrieved from the library generated by compiling Ruby methods.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/yadriggy/c/ffi.rb', line 143 def self.attach(module_obj, func_names, method_types, lib_name, dir='./') module_obj.module_eval('extend FFI::Library') module_obj.ffi_lib("#{dir}lib#{lib_name}#{Config::LibExtension}") func_names.each_with_index do |name,i| mtype = method_types[i] module_obj.attach_function((name + '__org').to_sym, name.to_sym, CFI::param_types(mtype), CFI::return_type(mtype)) ivk_name = invoker_name(mtype) module_obj.module_eval " def self.\#{name}(*args)\n Yadriggy::C::invoke\#{ivk_name}(self, :\#{name}__org, args)\n end\n code\n end\n module_obj\nend\n", __FILE__, __LINE__ |
.attach_funcs(pub_methods, checker, gen, module_name, lib_name, dir) ⇒ Pair<Module,Array<String>>
Returns the module where the methods are attached. The second element is method names.
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/yadriggy/c/c.rb', line 191 def self.attach_funcs(pub_methods, checker, gen, module_name, lib_name, dir) func_names = pub_methods.map { |ast| gen.c_function_name(ast.tree) } func_types = pub_methods.map { |ast| checker.type(ast.tree) } func_names, func_types = gen.(func_names, func_types) unless module_name.nil? make_attach_file(module_name, func_names, func_types, lib_name, dir) end [attach(Module.new, func_names, func_types, lib_name, dir), func_names] end |
.compile(obj, lib_name = nil, dir = Config::WorkDir, module_name = nil) ⇒ Module
Compiles methods into binary code.
92 93 94 95 96 |
# File 'lib/yadriggy/c/c.rb', line 92 def self.compile(obj, lib_name=nil, dir=Config::WorkDir, module_name=nil) mod, funcs = compile0(obj, lib_name, dir, module_name, ClangTypeChecker, CodeGen)[0] mod end |
.compile0(obj, lib_name, dir, module_name, typechecker_class, gen_class) ⇒ Pair<Module,Array<String>>
100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/yadriggy/c/c.rb', line 100 def self.compile0(obj, lib_name, dir, module_name, typechecker_class, gen_class) begin compile1(obj, lib_name, dir, module_name, typechecker_class, gen_class) rescue SyntaxError, CheckError, BuildError => err raise err if Yadriggy.debug > 0 warn err. nil end end |
.compile1(obj, lib_name, dir, module_name, typechecker_class, gen_class) ⇒ Pair<Module,Array<String>>
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/yadriggy/c/c.rb', line 114 def self.compile1(obj, lib_name, dir, module_name, typechecker_class, gen_class) lib_name0 = obj.class.name method_objs = if obj.is_a?(Proc) || obj.is_a?(Method) || obj.is_a?(UnboundMethod) lib_name0 += obj.object_id.to_s(16) [obj] else obj.public_methods(false).map do |name| obj.method(name) end end lib_name = lib_name0.gsub('::', '_').downcase if lib_name.nil? raise BuildError.new('no methods specified') if method_objs.size < 1 checker = typechecker_class.new(@syntax) pub_methods = compiled_methods(checker, method_objs) dir += File::Separator unless dir.end_with?(File::Separator) FileUtils.mkdir_p(dir) printer = Yadriggy::FilePrinter.new(gen_class.c_src_file(dir, lib_name)) gen = gen_class.new(printer, checker, pub_methods) generate_funcs(pub_methods[0], gen, printer) gen.build_lib(lib_name, dir) attach_funcs(pub_methods, checker, gen, module_name, lib_name, dir) end |
.compiled_methods(checker, method_objs) ⇒ Array<ASTree>
Returns the ASTs of compiled methods.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/yadriggy/c/c.rb', line 146 def self.compiled_methods(checker, method_objs) ast = nil pub_methods = method_objs.map do |mthd| if ast.nil? ast = Yadriggy::reify(mthd) else ast = ast.reify(mthd) end if ast.nil? raise SyntaxError.new( "cannot locate the source: #{mthd.name.to_s} in #{mthd.receiver.class}") end @syntax.raise_error unless @syntax.check(ast.tree) checker.typecheck(ast.tree) ast end return pub_methods end |
.generate_funcs(ast, gen, printer) ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/yadriggy/c/c.rb', line 169 def self.generate_funcs(ast, gen, printer) gen.name_global_variables gen.headers gen.variable_declarations ast.astrees.each do |e| gen.prototype(e.tree) end gen.preamble ast.astrees.each do |e| printer << :nl gen.c_function(e.tree) end printer.output printer.close raise BuildError.new(gen.) if gen.errors? end |
.invoke(module_obj, func_name, args) ⇒ Object
235 236 237 238 239 240 241 242 243 244 |
# File 'lib/yadriggy/c/ffi.rb', line 235 def self.invoke(module_obj, func_name, args) args2 = args.map do |e| if e.is_a?(IntArray) || e.is_a?(FloatArray) || e.is_a?(Float32Array) e.memory_pointer else e end end module_obj.method(func_name).call(*args2) end |
.invoke_float(module_obj, func_name, args) ⇒ Object
223 224 225 226 |
# File 'lib/yadriggy/c/ffi.rb', line 223 def self.invoke_float(module_obj, func_name, args) r = invoke(module_obj, func_name, args) FloatArray.new(0, r) end |
.invoke_float32(module_obj, func_name, args) ⇒ Object
229 230 231 232 |
# File 'lib/yadriggy/c/ffi.rb', line 229 def self.invoke_float32(module_obj, func_name, args) r = invoke(module_obj, func_name, args) Float32Array.new(0, r) end |
.invoke_int(module_obj, func_name, args) ⇒ Object
217 218 219 220 |
# File 'lib/yadriggy/c/ffi.rb', line 217 def self.invoke_int(module_obj, func_name, args) r = invoke(module_obj, func_name, args) IntArray.new(0, r) end |
.invoker_name(mtype) ⇒ Object
203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/yadriggy/c/ffi.rb', line 203 def self.invoker_name(mtype) case ArrayType.role(MethodType.role(mtype)&.result_type)&.element_type when RubyClass::Integer '_int' when RubyClass::Float '_float' when CType::Float32Type '_float32' else '' end end |
.make_attach_file(module_name, func_names, method_types, lib_name, dir = './') ⇒ String
Generates a Ruby source file. When the file is executed, it retrieves functions from the library generated by compiling Ruby methods, and then it attaches the functions to a specified module.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/yadriggy/c/ffi.rb', line 174 def self.make_attach_file(module_name, func_names, method_types, lib_name, dir='./') file_name0 = module_name.gsub(/::|\./, '_').downcase file_name = "#{dir}#{file_name0}.rb" printer = Yadriggy::FilePrinter.new(file_name) printer << "require 'yadriggy/c/ffi'" << :nl << :nl printer << "module #{module_name} extend FFI::Library" << :nl printer << " self.ffi_lib(\"#{dir}lib#{lib_name}#{Config::LibExtension}\")" << :nl func_names.each_with_index do |name,i| mtype = method_types[i] printer << " self.attach_function(:\"#{name}__org\", " printer << ":\"#{name}\", " printer << "#{CFI::param_types(mtype).to_s}, " printer << ":#{CFI::return_type(mtype)})" printer << :nl printer << " def self.#{name}(*args)" << :nl printer << " Yadriggy::C::invoke#{invoker_name(mtype)}(self, " printer << ":\"#{name}__org\", args)" << :nl printer << ' end' << :nl end printer << 'end' << :nl printer.output printer.close file_name end |
.ocl_compile(obj, lib_name = nil, dir = Config::WorkDir, module_name = nil) ⇒ Object
Compiles OpenCL methods into binary code.
13 14 15 16 17 18 |
# File 'lib/yadriggy/c/opencl.rb', line 13 def self.ocl_compile(obj, lib_name=nil, dir=Config::WorkDir, module_name=nil) mod, funcs = compile0(obj, lib_name, dir, module_name, OclTypeChecker, OclCodeGen) mod end |
.run(lib_name = nil, *args, dir: Config::WorkDir, &block) ⇒ Object
Compiles and runs a block.
213 214 215 216 217 218 |
# File 'lib/yadriggy/c/c.rb', line 213 def self.run(lib_name=nil, *args, dir: Config::WorkDir, &block) raise BuildError.new('no block given') if block.nil? mod, mths = compile0(block, lib_name, dir, nil, ClangTypeChecker, CodeGen) mod.method(mths[0]).call(*args) end |
.syntax ⇒ Syntax
Returns the syntax.
75 76 77 |
# File 'lib/yadriggy/c/c.rb', line 75 def self.syntax @syntax end |