summaryrefslogtreecommitdiff
path: root/qpid/cpp/rubygen/amqpgen.rb
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/cpp/rubygen/amqpgen.rb')
-rwxr-xr-xqpid/cpp/rubygen/amqpgen.rb490
1 files changed, 0 insertions, 490 deletions
diff --git a/qpid/cpp/rubygen/amqpgen.rb b/qpid/cpp/rubygen/amqpgen.rb
deleted file mode 100755
index b1e635a27b..0000000000
--- a/qpid/cpp/rubygen/amqpgen.rb
+++ /dev/null
@@ -1,490 +0,0 @@
-#
-# Generic AMQP code generation library.
-#
-
-# TODO aconway 2008-02-21:
-#
-# The amqp_attr_reader and amqp_child_reader for each Amqp* class
-# should correspond exactly to ampq.dtd. Currently they are more
-# permissive so we can parse 0-10 preview and 0-10 final XML.
-#
-# Code marked with "# preview" should be removed/modified when final 0-10
-# is complete and we are ready to remove preview-related code.
-#
-
-require 'delegate'
-require 'rexml/document'
-require 'pathname'
-include REXML
-
-# Handy String functions for converting names.
-class String
- # Convert to CapitalizedForm.
- def caps() gsub( /(^|\W)(\w)/ ) { |m| $2.upcase } end
-
- # Convert to underbar_separated_form.
- def bars() tr('- .','_'); end
-
- # Convert to ALL_UPPERCASE_FORM
- def shout() bars.upcase!; end
-
- # Convert to lowerCaseCapitalizedForm
- def lcaps() gsub( /\W(\w)/ ) { |m| $1.upcase } end
-
- def plural() self + (/[xs]$/ === self ? 'es' : 's'); end
-end
-
-# Sort an array by name.
-module Enumerable
- def sort_by_name() sort { |a,b| a.name <=> b.name }; end
-end
-
-# Add functions similar to attr_reader for AMQP attributes/children.
-# Symbols that are ruby Object function names (e.g. class) get
-# an "_" suffix.
-class Module
- # Add trailing _ to avoid conflict with Object methods.
- def mangle(sym)
- (Object.method_defined? sym) ? (sym.to_s+"_").intern : sym
- end
-
- # Add attribute reader for XML attribute.
- def amqp_attr_reader(*attrs)
- attrs.each { |a|
- case a
- when Symbol
- define_method(mangle(a)) {
- @amqp_attr_reader||={ }
- @amqp_attr_reader[a] ||= xml.attributes[a.to_s]
- }
- when Hash
- a.each { |attr, default|
- define_method(mangle(attr)) {
- @amqp_attr_reader||={ }
- value = xml.attributes[attr.to_s]
- if value
- @amqp_attr_reader[attr] ||= value
- else
- @amqp_attr_reader[attr] ||= default
- end
- }
- }
- end
- }
- end
-
- # Add 2 child readers:
- # elname(name) == child('elname',name)
- # elnames() == children('elname')
- def amqp_child_reader(*element_names)
- element_names.each { |e|
- define_method(mangle(e)) { |name| child(e.to_s, name) }
- define_method(mangle(e.to_s.plural)) { children(e.to_s) } }
- end
-
- # When there can only be one child instance
- def amqp_single_child_reader(*element_names)
- element_names.each { |e|
- define_method(mangle(e)) { children(e.to_s)[0] } }
- end
-end
-
-
-# An AmqpElement contains an XML element and provides a convenient
-# API to access AMQP data.
-#
-# NB: AmqpElements cache values from XML, they assume that
-# the XML model does not change after the AmqpElement has
-# been created.
-class AmqpElement
-
- def wrap(xml)
- return nil if ["assert","rule"].include? xml.name
- eval("Amqp"+xml.name.caps).new(xml, self) or raise "nil wrapper"
- end
-
- public
-
- def initialize(xml, parent)
- @xml, @parent=xml, parent
- @children=xml.elements.map { |e| wrap e }.compact
- @cache_child={}
- @cache_children={}
- @cache_children[nil]=@children
- end
-
- attr_reader :parent, :xml, :children, :doc
- amqp_attr_reader :name, :label
-
- # List of children of type elname, or all children if elname
- # not specified.
- def children(elname=nil)
- if elname
- @cache_children[elname] ||= @children.select { |c| elname==c.xml.name }
- else
- @children
- end
- end
-
- def each_descendant(&block)
- yield self
- @children.each { |c| c.each_descendant(&block) }
- end
-
- # Look up child of type elname with attribute name.
- def child(elname, name)
- @cache_child[[elname,name]] ||= children(elname).find { |c| c.name==name }
- end
-
- # Fully qualified amqp dotted name of this element
- def dotted_name() (parent ? parent.dotted_name+"." : "") + name; end
-
- # The root <amqp> element.
- def root() @root ||=parent ? parent.root : self; end
-
- # Are we in preview or final 0-10
- # preview - used to make some classes behave differently for preview vs. final
- def final?() root().version == "0-10"; end
-
- def to_s() "#<#{self.class}(#{name})>"; end
- def inspect() to_s; end
-
- # Text of doc child if there is one.
- def doc() d=xml.elements["doc"]; d and d.text; end
-
- def fqname()
- throw "fqname: #{self} #{parent.fqname} has no name" unless name
- p=parent && parent.fqname
- p ? p+"."+name : name;
- end
-
- def containing_class()
- return self if is_a? AmqpClass
- return parent && parent.containing_class
- end
-
-end
-
-class AmqpResponse < AmqpElement
- def initialize(xml, parent) super; end
-end
-
-class AmqpDoc < AmqpElement
- def initialize(xml,parent) super; end
- def text() @xml.text end
-end
-
-class AmqpChoice < AmqpElement
- def initialize(xml,parent) super; end
- amqp_attr_reader :name, :value
-end
-
-class AmqpEnum < AmqpElement
- def initialize(xml,parent) super; end
- amqp_child_reader :choice
-end
-
-# 0-10 array domains are missing element type information, add it here.
-ArrayTypes={
- "str16-array" => "str-16",
- "amqp-host-array" => "connection.amqp-host-url",
- "command-fragments" => "session.command-fragment",
- "in-doubt" => "dtx.xid"
-}
-
-class AmqpDomain < AmqpElement
- def initialize(xml, parent)
- super
- root.used_by[uses].push(fqname) if uses and uses.index('.')
- end
-
- amqp_attr_reader :type
- amqp_single_child_reader :struct # preview
- amqp_single_child_reader :enum
-
- def uses() type_=="array" ? ArrayTypes[name] : type_; end
-
- def unalias()
- d=self
- while (d.type_ != d.name and root.domain(d.type_))
- d=root.domain(d.type_)
- end
- return d
- end
-end
-
-class AmqpException < AmqpElement
- def initialize(xml, amqp) super; end;
- amqp_attr_reader :error_code
-end
-
-class AmqpField < AmqpElement
- def initialize(xml, amqp)
- super;
- root.used_by[type_].push(parent.fqname) if type_ and type_.index('.')
- end
-
- def domain() root.domain(xml.attributes["domain"]); end
- amqp_single_child_reader :struct # preview
- amqp_child_reader :exception
- amqp_attr_reader :type, :default, :code, :required
-end
-
-class AmqpChassis < AmqpElement # preview
- def initialize(xml, parent) super; end
- amqp_attr_reader :implement
-end
-
-class AmqpConstant < AmqpElement
- def initialize(xml, parent) super; end
- amqp_attr_reader :value, :class
-end
-
-class AmqpResult < AmqpElement
- def initialize(xml, parent) super; end
- amqp_single_child_reader :struct # preview
- amqp_attr_reader :type
- def name() "result"; end
-end
-
-class AmqpEntry < AmqpElement
- def initialize(xml,parent) super; end
- amqp_attr_reader :type
-end
-
-class AmqpHeader < AmqpElement
- def initialize(xml,parent) super; end
- amqp_child_reader :entry
- amqp_attr_reader :required
-end
-
-class AmqpBody < AmqpElement
- def initialize(xml,parent) super; end
- amqp_attr_reader :required
-end
-
-class AmqpSegments < AmqpElement
- def initialize(xml,parent) super; end
- amqp_child_reader :header, :body
-end
-
-class AmqpStruct < AmqpElement
- def initialize(xml, parent) super; end
- amqp_attr_reader :type # preview
- amqp_attr_reader :size, :code, :pack
- amqp_child_reader :field
-
- # preview - preview code needs default "short" for pack.
- alias :raw_pack :pack
- def pack() raw_pack or (not parent.final? and "short"); end
- def result?() parent.xml.name == "result"; end
- def domain?() parent.xml.name == "domain"; end
-end
-
-class AmqpMethod < AmqpElement
- def initialize(xml, parent) super; end
-
- amqp_attr_reader :content, :index, :synchronous
- amqp_child_reader :field, :chassis,:response
- amqp_single_child_reader :result
-
- def on_chassis?(chassis) child("chassis", chassis); end
- def on_client?() on_chassis? "client"; end
- def on_server?() on_chassis? "server"; end
-end
-
-class AmqpImplement < AmqpElement
- def initialize(xml,amqp) super; end
- amqp_attr_reader :handle, :send
-end
-
-class AmqpRole < AmqpElement
- def initialize(xml,amqp) super; end
- amqp_attr_reader :implement
-end
-
-# Base class for command and control.
-class AmqpAction < AmqpElement
- def initialize(xml,amqp) super; end
- amqp_child_reader :implement, :field, :response
- amqp_attr_reader :code
-end
-
-class AmqpControl < AmqpAction
- def initialize(xml,amqp) super; end
-end
-
-class AmqpCommand < AmqpAction
- def initialize(xml,amqp) super; end
- amqp_child_reader :exception
- amqp_single_child_reader :result, :segments
-end
-
-class AmqpClass < AmqpElement
- def initialize(xml,amqp) super; end
-
- amqp_attr_reader :index # preview
- amqp_child_reader :method # preview
-
- amqp_child_reader :struct, :domain, :control, :command, :role
- amqp_attr_reader :code
-
- # chassis should be "client" or "server"
- def methods_on(chassis) # preview
- @methods_on ||= { }
- @methods_on[chassis] ||= methods_.select { |m| m.on_chassis? chassis }
- end
-
- def l4?() # preview
- !["connection", "session", "execution"].include?(name)
- end
-
- def actions() controls+commands; end
-end
-
-class AmqpType < AmqpElement
- def initialize(xml,amqp) super; end
- amqp_attr_reader :code, :fixed_width, :variable_width
-end
-
-class AmqpXref < AmqpElement
- def initialize(xml,amqp) super; end
-end
-
-# AMQP root element.
-class AmqpRoot < AmqpElement
- amqp_attr_reader :major, :minor, :port, :comment
- amqp_child_reader :doc, :type, :struct, :domain, :constant, :class
-
- def parse(filename) Document.new(File.new(filename)).root; end
-
- # Initialize with output directory and spec files from ARGV.
- def initialize(*specs)
- raise "No XML spec files." if specs.empty?
- xml=parse(specs.shift)
- specs.each { |s| xml_merge(xml, parse(s)) }
- @used_by=Hash.new{ |h,k| h[k]=[] }
- super(xml, nil)
- end
-
- attr_reader :used_by
-
- def merge(root) xml_merge(xml, root.xml); end
-
- def version() major + "-" + minor; end
-
- # preview - only struct child reader remains for new mapping
- def domain_structs() domains.map{ |d| d.struct }.compact; end
- def result_structs()
- methods_.map { |m| m.result and m.result.struct }.compact
- end
- def structs() result_structs+domain_structs; end
-
- def methods_() classes.map { |c| c.methods_ }.flatten; end
-
- # Return all methods on chassis for all classes.
- def methods_on(chassis)
- @methods_on ||= { }
- @methods_on[chassis] ||= classes.map { |c| c.methods_on(chassis) }.flatten
- end
-
- def fqname() nil; end
-
- # TODO aconway 2008-02-21: methods by role.
-
- private
-
- # Merge contents of elements.
- def xml_merge(to,from)
- from.elements.each { |from_child|
- tag,name = from_child.name, from_child.attributes["name"]
- to_child=to.elements["./#{tag}[@name='#{name}']"]
- to_child ? xml_merge(to_child, from_child) : to.add(from_child.deep_clone) }
- end
-end
-
-# Collect information about generated files.
-class GenFiles
- @@files =[]
- def GenFiles.add(f) @@files << f; end
- def GenFiles.get() @@files; end
-end
-
-# Base class for code generators.
-# Supports setting a per-line prefix, useful for e.g. indenting code.
-#
-class Generator
- # Takes directory for output or "-", meaning print file names that
- # would be generated.
- def initialize (outdir, amqp)
- @amqp=amqp
- @outdir=outdir
- @prefix=[''] # For indentation or comments.
- @indentstr=' ' # One indent level.
- @outdent=2
- Pathname.new(@outdir).mkpath unless @outdir=="-"
- end
-
- # Create a new file, set @out.
- def file(file, &block)
- GenFiles.add file
- if (@outdir != "-")
- @path=Pathname.new "#{@outdir}/#{file}"
- @path.parent.mkpath
- @out=String.new # Generate in memory first
- if block then yield; endfile; end
- end
- end
-
- def endfile()
- if @outdir != "-"
- if @path.exist? and @path.read == @out
- puts "Skipped #{@path} - unchanged" # Dont generate if unchanged
- else
- @path.open('w') { |f| f << @out }
- puts "Generated #{@path}"
- end
- end
- end
-
- # Append multi-line string to generated code, prefixing each line.
- def gen (str)
- str.each_line { |line|
- @out << @prefix.last unless @midline
- @out << line
- @midline = nil
- }
- # Note if we stopped mid-line
- @midline = /[^\n]\z/ === str
- end
-
- # Append str + '\n' to generated code.
- def genl(str="")
- gen str
- gen "\n"
- end
-
- # Generate code with added prefix.
- def prefix(add, &block)
- @prefix.push @prefix.last+add
- if block then yield; endprefix; end
- end
-
- def endprefix()
- @prefix.pop
- end
-
- # Generate indented code
- def indent(n=1,&block) prefix(@indentstr * n,&block); end
- alias :endindent :endprefix
-
- # Generate outdented code
- def outdent(&block)
- @prefix.push @prefix.last[0...-2]
- if block then yield; endprefix; end
- end
- alias :endoutdent :endprefix
-
- attr_accessor :out
-end
-