class Xdrgen::Generators::Go
Public Instance Methods
generate()
click to toggle source
# File lib/xdrgen/generators/go.rb, line 6 def generate @already_rendered = [] path = "#{@namespace}_generated.go" out = @output.open(path) render_top_matter out render_definitions(out, @top) render_bottom_matter out end
Private Instance Methods
access_arm(arm)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 493 def access_arm(arm) <<-EOS.strip_heredoc // Must#{name arm} retrieves the #{name arm} value from the union, // panicing if the value is not set. func (u #{name arm.union}) Must#{name arm}() #{reference arm.type} { val, ok := u.Get#{name arm}() if !ok { panic("arm #{name arm} is not set") } return val } // Get#{name arm} retrieves the #{name arm} value from the union, // returning ok if the union's switch indicated the value is valid. func (u #{name arm.union}) Get#{name arm}() (result #{reference arm.type}, ok bool) { armName, _ := u.ArmForSwitch(int32(u.#{name arm.union.discriminant})) if armName == "#{name arm}" { result = *u.#{name arm} ok = true } return } EOS end
escape_name(name)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 451 def escape_name(name) case name when "type" ; "aType" when "func" ; "aFunc" else ; name end end
field_tag(struct, field)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 560 def field_tag(struct, field) size = nil case field.declaration when Xdrgen::AST::Declarations::Opaque size = field.declaration.resolved_size when Xdrgen::AST::Declarations::String size = field.declaration.resolved_size when Xdrgen::AST::Declarations::Array size = field.declaration.resolved_size unless field.declaration.fixed? end return "`xdrmaxsize:\"#{size}\"`" if size.present? end
name(named)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 435 def name(named) parent = name named.parent_defn if named.is_a?(AST::Concerns::NestedDefinition) base = if named.respond_to?(:name) named.name else named.text_value end "#{parent}#{base.underscore.camelize}" end
private_name(named)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 447 def private_name(named) escape_name named.name.underscore.camelize(:lower) end
reference(type)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 377 def reference(type) baseReference = case type when AST::Typespecs::Bool "bool" when AST::Typespecs::Double "float64" when AST::Typespecs::Float "float32" when AST::Typespecs::Hyper "int64" when AST::Typespecs::Int "int32" when AST::Typespecs::Opaque if type.fixed? "[#{type.size}]byte" else "[]byte" end when AST::Typespecs::Quadruple raise "no quadruple support for go" when AST::Typespecs::String "string" when AST::Typespecs::UnsignedHyper "uint64" when AST::Typespecs::UnsignedInt "uint32" when AST::Typespecs::Simple name type when AST::Definitions::Base name type when AST::Concerns::NestedDefinition name type else raise "Unknown reference type: #{type.class.name}, #{type.class.ancestors}" end case type.sub_type when :simple baseReference when :optional "*#{baseReference}" when :array is_named, size = type.array_size # if named, lookup the const definition if is_named size = name @top.find_definition(size) end "[#{size}]#{baseReference}" when :var_array "[#{size}]#{baseReference}" else raise "Unknown sub_type: #{type.sub_type}" end end
render_binary_interface(out, name)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 314 def render_binary_interface(out, name) out.puts "// MarshalBinary implements encoding.BinaryMarshaler." out.puts "func (s #{name}) MarshalBinary() ([]byte, error) {" out.puts " b := new(bytes.Buffer)" out.puts " _, err := Marshal(b, s)" out.puts " return b.Bytes(), err" out.puts "}" out.break out.puts "// UnmarshalBinary implements encoding.BinaryUnmarshaler." out.puts "func (s *#{name}) UnmarshalBinary(inp []byte) error {" out.puts " _, err := Unmarshal(bytes.NewReader(inp), s)" out.puts " return err" out.puts "}" out.break out.puts "var (" out.puts " _ encoding.BinaryMarshaler = (*#{name})(nil)" out.puts " _ encoding.BinaryUnmarshaler = (*#{name})(nil)" out.puts ")" out.break end
render_bottom_matter(out)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 368 def render_bottom_matter(out) out.puts <<-EOS var fmtTest = fmt.Sprint("this is a dummy usage of fmt") EOS end
render_const(out, const)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 135 def render_const(out, const) out.puts "const #{name const} = #{const.value}" out.break end
render_definition(out, defn)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 150 def render_definition(out, defn) if @already_rendered.include? name(defn) unless defn.is_a?(AST::Definitions::Namespace) $stderr.puts "warn: #{name(defn)} is defined twice. skipping" end return end render_nested_definitions(out, defn) render_source_comment(out, defn) @already_rendered << name(defn) case defn when AST::Definitions::Struct ; render_struct out, defn render_binary_interface out, name(defn) when AST::Definitions::Enum ; render_enum out, defn render_binary_interface out, name(defn) when AST::Definitions::Union ; render_union out, defn render_binary_interface out, name(defn) when AST::Definitions::Typedef ; render_typedef out, defn render_binary_interface out, name(defn) when AST::Definitions::Const ; render_const out, defn end end
render_definitions(out, node)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 140 def render_definitions(out, node) node.definitions.each{|n| render_definition out, n } node.namespaces.each{|n| render_definitions out, n } end
render_enum(out, enum)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 211 def render_enum(out, enum) # render the "enum" out.puts "type #{name enum} int32" out.puts "const (" out.indent do first_member = enum.members.first out.puts "#{name enum}#{name first_member} #{name enum} = #{first_member.value}" rest_members = enum.members.drop(1) rest_members.each do |m| out.puts "#{name enum}#{name m} #{name enum} = #{m.value}" end end out.puts ")" # render the map used by xdr to decide valid values out.puts "var #{private_name enum}Map = map[int32]string{" out.indent do enum.members.each do |m| out.puts "#{m.value}: \"#{name enum}#{name m}\"," end end out.puts "}" out.break out.puts <<-EOS.strip_heredoc // ValidEnum validates a proposed value for this enum. Implements // the Enum interface for #{name enum} func (e #{name enum}) ValidEnum(v int32) bool { _, ok := #{private_name enum}Map[v] return ok } EOS out.puts <<-EOS.strip_heredoc // String returns the name of `e` func (e #{name enum}) String() string { name, _ := #{private_name enum}Map[int32(e)] return name } EOS out.break end
render_enum_typedef(out, typedef, enum)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 59 def render_enum_typedef(out, typedef, enum) out.puts <<-EOS.strip_heredoc // ValidEnum validates a proposed value for this enum. Implements // the Enum interface for #{name typedef} func (e #{name typedef}) ValidEnum(v int32) bool { return #{name enum}(e).ValidEnum(v) } EOS out.puts <<-EOS.strip_heredoc // String returns the name of `e` func (e #{name typedef}) String() string { return #{name enum}(e).String() } EOS out.break end
render_maxsize_method(out, typedef, size)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 48 def render_maxsize_method(out, typedef, size) return if size.blank? out.puts <<-EOS.strip_heredoc // XDRMaxSize implements the Sized interface for #{name typedef} func (e #{name typedef}) XDRMaxSize() int { return #{size} } EOS end
render_nested_definitions(out, defn)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 145 def render_nested_definitions(out, defn) return unless defn.respond_to? :nested_definitions defn.nested_definitions.each{|ndefn| render_definition out, ndefn} end
render_source_comment(out, defn)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 183 def render_source_comment(out, defn) return if defn.is_a?(AST::Definitions::Namespace) out.puts <<-EOS.strip_heredoc // #{name defn} is an XDR #{defn.class.name.demodulize} defines as: // EOS out.puts "// " + defn.text_value.split("\n").join("\n// ") out.puts <<-EOS.strip_heredoc // EOS end
render_struct(out, struct)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 198 def render_struct(out, struct) out.puts "type #{name struct} struct {" out.indent do struct.members.each do |m| out.puts "#{name m} #{reference(m.declaration.type)} #{field_tag struct, m}" end end out.puts "}" out.break end
render_top_matter(out)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 335 def render_top_matter(out) out.puts <<-EOS.strip_heredoc // Package #{@namespace || "main"} is generated from: // // #{@output.source_paths.join("\n// ")} // // DO NOT EDIT or your changes may be overwritten package #{@namespace || "main"} import ( "bytes" "encoding" "io" "fmt" "github.com/stellar/go-xdr/xdr3" ) // Unmarshal reads an xdr element from `r` into `v`. func Unmarshal(r io.Reader, v interface{}) (int, error) { // delegate to xdr package's Unmarshal return xdr.Unmarshal(r, v) } // Marshal writes an xdr element `v` into `w`. func Marshal(w io.Writer, v interface{}) (int, error) { // delegate to xdr package's Marshal return xdr.Marshal(w, v) } EOS out.break end
render_typedef(out, typedef)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 18 def render_typedef(out, typedef) out.puts "type #{name typedef} #{reference typedef.declaration.type}" # write sizing restrictions case typedef.declaration when Xdrgen::AST::Declarations::String render_maxsize_method out, typedef, typedef.declaration.resolved_size when Xdrgen::AST::Declarations::Opaque render_maxsize_method out, typedef, typedef.declaration.resolved_size when Xdrgen::AST::Declarations::Array unless typedef.declaration.fixed? render_maxsize_method out, typedef, typedef.declaration.resolved_size end end return unless typedef.sub_type == :simple resolved = typedef.resolved_type case resolved when AST::Definitions::Enum render_enum_typedef out, typedef, resolved when AST::Definitions::Union render_union_typedef out, typedef, resolved end out.break end
render_union(out, union)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 259 def render_union(out, union) out.puts "type #{name union} struct{" out.indent do out.puts "#{name union.discriminant} #{reference union.discriminant.type}" union.arms.each do |arm| next if arm.void? out.puts "#{name arm} *#{reference arm.type} #{field_tag union, arm}" end end out.puts "}" out.break out.puts <<-EOS.strip_heredoc // SwitchFieldName returns the field name in which this union's // discriminant is stored func (u #{name union}) SwitchFieldName() string { return "#{name union.discriminant}" } EOS out.break out.puts <<-EOS.strip_heredoc // ArmForSwitch returns which field name should be used for storing // the value for an instance of #{name union} func (u #{name union}) ArmForSwitch(sw int32) (string, bool) { EOS switch_for(out, union, "sw") do |arm, kase| "return \"#{name arm unless arm.void?}\", true" end # when the default arm is not present, we must render the failure case unless union.default_arm.present? out.puts 'return "-", false' end out.puts "}" out.break # Add constructor of the form u := NewUnion(switch,val) render_union_constructor(out, union) # Add accessors for of form val, ok := union.GetArmName() # and val := union.MustArmName() union.arms.each do |arm| next if arm.void? out.puts access_arm(arm) end out.break end
render_union_constructor(out, union)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 459 def render_union_constructor(out, union) constructor_name = "New#{name union}" discriminant_arg = private_name union.discriminant discriminant_type = reference union.discriminant.type out.puts <<-EOS.strip_heredoc // #{constructor_name} creates a new #{name union}. func #{constructor_name}(#{discriminant_arg} #{discriminant_type}, value interface{}) (result #{reference union}, err error) { result.#{name union.discriminant} = #{discriminant_arg} EOS switch_for(out, union, discriminant_arg) do |arm, kase| if arm.void? "// void" else <<-EOS tv, ok := value.(#{reference arm.type}) if !ok { err = fmt.Errorf("invalid value, must be #{reference arm.type}") return } result.#{name arm} = &tv EOS end end out.puts <<-EOS.strip_heredoc return } EOS end
render_union_typedef(out, typedef, union)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 78 def render_union_typedef(out, typedef, union) out.puts <<-EOS.strip_heredoc // SwitchFieldName returns the field name in which this union's // discriminant is stored func (u #{name typedef}) SwitchFieldName() string { return #{name union}(u).SwitchFieldName() } EOS out.break out.puts <<-EOS.strip_heredoc // ArmForSwitch returns which field name should be used for storing // the value for an instance of #{name union} func (u #{name typedef}) ArmForSwitch(sw int32) (string, bool) { return #{name union}(u).ArmForSwitch(sw) } EOS out.break constructor_name = "New#{name typedef}" discriminant_arg = private_name union.discriminant discriminant_type = reference union.discriminant.type out.puts <<-EOS.strip_heredoc // #{constructor_name} creates a new #{name typedef}. func #{constructor_name}(#{discriminant_arg} #{discriminant_type}, value interface{}) (result #{reference typedef}, err error) { u, err := New#{name union}(#{discriminant_arg}, value) result = #{name typedef}(u) return } EOS out.break # Add accessors for of form val, ok := union.GetArmName() # and val := union.MustArmName() union.arms.each do |arm| next if arm.void? out.puts <<-EOS.strip_heredoc // Must#{name arm} retrieves the #{name arm} value from the union, // panicing if the value is not set. func (u #{name typedef}) Must#{name arm}() #{reference arm.type} { return #{name union}(u).Must#{name arm}() } // Get#{name arm} retrieves the #{name arm} value from the union, // returning ok if the union's switch indicated the value is valid. func (u #{name typedef}) Get#{name arm}() (result #{reference arm.type}, ok bool) { return #{name union}(u).Get#{name arm}() } EOS end end
size(size_s)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 523 def size(size_s) result = size_s result = "MaxXdrElements" if result.blank? result end
switch_for(out, union, ident)
click to toggle source
# File lib/xdrgen/generators/go.rb, line 529 def switch_for(out, union, ident) out.puts "switch #{reference union.discriminant.type}(#{ident}) {" union.normal_arms.each do |arm| arm.cases.each do |c| value = if c.value.is_a?(AST::Identifier) member = union.resolved_case(c) if union.discriminant_type.nil? then "int32(#{name member.enum}#{name member})" else "#{name union.discriminant_type}#{name member}" end else c.value.text_value end out.puts " case #{value}:" out.puts " #{yield arm, c}" end end if union.default_arm.present? arm = union.default_arm out.puts " default:" out.puts " #{yield arm, :default}" end out.puts "}" end