xdrgen 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Guardfile +12 -0
- data/LICENSE.txt +202 -0
- data/README.md +79 -0
- data/Rakefile +6 -0
- data/bin/xdrgen +5 -0
- data/lib/xdrgen.rb +24 -0
- data/lib/xdrgen/ast.rb +81 -0
- data/lib/xdrgen/ast/concerns/contained.rb +32 -0
- data/lib/xdrgen/ast/concerns/has_children.rb +9 -0
- data/lib/xdrgen/ast/concerns/has_definitions.rb +90 -0
- data/lib/xdrgen/ast/concerns/named.rb +16 -0
- data/lib/xdrgen/ast/concerns/namespace.rb +7 -0
- data/lib/xdrgen/ast/concerns/nested_definition.rb +16 -0
- data/lib/xdrgen/ast/constant.rb +7 -0
- data/lib/xdrgen/ast/decimal_constant.rb +7 -0
- data/lib/xdrgen/ast/declarations/array.rb +15 -0
- data/lib/xdrgen/ast/declarations/base.rb +28 -0
- data/lib/xdrgen/ast/declarations/opaque.rb +11 -0
- data/lib/xdrgen/ast/declarations/optional.rb +5 -0
- data/lib/xdrgen/ast/declarations/simple.rb +7 -0
- data/lib/xdrgen/ast/declarations/string.rb +7 -0
- data/lib/xdrgen/ast/declarations/void.rb +7 -0
- data/lib/xdrgen/ast/definitions/base.rb +9 -0
- data/lib/xdrgen/ast/definitions/const.rb +12 -0
- data/lib/xdrgen/ast/definitions/enum.rb +17 -0
- data/lib/xdrgen/ast/definitions/enum_member.rb +44 -0
- data/lib/xdrgen/ast/definitions/namespace.rb +9 -0
- data/lib/xdrgen/ast/definitions/nested_enum.rb +7 -0
- data/lib/xdrgen/ast/definitions/nested_struct.rb +7 -0
- data/lib/xdrgen/ast/definitions/nested_union.rb +7 -0
- data/lib/xdrgen/ast/definitions/struct.rb +18 -0
- data/lib/xdrgen/ast/definitions/struct_body.rb +11 -0
- data/lib/xdrgen/ast/definitions/struct_member.rb +12 -0
- data/lib/xdrgen/ast/definitions/typedef.rb +19 -0
- data/lib/xdrgen/ast/definitions/union.rb +55 -0
- data/lib/xdrgen/ast/definitions/union_arm.rb +33 -0
- data/lib/xdrgen/ast/definitions/union_arm_case.rb +11 -0
- data/lib/xdrgen/ast/definitions/union_body.rb +22 -0
- data/lib/xdrgen/ast/definitions/union_default_arm.rb +19 -0
- data/lib/xdrgen/ast/fixed_size.rb +23 -0
- data/lib/xdrgen/ast/hexadecimal_constant.rb +7 -0
- data/lib/xdrgen/ast/identifier.rb +5 -0
- data/lib/xdrgen/ast/octal_constant.rb +7 -0
- data/lib/xdrgen/ast/top.rb +5 -0
- data/lib/xdrgen/ast/typespecs/base.rb +27 -0
- data/lib/xdrgen/ast/typespecs/bool.rb +5 -0
- data/lib/xdrgen/ast/typespecs/double.rb +5 -0
- data/lib/xdrgen/ast/typespecs/float.rb +5 -0
- data/lib/xdrgen/ast/typespecs/hyper.rb +6 -0
- data/lib/xdrgen/ast/typespecs/int.rb +6 -0
- data/lib/xdrgen/ast/typespecs/opaque.rb +10 -0
- data/lib/xdrgen/ast/typespecs/quadruple.rb +5 -0
- data/lib/xdrgen/ast/typespecs/simple.rb +14 -0
- data/lib/xdrgen/ast/typespecs/string.rb +9 -0
- data/lib/xdrgen/ast/typespecs/unsigned_hyper.rb +5 -0
- data/lib/xdrgen/ast/typespecs/unsigned_int.rb +5 -0
- data/lib/xdrgen/ast/var_size.rb +26 -0
- data/lib/xdrgen/ast/whitespace.rb +5 -0
- data/lib/xdrgen/cli.rb +31 -0
- data/lib/xdrgen/compilation.rb +31 -0
- data/lib/xdrgen/generators.rb +16 -0
- data/lib/xdrgen/generators/base.rb +11 -0
- data/lib/xdrgen/generators/elixir.rb +260 -0
- data/lib/xdrgen/generators/go.rb +578 -0
- data/lib/xdrgen/generators/java.rb +810 -0
- data/lib/xdrgen/generators/java/XdrDataInputStream.erb +122 -0
- data/lib/xdrgen/generators/java/XdrDataOutputStream.erb +96 -0
- data/lib/xdrgen/generators/java/XdrElement.erb +10 -0
- data/lib/xdrgen/generators/java/XdrString.erb +58 -0
- data/lib/xdrgen/generators/javascript.rb +248 -0
- data/lib/xdrgen/generators/ruby.rb +283 -0
- data/lib/xdrgen/grammar/base.treetop +71 -0
- data/lib/xdrgen/grammar/comments.treetop +15 -0
- data/lib/xdrgen/grammar/const.treetop +8 -0
- data/lib/xdrgen/grammar/declaration.treetop +99 -0
- data/lib/xdrgen/grammar/enum.treetop +46 -0
- data/lib/xdrgen/grammar/main.treetop +30 -0
- data/lib/xdrgen/grammar/namespace.treetop +12 -0
- data/lib/xdrgen/grammar/struct.treetop +32 -0
- data/lib/xdrgen/grammar/typedef.treetop +12 -0
- data/lib/xdrgen/grammar/union.treetop +63 -0
- data/lib/xdrgen/output.rb +37 -0
- data/lib/xdrgen/output_file.rb +87 -0
- data/lib/xdrgen/parser.rb +40 -0
- data/lib/xdrgen/version.rb +3 -0
- data/spec/fixtures/generator/block_comments.x +14 -0
- data/spec/fixtures/generator/const.x +4 -0
- data/spec/fixtures/generator/enum.x +36 -0
- data/spec/fixtures/generator/nesting.x +24 -0
- data/spec/fixtures/generator/optional.x +8 -0
- data/spec/fixtures/generator/struct.x +10 -0
- data/spec/fixtures/generator/test.x +77 -0
- data/spec/fixtures/generator/union.x +28 -0
- data/spec/fixtures/parser/block_comments.x +14 -0
- data/spec/fixtures/parser/const.x +1 -0
- data/spec/fixtures/parser/enum.x +35 -0
- data/spec/fixtures/parser/nesting.x +26 -0
- data/spec/fixtures/parser/optional.x +8 -0
- data/spec/fixtures/parser/struct.x +8 -0
- data/spec/fixtures/parser/test.x +77 -0
- data/spec/fixtures/parser/union.x +10 -0
- data/spec/lib/xdrgen/generator_spec.rb +30 -0
- data/spec/lib/xdrgen/output_file_spec.rb +33 -0
- data/spec/lib/xdrgen/parser_spec.rb +27 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support/fixtures.rb +27 -0
- data/xdrgen.gemspec +32 -0
- metadata +301 -0
|
@@ -0,0 +1,810 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
module Xdrgen
|
|
4
|
+
module Generators
|
|
5
|
+
|
|
6
|
+
class Java < Xdrgen::Generators::Base
|
|
7
|
+
|
|
8
|
+
def generate
|
|
9
|
+
render_lib
|
|
10
|
+
render_definitions(@top)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def render_lib
|
|
14
|
+
template = IO.read(__dir__ + "/java/XdrDataInputStream.erb")
|
|
15
|
+
result = ERB.new(template).result binding
|
|
16
|
+
@output.write "XdrDataInputStream.java", result
|
|
17
|
+
|
|
18
|
+
template = IO.read(__dir__ + "/java/XdrDataOutputStream.erb")
|
|
19
|
+
result = ERB.new(template).result binding
|
|
20
|
+
@output.write "XdrDataOutputStream.java", result
|
|
21
|
+
|
|
22
|
+
template = IO.read(__dir__ + "/java/XdrElement.erb")
|
|
23
|
+
result = ERB.new(template).result binding
|
|
24
|
+
@output.write "XdrElement.java", result
|
|
25
|
+
|
|
26
|
+
template = IO.read(__dir__ + "/java/XdrString.erb")
|
|
27
|
+
result = ERB.new(template).result binding
|
|
28
|
+
@output.write "XdrString.java", result
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def render_definitions(node)
|
|
32
|
+
node.namespaces.each{|n| render_definitions n }
|
|
33
|
+
node.definitions.each(&method(:render_definition))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def add_imports_for_definition(defn, imports)
|
|
37
|
+
case defn
|
|
38
|
+
when AST::Definitions::Struct ;
|
|
39
|
+
defn.members.each do |m|
|
|
40
|
+
if is_decl_array(m.declaration)
|
|
41
|
+
imports.add('java.util.Arrays')
|
|
42
|
+
else
|
|
43
|
+
imports.add('com.google.common.base.Objects')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
# if we have more than one member field then the
|
|
47
|
+
# hash code will be computed by
|
|
48
|
+
# Objects.hashCode(field1, field2, ..., fieldN)
|
|
49
|
+
# therefore, we should always import com.google.common.base.Objects
|
|
50
|
+
if defn.members.length > 1
|
|
51
|
+
imports.add("com.google.common.base.Objects")
|
|
52
|
+
end
|
|
53
|
+
when AST::Definitions::Enum ;
|
|
54
|
+
# no imports required for enums
|
|
55
|
+
when AST::Definitions::Union ;
|
|
56
|
+
nonVoidArms = defn.arms.select { |arm| !arm.void? }
|
|
57
|
+
# add 1 because of the discriminant
|
|
58
|
+
totalFields = nonVoidArms.length + 1
|
|
59
|
+
|
|
60
|
+
if is_type_array(defn.discriminant.type)
|
|
61
|
+
imports.add('java.util.Arrays')
|
|
62
|
+
else
|
|
63
|
+
imports.add('com.google.common.base.Objects')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
nonVoidArms.each do |a|
|
|
67
|
+
if is_decl_array(a.declaration)
|
|
68
|
+
imports.add('java.util.Arrays')
|
|
69
|
+
else
|
|
70
|
+
imports.add('com.google.common.base.Objects')
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# if we have more than one field then the
|
|
75
|
+
# hash code will be computed by
|
|
76
|
+
# Objects.hashCode(field1, field2, ..., fieldN)
|
|
77
|
+
# therefore, we should always import com.google.common.base.Objects
|
|
78
|
+
# if we have more than one field
|
|
79
|
+
if totalFields > 1
|
|
80
|
+
imports.add("com.google.common.base.Objects")
|
|
81
|
+
end
|
|
82
|
+
when AST::Definitions::Typedef ;
|
|
83
|
+
if is_decl_array(defn.declaration)
|
|
84
|
+
imports.add('java.util.Arrays')
|
|
85
|
+
else
|
|
86
|
+
imports.add('com.google.common.base.Objects')
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if defn.respond_to? :nested_definitions
|
|
91
|
+
defn.nested_definitions.each{ |child_defn| add_imports_for_definition(child_defn, imports) }
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def render_definition(defn)
|
|
96
|
+
imports = Set[]
|
|
97
|
+
add_imports_for_definition(defn, imports)
|
|
98
|
+
|
|
99
|
+
case defn
|
|
100
|
+
when AST::Definitions::Struct ;
|
|
101
|
+
render_element "public class", imports, defn do |out|
|
|
102
|
+
render_struct defn, out
|
|
103
|
+
render_nested_definitions defn, out
|
|
104
|
+
end
|
|
105
|
+
when AST::Definitions::Enum ;
|
|
106
|
+
render_element "public enum", imports, defn do |out|
|
|
107
|
+
render_enum defn, out
|
|
108
|
+
end
|
|
109
|
+
when AST::Definitions::Union ;
|
|
110
|
+
render_element "public class", imports, defn do |out|
|
|
111
|
+
render_union defn, out
|
|
112
|
+
render_nested_definitions defn, out
|
|
113
|
+
end
|
|
114
|
+
when AST::Definitions::Typedef ;
|
|
115
|
+
render_element "public class", imports, defn do |out|
|
|
116
|
+
render_typedef defn, out
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def render_nested_definitions(defn, out)
|
|
122
|
+
return unless defn.respond_to? :nested_definitions
|
|
123
|
+
defn.nested_definitions.each{|ndefn|
|
|
124
|
+
case ndefn
|
|
125
|
+
when AST::Definitions::Struct ;
|
|
126
|
+
name = name ndefn
|
|
127
|
+
out.puts "public static class #{name} {"
|
|
128
|
+
out.indent do
|
|
129
|
+
render_struct ndefn, out
|
|
130
|
+
render_nested_definitions ndefn , out
|
|
131
|
+
end
|
|
132
|
+
out.puts "}"
|
|
133
|
+
when AST::Definitions::Enum ;
|
|
134
|
+
name = name ndefn
|
|
135
|
+
out.puts "public static enum #{name} {"
|
|
136
|
+
out.indent do
|
|
137
|
+
render_enum ndefn, out
|
|
138
|
+
end
|
|
139
|
+
out.puts "}"
|
|
140
|
+
when AST::Definitions::Union ;
|
|
141
|
+
name = name ndefn
|
|
142
|
+
out.puts "public static class #{name} {"
|
|
143
|
+
out.indent do
|
|
144
|
+
render_union ndefn, out
|
|
145
|
+
render_nested_definitions ndefn, out
|
|
146
|
+
end
|
|
147
|
+
out.puts "}"
|
|
148
|
+
when AST::Definitions::Typedef ;
|
|
149
|
+
name = name ndefn
|
|
150
|
+
out.puts "public static class #{name} {"
|
|
151
|
+
out.indent do
|
|
152
|
+
render_typedef ndefn, out
|
|
153
|
+
end
|
|
154
|
+
out.puts "}"
|
|
155
|
+
end
|
|
156
|
+
}
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def render_element(type, imports, element, post_name="implements XdrElement")
|
|
160
|
+
path = element.name.camelize + ".java"
|
|
161
|
+
name = name_string element.name
|
|
162
|
+
out = @output.open(path)
|
|
163
|
+
render_top_matter out
|
|
164
|
+
imports.each do |import|
|
|
165
|
+
out.puts "import #{import};"
|
|
166
|
+
end
|
|
167
|
+
out.puts "\n"
|
|
168
|
+
render_source_comment out, element
|
|
169
|
+
out.puts "#{type} #{name} #{post_name} {"
|
|
170
|
+
out.indent do
|
|
171
|
+
yield out
|
|
172
|
+
out.unbreak
|
|
173
|
+
end
|
|
174
|
+
out.puts "}"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def render_enum(enum, out)
|
|
178
|
+
out.balance_after /,[\s]*/ do
|
|
179
|
+
enum.members.each do |em|
|
|
180
|
+
out.puts "#{em.name}(#{em.value}),"
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
out.puts ";\n"
|
|
184
|
+
out.puts <<-EOS.strip_heredoc
|
|
185
|
+
private int mValue;
|
|
186
|
+
|
|
187
|
+
#{name_string enum.name}(int value) {
|
|
188
|
+
mValue = value;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public int getValue() {
|
|
192
|
+
return mValue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public static #{name_string enum.name} decode(XdrDataInputStream stream) throws IOException {
|
|
196
|
+
int value = stream.readInt();
|
|
197
|
+
switch (value) {
|
|
198
|
+
EOS
|
|
199
|
+
out.indent 2 do
|
|
200
|
+
enum.members.each do |em|
|
|
201
|
+
out.puts "case #{em.value}: return #{em.name};"
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
out.puts <<-EOS.strip_heredoc
|
|
205
|
+
default:
|
|
206
|
+
throw new RuntimeException("Unknown enum value: " + value);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
public static void encode(XdrDataOutputStream stream, #{name_string enum.name} value) throws IOException {
|
|
211
|
+
stream.writeInt(value.getValue());
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public void encode(XdrDataOutputStream stream) throws IOException {
|
|
215
|
+
encode(stream, this);
|
|
216
|
+
}
|
|
217
|
+
EOS
|
|
218
|
+
out.break
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def render_struct(struct, out)
|
|
222
|
+
out.puts "public #{name struct} () {}"
|
|
223
|
+
struct.members.each do |m|
|
|
224
|
+
out.puts <<-EOS.strip_heredoc
|
|
225
|
+
private #{decl_string(m.declaration)} #{m.name};
|
|
226
|
+
public #{decl_string(m.declaration)} get#{m.name.slice(0,1).capitalize+m.name.slice(1..-1)}() {
|
|
227
|
+
return this.#{m.name};
|
|
228
|
+
}
|
|
229
|
+
public void set#{m.name.slice(0,1).capitalize+m.name.slice(1..-1)}(#{decl_string m.declaration} value) {
|
|
230
|
+
this.#{m.name} = value;
|
|
231
|
+
}
|
|
232
|
+
EOS
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
out.puts "public static void encode(XdrDataOutputStream stream, #{name struct} encoded#{name struct}) throws IOException{"
|
|
237
|
+
struct.members.each do |m|
|
|
238
|
+
out.indent do
|
|
239
|
+
encode_member "encoded#{name struct}", m, out
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
out.puts "}"
|
|
243
|
+
|
|
244
|
+
out.puts <<-EOS.strip_heredoc
|
|
245
|
+
public void encode(XdrDataOutputStream stream) throws IOException {
|
|
246
|
+
encode(stream, this);
|
|
247
|
+
}
|
|
248
|
+
EOS
|
|
249
|
+
|
|
250
|
+
out.puts <<-EOS.strip_heredoc
|
|
251
|
+
public static #{name struct} decode(XdrDataInputStream stream) throws IOException {
|
|
252
|
+
#{name struct} decoded#{name struct} = new #{name struct}();
|
|
253
|
+
EOS
|
|
254
|
+
struct.members.each do |m|
|
|
255
|
+
out.indent do
|
|
256
|
+
decode_member "decoded#{name struct}", m, out
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
out.indent do
|
|
260
|
+
out.puts "return decoded#{name struct};"
|
|
261
|
+
end
|
|
262
|
+
out.puts "}"
|
|
263
|
+
|
|
264
|
+
hashCodeExpression = case struct.members.length
|
|
265
|
+
when 0
|
|
266
|
+
"0"
|
|
267
|
+
when 1
|
|
268
|
+
if is_decl_array(struct.members[0].declaration)
|
|
269
|
+
"Arrays.hashCode(this.#{struct.members[0].name})"
|
|
270
|
+
else
|
|
271
|
+
"Objects.hashCode(this.#{struct.members[0].name})"
|
|
272
|
+
end
|
|
273
|
+
else
|
|
274
|
+
"Objects.hashCode(#{
|
|
275
|
+
(struct.members.map { |m|
|
|
276
|
+
if is_decl_array(m.declaration)
|
|
277
|
+
"Arrays.hashCode(this.#{m.name})"
|
|
278
|
+
else
|
|
279
|
+
"this.#{m.name}"
|
|
280
|
+
end
|
|
281
|
+
}).join(", ")
|
|
282
|
+
})"
|
|
283
|
+
end
|
|
284
|
+
out.puts <<-EOS.strip_heredoc
|
|
285
|
+
@Override
|
|
286
|
+
public int hashCode() {
|
|
287
|
+
return #{hashCodeExpression};
|
|
288
|
+
}
|
|
289
|
+
EOS
|
|
290
|
+
|
|
291
|
+
equalParts = struct.members.map { |m|
|
|
292
|
+
if is_decl_array(m.declaration)
|
|
293
|
+
"Arrays.equals(this.#{m.name}, other.#{m.name})"
|
|
294
|
+
else
|
|
295
|
+
"Objects.equal(this.#{m.name}, other.#{m.name})"
|
|
296
|
+
end
|
|
297
|
+
}
|
|
298
|
+
equalExpression = case equalParts.length
|
|
299
|
+
when 0
|
|
300
|
+
"true"
|
|
301
|
+
else
|
|
302
|
+
equalParts.join(" && ")
|
|
303
|
+
end
|
|
304
|
+
type = name struct
|
|
305
|
+
out.puts <<-EOS.strip_heredoc
|
|
306
|
+
@Override
|
|
307
|
+
public boolean equals(Object object) {
|
|
308
|
+
if (object == null || !(object instanceof #{type})) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
#{type} other = (#{type}) object;
|
|
313
|
+
return #{equalExpression};
|
|
314
|
+
}
|
|
315
|
+
EOS
|
|
316
|
+
|
|
317
|
+
out.break
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def render_typedef(typedef, out)
|
|
321
|
+
out.puts <<-EOS.strip_heredoc
|
|
322
|
+
private #{decl_string typedef.declaration} #{typedef.name};
|
|
323
|
+
public #{decl_string typedef.declaration} get#{typedef.name.slice(0,1).capitalize+typedef.name.slice(1..-1)}() {
|
|
324
|
+
return this.#{typedef.name};
|
|
325
|
+
}
|
|
326
|
+
public void set#{typedef.name.slice(0,1).capitalize+typedef.name.slice(1..-1)}(#{decl_string typedef.declaration} value) {
|
|
327
|
+
this.#{typedef.name} = value;
|
|
328
|
+
}
|
|
329
|
+
EOS
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
out.puts "public static void encode(XdrDataOutputStream stream, #{name typedef} encoded#{name typedef}) throws IOException {"
|
|
333
|
+
encode_member "encoded#{name typedef}", typedef, out
|
|
334
|
+
out.puts "}"
|
|
335
|
+
|
|
336
|
+
out.puts <<-EOS.strip_heredoc
|
|
337
|
+
public void encode(XdrDataOutputStream stream) throws IOException {
|
|
338
|
+
encode(stream, this);
|
|
339
|
+
}
|
|
340
|
+
EOS
|
|
341
|
+
|
|
342
|
+
out.puts <<-EOS.strip_heredoc
|
|
343
|
+
public static #{name typedef} decode(XdrDataInputStream stream) throws IOException {
|
|
344
|
+
#{name typedef} decoded#{name typedef} = new #{name typedef}();
|
|
345
|
+
EOS
|
|
346
|
+
decode_member "decoded#{name typedef}", typedef, out
|
|
347
|
+
out.indent do
|
|
348
|
+
out.puts "return decoded#{name typedef};"
|
|
349
|
+
end
|
|
350
|
+
out.puts "}"
|
|
351
|
+
|
|
352
|
+
hash_coder_for_decl =
|
|
353
|
+
if is_decl_array(typedef.declaration)
|
|
354
|
+
"Arrays.hashCode"
|
|
355
|
+
else
|
|
356
|
+
"Objects.hashCode"
|
|
357
|
+
end
|
|
358
|
+
out.puts <<-EOS.strip_heredoc
|
|
359
|
+
@Override
|
|
360
|
+
public int hashCode() {
|
|
361
|
+
return #{hash_coder_for_decl}(this.#{typedef.name});
|
|
362
|
+
}
|
|
363
|
+
EOS
|
|
364
|
+
|
|
365
|
+
equals_for_decl =
|
|
366
|
+
if is_decl_array(typedef.declaration)
|
|
367
|
+
"Arrays.equals"
|
|
368
|
+
else
|
|
369
|
+
"Objects.equal"
|
|
370
|
+
end
|
|
371
|
+
type = name_string typedef.name
|
|
372
|
+
out.puts <<-EOS.strip_heredoc
|
|
373
|
+
@Override
|
|
374
|
+
public boolean equals(Object object) {
|
|
375
|
+
if (object == null || !(object instanceof #{type})) {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
#{type} other = (#{type}) object;
|
|
380
|
+
return #{equals_for_decl}(this.#{typedef.name}, other.#{typedef.name});
|
|
381
|
+
}
|
|
382
|
+
EOS
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def render_union(union, out)
|
|
386
|
+
out.puts "public #{name union} () {}"
|
|
387
|
+
out.puts <<-EOS.strip_heredoc
|
|
388
|
+
#{type_string union.discriminant.type} #{union.discriminant.name};
|
|
389
|
+
public #{type_string union.discriminant.type} getDiscriminant() {
|
|
390
|
+
return this.#{union.discriminant.name};
|
|
391
|
+
}
|
|
392
|
+
public void setDiscriminant(#{type_string union.discriminant.type} value) {
|
|
393
|
+
this.#{union.discriminant.name} = value;
|
|
394
|
+
}
|
|
395
|
+
EOS
|
|
396
|
+
union.arms.each do |arm|
|
|
397
|
+
next if arm.void?
|
|
398
|
+
out.puts <<-EOS.strip_heredoc
|
|
399
|
+
private #{decl_string(arm.declaration)} #{arm.name};
|
|
400
|
+
public #{decl_string(arm.declaration)} get#{arm.name.slice(0,1).capitalize+arm.name.slice(1..-1)}() {
|
|
401
|
+
return this.#{arm.name};
|
|
402
|
+
}
|
|
403
|
+
public void set#{arm.name.slice(0,1).capitalize+arm.name.slice(1..-1)}(#{decl_string arm.declaration} value) {
|
|
404
|
+
this.#{arm.name} = value;
|
|
405
|
+
}
|
|
406
|
+
EOS
|
|
407
|
+
end
|
|
408
|
+
out.puts "public static void encode(XdrDataOutputStream stream, #{name union} encoded#{name union}) throws IOException {"
|
|
409
|
+
out.puts('//' + union.discriminant.type.class.to_s)
|
|
410
|
+
out.puts("//" + type_string(union.discriminant.type))
|
|
411
|
+
if union.discriminant.type.is_a?(AST::Typespecs::Int)
|
|
412
|
+
out.puts "stream.writeInt(encoded#{name union}.getDiscriminant().intValue());"
|
|
413
|
+
elsif type_string(union.discriminant.type) == "Uint32"
|
|
414
|
+
# ugly workaround for compile error after generating source for AuthenticatedMessage in stellar-core
|
|
415
|
+
out.puts "stream.writeInt(encoded#{name union}.getDiscriminant().getUint32());"
|
|
416
|
+
else
|
|
417
|
+
out.puts "stream.writeInt(encoded#{name union}.getDiscriminant().getValue());"
|
|
418
|
+
end
|
|
419
|
+
if type_string(union.discriminant.type) == "Uint32"
|
|
420
|
+
# ugly workaround for compile error after generating source for AuthenticatedMessage in stellar-core
|
|
421
|
+
out.puts "switch (encoded#{name union}.getDiscriminant().getUint32()) {"
|
|
422
|
+
else
|
|
423
|
+
out.puts "switch (encoded#{name union}.getDiscriminant()) {"
|
|
424
|
+
end
|
|
425
|
+
union.arms.each do |arm|
|
|
426
|
+
case arm
|
|
427
|
+
when AST::Definitions::UnionDefaultArm ;
|
|
428
|
+
out.puts "default:"
|
|
429
|
+
else
|
|
430
|
+
arm.cases.each do |kase|
|
|
431
|
+
if kase.value.is_a?(AST::Identifier)
|
|
432
|
+
if type_string(union.discriminant.type) == "Integer"
|
|
433
|
+
member = union.resolved_case(kase)
|
|
434
|
+
out.puts "case #{member.value}:"
|
|
435
|
+
else
|
|
436
|
+
out.puts "case #{kase.value.name}:"
|
|
437
|
+
end
|
|
438
|
+
else
|
|
439
|
+
out.puts "case #{kase.value.value}:"
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
encode_member "encoded#{name union}", arm, out
|
|
444
|
+
out.puts "break;"
|
|
445
|
+
end
|
|
446
|
+
out.puts "}\n}"
|
|
447
|
+
out.puts <<-EOS.strip_heredoc
|
|
448
|
+
public void encode(XdrDataOutputStream stream) throws IOException {
|
|
449
|
+
encode(stream, this);
|
|
450
|
+
}
|
|
451
|
+
EOS
|
|
452
|
+
|
|
453
|
+
out.puts "public static #{name union} decode(XdrDataInputStream stream) throws IOException {"
|
|
454
|
+
out.puts "#{name union} decoded#{name union} = new #{name union}();"
|
|
455
|
+
if union.discriminant.type.is_a?(AST::Typespecs::Int)
|
|
456
|
+
out.puts "Integer discriminant = stream.readInt();"
|
|
457
|
+
else
|
|
458
|
+
out.puts "#{name union.discriminant.type} discriminant = #{name union.discriminant.type}.decode(stream);"
|
|
459
|
+
end
|
|
460
|
+
out.puts "decoded#{name union}.setDiscriminant(discriminant);"
|
|
461
|
+
|
|
462
|
+
if type_string(union.discriminant.type) == "Uint32"
|
|
463
|
+
# ugly workaround for compile error after generating source for AuthenticatedMessage in stellar-core
|
|
464
|
+
out.puts "switch (decoded#{name union}.getDiscriminant().getUint32()) {"
|
|
465
|
+
else
|
|
466
|
+
out.puts "switch (decoded#{name union}.getDiscriminant()) {"
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
union.arms.each do |arm|
|
|
470
|
+
case arm
|
|
471
|
+
when AST::Definitions::UnionDefaultArm ;
|
|
472
|
+
out.puts "default:"
|
|
473
|
+
else
|
|
474
|
+
arm.cases.each do |kase|
|
|
475
|
+
if kase.value.is_a?(AST::Identifier)
|
|
476
|
+
if type_string(union.discriminant.type) == "Integer"
|
|
477
|
+
member = union.resolved_case(kase)
|
|
478
|
+
out.puts "case #{member.value}:"
|
|
479
|
+
else
|
|
480
|
+
out.puts "case #{kase.value.name}:"
|
|
481
|
+
end
|
|
482
|
+
else
|
|
483
|
+
out.puts "case #{kase.value.value}:"
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
decode_member "decoded#{name union}", arm, out
|
|
488
|
+
out.puts "break;"
|
|
489
|
+
end
|
|
490
|
+
out.puts "}\n"
|
|
491
|
+
out.indent do
|
|
492
|
+
out.puts "return decoded#{name union};"
|
|
493
|
+
end
|
|
494
|
+
out.puts "}"
|
|
495
|
+
|
|
496
|
+
nonVoidArms = union.arms.select { |arm| !arm.void? }
|
|
497
|
+
|
|
498
|
+
discriminantPart = if is_type_array(union.discriminant.type)
|
|
499
|
+
"Arrays.hashCode(this.#{union.discriminant.name})"
|
|
500
|
+
else
|
|
501
|
+
"this.#{union.discriminant.name}"
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
parts = nonVoidArms.map { |a|
|
|
505
|
+
if is_decl_array(a.declaration)
|
|
506
|
+
"Arrays.hashCode(this.#{a.name})"
|
|
507
|
+
else
|
|
508
|
+
"this.#{a.name}"
|
|
509
|
+
end
|
|
510
|
+
}
|
|
511
|
+
parts.append(discriminantPart)
|
|
512
|
+
|
|
513
|
+
hashCodeExpression = "Objects.hashCode(#{parts.join(", ")})"
|
|
514
|
+
out.puts <<-EOS.strip_heredoc
|
|
515
|
+
@Override
|
|
516
|
+
public int hashCode() {
|
|
517
|
+
return #{hashCodeExpression};
|
|
518
|
+
}
|
|
519
|
+
EOS
|
|
520
|
+
|
|
521
|
+
equalParts = nonVoidArms.map { |a|
|
|
522
|
+
if is_decl_array(a.declaration)
|
|
523
|
+
"Arrays.equals(this.#{a.name}, other.#{a.name})"
|
|
524
|
+
else
|
|
525
|
+
"Objects.equal(this.#{a.name}, other.#{a.name})"
|
|
526
|
+
end
|
|
527
|
+
}
|
|
528
|
+
equalParts.append(
|
|
529
|
+
if is_type_array(union.discriminant.type)
|
|
530
|
+
"Arrays.equals(this.#{union.discriminant.name}, other.#{union.discriminant.name})"
|
|
531
|
+
else
|
|
532
|
+
"Objects.equal(this.#{union.discriminant.name}, other.#{union.discriminant.name})"
|
|
533
|
+
end
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
equalExpression = case equalParts.length
|
|
537
|
+
when 0
|
|
538
|
+
"true"
|
|
539
|
+
else
|
|
540
|
+
equalParts.join(" && ")
|
|
541
|
+
end
|
|
542
|
+
type = name union
|
|
543
|
+
out.puts <<-EOS.strip_heredoc
|
|
544
|
+
@Override
|
|
545
|
+
public boolean equals(Object object) {
|
|
546
|
+
if (object == null || !(object instanceof #{type})) {
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
#{type} other = (#{type}) object;
|
|
551
|
+
return #{equalExpression};
|
|
552
|
+
}
|
|
553
|
+
EOS
|
|
554
|
+
|
|
555
|
+
out.break
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
def render_top_matter(out)
|
|
559
|
+
out.puts <<-EOS.strip_heredoc
|
|
560
|
+
// Automatically generated by xdrgen
|
|
561
|
+
// DO NOT EDIT or your changes may be overwritten
|
|
562
|
+
|
|
563
|
+
package #{@namespace};
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
import java.io.IOException;
|
|
567
|
+
EOS
|
|
568
|
+
out.break
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
def render_source_comment(out, defn)
|
|
572
|
+
return if defn.is_a?(AST::Definitions::Namespace)
|
|
573
|
+
|
|
574
|
+
out.puts <<-EOS.strip_heredoc
|
|
575
|
+
// === xdr source ============================================================
|
|
576
|
+
|
|
577
|
+
EOS
|
|
578
|
+
|
|
579
|
+
out.puts "// " + defn.text_value.split("\n").join("\n// ")
|
|
580
|
+
|
|
581
|
+
out.puts <<-EOS.strip_heredoc
|
|
582
|
+
|
|
583
|
+
// ===========================================================================
|
|
584
|
+
EOS
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
def encode_member(value, member, out)
|
|
588
|
+
case member.declaration
|
|
589
|
+
when AST::Declarations::Void
|
|
590
|
+
return
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
if member.type.sub_type == :optional
|
|
594
|
+
out.puts "if (#{value}.#{member.name} != null) {"
|
|
595
|
+
out.puts "stream.writeInt(1);"
|
|
596
|
+
end
|
|
597
|
+
case member.declaration
|
|
598
|
+
when AST::Declarations::Opaque ;
|
|
599
|
+
out.puts "int #{member.name}size = #{value}.#{member.name}.length;"
|
|
600
|
+
unless member.declaration.fixed?
|
|
601
|
+
out.puts "stream.writeInt(#{member.name}size);"
|
|
602
|
+
end
|
|
603
|
+
out.puts <<-EOS.strip_heredoc
|
|
604
|
+
stream.write(#{value}.get#{member.name.slice(0,1).capitalize+member.name.slice(1..-1)}(), 0, #{member.name}size);
|
|
605
|
+
EOS
|
|
606
|
+
when AST::Declarations::Array ;
|
|
607
|
+
out.puts "int #{member.name}size = #{value}.get#{member.name.slice(0,1).capitalize+member.name.slice(1..-1)}().length;"
|
|
608
|
+
unless member.declaration.fixed?
|
|
609
|
+
out.puts "stream.writeInt(#{member.name}size);"
|
|
610
|
+
end
|
|
611
|
+
out.puts <<-EOS.strip_heredoc
|
|
612
|
+
for (int i = 0; i < #{member.name}size; i++) {
|
|
613
|
+
#{encode_type member.declaration.type, "#{value}.#{member.name}[i]"};
|
|
614
|
+
}
|
|
615
|
+
EOS
|
|
616
|
+
else
|
|
617
|
+
out.puts "#{encode_type member.declaration.type, "#{value}.#{member.name}"};"
|
|
618
|
+
end
|
|
619
|
+
if member.type.sub_type == :optional
|
|
620
|
+
out.puts "} else {"
|
|
621
|
+
out.puts "stream.writeInt(0);"
|
|
622
|
+
out.puts "}"
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
def encode_type(type, value)
|
|
627
|
+
case type
|
|
628
|
+
when AST::Typespecs::Int ;
|
|
629
|
+
"stream.writeInt(#{value})"
|
|
630
|
+
when AST::Typespecs::UnsignedInt ;
|
|
631
|
+
"stream.writeInt(#{value})"
|
|
632
|
+
when AST::Typespecs::Hyper ;
|
|
633
|
+
"stream.writeLong(#{value})"
|
|
634
|
+
when AST::Typespecs::UnsignedHyper ;
|
|
635
|
+
"stream.writeLong(#{value})"
|
|
636
|
+
when AST::Typespecs::Float ;
|
|
637
|
+
"stream.writeFloat(#{value})"
|
|
638
|
+
when AST::Typespecs::Double ;
|
|
639
|
+
"stream.writeDouble(#{value})"
|
|
640
|
+
when AST::Typespecs::Quadruple ;
|
|
641
|
+
raise "cannot render quadruple in golang"
|
|
642
|
+
when AST::Typespecs::Bool ;
|
|
643
|
+
"stream.writeInt(#{value} ? 1 : 0)"
|
|
644
|
+
when AST::Typespecs::String ;
|
|
645
|
+
"#{value}.encode(stream)"
|
|
646
|
+
when AST::Typespecs::Simple ;
|
|
647
|
+
"#{name type.resolved_type}.encode(stream, #{value})"
|
|
648
|
+
when AST::Concerns::NestedDefinition ;
|
|
649
|
+
"#{name type}.encode(stream, #{value})"
|
|
650
|
+
else
|
|
651
|
+
raise "Unknown typespec: #{type.class.name}"
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
def decode_member(value, member, out)
|
|
656
|
+
case member.declaration
|
|
657
|
+
when AST::Declarations::Void ;
|
|
658
|
+
return
|
|
659
|
+
end
|
|
660
|
+
if member.type.sub_type == :optional
|
|
661
|
+
out.puts <<-EOS.strip_heredoc
|
|
662
|
+
int #{member.name}Present = stream.readInt();
|
|
663
|
+
if (#{member.name}Present != 0) {
|
|
664
|
+
EOS
|
|
665
|
+
end
|
|
666
|
+
case member.declaration
|
|
667
|
+
when AST::Declarations::Opaque ;
|
|
668
|
+
if (member.declaration.fixed?)
|
|
669
|
+
out.puts "int #{member.name}size = #{member.declaration.size};"
|
|
670
|
+
else
|
|
671
|
+
out.puts "int #{member.name}size = stream.readInt();"
|
|
672
|
+
end
|
|
673
|
+
out.puts <<-EOS.strip_heredoc
|
|
674
|
+
#{value}.#{member.name} = new byte[#{member.name}size];
|
|
675
|
+
stream.read(#{value}.#{member.name}, 0, #{member.name}size);
|
|
676
|
+
EOS
|
|
677
|
+
when AST::Declarations::Array ;
|
|
678
|
+
if (member.declaration.fixed?)
|
|
679
|
+
out.puts "int #{member.name}size = #{member.declaration.size};"
|
|
680
|
+
else
|
|
681
|
+
out.puts "int #{member.name}size = stream.readInt();"
|
|
682
|
+
end
|
|
683
|
+
out.puts <<-EOS.strip_heredoc
|
|
684
|
+
#{value}.#{member.name} = new #{type_string member.type}[#{member.name}size];
|
|
685
|
+
for (int i = 0; i < #{member.name}size; i++) {
|
|
686
|
+
#{value}.#{member.name}[i] = #{decode_type member.declaration};
|
|
687
|
+
}
|
|
688
|
+
EOS
|
|
689
|
+
else
|
|
690
|
+
out.puts "#{value}.#{member.name} = #{decode_type member.declaration};"
|
|
691
|
+
end
|
|
692
|
+
if member.type.sub_type == :optional
|
|
693
|
+
out.puts "}"
|
|
694
|
+
end
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
def decode_type(decl)
|
|
698
|
+
case decl.type
|
|
699
|
+
when AST::Typespecs::Int ;
|
|
700
|
+
"stream.readInt()"
|
|
701
|
+
when AST::Typespecs::UnsignedInt ;
|
|
702
|
+
"stream.readInt()"
|
|
703
|
+
when AST::Typespecs::Hyper ;
|
|
704
|
+
"stream.readLong()"
|
|
705
|
+
when AST::Typespecs::UnsignedHyper ;
|
|
706
|
+
"stream.readLong()"
|
|
707
|
+
when AST::Typespecs::Float ;
|
|
708
|
+
"stream.readFloat()"
|
|
709
|
+
when AST::Typespecs::Double ;
|
|
710
|
+
"stream.readDouble()"
|
|
711
|
+
when AST::Typespecs::Quadruple ;
|
|
712
|
+
raise "cannot render quadruple in golang"
|
|
713
|
+
when AST::Typespecs::Bool ;
|
|
714
|
+
"stream.readInt() == 1 ? true : false"
|
|
715
|
+
when AST::Typespecs::String ;
|
|
716
|
+
"XdrString.decode(stream, #{decl.size})"
|
|
717
|
+
when AST::Typespecs::Simple ;
|
|
718
|
+
"#{name decl.type.resolved_type}.decode(stream)"
|
|
719
|
+
when AST::Concerns::NestedDefinition ;
|
|
720
|
+
"#{name decl.type}.decode(stream)"
|
|
721
|
+
else
|
|
722
|
+
raise "Unknown typespec: #{decl.type.class.name}"
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
def decl_string(decl)
|
|
727
|
+
case decl
|
|
728
|
+
when AST::Declarations::Opaque ;
|
|
729
|
+
"byte[]"
|
|
730
|
+
when AST::Declarations::String ;
|
|
731
|
+
"XdrString"
|
|
732
|
+
when AST::Declarations::Array ;
|
|
733
|
+
"#{type_string decl.type}[]"
|
|
734
|
+
when AST::Declarations::Optional ;
|
|
735
|
+
"#{type_string(decl.type)}"
|
|
736
|
+
when AST::Declarations::Simple ;
|
|
737
|
+
type_string(decl.type)
|
|
738
|
+
else
|
|
739
|
+
raise "Unknown declaration type: #{decl.class.name}"
|
|
740
|
+
end
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
def is_decl_array(decl)
|
|
744
|
+
case decl
|
|
745
|
+
when AST::Declarations::Opaque ;
|
|
746
|
+
true
|
|
747
|
+
when AST::Declarations::Array ;
|
|
748
|
+
true
|
|
749
|
+
when AST::Declarations::Optional ;
|
|
750
|
+
is_type_array(decl.type)
|
|
751
|
+
when AST::Declarations::Simple ;
|
|
752
|
+
is_type_array(decl.type)
|
|
753
|
+
else
|
|
754
|
+
false
|
|
755
|
+
end
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
def is_type_array(type)
|
|
759
|
+
case type
|
|
760
|
+
when AST::Typespecs::Opaque ;
|
|
761
|
+
true
|
|
762
|
+
else
|
|
763
|
+
false
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
def type_string(type)
|
|
768
|
+
case type
|
|
769
|
+
when AST::Typespecs::Int ;
|
|
770
|
+
"Integer"
|
|
771
|
+
when AST::Typespecs::UnsignedInt ;
|
|
772
|
+
"Integer"
|
|
773
|
+
when AST::Typespecs::Hyper ;
|
|
774
|
+
"Long"
|
|
775
|
+
when AST::Typespecs::UnsignedHyper ;
|
|
776
|
+
"Long"
|
|
777
|
+
when AST::Typespecs::Float ;
|
|
778
|
+
"Float"
|
|
779
|
+
when AST::Typespecs::Double ;
|
|
780
|
+
"Double"
|
|
781
|
+
when AST::Typespecs::Quadruple ;
|
|
782
|
+
raise "cannot render quadruple in golang"
|
|
783
|
+
when AST::Typespecs::Bool ;
|
|
784
|
+
"Boolean"
|
|
785
|
+
when AST::Typespecs::Opaque ;
|
|
786
|
+
"Byte[#{type.size}]"
|
|
787
|
+
when AST::Typespecs::String ;
|
|
788
|
+
"XdrString"
|
|
789
|
+
when AST::Typespecs::Simple ;
|
|
790
|
+
name type.resolved_type
|
|
791
|
+
when AST::Concerns::NestedDefinition ;
|
|
792
|
+
name type
|
|
793
|
+
else
|
|
794
|
+
raise "Unknown typespec: #{type.class.name}"
|
|
795
|
+
end
|
|
796
|
+
end
|
|
797
|
+
|
|
798
|
+
def name(named)
|
|
799
|
+
parent = name named.parent_defn if named.is_a?(AST::Concerns::NestedDefinition)
|
|
800
|
+
result = named.name.camelize
|
|
801
|
+
|
|
802
|
+
"#{parent}#{result}"
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
def name_string(name)
|
|
806
|
+
name.camelize
|
|
807
|
+
end
|
|
808
|
+
end
|
|
809
|
+
end
|
|
810
|
+
end
|