201 行
6.0 KiB
Go
201 行
6.0 KiB
Go
package exp
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/dave/jennifer/jen"
|
|
)
|
|
|
|
// TODO: Kind serialize/deserialize use Method/Function.
|
|
|
|
const (
|
|
// Method names for generated code
|
|
getMethod = "Get"
|
|
setMethod = "Set"
|
|
hasMethod = "Has"
|
|
clearMethod = "Clear"
|
|
iteratorClearMethod = "clear"
|
|
isMethod = "Is"
|
|
appendMethod = "Append"
|
|
prependMethod = "Prepend"
|
|
removeMethod = "Remove"
|
|
lenMethod = "Len"
|
|
swapMethod = "Swap"
|
|
lessMethod = "Less"
|
|
kindIndexMethod = "kindIndex"
|
|
serializeMethod = "Serialize"
|
|
deserializeMethod = "Deserialize"
|
|
nameMethod = "Name"
|
|
serializeIteratorMethod = "serialize"
|
|
deserializeIteratorMethod = "deserialize"
|
|
isLanguageMapMethod = "IsLanguageMap"
|
|
hasLanguageMethod = "HasLanguage"
|
|
getLanguageMethod = "GetLanguage"
|
|
setLanguageMethod = "SetLanguage"
|
|
// Member names for generated code
|
|
unknownMemberName = "unknown"
|
|
langMapMember = "langMap"
|
|
)
|
|
|
|
// join appends a bunch of Go Code together, each on their own line.
|
|
func join(s []jen.Code) *jen.Statement {
|
|
r := jen.Empty()
|
|
for i, stmt := range s {
|
|
if i > 0 {
|
|
r.Line()
|
|
}
|
|
r.Add(stmt)
|
|
}
|
|
return r
|
|
}
|
|
|
|
// Identifier determines how a name will appear in documentation and Go code.
|
|
type Identifier struct {
|
|
// LowerName is the typical name used in documentation.
|
|
LowerName string
|
|
// CamelName is the typical name used in identifiers in code.
|
|
CamelName string
|
|
}
|
|
|
|
// Kind is data that describes a concrete Go type, how to serialize and
|
|
// deserialize such types, compare the types, and other meta-information to use
|
|
// during Go code generation.
|
|
type Kind struct {
|
|
Name Identifier
|
|
ConcreteKind string
|
|
Nilable bool
|
|
HasNaturalLanguageMap bool
|
|
SerializeFnName string
|
|
DeserializeFnName string
|
|
LessFnName string
|
|
}
|
|
|
|
// PropertyGenerator is a common base struct used in both Functional and
|
|
// NonFunctional ActivityStreams properties. It provides common naming patterns,
|
|
// logic, and common Go code to be generated.
|
|
//
|
|
// It also properly handles the concept of generating Go code for property
|
|
// iterators, which are needed for NonFunctional properties.
|
|
type PropertyGenerator struct {
|
|
Package string
|
|
Name Identifier
|
|
Kinds []Kind
|
|
HasNaturalLanguageMap bool
|
|
asIterator bool
|
|
}
|
|
|
|
// packageName returns the name of the package for the property to be generated.
|
|
func (p *PropertyGenerator) packageName() string {
|
|
return p.Package
|
|
}
|
|
|
|
// structName returns the name of the type, which may or may not be a struct,
|
|
// to generate.
|
|
func (p *PropertyGenerator) structName() string {
|
|
if p.asIterator {
|
|
return p.Name.CamelName
|
|
}
|
|
return fmt.Sprintf("%sProperty", p.Name.CamelName)
|
|
}
|
|
|
|
// propertyName returns the name of this property, as defined in
|
|
// specifications. It is not suitable for use in generated code function
|
|
// identifiers.
|
|
func (p *PropertyGenerator) propertyName() string {
|
|
return p.Name.LowerName
|
|
}
|
|
|
|
// deserializeFnName returns the identifier of the function that deserializes
|
|
// raw JSON into the generated Go type.
|
|
func (p *PropertyGenerator) deserializeFnName() string {
|
|
if p.asIterator {
|
|
return fmt.Sprintf("%s%s", deserializeIteratorMethod, p.Name.CamelName)
|
|
}
|
|
return fmt.Sprintf("%s%sProperty", deserializeMethod, p.Name.CamelName)
|
|
}
|
|
|
|
// getFnName returns the identifier of the function that fetches concrete types
|
|
// of the property.
|
|
func (p *PropertyGenerator) getFnName(i int) string {
|
|
if len(p.Kinds) == 1 {
|
|
return getMethod
|
|
}
|
|
return fmt.Sprintf("%s%s", getMethod, p.kindCamelName(i))
|
|
}
|
|
|
|
// setFnName returns the identifier of the function that sets concrete types
|
|
// of the property.
|
|
func (p *PropertyGenerator) setFnName(i int) string {
|
|
if len(p.Kinds) == 1 {
|
|
return setMethod
|
|
}
|
|
return fmt.Sprintf("%s%s", setMethod, p.kindCamelName(i))
|
|
}
|
|
|
|
// serializeFnName returns the identifier of the function that serializes the
|
|
// generated Go type into raw JSON.
|
|
func (p *PropertyGenerator) serializeFnName() string {
|
|
if p.asIterator {
|
|
return serializeIteratorMethod
|
|
}
|
|
return serializeMethod
|
|
}
|
|
|
|
// kindCamelName returns an identifier-friendly name for the kind at the
|
|
// specified index.
|
|
//
|
|
// It will panic if 'i' is out of range.
|
|
func (p *PropertyGenerator) kindCamelName(i int) string {
|
|
return p.Kinds[i].Name.CamelName
|
|
}
|
|
|
|
// memberName returns the identifier to use for the kind at the specified index.
|
|
//
|
|
// It will panic if 'i' is out of range.
|
|
func (p *PropertyGenerator) memberName(i int) string {
|
|
return fmt.Sprintf("%sMember", p.Kinds[i].Name.LowerName)
|
|
}
|
|
|
|
// hasMemberName returns the identifier to use for struct members that determine
|
|
// whether non-nilable types have been set. Panics if called for a Kind that is
|
|
// nilable.
|
|
func (p *PropertyGenerator) hasMemberName(i int) string {
|
|
if len(p.Kinds) == 1 && p.Kinds[0].Nilable {
|
|
panic("PropertyGenerator.hasMemberName called for nilable single value")
|
|
}
|
|
return fmt.Sprintf("has%sMember", p.Kinds[i].Name.CamelName)
|
|
}
|
|
|
|
// clearMethodName returns the identifier to use for methods that clear all
|
|
// values from the property.
|
|
func (p *PropertyGenerator) clearMethodName() string {
|
|
if p.asIterator {
|
|
return iteratorClearMethod
|
|
}
|
|
return clearMethod
|
|
}
|
|
|
|
// commonMethods returns methods common to every property.
|
|
func (p *PropertyGenerator) commonMethods() []*Method {
|
|
return []*Method{
|
|
NewCommentedValueMethod(
|
|
p.packageName(),
|
|
nameMethod,
|
|
p.structName(),
|
|
/*params=*/ nil,
|
|
[]jen.Code{jen.String()},
|
|
[]jen.Code{
|
|
jen.Return(
|
|
jen.Lit(p.propertyName()),
|
|
),
|
|
},
|
|
jen.Commentf("%s returns the name of this property: %q.", nameMethod, p.propertyName()),
|
|
),
|
|
}
|
|
}
|
|
|
|
// isMethodName returns the identifier to use for methods that determine if a
|
|
// property holds a specific Kind of value.
|
|
func (p *PropertyGenerator) isMethodName(i int) string {
|
|
return fmt.Sprintf("%s%s", isMethod, p.kindCamelName(i))
|
|
}
|