diff options
Diffstat (limited to 'qpid/cpp/rubygen/0-10')
-rwxr-xr-x | qpid/cpp/rubygen/0-10/allsegmenttypes.rb | 52 | ||||
-rwxr-xr-x | qpid/cpp/rubygen/0-10/exceptions.rb | 73 | ||||
-rwxr-xr-x | qpid/cpp/rubygen/0-10/handlers.rb | 47 | ||||
-rwxr-xr-x | qpid/cpp/rubygen/0-10/specification.rb | 389 | ||||
-rwxr-xr-x | qpid/cpp/rubygen/0-10/typecode.rb | 117 |
5 files changed, 678 insertions, 0 deletions
diff --git a/qpid/cpp/rubygen/0-10/allsegmenttypes.rb b/qpid/cpp/rubygen/0-10/allsegmenttypes.rb new file mode 100755 index 0000000000..26363d6a1f --- /dev/null +++ b/qpid/cpp/rubygen/0-10/allsegmenttypes.rb @@ -0,0 +1,52 @@ +#!/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' + +class GenAllSegmentTypes < CppGen + def initialize(outdir, amqp) + super(outdir, amqp) + end + + def generate + h_file("tests/allSegmentTypes.h") { + include "qpid/amqp_0_10/specification.h" + include "qpid/amqp_0_10/Header.h" + include "qpid/amqp_0_10/Body.h" + genl + genl "using namespace qpid::amqp_0_10;" + genl + scope("template <class Op> size_t allSegmentTypes(Op& op) {"){ + genl "op(Header());" + genl "op(Body());" + n = 2; + @amqp.classes.each { |c| + c.commands.each { |s| genl "op(CommandHolder(#{c.nsname}::#{s.classname}()));" } + c.controls.each { |s| genl "op(ControlHolder(#{c.nsname}::#{s.classname}()));" } + n += 2 + } + genl "return #{n};" + } + } + end +end + +GenAllSegmentTypes.new($outdir, $amqp).generate(); + diff --git a/qpid/cpp/rubygen/0-10/exceptions.rb b/qpid/cpp/rubygen/0-10/exceptions.rb new file mode 100755 index 0000000000..02e3a5d547 --- /dev/null +++ b/qpid/cpp/rubygen/0-10/exceptions.rb @@ -0,0 +1,73 @@ +#!/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' + +class GenExceptions < CppGen + + def initialize(outdir, amqp) + super(outdir, amqp) + @ns="qpid::amqp_#{@amqp.version.bars}" + @dir="qpid/amqp_#{@amqp.version.bars}" + end + + def exceptions_for_enum(enum, base, ns, suffix="") + enum.choices.each { |c| + name=c.name.typename+suffix+"Exception" + genl + doxygen_comment { genl c.doc } + struct(name, "public #{base}") { + genl "#{name}(const std::string& msg=std::string())" + genl " : #{base}(#{ns}::#{c.name.shout}, msg) {}" + protected + genl "std::string getPrefix() const { return \"#{name}\"; }" + } + } + end + + def gen_exceptions() + h_file("#{@dir}/exceptions") { + include "qpid/amqp_0_10/Exception" + namespace("#{@ns}") { + error_code = @amqp.class_("execution").domain("error-code").enum + exceptions_for_enum(error_code, "SessionAbortedException", "execution") + genl + + detach_code = @amqp.class_("session").domain("detach-code").enum + exceptions_for_enum(detach_code, "SessionDetachedException", "session", "Detached") + + genl + exceptions_for_enum(detach_code, "SessionExpiredException", "session", "Expired") + genl + + close_code = @amqp.class_("connection").domain("close-code").enum + exceptions_for_enum(close_code, "ConnectionException", "connection") + } + } + end + + def generate() + gen_exceptions + end +end + +GenExceptions.new($outdir, $amqp).generate(); + + diff --git a/qpid/cpp/rubygen/0-10/handlers.rb b/qpid/cpp/rubygen/0-10/handlers.rb new file mode 100755 index 0000000000..981ea890e6 --- /dev/null +++ b/qpid/cpp/rubygen/0-10/handlers.rb @@ -0,0 +1,47 @@ +#!/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' + +class GenHandlers < CppGen + def initialize(outdir, amqp) + super(outdir, amqp) + @ns="qpid::amqp_#{@amqp.version.bars}" + @dir="qpid/amqp_#{@amqp.version.bars}" + end + + def action_handler(type, actions) + genl + bases=actions.map { |a| "public #{a.fqclassname}::Handler" } + struct("#{type}Handler", *bases) { } + end + + def generate() + h_file("#{@dir}/handlers.h") { + include "#{@dir}/specification" + namespace("#{@ns}") { + action_handler "Command", @amqp.collect_all(AmqpCommand) + action_handler "Control", @amqp.collect_all(AmqpControl) + } + } + end +end + +GenHandlers.new($outdir, $amqp).generate() 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(); diff --git a/qpid/cpp/rubygen/0-10/typecode.rb b/qpid/cpp/rubygen/0-10/typecode.rb new file mode 100755 index 0000000000..0ab9c4be5d --- /dev/null +++ b/qpid/cpp/rubygen/0-10/typecode.rb @@ -0,0 +1,117 @@ +#!/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' + +class TypeCode < CppGen + def initialize(outdir, amqp) + super(outdir, amqp) + @ns="qpid::amqp_#{@amqp.version.bars}" + @dir="qpid/amqp_#{@amqp.version.bars}" + @types = @amqp.collect_all(AmqpType).select { |t| t.code } + + end + + def type_for_code_h() + h_file("#{@dir}/TypeForCode") { + include "#{@dir}/built_in_types.h" + include "#{@dir}/UnknownType.h" + namespace(@ns) { + genl + genl "template <uint8_t Code> struct TypeForCode;" + genl + @types.each { |t| + genl "template <> struct TypeForCode<#{t.code}> { typedef #{t.typename} type; };" + } + genl + genl "template <class V> typename V::result_type" + scope("apply_visitor(V& visitor, uint8_t code) {") { + scope("switch (code) {", "}") { + @types.each { |t| + genl "case #{t.code}: return visitor((#{t.typename}*)0);" + } + genl "default: return visitor((UnknownType*)0);" + } + } + genl + genl "std::string typeName(uint8_t code);" + } + } + end + + def type_for_code_cpp() + cpp_file("#{@dir}/TypeForCode") { + include "<string>" + include "<sstream>" + namespace(@ns) { + namespace("") { + struct("Names") { + scope("Names() {") { + scope("for (int i =0; i < 256; ++i) {") { + genl "std::ostringstream os;" + genl "os << \"UnknownType<\" << i << \">\";" + genl "names[i] = os.str();" + } + @types.each { |t| genl "names[#{t.code}] = \"#{t.name}\";" } + } + genl "std::string names[256];" + } + genl "Names names;" + } + genl "std::string typeName(uint8_t code) { return names.names[code]; }" + }} + end + + def code_for_type_h() + name="#{@dir}/CodeForType" + h_file(name) { + include "#{@dir}/built_in_types.h" + + namespace(@ns) { + genl + genl "template <class T> struct CodeForType;" + genl + @types.each { |t| + genl "template <> struct CodeForType<#{t.typename}> { static const uint8_t value; };" + } + genl + genl "template <class T> uint8_t codeFor(const T&) { return CodeForType<T>::value; }" + } + } + + cpp_file(name) { + include name + namespace(@ns) { + @types.each { |t| + genl "const uint8_t CodeForType<#{t.typename}>::value=#{t.code};" + } + } + } + end + + def generate + type_for_code_h + type_for_code_cpp + code_for_type_h + end +end + +TypeCode.new($outdir, $amqp).generate(); + |