diff options
Diffstat (limited to 'cpp/rubygen/templates')
-rw-r--r-- | cpp/rubygen/templates/InvocationVisitor.rb | 105 | ||||
-rwxr-xr-x | cpp/rubygen/templates/Operations.rb | 108 | ||||
-rw-r--r-- | cpp/rubygen/templates/Session.rb | 6 | ||||
-rw-r--r-- | cpp/rubygen/templates/structs.rb | 345 |
4 files changed, 561 insertions, 3 deletions
diff --git a/cpp/rubygen/templates/InvocationVisitor.rb b/cpp/rubygen/templates/InvocationVisitor.rb new file mode 100644 index 0000000000..f3ac03ece2 --- /dev/null +++ b/cpp/rubygen/templates/InvocationVisitor.rb @@ -0,0 +1,105 @@ +#!/usr/bin/env ruby +$: << ".." # Include .. in load path +require 'cppgen' + +class InvocationVisitor < CppGen + + def initialize(outdir, amqp) + super(outdir, amqp) + @namespace="qpid::framing" + @classname="InvocationVisitor" + @filename="qpid/framing/InvocationVisitor" + end + + def invocation_args(m) + if (m.amqp_parent.name == "message" && (m.name == "transfer" || m.name == "append")) + "body" + else + m.param_names.collect {|p| "body.get" + p.caps + "()" }.join(",\n") + end + end + + def null_visit(m) + genl "void InvocationVisitor::visit(const #{m.body_name}&){}" + end + + def define_visit(m) + if (m.fields.size > 0) + body = "body" + else + body = "/*body*/" + end + gen <<EOS +void InvocationVisitor::visit(const #{m.body_name}& #{body}) +{ + AMQP_ServerOperations::#{m.amqp_parent.cppname}Handler* ptr(0); + if (invocable) { + ptr = dynamic_cast<AMQP_ServerOperations::#{m.amqp_parent.cppname}Handler*>(invocable); + } else { + ptr = ops->get#{m.amqp_parent.cppname}Handler(); + } + + if (ptr) { +EOS + if (m.has_result?) + indent(2) { genl "encode<#{m.result_struct.cppname.caps}>(ptr->#{m.cppname}(#{invocation_args(m)}), result);" } + else + indent(2) { genl "ptr->#{m.cppname}(#{invocation_args(m)});" } + end + + gen <<EOS + succeeded = true; + } else { + succeeded = false; + } +} +EOS + end + + def generate() + h_file("#{@filename}") { + include "AMQP_ServerOperations.h" + include "MethodBodyConstVisitor.h" + include "qpid/framing/StructHelper.h" + namespace(@namespace) { + cpp_class("InvocationVisitor", ["public MethodBodyConstVisitor", "private StructHelper"]) { + indent { + genl "AMQP_ServerOperations* const ops;" + genl "Invocable* const invocable;" + genl "std::string result;" + genl "bool succeeded;" + } + genl "public:" + indent { + genl "InvocationVisitor(AMQP_ServerOperations* _ops) : ops(_ops), invocable(0) {}" + genl "InvocationVisitor(Invocable* _invocable) : ops(0), invocable(_invocable) {}" + genl "const std::string& getResult() const { return result; }" + genl "const bool hasResult() const { return !result.empty(); }" + genl "bool wasHandled() const { return succeeded; }" + genl "void clear();" + genl "virtual ~InvocationVisitor() {}" + } + @amqp.amqp_methods.each { |m| genl "void visit(const #{m.body_name}&);" } + } + } + } + + cpp_file("#{@filename}") { + include "InvocationVisitor.h" + @amqp.amqp_methods.each { |m| include m.body_name } + namespace(@namespace) { + genl "void InvocationVisitor::clear() {" + indent { + genl "succeeded = false;" + genl "result.clear();" + } + genl "}" + genl + @amqp.amqp_methods.each { |m| m.is_server_method? ? define_visit(m) : null_visit(m) } + } + } + end +end + +InvocationVisitor.new(Outdir, Amqp).generate(); + diff --git a/cpp/rubygen/templates/Operations.rb b/cpp/rubygen/templates/Operations.rb new file mode 100755 index 0000000000..79b82a9d59 --- /dev/null +++ b/cpp/rubygen/templates/Operations.rb @@ -0,0 +1,108 @@ +#!/usr/bin/env ruby +# Usage: output_directory xml_spec_file [xml_spec_file...] +# +$: << '..' +require 'cppgen' + +class OperationsGen < CppGen + + def initialize(chassis, outdir, amqp) + super(outdir, amqp) + @chassis=chassis + @classname="AMQP_#{@chassis.caps}Operations" + end + + def handler_method (m) + if (m.has_result?) + return_type = "#{m.amqp_parent.name.caps}#{m.cppname.caps}Result" + else + return_type = "void" + end + if (m.amqp_parent.name == "message" && (m.name == "transfer" || m.name == "append")) + gen "\nvirtual #{return_type} #{m.cppname}(const framing::AMQMethodBody& context) = 0;\n" + else + gen "\nvirtual #{return_type} #{m.cppname}(" + gen m.signature.join(",\n") + gen ") = 0;\n" + end + end + + def handler_classname(c) c.name.caps+"Handler"; end + + def handler_class(c) + if (!c.amqp_methods_on(@chassis).empty?) + handlerclass=handler_classname c + gen <<EOS +// ==================== class #{handlerclass} ==================== +class #{handlerclass} : public virtual Invocable { + // Constructors and destructors + public: + #{handlerclass}(){}; + virtual ~#{handlerclass}() {} + // Protocol methods +EOS + c.amqp_methods_on(@chassis).each { |m| handler_method(m) } + gen <<EOS +}; // class #{handlerclass} + + +EOS + end + end + + def handler_get(c) + if (!c.amqp_methods_on(@chassis).empty?) + handlerclass=handler_classname c + gen "virtual #{handlerclass}* get#{handlerclass}() = 0;\n" + end + end + + def generate() + h_file("qpid/framing/#{@classname}.h") { + gen <<EOS +#include <sstream> +#include "qpid/framing/ProtocolVersion.h" +#include "qpid/framing/amqp_structs.h" + +namespace qpid { +namespace framing { + +class AMQMethodBody; + +class Invocable +{ +protected: + Invocable() {} + virtual ~Invocable() {} +}; + +class #{@classname} { + + public: + virtual ~#{@classname}() {} + + virtual ProtocolVersion getVersion() const = 0; + + // Include framing constant declarations - why? + //#include "qpid/framing/AMQP_Constants.h" + + // Inner classes +EOS + indent { @amqp.amqp_classes.each { |c| handler_class(c) } } + gen <<EOS + + // Method handler get methods + +EOS + indent { @amqp.amqp_classes.each { |c| handler_get(c) } } + gen <<EOS +}; /* class #{@classname} */ +}} +EOS +} + end +end + +OperationsGen.new("client",ARGV[0], Amqp).generate() +OperationsGen.new("server",ARGV[0], Amqp).generate() + diff --git a/cpp/rubygen/templates/Session.rb b/cpp/rubygen/templates/Session.rb index d5b6d9e8c2..0d5808318a 100644 --- a/cpp/rubygen/templates/Session.rb +++ b/cpp/rubygen/templates/Session.rb @@ -67,9 +67,9 @@ class SessionGen < CppGen #include "qpid/framing/amqp_framing.h" #include "qpid/framing/ProtocolVersion.h" #include "qpid/framing/MethodContent.h" -#include "ConnectionImpl.h" -#include "Response.h" -#include "SessionCore.h" +#include "qpid/client/ConnectionImpl.h" +#include "qpid/client/Response.h" +#include "qpid/client/SessionCore.h" namespace qpid { namespace client { diff --git a/cpp/rubygen/templates/structs.rb b/cpp/rubygen/templates/structs.rb new file mode 100644 index 0000000000..972a0386b9 --- /dev/null +++ b/cpp/rubygen/templates/structs.rb @@ -0,0 +1,345 @@ +#!/usr/bin/env ruby +# Usage: output_directory xml_spec_file [xml_spec_file...] +# +$: << '..' +require 'cppgen' + +class StructGen < CppGen + + def initialize(outdir, amqp) + super(outdir, amqp) + end + + EncodingMap={ + "octet"=>"Octet", + "short"=>"Short", + "long"=>"Long", + "longlong"=>"LongLong", + "longstr"=>"LongString", + "shortstr"=>"ShortString", + "timestamp"=>"LongLong", + "uuid"=>"ShortString",#FIXME + "table"=>"FieldTable", + "content"=>"Content", + "long-struct"=>"LongString" + } + SizeMap={ + "octet"=>"1", + "short"=>"2", + "long"=>"4", + "longlong"=>"8", + "timestamp"=>"8" + } + + ValueTypes=["octet", "short", "long", "longlong", "timestamp"] + + def printable_form(f) + if (f.cpptype == "u_int8_t") + return "(int) " + f.cppname + else + return f.cppname + end + end + + def generate_encode(f, combined) + if (f.field_type == "bit") + genl "uint8_t #{f.cppname}_bits = #{f.cppname};" + count = 0 + combined.each { |c| genl "#{f.cppname}_bits |= #{c.cppname} << #{count += 1};" } + genl "buffer.putOctet(#{f.cppname}_bits);" + else + encoded = EncodingMap[f.field_type] + if (encoded) + genl "buffer.put#{encoded}(#{f.cppname});" + else + genl "#{f.cppname}.encode(buffer);" + end + end + end + + def generate_decode(f, combined) + if (f.field_type == "bit") + genl "uint8_t #{f.cppname}_bits = buffer.getOctet();" + genl "#{f.cppname} = 1 & #{f.cppname}_bits;" + count = 0 + combined.each { |c| genl "#{c.cppname} = (1 << #{count += 1}) & #{f.cppname}_bits;" } + else + encoded = EncodingMap[f.field_type] + if (encoded) + if (ValueTypes.include?(f.field_type)) + genl "#{f.cppname} = buffer.get#{encoded}();" + else + genl "buffer.get#{encoded}(#{f.cppname});" + end + else + genl "#{f.cppname}.decode(buffer);" + end + end + end + + def generate_size(f, combined) + if (f.field_type == "bit") + names = ([f] + combined).collect {|g| g.cppname} + genl "+ 1 //#{names.join(", ")}" + else + size = SizeMap[f.field_type] + if (size) + genl "+ #{size} //#{f.cppname}" + elsif (f.cpp_member_type == "SequenceNumberSet") + genl "+ #{f.cppname}.encodedSize()" + else + encoded = EncodingMap[f.field_type] + gen "+ 4 " if encoded == "LongString" + gen "+ 1 " if encoded == "ShortString" + genl "+ #{f.cppname}.size()" + end + end + end + + def process_fields(s) + last = nil + count = 0 + bits = [] + s.fields.each { + |f| if (last and last.bit? and f.bit? and count < 7) + count += 1 + bits << f + else + if (last and last.bit?) + yield last, bits + count = 0 + bits = [] + end + if (not f.bit?) + yield f + end + last = f + end + } + if (last and last.bit?) + yield last, bits + end + end + + def methodbody_extra_defs(s) + gen <<EOS + using AMQMethodBody::accept; + void accept(MethodBodyConstVisitor& v) const { v.visit(*this); } + + inline ClassId amqpClassId() const { return CLASS_ID; } + inline MethodId amqpMethodId() const { return METHOD_ID; } +EOS + if (s.is_server_method?) + gen <<EOS + void invoke(AMQP_ServerOperations& target) + { + target.get#{s.amqp_parent.cppname}Handler()->#{s.cppname} + ( +EOS + if (s.amqp_parent.name == "message" && (s.name == "transfer" || s.name == "append")) + indent(4) { genl "*this" } + else + indent(4) { genl s.param_names.join(",\n") } + end + + genl <<EOS + ); + } + + bool invoke(Invocable* target) + { + AMQP_ServerOperations::#{s.amqp_parent.cppname}Handler* ptr + = dynamic_cast<AMQP_ServerOperations::#{s.amqp_parent.cppname}Handler*>(target); + if (ptr) { + ptr->#{s.cppname}( +EOS + if (s.amqp_parent.name == "message" && (s.name == "transfer" || s.name == "append")) + indent(5) { genl "*this" } + else + indent(5) { genl s.param_names.join(",\n") } + end + + gen <<EOS + ); + return true; + } else { + return false; + } + } +EOS + end + end + + def define_constructor(name, s) + if (s.fields.size > 0) + genl "#{name}(" + if (s.kind_of? AmqpMethod) + indent {gen "ProtocolVersion, "} + end + indent { gen s.fields.collect { |f| "#{f.cpptype} _#{f.cppname}" }.join(",\n") } + gen ")" + genl ": " if s.fields.size > 0 + indent { gen s.fields.collect { |f| " #{f.cppname}(_#{f.cppname})" }.join(",\n") } + genl " {}" + end + if (s.kind_of? AmqpMethod) + genl "#{name}(ProtocolVersion=ProtocolVersion()) {}" + end + end + + def define_accessors(f) + genl "void set#{f.name.caps}(#{f.cpptype} _#{f.cppname}) { #{f.cppname} = _#{f.cppname}; }" + genl "#{f.cpptype} get#{f.name.caps}() const { return #{f.cppname}; }" + end + + def define_struct(s) + classname = s.cppname + inheritance = "" + if (s.kind_of? AmqpMethod) + classname = s.body_name + inheritance = ": public AMQMethodBody" + end + + h_file("qpid/framing/#{classname}.h") { + if (s.kind_of? AmqpMethod) + gen <<EOS +#include "qpid/framing/AMQMethodBody.h" +#include "qpid/framing/AMQP_ServerOperations.h" +#include "qpid/framing/MethodBodyConstVisitor.h" +EOS + end + + #need to include any nested struct definitions + s.fields.select {|f| f.defined_as_struct }.map {|f| include f.name.caps} + + gen <<EOS + +#include <ostream> +#include "qpid/framing/amqp_types_full.h" + +namespace qpid { +namespace framing { + +class #{classname} #{inheritance} { +EOS + indent { s.fields.each { |f| genl "#{f.cpp_member_type} #{f.cppname};" } } + genl "public:" + if (s.kind_of? AmqpMethod) + indent { genl "static const ClassId CLASS_ID = #{s.amqp_parent.index};" } + indent { genl "static const MethodId METHOD_ID = #{s.index};" } + end + + if (s.kind_of? AmqpStruct) + if (s.type) + if (s.result?) + #as result structs have types that are only unique to the + #class, they have a class dependent qualifier added to them + #(this is inline with current python code but a formal + #solution is expected from the WG + indent { genl "static const uint16_t TYPE = #{s.type} + #{s.amqp_parent.amqp_parent.index} * 256;" } + else + indent { genl "static const uint16_t TYPE = #{s.type};" } + end + end + end + + indent { + define_constructor(classname, s) + genl "" + s.fields.each { |f| define_accessors(f) } + } + if (s.kind_of? AmqpMethod) + methodbody_extra_defs(s) + end + if (s.kind_of? AmqpStruct) + indent {genl "friend std::ostream& operator<<(std::ostream&, const #{classname}&);" } + end + + gen <<EOS + void encode(Buffer&) const; + void decode(Buffer&, uint32_t=0); + uint32_t size() const; + void print(std::ostream& out) const; +}; /* class #{classname} */ + +}} +EOS + } + cpp_file("qpid/framing/#{classname}.cpp") { + if (s.fields.size > 0) + buffer = "buffer" + else + buffer = "/*buffer*/" + end + gen <<EOS +#include "#{classname}.h" + +using namespace qpid::framing; + +void #{classname}::encode(Buffer& #{buffer}) const +{ +EOS + indent { process_fields(s) { |f, combined| generate_encode(f, combined) } } + gen <<EOS +} + +void #{classname}::decode(Buffer& #{buffer}, uint32_t /*size*/) +{ +EOS + indent { process_fields(s) { |f, combined| generate_decode(f, combined) } } + gen <<EOS +} + +uint32_t #{classname}::size() const +{ + return 0 +EOS + indent { process_fields(s) { |f, combined| generate_size(f, combined) } } + gen <<EOS + ; +} + +void #{classname}::print(std::ostream& out) const +{ + out << "#{classname}: "; +EOS + copy = Array.new(s.fields) + f = copy.shift + + indent { + genl "out << \"#{f.name}=\" << #{printable_form(f)};" if f + copy.each { |f| genl "out << \"; #{f.name}=\" << #{printable_form(f)};" } + } + gen <<EOS +} +EOS + + if (s.kind_of? AmqpStruct) + gen <<EOS +namespace qpid{ +namespace framing{ + + std::ostream& operator<<(std::ostream& out, const #{classname}& s) + { + s.print(out); + return out; + } + +} +} +EOS + end + +} + end + + def generate() + @amqp.amqp_structs.each { |s| define_struct(s) } + @amqp.amqp_methods.each { |m| define_struct(m) } + #generate a single include file containing the list of structs for convenience + h_file("qpid/framing/amqp_structs.h") { @amqp.amqp_structs.each { |s| genl "#include \"#{s.cppname}.h\"" } } + end +end + +StructGen.new(ARGV[0], Amqp).generate() + |