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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +12 -0
  6. data/LICENSE.txt +202 -0
  7. data/README.md +79 -0
  8. data/Rakefile +6 -0
  9. data/bin/xdrgen +5 -0
  10. data/lib/xdrgen.rb +24 -0
  11. data/lib/xdrgen/ast.rb +81 -0
  12. data/lib/xdrgen/ast/concerns/contained.rb +32 -0
  13. data/lib/xdrgen/ast/concerns/has_children.rb +9 -0
  14. data/lib/xdrgen/ast/concerns/has_definitions.rb +90 -0
  15. data/lib/xdrgen/ast/concerns/named.rb +16 -0
  16. data/lib/xdrgen/ast/concerns/namespace.rb +7 -0
  17. data/lib/xdrgen/ast/concerns/nested_definition.rb +16 -0
  18. data/lib/xdrgen/ast/constant.rb +7 -0
  19. data/lib/xdrgen/ast/decimal_constant.rb +7 -0
  20. data/lib/xdrgen/ast/declarations/array.rb +15 -0
  21. data/lib/xdrgen/ast/declarations/base.rb +28 -0
  22. data/lib/xdrgen/ast/declarations/opaque.rb +11 -0
  23. data/lib/xdrgen/ast/declarations/optional.rb +5 -0
  24. data/lib/xdrgen/ast/declarations/simple.rb +7 -0
  25. data/lib/xdrgen/ast/declarations/string.rb +7 -0
  26. data/lib/xdrgen/ast/declarations/void.rb +7 -0
  27. data/lib/xdrgen/ast/definitions/base.rb +9 -0
  28. data/lib/xdrgen/ast/definitions/const.rb +12 -0
  29. data/lib/xdrgen/ast/definitions/enum.rb +17 -0
  30. data/lib/xdrgen/ast/definitions/enum_member.rb +44 -0
  31. data/lib/xdrgen/ast/definitions/namespace.rb +9 -0
  32. data/lib/xdrgen/ast/definitions/nested_enum.rb +7 -0
  33. data/lib/xdrgen/ast/definitions/nested_struct.rb +7 -0
  34. data/lib/xdrgen/ast/definitions/nested_union.rb +7 -0
  35. data/lib/xdrgen/ast/definitions/struct.rb +18 -0
  36. data/lib/xdrgen/ast/definitions/struct_body.rb +11 -0
  37. data/lib/xdrgen/ast/definitions/struct_member.rb +12 -0
  38. data/lib/xdrgen/ast/definitions/typedef.rb +19 -0
  39. data/lib/xdrgen/ast/definitions/union.rb +55 -0
  40. data/lib/xdrgen/ast/definitions/union_arm.rb +33 -0
  41. data/lib/xdrgen/ast/definitions/union_arm_case.rb +11 -0
  42. data/lib/xdrgen/ast/definitions/union_body.rb +22 -0
  43. data/lib/xdrgen/ast/definitions/union_default_arm.rb +19 -0
  44. data/lib/xdrgen/ast/fixed_size.rb +23 -0
  45. data/lib/xdrgen/ast/hexadecimal_constant.rb +7 -0
  46. data/lib/xdrgen/ast/identifier.rb +5 -0
  47. data/lib/xdrgen/ast/octal_constant.rb +7 -0
  48. data/lib/xdrgen/ast/top.rb +5 -0
  49. data/lib/xdrgen/ast/typespecs/base.rb +27 -0
  50. data/lib/xdrgen/ast/typespecs/bool.rb +5 -0
  51. data/lib/xdrgen/ast/typespecs/double.rb +5 -0
  52. data/lib/xdrgen/ast/typespecs/float.rb +5 -0
  53. data/lib/xdrgen/ast/typespecs/hyper.rb +6 -0
  54. data/lib/xdrgen/ast/typespecs/int.rb +6 -0
  55. data/lib/xdrgen/ast/typespecs/opaque.rb +10 -0
  56. data/lib/xdrgen/ast/typespecs/quadruple.rb +5 -0
  57. data/lib/xdrgen/ast/typespecs/simple.rb +14 -0
  58. data/lib/xdrgen/ast/typespecs/string.rb +9 -0
  59. data/lib/xdrgen/ast/typespecs/unsigned_hyper.rb +5 -0
  60. data/lib/xdrgen/ast/typespecs/unsigned_int.rb +5 -0
  61. data/lib/xdrgen/ast/var_size.rb +26 -0
  62. data/lib/xdrgen/ast/whitespace.rb +5 -0
  63. data/lib/xdrgen/cli.rb +31 -0
  64. data/lib/xdrgen/compilation.rb +31 -0
  65. data/lib/xdrgen/generators.rb +16 -0
  66. data/lib/xdrgen/generators/base.rb +11 -0
  67. data/lib/xdrgen/generators/elixir.rb +260 -0
  68. data/lib/xdrgen/generators/go.rb +578 -0
  69. data/lib/xdrgen/generators/java.rb +810 -0
  70. data/lib/xdrgen/generators/java/XdrDataInputStream.erb +122 -0
  71. data/lib/xdrgen/generators/java/XdrDataOutputStream.erb +96 -0
  72. data/lib/xdrgen/generators/java/XdrElement.erb +10 -0
  73. data/lib/xdrgen/generators/java/XdrString.erb +58 -0
  74. data/lib/xdrgen/generators/javascript.rb +248 -0
  75. data/lib/xdrgen/generators/ruby.rb +283 -0
  76. data/lib/xdrgen/grammar/base.treetop +71 -0
  77. data/lib/xdrgen/grammar/comments.treetop +15 -0
  78. data/lib/xdrgen/grammar/const.treetop +8 -0
  79. data/lib/xdrgen/grammar/declaration.treetop +99 -0
  80. data/lib/xdrgen/grammar/enum.treetop +46 -0
  81. data/lib/xdrgen/grammar/main.treetop +30 -0
  82. data/lib/xdrgen/grammar/namespace.treetop +12 -0
  83. data/lib/xdrgen/grammar/struct.treetop +32 -0
  84. data/lib/xdrgen/grammar/typedef.treetop +12 -0
  85. data/lib/xdrgen/grammar/union.treetop +63 -0
  86. data/lib/xdrgen/output.rb +37 -0
  87. data/lib/xdrgen/output_file.rb +87 -0
  88. data/lib/xdrgen/parser.rb +40 -0
  89. data/lib/xdrgen/version.rb +3 -0
  90. data/spec/fixtures/generator/block_comments.x +14 -0
  91. data/spec/fixtures/generator/const.x +4 -0
  92. data/spec/fixtures/generator/enum.x +36 -0
  93. data/spec/fixtures/generator/nesting.x +24 -0
  94. data/spec/fixtures/generator/optional.x +8 -0
  95. data/spec/fixtures/generator/struct.x +10 -0
  96. data/spec/fixtures/generator/test.x +77 -0
  97. data/spec/fixtures/generator/union.x +28 -0
  98. data/spec/fixtures/parser/block_comments.x +14 -0
  99. data/spec/fixtures/parser/const.x +1 -0
  100. data/spec/fixtures/parser/enum.x +35 -0
  101. data/spec/fixtures/parser/nesting.x +26 -0
  102. data/spec/fixtures/parser/optional.x +8 -0
  103. data/spec/fixtures/parser/struct.x +8 -0
  104. data/spec/fixtures/parser/test.x +77 -0
  105. data/spec/fixtures/parser/union.x +10 -0
  106. data/spec/lib/xdrgen/generator_spec.rb +30 -0
  107. data/spec/lib/xdrgen/output_file_spec.rb +33 -0
  108. data/spec/lib/xdrgen/parser_spec.rb +27 -0
  109. data/spec/spec_helper.rb +13 -0
  110. data/spec/support/fixtures.rb +27 -0
  111. data/xdrgen.gemspec +32 -0
  112. 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