Skip to content

Commit

Permalink
Merge pull request #5 from gmarcosb/main
Browse files Browse the repository at this point in the history
Add TypeDef support, minor tweaks to XML output (to match XSD)
  • Loading branch information
hasty authored Sep 30, 2024
2 parents 0d8bfe4 + 99e5bb6 commit 2cff917
Show file tree
Hide file tree
Showing 18 changed files with 190 additions and 20 deletions.
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...)
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

0 comments on commit 2cff917

Please sign in to comment.