diff options
author | Rajith Muditha Attapattu <rajith@apache.org> | 2011-05-27 15:44:23 +0000 |
---|---|---|
committer | Rajith Muditha Attapattu <rajith@apache.org> | 2011-05-27 15:44:23 +0000 |
commit | 66765100f4257159622cefe57bed50125a5ad017 (patch) | |
tree | a88ee23bb194eb91f0ebb2d9b23ff423e3ea8e37 /qpid/cpp/rubygen/0-10/specification.rb | |
parent | 1aeaa7b16e5ce54f10c901d75c4d40f9f88b9db6 (diff) | |
parent | 88b98b2f4152ef59a671fad55a0d08338b6b78ca (diff) | |
download | qpid-python-rajith_jms_client.tar.gz |
Creating a branch for experimenting with some ideas for JMS client.rajith_jms_client
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/rajith_jms_client@1128369 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/cpp/rubygen/0-10/specification.rb')
-rwxr-xr-x | qpid/cpp/rubygen/0-10/specification.rb | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/qpid/cpp/rubygen/0-10/specification.rb b/qpid/cpp/rubygen/0-10/specification.rb new file mode 100755 index 0000000000..ef193f5fd0 --- /dev/null +++ b/qpid/cpp/rubygen/0-10/specification.rb @@ -0,0 +1,389 @@ +#!/usr/bin/env ruby +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +$: << ".." # Include .. in load path +require 'cppgen' + + +# Dummy element representing an unknown struct type. +class UnknownStruct + def visitable?() true end + def fqclassname() "UnknownStruct" end +end + +# Dummy element representing a session.header field +class SessionHeaderField + def amqp2cpp() "session::Header" end + def cppname() "sessionHeader" end + def name() "session-header" end +end + +class Specification < CppGen + def initialize(outdir, amqp) + super(outdir, amqp) + @ns="qpid::amqp_#{@amqp.version.bars}" + @dir="qpid/amqp_#{@amqp.version.bars}" + end + + # domains + + def domain_h(d) + genl + typename=d.name.typename + if d.enum + scope("enum #{typename} {", "};") { + genl d.enum.choices.map { |c| + "#{c.name.constname} = #{c.value}" }.join(",\n") + } + scope("inline SerializeAs<#{typename}, uint8_t> serializable(#{typename}& e) {") { + genl "return SerializeAs<#{typename}, uint8_t>(e);" + } + else + genl "typedef #{d.amqp2cpp} #{typename};" + end + end + + def visitable?(x) x.code and x.size=="4" end + + # Used by structs, commands and controls. + def action_struct_h(x, base, consts, &block) + genl + base = visitable?(x) ? ["public #{base}"] : [] + struct(x.classname, *base) { + x.fields.each { |f| genl "#{f.amqp2cpp} #{f.cppname};" } + genl + genl "static const char* NAME;" + consts.each { + |c| genl "static const uint8_t #{c.upcase}=#{(x.send c) or 0};" + } + genl "static const uint8_t CLASS_CODE=#{x.containing_class.nsname}::CODE;" + genl "static const char* CLASS_NAME;" + ctor_decl("explicit #{x.classname}", x.parameters(true)) + + if visitable? x + genl "void accept(Visitor&);" + genl "void accept(ConstVisitor&) const;" + end + + if (x.fields.empty?) + genl "template <class S> void serialize(S&) {}" + else + scope("template <class S> void serialize(S& s) {") { + gen "s"; x.fields.each { |f| gen "(#{f.cppname})"}; genl ";" + } + end + genl + yield if block + } + case x + when AmqpCommand then packer = "CommandPacker" + when AmqpControl then packer = "Packer" + when AmqpStruct then packer = "SizedPacker" + end + genl "inline #{packer}<#{x.classname}> serializable(#{x.classname}& x) { return #{packer}<#{x.classname}>(x); }" unless x.respond_to? :pack and x.pack == "0" + genl "std::ostream& operator << (std::ostream&, const #{x.classname}&);" + genl "bool operator==(const #{x.classname}&, const #{x.classname}&);" + end + + def action_struct_cpp(x, &block) + genl + genl "const char* #{x.classname}::NAME=\"#{x.fqname}\";" + genl "const char* #{x.classname}::CLASS_NAME=#{x.containing_class.nsname}::NAME;" + genl + ctor=x.classname+"::"+x.classname + ctor_defn(ctor, x.parameters, x.initializers) {} + + if visitable? x + genl "void #{x.classname}::accept(Visitor& v) { v.visit(*this); }" + genl "void #{x.classname}::accept(ConstVisitor& v) const { v.visit(*this); }" + end + genl + scope("std::ostream& operator << (std::ostream& o, const #{x.classname}&#{"x" unless x.fields.empty?}) {") { + genl "o << \"#{x.fqname}[\";"; + x.fields.each{ |f| genl "o << \" #{f.name}=\" << x.#{f.cppname};" } + genl "o << \"]\";" + genl "return o;" + } + yield if block + end + + # structs + + def struct_h(s) action_struct_h(s, "Struct", ["size","pack","code"]); end + def struct_cpp(s) action_struct_cpp(s) end + + # command and control + + def action_h(a) + action_struct_h(a, a.base, ["code"]) { + struct("Handler") { + scope("void #{a.funcname}(", ");") { + genl a.parameters.join(",\n") + } + } + function_defn("template <class T> void invoke", ["T& target"], "const") { + genl "target.#{a.funcname}(#{a.values.join(', ')} );" + } + } + end + + def action_cpp(a) + action_struct_cpp(a) { + scope("void #{a.classname}::Handler::#{a.funcname}(", ")") { + genl a.unused_parameters.join(",\n") + } + scope { + genl "assert(0);" + genl "throw NotImplementedException(QPID_MSG(\"#{a.fqname} not implemented.\"));" + } + } + end + + # Types that must be generated early because they are used by other types. + def pregenerate?(x) not @amqp.used_by[x.fqname].empty?; end + + def pregenerate_class?(c) + c.children.select{ |t| (t.is_a? AmqpStruct or t.is_a? AmqpDomain) and pregenerate? t} + end + + # Typedefs, enums and forward declarations for classes. + def gen_specification_fwd() + h_file("#{@dir}/specification_fwd") { + include "#{@dir}/built_in_types" + namespace(@ns) { + # Top level + @amqp.domains.each { |d| + # segment-type and track are are built in + domain_h d unless ["track","segment-type"].include?(d.name) + } + each_class_ns { |c| + genl "const uint8_t CODE=#{c.code};" # class code + genl "extern const char* NAME;" + c.each_descendant { |x| + case x + when AmqpDomain then domain_h x + when AmqpStruct then genl "class #{x.classname};" + when AmqpAction then genl "class #{x.classname};" + end + } + } + } + } + end + + # Generate struct definitions into a separate header file so the + # can be included by StructHolder.h without circularity. + def gen_structs() + h_file("#{@dir}/structs") { + include "#{@dir}/specification_fwd" + include "#{@dir}/Map.h" + include "#{@dir}/Array.h" + include "#{@dir}/Struct.h" + include "#{@dir}/UnknownStruct.h" + include "#{@dir}/Packer.h" + namespace(@ns) { + each_class_ns { |c| + c.collect_all(AmqpStruct).each { |s| struct_h s } + } + } + } + + cpp_file("#{@dir}/structs") { + include "#{@dir}/structs" + include "#{@dir}/StructHolder" + namespace(@ns) { + each_class_ns { |c| + c.collect_all(AmqpStruct).each { |s| struct_cpp(s) } + } + } + } + end + + # Generate the specification files + def gen_specification() + h_file("#{@dir}/specification") { + include "#{@dir}/specification_fwd.h" + include "#{@dir}/Map.h" + include "#{@dir}/Array.h" + include "#{@dir}/UnknownType.h" + include "#{@dir}/Struct32" + include "#{@dir}/Control.h" + include "#{@dir}/Command.h" + include "#{@dir}/Packer.h" + include "<iosfwd>" + namespace(@ns) { + each_class_ns { |c| + c.collect_all(AmqpAction).each { |a| action_h a } + } + }} + + cpp_file("#{@dir}/specification") { + include "#{@dir}/specification" + include "#{@dir}/exceptions" + include "<iostream>" + ["Command","Control", "Struct"].each { |x| include "#{@dir}/Apply#{x}" } + namespace(@ns) { + each_class_ns { |c| + genl "const char* NAME=\"#{c.fqname}\";" + c.actions.each { |a| action_cpp a} + } + } + } + end + + def gen_proxy() + h_file("#{@dir}/ProxyTemplate.h") { + include "#{@dir}/specification" + namespace(@ns) { + genl "template <class F, class R=typename F::result_type>" + cpp_extern_class("QPID_COMMON_CLASS_EXTERN", "ProxyTemplate") { + public + genl "ProxyTemplate(F f=F()) : functor(f) {}" + @amqp.classes.each { |c| + c.actions.each { |a| + genl + function_defn("R #{a.funcname}", a.parameters) { + var=a.name.funcname + args = a.arguments.empty? ? "" : "("+a.arguments.join(", ")+")" + genl("#{a.fqclassname} #{var}#{args};") + genl "return functor(#{var});" + } + } + } + private + genl "F functor;" + } + } + } + end + + def visitor_interface_h(base, subs, is_const) + name="#{is_const ? 'Const' : ''}#{base}Visitor" + const=is_const ? "const " : "" + struct(name) { + genl "virtual ~#{name}() {}" + genl "typedef #{const}#{base} BaseType;" + subs.each{ |s| + genl "virtual void visit(#{const}#{s.fqclassname}&) = 0;" + }} + end + + def visitor_impl(base, subs, is_const) + name="#{is_const ? 'Const' : ''}#{base}Visitor" + const=is_const ? "const " : "" + genl "template <class F>" + struct("ApplyVisitor<#{name}, F>", "public ApplyVisitorBase<#{name}, F>") { + subs.each{ |s| + genl "virtual void visit(#{const}#{s.fqclassname}& x) { this->invoke(x); }" + }} + end + + def gen_visitor(base, subs) + h_file("#{@dir}/#{base}Visitor.h") { + include base=="Struct" ? "#{@dir}/structs" : "#{@dir}/specification" + namespace("#{@ns}") { + visitor_interface_h(base, subs, false) + visitor_interface_h(base, subs, true) + }} + + h_file("#{@dir}/Apply#{base}.h") { + include "#{@dir}/#{base}Visitor.h" + include "#{@dir}/apply.h" + namespace("#{@ns}") { + visitor_impl(base, subs, false) + visitor_impl(base, subs, true) + } + } + end + + def gen_holder(base, subs) + name=base+"Holder" + h_file("#{@dir}/#{name}") { + include "#{@dir}/Apply#{base}" + include "#{@dir}/Holder" + include base=="Struct" ? "#{@dir}/structs" : "#{@dir}/specification" + namespace(@ns){ + namespace("#{base.downcase}_max") { + genl "static const size_t MAX000=0;" + last="MAX000" + subs.each { |s| + sizeof="sizeof(#{s.fqclassname})" + genl "static const size_t #{last.succ} = #{sizeof} > #{last} ? #{sizeof} : #{last};" + last.succ! + } + genl "static const int MAX=#{last};" + } + holder_base="amqp_0_10::Holder<#{name}, #{base}, #{base.downcase}_max::MAX>" + struct("#{name}", "public #{holder_base}") { + genl "#{name}() {}" + genl "template <class T> explicit #{name}(const T& t) : #{holder_base}(t) {}" + genl "using #{holder_base}::operator=;" + genl "void set(uint8_t classCode, uint8_t code);" + } + genl + genl "std::ostream& operator<<(std::ostream& o, const #{name}& h);" + } + } + + cpp_file("#{@dir}/#{name}") { + include "#{@dir}/#{name}" + include "#{@dir}/exceptions.h" + namespace(@ns) { + genl "using framing::in_place;" + genl + scope("void #{name}::set(uint8_t classCode, uint8_t code) {") { + genl "uint16_t key=(classCode<<8)+code;" + scope ("switch(key) {") { + subs.each { |s| + genl "case 0x#{s.full_code.to_s(16)}: *this=in_place<#{s.fqclassname}>(); break;" unless (s.is_a? UnknownStruct) + } + genl "default: " + indent { + if (base=="Struct") + genl "*this=in_place<UnknownStruct>(classCode, code);" + else + genl "throw CommandInvalidException(QPID_MSG(\"Invalid class-#{base.downcase} key \" << std::hex << key));" + end + } + } + } + genl + genl "std::ostream& operator<<(std::ostream& o, const #{name}& h) { return h.get() ? (o << *h.get()) : (o << \"<empty #{name}>\"); }" + } + } + end + + def gen_visitable(base, subs) + subs << UnknownStruct.new if base=="Struct" # Extra case for unknown structs. + gen_holder(base, subs) + gen_visitor(base, subs) + end + + def generate + gen_specification_fwd + gen_specification + gen_proxy + gen_structs + gen_visitable("Command", @amqp.collect_all(AmqpCommand)) + gen_visitable("Control", @amqp.collect_all(AmqpControl)) + gen_visitable("Struct", @amqp.collect_all(AmqpStruct).select { |s| s.code}) + end +end + +Specification.new($outdir, $amqp).generate(); |