mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-05 02:59:44 -06:00
Get rid of UnionKind
As arv pointed out, the parser should no longer generate TypeRefs of UnionKind, so I made it stop doing that. Getting rid of UnionKind has the side effect of making UnionDesc no longer capable of satisfying TypeDesc, so one can no longer create a TypeRef that holds a UnionDesc. That's correct for production, but I'd been using Field structs (which contain a TypeRef) to define my test cases. Since I still need to test that the parser correctly handles named union fields in structs, and Field structs are no longer capable of expressing that, I needed to create a new testField struct and some attendant types to allow me to write all my test cases.
This commit is contained in:
@@ -40,12 +40,6 @@ Package <- _ dd:Definition+ _ EOF {
|
||||
if _, present := named[d.Name]; present {
|
||||
return nil, fmt.Errorf("Redefinition of enum " + d.Name)
|
||||
}
|
||||
if d.Desc.Kind() == StructKind {
|
||||
namedUnions := d.Desc.(StructDesc).GetNamedUnions()
|
||||
for i, u := range namedUnions {
|
||||
d.Desc.(StructDesc).Fields[i].T = makeStructTypeRef("", nil, u)
|
||||
}
|
||||
}
|
||||
named[d.Name] = d
|
||||
}
|
||||
}
|
||||
@@ -130,7 +124,7 @@ Type <- t:(PrimitiveType / CompoundType / Union / NamespaceIdent) {
|
||||
case TypeRef:
|
||||
return t, nil
|
||||
case UnionDesc:
|
||||
return TypeRef{Desc:t}, nil
|
||||
return makeStructTypeRef("", nil, &t), nil
|
||||
case namespaceIdent:
|
||||
return TypeRef{PkgRef:t.Namespace, Name:t.ID}, nil
|
||||
default:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -100,7 +100,6 @@ const (
|
||||
MapKind
|
||||
RefKind
|
||||
SetKind
|
||||
UnionKind
|
||||
EnumKind
|
||||
StructKind
|
||||
)
|
||||
@@ -236,32 +235,13 @@ func (e EnumDesc) describe() string {
|
||||
return "enum: { " + strings.Join(e.IDs, "\n") + "}\n"
|
||||
}
|
||||
|
||||
func makeUnionTypeRef(c []Field) TypeRef {
|
||||
return TypeRef{Desc: UnionDesc{c}}
|
||||
}
|
||||
|
||||
// UnionDesc represents each choice as a Field, akin to a StructDesc.
|
||||
// NB: UnionDesc DOES NOT SATISFY TypeDesc, as Union is not a first-class Noms Type.
|
||||
type UnionDesc struct {
|
||||
Choices []Field
|
||||
}
|
||||
|
||||
func (u UnionDesc) Kind() NomsKind {
|
||||
return UnionKind
|
||||
}
|
||||
|
||||
func (u UnionDesc) Equals(other TypeDesc) bool {
|
||||
if u.Kind() != other.Kind() || len(u.Choices) != len(other.(UnionDesc).Choices) {
|
||||
return false
|
||||
}
|
||||
for i, c := range other.(UnionDesc).Choices {
|
||||
if !u.Choices[i].Equals(c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (u UnionDesc) describe() (out string) {
|
||||
func (u *UnionDesc) describe() (out string) {
|
||||
out = "union {\n"
|
||||
for _, c := range u.Choices {
|
||||
out += fmt.Sprintf(" %s :%s\n", c.Name, c.T.describe())
|
||||
@@ -307,21 +287,9 @@ func (s StructDesc) Equals(other TypeDesc) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetNamedUnions returns a map of field index to TypeDesc for all named union fields in s.
|
||||
func (s StructDesc) GetNamedUnions() map[int]*UnionDesc {
|
||||
structs := map[int]*UnionDesc{}
|
||||
for i, f := range s.Fields {
|
||||
if u, ok := f.T.Desc.(UnionDesc); ok {
|
||||
structs[i] = &u
|
||||
}
|
||||
}
|
||||
return structs
|
||||
}
|
||||
|
||||
func (s StructDesc) describe() (out string) {
|
||||
out = ""
|
||||
if len(s.Union.Choices) != 0 {
|
||||
out += fmt.Sprintf(" anon %s\n", s.Union.describe())
|
||||
if s.Union != nil {
|
||||
out += s.Union.describe()
|
||||
}
|
||||
for _, f := range s.Fields {
|
||||
out += fmt.Sprintf(" %s: %s\n", f.Name, f.T.describe())
|
||||
|
||||
@@ -126,31 +126,31 @@ func (suite *ParserTestSuite) TestEnum() {
|
||||
type ParsedResultTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
primField Field
|
||||
compoundField Field
|
||||
compoundOfCompoundField Field
|
||||
mapOfNamedTypeField Field
|
||||
namedTypeField Field
|
||||
namespacedTypeField Field
|
||||
primField testField
|
||||
compoundField testField
|
||||
compoundOfCompoundField testField
|
||||
mapOfNamedTypeField testField
|
||||
namedTypeField testField
|
||||
namespacedTypeField testField
|
||||
union UnionDesc
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) SetupTest() {
|
||||
suite.primField = Field{"a", makePrimitiveTypeRef("Int64")}
|
||||
suite.compoundField = Field{"set", makeCompoundTypeRef(SetKind, []TypeRef{makePrimitiveTypeRef("String")})}
|
||||
suite.compoundOfCompoundField = Field{
|
||||
suite.primField = testField{"a", makePrimitiveTypeRef("Int64")}
|
||||
suite.compoundField = testField{"set", makeCompoundTypeRef(SetKind, []TypeRef{makePrimitiveTypeRef("String")})}
|
||||
suite.compoundOfCompoundField = testField{
|
||||
"listOfSet",
|
||||
makeCompoundTypeRef(ListKind, []TypeRef{
|
||||
makeCompoundTypeRef(SetKind, []TypeRef{makePrimitiveTypeRef("String")})})}
|
||||
suite.mapOfNamedTypeField = Field{
|
||||
suite.mapOfNamedTypeField = testField{
|
||||
"mapOfStructToOther",
|
||||
makeCompoundTypeRef(MapKind, []TypeRef{
|
||||
makeTypeRef("", "Struct"),
|
||||
makeTypeRef("Elsewhere", "Other"),
|
||||
}),
|
||||
}
|
||||
suite.namedTypeField = Field{"otherStruct", makeTypeRef("", "Other")}
|
||||
suite.namespacedTypeField = Field{"namespacedStruct", makeTypeRef("Elsewhere", "Other")}
|
||||
suite.namedTypeField = testField{"otherStruct", makeTypeRef("", "Other")}
|
||||
suite.namespacedTypeField = testField{"namespacedStruct", makeTypeRef("Elsewhere", "Other")}
|
||||
suite.union = UnionDesc{[]Field{
|
||||
Field{"a", makePrimitiveTypeRef("Int32")},
|
||||
Field{"n", makeTypeRef("NN", "Other")},
|
||||
@@ -158,70 +158,87 @@ func (suite *ParsedResultTestSuite) SetupTest() {
|
||||
}}
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) toText(s TypeRef) string {
|
||||
suite.Equal(StructKind, s.Desc.Kind())
|
||||
desc := s.Desc.(StructDesc)
|
||||
return fmt.Sprintf(structTmpl, s.Name, desc.fieldsToString(), desc.unionToString())
|
||||
type structTestCase struct {
|
||||
Name string
|
||||
Union *UnionDesc
|
||||
Fields []testField
|
||||
}
|
||||
|
||||
func (s StructDesc) fieldsToString() (out string) {
|
||||
func makeStructTestCase(n string, u *UnionDesc, fields ...testField) structTestCase {
|
||||
return structTestCase{n, u, fields}
|
||||
}
|
||||
|
||||
func (s structTestCase) toText() string {
|
||||
return fmt.Sprintf(structTmpl, s.Name, s.fieldsToString(), s.unionToString())
|
||||
}
|
||||
|
||||
func (s structTestCase) fieldsToString() (out string) {
|
||||
for _, f := range s.Fields {
|
||||
out += f.Name + " :" + f.T.describe() + "\n"
|
||||
out += f.Name + " :" + f.D.describe() + "\n"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s StructDesc) unionToString() string {
|
||||
func (s structTestCase) unionToString() string {
|
||||
if s.Union == nil {
|
||||
return ""
|
||||
}
|
||||
return s.Union.describe()
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) checkStruct(pkg Package, str TypeRef) {
|
||||
suite.Equal(StructKind, str.Desc.Kind())
|
||||
strFields := str.Desc.(StructDesc).Fields
|
||||
strUnion := str.Desc.(StructDesc).Union
|
||||
type testField struct {
|
||||
Name string
|
||||
D describable
|
||||
}
|
||||
|
||||
typ := pkg.NamedTypes[str.Name]
|
||||
func (t testField) toField() Field {
|
||||
return Field{t.Name, t.D.(TypeRef)}
|
||||
}
|
||||
|
||||
type describable interface {
|
||||
describe() string
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) checkStruct(pkg Package, s structTestCase) {
|
||||
typ := pkg.NamedTypes[s.Name]
|
||||
typFields := typ.Desc.(StructDesc).Fields
|
||||
typUnion := typ.Desc.(StructDesc).Union
|
||||
|
||||
suite.Equal(str.Name, typ.Name)
|
||||
suite.Len(typFields, len(strFields))
|
||||
for i, f := range strFields {
|
||||
suite.Equal(s.Name, typ.Name)
|
||||
suite.Len(typFields, len(s.Fields))
|
||||
for i, f := range s.Fields {
|
||||
// Named unions are syntactic sugar for a struct Field that points to an anonymous struct containing an anonymous union.
|
||||
// So, if the field in the input was of UnionKind...
|
||||
if f.T.Desc != nil && f.T.Desc.Kind() == UnionKind {
|
||||
// So, if the field in the test input was a union...
|
||||
if desc, ok := f.D.(*UnionDesc); ok {
|
||||
// ...make sure the names are the same...
|
||||
suite.Equal(f.Name, typFields[i].Name)
|
||||
if tfd, ok := typFields[i].T.Desc.(StructDesc); ok {
|
||||
// ...and that the IR has a TypeRef of StructKind with no fields, but an anonymous union.
|
||||
suite.Len(tfd.Fields, 0)
|
||||
suite.NotNil(tfd.Union)
|
||||
suite.EqualValues(f.T.Desc, tfd.Union)
|
||||
suite.EqualValues(desc, tfd.Union)
|
||||
} else {
|
||||
suite.Fail("Named unions must be parsed as anonymous structs containing an anonymous union.", "%#v", typFields[i])
|
||||
}
|
||||
} else {
|
||||
suite.EqualValues(f, typFields[i])
|
||||
suite.EqualValues(s.Fields[i].toField(), typFields[i])
|
||||
}
|
||||
}
|
||||
if strUnion != nil && suite.NotNil(typUnion) {
|
||||
suite.Len(typUnion.Choices, len(strUnion.Choices))
|
||||
for i := range strUnion.Choices {
|
||||
suite.EqualValues(strUnion.Choices[i], typUnion.Choices[i])
|
||||
if s.Union != nil && suite.NotNil(typUnion) {
|
||||
suite.Len(typUnion.Choices, len(s.Union.Choices))
|
||||
for i := range s.Union.Choices {
|
||||
suite.EqualValues(s.Union.Choices[i], typUnion.Choices[i])
|
||||
}
|
||||
} else {
|
||||
suite.EqualValues(strUnion, typUnion, "If strUnion is nil, so should typUnion be.")
|
||||
suite.EqualValues(s.Union, typUnion, "If s.Union is nil, so should typUnion be.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) parseAndCheckStructs(structs ...TypeRef) {
|
||||
func (suite *ParsedResultTestSuite) parseAndCheckStructs(structs ...structTestCase) {
|
||||
pkgDef := ""
|
||||
for _, s := range structs {
|
||||
pkgDef += suite.toText(s) + "\n"
|
||||
pkgDef += s.toText() + "\n"
|
||||
}
|
||||
err := d.Try(func() {
|
||||
pkg := ParsePackage("", strings.NewReader(pkgDef))
|
||||
@@ -233,89 +250,89 @@ func (suite *ParsedResultTestSuite) parseAndCheckStructs(structs ...TypeRef) {
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestPrimitiveField() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("Simple", []Field{suite.primField}, nil))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("Simple", nil, suite.primField))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestAnonUnion() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("WithAnon", []Field{suite.primField}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("WithAnon", &suite.union, suite.primField))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestAnonUnionFirst() {
|
||||
anonUnionFirstRef := makeStructTypeRef("WithAnonFirst", []Field{suite.primField}, &suite.union)
|
||||
anonUnionFirst := makeStructTestCase("WithAnonFirst", &suite.union, suite.primField)
|
||||
|
||||
pkgDef := fmt.Sprintf(structTmpl, anonUnionFirstRef.Name, anonUnionFirstRef.Desc.(StructDesc).unionToString(), anonUnionFirstRef.Desc.(StructDesc).fieldsToString())
|
||||
pkgDef := fmt.Sprintf(structTmpl, anonUnionFirst.Name, anonUnionFirst.unionToString(), anonUnionFirst.fieldsToString())
|
||||
err := d.Try(func() {
|
||||
pkg := ParsePackage("", strings.NewReader(pkgDef))
|
||||
suite.checkStruct(pkg, anonUnionFirstRef)
|
||||
suite.checkStruct(pkg, anonUnionFirst)
|
||||
})
|
||||
suite.NoError(err, pkgDef)
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestCompoundField() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("Compound", []Field{suite.compoundField}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("Compound", &suite.union, suite.compoundField))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestCompoundOfCompoundField() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("CofC", []Field{suite.compoundOfCompoundField}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("CofC", &suite.union, suite.compoundOfCompoundField))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestNamedTypeField() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("Named", []Field{suite.namedTypeField}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("Named", &suite.union, suite.namedTypeField))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestNamespacedTypeField() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("Namespaced", []Field{suite.namespacedTypeField}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("Namespaced", &suite.union, suite.namespacedTypeField))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestMapOfNamedTypeField() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("MapStruct", []Field{suite.mapOfNamedTypeField}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("MapStruct", &suite.union, suite.mapOfNamedTypeField))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestMultipleFields() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("Multi", []Field{
|
||||
Field{suite.primField.Name, suite.primField.T},
|
||||
Field{suite.namedTypeField.Name, suite.namedTypeField.T},
|
||||
Field{suite.namespacedTypeField.Name, suite.namespacedTypeField.T},
|
||||
Field{suite.compoundField.Name, suite.compoundField.T},
|
||||
Field{suite.compoundOfCompoundField.Name, suite.compoundOfCompoundField.T},
|
||||
Field{"namedUnion", TypeRef{Desc: &suite.union}},
|
||||
}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("Multi", &suite.union,
|
||||
suite.primField,
|
||||
suite.namedTypeField,
|
||||
suite.namespacedTypeField,
|
||||
suite.compoundField,
|
||||
suite.compoundOfCompoundField,
|
||||
testField{"namedUnion", &suite.union},
|
||||
))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestNamedAndAnonUnion() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("NamedAndAnon", []Field{
|
||||
Field{"namedUnion", TypeRef{Desc: &suite.union}},
|
||||
}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("NamedAndAnon", &suite.union,
|
||||
testField{"namedUnion", &suite.union},
|
||||
))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestNamedUnionOnly() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("NamedUnionOnly", []Field{
|
||||
Field{"namedUnion", TypeRef{Desc: &suite.union}},
|
||||
}, nil))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("NamedUnionOnly", nil,
|
||||
testField{"namedUnion", &suite.union},
|
||||
))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestTwoNamedAndAnonUnion() {
|
||||
suite.parseAndCheckStructs(makeStructTypeRef("TwoNamedAndAnon", []Field{
|
||||
Field{"namedUnion1", TypeRef{Desc: &suite.union}},
|
||||
Field{"namedUnion2", TypeRef{Desc: &suite.union}},
|
||||
}, &suite.union))
|
||||
suite.parseAndCheckStructs(makeStructTestCase("TwoNamedAndAnon", &suite.union,
|
||||
testField{"namedUnion1", &suite.union},
|
||||
testField{"namedUnion2", &suite.union},
|
||||
))
|
||||
}
|
||||
|
||||
func (suite *ParsedResultTestSuite) TestMultipleStructs() {
|
||||
defns := []TypeRef{
|
||||
makeStructTypeRef("Simple", []Field{suite.primField}, nil),
|
||||
makeStructTypeRef("Compound", []Field{suite.compoundField}, nil),
|
||||
makeStructTypeRef("CompoundWithUnion", []Field{suite.compoundField}, &suite.union),
|
||||
makeStructTypeRef("TwoNamedAndAnon", []Field{
|
||||
Field{"namedUnion1", TypeRef{Desc: &suite.union}},
|
||||
Field{"namedUnion2", TypeRef{Desc: &suite.union}},
|
||||
}, &suite.union),
|
||||
makeStructTypeRef("Multi", []Field{
|
||||
Field{suite.primField.Name, suite.primField.T},
|
||||
Field{suite.namespacedTypeField.Name, suite.namespacedTypeField.T},
|
||||
Field{suite.compoundField.Name, suite.compoundField.T},
|
||||
Field{"namedUnion", TypeRef{Desc: &suite.union}},
|
||||
}, &suite.union),
|
||||
defns := []structTestCase{
|
||||
makeStructTestCase("Simple", nil, suite.primField),
|
||||
makeStructTestCase("Compound", nil, suite.compoundField),
|
||||
makeStructTestCase("CompoundWithUnion", &suite.union, suite.compoundField),
|
||||
makeStructTestCase("TwoNamedAndAnon", &suite.union,
|
||||
testField{"namedUnion1", &suite.union},
|
||||
testField{"namedUnion2", &suite.union},
|
||||
),
|
||||
makeStructTestCase("Multi", &suite.union,
|
||||
suite.primField,
|
||||
suite.namespacedTypeField,
|
||||
suite.compoundField,
|
||||
testField{"namedUnion", &suite.union},
|
||||
),
|
||||
}
|
||||
suite.parseAndCheckStructs(defns...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user