xdrgen 0.1.0 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30ccfde98b0baa13f03916b4b2d89c774ed8119e373e23541ca8e46e87f1db06
4
- data.tar.gz: abd5834683ef1d6e74e6decf61b7c3155a0cf1ef5fd03a4592acb43abd2e7446
3
+ metadata.gz: 838bb9438d35d145a409589e774549bf2e74ef83c25156abf40f410e2064a32b
4
+ data.tar.gz: 25488d84cb7c5c641c52308e915d8b2d4d63631c67aa7bcda22c18635fb0fd7b
5
5
  SHA512:
6
- metadata.gz: '040408ad8434aaa992df6533dd66954c85c389cfe76130ca188c2008c1592a758e315c0036929e9064b48d3d49bcf18fdf902455f1a7fdd0522da91d76d6085e'
7
- data.tar.gz: ec2721ba15cb25ec6aff042a5c1c3697b557d1dab85e6c61a2cc242b5be87c6af815e1e685b335e21e7da98b0ebe4156cc39444057141e8fb8521231b2444d7e
6
+ metadata.gz: 5bb40e6312ffc8c27febe50c367ab0b99141751b0b1b47c4a51c3cff7d33420b8a1410318175657756dbefc4ed20d7e9de5f37415692f423cd7043476e45842a
7
+ data.tar.gz: 33d7132dad38f3baedf34e17acc5704c688fdd280908864732f607821e831d6eca7e6544d258a80ff1575e547e50b38985131ed54d6a7286b05777942c2e729b
@@ -0,0 +1,23 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ ruby-version: ['2.7', '3.0']
14
+
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - name: Set up Ruby
18
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
19
+ with:
20
+ ruby-version: ${{ matrix.ruby-version }}
21
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
22
+ - name: Run Rspec tests
23
+ run: bundle exec rspec
data/README.md CHANGED
@@ -25,7 +25,8 @@ golang, and elixir:
25
25
  - golang: currently using a fork of go-xdr, but has complete support
26
26
  - elixir: support is experimental as the SDK is in early development. Generated
27
27
  code requires [:exdr](https://github.com/revelrylabs/exdr) in your deps
28
-
28
+ - C#: complete support
29
+
29
30
  Testing is _very_ sparse, but will improve over time.
30
31
 
31
32
  ## Usage as a binary
data/lib/xdrgen/cli.rb CHANGED
@@ -5,7 +5,7 @@ module Xdrgen
5
5
  def self.run(args)
6
6
  args = args.dup
7
7
  opts = Slop.parse! args do
8
- banner 'Usage: xdrgen -o OUTPUT_DIR INPUT --gen=ruby'
8
+ banner 'Usage: xdrgen -o OUTPUT_DIR INPUT --language=ruby'
9
9
  on 'o', 'output=', 'The output directory'
10
10
  on 'l', 'language=', 'The output language', default: 'ruby'
11
11
  on 'n', 'namespace=', '"namespace" to generate code within (language-specific)'
@@ -16,7 +16,7 @@ module Xdrgen
16
16
 
17
17
  compilation = Compilation.new(
18
18
  args,
19
- output_dir: opts[:output],
19
+ output_dir: opts[:output],
20
20
  language: opts[:language].to_sym,
21
21
  namespace: opts[:namespace]
22
22
  )
@@ -28,4 +28,4 @@ module Xdrgen
28
28
  exit(code)
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -7,6 +7,7 @@ module Xdrgen::Generators
7
7
  autoload :Javascript
8
8
  autoload :Java
9
9
  autoload :Elixir
10
+ autoload :Csharp
10
11
 
11
12
  def self.for_language(language)
12
13
  const_get language.to_s.classify
@@ -0,0 +1,580 @@
1
+ module Xdrgen
2
+ module Generators
3
+ class Csharp < Xdrgen::Generators::Base
4
+ def generate
5
+ render_lib
6
+ render_definitions(@top)
7
+ end
8
+
9
+ def render_lib; end
10
+
11
+ def render_definitions(node)
12
+ node.namespaces.each { |n| render_definitions n }
13
+ node.definitions.each(&method(:render_definition))
14
+ end
15
+
16
+ def render_definition(defn)
17
+ case defn
18
+ when AST::Definitions::Struct
19
+ render_element 'public class', defn do |out|
20
+ render_struct defn, out
21
+ render_nested_definitions defn, out
22
+ end
23
+ when AST::Definitions::Enum
24
+ render_element 'public class', defn do |out|
25
+ render_enum defn, out
26
+ end
27
+ when AST::Definitions::Union
28
+ render_element 'public class', defn do |out|
29
+ render_union defn, out
30
+ render_nested_definitions defn, out
31
+ end
32
+ when AST::Definitions::Typedef
33
+ render_element 'public class', defn do |out|
34
+ render_typedef defn, out
35
+ end
36
+ end
37
+ end
38
+
39
+ def render_nested_definitions(defn, out)
40
+ return unless defn.respond_to? :nested_definitions
41
+ defn.nested_definitions.each do |ndefn|
42
+ case ndefn
43
+ when AST::Definitions::Struct
44
+ name = name ndefn
45
+ out.puts "public class #{name} {"
46
+ out.indent do
47
+ render_struct ndefn, out
48
+ render_nested_definitions ndefn, out
49
+ end
50
+ out.puts '}'
51
+ when AST::Definitions::Enum
52
+ name = name ndefn
53
+ out.puts "public class #{name} {"
54
+ out.indent do
55
+ render_enum ndefn, out
56
+ end
57
+ out.puts '}'
58
+ when AST::Definitions::Union
59
+ name = name ndefn
60
+ out.puts "public class #{name} {"
61
+ out.indent do
62
+ render_union ndefn, out
63
+ render_nested_definitions ndefn, out
64
+ end
65
+ out.puts '}'
66
+ when AST::Definitions::Typedef
67
+ name = name ndefn
68
+ out.puts "public class #{name} {"
69
+ out.indent do
70
+ render_typedef ndefn, out
71
+ end
72
+ out.puts '}'
73
+ end
74
+ end
75
+ end
76
+
77
+ def render_element(type, element, post_name = '')
78
+ path = element.name.camelize + '.cs'
79
+ name = name_string element.name
80
+ out = @output.open(path)
81
+ render_top_matter out
82
+ render_source_comment out, element
83
+
84
+ out.puts "#{type} #{name} #{post_name} {"
85
+ out.indent do
86
+ yield out
87
+ out.unbreak
88
+ end
89
+ out.puts '}'
90
+ out.puts '}'
91
+ end
92
+
93
+ def render_enum(enum, out)
94
+ enumname = enum.name + 'Enum'
95
+
96
+ out.puts "public enum #{enumname} {"
97
+ out.balance_after /,[\s]*/ do
98
+ enum.members.each do |em|
99
+ out.puts "#{em.name} = #{em.value},"
100
+ end
101
+ end
102
+ out.puts "}\n"
103
+ out.puts <<-EOS.strip_heredoc
104
+ public #{enumname} InnerValue {get; set;} = default(#{enumname});
105
+
106
+ public static #{enum.name} Create(#{enumname} v)
107
+ {
108
+ return new #{enum.name} {
109
+ InnerValue = v
110
+ };
111
+ }
112
+
113
+ public static #{name_string enum.name} Decode(XdrDataInputStream stream) {
114
+ int value = stream.ReadInt();
115
+ switch (value) {
116
+ EOS
117
+ out.indent 2 do
118
+ enum.members.each do |em|
119
+ out.puts "case #{em.value}: return Create(#{enumname}.#{em.name});"
120
+ end
121
+ end
122
+ out.puts <<-EOS.strip_heredoc
123
+ default:
124
+ throw new Exception("Unknown enum value: " + value);
125
+ }
126
+ }
127
+
128
+ public static void Encode(XdrDataOutputStream stream, #{name_string enum.name} value) {
129
+ stream.WriteInt((int)value.InnerValue);
130
+ }
131
+ EOS
132
+ out.break
133
+ end
134
+
135
+ def render_struct(struct, out)
136
+ out.puts "public #{name struct} () {}"
137
+ struct.members.each do |m|
138
+ out.puts <<-EOS.strip_heredoc
139
+ public #{decl_string(m.declaration)} #{m.name.camelize} {get; set;}
140
+ EOS
141
+ end
142
+ out.puts "\n"
143
+ out.puts "public static void Encode(XdrDataOutputStream stream, #{name struct} encoded#{name struct}) {"
144
+ struct.members.each do |m|
145
+ out.indent do
146
+ encode_member "encoded#{name struct}", m, out
147
+ end
148
+ end
149
+ out.puts '}'
150
+
151
+ out.puts <<-EOS.strip_heredoc
152
+ public static #{name struct} Decode(XdrDataInputStream stream) {
153
+ #{name struct} decoded#{name struct} = new #{name struct}();
154
+ EOS
155
+ struct.members.each do |m|
156
+ out.indent do
157
+ decode_member "decoded#{name struct}", m, out
158
+ end
159
+ end
160
+ out.indent do
161
+ out.puts "return decoded#{name struct};"
162
+ end
163
+ out.puts '}'
164
+
165
+ out.break
166
+ end
167
+
168
+ def render_typedef(typedef, out)
169
+ out.puts <<-EOS.strip_heredoc
170
+ public #{decl_string typedef.declaration} InnerValue {get; set;} = default(#{decl_string typedef.declaration});
171
+
172
+ public #{typedef.name.camelize}() {}
173
+
174
+ public #{typedef.name.camelize}(#{decl_string typedef.declaration} value)
175
+ {
176
+ InnerValue = value;
177
+ }
178
+
179
+ EOS
180
+ out.puts "public static void Encode(XdrDataOutputStream stream, #{name typedef} encoded#{name typedef}) {"
181
+ encode_innervalue_member "encoded#{name typedef}", typedef, out
182
+ out.puts '}'
183
+
184
+ out.puts <<-EOS.strip_heredoc
185
+ public static #{name typedef} Decode(XdrDataInputStream stream) {
186
+ #{name typedef} decoded#{name typedef} = new #{name typedef}();
187
+ EOS
188
+ decode_innervalue_member "decoded#{name typedef}", typedef, out
189
+ out.indent do
190
+ out.puts "return decoded#{name typedef};"
191
+ end
192
+ out.puts '}'
193
+ end
194
+
195
+ def render_union(union, out)
196
+ has_inner_value = false
197
+
198
+ out.puts "public #{name union} () {}"
199
+ out.puts <<-EOS.strip_heredoc
200
+
201
+ public #{type_string union.discriminant.type} Discriminant { get; set; } = new #{type_string union.discriminant.type}();
202
+
203
+ EOS
204
+ union.arms.each do |arm|
205
+ next if arm.void?
206
+ out.puts <<-EOS.strip_heredoc
207
+ public #{decl_string(arm.declaration)} #{arm.name.camelize} {get; set;}
208
+ EOS
209
+ end
210
+
211
+ out.puts "public static void Encode(XdrDataOutputStream stream, #{name union} encoded#{name union}) {"
212
+ if union.discriminant.type.is_a?(AST::Typespecs::Int)
213
+ out.puts "stream.WriteInt((int)encoded#{name union}.Discriminant);"
214
+ out.puts "switch (encoded#{name union}.Discriminant) {"
215
+ # elsif [discriminant is AST::Definitions::Typedef]
216
+ # out.puts "stream.writeInt(encoded#{name union}.getDiscriminant().get#{name union.discriminant.type}());"
217
+ else
218
+ has_inner_value = true
219
+ out.puts "stream.WriteInt((int)encoded#{name union}.Discriminant.InnerValue);"
220
+ out.puts "switch (encoded#{name union}.Discriminant.InnerValue) {"
221
+ end
222
+
223
+ union.arms.each do |arm|
224
+ case arm
225
+ when AST::Definitions::UnionDefaultArm
226
+ out.puts 'default:'
227
+ else
228
+ arm.cases.each do |kase|
229
+ if kase.value.is_a?(AST::Identifier)
230
+ out.puts "case #{type_string union.discriminant.type}.#{type_string union.discriminant.type}Enum.#{kase.value.name}:"
231
+ else
232
+ out.puts "case #{kase.value.value}:"
233
+ end
234
+ end
235
+ end
236
+ encode_member "encoded#{name union}", arm, out
237
+ out.puts 'break;'
238
+ end
239
+ out.puts "}\n}"
240
+
241
+ out.puts "public static #{name union} Decode(XdrDataInputStream stream) {"
242
+ out.puts "#{name union} decoded#{name union} = new #{name union}();"
243
+ if union.discriminant.type.is_a?(AST::Typespecs::Int)
244
+ out.puts 'int discriminant = stream.ReadInt();'
245
+ out.puts "decoded#{name union}.Discriminant = discriminant;"
246
+ out.puts "switch (decoded#{name union}.Discriminant) {"
247
+ else
248
+ out.puts "#{name union.discriminant.type} discriminant = #{name union.discriminant.type}.Decode(stream);"
249
+ out.puts "decoded#{name union}.Discriminant = discriminant;"
250
+ out.puts "switch (decoded#{name union}.Discriminant.InnerValue) {"
251
+ end
252
+
253
+ union.arms.each do |arm|
254
+ case arm
255
+ when AST::Definitions::UnionDefaultArm
256
+ out.puts 'default:'
257
+ else
258
+ arm.cases.each do |kase|
259
+ if kase.value.is_a?(AST::Identifier)
260
+ out.puts "case #{type_string union.discriminant.type}.#{type_string union.discriminant.type}Enum.#{kase.value.name}:"
261
+ else
262
+ out.puts "case #{kase.value.value}:"
263
+ end
264
+ end
265
+ end
266
+ decode_member "decoded#{name union}", arm, out
267
+ out.puts 'break;'
268
+ end
269
+ out.puts "}\n"
270
+ out.indent do
271
+ out.puts "return decoded#{name union};"
272
+ end
273
+ out.puts '}'
274
+
275
+ out.break
276
+ end
277
+
278
+ def render_top_matter(out)
279
+ out.puts <<-EOS.strip_heredoc
280
+ // Automatically generated by xdrgen
281
+ // DO NOT EDIT or your changes may be overwritten
282
+ using System;
283
+
284
+ namespace #{@namespace} {
285
+ EOS
286
+ out.break
287
+ end
288
+
289
+ def render_source_comment(out, defn)
290
+ return if defn.is_a?(AST::Definitions::Namespace)
291
+
292
+ out.puts <<-EOS.strip_heredoc
293
+ // === xdr source ============================================================
294
+
295
+ EOS
296
+
297
+ out.puts '// ' + defn.text_value.split("\n").join("\n// ")
298
+
299
+ out.puts <<-EOS.strip_heredoc
300
+
301
+ // ===========================================================================
302
+ EOS
303
+ end
304
+
305
+ def encode_innervalue_member(value, member, out)
306
+ case member.declaration
307
+ when AST::Declarations::Void
308
+ return
309
+ end
310
+
311
+ if member.type.sub_type == :optional
312
+ out.puts "if (#{value}.InnerValue != null) {"
313
+ out.puts 'stream.WriteInt(1);'
314
+ end
315
+
316
+ case member.declaration
317
+ when AST::Declarations::Opaque
318
+ out.puts "int #{member.name}size = #{value}.InnerValue.Length;"
319
+ unless member.declaration.fixed?
320
+ out.puts "stream.WriteInt(#{member.name.camelize}size);"
321
+ end
322
+ out.puts <<-EOS.strip_heredoc
323
+ stream.Write(#{value}.InnerValue, 0, #{member.name}size);
324
+ EOS
325
+ when AST::Declarations::Array
326
+ out.puts "int #{member.name}size = #{value}.InnerValue.Length;"
327
+ unless member.declaration.fixed?
328
+ out.puts "stream.WriteInt(#{member.name}size);"
329
+ end
330
+ out.puts <<-EOS.strip_heredoc
331
+ for (int i = 0; i < #{member.name}size; i++) {
332
+ #{encode_type member.declaration.type, "#{value}.InnerValue[i]"};
333
+ }
334
+ EOS
335
+ else
336
+ out.puts "#{encode_type member.declaration.type, "#{value}.InnerValue"};"
337
+ end
338
+ if member.type.sub_type == :optional
339
+ out.puts '} else {'
340
+ out.puts 'stream.WriteInt(0);'
341
+ out.puts '}'
342
+ end
343
+ end
344
+
345
+ def encode_member(value, member, out)
346
+ case member.declaration
347
+ when AST::Declarations::Void
348
+ return
349
+ end
350
+
351
+ if member.type.sub_type == :optional
352
+ out.puts "if (#{value}.#{member.name.camelize} != null) {"
353
+ out.puts 'stream.WriteInt(1);'
354
+ end
355
+ case member.declaration
356
+ when AST::Declarations::Opaque
357
+ out.puts "int #{member.name}size = #{value}.#{member.name.camelize}.Length;"
358
+ unless member.declaration.fixed?
359
+ out.puts "stream.WriteInt(#{member.name.camelize}size);"
360
+ end
361
+ out.puts <<-EOS.strip_heredoc
362
+ stream.Write(#{value}.#{member.name.camelize}, 0, #{member.name}size);
363
+ EOS
364
+ when AST::Declarations::Array
365
+ out.puts "int #{member.name}size = #{value}.#{member.name.camelize}.Length;"
366
+ unless member.declaration.fixed?
367
+ out.puts "stream.WriteInt(#{member.name}size);"
368
+ end
369
+ out.puts <<-EOS.strip_heredoc
370
+ for (int i = 0; i < #{member.name}size; i++) {
371
+ #{encode_type member.declaration.type, "#{value}.#{member.name.camelize}[i]"};
372
+ }
373
+ EOS
374
+ else
375
+ out.puts "#{encode_type member.declaration.type, "#{value}.#{member.name.camelize}"};"
376
+ end
377
+ if member.type.sub_type == :optional
378
+ out.puts '} else {'
379
+ out.puts 'stream.WriteInt(0);'
380
+ out.puts '}'
381
+ end
382
+ end
383
+
384
+ def encode_type(type, value)
385
+ case type
386
+ when AST::Typespecs::Int
387
+ "stream.WriteInt(#{value})"
388
+ when AST::Typespecs::UnsignedInt
389
+ "stream.WriteInt(#{value})"
390
+ when AST::Typespecs::Hyper
391
+ "stream.WriteLong(#{value})"
392
+ when AST::Typespecs::UnsignedHyper
393
+ "stream.WriteLong(#{value})"
394
+ when AST::Typespecs::Float
395
+ "stream.WriteFloat(#{value})"
396
+ when AST::Typespecs::Double
397
+ "stream.WriteDouble(#{value})"
398
+ when AST::Typespecs::Quadruple
399
+ raise 'cannot render quadruple in c#'
400
+ when AST::Typespecs::Bool
401
+ "stream.WriteInt(#{value} ? 1 : 0)"
402
+ when AST::Typespecs::String
403
+ "stream.WriteString(#{value})"
404
+ when AST::Typespecs::Simple
405
+ "#{name type.resolved_type}.Encode(stream, #{value})"
406
+ when AST::Concerns::NestedDefinition
407
+ "#{name type}.Encode(stream, #{value})"
408
+ else
409
+ raise "Unknown typespec: #{type.class.name}"
410
+ end
411
+ end
412
+
413
+ def decode_innervalue_member(value, member, out)
414
+ case member.declaration
415
+ when AST::Declarations::Void
416
+ return
417
+ end
418
+ if member.type.sub_type == :optional
419
+ out.puts <<-EOS.strip_heredoc
420
+ int #{member.name.camelize}Present = stream.ReadInt();
421
+ if (#{member.name.camelize}Present != 0) {
422
+ EOS
423
+ end
424
+ case member.declaration
425
+ when AST::Declarations::Opaque
426
+ if member.declaration.fixed?
427
+ out.puts "int #{member.name}size = #{member.declaration.size};"
428
+ else
429
+ out.puts "int #{member.name}size = stream.ReadInt();"
430
+ end
431
+ out.puts <<-EOS.strip_heredoc
432
+ #{value}.InnerValue = new byte[#{member.name}size];
433
+ stream.Read(#{value}.InnerValue, 0, #{member.name}size);
434
+ EOS
435
+ when AST::Declarations::Array
436
+ if member.declaration.fixed?
437
+ out.puts "int #{member.name}size = #{member.declaration.size};"
438
+ else
439
+ out.puts "int #{member.name}size = stream.ReadInt();"
440
+ end
441
+ out.puts <<-EOS.strip_heredoc
442
+ #{value}.InnerValue = new #{type_string member.type}[#{member.name}size];
443
+ for (int i = 0; i < #{member.name}size; i++) {
444
+ #{value}.InnerValue[i] = #{decode_type member.declaration.type};
445
+ }
446
+ EOS
447
+ else
448
+ out.puts "#{value}.InnerValue = #{decode_type member.declaration.type};"
449
+ end
450
+ out.puts '}' if member.type.sub_type == :optional
451
+ end
452
+
453
+ def decode_member(value, member, out)
454
+ case member.declaration
455
+ when AST::Declarations::Void
456
+ return
457
+ end
458
+ if member.type.sub_type == :optional
459
+ out.puts <<-EOS.strip_heredoc
460
+ int #{member.name.camelize}Present = stream.ReadInt();
461
+ if (#{member.name.camelize}Present != 0) {
462
+ EOS
463
+ end
464
+ case member.declaration
465
+ when AST::Declarations::Opaque
466
+ if member.declaration.fixed?
467
+ out.puts "int #{member.name}size = #{member.declaration.size};"
468
+ else
469
+ out.puts "int #{member.name}size = stream.ReadInt();"
470
+ end
471
+ out.puts <<-EOS.strip_heredoc
472
+ #{value}.#{member.name.camelize} = new byte[#{member.name}size];
473
+ stream.Read(#{value}.#{member.name.camelize},0,#{member.name}size);
474
+ EOS
475
+ when AST::Declarations::Array
476
+ if member.declaration.fixed?
477
+ out.puts "int #{member.name}size = #{member.declaration.size};"
478
+ else
479
+ out.puts "int #{member.name}size = stream.ReadInt();"
480
+ end
481
+ out.puts <<-EOS.strip_heredoc
482
+ #{value}.#{member.name.camelize} = new #{type_string member.type}[#{member.name}size];
483
+ for (int i = 0; i < #{member.name}size; i++) {
484
+ #{value}.#{member.name.camelize}[i] = #{decode_type member.declaration.type};
485
+ }
486
+ EOS
487
+ else
488
+ out.puts "#{value}.#{member.name.camelize} = #{decode_type member.declaration.type};"
489
+ end
490
+ out.puts '}' if member.type.sub_type == :optional
491
+ end
492
+
493
+ def decode_type(type)
494
+ case type
495
+ when AST::Typespecs::Int
496
+ 'stream.ReadInt()'
497
+ when AST::Typespecs::UnsignedInt
498
+ 'stream.ReadInt()'
499
+ when AST::Typespecs::Hyper
500
+ 'stream.ReadLong()'
501
+ when AST::Typespecs::UnsignedHyper
502
+ 'stream.ReadLong()'
503
+ when AST::Typespecs::Float
504
+ 'stream.ReadFloat()'
505
+ when AST::Typespecs::Double
506
+ 'stream.ReadDouble()'
507
+ when AST::Typespecs::Quadruple
508
+ raise 'cannot render quadruple in c#'
509
+ when AST::Typespecs::Bool
510
+ 'stream.ReadInt() == 1 ? true : false'
511
+ when AST::Typespecs::String
512
+ 'stream.ReadString()'
513
+ when AST::Typespecs::Simple
514
+ "#{name type.resolved_type}.Decode(stream)"
515
+ when AST::Concerns::NestedDefinition
516
+ "#{name type}.Decode(stream)"
517
+ else
518
+ raise "Unknown typespec: #{type.class.name}"
519
+ end
520
+ end
521
+
522
+ def decl_string(decl)
523
+ case decl
524
+ when AST::Declarations::Opaque
525
+ 'byte[]'
526
+ when AST::Declarations::String
527
+ 'String'
528
+ when AST::Declarations::Array
529
+ "#{type_string decl.type}[]"
530
+ when AST::Declarations::Optional
531
+ type_string(decl.type).to_s
532
+ when AST::Declarations::Simple
533
+ type_string(decl.type)
534
+ else
535
+ raise "Unknown declaration type: #{decl.class.name}"
536
+ end
537
+ end
538
+
539
+ def type_string(type)
540
+ case type
541
+ when AST::Typespecs::Int
542
+ 'int'
543
+ when AST::Typespecs::UnsignedInt
544
+ 'int'
545
+ when AST::Typespecs::Hyper
546
+ 'long'
547
+ when AST::Typespecs::UnsignedHyper
548
+ 'long'
549
+ when AST::Typespecs::Float
550
+ 'float'
551
+ when AST::Typespecs::Double
552
+ 'double'
553
+ when AST::Typespecs::Quadruple
554
+ 'Tuple'
555
+ when AST::Typespecs::Bool
556
+ 'bool'
557
+ when AST::Typespecs::Opaque
558
+ "Byte[#{type.size}]"
559
+ when AST::Typespecs::Simple
560
+ name type.resolved_type
561
+ when AST::Concerns::NestedDefinition
562
+ name type
563
+ else
564
+ raise "Unknown typespec: #{type.class.name}"
565
+ end
566
+ end
567
+
568
+ def name(named)
569
+ parent = name named.parent_defn if named.is_a?(AST::Concerns::NestedDefinition)
570
+ result = named.name.camelize
571
+
572
+ "#{parent}#{result}"
573
+ end
574
+
575
+ def name_string(name)
576
+ name.camelize
577
+ end
578
+ end
579
+ end
580
+ end
@@ -164,7 +164,7 @@ module Xdrgen
164
164
  parent = name named.parent_defn if named.is_a?(AST::Concerns::NestedDefinition)
165
165
 
166
166
  # NOTE: classify will strip plurality, so we restore it if necessary
167
- plural = named.name.downcase.pluralize == named.name.downcase
167
+ plural = named.name.underscore.downcase.pluralize == named.name.underscore.downcase
168
168
  base = named.name.underscore.classify
169
169
  result = plural ? base.pluralize : base
170
170
 
@@ -305,33 +305,77 @@ module Xdrgen
305
305
  out.puts <<-EOS.strip_heredoc
306
306
  @Override
307
307
  public boolean equals(Object object) {
308
- if (object == null || !(object instanceof #{type})) {
308
+ if (!(object instanceof #{type})) {
309
309
  return false;
310
310
  }
311
311
 
312
312
  #{type} other = (#{type}) object;
313
313
  return #{equalExpression};
314
314
  }
315
+
315
316
  EOS
316
317
 
318
+ out.puts "public static final class Builder {"
319
+ out.indent do
320
+ struct.members.map { |m|
321
+ out.puts "private #{decl_string(m.declaration)} #{m.name};"
322
+ }
323
+
324
+ struct.members.map { |m|
325
+ out.puts <<-EOS.strip_heredoc
326
+
327
+ public Builder #{m.name}(#{decl_string(m.declaration)} #{m.name}) {
328
+ this.#{m.name} = #{m.name};
329
+ return this;
330
+ }
331
+ EOS
332
+ }
333
+
334
+ end
335
+
336
+
337
+ out.indent do
338
+ out.break
339
+ out.puts "public #{name struct} build() {"
340
+ out.indent do
341
+ out.puts "#{name struct} val = new #{name struct}();"
342
+ struct.members.map { |m|
343
+ out.puts "val.set#{m.name.slice(0,1).capitalize+m.name.slice(1..-1)}(#{m.name});"
344
+ }
345
+ out.puts "return val;"
346
+ end
347
+ out.puts "}"
348
+ end
349
+ out.puts "}"
317
350
  out.break
318
351
  end
319
352
 
320
353
  def render_typedef(typedef, out)
321
354
  out.puts <<-EOS.strip_heredoc
322
355
  private #{decl_string typedef.declaration} #{typedef.name};
356
+
357
+ public #{typedef.name.camelize}() {}
358
+
359
+ public #{typedef.name.camelize}(#{decl_string typedef.declaration} #{typedef.name}) {
360
+ this.#{typedef.name} = #{typedef.name};
361
+ }
362
+
323
363
  public #{decl_string typedef.declaration} get#{typedef.name.slice(0,1).capitalize+typedef.name.slice(1..-1)}() {
324
364
  return this.#{typedef.name};
325
365
  }
366
+
326
367
  public void set#{typedef.name.slice(0,1).capitalize+typedef.name.slice(1..-1)}(#{decl_string typedef.declaration} value) {
327
368
  this.#{typedef.name} = value;
328
369
  }
329
- EOS
330
370
 
371
+ EOS
331
372
 
332
373
  out.puts "public static void encode(XdrDataOutputStream stream, #{name typedef} encoded#{name typedef}) throws IOException {"
333
- encode_member "encoded#{name typedef}", typedef, out
374
+ out.indent do
375
+ encode_member "encoded#{name typedef}", typedef, out
376
+ end
334
377
  out.puts "}"
378
+ out.break
335
379
 
336
380
  out.puts <<-EOS.strip_heredoc
337
381
  public void encode(XdrDataOutputStream stream) throws IOException {
@@ -343,11 +387,12 @@ module Xdrgen
343
387
  public static #{name typedef} decode(XdrDataInputStream stream) throws IOException {
344
388
  #{name typedef} decoded#{name typedef} = new #{name typedef}();
345
389
  EOS
346
- decode_member "decoded#{name typedef}", typedef, out
347
390
  out.indent do
391
+ decode_member "decoded#{name typedef}", typedef, out
348
392
  out.puts "return decoded#{name typedef};"
349
393
  end
350
394
  out.puts "}"
395
+ out.break
351
396
 
352
397
  hash_coder_for_decl =
353
398
  if is_decl_array(typedef.declaration)
@@ -360,6 +405,7 @@ module Xdrgen
360
405
  public int hashCode() {
361
406
  return #{hash_coder_for_decl}(this.#{typedef.name});
362
407
  }
408
+
363
409
  EOS
364
410
 
365
411
  equals_for_decl =
@@ -372,7 +418,7 @@ module Xdrgen
372
418
  out.puts <<-EOS.strip_heredoc
373
419
  @Override
374
420
  public boolean equals(Object object) {
375
- if (object == null || !(object instanceof #{type})) {
421
+ if (!(object instanceof #{type})) {
376
422
  return false;
377
423
  }
378
424
 
@@ -405,6 +451,54 @@ module Xdrgen
405
451
  }
406
452
  EOS
407
453
  end
454
+ out.break
455
+
456
+ out.puts "public static final class Builder {"
457
+ out.indent do
458
+ out.puts "private #{type_string union.discriminant.type} discriminant;"
459
+ union.arms.each do |arm|
460
+ next if arm.void?
461
+ out.puts "private #{decl_string(arm.declaration)} #{arm.name};"
462
+ end
463
+ out.break
464
+
465
+ out.puts <<-EOS.strip_heredoc
466
+ public Builder discriminant(#{type_string union.discriminant.type} discriminant) {
467
+ this.discriminant = discriminant;
468
+ return this;
469
+ }
470
+ EOS
471
+
472
+ union.arms.each do |arm|
473
+ next if arm.void?
474
+ out.puts <<-EOS.strip_heredoc
475
+
476
+ public Builder #{arm.name}(#{decl_string(arm.declaration)} #{arm.name}) {
477
+ this.#{arm.name} = #{arm.name};
478
+ return this;
479
+ }
480
+ EOS
481
+ end
482
+ end
483
+
484
+ out.indent do
485
+ out.break
486
+ out.puts "public #{name union} build() {"
487
+ out.indent do
488
+ out.puts "#{name union} val = new #{name union}();"
489
+ out.puts "val.setDiscriminant(discriminant);"
490
+ union.arms.each do |arm|
491
+ next if arm.void?
492
+ out.puts "val.set#{arm.name.slice(0,1).capitalize+arm.name.slice(1..-1)}(#{arm.name});"
493
+ end
494
+ out.puts "return val;"
495
+ end
496
+ out.puts "}"
497
+ end
498
+ out.puts "}"
499
+ out.break
500
+
501
+
408
502
  out.puts "public static void encode(XdrDataOutputStream stream, #{name union} encoded#{name union}) throws IOException {"
409
503
  out.puts('//' + union.discriminant.type.class.to_s)
410
504
  out.puts("//" + type_string(union.discriminant.type))
@@ -543,7 +637,7 @@ module Xdrgen
543
637
  out.puts <<-EOS.strip_heredoc
544
638
  @Override
545
639
  public boolean equals(Object object) {
546
- if (object == null || !(object instanceof #{type})) {
640
+ if (!(object instanceof #{type})) {
547
641
  return false;
548
642
  }
549
643
 
@@ -178,7 +178,7 @@ module Xdrgen
178
178
  # "BEGIN_SPONSORING_FUTURE_RESERVEs" == "BEGIN_SPONSORING_FUTURE_RESERVES"
179
179
  # => false
180
180
  #
181
- plural = named.name.downcase.pluralize == named.name.downcase
181
+ plural = named.name.underscore.downcase.pluralize == named.name.underscore.downcase
182
182
  base = named.name.underscore.classify
183
183
  result = plural ? base.pluralize : base
184
184
 
@@ -1,3 +1,3 @@
1
1
  module Xdrgen
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xdrgen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Fleckenstein
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-06 00:00:00.000000000 Z
11
+ date: 2021-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: treetop
@@ -136,7 +136,7 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
- description:
139
+ description:
140
140
  email:
141
141
  - scott@stellar.org
142
142
  executables:
@@ -144,8 +144,8 @@ executables:
144
144
  extensions: []
145
145
  extra_rdoc_files: []
146
146
  files:
147
+ - ".github/workflows/ruby.yml"
147
148
  - ".gitignore"
148
- - ".travis.yml"
149
149
  - Gemfile
150
150
  - Guardfile
151
151
  - LICENSE.txt
@@ -209,6 +209,7 @@ files:
209
209
  - lib/xdrgen/compilation.rb
210
210
  - lib/xdrgen/generators.rb
211
211
  - lib/xdrgen/generators/base.rb
212
+ - lib/xdrgen/generators/csharp.rb
212
213
  - lib/xdrgen/generators/elixir.rb
213
214
  - lib/xdrgen/generators/go.rb
214
215
  - lib/xdrgen/generators/java.rb
@@ -258,7 +259,7 @@ homepage: http://github.com/stellar/xdrgen
258
259
  licenses:
259
260
  - ISC
260
261
  metadata: {}
261
- post_install_message:
262
+ post_install_message:
262
263
  rdoc_options: []
263
264
  require_paths:
264
265
  - lib
@@ -273,8 +274,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
273
274
  - !ruby/object:Gem::Version
274
275
  version: '0'
275
276
  requirements: []
276
- rubygems_version: 3.0.3
277
- signing_key:
277
+ rubygems_version: 3.2.15
278
+ signing_key:
278
279
  specification_version: 4
279
280
  summary: An XDR code generator
280
281
  test_files:
data/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- language: ruby
2
- script: bundle exec rspec
3
- rvm:
4
- - 2.7.0