Skip to content

Commit

Permalink
Support for tracking and maintaining spec order when generating ZAP t…
Browse files Browse the repository at this point in the history
…emplates
  • Loading branch information
hasty committed Nov 4, 2024
1 parent e5b1851 commit 6e00f9e
Show file tree
Hide file tree
Showing 29 changed files with 287 additions and 279 deletions.
11 changes: 7 additions & 4 deletions cmd/zap/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func init() {
Command.Flags().String("sdkRoot", "connectedhomeip", "the root of your clone of project-chip/connectedhomeip")
Command.Flags().Bool("featureXML", true, "write new style feature XML")
Command.Flags().Bool("conformanceXML", false, "write new style conformance XML")
Command.Flags().Bool("specOrder", false, "write ZAP template XML in spec order")
}

func zapTemplates(cmd *cobra.Command, args []string) (err error) {
Expand Down Expand Up @@ -101,7 +102,9 @@ func zapTemplates(cmd *cobra.Command, args []string) (err error) {
featureXML, _ := cmd.Flags().GetBool("featureXML")
templateOptions = append(templateOptions, generate.GenerateFeatureXML(featureXML))
conformanceXML, _ := cmd.Flags().GetBool("conformanceXML")
specOrder, _ := cmd.Flags().GetBool("specOrder")
templateOptions = append(templateOptions, generate.GenerateConformanceXML(conformanceXML))
templateOptions = append(templateOptions, generate.SpecOrder(specOrder))
templateOptions = append(templateOptions, generate.AsciiAttributes(asciiSettings))
templateOptions = append(templateOptions, generate.SpecRoot(specRoot))

Expand Down Expand Up @@ -244,19 +247,19 @@ func patchSpec(spec *spec.Specification) {
Another hacky workaround: the spec defines LabelStruct under a base cluster called Label Cluster, but the
ZAP XML has this struct under Fixed Label
*/
fixedLabel, ok := spec.ClustersByName["Fixed Label"]
fixedLabelCluster, ok := spec.ClustersByName["Fixed Label"]
if !ok {
slog.Warn("Could not find Fixed Label cluster")
return
}
label, ok := spec.ClustersByName["Label"]
labelCluster, ok := spec.ClustersByName["Label"]
if !ok {
slog.Warn("Could not find Label cluster")
return
}
for _, s := range label.Structs {
for _, s := range labelCluster.Structs {
if s.Name == "LabelStruct" {
fixedLabel.MoveStruct(s)
fixedLabelCluster.MoveStruct(s)
break
}
}
Expand Down
5 changes: 2 additions & 3 deletions matter/spec/attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import (
"log/slog"
"strings"

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

func (s *Section) toAttributes(d *Doc, cluster *matter.Cluster, entityMap map[asciidoc.Attributable][]types.Entity) (attributes matter.FieldSet, err error) {
func (s *Section) toAttributes(d *Doc, cluster *matter.Cluster, pc *parseContext) (attributes matter.FieldSet, err error) {
var ti *TableInfo
ti, err = parseFirstTable(d, s)
if err != nil {
Expand Down Expand Up @@ -65,6 +64,6 @@ func (s *Section) toAttributes(d *Doc, cluster *matter.Cluster, entityMap map[as
attributes = append(attributes, attr)
attributeMap[attr.Name] = attr
}
err = s.mapFields(attributeMap, entityMap)
err = s.mapFields(attributeMap, pc)
return
}
6 changes: 3 additions & 3 deletions matter/spec/bitmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import (
"fmt"
"log/slog"

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

func (s *Section) toBitmap(d *Doc, entityMap map[asciidoc.Attributable][]types.Entity) (bm *matter.Bitmap, err error) {
func (s *Section) toBitmap(d *Doc, pc *parseContext) (bm *matter.Bitmap, err error) {
name := text.TrimCaseInsensitiveSuffix(s.Name, " Type")

dt := s.GetDataType()
Expand Down Expand Up @@ -69,7 +68,8 @@ func (s *Section) toBitmap(d *Doc, entityMap map[asciidoc.Attributable][]types.E
bv := matter.NewBitmapBit(s.Base, bit, CanonicalName(name), summary, conf)
bm.Bits = append(bm.Bits, bv)
}
entityMap[s.Base] = append(entityMap[s.Base], bm)
pc.orderedEntities = append(pc.orderedEntities, bm)
pc.entitiesByElement[s.Base] = append(pc.entitiesByElement[s.Base], bm)
bm.Name = CanonicalName(bm.Name)
return
}
65 changes: 58 additions & 7 deletions matter/spec/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,64 @@ func (sp *Builder) buildSpec(docs []*Doc) (spec *Specification, err error) {
}
case *matter.Namespace:
spec.Namespaces = append(spec.Namespaces, m)
case *matter.Bitmap:
slog.Debug("Found global bitmap", "name", m.Name, "path", d.Path)
_, ok := spec.bitmapIndex[m.Name]
if ok {
slog.Error("multiple bitmaps with same name", "name", m.Name)
} else {
spec.bitmapIndex[m.Name] = m
}
spec.addEntityByName(m.Name, m, nil)
spec.GlobalObjects[m] = struct{}{}
case *matter.Enum:
slog.Debug("Found global enum", "name", m.Name, "path", d.Path)
_, ok := spec.enumIndex[m.Name]
if ok {
slog.Error("multiple enums with same name", "name", m.Name)
} else {
spec.enumIndex[m.Name] = m
}
spec.addEntityByName(m.Name, m, nil)
spec.GlobalObjects[m] = struct{}{}
case *matter.Struct:
slog.Debug("Found global struct", "name", m.Name, "path", d.Path)
_, ok := spec.structIndex[m.Name]
if ok {
slog.Error("multiple structs with same name", "name", m.Name)
} else {
spec.structIndex[m.Name] = m
}
spec.addEntityByName(m.Name, m, nil)
spec.GlobalObjects[m] = struct{}{}
case *matter.TypeDef:
slog.Debug("Found global typedef", "name", m.Name, "path", d.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)
spec.GlobalObjects[m] = struct{}{}
case *matter.Command:
_, ok := spec.commandIndex[m.Name]
if ok {
slog.Error("multiple commands with same name", "name", m.Name)
} else {
spec.commandIndex[m.Name] = m
}
spec.addEntityByName(m.Name, m, nil)
spec.GlobalObjects[m] = struct{}{}
case *matter.Event:
_, ok := spec.eventIndex[m.Name]
if ok {
slog.Error("multiple events with same name", "name", m.Name)
} else {
spec.eventIndex[m.Name] = m
}
spec.addEntityByName(m.Name, m, nil)
spec.GlobalObjects[m] = struct{}{}
default:
slog.Warn("unknown entity type", "path", d.Path, "type", fmt.Sprintf("%T", m))
}
Expand All @@ -116,13 +174,6 @@ func (sp *Builder) buildSpec(docs []*Doc) (spec *Specification, err error) {
}
}

err = addGlobalEntities(spec, d)

if err != nil {
slog.Warn("error building global objects", "doc", d.Path, "error", err)
continue
}

}

if !sp.IgnoreHierarchy {
Expand Down
43 changes: 27 additions & 16 deletions matter/spec/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/project-chip/alchemy/matter/types"
)

func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types.Entity) (entities []types.Entity, err error) {
func (s *Section) toClusters(d *Doc, pc *parseContext) (err error) {
var clusters []*matter.Cluster
var description string
p := parse.FindFirst[*asciidoc.Paragraph](s.Elements())
Expand All @@ -32,7 +32,7 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
clusters, err = readClusterIDs(d, s)
}
if err != nil {
return nil, err
return
}
}

Expand Down Expand Up @@ -66,23 +66,29 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
var es matter.EnumSet
var ss matter.StructSet
var ts matter.TypeDefSet
bs, es, ss, ts, err = s.toDataTypes(d, entityMap)
bs, es, ss, ts, err = s.toDataTypes(d, pc)
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)
features, err = s.toFeatures(d, pc)
if err != nil {
return
}
}
if err != nil {
return
}
}

if clusterGroup != nil {
entities = append(entities, clusterGroup)
pc.entities = append(pc.entities, clusterGroup)
pc.orderedEntities = append(pc.orderedEntities, clusterGroup)
pc.entitiesByElement[s.Base] = append(pc.entitiesByElement[s.Base], clusterGroup)

clusterGroup.AddBitmaps(bitmaps...)
clusterGroup.AddEnums(enums...)
clusterGroup.AddStructs(structs...)
Expand All @@ -94,11 +100,14 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
err = readClusterClassification(d, clusterGroup.Name, &clusterGroup.ClusterClassification, s)
}
if err != nil {
return nil, fmt.Errorf("error reading section in %s: %w", d.Path, err)
err = fmt.Errorf("error reading section in %s: %w", d.Path, err)
return
}
}
} else {
entities = append(entities, clusters[0])
pc.entities = append(pc.entities, clusters[0])
pc.orderedEntities = append(pc.orderedEntities, clusters[0])
pc.entitiesByElement[s.Base] = append(pc.entitiesByElement[s.Base], clusters[0])
}

for _, c := range clusters {
Expand All @@ -115,21 +124,22 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
err = readClusterClassification(d, c.Name, &c.ClusterClassification, s)
}
if err != nil {
return nil, fmt.Errorf("error reading section in %s: %w", d.Path, err)
err = fmt.Errorf("error reading section in %s: %w", d.Path, err)
return
}
}
for _, s := range elements {
switch s.SecType {
case matter.SectionAttributes:
var attr []*matter.Field
attr, err = s.toAttributes(d, c, entityMap)
attr, err = s.toAttributes(d, c, pc)
if err == nil {
c.Attributes = append(c.Attributes, attr...)
}
case matter.SectionEvents:
c.Events, err = s.toEvents(d, entityMap)
c.Events, err = s.toEvents(d, pc)
case matter.SectionCommands:
c.Commands, err = s.toCommands(d, entityMap)
c.Commands, err = s.toCommands(d, pc)
case matter.SectionRevisionHistory:
c.Revisions, err = readRevisionHistory(d, s)
case matter.SectionDerivedClusterNamespace:
Expand All @@ -138,9 +148,10 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
case matter.SectionDataTypes, matter.SectionFeatures, matter.SectionStatusCodes: // Handled above
default:
var looseEntities []types.Entity
looseEntities, err = findLooseEntities(d, s, entityMap)
looseEntities, err = findLooseEntities(d, s, pc)
if err != nil {
return nil, fmt.Errorf("error reading section %s: %w", s.Name, err)
err = fmt.Errorf("error reading section %s: %w", s.Name, err)
return
}
if len(looseEntities) > 0 {
for _, le := range looseEntities {
Expand All @@ -160,14 +171,14 @@ func (s *Section) toClusters(d *Doc, entityMap map[asciidoc.Attributable][]types
}
}
if err != nil {
return nil, fmt.Errorf("error reading section in %s: %w", d.Path, err)
err = fmt.Errorf("error reading section in %s: %w", d.Path, err)
return
}
}
assignCustomDataTypes(c)
}

entityMap[s.Base] = append(entityMap[s.Base], entities...)
return entities, nil
return
}

func assignCustomDataTypes(c *matter.Cluster) {
Expand Down
8 changes: 4 additions & 4 deletions matter/spec/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (cf *commandFactory) New(d *Doc, s *Section, ti *TableInfo, row *asciidoc.T
return cmd, nil
}

func (cf *commandFactory) Details(d *Doc, s *Section, entityMap map[asciidoc.Attributable][]types.Entity, c *matter.Command) (err error) {
func (cf *commandFactory) Details(d *Doc, s *Section, pc *parseContext, c *matter.Command) (err error) {
c.Description = getDescription(d, s.Elements())

if !d.errata.Spec.IgnoreSection(s.Name, errata.SpecPurposeCommandArguments) {
Expand All @@ -75,7 +75,7 @@ func (cf *commandFactory) Details(d *Doc, s *Section, entityMap map[asciidoc.Att
for _, f := range c.Fields {
fieldMap[f.Name] = f
}
err = s.mapFields(fieldMap, entityMap)
err = s.mapFields(fieldMap, pc)
if err != nil {
return
}
Expand All @@ -101,15 +101,15 @@ func (cf *commandFactory) Children(d *Doc, s *Section) iter.Seq[*Section] {
}
}

func (s *Section) toCommands(d *Doc, entityMap map[asciidoc.Attributable][]types.Entity) (commands matter.CommandSet, err error) {
func (s *Section) toCommands(d *Doc, pc *parseContext) (commands matter.CommandSet, err error) {

t := FindFirstTable(s)
if t == nil {
return nil, nil
}

var cf commandFactory
commands, err = buildList(d, s, t, entityMap, commands, &cf)
commands, err = buildList(d, s, t, pc, commands, &cf)

for _, cmd := range commands {
if cmd.Response != nil {
Expand Down
11 changes: 5 additions & 6 deletions matter/spec/datatypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ 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, typedefs matter.TypeDefSet, err error) {
func (s *Section) toDataTypes(d *Doc, pc *parseContext) (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 {
case matter.SectionDataTypeBitmap:
var mb *matter.Bitmap
mb, err = s.toBitmap(d, entityMap)
mb, err = s.toBitmap(d, pc)
if err != nil {
slog.Warn("Error converting section to bitmap", log.Element("path", d.Path, s.Base), slog.Any("error", err))
err = nil
Expand All @@ -27,7 +27,7 @@ func (s *Section) toDataTypes(d *Doc, entityMap map[asciidoc.Attributable][]type
}
case matter.SectionDataTypeEnum:
var me *matter.Enum
me, err = s.toEnum(d, entityMap)
me, err = s.toEnum(d, pc)
if err != nil {
slog.Warn("Error converting section to enum", log.Element("path", d.Path, s.Base), slog.Any("error", err))
err = nil
Expand All @@ -36,7 +36,7 @@ func (s *Section) toDataTypes(d *Doc, entityMap map[asciidoc.Attributable][]type
}
case matter.SectionDataTypeStruct:
var me *matter.Struct
me, err = s.toStruct(d, entityMap)
me, err = s.toStruct(d, pc)
if err != nil {
slog.Warn("Error converting section to struct", log.Element("path", d.Path, s.Base), slog.Any("error", err))
err = nil
Expand All @@ -45,13 +45,12 @@ func (s *Section) toDataTypes(d *Doc, entityMap map[asciidoc.Attributable][]type
}
case matter.SectionDataTypeDef:
var me *matter.TypeDef
me, err = s.toTypeDef(d, entityMap)
me, err = s.toTypeDef(d, pc)
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:
}
Expand Down
Loading

0 comments on commit 6e00f9e

Please sign in to comment.