main.rb (2238B)
1 # frozen_string_literal: true 2 3 require_relative '../ext/ffi-clang/lib/ffi/clang' 4 require_relative '../tools/ci_lib' 5 6 class Parser 7 CLANG_VERSION = FFI::Clang.clang_version_string.match(/\d+\.\d+\.\d+/).match 0 8 alias inspect to_s 9 10 @@opts = %w( 11 -std=c++17 -Wno-undefined-inline -Wno-undefined-internal -Wno-assume 12 ) 13 clangdir = File.join ENV['PREFIX'] || '/usr', 'lib/clang', CLANG_VERSION 14 if File.exist? File.join clangdir, 'include/stddef.h' 15 @@opts << "-resource-dir=#{clangdir}" 16 end 17 18 def self.add_opts opts 19 @@opts.concat opts 20 end 21 22 @@src = {} 23 def self.add_src handlers, src 24 src.each do |s| 25 (@@src[s] ||= Set.new).merge handlers 26 end 27 end 28 def self.src = @@src 29 30 def self.gen_binding src, dst, args 31 new.gen_binding src, dst, args 32 end 33 34 attr_reader :tu, :filter 35 36 def parse src, args 37 src_noext = src.gsub(/\.[^.]*$/, '') 38 fname_map = {} 39 @filter = ->c, parent do 40 c.visit_children do |c2| 41 if c2.kind == :annotate_attr && c2.spelling.start_with?('alias_file ') 42 fname_map[c2.location.file] = c2.spelling[11..] 43 end 44 :break 45 end 46 47 loc = c.location.file or return true 48 loc = fname_map[loc] || loc 49 loc.gsub(/\.[^.]*$/, '') == src_noext 50 end 51 52 parse_tu src, args 53 end 54 55 def parse_tu fname, extra_opts 56 index = FFI::Clang::Index.new 57 @tu = index.parse_translation_unit fname, @@opts + extra_opts, [], 58 %i(keep_going skip_function_bodies) 59 @tu.diagnostics.each do |d| 60 if d.severity == :error || d.severity == :fatal 61 CI.eerror d.format 62 else 63 CI.ewarn d.format 64 end 65 end 66 self 67 end 68 69 def gen dst 70 dst.puts <<EOS 71 // Auto generated code, do not edit. See gen_binding in project root. 72 #ifndef LIBSHIT_BINDING_GENERATOR 73 EOS 74 @hs.each {|h| h.generate dst } 75 dst.puts '#endif' 76 self 77 end 78 79 def gen_binding src, dst, args 80 dst ||= "#{src.sub /\.[^.]+\z/, ''}.binding.hpp" 81 hs = @@src[src] or fail "Unknown source #{src.inspect}" 82 parse src, args 83 @hs = hs.map {|h| h.new self } 84 @hs.each &:parse 85 86 if dst == '-' 87 gen $stdout 88 else 89 File.open(dst, 'w') {|f| gen f } 90 end 91 self 92 end 93 end