Commit 6898ed22 authored by Eric Myhre's avatar Eric Myhre

Core of generateKindStruct.

Generates the struct itself (including the variations of pointers
and/or extra fields necessary),

There are several major TODOs outstanding; and the generated code
doesn't *quite* compile due to several missing references, namely:

- ipld.ErrNoSuchField
- ipld.Nil
- ipld.Undefined

The other issues remaining:

- The reason ErrNoSuchField is missing is because it needs to be
decided where an error like that should go.  Is it meaningfully
distinct from a general "key absent" error, like a map can return?
If it is indeed a distinct thing, does it go in the schema package,
or will that just make things annoying until the end of time since
every occurence-site-sibling error is in the ipld main package?

- We need to think about typed nil / typed undefined.  I suspect they
are an idea to be avoided (but doing so means using the NodeBuilder()
method on the nil or undefined values from a struct will *not* "DTRT",
which may be problematic; this can in turn be avoided by "knowing"
you're working on a typed node, but, erm.  It turns into a question of
which of these things is less annoying).

- We'll need to backtrack up to the main ipld.Node interface and add
that 'IsUndefined() bool' method now!  (Or, take a radical approach of
using a magic const for that.  But... no, that doesn't sound fun.)

- Haven't even touched the NodeBuilder yet.  (And the typeGenerator
interface needs to have those bits broken down, as well, so that we can
do good stuff with error path codesharing as with funcs for Node.)

- Haven't filled in MapIterator.  But that's probably just easy chug.

Lots to do, in short.  I just need a checkpoint.

Note how we've had this on the clipboard for a while already, heh --
the info_test.go file and TestUnderstandingStructMemoryLayout have been
aimed at this; notice how any extra bool fields are generated at the
bottom of the emitted struct.  Many yaks have been shaved in the
meanwhile, and yet look at how many we have to go.  Isn't this fun?
Signed-off-by: default avatarEric Myhre <hash@exultant.us>
parent 25702f19
package gengo
import (
"io"
"github.com/ipld/go-ipld-prime/schema"
)
func NewGeneratorForKindStruct(t schema.Type) typeGenerator {
return generateKindStruct{
t.(schema.TypeStruct),
generateKindedRejections_Map{t},
}
}
type generateKindStruct struct {
schema.TypeStruct
Type schema.TypeStruct
generateKindedRejections_Map
// FUTURE: probably some adjunct config data should come with here as well.
// FUTURE: perhaps both a global one (e.g. output package name) and a per-type one.
}
func (gk generateKindStruct) EmitNodeType(w io.Writer) {
// Observe that we get a '*' if a field is *either* nullable *or* optional;
// and we get an extra bool for the second cardinality +1'er if both are true.
doTemplate(`
var _ ipld.Node = {{ .Type.Name }}{}
type {{ .Type.Name }} struct{
{{- range $field := .Type.Fields }}
{{ $field.Name }} {{if or $field.IsOptional $field.IsNullable }}*{{end}}{{ $field.Type.Name }}
{{- end}}
{{ range $field := .Type.Fields }}
{{- if and $field.IsOptional $field.IsNullable }}
{{ $field.Name }}__exists bool
{{- end}}
{{- end}}
}
`, w, gk)
}
func (gk generateKindStruct) EmitNodeMethodReprKind(w io.Writer) {
doTemplate(`
func ({{ .Type.Name }}) ReprKind() ipld.ReprKind {
return ipld.ReprKind_Map
}
`, w, gk)
}
func (gk generateKindStruct) EmitNodeMethodTraverseField(w io.Writer) {
doTemplate(`
func (x {{ .Type.Name }}) TraverseField(key string) (ipld.Node, error) {
switch key {
{{- range $field := .Type.Fields }}
case "{{ $field.Name }}":
{{- if and $field.IsOptional $field.IsNullable }}
if !x.{{ $field.Name }}__exists {
return ipld.Undefined, nil
}
if x.{{ $field.Name }} == nil {
return ipld.Nil, nil
}
{{- else if $field.IsOptional }}
if x.{{ $field.Name }} == nil {
return ipld.Undefined, nil
}
{{- else if $field.IsNullable }}
if x.{{ $field.Name }} == nil {
return ipld.Nil, nil
}
{{- end}}
return x.{{ $field.Name }}, nil
{{- end}}
default:
return nil, ipld.ErrNoSuchField{FieldName: key} /* FIXME would this belong in the typed package? or..? */
}
}
`, w, gk)
}
func (gk generateKindStruct) EmitNodeMethodMapIterator(w io.Writer) {
doTemplate(`
func ({{ .Type.Name }}) MapIterator() ipld.MapIterator {
return nil // TODO EmitNodeMethodMapIterator
}
`, w, gk)
}
func (gk generateKindStruct) EmitNodeMethodLength(w io.Writer) {
doTemplate(`
func ({{ .Type.Name }}) Length() int {
return {{ len .Type.Fields }}
}
`, w, gk)
}
func (gk generateKindStruct) EmitNodeMethodNodeBuilder(w io.Writer) {
doTemplate(`
func ({{ .Type.Name }}) NodeBuilder() ipld.NodeBuilder {
return nil // TODO EmitNodeMethodNodeBuilder
}
`, w, gk)
}
......@@ -46,13 +46,32 @@ func TestNuevo(t *testing.T) {
)},
schema.StructRepresentation_Map{},
)
tStract2 := schema.SpawnStruct("Stract2",
[]schema.StructField{schema.SpawnStructField(
"nulble", tStrang, false, true,
)},
schema.StructRepresentation_Map{},
)
tStract3 := schema.SpawnStruct("Stract3",
[]schema.StructField{schema.SpawnStructField(
"noptble", tStrang, true, true,
)},
schema.StructRepresentation_Map{},
)
f = openOrPanic("_test/tStrang.go")
emitFileHeader(f)
emitType(NewGeneratorForKindString(tStrang), f)
_ = generateKindStruct{tStract}
//f = openOrPanic("_test/tStract.go")
//emitFileHeader(f)
//emitType(generateKindStruct{tStract}, f)
f = openOrPanic("_test/Stract.go")
emitFileHeader(f)
emitType(NewGeneratorForKindStruct(tStract), f)
f = openOrPanic("_test/Stract2.go")
emitFileHeader(f)
emitType(NewGeneratorForKindStruct(tStract2), f)
f = openOrPanic("_test/Stract3.go")
emitFileHeader(f)
emitType(NewGeneratorForKindStruct(tStract3), f)
}
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