Created
December 28, 2010 01:47
-
-
Save jarib/756783 to your computer and use it in GitHub Desktop.
Spike of FFI wrapper for libclang
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'ffi' | |
module Clang | |
module Lib | |
extend FFI::Library | |
ffi_lib "clang" | |
attach_function :create_index, :clang_createIndex, [:int, :int], :pointer | |
attach_function :dispose_index, :clang_disposeIndex, [:pointer], :void | |
attach_function :parse_translation_unit, :clang_parseTranslationUnit, [:pointer, :string, :pointer, :int, :pointer, :uint, :uint], :pointer | |
attach_function :dispose_translation_unit, :clang_disposeTranslationUnit, [:pointer], :void | |
attach_function :get_num_diagnostics, :clang_getNumDiagnostics, [:pointer], :uint | |
attach_function :get_diagnostic, :clang_getDiagnostic, [:pointer, :uint], :pointer | |
attach_function :dispose_diagnostic, :clang_disposeDiagnostic, [:pointer], :void | |
attach_function :format_diagnostic, :clang_formatDiagnostic, [:pointer, :uint], :pointer | |
attach_function :default_diagnostic_display_options, :clang_defaultDiagnosticDisplayOptions, [], :uint | |
attach_function :get_c_string, :clang_getCString, [:pointer], :string | |
attach_function :dispose_string, :clang_disposeString, [:pointer], :void | |
attach_function :get_diagnostic_location, :clang_getDiagnosticLocation, [:pointer], :pointer | |
attach_function :equal_locations, :clang_equalLocations, [:pointer, :pointer], :uint | |
end | |
class TranslationUnit | |
def initialize(ptr) | |
@ptr = FFI::AutoPointer.new(ptr, Lib.method(:dispose_translation_unit)) | |
end | |
def diagnostics | |
n = Lib.get_num_diagnostics(@ptr) | |
0.upto(n - 1).map do |idx| | |
Diagnostic.new(Lib.get_diagnostic(@ptr, idx)) | |
end | |
end | |
end | |
class Diagnostic | |
def initialize(ptr) | |
@ptr = FFI::AutoPointer.new(ptr, Lib.method(:dispose_diagnostic)) | |
end | |
def format(opts = {}) | |
raise NotImplementedError, "#{self.class}#format options" unless opts.empty? | |
cxstring = Lib.format_diagnostic(@ptr, Lib.default_diagnostic_display_options) | |
result = Lib.get_c_string(cxstring) | |
Lib.dispose_string(cxstring) | |
result | |
end | |
def severity | |
raise NotImplementedError | |
end | |
def source_location | |
SourceLocation.new(Lib.get_diagnostic_location(@ptr)) | |
end | |
def fixits | |
raise NotImplementedError | |
# unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag); | |
# – CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, | |
# unsigned FixIt, | |
# CXSourceRange *ReplacementRange); | |
end | |
def spelling | |
raise NotImplementedError | |
end | |
end | |
class SourceLocation | |
def initialize(ptr) | |
# no release? should we keep a reference to TU / diagnostic? | |
@ptr = ptr | |
end | |
def ==(other) | |
return unless other.kind_of? self.class | |
Lib.equal_locations(@ptr, other.ptr) != 0 | |
end | |
alias_method :eql?, :== | |
protected | |
def ptr | |
@ptr | |
end | |
end | |
class Index | |
def initialize(opts = {}) | |
exclude_declarations_from_pch = opts[:exclude_declarations_from_pch] ? 1 : 0 | |
display_diagnostics = opts[:display_diagnostics] ? 1 : 0 | |
@ptr = FFI::AutoPointer.new Lib.create_index(exclude_declarations_from_pch, display_diagnostics), | |
Lib.method(:dispose_index) | |
end | |
def parse_translation_unit(source_file, command_line_args = nil, opts = {}) | |
command_line_args = Array(command_line_args) | |
args_pointer = FFI::MemoryPointer.new(:pointer) | |
strings = command_line_args.map do |arg| | |
FFI::MemoryPointer.from_string(arg.to_s) | |
end | |
args_pointer.put_array_of_pointer(strings) unless strings.empty? | |
raise NotImplementedError, "options for #{self.class}#parse_translation_unit" unless opts.empty? | |
tu = Lib.parse_translation_unit(@ptr, source_file, args_pointer, command_line_args.size, nil, 0, 0) | |
raise "error parsing #{source_file.inspect}" if tu.nil? || tu.null? | |
TranslationUnit.new tu | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment