Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codegen update -- Assemblers, and many new representations #52

Merged
merged 102 commits into from
Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
3f138f7
Begin reboot of codegen; also, some research.
warpfork Mar 29, 2020
14e6653
Codegen now has widespread symbol customization.
warpfork Mar 29, 2020
cbef5c3
Fix excessing pointers in maybes.
warpfork Mar 29, 2020
59c295d
Beginning of struct gen; much ado about Maybes.
warpfork Mar 29, 2020
80b0ba2
Checkpoint of struct gen progress.
warpfork Apr 1, 2020
96d63ad
Correct iterators for representatons of structs with absent optional …
warpfork Apr 1, 2020
7ff42bd
Nicely composable NodeBuilderGenerator, +mixins.
warpfork Apr 1, 2020
f3be0c3
Fix basicnode maps to not wedge on repeated keys; and DRY maps and li…
warpfork Apr 1, 2020
fd94a06
Checkpoint of codegen'd struct assemblers.
warpfork Apr 1, 2020
27873cb
ErrInvalidKey type, and use it.
warpfork Apr 1, 2020
896d0e5
Late night thoughts on reducing gen type count.
warpfork Apr 1, 2020
125a2a7
Fix many issues with maybes; adjunct config for if maybe is implement…
warpfork Apr 1, 2020
255bbc5
Support maybe implemented using ptr.
warpfork Apr 1, 2020
1a6143a
Contemplations about defaults for MaybeUsingPtr.
warpfork Apr 1, 2020
6dfdc19
More smoke test types: exercise maybeptr=true.
warpfork Apr 1, 2020
072098e
Tests on gen output; some fixes; working.
warpfork Apr 1, 2020
bcf7b05
Test null nullable field; works.
warpfork Apr 1, 2020
ddcf6b4
All nullable and optional cases tested & passing.
warpfork Apr 1, 2020
e422966
Merge branch 'codegen-how-maybe' into codegen-oppdatering
warpfork Apr 1, 2020
de61bf1
Couldn't resist adding a few more test cases.
warpfork Apr 2, 2020
f44ea65
Addntl questions on semantics of absent values.
warpfork Apr 3, 2020
58aa17a
Refine nullable implementation; some more of struct map reprs.
warpfork Apr 6, 2020
54f5e47
Stamp out remainder of map repr for struct.
warpfork Apr 6, 2020
5f93c29
Support for struct field rename directives.
warpfork Apr 7, 2020
616051d
Emit multiple packages in codegen tests. Exericse as plugins.
warpfork Apr 10, 2020
5e815e5
Try using 'go test' subprocesses instead.
warpfork Apr 10, 2020
ad0a283
Deeper attempt to parse child 'go test'. Not good.
warpfork Apr 10, 2020
04d2d3e
Merge-ignore branch 'test-codegen-using-go-test-subproc' into test-co…
warpfork Apr 10, 2020
79de0e2
Complete codegen tests using plugins.
warpfork Apr 10, 2020
e11bc44
Smooth skips when plugins aren't available (or on request); docs on t…
warpfork Apr 12, 2020
3705531
Merge branch 'test-codegen-using-plugins' into codegen-oppdatering
warpfork Apr 12, 2020
62a03ee
Extract total Generate method.
warpfork Apr 12, 2020
a83fad3
Fix wrong constant in text matrix.
warpfork Apr 13, 2020
a446f41
Fix typo in error messages.
warpfork Apr 13, 2020
6eafb5c
Support for generating int types.
warpfork Apr 13, 2020
3d96f41
Fix gen struct repr map with no optionals.
warpfork Apr 13, 2020
2e79a3e
Support for structs with stringjoin reprsentation!
warpfork Apr 13, 2020
2015992
Demo: codegen matching our Map3StrInt benchmark!
warpfork Apr 16, 2020
6d31b15
Remove finish callback. Much faster. Bench.
warpfork Apr 16, 2020
e8d9a8f
Fix use of StructField as map key.
warpfork Apr 17, 2020
d21dad4
Recursive structs with string representation.
warpfork Apr 17, 2020
d12324e
Fix some typos in kind errors.
warpfork Apr 19, 2020
25dcc61
Comments speculating on how to improve templates.
warpfork Apr 19, 2020
65f49f7
Fix safety in face of over-held child assemblers for struct fields th…
warpfork Apr 19, 2020
5ed03b8
Checkpoint first thrust of map gen features.
warpfork Apr 19, 2020
2a34785
Next checkpoint in progress towards map gen.
warpfork Apr 19, 2020
81bdd93
Third checkpoint in progress towards map gen.
warpfork Apr 19, 2020
7fe8c83
Refactor 'construct'->'fromString'.
warpfork Apr 19, 2020
fa8b487
Map gen now works.
warpfork Apr 19, 2020
51d3e05
Fix typo in interface assertions.
warpfork Apr 19, 2020
9c925d1
Test structs with nested structs.
warpfork Apr 19, 2020
5146075
Dry up emitNativeMaybe, and apply it everywhere.
warpfork Apr 19, 2020
bb7c912
Several functional tests for generated maps.
warpfork Apr 19, 2020
d52e2c2
Recursive maps: works, and tested.
warpfork Apr 19, 2020
66047ce
Terribly important character. Avoids alloc.
warpfork Apr 19, 2020
3b33e05
MapNStrMap3StrInt benchmarks on codegen.
warpfork Apr 19, 2020
2c41e28
Add test for maps with complex keys.
warpfork Apr 24, 2020
0551903
Test for nested structs with stringjoin repr.
warpfork Apr 24, 2020
5e8f180
Update struct stringjoin repr assembler.
warpfork Apr 24, 2020
7975725
Remove todo comment fixed in 2c41e2827.
warpfork Apr 24, 2020
0827921
List gen support, and tests.
warpfork Apr 24, 2020
ac7732c
Fix stutters in some generated messages.
warpfork Apr 24, 2020
33c611f
The type(/style) access table is now genned.
warpfork Apr 24, 2020
75595ed
Update int gen to use the Style.FromInt pattern.
warpfork Apr 24, 2020
ca7481a
Considering extracting some common parts.
warpfork Apr 26, 2020
83bf3c0
DRY EmitTypedNodeMethodRepresentation.
warpfork Apr 26, 2020
8d848ed
Typo fix in error messages in generated ints.
warpfork Apr 26, 2020
f6cbe84
More DRY'ing efforts in codegen.
warpfork Apr 26, 2020
680f138
The string of kinds should really be lowercase.
warpfork Apr 26, 2020
9737070
Comment typo fix.
warpfork Apr 26, 2020
ef17e64
Extract and DRY AssignNull method for most types.
warpfork Apr 26, 2020
3c03a6d
AssignNull method now also DRY across reprs :D
warpfork Apr 26, 2020
7cdaa71
Basically everything for scalar assemblers DRY.
warpfork Apr 26, 2020
7754ce0
More extraction and DRY'ing.
warpfork Apr 26, 2020
2f7df51
All the other scalars.
warpfork Apr 26, 2020
f1eeeaf
Comments contemplating options to DRY list repr.
warpfork Apr 28, 2020
38a6fd0
the most hygenic of macros have been deployed here
warpfork May 8, 2020
4d56c5e
Dry'ing more templates across repr-or-not.
warpfork May 8, 2020
7ff6310
Generate list representation node.
warpfork May 8, 2020
e157f3b
Generalize more shared templates over repr.
warpfork May 8, 2020
9cae922
Finish list repr list gen.
warpfork May 22, 2020
160062b
Fix missing zeroing of wip pointer during nullable children in recurs…
warpfork May 22, 2020
d87c67e
Make this error less fragile.
warpfork May 22, 2020
6c65fd6
Test for lists-of-lists and that representation-mode recursion works …
warpfork May 22, 2020
3d4cd43
Maps now correctly stay in representation mode when read.
warpfork May 22, 2020
6916052
comment typo fix
warpfork May 22, 2020
e9bb741
Map representations now work and correctly stay in representation mod…
warpfork May 22, 2020
e198e32
Feature table in readme!
warpfork May 22, 2020
a7e8b2f
Refresh HACKME documents.
warpfork May 22, 2020
f1f9308
Clean up minima.
warpfork May 22, 2020
0009613
Regen the realgen package.
warpfork May 22, 2020
e9455cd
gendemo package is now real generation :3
warpfork May 22, 2020
59b1625
Clean up notes about how gen templates are organized.
warpfork May 25, 2020
9f0968c
Clean up docs on how/why codegen "maybe"s work.
warpfork Jun 3, 2020
9d4171a
Move files to use genparts prefix consistently.
warpfork Jun 3, 2020
cc9f331
brief review of absent value handling policy
warpfork Jun 8, 2020
ec24732
More goals statements for codegen.
warpfork Jun 15, 2020
87794f5
Clean out remaining wip documents.
warpfork Jun 15, 2020
befa498
Fix some out of date docs.
warpfork Jun 15, 2020
13a3cd3
Regen gendemo package.
warpfork Jun 15, 2020
6ca0abc
Merge branch 'master' into codegen-oppdatering
warpfork Jun 15, 2020
21c8792
Update tests that had semantic conflicts.
warpfork Jun 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ before_script:
- go test -run xxxx ./...

script:
- go test -race -short -coverprofile=coverage.txt ./...
- go test -short -coverprofile=coverage.txt ./...

after_success:
- bash <(curl -s https://codecov.io/bash)
15 changes: 15 additions & 0 deletions _rsrch/methodsets/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package methodsets

type Thing struct {
Alpha string
Beta string
}

func (x *Thing) Pow() {
x.Alpha = "base"
}

type ThingPrivate struct {
a string
b string
}
26 changes: 26 additions & 0 deletions _rsrch/methodsets/crosspkg/isomorphicCast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package crosspkg

import (
"github.com/ipld/go-ipld-prime/_rsrch/methodsets"
)

type What struct {
Alpha string
Beta string
}

func FlipWhat(x *methodsets.Thing) *What {
return (*What)(x)
}

type WhatPrivate struct {
a string
b string
}

//func FlipWhatPrivate(x *methodsets.ThingPrivate) *What {
// return (*WhatPrivate)(x)
//}
// NOPE!
// (thank HEAVENS.)
// ./isomorphicCast.go:22:23: cannot convert x (type *methodsets.ThingPrivate) to type *WhatPrivate
28 changes: 28 additions & 0 deletions _rsrch/methodsets/viaAliases.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package methodsets

type AliasThing = Thing

// func (x *AliasThing) Pow() {}
// NOPE!
// ./viaAliases.go:5:22: (*Thing).Pow redeclared in this block
// previous declaration at ./base.go:8:6

type AliasPtr = *Thing

// ^ Oddly, works.

// func (x *AliasPtr) Pow() {}
// NOPE!
// ./aliases.go:14:6: invalid receiver type **Thing (*Thing is not a defined type)

// func (x AliasPtr) Pow() {}
// NOPE!
// ./aliases.go:18:19: (*Thing).Pow redeclared in this block
// previous declaration at ./base.go:8:6

/*
Conclusion: no joy.
Aliases really are a syntactic sugar thing, and do not seem to enable
any interesting tricks that would not otherwise be possible,
and certainly don't appear to get us closer to the "methodsets" semantic I yearn for.
*/
15 changes: 15 additions & 0 deletions _rsrch/methodsets/viaTypedef.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package methodsets

type Thing2ViaTypedef Thing

// This also compiles and works if you longhand the entire struct defn again...
// as long as it's identical, it works.
// (This does not extend to replacing field types with other-named but structurally identical types.)

func FlipTypedef(x *Thing) *Thing2ViaTypedef {
return (*Thing2ViaTypedef)(x)
}

func (x *Thing2ViaTypedef) Pow() {
x.Alpha = "typedef"
}
28 changes: 28 additions & 0 deletions _rsrch/methodsets/viaTypedef_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package methodsets

import (
"testing"

. "github.com/warpfork/go-wish"
)

func TestViaTypedef(t *testing.T) {
x := Thing{"alpha", "beta"}

x.Pow()
Wish(t, x, ShouldEqual, Thing{"base", "beta"})

x2 := FlipTypedef(&x)
Wish(t, x2, ShouldEqual, &Thing2ViaTypedef{"base", "beta"})

x2.Pow()
Wish(t, x2, ShouldEqual, &Thing2ViaTypedef{"typedef", "beta"})

Wish(t, x, ShouldEqual, Thing{"typedef", "beta"}) // ! effects propagate back to original.

x.Pow()
Wish(t, x2, ShouldEqual, &Thing2ViaTypedef{"base", "beta"}) // ! and still also vice versa.

// it's not just that we care about retaining mutability (though that's sometimes useful);
// it's that a 'yes' to that directly implies 'yes' to "can we get this pov without any allocations".
}
22 changes: 22 additions & 0 deletions _rsrch/methodsets/viaUnsafe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package methodsets

import (
"unsafe"
)

type Thing2ViaUnsafe struct {
Alpha string
Beta string
}

func FlipUnsafe(x *Thing) *Thing2ViaUnsafe {
return (*Thing2ViaUnsafe)(unsafe.Pointer(x))
}

func UnflipUnsafe(x *Thing2ViaUnsafe) *Thing {
return (*Thing)(unsafe.Pointer(x))
}

func (x *Thing2ViaUnsafe) Pow() {
x.Alpha = "unsafe"
}
28 changes: 28 additions & 0 deletions _rsrch/methodsets/viaUnsafe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package methodsets

import (
"testing"

. "github.com/warpfork/go-wish"
)

func TestViaUnsafe(t *testing.T) {
x := Thing{"alpha", "beta"}

x.Pow()
Wish(t, x, ShouldEqual, Thing{"base", "beta"})

x2 := FlipUnsafe(&x)
Wish(t, x2, ShouldEqual, &Thing2ViaUnsafe{"base", "beta"})

x2.Pow()
Wish(t, x2, ShouldEqual, &Thing2ViaUnsafe{"unsafe", "beta"})

Wish(t, x, ShouldEqual, Thing{"unsafe", "beta"}) // ! effects propagate back to original.

x.Pow()
Wish(t, x2, ShouldEqual, &Thing2ViaUnsafe{"base", "beta"}) // ! and still also vice versa.

// it's not just that we care about retaining mutability (though that's sometimes useful);
// it's that a 'yes' to that directly implies 'yes' to "can we get this pov without any allocations".
}
56 changes: 56 additions & 0 deletions _rsrch/nozeros/crosspkg/zero_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package crosspkg

import (
"testing"

. "github.com/warpfork/go-wish"

"github.com/ipld/go-ipld-prime/_rsrch/nozeros"
)

func TestStuff(t *testing.T) {
_ = nozeros.ExportedAlias{} // undesirable

// _ = nozeros.ExportedPtr{} // undesirable
// NOPE! (Success!)
// ./zero.go:14:25: invalid pointer type nozeros.ExportedPtr for composite literal (use &nozeros.internal instead)

v := nozeros.NewExportedPtr("woo")
var typecheckMe interface{} = v
v2, ok := typecheckMe.(nozeros.ExportedPtr)

Wish(t, ok, ShouldEqual, true) // well, duh. Mostly we wanted to know if even asking was allowed.
Wish(t, v2, ShouldEqual, v) // well, duh. But sanity check, I guess.

v.Pow() // check that your IDE can autocomplete this, too. it should.

// this is all the semantics we wanted; awesome.
//
// still unfortunate: Pow won't show up in docs, since it's on an unexported type.

// exporting an alias of the non-pointer makes a hole in your guarantees, of course:
var hmm nozeros.ExportedPtr
hmm = &nozeros.ExportedAlias{}
_ = hmm
}

func TestStranger(t *testing.T) {
var foo nozeros.Foo
// foo = &nozeros.FooData{} // undesirable
// NOPE! (Success!)

foo = nozeros.Foo(nil) // possible, yes. but fairly irrelevant.
_ = foo

v := nozeros.NewFoo("woo")

Wish(t, v.Read(), ShouldEqual, "woo")

v.Pow()

Wish(t, v.Read(), ShouldEqual, "waht")

v.Pow()

t.Logf("%#v", v) // this will log the internal type name, not the exported alias. Arguably not ideal.
}
43 changes: 43 additions & 0 deletions _rsrch/nozeros/nozeros.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package nozeros

type internal struct {
x string
}

func (x *internal) Pow() {}

// func (x ExportedPtr) Pow() {} // no, "invalid receiver type ExportedPtr (ExportedPtr is a pointer type)".
// wait, no, this was only illegal for `type ExportedPtr *internal` -- AHHAH

type ExportedAlias = internal

type ExportedPtr = *internal

// type ExportedPtr *internal // ALMOST works...
// except somewhat bizarrely, 'Pow()' becomes undefined and invisible on the exported type.
// As far as I can tell, aside from that, it's identical to using the alias.

func NewExportedPtr(v string) ExportedPtr {
return &internal{v}
}

// ---

type FooData struct {
x string
}

func (x Foo) Pow() {
x.x = "waht"
}
func (x Foo) Read() string {
return x.x
}

type foo FooData

type Foo = *foo

func NewFoo(v string) Foo {
return &foo{v}
}
50 changes: 49 additions & 1 deletion errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,55 @@ func (e ErrRepeatedMapKey) Error() string {
return fmt.Sprintf("cannot repeat map key (\"%s\")", e.Key)
}

// ErrInvalidKey indicates a key is invalid for some reason.
//
// This is only possible for typed nodes; specifically, it may show up when
// handling struct types, or maps with interesting key types.
// (Other kinds of key invalidity that happen for untyped maps
// fall under ErrRepeatedMapKey or ErrWrongKind.)
// (Union types use ErrInvalidUnionDiscriminant instead of ErrInvalidKey,
// even when their representation strategy is maplike.)
type ErrInvalidKey struct {
// TypeName will indicate the named type of a node the function was called on.
TypeName string

// Key is the key that was rejected.
Key Node

// Reason, if set, may provide details (for example, the reason a key couldn't be converted to a type).
// If absent, it'll be presumed "no such field".
// ErrUnmatchable may show up as a reason for typed maps with complex keys.
Reason error
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add Unwrap() error { return e.Reason } for use with Is and As

}

func (e ErrInvalidKey) Error() string {
if e.Reason == nil {
return fmt.Sprintf("invalid key for map %s: \"%s\": no such field", e.TypeName, e.Key)
} else {
return fmt.Sprintf("invalid key for map %s: \"%s\": %s", e.TypeName, e.Key, e.Reason)
}
}

// ErrUnmatchable is the catch-all type for parse errors in schema representation work.
//
// REVIEW: are builders at type level ever going to return this? i don't think so.
// REVIEW: can this ever be triggered during the marshalling direction? perhaps not.
// REVIEW: do things like ErrWrongKind end up being wrapped by this? that doesn't seem pretty.
// REVIEW: do natural representations ever trigger this? i don't think so. maybe that's a hint towards a better name.
// REVIEW: are user validation functions encouraged to return this? or something else?
//
type ErrUnmatchable struct {
// TypeName will indicate the named type of a node the function was called on.
TypeName string

// Reason must always be present. ErrUnmatchable doesn't say much otherwise.
Reason error
}

func (e ErrUnmatchable) Error() string {
return fmt.Sprintf("parsing of %s rejected: %s", e.TypeName, e.Reason)
}

// ErrIteratorOverread is returned when calling 'Next' on a MapIterator or
// ListIterator when it is already done.
type ErrIteratorOverread struct{}
Expand All @@ -80,7 +129,6 @@ func (e ErrIteratorOverread) Error() string {

type ErrCannotBeNull struct{} // Review: arguably either ErrInvalidKindForNodeStyle.

type ErrInvalidStructKey struct{} // only possible for typed nodes -- specifically, struct types.
type ErrMissingRequiredField struct{} // only possible for typed nodes -- specifically, struct types.
type ErrListOverrun struct{} // only possible for typed nodes -- specifically, struct types with list (aka tuple) representations.
type ErrInvalidUnionDiscriminant struct{} // only possible for typed nodes -- specifically, union types.
9 changes: 9 additions & 0 deletions kind.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,12 @@ func (x ReprKindSet) String() string {
s += x[len(x)-1].String()
return s
}

func (x ReprKindSet) Contains(e ReprKind) bool {
for _, v := range x {
if v == e {
return true
}
}
return false
}
2 changes: 1 addition & 1 deletion module.tl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"action": {
"exec": [
"/bin/bash", "-c",
"export PATH=$PATH:/app/go/go/bin && export GOPATH=$PWD/.gopath && go test ./..."
"export PATH=$PATH:/app/go/go/bin && export GOPATH=$PWD/.gopath && go test -tags 'skipgenbehavtests' ./..."
]
}
}
Expand Down
7 changes: 4 additions & 3 deletions node/basic/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,18 @@ func (plainList__Assembler) AssignLink(ipld.Link) error {
}
func (na *plainList__Assembler) AssignNode(v ipld.Node) error {
// Sanity check, then update, assembler state.
// Update of state to 'finished' comes later; where exactly depends on if shortcuts apply.
if na.state != laState_initial {
panic("misuse")
}
na.state = laState_finished
// Copy the content.
if v2, ok := v.(*plainList); ok { // if our own type: shortcut.
// Copy the structure by value.
// This means we'll have pointers into the same internal maps and slices;
// this is okay, because the Node type promises it's immutable, and we are going to instantly finish ourselves to also maintain that.
// FIXME: the shortcut behaves differently than the long way: it discards any existing progress. Doesn't violate immut, but is odd.
*na.w = *v2
na.state = laState_finished
return nil
}
// If the above shortcut didn't work, resort to a generic copy.
Expand All @@ -209,8 +211,7 @@ func (na *plainList__Assembler) AssignNode(v ipld.Node) error {
return err
}
}
// validators could run and report errors promptly, if this type had any -- same as for regular Finish.
return nil
return na.Finish()
}
func (plainList__Assembler) Style() ipld.NodeStyle {
return Style__List{}
Expand Down
Loading