rbgccxml 0.8 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +5 -5
- data/lib/rbgccxml/node.rb +75 -73
- data/lib/rbgccxml/nodes/argument.rb +13 -2
- data/lib/rbgccxml/nodes/base.rb +14 -0
- data/lib/rbgccxml/nodes/class.rb +46 -8
- data/lib/rbgccxml/nodes/constructor.rb +8 -1
- data/lib/rbgccxml/nodes/destructor.rb +7 -0
- data/lib/rbgccxml/nodes/enum_value.rb +6 -4
- data/lib/rbgccxml/nodes/enumeration.rb +21 -2
- data/lib/rbgccxml/nodes/field.rb +18 -0
- data/lib/rbgccxml/nodes/file.rb +4 -1
- data/lib/rbgccxml/nodes/function.rb +6 -4
- data/lib/rbgccxml/nodes/function_type.rb +7 -0
- data/lib/rbgccxml/nodes/method.rb +6 -4
- data/lib/rbgccxml/nodes/struct.rb +3 -2
- data/lib/rbgccxml/nodes/type.rb +5 -3
- data/lib/rbgccxml/nodes/types/array_type.rb +29 -0
- data/lib/rbgccxml/nodes/types/cv_qualified_type.rb +9 -5
- data/lib/rbgccxml/nodes/types/fundamental_type.rb +3 -2
- data/lib/rbgccxml/nodes/types/pointer_type.rb +6 -3
- data/lib/rbgccxml/nodes/types/reference_type.rb +6 -3
- data/lib/rbgccxml/nodes/types/typedef.rb +2 -2
- data/lib/rbgccxml/nodes/variable.rb +7 -0
- data/lib/rbgccxml/parser.rb +47 -32
- data/lib/rbgccxml/query_result.rb +62 -25
- data/lib/rbgccxml/rbgccxml.rb +13 -16
- data/lib/rbgccxml/xml_parsing.rb +65 -97
- data/lib/rbgccxml.rb +26 -22
- data/test/arguments_test.rb +29 -0
- data/test/classes_test.rb +164 -26
- data/test/enumerations_test.rb +27 -19
- data/test/function_pointers_test.rb +18 -0
- data/test/functions_test.rb +7 -2
- data/test/methods_test.rb +3 -3
- data/test/namespaces_test.rb +1 -1
- data/test/node_test.rb +11 -31
- data/test/parser_test.rb +1 -1
- data/test/query_results_test.rb +15 -14
- data/test/structs_test.rb +10 -12
- data/test/test_helper.rb +10 -2
- data/test/types_test.rb +63 -38
- data/test/variables_test.rb +26 -0
- metadata +46 -31
@@ -1,15 +1,18 @@
|
|
1
1
|
module RbGCCXML
|
2
|
-
|
2
|
+
|
3
|
+
# Represents a <PointerType>, a node designating a pointer type to another Type.
|
3
4
|
class PointerType < Type
|
4
5
|
|
5
6
|
def ==(val)
|
6
7
|
check_sub_type_without(val, /\*/)
|
7
8
|
end
|
8
9
|
|
9
|
-
|
10
|
+
# See Node#to_cpp
|
11
|
+
def to_cpp(qualified = true)
|
10
12
|
type = XMLParsing.find_type_of(self.node, "type")
|
11
|
-
"#{type.
|
13
|
+
"#{type.to_cpp(qualified)}*"
|
12
14
|
end
|
15
|
+
|
13
16
|
end
|
14
17
|
|
15
18
|
end
|
@@ -1,14 +1,17 @@
|
|
1
1
|
module RbGCCXML
|
2
|
-
|
2
|
+
|
3
|
+
# References a <ReferenceType> node, which is a reference to another Type.
|
3
4
|
class ReferenceType < Type
|
4
5
|
|
5
6
|
def ==(val)
|
6
7
|
check_sub_type_without(val, /\&/)
|
7
8
|
end
|
8
9
|
|
9
|
-
def
|
10
|
+
def to_cpp(qualified = true)
|
10
11
|
type = XMLParsing.find_type_of(self.node, "type")
|
11
|
-
"#{type.
|
12
|
+
"#{type.to_cpp(qualified)}&"
|
12
13
|
end
|
14
|
+
|
13
15
|
end
|
16
|
+
|
14
17
|
end
|
data/lib/rbgccxml/parser.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'libxml'
|
2
2
|
|
3
3
|
module RbGCCXML
|
4
4
|
|
@@ -6,48 +6,63 @@ module RbGCCXML
|
|
6
6
|
# Please use RbGCCXML.parse and not this class directly
|
7
7
|
class Parser
|
8
8
|
|
9
|
-
def initialize(config = {})
|
10
|
-
|
9
|
+
def initialize(config = {})
|
10
|
+
if config[:pregenerated]
|
11
|
+
@xml_file = config.delete[:pregenerated]
|
12
|
+
else
|
13
|
+
require 'gccxml'
|
14
|
+
@gccxml = GCCXML.new
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
if includes = config.delete(:includes)
|
17
|
+
@gccxml.add_include includes
|
18
|
+
end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
if flags = config.delete(:cxxflags)
|
21
|
+
@gccxml.add_cxxflags flags
|
22
|
+
end
|
19
23
|
|
20
|
-
|
24
|
+
validate_glob(config[:files])
|
25
|
+
end
|
21
26
|
end
|
22
27
|
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
+
# Starts the parsing process. If the parser was configured
|
29
|
+
# with one or more header files, this includes:
|
30
|
+
# 1. Creating a temp file for the resulting XML.
|
31
|
+
# 2. Finding all the files to run through GCC-XML.
|
32
|
+
# 3. If applicable (more than one header was specified),
|
33
|
+
# build another temp file and #include the header files
|
34
|
+
# to ensure one and only one pass into GCC-XML.
|
28
35
|
# 4. Build up our :: Namespace node and pass that back
|
29
|
-
# to the user for querying
|
36
|
+
# to the user for querying.
|
37
|
+
#
|
38
|
+
# If the parser was configured for pregenerated GCC-XML
|
39
|
+
# output, we only have to perform step 4 above.
|
30
40
|
def parse
|
31
|
-
@
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
41
|
+
if @gccxml
|
42
|
+
require 'tempfile'
|
43
|
+
@results_file = Tempfile.new("rbgccxml")
|
44
|
+
parse_file = nil
|
45
|
+
|
46
|
+
if @files.length == 1
|
47
|
+
parse_file = @files[0]
|
48
|
+
else
|
49
|
+
# Otherwise we need to build up a single header file
|
50
|
+
# that #include's all of the files in the list, and
|
51
|
+
# parse that out instead
|
52
|
+
parse_file = build_header_for(@files)
|
53
|
+
end
|
54
|
+
|
55
|
+
xml_file = @results_file.path
|
56
|
+
@gccxml.parse(parse_file, xml_file)
|
36
57
|
else
|
37
|
-
|
38
|
-
# that #include's all of the files in the list, and
|
39
|
-
# parse that out instead
|
40
|
-
parse_file = build_header_for(@files)
|
58
|
+
xml_file = @xml_file
|
41
59
|
end
|
42
60
|
|
43
|
-
|
44
|
-
|
61
|
+
document = LibXML::XML::Document.file(xml_file)
|
62
|
+
root = document.root
|
45
63
|
# Everything starts at the :: Namespace
|
46
|
-
|
47
|
-
global_ns = document.search("//Namespace[@name='::']")[0]
|
48
|
-
|
64
|
+
global_ns = root.find("//Namespace[@name='::']")[0]
|
49
65
|
XMLParsing.doc_root = document
|
50
|
-
|
51
66
|
Namespace.new global_ns
|
52
67
|
end
|
53
68
|
|
@@ -82,7 +97,7 @@ module RbGCCXML
|
|
82
97
|
if found.empty?
|
83
98
|
raise SourceNotFoundError.new(
|
84
99
|
"Cannot find files matching #{files.inspect}. " +
|
85
|
-
"You might need to specify a full path.")
|
100
|
+
"You might need to specify a full path.")
|
86
101
|
end
|
87
102
|
|
88
103
|
@files = found.select {|f| !::File.directory?(f) }
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RbGCCXML
|
2
2
|
# All queries return either an instance of this class, or in the case of
|
3
3
|
# a single result, the node found. Use this class to further define query
|
4
|
-
# parameters.
|
4
|
+
# parameters for multiple return sets.
|
5
5
|
class QueryResult < Array
|
6
6
|
|
7
7
|
# To facilitate the management of what could be many nodes found by a single query,
|
@@ -9,8 +9,10 @@ module RbGCCXML
|
|
9
9
|
# We assume that if one node accepts the method, then all of them will.
|
10
10
|
def method_missing(name, *args)
|
11
11
|
if self[0].respond_to?(name)
|
12
|
-
self.
|
13
|
-
node.send(name, *args)
|
12
|
+
self.inject(QueryResult.new) do |memo, node|
|
13
|
+
ret = node.send(name, *args)
|
14
|
+
memo << ret if ret
|
15
|
+
memo
|
14
16
|
end
|
15
17
|
else
|
16
18
|
super
|
@@ -19,13 +21,14 @@ module RbGCCXML
|
|
19
21
|
|
20
22
|
EXPECTED_OPTIONS = [:name, :returns, :arguments, :access] unless defined?(EXPECTED_OPTIONS)
|
21
23
|
|
22
|
-
# Find within this result set any nodes that match the given options
|
23
|
-
# Options can be any or all of the following, based on the type of node
|
24
|
-
#
|
24
|
+
# Find within this result set any nodes that match the given options.
|
25
|
+
# Options can be any or all of the following, based on the type of node
|
26
|
+
# (all entries can be either Strings or Symbols):
|
27
|
+
#
|
25
28
|
# <tt>:name</tt>:: The unmangled name of the node. Can be a string or Regexp. Works on all nodes.
|
26
|
-
# <tt>:arguments</tt>:: Search according to argument types.
|
27
|
-
# This needs to be an array of strings or symbols. nil
|
28
|
-
#
|
29
|
+
# <tt>:arguments</tt>:: Search according to argument types.
|
30
|
+
# This needs to be an array of strings or symbols. nil is used as the wildcard.
|
31
|
+
# Only works on Functions, Methods, and Constructors
|
29
32
|
# <tt>:returns</tt>:: Search according to the return type. Can be a string or symbol.
|
30
33
|
# Only works on Functions and Methods
|
31
34
|
# <tt>:access</tt>:: Search according to access properties. Can be :public, :protected, or :private.
|
@@ -36,32 +39,32 @@ module RbGCCXML
|
|
36
39
|
#
|
37
40
|
# find(:arguments => [nil, nil, nil], :returns => :int)
|
38
41
|
#
|
39
|
-
# It's also possible to do this in two steps, chaining the +find+ calls, as long as
|
42
|
+
# It's also possible to do this in two steps, chaining the +find+ calls, as long as
|
40
43
|
# each +find+ in the chain has multiple results:
|
41
44
|
#
|
42
45
|
# find(:arguments => [nil, nil, nil]).find(:returns => :int)
|
43
|
-
#
|
44
|
-
# However if you want 3 random arguments OR returning int, you should use
|
46
|
+
#
|
47
|
+
# However if you want 3 random arguments OR returning int, you should use
|
45
48
|
# two seperate queries:
|
46
49
|
#
|
47
50
|
# find(:arguments => [nil, nil, nil])
|
48
51
|
# find(:returns => :int)
|
49
52
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# functions that return a pointer to MyClass:
|
53
|
+
# Typedefs, user defined types, fundamental types (int, char, etc), pointers, and references
|
54
|
+
# are all supported. For example, to find functions that return a pointer to MyClass:
|
53
55
|
#
|
54
56
|
# find(:returns => "MyClass*")
|
55
57
|
#
|
56
|
-
# There will be cases where you'll want to search *all* of a given type no matter what scope
|
57
|
-
# or nesting
|
58
|
+
# There will be cases where you'll want to search *all* of a given type no matter what the current scope
|
59
|
+
# or nesting. To put a finder into this mode, specify :all as the first parameter:
|
58
60
|
#
|
59
61
|
# find(:all, [arguments as defined above])
|
60
62
|
#
|
61
|
-
# will find all nodes that fit the normal arguments for a given type (the node type of the first
|
62
|
-
# in the initial result set. e.g. if you run <tt>classes.find(:all)</tt> then all Class nodes)
|
63
|
+
# This will find all nodes that fit the normal arguments for a given type (the node type of the first
|
64
|
+
# in the initial result set. e.g. if you run <tt>classes.find(:all)</tt> then all Class nodes) across
|
65
|
+
# the entire source.
|
63
66
|
#
|
64
|
-
# Returns: A new QueryResult containing the results, allowing for nested +finds+.
|
67
|
+
# Returns: A new QueryResult containing the results, allowing for nested +finds+.
|
65
68
|
# However, If there is only one result, returns that single Node instead.
|
66
69
|
def find(*options)
|
67
70
|
result = QueryResult.new
|
@@ -69,7 +72,7 @@ module RbGCCXML
|
|
69
72
|
|
70
73
|
if options[0] == :all
|
71
74
|
node_type = self[0].class.to_s.split(/::/)[-1]
|
72
|
-
query_set = XMLParsing.find_all(:
|
75
|
+
query_set = XMLParsing.find_all(:node_type => node_type)
|
73
76
|
options = options[1]
|
74
77
|
else
|
75
78
|
options = options[0]
|
@@ -90,13 +93,13 @@ module RbGCCXML
|
|
90
93
|
# C++ name
|
91
94
|
if name
|
92
95
|
found[:name] ||= []
|
93
|
-
found[:name] << node if node
|
96
|
+
found[:name] << node if matches?(node.name, name)
|
94
97
|
end
|
95
98
|
|
96
99
|
# Return type
|
97
100
|
if returns && [Function, Method].include?(node.class)
|
98
101
|
found[:returns] ||= []
|
99
|
-
found[:returns] << node if node.return_type
|
102
|
+
found[:returns] << node if type_matches?(node.return_type, returns.to_s)
|
100
103
|
end
|
101
104
|
|
102
105
|
# Arguments list
|
@@ -109,7 +112,7 @@ module RbGCCXML
|
|
109
112
|
keep = true
|
110
113
|
arguments.each_with_index do |arg, idx|
|
111
114
|
# nil is the "any" flag
|
112
|
-
if !arg.nil? && args[idx].cpp_type
|
115
|
+
if !arg.nil? && !type_matches?(args[idx].cpp_type, arg.to_s)
|
113
116
|
keep = false
|
114
117
|
break
|
115
118
|
end
|
@@ -134,12 +137,46 @@ module RbGCCXML
|
|
134
137
|
tmp = (tmp & value)
|
135
138
|
end
|
136
139
|
|
137
|
-
# But make sure that we always have a QueryResult and
|
140
|
+
# But make sure that we always have a QueryResult and
|
138
141
|
# not a plain Array
|
139
142
|
result << tmp
|
140
143
|
result.flatten!
|
141
144
|
|
142
145
|
result.length == 1 ? result[0] : result
|
143
146
|
end
|
147
|
+
|
148
|
+
# Performs a normal Enumerable#find_all operation, except that if only
|
149
|
+
# one Node is being returned by the Enumerable#find_all, returns that
|
150
|
+
# single node.
|
151
|
+
def find_all(&block)
|
152
|
+
res = super
|
153
|
+
res.length == 1 ? res[0] : res
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
# Finders can take strings or regexes, so this wraps up the logic that chooses
|
159
|
+
# between straight equality matching and matching
|
160
|
+
def matches?(value, against)
|
161
|
+
case against
|
162
|
+
when Regexp
|
163
|
+
value =~ against
|
164
|
+
else
|
165
|
+
value == against
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def type_matches?(node, against)
|
170
|
+
against_full =
|
171
|
+
against.is_a?(Regexp) ?
|
172
|
+
against :
|
173
|
+
/#{against.to_s.gsub("*", "\\*").gsub(/^::/, "").gsub("[", "\\[").gsub("]", "\\]")}$/
|
174
|
+
|
175
|
+
matches?(node.name, against) ||
|
176
|
+
matches?(node.to_cpp, against_full) ||
|
177
|
+
matches?(node.to_cpp(false), against_full)
|
178
|
+
end
|
179
|
+
|
180
|
+
|
144
181
|
end
|
145
182
|
end
|
data/lib/rbgccxml/rbgccxml.rb
CHANGED
@@ -3,15 +3,17 @@ module RbGCCXML
|
|
3
3
|
|
4
4
|
class << self
|
5
5
|
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# Starting point to any RbGCCXML parsing project.
|
7
|
+
#
|
8
|
+
# This method must be called *after* any calls to RbGCCXML.gccxml_path=
|
9
|
+
# or RbGCCXML.add_include_paths. Files can be one of many formats
|
10
|
+
# (and should always be full directory paths):
|
9
11
|
#
|
10
12
|
# <tt>"/path/to/file.h"</tt>
|
11
13
|
#
|
12
14
|
# <tt>"/dir/glob/**/*.h"</tt>
|
13
15
|
#
|
14
|
-
#
|
16
|
+
# or an array of either of the above.
|
15
17
|
#
|
16
18
|
# +options+ can be any of:
|
17
19
|
#
|
@@ -19,24 +21,19 @@ module RbGCCXML
|
|
19
21
|
# cxxflags: A single string, or an array of strings of other command line flags
|
20
22
|
#
|
21
23
|
# Returns the Namespace Node linked to the global namespace "::".
|
22
|
-
#
|
23
24
|
def parse(files, options = {})
|
24
|
-
# Steps here:
|
25
|
-
# 1. Find gccxml
|
26
|
-
# 2. Find all files expected to be parsed
|
27
|
-
# 3. If multiple files:
|
28
|
-
# Build up a temp file with #includes to each file to be parsed
|
29
|
-
# 4. If multiple files:
|
30
|
-
# Run gccxml on this generated file
|
31
|
-
# else
|
32
|
-
# Run gccxml on the expected file
|
33
|
-
# 5. Parse out XML into class tree
|
34
|
-
|
35
25
|
options.merge!(:files => files)
|
36
26
|
@parser = Parser.new options
|
37
27
|
@parser.parse
|
38
28
|
end
|
39
29
|
|
30
|
+
# Use this call to parse a pregenerated GCC-XML file.
|
31
|
+
#
|
32
|
+
# Returns the Namespace Node linked to the global namespace "::".
|
33
|
+
def parse_xml(filename)
|
34
|
+
@parser = Parser.new :pregenerated => filename
|
35
|
+
@parser.parse
|
36
|
+
end
|
40
37
|
end
|
41
38
|
|
42
39
|
class SourceNotFoundError < RuntimeError; end
|
data/lib/rbgccxml/xml_parsing.rb
CHANGED
@@ -1,44 +1,51 @@
|
|
1
1
|
module RbGCCXML
|
2
2
|
|
3
|
-
# A module of methods used to parse out the flat GCC-XML
|
3
|
+
# A module of methods used to parse out the flat GCC-XML xml structure into
|
4
4
|
# a proper heirarchy. These methods are used internally and not intended
|
5
5
|
# for outside use.
|
6
6
|
module XMLParsing
|
7
7
|
|
8
|
-
#
|
9
|
-
# root or if I just can't find how, but we give this module the
|
10
|
-
# Hpricot document to do proper searching.
|
8
|
+
# Save a reference to the root node of the parsed XML
|
11
9
|
def self.doc_root=(root)
|
12
10
|
@@doc_root = root
|
11
|
+
self.clear_cache
|
12
|
+
end
|
13
|
+
|
14
|
+
# Clear the internal query cache
|
15
|
+
def self.clear_cache
|
16
|
+
@@find_query_cache = {}
|
17
|
+
@@all_query_cache = {}
|
13
18
|
end
|
14
19
|
|
15
20
|
# Generic finding of nodes according to attributes.
|
16
21
|
# Special options:
|
17
22
|
#
|
18
|
-
# <tt>:
|
23
|
+
# <tt>:node_type</tt>:: Specify a certain node type to search by
|
19
24
|
#
|
20
25
|
# Any other options is directly mapped to attributes on the node. For example, to find
|
21
26
|
# a Function node that have the name "functor":
|
22
27
|
#
|
23
|
-
# XMLParsing.find(:
|
28
|
+
# XMLParsing.find(:node_type => "Function", :name => "functor")
|
24
29
|
#
|
25
30
|
# Returns the first found node
|
26
31
|
def self.find(options = {})
|
27
32
|
return nil if options.empty?
|
28
|
-
type = options.delete(:type)
|
29
|
-
|
30
|
-
# Look value up in the cache for common operations if a type was given
|
31
|
-
if(type && options.length == 1 && options.keys[0] == :id)
|
32
|
-
return cache(type, options[:id])
|
33
|
-
end
|
34
33
|
|
35
|
-
|
36
|
-
|
34
|
+
cache_key = options.to_s
|
35
|
+
cached = @@find_query_cache[cache_key]
|
36
|
+
return cached if cached
|
37
37
|
|
38
|
-
|
38
|
+
type = options.delete(:node_type)
|
39
|
+
|
40
|
+
attrs = options.map {|key, value| "[@#{key}='#{value}']"}.join
|
41
|
+
xpath = "//#{type || '*'}#{attrs}"
|
42
|
+
|
43
|
+
got = @@doc_root.find(xpath).first
|
39
44
|
|
40
45
|
if got
|
41
|
-
|
46
|
+
result = build_type(type || got.name, got)
|
47
|
+
@@find_query_cache[cache_key] = result
|
48
|
+
result
|
42
49
|
else
|
43
50
|
nil
|
44
51
|
end
|
@@ -47,31 +54,36 @@ module RbGCCXML
|
|
47
54
|
# Generic finding of nodes according to attributes.
|
48
55
|
# Special options:
|
49
56
|
#
|
50
|
-
# <tt>:
|
57
|
+
# <tt>:node_type</tt>:: Specify a certain node type to search by
|
51
58
|
#
|
52
59
|
# Any other options is directly mapped to attributes on the node. For example, to find all
|
53
60
|
# Function nodes:
|
54
61
|
#
|
55
|
-
# XMLParsing.find_all(:
|
62
|
+
# XMLParsing.find_all(:node_type => "Function")
|
56
63
|
#
|
57
64
|
# Returns all matching nodes
|
58
65
|
def self.find_all(options = {})
|
59
|
-
|
66
|
+
results = QueryResult.new
|
67
|
+
return results if options.empty?
|
68
|
+
cache_key = options.to_s
|
69
|
+
|
70
|
+
cached = @@all_query_cache[cache_key]
|
71
|
+
return cached if cached
|
60
72
|
|
61
|
-
type = options.delete(:
|
73
|
+
type = options.delete(:node_type)
|
62
74
|
attrs = options.map {|key, value| "[@#{key}='#{value}']"}.join
|
63
75
|
|
64
76
|
xpath = "//#{type}#{attrs}"
|
65
77
|
|
66
|
-
|
78
|
+
found = @@doc_root.find(xpath)
|
67
79
|
|
68
|
-
if
|
69
|
-
|
70
|
-
|
80
|
+
if found
|
81
|
+
found.each do |got|
|
82
|
+
results << build_type(type || got.name, got)
|
71
83
|
end
|
72
|
-
|
73
|
-
nil
|
84
|
+
@@all_query_cache[cache_key] = results
|
74
85
|
end
|
86
|
+
results
|
75
87
|
end
|
76
88
|
|
77
89
|
# Look through the DOM under +node+ for +node_type+ nodes.
|
@@ -79,18 +91,7 @@ module RbGCCXML
|
|
79
91
|
#
|
80
92
|
# Returns a QueryResult with the findings.
|
81
93
|
def self.find_nested_nodes_of_type(node, node_type)
|
82
|
-
|
83
|
-
|
84
|
-
# First of all limit which elements we're searching for, to ease processing.
|
85
|
-
# In the GCCXML output, node heirarchy is designated by id, members, and context
|
86
|
-
# attributes:
|
87
|
-
#
|
88
|
-
# id => Unique identifier of a given node
|
89
|
-
# members => Space-delimited array of node id's that are under this node
|
90
|
-
# context => The parent node id of this node
|
91
|
-
#
|
92
|
-
# We only want those nodes in node's context.
|
93
|
-
return nested_cache(node_type, node.attributes["id"]).flatten
|
94
|
+
self.find_all(:node_type => node_type, :context => node.attributes["id"])
|
94
95
|
end
|
95
96
|
|
96
97
|
# Arguments are a special case in gccxml as they are actual children of
|
@@ -99,6 +100,19 @@ module RbGCCXML
|
|
99
100
|
get_children_nodes_of_type(node, "Argument")
|
100
101
|
end
|
101
102
|
|
103
|
+
# Classes / Structs can have superclasses. This method finds the
|
104
|
+
# classes that are those superclasses according to the access type
|
105
|
+
# passed in (nil means find all of them)
|
106
|
+
def self.find_bases_for(node, access_type = nil)
|
107
|
+
bases = get_children_nodes_of_type(node, "Base")
|
108
|
+
|
109
|
+
if access_type
|
110
|
+
bases = bases.select {|b| b.attributes["access"] == access_type.to_s }
|
111
|
+
end
|
112
|
+
|
113
|
+
bases.map {|b| b.cpp_type }
|
114
|
+
end
|
115
|
+
|
102
116
|
# Enumeration values are children of the Enumeration element
|
103
117
|
def self.get_values_of(enum)
|
104
118
|
get_children_nodes_of_type(enum.node, "EnumValue")
|
@@ -109,76 +123,30 @@ module RbGCCXML
|
|
109
123
|
def self.get_children_nodes_of_type(node, type)
|
110
124
|
results = QueryResult.new
|
111
125
|
|
112
|
-
node.
|
113
|
-
|
126
|
+
node.children.each do |found|
|
127
|
+
next unless found.element?
|
128
|
+
results << build_type(type, found)
|
114
129
|
end
|
115
130
|
|
116
131
|
results.flatten
|
117
132
|
end
|
118
133
|
|
119
|
-
# Entrance into the type management. Given a
|
134
|
+
# Entrance into the type management. Given a GCC-XML node and an attribute
|
120
135
|
# to reference, find the C++ type related. For example, finding the return
|
121
136
|
# type of a function:
|
122
137
|
#
|
123
138
|
# +find_type_of(func_node, "returns")+ could return "std::string" node, "int" node, etc
|
124
|
-
def self.find_type_of(node, attribute)
|
125
|
-
id = node.attributes[attribute]
|
126
|
-
%w( PointerType ReferenceType FundamentalType Typedef Enumeration CvQualifiedType Class Struct ).each do |type|
|
127
|
-
return cache(type, id) if cache(type, id)
|
128
|
-
end
|
129
|
-
return nil
|
130
|
-
end
|
131
|
-
|
132
|
-
#
|
133
|
-
# Returns the element in cache for type at id.
|
134
|
-
# Used internally.
|
135
|
-
#
|
136
|
-
def self.cache(type, id)
|
137
|
-
@@types_cache ||= {}
|
138
|
-
@@types_cache[type] ||= {}
|
139
|
-
build_cache(type) if @@types_cache[type].empty?
|
140
|
-
return @@types_cache[type][id]
|
141
|
-
end
|
142
|
-
|
143
|
-
#
|
144
|
-
# Creates a cache to work off of.
|
145
|
-
# Used internally
|
146
|
-
#
|
147
|
-
def self.build_cache(type)
|
148
|
-
XMLParsing.find_all(:type => type).each do |result|
|
149
|
-
@@types_cache[type][result.attributes["id"]] = result
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
#
|
154
|
-
# Returns the element in cache for type at id
|
155
|
-
# Used internally
|
156
139
|
#
|
157
|
-
def self.
|
158
|
-
|
159
|
-
@@nested_cache[type] ||= {}
|
160
|
-
build_nested_cache(type) if @@nested_cache[type].empty?
|
161
|
-
return @@nested_cache[type][context] || QueryResult.new
|
140
|
+
def self.find_type_of(node, attr)
|
141
|
+
self.find(:id => node.attributes[attr])
|
162
142
|
end
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
#
|
167
|
-
#
|
168
|
-
def self.
|
169
|
-
|
170
|
-
@@nested_cache[type][result.attributes["context"]] ||= QueryResult.new
|
171
|
-
@@nested_cache[type][result.attributes["context"]] << result
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
|
176
|
-
#
|
177
|
-
# Clears the cache. Use this if you are querying two seperate libraries.
|
178
|
-
#
|
179
|
-
def self.clear_cache
|
180
|
-
@@nested_cache = nil
|
181
|
-
@@types_cache = nil
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
# Builds up the related RbGCCXML node according to the GCC-XML node found
|
147
|
+
# for a given query.
|
148
|
+
def self.build_type(type_name, node)
|
149
|
+
RbGCCXML.const_get(type_name).new(node)
|
182
150
|
end
|
183
151
|
end
|
184
152
|
end
|