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,16 @@
|
|
|
1
|
+
module Xdrgen::Generators
|
|
2
|
+
extend ActiveSupport::Autoload
|
|
3
|
+
|
|
4
|
+
autoload :Base
|
|
5
|
+
autoload :Ruby
|
|
6
|
+
autoload :Go
|
|
7
|
+
autoload :Javascript
|
|
8
|
+
autoload :Java
|
|
9
|
+
autoload :Elixir
|
|
10
|
+
|
|
11
|
+
def self.for_language(language)
|
|
12
|
+
const_get language.to_s.classify
|
|
13
|
+
rescue NameError
|
|
14
|
+
raise ArgumentError, "Unsupported language: #{language}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
module Xdrgen
|
|
2
|
+
module Generators
|
|
3
|
+
class Elixir < Xdrgen::Generators::Base
|
|
4
|
+
MAX_INT = (2**31) - 1
|
|
5
|
+
def generate
|
|
6
|
+
path = "#{@namespace}_generated.ex"
|
|
7
|
+
out = @output.open(path)
|
|
8
|
+
|
|
9
|
+
render_define_block(out) do
|
|
10
|
+
out.indent() do
|
|
11
|
+
render_definitions(out, @top)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
def render_definitions(out, node)
|
|
18
|
+
node.definitions.each{|n| render_definition out, n }
|
|
19
|
+
node.namespaces.each{|n| render_definitions out, n }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def render_nested_definitions(out, defn)
|
|
23
|
+
return unless defn.respond_to? :nested_definitions
|
|
24
|
+
defn.nested_definitions.each{|ndefn| render_definition out, ndefn}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def render_definition(out, defn)
|
|
28
|
+
render_nested_definitions(out, defn)
|
|
29
|
+
render_source_comment(out, defn)
|
|
30
|
+
|
|
31
|
+
case defn
|
|
32
|
+
when AST::Definitions::Struct ;
|
|
33
|
+
render_struct out, defn
|
|
34
|
+
when AST::Definitions::Enum ;
|
|
35
|
+
render_enum out, defn
|
|
36
|
+
when AST::Definitions::Union ;
|
|
37
|
+
render_union out, defn
|
|
38
|
+
when AST::Definitions::Typedef ;
|
|
39
|
+
render_typedef out, defn
|
|
40
|
+
when AST::Definitions::Const ;
|
|
41
|
+
render_const out, defn
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
out.break
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def render_source_comment(out, defn)
|
|
48
|
+
return if defn.is_a?(AST::Definitions::Namespace)
|
|
49
|
+
|
|
50
|
+
out.puts <<-EOS.strip_heredoc
|
|
51
|
+
comment ~S"""
|
|
52
|
+
=== xdr source ============================================================
|
|
53
|
+
|
|
54
|
+
EOS
|
|
55
|
+
|
|
56
|
+
out.puts " " + defn.text_value.split("\n").join("\n ")
|
|
57
|
+
|
|
58
|
+
out.puts <<-EOS.strip_heredoc
|
|
59
|
+
|
|
60
|
+
===========================================================================
|
|
61
|
+
"""
|
|
62
|
+
EOS
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def render_moduledoc(out)
|
|
66
|
+
out.puts <<-EOS.strip_heredoc
|
|
67
|
+
@moduledoc """
|
|
68
|
+
Automatically generated on #{Time.now.iso8601}
|
|
69
|
+
DO NOT EDIT or your changes may be overwritten
|
|
70
|
+
|
|
71
|
+
Target implementation: exdr at https://hex.pm/packages/exdr
|
|
72
|
+
"""
|
|
73
|
+
EOS
|
|
74
|
+
out.break
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def render_define_block(out)
|
|
78
|
+
out.puts "defmodule #{@namespace} do"
|
|
79
|
+
out.indent do
|
|
80
|
+
render_moduledoc(out)
|
|
81
|
+
out.puts "use XDR.Base\n\n"
|
|
82
|
+
end
|
|
83
|
+
yield
|
|
84
|
+
ensure
|
|
85
|
+
out.puts "end"
|
|
86
|
+
out.break
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def render_typedef(out, typedef)
|
|
91
|
+
out.puts "define_type(\"#{name typedef}\", #{build_type_args typedef.declaration.type})"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def render_const(out, const)
|
|
95
|
+
out.puts "define_type(\"#{const_name const}\", Const, #{const.value});"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def render_struct(out, struct)
|
|
99
|
+
out.puts "define_type(\"#{name struct}\", Struct,"
|
|
100
|
+
out.indent do
|
|
101
|
+
struct.members.each_with_index do |m, i|
|
|
102
|
+
out.puts "#{member_name m}: #{type_reference m.type}#{comma_unless_last(i, struct.members)}"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
out.puts ")"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def render_enum(out, enum)
|
|
109
|
+
out.puts "define_type(\"#{name enum}\", Enum,"
|
|
110
|
+
out.indent do
|
|
111
|
+
enum.members.each_with_index do |m, i|
|
|
112
|
+
out.puts "#{member_name m}: #{m.value}#{comma_unless_last(i, enum.members)}"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
out.puts ")"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def render_union(out, union)
|
|
119
|
+
out.puts "define_type(\"#{name union}\", Union,"
|
|
120
|
+
out.indent do
|
|
121
|
+
out.puts "switch_type: #{type_reference union.discriminant.type},"
|
|
122
|
+
out.puts "switch_name: :#{member_name union.discriminant},"
|
|
123
|
+
|
|
124
|
+
out.puts "switches: ["
|
|
125
|
+
out.indent do
|
|
126
|
+
union.normal_arms.each do |arm|
|
|
127
|
+
arm_name = arm.void? ? "XDR.Type.Void" : ":#{member_name(arm)}"
|
|
128
|
+
|
|
129
|
+
arm.cases.each do |acase|
|
|
130
|
+
switch = if acase.value.is_a?(AST::Identifier)
|
|
131
|
+
":#{member_name(acase.value)}"
|
|
132
|
+
else
|
|
133
|
+
acase.value.text_value
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
out.puts "{#{switch}, #{arm_name}},"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
out.puts "],"
|
|
141
|
+
|
|
142
|
+
out.puts "arms: ["
|
|
143
|
+
out.indent do
|
|
144
|
+
union.arms.each do |arm|
|
|
145
|
+
next if arm.void?
|
|
146
|
+
out.puts "#{member_name arm}: #{type_reference arm.type},"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
out.puts union.default_arm.present? ? "]," : "]"
|
|
150
|
+
|
|
151
|
+
if union.default_arm.present?
|
|
152
|
+
arm = union.default_arm
|
|
153
|
+
arm_name = arm.void? ? "XDR.Type.Void" : member_name(arm)
|
|
154
|
+
out.puts "default_arm: #{arm_name},"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
out.puts ")"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private
|
|
161
|
+
def name(named)
|
|
162
|
+
return nil unless named.respond_to?(:name)
|
|
163
|
+
|
|
164
|
+
parent = name named.parent_defn if named.is_a?(AST::Concerns::NestedDefinition)
|
|
165
|
+
|
|
166
|
+
# NOTE: classify will strip plurality, so we restore it if necessary
|
|
167
|
+
plural = named.name.pluralize == named.name
|
|
168
|
+
base = named.name.underscore.classify
|
|
169
|
+
result = plural ? base.pluralize : base
|
|
170
|
+
|
|
171
|
+
"#{parent}#{result}"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def const_name(named)
|
|
175
|
+
# NOTE: classify will strip plurality, so we restore it if necessary
|
|
176
|
+
plural = named.name.pluralize == named.name
|
|
177
|
+
base = named.name.underscore.upcase
|
|
178
|
+
plural ? base.pluralize : base
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def member_name(member)
|
|
182
|
+
name(member).underscore
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# this can be a string to reference a custom type
|
|
186
|
+
# or a build_type call like build_type(VariableOpaque, 100)
|
|
187
|
+
# args for build_type can be created with build_type_args
|
|
188
|
+
def type_reference(type)
|
|
189
|
+
build_args = build_type_args(type)
|
|
190
|
+
|
|
191
|
+
build_args === "\"#{name type}\"" ? build_args : "build_type(#{build_args})"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def comma_unless_last(index, collection)
|
|
195
|
+
if index + 1 >= collection.length
|
|
196
|
+
""
|
|
197
|
+
else
|
|
198
|
+
","
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# the args to supply build_type (or define_type(name, ...args))
|
|
203
|
+
def build_type_args(type)
|
|
204
|
+
base_ref = case type
|
|
205
|
+
when AST::Typespecs::Bool
|
|
206
|
+
"Bool"
|
|
207
|
+
when AST::Typespecs::Double
|
|
208
|
+
"Double"
|
|
209
|
+
when AST::Typespecs::Float
|
|
210
|
+
"Float"
|
|
211
|
+
when AST::Typespecs::Hyper
|
|
212
|
+
"HyperInt"
|
|
213
|
+
when AST::Typespecs::Int
|
|
214
|
+
"Int"
|
|
215
|
+
when AST::Typespecs::Opaque
|
|
216
|
+
if type.fixed?
|
|
217
|
+
"Opaque, #{type.size}"
|
|
218
|
+
else
|
|
219
|
+
type.size ? "VariableOpaque, #{type.size}" : "VariableOpaque"
|
|
220
|
+
end
|
|
221
|
+
when AST::Typespecs::Quadruple
|
|
222
|
+
raise "no quadruple support in elixir"
|
|
223
|
+
when AST::Typespecs::String
|
|
224
|
+
"XDR.Type.String, #{type.size}"
|
|
225
|
+
when AST::Typespecs::UnsignedHyper
|
|
226
|
+
"UnsignedHyperInt"
|
|
227
|
+
when AST::Typespecs::UnsignedInt
|
|
228
|
+
"UnsignedInt"
|
|
229
|
+
when AST::Typespecs::Simple
|
|
230
|
+
"\"#{name type}\""
|
|
231
|
+
when AST::Definitions::Base
|
|
232
|
+
"\"#{name type}\""
|
|
233
|
+
when AST::Concerns::NestedDefinition
|
|
234
|
+
"\"#{name type}\""
|
|
235
|
+
else
|
|
236
|
+
raise "Unknown reference type: #{type.class.name}, #{type.class.ancestors}"
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
base_type = base_ref === "\"#{name type}\"" ? base_ref : "buid_type(base_ref)"
|
|
240
|
+
|
|
241
|
+
case type.sub_type
|
|
242
|
+
when :simple
|
|
243
|
+
base_ref
|
|
244
|
+
when :optional
|
|
245
|
+
"Optional, #{base_type}"
|
|
246
|
+
when :array
|
|
247
|
+
is_named, size = type.array_size
|
|
248
|
+
size = is_named ? "\"#{size}\"" : size
|
|
249
|
+
"Array, length: #{size}, type: #{base_type}"
|
|
250
|
+
when :var_array
|
|
251
|
+
is_named, size = type.array_size
|
|
252
|
+
size = is_named ? "\"#{size}\"" : (size || MAX_INT)
|
|
253
|
+
"VariableArray, max_length: #{size}, type: #{base_type}"
|
|
254
|
+
else
|
|
255
|
+
raise "Unknown sub_type: #{type.sub_type}"
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
module Xdrgen
|
|
2
|
+
module Generators
|
|
3
|
+
|
|
4
|
+
class Go < Xdrgen::Generators::Base
|
|
5
|
+
|
|
6
|
+
def generate
|
|
7
|
+
@already_rendered = []
|
|
8
|
+
path = "#{@namespace}_generated.go"
|
|
9
|
+
out = @output.open(path)
|
|
10
|
+
|
|
11
|
+
render_top_matter out
|
|
12
|
+
render_definitions(out, @top)
|
|
13
|
+
render_bottom_matter out
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def render_typedef(out, typedef)
|
|
19
|
+
out.puts "type #{name typedef} #{reference typedef.declaration.type}"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# write sizing restrictions
|
|
23
|
+
case typedef.declaration
|
|
24
|
+
when Xdrgen::AST::Declarations::String
|
|
25
|
+
render_maxsize_method out, typedef, typedef.declaration.resolved_size
|
|
26
|
+
when Xdrgen::AST::Declarations::Opaque
|
|
27
|
+
render_maxsize_method out, typedef, typedef.declaration.resolved_size
|
|
28
|
+
when Xdrgen::AST::Declarations::Array
|
|
29
|
+
unless typedef.declaration.fixed?
|
|
30
|
+
render_maxsize_method out, typedef, typedef.declaration.resolved_size
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
return unless typedef.sub_type == :simple
|
|
35
|
+
|
|
36
|
+
resolved = typedef.resolved_type
|
|
37
|
+
|
|
38
|
+
case resolved
|
|
39
|
+
when AST::Definitions::Enum
|
|
40
|
+
render_enum_typedef out, typedef, resolved
|
|
41
|
+
when AST::Definitions::Union
|
|
42
|
+
render_union_typedef out, typedef, resolved
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
out.break
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def render_maxsize_method(out, typedef, size)
|
|
49
|
+
return if size.blank?
|
|
50
|
+
|
|
51
|
+
out.puts <<-EOS.strip_heredoc
|
|
52
|
+
// XDRMaxSize implements the Sized interface for #{name typedef}
|
|
53
|
+
func (e #{name typedef}) XDRMaxSize() int {
|
|
54
|
+
return #{size}
|
|
55
|
+
}
|
|
56
|
+
EOS
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def render_enum_typedef(out, typedef, enum)
|
|
60
|
+
out.puts <<-EOS.strip_heredoc
|
|
61
|
+
// ValidEnum validates a proposed value for this enum. Implements
|
|
62
|
+
// the Enum interface for #{name typedef}
|
|
63
|
+
func (e #{name typedef}) ValidEnum(v int32) bool {
|
|
64
|
+
return #{name enum}(e).ValidEnum(v)
|
|
65
|
+
}
|
|
66
|
+
EOS
|
|
67
|
+
|
|
68
|
+
out.puts <<-EOS.strip_heredoc
|
|
69
|
+
// String returns the name of `e`
|
|
70
|
+
func (e #{name typedef}) String() string {
|
|
71
|
+
return #{name enum}(e).String()
|
|
72
|
+
}
|
|
73
|
+
EOS
|
|
74
|
+
|
|
75
|
+
out.break
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def render_union_typedef(out, typedef, union)
|
|
79
|
+
out.puts <<-EOS.strip_heredoc
|
|
80
|
+
// SwitchFieldName returns the field name in which this union's
|
|
81
|
+
// discriminant is stored
|
|
82
|
+
func (u #{name typedef}) SwitchFieldName() string {
|
|
83
|
+
return #{name union}(u).SwitchFieldName()
|
|
84
|
+
}
|
|
85
|
+
EOS
|
|
86
|
+
|
|
87
|
+
out.break
|
|
88
|
+
|
|
89
|
+
out.puts <<-EOS.strip_heredoc
|
|
90
|
+
// ArmForSwitch returns which field name should be used for storing
|
|
91
|
+
// the value for an instance of #{name union}
|
|
92
|
+
func (u #{name typedef}) ArmForSwitch(sw int32) (string, bool) {
|
|
93
|
+
return #{name union}(u).ArmForSwitch(sw)
|
|
94
|
+
}
|
|
95
|
+
EOS
|
|
96
|
+
|
|
97
|
+
out.break
|
|
98
|
+
|
|
99
|
+
constructor_name = "New#{name typedef}"
|
|
100
|
+
discriminant_arg = private_name union.discriminant
|
|
101
|
+
discriminant_type = reference union.discriminant.type
|
|
102
|
+
|
|
103
|
+
out.puts <<-EOS.strip_heredoc
|
|
104
|
+
// #{constructor_name} creates a new #{name typedef}.
|
|
105
|
+
func #{constructor_name}(#{discriminant_arg} #{discriminant_type}, value interface{}) (result #{reference typedef}, err error) {
|
|
106
|
+
u, err := New#{name union}(#{discriminant_arg}, value)
|
|
107
|
+
result = #{name typedef}(u)
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
EOS
|
|
111
|
+
|
|
112
|
+
out.break
|
|
113
|
+
|
|
114
|
+
# Add accessors for of form val, ok := union.GetArmName()
|
|
115
|
+
# and val := union.MustArmName()
|
|
116
|
+
union.arms.each do |arm|
|
|
117
|
+
next if arm.void?
|
|
118
|
+
out.puts <<-EOS.strip_heredoc
|
|
119
|
+
// Must#{name arm} retrieves the #{name arm} value from the union,
|
|
120
|
+
// panicing if the value is not set.
|
|
121
|
+
func (u #{name typedef}) Must#{name arm}() #{reference arm.type} {
|
|
122
|
+
return #{name union}(u).Must#{name arm}()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Get#{name arm} retrieves the #{name arm} value from the union,
|
|
126
|
+
// returning ok if the union's switch indicated the value is valid.
|
|
127
|
+
func (u #{name typedef}) Get#{name arm}() (result #{reference arm.type}, ok bool) {
|
|
128
|
+
return #{name union}(u).Get#{name arm}()
|
|
129
|
+
}
|
|
130
|
+
EOS
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def render_const(out, const)
|
|
136
|
+
out.puts "const #{name const} = #{const.value}"
|
|
137
|
+
out.break
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def render_definitions(out, node)
|
|
141
|
+
node.definitions.each{|n| render_definition out, n }
|
|
142
|
+
node.namespaces.each{|n| render_definitions out, n }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def render_nested_definitions(out, defn)
|
|
146
|
+
return unless defn.respond_to? :nested_definitions
|
|
147
|
+
defn.nested_definitions.each{|ndefn| render_definition out, ndefn}
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def render_definition(out, defn)
|
|
151
|
+
if @already_rendered.include? name(defn)
|
|
152
|
+
|
|
153
|
+
unless defn.is_a?(AST::Definitions::Namespace)
|
|
154
|
+
$stderr.puts "warn: #{name(defn)} is defined twice. skipping"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
return
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
render_nested_definitions(out, defn)
|
|
161
|
+
render_source_comment(out, defn)
|
|
162
|
+
|
|
163
|
+
@already_rendered << name(defn)
|
|
164
|
+
|
|
165
|
+
case defn
|
|
166
|
+
when AST::Definitions::Struct ;
|
|
167
|
+
render_struct out, defn
|
|
168
|
+
render_binary_interface out, name(defn)
|
|
169
|
+
when AST::Definitions::Enum ;
|
|
170
|
+
render_enum out, defn
|
|
171
|
+
render_binary_interface out, name(defn)
|
|
172
|
+
when AST::Definitions::Union ;
|
|
173
|
+
render_union out, defn
|
|
174
|
+
render_binary_interface out, name(defn)
|
|
175
|
+
when AST::Definitions::Typedef ;
|
|
176
|
+
render_typedef out, defn
|
|
177
|
+
render_binary_interface out, name(defn)
|
|
178
|
+
when AST::Definitions::Const ;
|
|
179
|
+
render_const out, defn
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def render_source_comment(out, defn)
|
|
184
|
+
return if defn.is_a?(AST::Definitions::Namespace)
|
|
185
|
+
|
|
186
|
+
out.puts <<-EOS.strip_heredoc
|
|
187
|
+
// #{name defn} is an XDR #{defn.class.name.demodulize} defines as:
|
|
188
|
+
//
|
|
189
|
+
EOS
|
|
190
|
+
|
|
191
|
+
out.puts "// " + defn.text_value.split("\n").join("\n// ")
|
|
192
|
+
|
|
193
|
+
out.puts <<-EOS.strip_heredoc
|
|
194
|
+
//
|
|
195
|
+
EOS
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def render_struct(out, struct)
|
|
199
|
+
out.puts "type #{name struct} struct {"
|
|
200
|
+
out.indent do
|
|
201
|
+
|
|
202
|
+
struct.members.each do |m|
|
|
203
|
+
out.puts "#{name m} #{reference(m.declaration.type)} #{field_tag struct, m}"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
end
|
|
207
|
+
out.puts "}"
|
|
208
|
+
out.break
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def render_enum(out, enum)
|
|
212
|
+
# render the "enum"
|
|
213
|
+
out.puts "type #{name enum} int32"
|
|
214
|
+
out.puts "const ("
|
|
215
|
+
out.indent do
|
|
216
|
+
first_member = enum.members.first
|
|
217
|
+
out.puts "#{name enum}#{name first_member} #{name enum} = #{first_member.value}"
|
|
218
|
+
|
|
219
|
+
rest_members = enum.members.drop(1)
|
|
220
|
+
rest_members.each do |m|
|
|
221
|
+
out.puts "#{name enum}#{name m} #{name enum} = #{m.value}"
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
out.puts ")"
|
|
225
|
+
|
|
226
|
+
# render the map used by xdr to decide valid values
|
|
227
|
+
out.puts "var #{private_name enum}Map = map[int32]string{"
|
|
228
|
+
out.indent do
|
|
229
|
+
|
|
230
|
+
enum.members.each do |m|
|
|
231
|
+
out.puts "#{m.value}: \"#{name enum}#{name m}\","
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
end
|
|
235
|
+
out.puts "}"
|
|
236
|
+
|
|
237
|
+
out.break
|
|
238
|
+
|
|
239
|
+
out.puts <<-EOS.strip_heredoc
|
|
240
|
+
// ValidEnum validates a proposed value for this enum. Implements
|
|
241
|
+
// the Enum interface for #{name enum}
|
|
242
|
+
func (e #{name enum}) ValidEnum(v int32) bool {
|
|
243
|
+
_, ok := #{private_name enum}Map[v]
|
|
244
|
+
return ok
|
|
245
|
+
}
|
|
246
|
+
EOS
|
|
247
|
+
|
|
248
|
+
out.puts <<-EOS.strip_heredoc
|
|
249
|
+
// String returns the name of `e`
|
|
250
|
+
func (e #{name enum}) String() string {
|
|
251
|
+
name, _ := #{private_name enum}Map[int32(e)]
|
|
252
|
+
return name
|
|
253
|
+
}
|
|
254
|
+
EOS
|
|
255
|
+
|
|
256
|
+
out.break
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def render_union(out, union)
|
|
260
|
+
|
|
261
|
+
out.puts "type #{name union} struct{"
|
|
262
|
+
out.indent do
|
|
263
|
+
out.puts "#{name union.discriminant} #{reference union.discriminant.type}"
|
|
264
|
+
|
|
265
|
+
union.arms.each do |arm|
|
|
266
|
+
next if arm.void?
|
|
267
|
+
out.puts "#{name arm} *#{reference arm.type} #{field_tag union, arm}"
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
out.puts "}"
|
|
271
|
+
out.break
|
|
272
|
+
|
|
273
|
+
out.puts <<-EOS.strip_heredoc
|
|
274
|
+
// SwitchFieldName returns the field name in which this union's
|
|
275
|
+
// discriminant is stored
|
|
276
|
+
func (u #{name union}) SwitchFieldName() string {
|
|
277
|
+
return "#{name union.discriminant}"
|
|
278
|
+
}
|
|
279
|
+
EOS
|
|
280
|
+
|
|
281
|
+
out.break
|
|
282
|
+
|
|
283
|
+
out.puts <<-EOS.strip_heredoc
|
|
284
|
+
// ArmForSwitch returns which field name should be used for storing
|
|
285
|
+
// the value for an instance of #{name union}
|
|
286
|
+
func (u #{name union}) ArmForSwitch(sw int32) (string, bool) {
|
|
287
|
+
EOS
|
|
288
|
+
|
|
289
|
+
switch_for(out, union, "sw") do |arm, kase|
|
|
290
|
+
"return \"#{name arm unless arm.void?}\", true"
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# when the default arm is not present, we must render the failure case
|
|
294
|
+
unless union.default_arm.present?
|
|
295
|
+
out.puts 'return "-", false'
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
out.puts "}"
|
|
299
|
+
out.break
|
|
300
|
+
|
|
301
|
+
# Add constructor of the form u := NewUnion(switch,val)
|
|
302
|
+
render_union_constructor(out, union)
|
|
303
|
+
|
|
304
|
+
# Add accessors for of form val, ok := union.GetArmName()
|
|
305
|
+
# and val := union.MustArmName()
|
|
306
|
+
union.arms.each do |arm|
|
|
307
|
+
next if arm.void?
|
|
308
|
+
out.puts access_arm(arm)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
out.break
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def render_binary_interface(out, name)
|
|
315
|
+
out.puts "// MarshalBinary implements encoding.BinaryMarshaler."
|
|
316
|
+
out.puts "func (s #{name}) MarshalBinary() ([]byte, error) {"
|
|
317
|
+
out.puts " b := new(bytes.Buffer)"
|
|
318
|
+
out.puts " _, err := Marshal(b, s)"
|
|
319
|
+
out.puts " return b.Bytes(), err"
|
|
320
|
+
out.puts "}"
|
|
321
|
+
out.break
|
|
322
|
+
out.puts "// UnmarshalBinary implements encoding.BinaryUnmarshaler."
|
|
323
|
+
out.puts "func (s *#{name}) UnmarshalBinary(inp []byte) error {"
|
|
324
|
+
out.puts " _, err := Unmarshal(bytes.NewReader(inp), s)"
|
|
325
|
+
out.puts " return err"
|
|
326
|
+
out.puts "}"
|
|
327
|
+
out.break
|
|
328
|
+
out.puts "var ("
|
|
329
|
+
out.puts " _ encoding.BinaryMarshaler = (*#{name})(nil)"
|
|
330
|
+
out.puts " _ encoding.BinaryUnmarshaler = (*#{name})(nil)"
|
|
331
|
+
out.puts ")"
|
|
332
|
+
out.break
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def render_top_matter(out)
|
|
336
|
+
out.puts <<-EOS.strip_heredoc
|
|
337
|
+
// Package #{@namespace || "main"} is generated from:
|
|
338
|
+
//
|
|
339
|
+
// #{@output.source_paths.join("\n// ")}
|
|
340
|
+
//
|
|
341
|
+
// DO NOT EDIT or your changes may be overwritten
|
|
342
|
+
package #{@namespace || "main"}
|
|
343
|
+
|
|
344
|
+
import (
|
|
345
|
+
"bytes"
|
|
346
|
+
"encoding"
|
|
347
|
+
"io"
|
|
348
|
+
"fmt"
|
|
349
|
+
|
|
350
|
+
"github.com/stellar/go-xdr/xdr3"
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
// Unmarshal reads an xdr element from `r` into `v`.
|
|
354
|
+
func Unmarshal(r io.Reader, v interface{}) (int, error) {
|
|
355
|
+
// delegate to xdr package's Unmarshal
|
|
356
|
+
return xdr.Unmarshal(r, v)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Marshal writes an xdr element `v` into `w`.
|
|
360
|
+
func Marshal(w io.Writer, v interface{}) (int, error) {
|
|
361
|
+
// delegate to xdr package's Marshal
|
|
362
|
+
return xdr.Marshal(w, v)
|
|
363
|
+
}
|
|
364
|
+
EOS
|
|
365
|
+
out.break
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def render_bottom_matter(out)
|
|
369
|
+
out.puts <<-EOS
|
|
370
|
+
var fmtTest = fmt.Sprint("this is a dummy usage of fmt")
|
|
371
|
+
|
|
372
|
+
EOS
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
private
|
|
376
|
+
|
|
377
|
+
def reference(type)
|
|
378
|
+
baseReference = case type
|
|
379
|
+
when AST::Typespecs::Bool
|
|
380
|
+
"bool"
|
|
381
|
+
when AST::Typespecs::Double
|
|
382
|
+
"float64"
|
|
383
|
+
when AST::Typespecs::Float
|
|
384
|
+
"float32"
|
|
385
|
+
when AST::Typespecs::Hyper
|
|
386
|
+
"int64"
|
|
387
|
+
when AST::Typespecs::Int
|
|
388
|
+
"int32"
|
|
389
|
+
when AST::Typespecs::Opaque
|
|
390
|
+
if type.fixed?
|
|
391
|
+
"[#{type.size}]byte"
|
|
392
|
+
else
|
|
393
|
+
"[]byte"
|
|
394
|
+
end
|
|
395
|
+
when AST::Typespecs::Quadruple
|
|
396
|
+
raise "no quadruple support for go"
|
|
397
|
+
when AST::Typespecs::String
|
|
398
|
+
"string"
|
|
399
|
+
when AST::Typespecs::UnsignedHyper
|
|
400
|
+
"uint64"
|
|
401
|
+
when AST::Typespecs::UnsignedInt
|
|
402
|
+
"uint32"
|
|
403
|
+
when AST::Typespecs::Simple
|
|
404
|
+
name type
|
|
405
|
+
when AST::Definitions::Base
|
|
406
|
+
name type
|
|
407
|
+
when AST::Concerns::NestedDefinition
|
|
408
|
+
name type
|
|
409
|
+
else
|
|
410
|
+
raise "Unknown reference type: #{type.class.name}, #{type.class.ancestors}"
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
case type.sub_type
|
|
414
|
+
when :simple
|
|
415
|
+
baseReference
|
|
416
|
+
when :optional
|
|
417
|
+
"*#{baseReference}"
|
|
418
|
+
when :array
|
|
419
|
+
is_named, size = type.array_size
|
|
420
|
+
|
|
421
|
+
# if named, lookup the const definition
|
|
422
|
+
if is_named
|
|
423
|
+
size = name @top.find_definition(size)
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
"[#{size}]#{baseReference}"
|
|
427
|
+
when :var_array
|
|
428
|
+
"[#{size}]#{baseReference}"
|
|
429
|
+
else
|
|
430
|
+
raise "Unknown sub_type: #{type.sub_type}"
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def name(named)
|
|
436
|
+
parent = name named.parent_defn if named.is_a?(AST::Concerns::NestedDefinition)
|
|
437
|
+
|
|
438
|
+
base = if named.respond_to?(:name)
|
|
439
|
+
named.name
|
|
440
|
+
else
|
|
441
|
+
named.text_value
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
"#{parent}#{base.underscore.camelize}"
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def private_name(named)
|
|
448
|
+
escape_name named.name.underscore.camelize(:lower)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def escape_name(name)
|
|
452
|
+
case name
|
|
453
|
+
when "type" ; "aType"
|
|
454
|
+
when "func" ; "aFunc"
|
|
455
|
+
else ; name
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def render_union_constructor(out, union)
|
|
460
|
+
constructor_name = "New#{name union}"
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
discriminant_arg = private_name union.discriminant
|
|
464
|
+
discriminant_type = reference union.discriminant.type
|
|
465
|
+
|
|
466
|
+
out.puts <<-EOS.strip_heredoc
|
|
467
|
+
// #{constructor_name} creates a new #{name union}.
|
|
468
|
+
func #{constructor_name}(#{discriminant_arg} #{discriminant_type}, value interface{}) (result #{reference union}, err error) {
|
|
469
|
+
result.#{name union.discriminant} = #{discriminant_arg}
|
|
470
|
+
EOS
|
|
471
|
+
|
|
472
|
+
switch_for(out, union, discriminant_arg) do |arm, kase|
|
|
473
|
+
if arm.void?
|
|
474
|
+
"// void"
|
|
475
|
+
else
|
|
476
|
+
<<-EOS
|
|
477
|
+
tv, ok := value.(#{reference arm.type})
|
|
478
|
+
if !ok {
|
|
479
|
+
err = fmt.Errorf("invalid value, must be #{reference arm.type}")
|
|
480
|
+
return
|
|
481
|
+
}
|
|
482
|
+
result.#{name arm} = &tv
|
|
483
|
+
EOS
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
out.puts <<-EOS.strip_heredoc
|
|
488
|
+
return
|
|
489
|
+
}
|
|
490
|
+
EOS
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
def access_arm(arm)
|
|
494
|
+
|
|
495
|
+
<<-EOS.strip_heredoc
|
|
496
|
+
// Must#{name arm} retrieves the #{name arm} value from the union,
|
|
497
|
+
// panicing if the value is not set.
|
|
498
|
+
func (u #{name arm.union}) Must#{name arm}() #{reference arm.type} {
|
|
499
|
+
val, ok := u.Get#{name arm}()
|
|
500
|
+
|
|
501
|
+
if !ok {
|
|
502
|
+
panic("arm #{name arm} is not set")
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return val
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Get#{name arm} retrieves the #{name arm} value from the union,
|
|
509
|
+
// returning ok if the union's switch indicated the value is valid.
|
|
510
|
+
func (u #{name arm.union}) Get#{name arm}() (result #{reference arm.type}, ok bool) {
|
|
511
|
+
armName, _ := u.ArmForSwitch(int32(u.#{name arm.union.discriminant}))
|
|
512
|
+
|
|
513
|
+
if armName == "#{name arm}" {
|
|
514
|
+
result = *u.#{name arm}
|
|
515
|
+
ok = true
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return
|
|
519
|
+
}
|
|
520
|
+
EOS
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def size(size_s)
|
|
524
|
+
result = size_s
|
|
525
|
+
result = "MaxXdrElements" if result.blank?
|
|
526
|
+
result
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
def switch_for(out, union, ident)
|
|
530
|
+
out.puts "switch #{reference union.discriminant.type}(#{ident}) {"
|
|
531
|
+
|
|
532
|
+
union.normal_arms.each do |arm|
|
|
533
|
+
arm.cases.each do |c|
|
|
534
|
+
|
|
535
|
+
value = if c.value.is_a?(AST::Identifier)
|
|
536
|
+
member = union.resolved_case(c)
|
|
537
|
+
if union.discriminant_type.nil? then
|
|
538
|
+
"int32(#{name member.enum}#{name member})"
|
|
539
|
+
else
|
|
540
|
+
"#{name union.discriminant_type}#{name member}"
|
|
541
|
+
end
|
|
542
|
+
else
|
|
543
|
+
c.value.text_value
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
out.puts " case #{value}:"
|
|
547
|
+
out.puts " #{yield arm, c}"
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
if union.default_arm.present?
|
|
552
|
+
arm = union.default_arm
|
|
553
|
+
out.puts " default:"
|
|
554
|
+
out.puts " #{yield arm, :default}"
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
out.puts "}"
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def field_tag(struct, field)
|
|
561
|
+
size = nil
|
|
562
|
+
|
|
563
|
+
case field.declaration
|
|
564
|
+
when Xdrgen::AST::Declarations::Opaque
|
|
565
|
+
size = field.declaration.resolved_size
|
|
566
|
+
when Xdrgen::AST::Declarations::String
|
|
567
|
+
size = field.declaration.resolved_size
|
|
568
|
+
when Xdrgen::AST::Declarations::Array
|
|
569
|
+
size = field.declaration.resolved_size unless field.declaration.fixed?
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
return "`xdrmaxsize:\"#{size}\"`" if size.present?
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
end
|
|
578
|
+
end
|