blob: 63bf107e381b40e2d4b3c0d5bbe40f978fa430b6 [file] [log] [blame]
#!/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 ConstantsGen < CppGen
def initialize(outdir, amqp)
super(outdir, amqp)
@namespace="qpid::framing"
@dir="qpid/framing"
end
def constants_h()
public_api("#{@dir}/constants.h")
h_file("#{@dir}/constants.h") {
namespace(@namespace) {
# Constants for class/method names.
scope("enum AmqpConstant {","};") {
l=[]
l.concat @amqp.constants.map { |c| "#{c.name.shout}=#{c.value}" }
@amqp.classes.each { |c|
l << "#{c.name.shout}_CLASS_ID=#{c.code}"
l.concat c.methods_.map { |m|
"#{c.name.shout}_#{m.name.shout}_METHOD_ID=#{m.code}" }
}
genl l.join(",\n")
}
}
}
end
def typecode_enum(t) "TYPE_CODE_#{t.name.shout}" end
def typecode_h_cpp
path="#{@dir}/TypeCode"
public_api(path+".h")
h_file(path) {
include("<iosfwd>")
include("\"qpid/sys/IntegerTypes.h\"")
namespace(@namespace) {
scope("enum TypeCode {", "};") {
genl @amqp.types.map { |t| "#{typecode_enum t} = #{t.code}" if t.code }.compact.join(",\n")
}
genl <<EOS
/** True if t is a valid TypeCode value */
bool isTypeCode(uint8_t t);
/** Throw exception if not a valid TypeCode */
TypeCode typeCode(uint8_t);
/**@return 0 if t is not a valid enum TypeCode value. */
const char* typeName(TypeCode t);
std::ostream& operator<<(std::ostream&, TypeCode);
EOS
}
}
cpp_file(path) {
include(path);
include("qpid/Exception.h")
include("qpid/Msg.h")
include("<ostream>")
namespace(@namespace) {
scope("const char* typeName(TypeCode t) {") {
scope("switch (t) {") {
@amqp.types.each { |t| genl "case #{typecode_enum t}: return \"#{t.name}\";" if t.code }
genl "default: break;"
}
genl "return 0;";
}
genl <<EOS
bool isTypeCode(uint8_t t) { return typeName(TypeCode(t)); }
TypeCode typeCode(uint8_t t) {
if (!isTypeCode(t)) throw Exception(QPID_MSG("Invalid TypeCode " << t));
return TypeCode(t);
}
std::ostream& operator<<(std::ostream& o, TypeCode t) {
if (isTypeCode(t)) return o << typeName(t);
else return o << "Invalid TypeCode " << t;
}
EOS
}
}
end
def enum_h()
public_api("#{@dir}/enum.h")
h_file("#{@dir}/enum.h") {
# Constants for enum domains.
namespace(@namespace) {
@amqp.domains.each { |d| declare_enum(d.enum) if d.enum }
@amqp.classes.each { |c|
enums=c.collect_all(AmqpEnum)
if !enums.empty? then
namespace(c.nsname) { enums.each { |e| declare_enum(e) } }
end
}
}
}
end
def declare_enum(enum)
# Generated like this: enum containing_class::Foo { FOO_X, FOO_Y; }
name="#{enum.parent.name.caps}"
prefix=enum.parent.name.shout+"_"
scope("enum #{name} {","};") {
genl enum.choices.collect { |c| "#{prefix}#{c.name.shout}=#{c.value}" }.join(",\n")
}
end
def declare_exception(c, base, package, enum)
name=c.name.caps+"Exception"
value="#{package}::#{enum.parent.name.shout}_#{c.name.shout}"
genl
doxygen_comment { genl c.doc }
cpp_extern_class("QPID_COMMON_CLASS_EXTERN", c.name.caps+"Exception", "public #{base}") {
public
genl "std::string getPrefix() const { return \"#{c.name}\"; }"
genl "#{c.name.caps}Exception(const std::string& msg=std::string()) : #{base}(#{value}, \"\"+msg) {}"
}
end
def declare_exceptions(class_name, domain_name, base)
enum = @amqp.class_(class_name).domain(domain_name).enum
enum.choices.each { |c| declare_exception(c, base, class_name, enum) unless c.name == "normal" }
genl
genl "QPID_COMMON_EXTERN sys::ExceptionHolder create#{base}(int code, const std::string& text);"
end
def create_exception(class_name, domain_name, base, invalid)
scope("sys::ExceptionHolder create#{base}(int code, const std::string& text) {") {
genl "sys::ExceptionHolder holder;"
scope("switch (code) {") {
enum = @amqp.class_(class_name).domain(domain_name).enum
enum.choices.each { |c|
assign = "holder = new #{c.name.caps}Exception(text); " unless c.name == "normal"
genl "case #{c.value}: #{assign}break;"
}
genl "default: holder = new #{invalid}(QPID_MSG(\"Bad #{enum.parent.name}: \" << code << \": \" << text));"
}
genl "return holder;"
}
end
def reply_exceptions_h()
public_api("#{@dir}/reply_exceptions.h")
h_file("#{@dir}/reply_exceptions.h") {
include "qpid/Exception"
include "qpid/sys/ExceptionHolder"
include "qpid/framing/enum"
include "qpid/CommonImportExport.h"
namespace(@namespace) {
declare_exceptions("execution", "error-code", "SessionException")
declare_exceptions("connection", "close-code", "ConnectionException")
declare_exceptions("session", "detach-code", "ChannelException")
}
}
end
def reply_exceptions_cpp()
cpp_file("#{@dir}/reply_exceptions") {
include "#{@dir}/reply_exceptions"
include "qpid/Msg.h"
include "<sstream>"
include "<assert.h>"
namespace("qpid::framing") {
create_exception("execution", "error-code", "SessionException", "InvalidArgumentException")
# FIXME aconway 2008-10-07: there are no good exception codes in 0-10 for an invalid code.
# The following choices are arbitrary.
create_exception("connection", "close-code", "ConnectionException", "FramingErrorException")
create_exception("session", "detach-code", "ChannelException", "NotAttachedException")
}
}
end
def generate()
constants_h
enum_h
reply_exceptions_h
reply_exceptions_cpp
typecode_h_cpp
end
end
ConstantsGen.new($outdir, $amqp).generate();