xdrgen 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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