Skip to content

Commit

Permalink
Switch to Ruby's enumerable module. This is a backwards incompatible …
Browse files Browse the repository at this point in the history
…change because it required renaming find_all to find_by_kind. In addition, the function signature changed to allow the caller to specify whether to search direct children or all children.
  • Loading branch information
cfis committed Apr 9, 2024
1 parent 66988eb commit 83080ef
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 88 deletions.
68 changes: 28 additions & 40 deletions lib/ffi/clang/cursor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
module FFI
module Clang
class Cursor
include Enumerable

attr_reader :cursor
attr_reader :translation_unit

Expand Down Expand Up @@ -163,7 +165,7 @@ def usr
end

def kind
@cursor[:kind]
@cursor ? @cursor[:kind] : nil
end

def kind_spelling
Expand Down Expand Up @@ -277,14 +279,36 @@ def num_args
Lib.get_num_args @cursor
end

def visit_children(&block)
def each(recurse = true, &block)
return to_enum(:each, recurse) unless block_given?

adapter = Proc.new do |cxcursor, parent_cursor, unused|
block.call Cursor.new(cxcursor, @translation_unit), Cursor.new(parent_cursor, @translation_unit)
# Call the block and capture the result. This lets advanced users
# modify the recursion on a case by case basis if needed
result = block.call Cursor.new(cxcursor, @translation_unit), Cursor.new(parent_cursor, @translation_unit)
case result
when :continue
:continue
when :recurse
:recurse
else
recurse ? :recurse : :continue
end
end

Lib.visit_children(@cursor, adapter, nil)
end

def find_by_kind(recurse, *kinds)
result = Array.new
self.each(recurse) do |child, parent|
if kinds.include?(child.kind)
result << child
end
end
result
end

def find_references_in_file(file = nil, &block)
file ||= Lib.extract_string Lib.get_translation_unit_spelling(@translation_unit)

Expand Down Expand Up @@ -392,46 +416,10 @@ def hash
Lib.get_cursor_hash(@cursor)
end

def find_all(*kinds)
filter do |child, parent|
kinds.include?(child.kind)
end
end

def find_first(*kinds)
find_all(*kinds).first
end

def filter
return to_enum(:select) unless block_given?

matching = []

self.visit_children do |child, parent|
if yield(child, parent)
matching << child
end

:recurse
end

return matching
end

def select
filter do |child, parent|
yield(child)
end
end

def to_s
"Cursor <#{self.kind.to_s.gsub(/^cursor_/, '')}: #{self.spelling}>"
end

def to_a
filter.collect{|child, parent| child}
end

def references(file = nil)
refs = []
self.find_references_in_file(file) do |cursor, unused|
Expand Down
2 changes: 1 addition & 1 deletion spec/ffi/clang/comment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

describe Comment do
let(:cursor) { Index.new.parse_translation_unit(fixture_path("docs.cc")).cursor }
let (:comment) { find_first(cursor, :cursor_function).comment }
let (:comment) { find_by_kind(cursor, :cursor_function).comment }

it "can be obtained from a cursor" do
expect(comment).to be_kind_of(Comment)
Expand Down
62 changes: 31 additions & 31 deletions spec/ffi/clang/cursor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
describe "Function Call Cursors" do
let(:translation_unit) {Index.new.parse_translation_unit(fixture_path("class.cpp"))}
let(:cursor) {translation_unit.cursor}
let(:call) {find_first(cursor, :cursor_call_expr)}
let(:call) {find_by_kind(cursor, :cursor_call_expr)}

it "should parse correctly" do
expect(translation_unit.diagnostics).to be_empty
Expand All @@ -29,9 +29,9 @@
describe FFI::Clang::Cursor do
let(:translation_unit) {Index.new.parse_translation_unit(fixture_path("class.cpp"))}
let(:cursor) {translation_unit.cursor}
let (:class1) { find_all(cursor, :cursor_class_decl)[0] }
let (:class2) { find_all(cursor, :cursor_class_decl)[1] }
let (:class3) { find_all(cursor, :cursor_class_decl)[2] }
let (:class1) { find_all_by_kind(cursor, :cursor_class_decl)[0] }
let (:class2) { find_all_by_kind(cursor, :cursor_class_decl)[1] }
let (:class3) { find_all_by_kind(cursor, :cursor_class_decl)[2] }

it "can find the first class" do
expect(class1).not_to equal(nil)
Expand All @@ -48,7 +48,7 @@
end

it "has constructors" do
constructors = find_all(class2, :cursor_constructor)
constructors = find_all_by_kind(class2, :cursor_constructor)
expect(constructors.length).to eq(5)

expect(constructors[0].default_constructor?).to eq(true)
Expand Down Expand Up @@ -80,7 +80,7 @@
end

it "has destructors" do
constructors = find_all(class2, :cursor_constructor)
constructors = find_all_by_kind(class2, :cursor_constructor)
expect(constructors.length).to eq(5)
end

Expand All @@ -91,7 +91,7 @@
end

it "field is mutable abstract" do
fields = find_all(class3, :cursor_field_decl)
fields = find_all_by_kind(class3, :cursor_field_decl)

field = fields[0]
expect(field.mutable?).to eq(true)
Expand Down Expand Up @@ -143,7 +143,7 @@

it "allows us to visit its children" do
counter = 0
cursor.visit_children do |cursor, parent|
cursor.each do |cursor, parent|
counter += 1
:recurse
end
Expand Down Expand Up @@ -174,7 +174,7 @@
end

describe "Function Cursors" do
let (:func) { find_first(cursor, :cursor_function) }
let (:func) { find_by_kind(cursor, :cursor_function) }

it "is not invalid?" do
expect(func.invalid?).to equal(false)
Expand All @@ -198,7 +198,7 @@
end

describe "Struct Cursors" do
let (:struct) { find_first(cursor, :cursor_struct) }
let (:struct) { find_by_kind(cursor, :cursor_struct) }

it "can find the first struct" do
expect(struct).not_to equal(nil)
Expand All @@ -217,47 +217,47 @@
end

describe '#kind_spelling' do
let (:struct) { find_first(cursor, :cursor_struct) }
let (:struct) { find_by_kind(cursor, :cursor_struct) }

it "returns the spelling of the given kind" do
expect(struct.kind_spelling).to eq('StructDecl')
end
end

describe '#declaration?' do
let (:struct) { find_first(cursor, :cursor_struct) }
let (:struct) { find_by_kind(cursor, :cursor_struct) }

it "checks the cursor is declaration" do
expect(struct.declaration?).to be true
end
end

describe '#reference?' do
let (:ref) { find_first(cursor, :cursor_type_ref) }
let (:ref) { find_by_kind(cursor, :cursor_type_ref) }

it "checks the cursor is reference" do
expect(ref.reference?).to be true
end
end

describe '#expression?' do
let (:literal) { find_first(cursor, :cursor_integer_literal) }
let (:literal) { find_by_kind(cursor, :cursor_integer_literal) }

it "checks the cursor is expression" do
expect(literal.expression?).to be true
end
end

describe '#statement?' do
let (:return_stmt) { find_first(cursor, :cursor_return_stmt) }
let (:return_stmt) { find_by_kind(cursor, :cursor_return_stmt) }

it "checks the cursor is statement" do
expect(return_stmt.statement?).to be true
end
end

describe '#attribute?' do
let (:attr) { find_first(cursor_cxx, :cursor_unexposed_attr) }
let (:attr) { find_by_kind(cursor_cxx, :cursor_unexposed_attr) }

it "checks the cursor is attribute" do
expect(attr.attribute?).to be true
Expand Down Expand Up @@ -292,7 +292,7 @@
end

describe '#preprocessing?' do
let (:pp) { find_first(cursor_pp, :cursor_macro_definition) }
let (:pp) { find_by_kind(cursor_pp, :cursor_macro_definition) }

it 'checks the cursor is preprocessing' do
expect(pp.preprocessing?).to be true
Expand Down Expand Up @@ -384,7 +384,7 @@
end

describe '#canonical' do
let (:structs) { find_all(cursor_canon, :cursor_struct) }
let (:structs) { find_all_by_kind(cursor_canon, :cursor_struct) }

it "mathes 3 cursors" do
expect(structs.size).to eq(3)
Expand All @@ -398,7 +398,7 @@
end

describe '#definition' do
let (:structs) { find_all(cursor_canon, :cursor_struct) }
let (:structs) { find_all_by_kind(cursor_canon, :cursor_struct) }

it "mathes 3 cursors" do
expect(structs.size).to eq(3)
Expand Down Expand Up @@ -444,7 +444,7 @@
end

describe '#translation_unit' do
let (:struct) { find_first(cursor, :cursor_struct) }
let (:struct) { find_by_kind(cursor, :cursor_struct) }

it "can find the first struct" do
expect(struct).not_to equal(nil)
Expand All @@ -457,7 +457,7 @@
end

describe '#find_references_in_file' do
let (:struct_cursor) {find_first(cursor_canon, :cursor_struct) }
let (:struct_cursor) {find_by_kind(cursor_canon, :cursor_struct) }

it "visits references to the cursor in the main file" do
counter = 0
Expand All @@ -479,8 +479,8 @@
end

describe '#linkage' do
let (:ref) { find_first(cursor, :cursor_type_ref) }
let (:func) { find_first(cursor, :cursor_function) }
let (:ref) { find_by_kind(cursor, :cursor_type_ref) }
let (:func) { find_by_kind(cursor, :cursor_function) }

it "returns :external if the cursor is non-static function" do
expect(func.linkage).to equal :external
Expand Down Expand Up @@ -514,15 +514,15 @@
end

describe '#definition?' do
let (:struct) { find_all(cursor_canon, :cursor_struct).at(2) }
let (:struct) { find_all_by_kind(cursor_canon, :cursor_struct).at(2) }

it "checks cursor is a definition" do
expect(struct.definition?).to be true
end
end

describe '#usr' do
let (:func) { find_first(cursor, :cursor_function) }
let (:func) { find_by_kind(cursor, :cursor_function) }

it "returns something in string" do
expect(func.usr).to be_kind_of(String)
Expand Down Expand Up @@ -551,23 +551,23 @@
end

describe '#hash' do
let (:func) { find_first(cursor, :cursor_function) }
let (:func) { find_by_kind(cursor, :cursor_function) }

it "computes hash for the cursor" do
expect(func.hash).to be_kind_of(Integer)
end
end

describe '#availability' do
let (:func) { find_first(cursor, :cursor_function) }
let (:func) { find_by_kind(cursor, :cursor_function) }

it "returns :available for the cursor availability" do
expect(func.availability).to equal(:available)
end
end

describe '#type' do
let (:field) { find_first(cursor, :cursor_field_decl) }
let (:field) { find_by_kind(cursor, :cursor_field_decl) }

it "returns type for the cursor" do
expect(field.type).to be_kind_of(Type)
Expand All @@ -576,7 +576,7 @@
end

describe '#underlying_type' do
let (:typedef) { find_first(cursor_cxx, :cursor_typedef_decl) }
let (:typedef) { find_by_kind(cursor_cxx, :cursor_typedef_decl) }

it "returns type that the cursor type is underlying" do
expect(typedef.underlying_type).to be_kind_of(Type)
Expand Down Expand Up @@ -728,7 +728,7 @@
end

describe '#included_file' do
let (:inclusion) { find_first(cursor_pp, :cursor_inclusion_directive) }
let (:inclusion) { find_by_kind(cursor_pp, :cursor_inclusion_directive) }

it 'returns the file that is included by the given inclusion directive cursor' do
expect(inclusion.included_file).to be_kind_of(FFI::Clang::File)
Expand All @@ -737,7 +737,7 @@
end

describe '#references' do
let (:struct_cursor) { find_first(cursor_canon, :cursor_struct) }
let (:struct_cursor) { find_by_kind(cursor_canon, :cursor_struct) }
let (:unspecified_references) { struct_cursor.references }
let (:specified_references) { struct_cursor.references(fixture_path("canonical.c")) }

Expand Down
2 changes: 1 addition & 1 deletion spec/ffi/clang/source_location_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
let(:translation_unit_location) { translation_unit.cursor.location }
let(:diagnostic_location) { translation_unit.diagnostics.first.location }
let(:loc1_translation_unit) { Index.new.parse_translation_unit(fixture_path("location1.c")) }
let(:loc1_cursor) { find_first(loc1_translation_unit.cursor, :cursor_function) }
let(:loc1_cursor) { find_by_kind(loc1_translation_unit.cursor, :cursor_function) }
let(:docs_cursor) { Index.new.parse_translation_unit(fixture_path("docs.c")).cursor }

it "should have a nil File if the SourceLocation is for a Translation Unit" do
Expand Down
4 changes: 2 additions & 2 deletions spec/ffi/clang/token_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
describe Tokens do
let(:translation_unit) { Index.new.parse_translation_unit(fixture_path("list.c")) }
let(:cursor) { translation_unit.cursor }
let(:range) { find_first(cursor, :cursor_struct).extent }
let(:range) { find_by_kind(cursor, :cursor_struct).extent }
let(:tokens) { translation_unit.tokenize(range) }

it "can be obtained from a translation unit" do
Expand Down Expand Up @@ -39,7 +39,7 @@
describe Token do
let(:translation_unit) { Index.new.parse_translation_unit(fixture_path("list.c")) }
let(:cursor) { translation_unit.cursor }
let(:range) { find_first(cursor, :cursor_struct).extent }
let(:range) { find_by_kind(cursor, :cursor_struct).extent }
let(:token) { translation_unit.tokenize(range).first }

it "can be obtained from a translation unit" do
Expand Down
Loading

0 comments on commit 83080ef

Please sign in to comment.