Commit 6eafb5c7 authored by Eric Myhre's avatar Eric Myhre

Support for generating int types.

parent a446f41b
package gengo
import (
"io"
"github.com/ipld/go-ipld-prime/schema"
"github.com/ipld/go-ipld-prime/schema/gen/go/mixins"
)
type intGenerator struct {
AdjCfg *AdjunctCfg
mixins.IntTraits
PkgName string
Type schema.TypeInt
}
// --- native content and specializations --->
func (g intGenerator) EmitNativeType(w io.Writer) {
// Using a struct with a single member is the same size in memory as a typedef,
// while also having the advantage of meaning we can block direct casting,
// which is desirable because the compiler then ensures our validate methods can't be evaded.
doTemplate(`
type _{{ .Type | TypeSymbol }} struct{ x int }
type {{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }}
`, w, g.AdjCfg, g)
}
func (g intGenerator) EmitNativeAccessors(w io.Writer) {
// The node interface's `AsInt` method is almost sufficient... but
// this method unboxes without needing to return an error that's statically impossible,
// which makes it easier to use in chaining.
doTemplate(`
func (n {{ .Type | TypeSymbol }}) Int() int {
return n.x
}
`, w, g.AdjCfg, g)
}
func (g intGenerator) EmitNativeBuilder(w io.Writer) {
// Scalar types are easy to generate a constructor function for.
// REVIEW: if this is useful and should be on by default; it also adds a decent amount of noise to a package.
// It might make perfect sense to put it on the NodeStyle instead, as `FromInt(int)`.
// FUTURE: should engage validation flow.
doTemplate(`
func New{{ .Type | TypeSymbol }}(v int) {{ .Type | TypeSymbol }} {
n := _{{ .Type | TypeSymbol }}{v}
return &n
}
`, w, g.AdjCfg, g)
}
func (g intGenerator) EmitNativeMaybe(w io.Writer) {
// REVIEW: can this be extracted to the mixins package? it doesn't appear to vary for kind.
doTemplate(`
type _{{ .Type | TypeSymbol }}__Maybe struct {
m schema.Maybe
v {{if not (MaybeUsesPtr .Type) }}_{{end}}{{ .Type | TypeSymbol }}
}
type Maybe{{ .Type | TypeSymbol }} = *_{{ .Type | TypeSymbol }}__Maybe
func (m Maybe{{ .Type | TypeSymbol }}) IsNull() bool {
return m.m == schema.Maybe_Null
}
func (m Maybe{{ .Type | TypeSymbol }}) IsUndefined() bool {
return m.m == schema.Maybe_Absent
}
func (m Maybe{{ .Type | TypeSymbol }}) Exists() bool {
return m.m == schema.Maybe_Value
}
func (m Maybe{{ .Type | TypeSymbol }}) AsNode() ipld.Node {
switch m.m {
case schema.Maybe_Absent:
return ipld.Undef
case schema.Maybe_Null:
return ipld.Null
case schema.Maybe_Value:
return {{if not (MaybeUsesPtr .Type) }}&{{end}}m.v
default:
panic("unreachable")
}
}
func (m Maybe{{ .Type | TypeSymbol }}) Must() {{ .Type | TypeSymbol }} {
if !m.Exists() {
panic("unbox of a maybe rejected")
}
return {{if not (MaybeUsesPtr .Type) }}&{{end}}m.v
}
`, w, g.AdjCfg, g)
}
// --- type info --->
func (g intGenerator) EmitTypeConst(w io.Writer) {
doTemplate(`
// TODO EmitTypeConst
`, w, g.AdjCfg, g)
}
// --- TypedNode interface satisfaction --->
func (g intGenerator) EmitTypedNodeMethodType(w io.Writer) {
doTemplate(`
func ({{ .Type | TypeSymbol }}) Type() schema.Type {
return nil /*TODO:typelit*/
}
`, w, g.AdjCfg, g)
}
func (g intGenerator) EmitTypedNodeMethodRepresentation(w io.Writer) {
// Perhaps surprisingly, the way to get the representation node pointer
// does not actually depend on what the representation strategy is.
doTemplate(`
func (n {{ .Type | TypeSymbol }}) Representation() ipld.Node {
return (*_{{ .Type | TypeSymbol }}__Repr)(n)
}
`, w, g.AdjCfg, g)
}
// --- Node interface satisfaction --->
func (g intGenerator) EmitNodeType(w io.Writer) {
// No additional types needed. Methods all attach to the native type.
}
func (g intGenerator) EmitNodeTypeAssertions(w io.Writer) {
doTemplate(`
var _ ipld.Node = ({{ .Type | TypeSymbol }})(&_{{ .Type | TypeSymbol }}{})
var _ schema.TypedNode = ({{ .Type | TypeSymbol }})(&_{{ .Type | TypeSymbol }}{})
`, w, g.AdjCfg, g)
}
func (g intGenerator) EmitNodeMethodAsInt(w io.Writer) {
doTemplate(`
func (n {{ .Type | TypeSymbol }}) AsInt() (int, error) {
return n.x, nil
}
`, w, g.AdjCfg, g)
}
func (g intGenerator) EmitNodeMethodStyle(w io.Writer) {
doTemplate(`
func ({{ .Type | TypeSymbol }}) Style() ipld.NodeStyle {
return _{{ .Type | TypeSymbol }}__Style{}
}
`, w, g.AdjCfg, g)
}
func (g intGenerator) EmitNodeStyleType(w io.Writer) {
doTemplate(`
type _{{ .Type | TypeSymbol }}__Style struct{}
func (_{{ .Type | TypeSymbol }}__Style) NewBuilder() ipld.NodeBuilder {
var nb _{{ .Type | TypeSymbol }}__Builder
nb.Reset()
return &nb
}
`, w, g.AdjCfg, g)
}
// --- NodeBuilder and NodeAssembler --->
func (g intGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {
return intBuilderGenerator{
g.AdjCfg,
mixins.IntAssemblerTraits{
g.PkgName,
g.TypeName,
"_" + g.AdjCfg.TypeSymbol(g.Type) + "__",
},
g.PkgName,
g.Type,
}
}
type intBuilderGenerator struct {
AdjCfg *AdjunctCfg
mixins.IntAssemblerTraits
PkgName string
Type schema.TypeInt
}
func (g intBuilderGenerator) EmitNodeBuilderType(w io.Writer) {
doTemplate(`
type _{{ .Type | TypeSymbol }}__Builder struct {
_{{ .Type | TypeSymbol }}__Assembler
}
`, w, g.AdjCfg, g)
}
func (g intBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) {
doTemplate(`
func (nb *_{{ .Type | TypeSymbol }}__Builder) Build() ipld.Node {
return nb.w
}
func (nb *_{{ .Type | TypeSymbol }}__Builder) Reset() {
var w _{{ .Type | TypeSymbol }}
*nb = _{{ .Type | TypeSymbol }}__Builder{_{{ .Type | TypeSymbol }}__Assembler{w: &w}}
}
`, w, g.AdjCfg, g)
// Cover up all the assembler methods that are prepared to handle null;
// this saves them from having to check for a nil 'fcb'.
doTemplate(`
func (nb *_{{ .Type | TypeSymbol }}__Builder) AssignNull() error {
return mixins.StringAssembler{"{{ .PkgName }}.{{ .TypeName }}"}.AssignNull()
}
func (nb *_{{ .Type | TypeSymbol }}__Builder) AssignInt(v int) error {
*nb.w = _{{ .Type | TypeSymbol }}{v}
return nil
}
func (nb *_{{ .Type | TypeSymbol }}__Builder) AssignNode(v ipld.Node) error {
if v2, err := v.AsInt(); err != nil {
return err
} else {
return nb.AssignInt(v2)
}
}
`, w, g.AdjCfg, g)
}
func (g intBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {
doTemplate(`
type _{{ .Type | TypeSymbol }}__Assembler struct {
w *_{{ .Type | TypeSymbol }}
z bool
fcb func() error
}
`, w, g.AdjCfg, g)
}
func (g intBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {
// Twist: All generated assemblers quietly accept null... and if used in a context they shouldn't,
// either this method gets overriden (this is the case for NodeBuilders),
// or the 'na.fcb' (short for "finish callback") returns the rejection.
// We don't need a nil check for 'fcb' because all parent assemblers use it, and root builders override all relevant methods.
// We don't pass any args to 'fcb' because we assume it comes from something that can already see this whole struct.
doTemplate(`
func (na *_{{ .Type | TypeSymbol }}__Assembler) AssignNull() error {
na.z = true
return na.fcb()
}
`, w, g.AdjCfg, g)
}
func (g intBuilderGenerator) EmitNodeAssemblerMethodAssignInt(w io.Writer) {
// This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated.
// This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe;
// otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual.
doTemplate(`
func (na *_{{ .Type | TypeSymbol }}__Assembler) AssignInt(v int) error {
{{- if .Type | MaybeUsesPtr }}
if na.w == nil {
na.w = &_{{ .Type | TypeSymbol }}{v}
return na.fcb()
}
{{- end}}
*na.w = _{{ .Type | TypeSymbol }}{v}
return na.fcb()
}
`, w, g.AdjCfg, g)
}
func (g intBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {
doTemplate(`
func (na *_{{ .Type | TypeSymbol }}__Assembler) AssignNode(v ipld.Node) error {
if v.IsNull() {
return na.AssignNull()
}
if v2, err := v.AsInt(); err != nil {
return err
} else {
return na.AssignInt(v2)
}
}
`, w, g.AdjCfg, g)
}
func (g intBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {
// Nothing needed here for int kinds.
}
package gengo
import (
"io"
"github.com/ipld/go-ipld-prime/schema"
"github.com/ipld/go-ipld-prime/schema/gen/go/mixins"
)
var _ TypeGenerator = &intReprIntGenerator{}
func NewIntReprIntGenerator(pkgName string, typ schema.TypeInt, adjCfg *AdjunctCfg) TypeGenerator {
return intReprIntGenerator{
intGenerator{
adjCfg,
mixins.IntTraits{
pkgName,
string(typ.Name()),
adjCfg.TypeSymbol(typ),
},
pkgName,
typ,
},
}
}
type intReprIntGenerator struct {
intGenerator
}
func (g intReprIntGenerator) GetRepresentationNodeGen() NodeGenerator {
return intReprIntReprGenerator{
g.AdjCfg,
g.Type,
}
}
type intReprIntReprGenerator struct {
AdjCfg *AdjunctCfg
Type schema.TypeInt
}
func (g intReprIntReprGenerator) EmitNodeType(w io.Writer) {
// Since this is a "natural" representation... there's just a type alias here.
// No new functions are necessary.
doTemplate(`
type _{{ .Type | TypeSymbol }}__Repr = _{{ .Type | TypeSymbol }}
`, w, g.AdjCfg, g)
}
func (g intReprIntReprGenerator) EmitNodeTypeAssertions(w io.Writer) {
doTemplate(`
var _ ipld.Node = &_{{ .Type | TypeSymbol }}__Repr{}
`, w, g.AdjCfg, g)
}
func (intReprIntReprGenerator) EmitNodeMethodReprKind(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodLookupString(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodLookup(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodLookupIndex(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodLookupSegment(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodMapIterator(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodListIterator(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodLength(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodIsUndefined(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodIsNull(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodAsBool(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodAsInt(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodAsFloat(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodAsString(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodAsBytes(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodAsLink(io.Writer) {}
func (intReprIntReprGenerator) EmitNodeMethodStyle(io.Writer) {}
func (g intReprIntReprGenerator) EmitNodeStyleType(w io.Writer) {
// Since this is a "natural" representation... there's just a type alias here.
// No new functions are necessary.
doTemplate(`
type _{{ .Type | TypeSymbol }}__ReprStyle = _{{ .Type | TypeSymbol }}__Style
`, w, g.AdjCfg, g)
}
func (g intReprIntReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator {
return intReprIntReprBuilderGenerator{g.AdjCfg, g.Type}
}
type intReprIntReprBuilderGenerator struct {
AdjCfg *AdjunctCfg
Type schema.TypeInt
}
func (intReprIntReprBuilderGenerator) EmitNodeBuilderType(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeBuilderMethods(io.Writer) {}
func (g intReprIntReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) {
// Since this is a "natural" representation... there's just a type alias here.
// No new functions are necessary.
doTemplate(`
type _{{ .Type | TypeSymbol }}__ReprAssembler = _{{ .Type | TypeSymbol }}__Assembler
`, w, g.AdjCfg, g)
}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodBeginMap(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodBeginList(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignBool(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignInt(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignFloat(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignBytes(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignLink(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerMethodStyle(io.Writer) {}
func (intReprIntReprBuilderGenerator) EmitNodeAssemblerOtherBits(io.Writer) {}
......@@ -19,6 +19,8 @@ func Generate(pth string, pkgName string, ts schema.TypeSystem, adjCfg *AdjunctC
withFile(filepath.Join(pth, "t"+typ.Name().String()+".go"), func(f io.Writer) {
EmitFileHeader(pkgName, f)
switch t2 := typ.(type) {
case schema.TypeInt:
EmitEntireType(NewIntReprIntGenerator(pkgName, t2, adjCfg), f)
case schema.TypeString:
EmitEntireType(NewStringReprStringGenerator(pkgName, t2, adjCfg), f)
case schema.TypeStruct:
......
package mixins
import (
"io"
ipld "github.com/ipld/go-ipld-prime"
)
type IntTraits struct {
PkgName string
TypeName string // see doc in kindTraitsGenerator
TypeSymbol string // see doc in kindTraitsGenerator
}
func (g IntTraits) EmitNodeMethodReprKind(w io.Writer) {
doTemplate(`
func ({{ .TypeSymbol }}) ReprKind() ipld.ReprKind {
return ipld.ReprKind_Int
}
`, w, g)
}
func (g IntTraits) EmitNodeMethodLookupString(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodLookupString(w)
}
func (g IntTraits) EmitNodeMethodLookup(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodLookup(w)
}
func (g IntTraits) EmitNodeMethodLookupIndex(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodLookupIndex(w)
}
func (g IntTraits) EmitNodeMethodLookupSegment(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodLookupSegment(w)
}
func (g IntTraits) EmitNodeMethodMapIterator(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodMapIterator(w)
}
func (g IntTraits) EmitNodeMethodListIterator(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodListIterator(w)
}
func (g IntTraits) EmitNodeMethodLength(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodLength(w)
}
func (g IntTraits) EmitNodeMethodIsUndefined(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodIsUndefined(w)
}
func (g IntTraits) EmitNodeMethodIsNull(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodIsNull(w)
}
func (g IntTraits) EmitNodeMethodAsBool(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodAsBool(w)
}
func (g IntTraits) EmitNodeMethodAsFloat(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodAsFloat(w)
}
func (g IntTraits) EmitNodeMethodAsString(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodAsString(w)
}
func (g IntTraits) EmitNodeMethodAsBytes(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodAsBytes(w)
}
func (g IntTraits) EmitNodeMethodAsLink(w io.Writer) {
kindTraitsGenerator{g.PkgName, g.TypeName, g.TypeSymbol, ipld.ReprKind_Int}.emitNodeMethodAsLink(w)
}
type IntAssemblerTraits struct {
PkgName string
TypeName string // see doc in kindAssemblerTraitsGenerator
AppliedPrefix string // see doc in kindAssemblerTraitsGenerator
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodBeginMap(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodBeginMap(w)
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodBeginList(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodBeginList(w)
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignNull(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodAssignNull(w)
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignBool(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodAssignBool(w)
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignFloat(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodAssignFloat(w)
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignString(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodAssignString(w)
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignBytes(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodAssignBytes(w)
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodAssignLink(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodAssignLink(w)
}
func (g IntAssemblerTraits) EmitNodeAssemblerMethodStyle(w io.Writer) {
kindAssemblerTraitsGenerator{g.PkgName, g.TypeName, g.AppliedPrefix, ipld.ReprKind_Int}.emitNodeAssemblerMethodStyle(w)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment