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

Add TypeDef support, minor tweaks to XML output (to match XSD) #5

Merged
merged 6 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 17 additions & 1 deletion db/datatypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func (h *Host) indexDataTypeModels(cxt context.Context, parent *sectionInfo, clu
h.indexBitmaps(cluster, parent)
h.indexEnums(cluster, parent)
h.indexStructs(cluster, parent)
h.indexTypeDefs(cluster, parent)
return nil
}

Expand Down Expand Up @@ -55,6 +56,16 @@ func (h *Host) indexEnums(cluster *matter.Cluster, parent *sectionInfo) {
}
}
}
func (h *Host) indexTypeDefs(cluster *matter.Cluster, parent *sectionInfo) {
for _, t := range cluster.TypeDefs {
row := newDBRow()
row.values[matter.TableColumnName] = t.Name
row.values[matter.TableColumnType] = t.Type.Name
row.values[matter.TableColumnDescription] = t.Description
ei := &sectionInfo{id: h.nextID(typedefTable), parent: parent, values: row, children: make(map[string][]*sectionInfo)}
parent.children[typedefTable] = append(parent.children[typedefTable], ei)
}
}

func (h *Host) readField(f *matter.Field, parent *sectionInfo, tableName string, entityType types.EntityType) {
sr := newDBRow()
Expand Down Expand Up @@ -93,7 +104,7 @@ func (h *Host) indexDataTypes(cxt context.Context, doc *spec.Doc, ds *sectionInf
}
for _, s := range parse.Skim[*spec.Section](dts.Elements()) {
switch s.SecType {
case matter.SectionDataTypeBitmap, matter.SectionDataTypeEnum, matter.SectionDataTypeStruct:
case matter.SectionDataTypeBitmap, matter.SectionDataTypeEnum, matter.SectionDataTypeStruct, matter.SectionDataTypeDef:
var t string
switch s.SecType {
case matter.SectionDataTypeBitmap:
Expand All @@ -102,6 +113,8 @@ func (h *Host) indexDataTypes(cxt context.Context, doc *spec.Doc, ds *sectionInf
t = "enum"
case matter.SectionDataTypeStruct:
t = "struct"
case matter.SectionDataTypeDef:
t = "typedef"
}
name := text.TrimCaseInsensitiveSuffix(s.Name, " Type")
name = matter.StripDataTypeSuffixes(name)
Expand All @@ -128,6 +141,9 @@ func (h *Host) indexDataTypes(cxt context.Context, doc *spec.Doc, ds *sectionInf
ci.id = h.nextID(structTable)
err = h.readTableSection(cxt, doc, ci, s, structField)
ds.children[structTable] = append(ds.children[structTable], ci)
case matter.SectionDataTypeDef:
ci.id = h.nextID(typedefTable)
ds.children[typedefTable] = append(ds.children[typedefTable], ci)
}
if err != nil {
return
Expand Down
9 changes: 9 additions & 0 deletions db/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var (
deviceTypeRevisionTable = "device_type_revision"
deviceTypeConditionTable = "device_type_condition"
deviceTypeClusterRequirementTable = "device_type_cluster_requirement"
typedefTable = "typedef"
)

type tableSchemaDef struct {
Expand Down Expand Up @@ -115,6 +116,14 @@ var tableSchema = map[string]tableSchemaDef{
matter.TableColumnConformance,
},
},
typedefTable: {
parent: clusterTable,
columns: []matter.TableColumn{
matter.TableColumnName,
matter.TableColumnDescription,
matter.TableColumnType,
},
},
attributeTable: {
parent: clusterTable,
columns: []matter.TableColumn{
Expand Down
5 changes: 3 additions & 2 deletions errata/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ const (
SpecPurposeCluster = 1 << (iota - 1)
SpecPurposeDeviceType = 1 << (iota - 1)
SpecPurposeCommandArguments = 1 << (iota - 1)
SpecPurposeDataTypesDef = 1 << (iota - 1)

SpecPurposeDataTypes SpecPurpose = SpecPurposeDataTypesBitmap | SpecPurposeDataTypesEnum | SpecPurposeDataTypesStruct
SpecPurposeAll SpecPurpose = SpecPurposeDataTypesBitmap | SpecPurposeDataTypesEnum | SpecPurposeDataTypesStruct | SpecPurposeCluster | SpecPurposeDeviceType | SpecPurposeCommandArguments
SpecPurposeDataTypes SpecPurpose = SpecPurposeDataTypesBitmap | SpecPurposeDataTypesEnum | SpecPurposeDataTypesStruct | SpecPurposeDataTypesDef
SpecPurposeAll SpecPurpose = SpecPurposeDataTypes | SpecPurposeCluster | SpecPurposeDeviceType | SpecPurposeCommandArguments
)

var specPurposes = map[string]SpecPurpose{
Expand Down
1 change: 1 addition & 0 deletions matter/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ type Cluster struct {

Features *Features `json:"features,omitempty"`
AssociatedDataTypes
TypeDefs TypeDefSet `json:"typedefs,omitempty"`
Attributes FieldSet `json:"attributes,omitempty"`
Events EventSet `json:"events,omitempty"`
Commands CommandSet `json:"commands,omitempty"`
Expand Down
5 changes: 4 additions & 1 deletion matter/sections.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
SectionDerivedClusterNamespace
SectionModeTags
SectionGlobalElements
SectionDataTypeDef
)

var TopLevelSectionOrders = map[DocType][]Section{
Expand Down Expand Up @@ -67,7 +68,7 @@ var TopLevelSectionOrders = map[DocType][]Section{
},
}

var DataTypeSectionOrder = []Section{SectionPrefix, SectionDataTypeBitmap, SectionDataTypeEnum, SectionDataTypeStruct}
var DataTypeSectionOrder = []Section{SectionPrefix, SectionDataTypeBitmap, SectionDataTypeEnum, SectionDataTypeStruct, SectionDataTypeDef}

var sectionTypeStrings = map[Section]string{
SectionPrefix: "Prefix",
Expand All @@ -85,6 +86,7 @@ var sectionTypeStrings = map[Section]string{
SectionDataTypeBitmap: "Bitmap",
SectionDataTypeEnum: "Enum",
SectionDataTypeStruct: "Struct",
SectionDataTypeDef: "TypeDef",
SectionDeviceType: "DeviceType",
SectionStatusCodes: "StatusCodes",
SectionAttributes: "Attributes",
Expand Down Expand Up @@ -130,6 +132,7 @@ var sectionTypeNames = map[Section]string{
SectionDataTypeBitmap: "Bitmap",
SectionDataTypeEnum: "Enum",
SectionDataTypeStruct: "Struct",
SectionDataTypeDef: "Type Definition",
SectionDeviceType: "Device Type",
SectionStatusCodes: "Status Codes",
SectionAttributes: "Attributes",
Expand Down
10 changes: 10 additions & 0 deletions matter/spec/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,16 @@ func addClusterToSpec(spec *Specification, d *Doc, m *matter.Cluster) {
spec.DocRefs[en] = d
spec.addEntityByName(en.Name, en, m)
}
for _, en := range m.TypeDefs {
_, ok := spec.typeDefIndex[en.Name]
if ok {
slog.Debug("multiple structs with same name", "name", en.Name)
} else {
spec.typeDefIndex[en.Name] = en
}
spec.DocRefs[en] = d
spec.addEntityByName(en.Name, en, m)
}
}

func (sp *Builder) resolveDataTypeReferences(spec *Specification) {
Expand Down
14 changes: 13 additions & 1 deletion matter/spec/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,20 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
var bitmaps matter.BitmapSet
var enums matter.EnumSet
var structs matter.StructSet
var typedefs matter.TypeDefSet
for _, s := range elements {
switch s.SecType {
case matter.SectionDataTypes, matter.SectionStatusCodes:
var bs matter.BitmapSet
var es matter.EnumSet
var ss matter.StructSet
bs, es, ss, err = s.toDataTypes(d, entityMap)
var ts matter.TypeDefSet
bs, es, ss, ts, err = s.toDataTypes(d, entityMap)
if err == nil {
bitmaps = append(bitmaps, bs...)
enums = append(enums, es...)
structs = append(structs, ss...)
typedefs = append(typedefs, ts...)
}
case matter.SectionFeatures:
features, err = s.toFeatures(d, entityMap)
Expand Down Expand Up @@ -90,6 +93,7 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
c.AddBitmaps(bitmaps...)
c.AddEnums(enums...)
c.AddStructs(structs...)
c.TypeDefs = append(c.TypeDefs, typedefs...)
gmarcosb marked this conversation as resolved.
Show resolved Hide resolved
c.Features = features

for _, s := range elements {
Expand Down Expand Up @@ -137,6 +141,8 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
c.AddEnums(le)
case *matter.Struct:
c.AddStructs(le)
case *matter.TypeDef:
c.TypeDefs = append(c.TypeDefs, le)
default:
slog.Warn("unexpected loose entity", log.Element("path", d.Path, s.Base), "entity", le)
}
Expand Down Expand Up @@ -206,6 +212,12 @@ func assignCustomDataType(c *matter.Cluster, dt *types.DataType) {
return
}
}
for _, t := range c.TypeDefs {
if name == t.Name {
dt.Entity = t
return
}
}
slog.Debug("unable to find data type for field", slog.String("dataType", name), log.Type("source", dt.Source))
}

Expand Down
14 changes: 12 additions & 2 deletions matter/spec/datatypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"github.com/project-chip/alchemy/matter/types"
)

func (s *Section) toDataTypes(d *Doc, entityMap map[asciidoc.Attributable][]types.Entity) (bitmaps matter.BitmapSet, enums matter.EnumSet, structs matter.StructSet, err error) {
func (s *Section) toDataTypes(d *Doc, entityMap map[asciidoc.Attributable][]types.Entity) (bitmaps matter.BitmapSet, enums matter.EnumSet, structs matter.StructSet, typedefs matter.TypeDefSet, err error) {

traverse(d, s, errata.SpecPurposeDataTypes, func(s *Section, parent parse.HasElements, index int) parse.SearchShould {
switch s.SecType {
Expand Down Expand Up @@ -47,6 +47,16 @@ func (s *Section) toDataTypes(d *Doc, entityMap map[asciidoc.Attributable][]type
} else {
structs = append(structs, me)
}
case matter.SectionDataTypeDef:
var me *matter.TypeDef
me, err = s.toTypeDef(d, entityMap)
if err != nil {
slog.Warn("Error converting section to typedef", log.Element("path", d.Path, s.Base), slog.Any("error", err))
err = nil
} else {
typedefs = append(typedefs, me)
entityMap[s.Base] = append(entityMap[s.Base], me)
}
default:
}
return parse.SearchShouldContinue
Expand Down Expand Up @@ -140,7 +150,7 @@ func (d *Doc) readFields(ti *TableInfo, entityType types.EntityType) (fields []*
return
}

var listDataTypeDefinitionPattern = regexp.MustCompile(`(?:list|List|DataTypeList)\[([^\]]+)\]`)
var listDataTypeDefinitionPattern = regexp.MustCompile(`(?:list|List|DataTypeList)\[([^]]+)]`)
var asteriskPattern = regexp.MustCompile(`\^[0-9]+\^\s*$`)

func (d *Doc) ReadRowDataType(row *asciidoc.TableRow, columnMap ColumnIndex, column matter.TableColumn) (*types.DataType, error) {
Expand Down
9 changes: 9 additions & 0 deletions matter/spec/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ func addGlobalEntities(spec *Specification, doc *Doc) error {
spec.structIndex[m.Name] = m
}
spec.addEntityByName(m.Name, m, nil)
case *matter.TypeDef:
slog.Debug("Found global typedef", "name", m.Name, "path", doc.Path)
_, ok := spec.typeDefIndex[m.Name]
if ok {
slog.Warn("multiple global typedefs with same name", "name", m.Name)
} else {
spec.typeDefIndex[m.Name] = m
}
spec.addEntityByName(m.Name, m, nil)
case *matter.Command:
_, ok := spec.commandIndex[m.Name]
if ok {
Expand Down
17 changes: 15 additions & 2 deletions matter/spec/section.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func AssignSectionTypes(doc *Doc, top *Section) error {

assignSectionType(doc, section, getSectionType(ps, section))
switch section.SecType {
case matter.SectionDataTypeBitmap, matter.SectionDataTypeEnum, matter.SectionDataTypeStruct:
case matter.SectionDataTypeBitmap, matter.SectionDataTypeEnum, matter.SectionDataTypeStruct, matter.SectionDataTypeDef:
if section.Base.Level > 2 {
slog.Debug("Unusual depth for section type", slog.String("name", section.Name), slog.String("type", section.SecType.String()), slog.String("path", doc.Path.String()))
}
Expand All @@ -177,6 +177,8 @@ func assignSectionType(doc *Doc, s *Section, sectionType matter.Section) {
ignore = doc.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeDataTypesEnum)
case matter.SectionDataTypeStruct:
ignore = doc.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeDataTypesStruct)
case matter.SectionDataTypeDef:
ignore = doc.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeDataTypesDef)
case matter.SectionCluster:
ignore = doc.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeCluster)
case matter.SectionDeviceType:
Expand Down Expand Up @@ -360,6 +362,8 @@ func deriveSectionType(section *Section, parent *Section) matter.Section {
return matter.SectionDataTypeBitmap
} else if dataType.BaseType == types.BaseDataTypeCustom {
return matter.SectionDataTypeStruct
} else if dataType.BaseType.IsSimple() {
return matter.SectionDataTypeDef
}
}
slog.Debug("unknown section type", "path", section.Doc.Path, "name", name)
Expand Down Expand Up @@ -453,7 +457,7 @@ func (s *Section) toGlobalObjects(d *Doc, entityMap map[asciidoc.Attributable][]
return entities, nil
}

var dataTypeDefinitionPattern = regexp.MustCompile(`is\s+derived\s+from\s+(?:<<enum-def\s*,\s*)?(enum8|enum16|enum32|map8|map16|map32)(?:\s*>>)?`)
var dataTypeDefinitionPattern = regexp.MustCompile(`is\s+derived\s+from\s+(?:<<enum-def\s*,\s*)?(enum8|enum16|enum32|map8|map16|map32|uint8|uint16|uint24|uint32|uint40|uint48|uint56|uint64|int8|int16|int24|int32|int40|int48|int56|int64|string)(?:\s*>>)?`)

func (s *Section) GetDataType() *types.DataType {
var dts string
Expand Down Expand Up @@ -527,6 +531,15 @@ func findLooseEntities(doc *Doc, section *Section, entityMap map[asciidoc.Attrib
} else {
entities = append(entities, s)
}
case matter.SectionDataTypeDef:
var t *matter.TypeDef
t, err = section.toTypeDef(doc, entityMap)
if err != nil {
slog.Warn("Error converting loose section to typedef", log.Element("path", doc.Path, section.Base), slog.Any("error", err))
err = nil
} else {
entities = append(entities, t)
}
case matter.SectionGlobalElements:
var ges []types.Entity
ges, err = section.toGlobalElements(doc, entityMap)
Expand Down
2 changes: 2 additions & 0 deletions matter/spec/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Specification struct {
bitmapIndex map[string]*matter.Bitmap
enumIndex map[string]*matter.Enum
structIndex map[string]*matter.Struct
typeDefIndex map[string]*matter.TypeDef
commandIndex map[string]*matter.Command
eventIndex map[string]*matter.Event

Expand All @@ -48,6 +49,7 @@ func newSpec() *Specification {
bitmapIndex: make(map[string]*matter.Bitmap),
enumIndex: make(map[string]*matter.Enum),
structIndex: make(map[string]*matter.Struct),
typeDefIndex: make(map[string]*matter.TypeDef),
commandIndex: make(map[string]*matter.Command),
eventIndex: make(map[string]*matter.Event),

Expand Down
25 changes: 25 additions & 0 deletions matter/spec/typedef.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package spec

import (
"fmt"

"github.com/project-chip/alchemy/asciidoc"
"github.com/project-chip/alchemy/internal/text"
"github.com/project-chip/alchemy/matter"
"github.com/project-chip/alchemy/matter/types"
)

func (s *Section) toTypeDef(d *Doc, entityMap map[asciidoc.Attributable][]types.Entity) (ms *matter.TypeDef, err error) {
name := text.TrimCaseInsensitiveSuffix(s.Name, " Type")
ms = matter.NewTypeDef(s.Base)
ms.Name = name

dt := s.GetDataType()
if (dt == nil) || !dt.BaseType.IsSimple() {
return nil, fmt.Errorf("unknown typedef data type: %s", dt.Name)
}
ms.Type = dt
entityMap[s.Base] = append(entityMap[s.Base], ms)
ms.Name = CanonicalName(ms.Name)
return
}
46 changes: 46 additions & 0 deletions matter/typedef.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package matter

import (
"github.com/project-chip/alchemy/asciidoc"
"github.com/project-chip/alchemy/matter/types"
)

type TypeDef struct {
entity
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Type *types.DataType `json:"type,omitempty"`
}

func NewTypeDef(source asciidoc.Element) *TypeDef {
return &TypeDef{
entity: entity{source: source},
}
}

func (*TypeDef) EntityType() types.EntityType {
return types.EntityTypeDef
}

func (s *TypeDef) Clone() *TypeDef {
ns := &TypeDef{Name: s.Name, Description: s.Description, Type: s.Type}
return ns
}

func (s *TypeDef) Inherit(parent *TypeDef) {
if len(s.Description) == 0 {
s.Description = parent.Description
}
s.Type = s.Type
}

type TypeDefSet []*TypeDef

func (ss TypeDefSet) Identifier(name string) (types.Entity, bool) {
for _, e := range ss {
if e.Name == name {
return e, true
}
}
return nil, false
}
Loading