Skip to content

Commit 2cff917

Browse files
authored
Merge pull request #5 from gmarcosb/main
Add TypeDef support, minor tweaks to XML output (to match XSD)
2 parents 0d8bfe4 + 99e5bb6 commit 2cff917

18 files changed

+190
-20
lines changed

db/datatypes.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func (h *Host) indexDataTypeModels(cxt context.Context, parent *sectionInfo, clu
1515
h.indexBitmaps(cluster, parent)
1616
h.indexEnums(cluster, parent)
1717
h.indexStructs(cluster, parent)
18+
h.indexTypeDefs(cluster, parent)
1819
return nil
1920
}
2021

@@ -55,6 +56,16 @@ func (h *Host) indexEnums(cluster *matter.Cluster, parent *sectionInfo) {
5556
}
5657
}
5758
}
59+
func (h *Host) indexTypeDefs(cluster *matter.Cluster, parent *sectionInfo) {
60+
for _, t := range cluster.TypeDefs {
61+
row := newDBRow()
62+
row.values[matter.TableColumnName] = t.Name
63+
row.values[matter.TableColumnType] = t.Type.Name
64+
row.values[matter.TableColumnDescription] = t.Description
65+
ei := &sectionInfo{id: h.nextID(typedefTable), parent: parent, values: row, children: make(map[string][]*sectionInfo)}
66+
parent.children[typedefTable] = append(parent.children[typedefTable], ei)
67+
}
68+
}
5869

5970
func (h *Host) readField(f *matter.Field, parent *sectionInfo, tableName string, entityType types.EntityType) {
6071
sr := newDBRow()
@@ -93,7 +104,7 @@ func (h *Host) indexDataTypes(cxt context.Context, doc *spec.Doc, ds *sectionInf
93104
}
94105
for _, s := range parse.Skim[*spec.Section](dts.Elements()) {
95106
switch s.SecType {
96-
case matter.SectionDataTypeBitmap, matter.SectionDataTypeEnum, matter.SectionDataTypeStruct:
107+
case matter.SectionDataTypeBitmap, matter.SectionDataTypeEnum, matter.SectionDataTypeStruct, matter.SectionDataTypeDef:
97108
var t string
98109
switch s.SecType {
99110
case matter.SectionDataTypeBitmap:
@@ -102,6 +113,8 @@ func (h *Host) indexDataTypes(cxt context.Context, doc *spec.Doc, ds *sectionInf
102113
t = "enum"
103114
case matter.SectionDataTypeStruct:
104115
t = "struct"
116+
case matter.SectionDataTypeDef:
117+
t = "typedef"
105118
}
106119
name := text.TrimCaseInsensitiveSuffix(s.Name, " Type")
107120
name = matter.StripDataTypeSuffixes(name)
@@ -128,6 +141,9 @@ func (h *Host) indexDataTypes(cxt context.Context, doc *spec.Doc, ds *sectionInf
128141
ci.id = h.nextID(structTable)
129142
err = h.readTableSection(cxt, doc, ci, s, structField)
130143
ds.children[structTable] = append(ds.children[structTable], ci)
144+
case matter.SectionDataTypeDef:
145+
ci.id = h.nextID(typedefTable)
146+
ds.children[typedefTable] = append(ds.children[typedefTable], ci)
131147
}
132148
if err != nil {
133149
return

db/schema.go

+9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var (
2222
deviceTypeRevisionTable = "device_type_revision"
2323
deviceTypeConditionTable = "device_type_condition"
2424
deviceTypeClusterRequirementTable = "device_type_cluster_requirement"
25+
typedefTable = "typedef"
2526
)
2627

2728
type tableSchemaDef struct {
@@ -115,6 +116,14 @@ var tableSchema = map[string]tableSchemaDef{
115116
matter.TableColumnConformance,
116117
},
117118
},
119+
typedefTable: {
120+
parent: clusterTable,
121+
columns: []matter.TableColumn{
122+
matter.TableColumnName,
123+
matter.TableColumnDescription,
124+
matter.TableColumnType,
125+
},
126+
},
118127
attributeTable: {
119128
parent: clusterTable,
120129
columns: []matter.TableColumn{

errata/spec.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ const (
3737
SpecPurposeCluster = 1 << (iota - 1)
3838
SpecPurposeDeviceType = 1 << (iota - 1)
3939
SpecPurposeCommandArguments = 1 << (iota - 1)
40+
SpecPurposeDataTypesDef = 1 << (iota - 1)
4041

41-
SpecPurposeDataTypes SpecPurpose = SpecPurposeDataTypesBitmap | SpecPurposeDataTypesEnum | SpecPurposeDataTypesStruct
42-
SpecPurposeAll SpecPurpose = SpecPurposeDataTypesBitmap | SpecPurposeDataTypesEnum | SpecPurposeDataTypesStruct | SpecPurposeCluster | SpecPurposeDeviceType | SpecPurposeCommandArguments
42+
SpecPurposeDataTypes SpecPurpose = SpecPurposeDataTypesBitmap | SpecPurposeDataTypesEnum | SpecPurposeDataTypesStruct | SpecPurposeDataTypesDef
43+
SpecPurposeAll SpecPurpose = SpecPurposeDataTypes | SpecPurposeCluster | SpecPurposeDeviceType | SpecPurposeCommandArguments
4344
)
4445

4546
var specPurposes = map[string]SpecPurpose{

matter/cluster.go

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ type Cluster struct {
8787

8888
Features *Features `json:"features,omitempty"`
8989
AssociatedDataTypes
90+
TypeDefs TypeDefSet `json:"typedefs,omitempty"`
9091
Attributes FieldSet `json:"attributes,omitempty"`
9192
Events EventSet `json:"events,omitempty"`
9293
Commands CommandSet `json:"commands,omitempty"`

matter/sections.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const (
3939
SectionDerivedClusterNamespace
4040
SectionModeTags
4141
SectionGlobalElements
42+
SectionDataTypeDef
4243
)
4344

4445
var TopLevelSectionOrders = map[DocType][]Section{
@@ -67,7 +68,7 @@ var TopLevelSectionOrders = map[DocType][]Section{
6768
},
6869
}
6970

70-
var DataTypeSectionOrder = []Section{SectionPrefix, SectionDataTypeBitmap, SectionDataTypeEnum, SectionDataTypeStruct}
71+
var DataTypeSectionOrder = []Section{SectionPrefix, SectionDataTypeBitmap, SectionDataTypeEnum, SectionDataTypeStruct, SectionDataTypeDef}
7172

7273
var sectionTypeStrings = map[Section]string{
7374
SectionPrefix: "Prefix",
@@ -85,6 +86,7 @@ var sectionTypeStrings = map[Section]string{
8586
SectionDataTypeBitmap: "Bitmap",
8687
SectionDataTypeEnum: "Enum",
8788
SectionDataTypeStruct: "Struct",
89+
SectionDataTypeDef: "TypeDef",
8890
SectionDeviceType: "DeviceType",
8991
SectionStatusCodes: "StatusCodes",
9092
SectionAttributes: "Attributes",
@@ -130,6 +132,7 @@ var sectionTypeNames = map[Section]string{
130132
SectionDataTypeBitmap: "Bitmap",
131133
SectionDataTypeEnum: "Enum",
132134
SectionDataTypeStruct: "Struct",
135+
SectionDataTypeDef: "Type Definition",
133136
SectionDeviceType: "Device Type",
134137
SectionStatusCodes: "Status Codes",
135138
SectionAttributes: "Attributes",

matter/spec/build.go

+10
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,16 @@ func addClusterToSpec(spec *Specification, d *Doc, m *matter.Cluster) {
231231
spec.DocRefs[en] = d
232232
spec.addEntityByName(en.Name, en, m)
233233
}
234+
for _, en := range m.TypeDefs {
235+
_, ok := spec.typeDefIndex[en.Name]
236+
if ok {
237+
slog.Debug("multiple structs with same name", "name", en.Name)
238+
} else {
239+
spec.typeDefIndex[en.Name] = en
240+
}
241+
spec.DocRefs[en] = d
242+
spec.addEntityByName(en.Name, en, m)
243+
}
234244
}
235245

236246
func (sp *Builder) resolveDataTypeReferences(spec *Specification) {

matter/spec/cluster.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,20 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
4040
var bitmaps matter.BitmapSet
4141
var enums matter.EnumSet
4242
var structs matter.StructSet
43+
var typedefs matter.TypeDefSet
4344
for _, s := range elements {
4445
switch s.SecType {
4546
case matter.SectionDataTypes, matter.SectionStatusCodes:
4647
var bs matter.BitmapSet
4748
var es matter.EnumSet
4849
var ss matter.StructSet
49-
bs, es, ss, err = s.toDataTypes(d, entityMap)
50+
var ts matter.TypeDefSet
51+
bs, es, ss, ts, err = s.toDataTypes(d, entityMap)
5052
if err == nil {
5153
bitmaps = append(bitmaps, bs...)
5254
enums = append(enums, es...)
5355
structs = append(structs, ss...)
56+
typedefs = append(typedefs, ts...)
5457
}
5558
case matter.SectionFeatures:
5659
features, err = s.toFeatures(d, entityMap)
@@ -90,6 +93,7 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
9093
c.AddBitmaps(bitmaps...)
9194
c.AddEnums(enums...)
9295
c.AddStructs(structs...)
96+
c.TypeDefs = append(c.TypeDefs, typedefs...)
9397
c.Features = features
9498

9599
for _, s := range elements {
@@ -137,6 +141,8 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
137141
c.AddEnums(le)
138142
case *matter.Struct:
139143
c.AddStructs(le)
144+
case *matter.TypeDef:
145+
c.TypeDefs = append(c.TypeDefs, le)
140146
default:
141147
slog.Warn("unexpected loose entity", log.Element("path", d.Path, s.Base), "entity", le)
142148
}
@@ -206,6 +212,12 @@ func assignCustomDataType(c *matter.Cluster, dt *types.DataType) {
206212
return
207213
}
208214
}
215+
for _, t := range c.TypeDefs {
216+
if name == t.Name {
217+
dt.Entity = t
218+
return
219+
}
220+
}
209221
slog.Debug("unable to find data type for field", slog.String("dataType", name), log.Type("source", dt.Source))
210222
}
211223

matter/spec/datatypes.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
"github.com/project-chip/alchemy/matter/types"
1717
)
1818

19-
func (s *Section) toDataTypes(d *Doc, entityMap map[asciidoc.Attributable][]types.Entity) (bitmaps matter.BitmapSet, enums matter.EnumSet, structs matter.StructSet, err error) {
19+
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) {
2020

2121
traverse(d, s, errata.SpecPurposeDataTypes, func(s *Section, parent parse.HasElements, index int) parse.SearchShould {
2222
switch s.SecType {
@@ -47,6 +47,16 @@ func (s *Section) toDataTypes(d *Doc, entityMap map[asciidoc.Attributable][]type
4747
} else {
4848
structs = append(structs, me)
4949
}
50+
case matter.SectionDataTypeDef:
51+
var me *matter.TypeDef
52+
me, err = s.toTypeDef(d, entityMap)
53+
if err != nil {
54+
slog.Warn("Error converting section to typedef", log.Element("path", d.Path, s.Base), slog.Any("error", err))
55+
err = nil
56+
} else {
57+
typedefs = append(typedefs, me)
58+
entityMap[s.Base] = append(entityMap[s.Base], me)
59+
}
5060
default:
5161
}
5262
return parse.SearchShouldContinue
@@ -140,7 +150,7 @@ func (d *Doc) readFields(ti *TableInfo, entityType types.EntityType) (fields []*
140150
return
141151
}
142152

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

146156
func (d *Doc) ReadRowDataType(row *asciidoc.TableRow, columnMap ColumnIndex, column matter.TableColumn) (*types.DataType, error) {

matter/spec/global.go

+9
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ func addGlobalEntities(spec *Specification, doc *Doc) error {
4545
spec.structIndex[m.Name] = m
4646
}
4747
spec.addEntityByName(m.Name, m, nil)
48+
case *matter.TypeDef:
49+
slog.Debug("Found global typedef", "name", m.Name, "path", doc.Path)
50+
_, ok := spec.typeDefIndex[m.Name]
51+
if ok {
52+
slog.Warn("multiple global typedefs with same name", "name", m.Name)
53+
} else {
54+
spec.typeDefIndex[m.Name] = m
55+
}
56+
spec.addEntityByName(m.Name, m, nil)
4857
case *matter.Command:
4958
_, ok := spec.commandIndex[m.Name]
5059
if ok {

matter/spec/section.go

+15-2
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func AssignSectionTypes(doc *Doc, top *Section) error {
156156

157157
assignSectionType(doc, section, getSectionType(ps, section))
158158
switch section.SecType {
159-
case matter.SectionDataTypeBitmap, matter.SectionDataTypeEnum, matter.SectionDataTypeStruct:
159+
case matter.SectionDataTypeBitmap, matter.SectionDataTypeEnum, matter.SectionDataTypeStruct, matter.SectionDataTypeDef:
160160
if section.Base.Level > 2 {
161161
slog.Debug("Unusual depth for section type", slog.String("name", section.Name), slog.String("type", section.SecType.String()), slog.String("path", doc.Path.String()))
162162
}
@@ -177,6 +177,8 @@ func assignSectionType(doc *Doc, s *Section, sectionType matter.Section) {
177177
ignore = doc.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeDataTypesEnum)
178178
case matter.SectionDataTypeStruct:
179179
ignore = doc.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeDataTypesStruct)
180+
case matter.SectionDataTypeDef:
181+
ignore = doc.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeDataTypesDef)
180182
case matter.SectionCluster:
181183
ignore = doc.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeCluster)
182184
case matter.SectionDeviceType:
@@ -360,6 +362,8 @@ func deriveSectionType(section *Section, parent *Section) matter.Section {
360362
return matter.SectionDataTypeBitmap
361363
} else if dataType.BaseType == types.BaseDataTypeCustom {
362364
return matter.SectionDataTypeStruct
365+
} else if dataType.BaseType.IsSimple() {
366+
return matter.SectionDataTypeDef
363367
}
364368
}
365369
slog.Debug("unknown section type", "path", section.Doc.Path, "name", name)
@@ -453,7 +457,7 @@ func (s *Section) toGlobalObjects(d *Doc, entityMap map[asciidoc.Attributable][]
453457
return entities, nil
454458
}
455459

456-
var dataTypeDefinitionPattern = regexp.MustCompile(`is\s+derived\s+from\s+(?:<<enum-def\s*,\s*)?(enum8|enum16|enum32|map8|map16|map32)(?:\s*>>)?`)
460+
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*>>)?`)
457461

458462
func (s *Section) GetDataType() *types.DataType {
459463
var dts string
@@ -527,6 +531,15 @@ func findLooseEntities(doc *Doc, section *Section, entityMap map[asciidoc.Attrib
527531
} else {
528532
entities = append(entities, s)
529533
}
534+
case matter.SectionDataTypeDef:
535+
var t *matter.TypeDef
536+
t, err = section.toTypeDef(doc, entityMap)
537+
if err != nil {
538+
slog.Warn("Error converting loose section to typedef", log.Element("path", doc.Path, section.Base), slog.Any("error", err))
539+
err = nil
540+
} else {
541+
entities = append(entities, t)
542+
}
530543
case matter.SectionGlobalElements:
531544
var ges []types.Entity
532545
ges, err = section.toGlobalElements(doc, entityMap)

matter/spec/spec.go

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type Specification struct {
2727
bitmapIndex map[string]*matter.Bitmap
2828
enumIndex map[string]*matter.Enum
2929
structIndex map[string]*matter.Struct
30+
typeDefIndex map[string]*matter.TypeDef
3031
commandIndex map[string]*matter.Command
3132
eventIndex map[string]*matter.Event
3233

@@ -48,6 +49,7 @@ func newSpec() *Specification {
4849
bitmapIndex: make(map[string]*matter.Bitmap),
4950
enumIndex: make(map[string]*matter.Enum),
5051
structIndex: make(map[string]*matter.Struct),
52+
typeDefIndex: make(map[string]*matter.TypeDef),
5153
commandIndex: make(map[string]*matter.Command),
5254
eventIndex: make(map[string]*matter.Event),
5355

matter/spec/typedef.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package spec
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/project-chip/alchemy/asciidoc"
7+
"github.com/project-chip/alchemy/internal/text"
8+
"github.com/project-chip/alchemy/matter"
9+
"github.com/project-chip/alchemy/matter/types"
10+
)
11+
12+
func (s *Section) toTypeDef(d *Doc, entityMap map[asciidoc.Attributable][]types.Entity) (ms *matter.TypeDef, err error) {
13+
name := text.TrimCaseInsensitiveSuffix(s.Name, " Type")
14+
ms = matter.NewTypeDef(s.Base)
15+
ms.Name = name
16+
17+
dt := s.GetDataType()
18+
if (dt == nil) || !dt.BaseType.IsSimple() {
19+
return nil, fmt.Errorf("unknown typedef data type: %s", dt.Name)
20+
}
21+
ms.Type = dt
22+
entityMap[s.Base] = append(entityMap[s.Base], ms)
23+
ms.Name = CanonicalName(ms.Name)
24+
return
25+
}

matter/typedef.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package matter
2+
3+
import (
4+
"github.com/project-chip/alchemy/asciidoc"
5+
"github.com/project-chip/alchemy/matter/types"
6+
)
7+
8+
type TypeDef struct {
9+
entity
10+
Name string `json:"name,omitempty"`
11+
Description string `json:"description,omitempty"`
12+
Type *types.DataType `json:"type,omitempty"`
13+
}
14+
15+
func NewTypeDef(source asciidoc.Element) *TypeDef {
16+
return &TypeDef{
17+
entity: entity{source: source},
18+
}
19+
}
20+
21+
func (*TypeDef) EntityType() types.EntityType {
22+
return types.EntityTypeDef
23+
}
24+
25+
func (s *TypeDef) Clone() *TypeDef {
26+
ns := &TypeDef{Name: s.Name, Description: s.Description, Type: s.Type}
27+
return ns
28+
}
29+
30+
func (s *TypeDef) Inherit(parent *TypeDef) {
31+
if len(s.Description) == 0 {
32+
s.Description = parent.Description
33+
}
34+
s.Type = s.Type
35+
}
36+
37+
type TypeDefSet []*TypeDef
38+
39+
func (ss TypeDefSet) Identifier(name string) (types.Entity, bool) {
40+
for _, e := range ss {
41+
if e.Name == name {
42+
return e, true
43+
}
44+
}
45+
return nil, false
46+
}

0 commit comments

Comments
 (0)