#--------------------------------------------------------------------
# delegate.rb - IDL delegator
#
# Author: Martin Corino
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the RIDL LICENSE which is
# included with this program.
#
# Copyright (c) Remedy IT Expertise BV
#--------------------------------------------------------------------
require 'ridl/node'
require 'ridl/expression'
module IDL
ORB_PIDL = 'orb.pidlc'.freeze
class Delegator
# #pragma handler registry
# each keyed entry a callable object:
# - responds to #call(delegator, cur_node, pragma_string)
# - returns boolean to indicate pragma recognized and handled (true) or not (false)
@@pragma_handlers = {}
def self.add_pragma_handler(key, h = nil, &block)
raise 'add_pragma_handler requires a callable object or a block' unless h&.respond_to?(:call) || block_given?
@@pragma_handlers[key] = block_given? ? block : h
end
def self.get_pragma_handler(key)
@@pragma_handlers[key]
end
def initialize(params = {})
@annotation_stack = IDL::AST::Annotations.new
@includes = {}
@expand_includes = params[:expand_includes] || false
@preprocess = params[:preprocess] || false
@preprocout = params[:output] if @preprocess
@ignore_pidl = params[:ignore_pidl] || false
@root_namespace = nil
unless params[:namespace].nil?
@root_namespace = IDL::AST::Module.new(params[:namespace], nil, {})
end
end
attr_reader :root, :root_namespace
def pre_parse
@root = nil
unless @preprocess || @ignore_pidl
IDL.backend.lookup_path.each do |be_root|
pidl_file = File.join(be_root, ORB_PIDL)
if File.file?(pidl_file) && File.readable?(pidl_file)
f = File.open(pidl_file, 'r')
begin
@root, @includes = Marshal.load(f)
@cur = @root
rescue Exception => e
IDL.error("RIDL - failed to load ORB pidlc [#{e}]\n You probably need to rebuild the bootstrap file (compile orb.idl to orb.pidlc).")
exit(1)
ensure
f.close
end
break
end
end
return if @root
end
@root = @cur = IDL::AST::Module.new(nil, nil, {}) # global root
@last = nil
@last_pos = nil
end
def post_parse
if @preprocess
Marshal.dump([@root, @includes], @preprocout)
end
end
private
def set_last(node = nil)
@last = node
@last_pos = @scanner.position.dup if node
node
end
public
def visit_nodes(walker)
walker.visit_nodes(self)
end
def walk_nodes(walker, root_node = nil)
(root_node || @root).walk_members { |m| walk_member(m, walker) }
end
def walk_member(m, w)
case m
when IDL::AST::Include
unless m.is_preprocessed?
if @expand_includes
if m.is_defined?
w.enter_include(m)
m.walk_members { |cm| walk_member(cm, w) }
w.leave_include(m)
end
else
w.visit_include(m)
end
end
when IDL::AST::Porttype, IDL::AST::TemplateModule
# these are template types and do not generally generate
# code by themselves but only when 'instantiated' (used)
# in another type
when IDL::AST::Module
w.enter_module(m)
m.walk_members { |cm| walk_member(cm, w) }
w.leave_module(m)
when IDL::AST::Interface
if m.is_forward?
w.declare_interface(m)
else
w.enter_interface(m)
m.walk_members { |cm| walk_member(cm, w) }
w.leave_interface(m)
end
when IDL::AST::Home
_te = w.respond_to?(:enter_home)
_tl = w.respond_to?(:leave_home)
return unless _te || _tl
w.enter_home(m) if _te
m.walk_members { |cm| walk_member(cm, w) }
w.leave_home(m) if _tl
when IDL::AST::Component
if m.is_forward?
w.declare_component(m) if w.respond_to?(:declare_component)
else
_te = w.respond_to?(:enter_component)
_tl = w.respond_to?(:leave_component)
return unless _te || _tl
w.enter_component(m) if _te
m.walk_members { |cm| walk_member(cm, w) }
w.leave_component(m) if _tl
end
when IDL::AST::Connector
_te = w.respond_to?(:enter_connector)
_tl = w.respond_to?(:leave_connector)
return unless _te || _tl
w.enter_connector(m) if _te
m.walk_members { |cm| walk_member(cm, w) }
w.leave_connector(m) if _tl
when IDL::AST::Port
w.visit_port(m) if w.respond_to?(:visit_port)
when IDL::AST::Valuebox
w.visit_valuebox(m)
when IDL::AST::Valuetype, IDL::AST::Eventtype
if m.is_forward?
w.declare_valuetype(m)
else
w.enter_valuetype(m)
m.walk_members { |cm| walk_member(cm, w) }
w.leave_valuetype(m)
end
when IDL::AST::Finder
w.visit_finder(m) if w.respond_to?(:visit_finder)
when IDL::AST::Initializer
w.visit_factory(m) if w.respond_to?(:visit_factory)
when IDL::AST::Const
w.visit_const(m)
when IDL::AST::Operation
w.visit_operation(m)
when IDL::AST::Attribute
w.visit_attribute(m)
when IDL::AST::Exception
w.enter_exception(m)
m.walk_members { |cm| walk_member(cm, w) }
w.leave_exception(m)
when IDL::AST::Struct
if m.is_forward?
w.declare_struct(m)
else
w.enter_struct(m)
m.walk_members { |cm| walk_member(cm, w) }
w.leave_struct(m)
end
when IDL::AST::Union
if m.is_forward?
w.declare_union(m)
else
w.enter_union(m)
m.walk_members { |cm| walk_member(cm, w) }
w.leave_union(m)
end
when IDL::AST::Typedef
w.visit_typedef(m)
when IDL::AST::Enum
w.visit_enum(m)
when IDL::AST::Enumerator
w.visit_enumerator(m)
else
raise "Invalid IDL member type for walkthrough: #{m.class.name}"
end
end
def is_included?(s)
@includes.has_key?(s)
end
def enter_include(s, fullpath)
params = { filename: s, fullpath: fullpath }
params[:defined] = true
params[:preprocessed] = @preprocess
@cur = @cur.define(IDL::AST::Include, "$INC:" + s, params)
@includes[s] = @cur
set_last
@cur
end
def leave_include
set_last
@cur = @cur.enclosure
end
def declare_include(s)
params = { filename: s, fullpath: @includes[s].fullpath }
params[:defined] = false
params[:preprocessed] = @includes[s].is_preprocessed?
@cur.define(IDL::AST::Include, "$INC:" + s, params)
end
def pragma_prefix(s)
@cur.prefix = s
end
def pragma_version(id, major, minor)
ids = id.split('::')
global = false
if ids.first.empty?
global = true
ids.shift
end
t = parse_scopedname(global, ids)
t.node.set_repo_version(major, minor)
end
def pragma_id(id, repo_id)
ids = id.split('::')
global = false
if ids.first.empty?
global = true
ids.shift
end
t = parse_scopedname(global, ids)
t.node.set_repo_id(repo_id)
end
def handle_pragma(pragma_string)
unless @@pragma_handlers.values.reduce(false) { |rc, h| h.call(self, @cur, pragma_string) || rc }
IDL.log(1, "RIDL - unrecognized pragma encountered: #{pragma_string}.")
end
end
def define_typeprefix(type, pfx)
type.node.replace_prefix(pfx.to_s)
end
def define_typeid(type, tid)
type.node.set_repo_id(tid.to_s)
end
def define_annotation(annid, annpos, anncomment, annbody)
IDL.log(3, "parsed #{anncomment ? 'commented ' : ''}Annotation #{annid}(#{annbody}) @ #{annpos}")
if anncomment && @last && (@last_pos.line == annpos.line) && (@last_pos.name == annpos.name)
IDL.log(3, 'adding annotation to last node')
@last.annotations << IDL::AST::Annotation.new(annid, annbody)
else
IDL.log(3, 'appending annotation cached stack')
@annotation_stack << IDL::AST::Annotation.new(annid, annbody)
end
end
def define_module(name)
@cur = @cur.define(IDL::AST::Module, name)
@cur.annotations.concat(@annotation_stack)
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur
end
def end_module(_node)
set_last(@cur)
@cur = @cur.enclosure # must equals to argument mod
end
def register_template_module_name(name_spec)
@template_module_name = name_spec
end
def define_template_module(global, names)
if global || names.size > 1
raise "no scoped identifier allowed for template module: #{(global ? '::' : '') + names.join('::')}"
end
@cur = @cur.define(IDL::AST::TemplateModule, names[0])
@cur.annotations.concat(@annotation_stack)
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur
end
alias :end_template_module :end_module
def define_template_parameter(name, type)
if @template_module_name
tmp = @template_module_name
@template_module_name = nil # reset
define_template_module(*tmp)
end
params = { type: type }
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::TemplateParam, name, params))
@cur
end
def instantiate_template_module(name, parameters)
tmp = @template_module_name
@template_module_name = nil # reset
template_type = parse_scopedname(*tmp)
unless template_type.node.is_a?(IDL::AST::TemplateModule)
raise "invalid module template specification: #{template_type.node.typename} #{template_type.node.scoped_lm_name}"
end
params = { template: template_type.node, template_params: parameters }
mod_inst = @cur.define(IDL::AST::Module, name, params)
mod_inst.annotations.concat(@annotation_stack)
@annotation_stack = IDL::AST::Annotations.new
set_last(mod_inst.template.instantiate(mod_inst))
@cur
end
def declare_template_reference(name, type, tpl_params)
params = {}
params[:tpl_type] = type
params[:tpl_params] = tpl_params || []
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::TemplateModuleReference, name, params))
@cur
end
def declare_interface(name, attrib = nil)
params = {}
params[:abstract] = attrib == :abstract
params[:local] = attrib == :local
params[:forward] = true
params[:pseudo] = false
raise "annotations with forward declaration of #{name} not allowed" unless @annotation_stack.empty?
@cur.define(IDL::AST::Interface, name, params)
set_last
@cur
end
def define_interface(name, attrib, inherits = [])
params = {}
params[:abstract] = attrib == :abstract
params[:local] = attrib == :local
params[:pseudo] = attrib == :pseudo
params[:forward] = false
params[:inherits] = inherits
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Interface, name, params)
end
def end_interface(_node)
set_last(@cur)
@cur = @cur.enclosure # must equals to argument mod
end
def define_home(name, base, component, key = nil, supports = nil)
params = {}
params[:base] = base
params[:component] = component
params[:key] = key
params[:supports] = supports || []
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Home, name, params)
end
def end_home(_node)
set_last(@cur)
@cur = @cur.enclosure
end
def declare_component(name)
params = {}
params[:forward] = true
raise "annotations with forward declaration of #{name} not allowed" unless @annotation_stack.empty?
set_last
@cur.define(IDL::AST::Component, name, params)
end
def define_component(name, base, supports = nil)
params = {}
params[:base] = base
params[:supports] = supports || []
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Component, name, params)
end
def end_component(_node)
set_last(@cur)
@cur = @cur.enclosure
end
def define_connector(name, base = nil)
params = {}
params[:base] = base
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Connector, name, params)
end
def end_connector(_node)
set_last(@cur)
@cur = @cur.enclosure
end
def define_porttype(name)
params = {}
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Porttype, name, params)
end
def end_porttype(_node)
set_last(@cur)
@cur = @cur.enclosure
end
def declare_port(name, porttype, type, multiple = false)
params = {}
params[:porttype] = porttype
params[:type] = type
params[:multiple] = multiple
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Port, name, params))
@cur
end
def declare_eventtype(name, attrib = nil)
params = {}
params[:abstract] = attrib == :abstract
params[:forward] = true
raise "annotations with forward declaration of #{name} not allowed" unless @annotation_stack.empty?
set_last
@cur.define(IDL::AST::Eventtype, name, params)
@cur
end
def define_eventtype(name, attrib, inherits = {})
params = {}
params[:abstract] = attrib == :abstract
params[:custom] = attrib == :custom
params[:forward] = false
params[:inherits] = inherits
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Eventtype, name, params)
@cur
end
def declare_valuetype(name, attrib = nil)
params = {}
params[:abstract] = attrib == :abstract
params[:forward] = true
raise "annotations with forward declaration of #{name} not allowed" unless @annotation_stack.empty?
set_last
@cur.define(IDL::AST::Valuetype, name, params)
@cur
end
def define_valuetype(name, attrib, inherits = {})
params = {}
params[:abstract] = attrib == :abstract
params[:custom] = attrib == :custom
params[:forward] = false
params[:inherits] = inherits
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Valuetype, name, params)
@cur
end
def end_valuetype(node)
node.defined = true
set_last(@cur)
ret = IDL::Type::ScopedName.new(@cur)
@cur = @cur.enclosure # must equals to argument mod
ret
end
alias :end_eventtype :end_valuetype
def declare_state_member(type, name, public_)
params = {}
params[:type] = type
params[:visibility] = (public_ ? :public : :private)
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::StateMember, name, params))
@cur
end
def define_valuebox(name, type)
params = { type: type }
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Valuebox, name, params))
@cur
end
def declare_initializer(name, params_, raises_)
params = {}
params[:params] = params_
params[:raises] = raises_
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Initializer, name, params))
@cur
end
def declare_finder(name, params_, raises_)
params = {}
params[:params] = params_
params[:raises] = raises_
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Finder, name, params))
@cur
end
def parse_scopedname(global, namelist)
node = root = if global then @root else @cur end
first = nil
namelist.each do |nm|
n = node.resolve(nm)
if n.nil?
raise "cannot find type name '#{nm}' in scope '#{node.scoped_name}'"
end
node = n
first = node if first.nil?
end
root.introduce(first)
case node
when IDL::AST::Module, IDL::AST::TemplateModule,
IDL::AST::Interface, IDL::AST::Home, IDL::AST::Component,
IDL::AST::Porttype, IDL::AST::Connector,
IDL::AST::Struct, IDL::AST::Union, IDL::AST::Typedef,
IDL::AST::Exception, IDL::AST::Enum,
IDL::AST::Valuetype, IDL::AST::Valuebox
Type::ScopedName.new(node)
when IDL::AST::TemplateParam
if node.idltype.is_a?(IDL::Type::Const)
Expression::ScopedName.new(node)
else
Type::ScopedName.new(node)
end
when IDL::AST::Const
Expression::ScopedName.new(node)
when IDL::AST::Enumerator
Expression::Enumerator.new(node)
else
raise "invalid reference to #{node.class.name}: #{node.scoped_name}"
end
end
def parse_literal(_typestring, _value)
k = Expression::Value
case _typestring
when :boolean
k.new(Type::Boolean.new, _value)
when :integer
_type = [
Type::Octet,
Type::Short,
Type::Long,
Type::LongLong,
Type::ULongLong
].detect { |t| t::Range === _value }
if _type.nil?
raise "it's not a valid integer: #{v.to_s}"
end
k.new(_type.new, _value)
when :string
k.new(Type::String.new, _value)
when :wstring
k.new(Type::WString.new, _value)
when :char
k.new(Type::Char.new, _value)
when :wchar
k.new(Type::WChar.new, _value)
when :fixed
k.new(Type::Fixed.new, _value)
when :float
k.new(Type::Float.new, _value)
else
raise ParseError, "unknown literal type: #{type}"
end
end
def parse_positive_int(_expression)
if _expression.is_template?
_expression
else
if not ::Integer === _expression.value
raise "must be integer: #{_expression.value.inspect}"
elsif _expression.value.negative?
raise "must be positive integer: #{_expression.value}"
end
_expression.value
end
end
def define_const(_type, _name, _expression)
params = { type: _type, expression: _expression }
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Const, _name, params))
@cur
end
def declare_op_header(_oneway, _type, _name)
params = {}
params[:oneway] = (_oneway == :oneway)
params[:type] = _type
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Operation, _name, params)
end
def declare_op_parameter(_attribute, _type, _name)
params = {}
params[:attribute] = _attribute
params[:type] = _type
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Parameter, _name, params))
@cur
end
def declare_op_footer(_raises, instantiation_context)
@cur.raises = _raises || []
@cur.context = instantiation_context
unless @cur.context.nil?
raise "context phrase's not supported"
end
set_last(@cur)
@cur = @cur.enclosure
end
def declare_attribute(_type, _name, _readonly = false)
params = {}
params[:type] = _type
params[:readonly] = _readonly
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Attribute, _name, params))
end
def declare_struct(name)
params = { forward: true }
raise "annotations with forward declaration of #{name} not allowed" unless @annotation_stack.empty?
set_last
@cur.define(IDL::AST::Struct, name, params)
@cur
end
def define_struct(name)
params = { forward: false }
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Struct, name, params)
end
def declare_member(_type, name)
params = {}
params[:type] = _type
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Member, name, params))
@cur
end
def end_struct(node)
node.defined = true
set_last(@cur)
ret = IDL::Type::ScopedName.new(@cur)
@cur = @cur.enclosure
ret
end
def define_exception(name)
params = { forward: false }
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Exception, name, params)
end
def end_exception(_node)
set_last(@cur)
ret = IDL::Type::ScopedName.new(@cur)
@cur = @cur.enclosure
ret
end
def declare_union(name)
params = { forward: true }
raise "annotations with forward declaration of #{name} not allowed" unless @annotation_stack.empty?
set_last
@cur.define(IDL::AST::Union, name, params)
@cur
end
def define_union(name)
params = { forward: false }
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Union, name, params)
end
def define_union_switchtype(union_node, switchtype)
union_node.set_switchtype(switchtype)
union_node.annotations.concat(@annotation_stack)
@annotation_stack = IDL::AST::Annotations.new
union_node
end
def define_case(_labels, _type, _name)
params = {}
params[:type] = _type
params[:labels] = _labels
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::UnionMember, _name, params))
@cur
end
def end_union(node)
node.validate_labels
node.defined = true
set_last(@cur)
ret = IDL::Type::ScopedName.new(@cur)
@cur = @cur.enclosure
ret
end
def define_enum(_name)
params = {}
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last
@cur = @cur.define(IDL::AST::Enum, _name, params)
end
def declare_enumerator(_name)
n = @cur.enumerators.length
params = {
value: n,
enum: @cur
}
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.enclosure.define(IDL::AST::Enumerator, _name, params))
@cur
end
def end_enum(_node)
set_last(@cur)
ret = IDL::Type::ScopedName.new(@cur)
@cur = @cur.enclosure
ret
end
def declare_typedef(_type, _name)
params = {}
params[:type] = _type
params[:annotations] = @annotation_stack
@annotation_stack = IDL::AST::Annotations.new
set_last(@cur.define(IDL::AST::Typedef, _name, params))
@cur
end
end # Delegator
end # IDL