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