Commit 7cdaa71e authored by Eric Myhre's avatar Eric Myhre

Basically everything for scalar assemblers DRY.

This'll probably be the end of my cleanup quest for the day, but it's
a pretty pleasing result.  More cleaned up more easily than I expected.
parent 3c03a6d3
......@@ -145,3 +145,64 @@ func emitNodeAssemblerMethodAssignNull_recursive(w io.Writer, adjCfg *AdjunctCfg
}
`, w, adjCfg, data)
}
// works for the AssignFoo methods for scalar kinds that are just boxing a thing.
// There's no equivalent of this at all for recursives -- they're too diverse.
func emitNodeAssemblerMethodAssignKind_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {
// 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) Assign{{ .ReprKind.String | title }}(v {{ .ReprKind | KindPrim}}) error {
switch *na.m {
case schema.Maybe_Value, schema.Maybe_Null:
panic("invalid state: cannot assign into assembler that's already finished")
}
{{- if .Type | MaybeUsesPtr }}
if na.w == nil {
na.w = &_{{ .Type | TypeSymbol }}{}
}
{{- end}}
na.w.x = v
*na.m = schema.Maybe_Value
return nil
}
`, w, adjCfg, data)
}
// leans heavily on the fact all the AsFoo and AssignFoo methods follow a very consistent textual pattern.
// FUTURE: may be able to get this to work for recursives, too -- but maps and lists each have very unique bottom thirds of this function.
func emitNodeAssemblerMethodAssignNode_scalar(w io.Writer, adjCfg *AdjunctCfg, data interface{}) {
// AssignNode goes through three phases:
// 1. is it null? Jump over to AssignNull (which may or may not reject it).
// 2. is it our own type? Handle specially -- we might be able to do efficient things.
// 3. is it the right kind to morph into us? Do so.
doTemplate(`
func (na *_{{ .Type | TypeSymbol }}__Assembler) AssignNode(v ipld.Node) error {
if v.IsNull() {
return na.AssignNull()
}
if v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {
switch *na.m {
case schema.Maybe_Value, schema.Maybe_Null:
panic("invalid state: cannot assign into assembler that's already finished")
}
{{- if .Type | MaybeUsesPtr }}
if na.w == nil {
na.w = v2
*na.m = schema.Maybe_Value
return nil
}
{{- end}}
*na.w = *v2
*na.m = schema.Maybe_Value
return nil
}
if v2, err := v.As{{ .ReprKind.String | title }}(); err != nil {
return err
} else {
return na.Assign{{ .ReprKind.String | title }}(v2)
}
}
`, w, adjCfg, data)
}
......@@ -155,59 +155,10 @@ func (g intBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {
emitNodeAssemblerMethodAssignNull_scalar(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 {
switch *na.m {
case schema.Maybe_Value, schema.Maybe_Null:
panic("invalid state: cannot assign into assembler that's already finished")
}
{{- if .Type | MaybeUsesPtr }}
if na.w == nil {
na.w = &_{{ .Type | TypeSymbol }}{}
}
{{- end}}
na.w.x = v
*na.m = schema.Maybe_Value
return nil
}
`, w, g.AdjCfg, g)
emitNodeAssemblerMethodAssignKind_scalar(w, g.AdjCfg, g)
}
func (g intBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {
// AssignNode goes through three phases:
// 1. is it null? Jump over to AssignNull (which may or may not reject it).
// 2. is it our own type? Handle specially -- we might be able to do efficient things.
// 3. is it the right kind to morph into us? Do so.
doTemplate(`
func (na *_{{ .Type | TypeSymbol }}__Assembler) AssignNode(v ipld.Node) error {
if v.IsNull() {
return na.AssignNull()
}
if v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {
switch *na.m {
case schema.Maybe_Value, schema.Maybe_Null:
panic("invalid state: cannot assign into assembler that's already finished")
}
{{- if .Type | MaybeUsesPtr }}
if na.w == nil {
na.w = v2
*na.m = schema.Maybe_Value
return nil
}
{{- end}}
*na.w = *v2
*na.m = schema.Maybe_Value
return nil
}
if v2, err := v.AsInt(); err != nil {
return err
} else {
return na.AssignInt(v2)
}
}
`, w, g.AdjCfg, g)
emitNodeAssemblerMethodAssignNode_scalar(w, g.AdjCfg, g)
}
func (g intBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {
// Nothing needed here for int kinds.
......
......@@ -165,59 +165,10 @@ func (g stringBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) {
emitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g)
}
func (g stringBuilderGenerator) EmitNodeAssemblerMethodAssignString(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) AssignString(v string) error {
switch *na.m {
case schema.Maybe_Value, schema.Maybe_Null:
panic("invalid state: cannot assign into assembler that's already finished")
}
{{- if .Type | MaybeUsesPtr }}
if na.w == nil {
na.w = &_{{ .Type | TypeSymbol }}{}
}
{{- end}}
na.w.x = v
*na.m = schema.Maybe_Value
return nil
}
`, w, g.AdjCfg, g)
emitNodeAssemblerMethodAssignKind_scalar(w, g.AdjCfg, g)
}
func (g stringBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) {
// AssignNode goes through three phases:
// 1. is it null? Jump over to AssignNull (which may or may not reject it).
// 2. is it our own type? Handle specially -- we might be able to do efficient things.
// 3. is it the right kind to morph into us? Do so.
doTemplate(`
func (na *_{{ .Type | TypeSymbol }}__Assembler) AssignNode(v ipld.Node) error {
if v.IsNull() {
return na.AssignNull()
}
if v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok {
switch *na.m {
case schema.Maybe_Value, schema.Maybe_Null:
panic("invalid state: cannot assign into assembler that's already finished")
}
{{- if .Type | MaybeUsesPtr }}
if na.w == nil {
na.w = v2
*na.m = schema.Maybe_Value
return nil
}
{{- end}}
*na.w = *v2
*na.m = schema.Maybe_Value
return nil
}
if v2, err := v.AsString(); err != nil {
return err
} else {
return na.AssignString(v2)
}
}
`, w, g.AdjCfg, g)
emitNodeAssemblerMethodAssignNode_scalar(w, g.AdjCfg, g)
}
func (g stringBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) {
// Nothing needed here for string kinds.
......
......@@ -6,6 +6,8 @@ import (
"text/template"
wish "github.com/warpfork/go-wish"
ipld "github.com/ipld/go-ipld-prime"
)
func doTemplate(tmplstr string, w io.Writer, adjCfg *AdjunctCfg, data interface{}) {
......@@ -15,8 +17,32 @@ func doTemplate(tmplstr string, w io.Writer, adjCfg *AdjunctCfg, data interface{
"FieldSymbolLower": adjCfg.FieldSymbolLower,
"FieldSymbolUpper": adjCfg.FieldSymbolUpper,
"MaybeUsesPtr": adjCfg.MaybeUsesPtr,
"add": func(a, b int) int { return a + b },
"title": func(s string) string { return strings.Title(s) },
"KindPrim": func(k ipld.ReprKind) string {
switch k {
case ipld.ReprKind_Map:
panic("this isn't useful for non-scalars")
case ipld.ReprKind_List:
panic("this isn't useful for non-scalars")
case ipld.ReprKind_Null:
panic("this isn't useful for null")
case ipld.ReprKind_Bool:
return "bool"
case ipld.ReprKind_Int:
return "int"
case ipld.ReprKind_Float:
return "float64"
case ipld.ReprKind_String:
return "string"
case ipld.ReprKind_Bytes:
return "[]byte"
case ipld.ReprKind_Link:
return "ipld.Link"
default:
panic("invalid enumeration value!")
}
},
"add": func(a, b int) int { return a + b },
"title": func(s string) string { return strings.Title(s) },
}).
// Seriously consider prepending `{{ $dot := . }}` (or 'top', or something).
// Or a func into the map that causes `dot` to mean `func() interface{} { return data }`.
......
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