Class: OroGen::Spec::Typekit

Inherits:
Object
  • Object
show all
Defined in:
lib/orogen/spec/typekit.rb

Overview

A typekit, i.e. a subpart of the system that handles a set of types

Typekits provide (at model time) definitions of types, and (at runtime) the support to marshal/unmarshal them on transports

Defined Under Namespace

Classes: OpaqueInfoListener

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(loader, name, registry = Typelib::Registry.new, typelist = [], interface_typelist = []) ⇒ Typekit


90
91
92
93
94
95
96
97
98
# File 'lib/orogen/spec/typekit.rb', line 90

def initialize(loader, name, registry = Typelib::Registry.new, typelist = [], interface_typelist = [])
    @loader = loader
    @name, @registry = name, registry
    @typelist = typelist.to_set
    @interface_typelist = interface_typelist.to_set
    @opaques = Array.new
    @opaque_registry = Typelib::Registry.new
    @imported_typekits = Set.new
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object

Adds to the API of self the create_* methods on Typelib::Registry. All create_ methods are available, as well as the corresponding create_interface_XXX which both creates the type and declares it as a valid interface type

Examples:

create a null type

typekit.create_interface_null('/NewType')

300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/orogen/spec/typekit.rb', line 300

def method_missing(m, *args, &block)
    case m.to_s
    when /^create_(interface_)?(\w+)$/
        interface = !!$1
        category  = $2
        type = registry.send("create_#{category}", *args, &block)
        typelist << type.name
        if interface
            interface_typelist << type.name
        end
        type
    else super
    end
end

Instance Attribute Details

#imported_typekitsObject (readonly)

Returns the value of attribute imported_typekits


17
18
19
# File 'lib/orogen/spec/typekit.rb', line 17

def imported_typekits
  @imported_typekits
end

#interface_typelistObject (readonly)

Returns the value of attribute interface_typelist


12
13
14
# File 'lib/orogen/spec/typekit.rb', line 12

def interface_typelist
  @interface_typelist
end

#loaderObject (readonly)

Returns the value of attribute loader


8
9
10
# File 'lib/orogen/spec/typekit.rb', line 8

def loader
  @loader
end

#nameObject (readonly)

Returns the value of attribute name


9
10
11
# File 'lib/orogen/spec/typekit.rb', line 9

def name
  @name
end

#opaque_registryObject (readonly)

Returns the value of attribute opaque_registry


15
16
17
# File 'lib/orogen/spec/typekit.rb', line 15

def opaque_registry
  @opaque_registry
end

#opaquesObject (readonly)

Returns the value of attribute opaques


14
15
16
# File 'lib/orogen/spec/typekit.rb', line 14

def opaques
  @opaques
end

#registryObject (readonly)

Returns the value of attribute registry


10
11
12
# File 'lib/orogen/spec/typekit.rb', line 10

def registry
  @registry
end

#typelistObject (readonly)

Returns the value of attribute typelist


11
12
13
# File 'lib/orogen/spec/typekit.rb', line 11

def typelist
  @typelist
end

Class Method Details

.from_raw_data(loader, name, registry_xml, typelist_txt) ⇒ Object


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/orogen/spec/typekit.rb', line 71

def self.from_raw_data(loader, name, registry_xml, typelist_txt)
    typekit_registry = Typelib::Registry.new
    Typelib::Registry.add_standard_cxx_types(typekit_registry)
    typekit_registry.merge_xml(registry_xml)

    typekit_typelist, typekit_interface_typelist = parse_typelist(typelist_txt)
    typekit = self.new(loader, name,
                  typekit_registry,
                  typekit_typelist,
                  typekit_interface_typelist)

    listener = OpaqueInfoListener.new(typekit_registry)
    REXML::Document.parse_stream(registry_xml, listener)
    typekit.opaques.concat(listener.opaques)
    typekit.opaque_registry.merge(listener.registry)

    typekit
end

.parse_typelist(typelist_txt) ⇒ Object


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/orogen/spec/typekit.rb', line 23

def self.parse_typelist(typelist_txt)
    raw_typelist = typelist_txt.split("\n").map(&:strip)
    typekit_typelist, typekit_interface_typelist = [], []
    raw_typelist.each do |decl|
        # using non greedy kleene star to match first expression: .*?
        # to handle following patterns:
        # /string
        # /unsigned char[8]
        # /unsigned char[8] 0 
        if decl =~ /^(.*) (\d)$/
            type, is_interface = $1, ($2 == '1')
        else
            type, is_interface = decl, true
        end

        typekit_typelist << type
        if is_interface
            typekit_interface_typelist << type
        end
    end
    return typekit_typelist, typekit_interface_typelist
end

Instance Method Details

#defines_array_of?(type) ⇒ Boolean


111
112
113
114
115
116
117
# File 'lib/orogen/spec/typekit.rb', line 111

def defines_array_of?(type)
    typename = if type.respond_to?(:name) then type.name
               else type.to_str
               end

    typelist.any? { |str| str =~ /#{Regexp.quote(typename)}(\[\d+\])+/ }
end

#find_opaque_for_intermediate(type) ⇒ Type?

Finds the opaque (or opaque-containing) type for which the given type is an intermediate


159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/orogen/spec/typekit.rb', line 159

def find_opaque_for_intermediate(type)
    type = resolve_type(type.name)
    if m_type?(type)
        # Yuk
        begin
            if @intermediate_to_opaque && (result = @intermediate_to_opaque[type.name])
                result
            elsif type.name =~ /_m$/
                resolve_type(type.name.gsub(/_m$/, ''))
            else raise Typelib::NotFound
            end
        rescue Typelib::NotFound
            # This is a pretty expensive operation and is seldom
            # needed, so avoid doing it unnecessarily
            @intermediate_to_opaque ||= Hash.new
            @indexed_intermediates ||= Set.new
            registry.each do |t|
                if !@indexed_intermediates.include?(t) && t.contains_opaques?
                    @indexed_intermediates << t
                    @intermediate_to_opaque[intermediate_type_name_for(t)] = t
                end
            end
            @intermediate_to_opaque[type.name]
        end
    elsif type <= Typelib::ContainerType
        if opaque_deference = find_opaque_for_intermediate(type.deference)
            resolve_type("#{type.container_kind}<#{opaque_deference.name}>")
        end
    elsif opaque_def = opaques.find { |spec| resolve_type(spec.intermediate).eql? type }
        opaque_def.type
    end
end

#has_opaques?Boolean


100
101
102
103
104
105
# File 'lib/orogen/spec/typekit.rb', line 100

def has_opaques?
    if @has_opaques.nil?
        @has_opaques = registry.any? { |t| includes?(t) && t.opaque? }
    end
    @has_opaques
end

#include?(type) ⇒ Boolean


125
126
127
128
129
130
# File 'lib/orogen/spec/typekit.rb', line 125

def include?(type)
    typename = if type.respond_to?(:name) then type.name
               else type.to_str
               end
    typelist.include?(typename)
end

#includes?(type) ⇒ Boolean

Deprecated.

use #include instead


121
122
123
# File 'lib/orogen/spec/typekit.rb', line 121

def includes?(type)
    include?(type)
end

#inspectObject


282
283
284
# File 'lib/orogen/spec/typekit.rb', line 282

def inspect
    "#<OroGen::Spec::Typekit #{name}>"
end

#interface_type?(type) ⇒ Boolean


132
133
134
135
136
137
# File 'lib/orogen/spec/typekit.rb', line 132

def interface_type?(type)
    typename = if type.respond_to?(:name) then type.name
               else type.to_str
               end
    interface_typelist.include?(typename)
end

#intermediate_type?(type) ⇒ Boolean

Checks if a type is used as an intermediate


256
257
258
# File 'lib/orogen/spec/typekit.rb', line 256

def intermediate_type?(type)
    !!find_opaque_for_intermediate(type)
end

#intermediate_type_for(type_def) ⇒ Type

Gets the intermediate type for a given type


239
240
241
242
# File 'lib/orogen/spec/typekit.rb', line 239

def intermediate_type_for(type_def)
    typename = intermediate_type_name_for(type_def)
    return resolve_type(typename)
end

#intermediate_type_name_for(type_def) ⇒ String

Computes the name of the type that should be used as an intermediate for the given type


202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/orogen/spec/typekit.rb', line 202

def intermediate_type_name_for(type_def)
    type = resolve_type(type_def)
    if type.opaque?
        opaque_specification(type_def).intermediate
    elsif type.contains_opaques?
        if type < Typelib::ArrayType
            "#{intermediate_type_name_for(type.deference)}[#{type.length}]"
        elsif type < Typelib::ContainerType
            "#{type.container_kind}<#{intermediate_type_name_for(type.deference)}>"
        else
            path = Typelib.split_typename(type.name)
            path.map! do |p|
                p.gsub(/[<>\[\], \/]/, '_')
            end
            "/" + path.join("/") + "_m"
        end
    else type.name
    end
end

#m_type?(type) ⇒ Boolean

Checks if a type is an oroGen-generated type used as an intermediate


262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/orogen/spec/typekit.rb', line 262

def m_type?(type)
    typename = type.name
    if type.name =~ /_m$/
        return true
    end

    if type.respond_to?(:deference)
        while type.respond_to?(:deference)
            type = type.deference
        end
        m_type?(type)
    else
        false
    end
end

#opaque_specification(type_def) ⇒ OpaqueDefinition

Get the opaque definition for a given type


143
144
145
146
147
148
149
150
151
152
# File 'lib/orogen/spec/typekit.rb', line 143

def opaque_specification(type_def)
    type = resolve_type(type_def)
    raise "#{type} is unknown" unless type
    raise "#{type} is not opaque" unless type.opaque?
    if result = opaques.find { |opaque_def| opaque_def.type.eql? type }
        result
    else
        raise InternalError, "#{self}#opaque_specification called for type #{type.name}, but could not find the corresponding opaque specification"
    end
end

#opaque_type_for(type) ⇒ Model<Typelib::Type>

Gets the opaque type for a given type


251
252
253
# File 'lib/orogen/spec/typekit.rb', line 251

def opaque_type_for(type)
    find_opaque_for_intermediate(type) || resolve_type(type)
end

#resolve_type(type) ⇒ Model<Typelib::Type>

Returns a matching type in #registry

Raises:

  • Typelib::NotFound


227
228
229
230
# File 'lib/orogen/spec/typekit.rb', line 227

def resolve_type(type)
    type = type.name if type.respond_to?(:name)
    registry.get(type)
end

#respond_to_missing?(m, include_private = false) ⇒ Boolean


286
287
288
289
290
291
# File 'lib/orogen/spec/typekit.rb', line 286

def respond_to_missing?(m, include_private = false)
    if super then return super
    elsif m.to_s =~ /^create_(interface_)?(\w+)$/
        registry.respond_to?("create_#{$2}")
    end
end

#self_typesObject


107
108
109
# File 'lib/orogen/spec/typekit.rb', line 107

def self_types
    typelist.map { |name| registry.get(name) }
end

#to_sObject


278
279
280
# File 'lib/orogen/spec/typekit.rb', line 278

def to_s
    "#<OroGen::Spec::Typekit #{name}>"
end