1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
#!/usr/bin/env ruby
$: << ".." # Include .. in load path
require 'cppgen'
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")
}
elsif (d.type_ == "array")
genl "typedef Array<#{ArrayTypes[d.name].amqp2cpp}> #{typename};"
else
genl "typedef #{d.type_.amqp2cpp} #{typename};"
end
end
# class constants
def class_h(c)
genl "const uint8_t CODE=#{c.code};"
genl "extern const char* NAME;"
end
def class_cpp(c)
genl "const char* NAME=\"#{c.fqname}\";"
end
# Used by structs, commands and controls.
def action_struct_h(x, base, consts, &block)
genl
struct(x.classname, "public #{base}") {
x.fields.each { |f| genl "#{f.type_.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;"
ctor_decl(x.classname,[])
ctor_decl(x.classname, x.parameters) unless x.fields.empty?
function_decl("void accept", ["Visitor&"], "const")
genl
yield if block
}
end
def action_struct_cpp(x)
genl
genl "const char* #{x.classname}::NAME=\"#{x.fqname}\";"
genl
ctor_defn(x.classname) {}
ctor_defn(x.classname, x.parameters, x.initializers) {} if not x.fields.empty?
function_defn("void #{x.classname}::accept", ["Visitor&"], "const") {
genl "// FIXME aconway 2008-02-27: todo"
}
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"]) {
function_defn("template <class T> void invoke", ["T& target"]) {
genl "target.#{a.funcname}(#{a.values.join(', ')});"
}
function_defn("template <class S> void serialize", ["S& s"]) {
gen "s"
a.fields.each { |f| gen "(#{f.cppname})"}
genl ";"
} unless a.fields.empty?
}
end
def action_cpp(a) action_struct_cpp(a); 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
# Generate the log
def gen_specification()
h_file("#{@dir}/specification") {
include "#{@dir}/built_in_types"
include "#{@dir}/helpers"
include "<boost/call_traits.hpp>"
genl "using boost::call_traits;"
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)
}
# Domains and structs that must be generated early because
# they are used by other definitions:
each_class_ns { |c|
class_h c
c.domains.each { |d| domain_h d if pregenerate? d }
c.structs.each { |s| struct_h s if pregenerate? s }
}
# Now dependent domains/structs and actions
each_class_ns { |c|
c.domains.each { |d| domain_h d if not pregenerate? d }
c.structs.each { |s| struct_h s if not pregenerate? s }
c.actions.each { |a| action_h a }
}
}
}
cpp_file("#{@dir}/specification") {
include "#{@dir}/specification"
namespace(@ns) {
each_class_ns { |c|
class_cpp c
c.actions.each { |a| action_cpp a}
c.structs.each { |s| struct_cpp s }
}
}
}
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_class("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 generate
gen_specification
gen_proxy
end
end
Specification.new($outdir, $amqp).generate();
|