Skip to content

Commit

Permalink
improve how typedefs, groupings and identities resolve references
Browse files Browse the repository at this point in the history
  • Loading branch information
dhubler committed Feb 4, 2020
1 parent fcf596f commit dcbba9f
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 316 deletions.
31 changes: 15 additions & 16 deletions meta/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,12 @@ func (b *Builder) Revision(o interface{}, rev string) *Revision {
switch x := o.(type) {
case *Module:
r.parent = x
r.scope = x
x.rev = append(x.rev, &r)
case *Import:
r.parent = x
r.scope = x
x.rev = &r
case *Include:
r.parent = x
r.scope = x
x.rev = &r
default:
b.setErr(fmt.Errorf("%T does not allow revisions, only modules, imports or includes do", o))
Expand Down Expand Up @@ -160,6 +157,7 @@ func (b *Builder) Grouping(o interface{}, ident string) *Grouping {
if !valid {
b.setErr(fmt.Errorf("%T does not support groupings", o))
} else {
g.originalParent = h.(Definition)
h.addGrouping(&g)
}

Expand Down Expand Up @@ -262,8 +260,8 @@ func (b *Builder) Must(o interface{}, expression string) *Must {
if !valid {
b.setErr(fmt.Errorf("%T does not support must", o))
} else {
m.parent = h.(Meta)
h.addMust(&m)
m.scopedParent = m.parent
}
return &m
}
Expand Down Expand Up @@ -327,6 +325,7 @@ func (b *Builder) Augment(o interface{}, path string) *Augment {
if x, valid := o.(HasAugments); !valid {
b.setErr(fmt.Errorf("%T does not allow augments", o))
} else {
a.originalParent = x.(Definition)
x.addAugments(&a)
}
return &a
Expand Down Expand Up @@ -408,7 +407,7 @@ func (b *Builder) Uses(o interface{}, ident string) *Uses {
}
if h, valid := b.parentDataDefinition(o, ident); valid {
x.parent = h
x.scope = h
x.originalParent = h
x.schemaId = b.uid
b.uid++
h.addDataDefinition(&x)
Expand All @@ -424,7 +423,7 @@ func (b *Builder) Container(o interface{}, ident string) *Container {
}
if h, valid := b.parentDataDefinition(o, ident); valid {
x.parent = h
x.scope = h
x.originalParent = h
h.addDataDefinition(&x)
}
return &x
Expand All @@ -436,7 +435,7 @@ func (b *Builder) List(o interface{}, ident string) *List {
}
if h, valid := b.parentDataDefinition(o, ident); valid {
x.parent = h
x.scope = h
x.originalParent = h
h.addDataDefinition(&x)
}
return &x
Expand All @@ -457,7 +456,7 @@ func (b *Builder) Leaf(o interface{}, ident string) *Leaf {
}
if h, valid := b.parentDataDefinition(o, ident); valid {
x.parent = h
x.scope = h
x.originalParent = h
h.addDataDefinition(&x)
}
return &x
Expand All @@ -469,7 +468,7 @@ func (b *Builder) LeafList(o interface{}, ident string) *LeafList {
}
if h, valid := b.parentDataDefinition(o, ident); valid {
x.parent = h
x.scope = h
x.originalParent = h
h.addDataDefinition(&x)
}
return &x
Expand All @@ -481,7 +480,7 @@ func (b *Builder) Any(o interface{}, ident string) *Any {
}
if h, valid := b.parentDataDefinition(o, ident); valid {
x.parent = h
x.scope = h
x.originalParent = h
h.addDataDefinition(&x)
}
return &x
Expand All @@ -494,7 +493,7 @@ func (b *Builder) Choice(o interface{}, ident string) *Choice {
}
if h, valid := b.parentDataDefinition(o, ident); valid {
x.parent = h
x.scope = h
x.originalParent = h
h.addDataDefinition(&x)
}
return &x
Expand All @@ -509,7 +508,7 @@ func (b *Builder) Case(o interface{}, ident string) *ChoiceCase {
b.setErr(fmt.Errorf("%T does not support case definitions, only choice does", o))
} else {
x.parent = h
x.scope = h
x.originalParent = h
h.cases[ident] = &x
}
return &x
Expand Down Expand Up @@ -537,7 +536,7 @@ func (b *Builder) Action(o interface{}, ident string) *Rpc {
b.setErr(fmt.Errorf("%T does not support actions", o))
} else {
x.parent = h
x.scope = h
x.originalParent = h
h.addAction(&x)
}
return &x
Expand All @@ -550,7 +549,7 @@ func (b *Builder) ActionInput(o interface{}) *RpcInput {
b.setErr(fmt.Errorf("%T does not support action input, only rpc or action does", o))
} else {
x.parent = h
x.scope = h
x.originalParent = h
h.input = &x
}
return &x
Expand All @@ -563,7 +562,7 @@ func (b *Builder) ActionOutput(o interface{}) *RpcOutput {
b.setErr(fmt.Errorf("%T does not support action output, only rpc or action does", o))
} else {
x.parent = h
x.scope = h
x.originalParent = h
h.output = &x
}
return &x
Expand All @@ -578,7 +577,7 @@ func (b *Builder) Notification(o interface{}, ident string) *Notification {
b.setErr(fmt.Errorf("%T does not support action output, only rpc or action does", o))
} else {
x.parent = h
x.scope = h
x.originalParent = h
h.addNotification(&x)
}
return &x
Expand Down
74 changes: 49 additions & 25 deletions meta/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ func (c *compiler) compile(o interface{}) error {
}
}
}
if x, ok := o.(Leafable); ok {
if err := c.compileType(x.Type(), x); err != nil {
if x, ok := o.(HasType); ok {
if err := c.compileType(x.Type(), x.(Leafable)); err != nil {
return err
}
if err := c.compile(x.Type()); err != nil {
Expand Down Expand Up @@ -187,21 +187,29 @@ func (c *compiler) identity(y *Identity) error {
return nil
}
y.derived = make(map[string]*Identity)

// add yourself to list
y.derived[y.ident] = y

// find all the derived identities
for _, baseId := range y.derivedIds {
m, baseIdent, err := rootByIdent(y, baseId)
m := y.parent
prefix, ident := splitIdent(baseId)
m, _, err := findModuleAndIsExternal(m, prefix)
if err != nil {
return err
}
ident, found := m.Identities()[baseIdent]
identity, found := m.Identities()[ident]
if !found {
return errors.New(SchemaPath(y) + " - " + baseId + " identity not found")
}
y.derived[baseId] = ident
if err := c.compile(ident); err != nil {
y.derived[baseId] = identity
if err := c.compile(identity); err != nil {
return err
}
for subId, subIdent := range ident.Identities() {
// copy in all the other identities because they all become part of
// the same identity set
for subId, subIdent := range identity.Identities() {
y.derived[subId] = subIdent
}
}
Expand All @@ -218,7 +226,7 @@ func (c *compiler) compileType(y *Type, parent Leafable) error {
var hasTypedef bool
y.format, hasTypedef = val.TypeAsFormat(y.ident)
if !hasTypedef {
tdef, err := c.findScopedTypedef(y, parent, y.ident)
tdef, err := c.findTypedef(y, parent, y.ident)
if err != nil {
return err
}
Expand Down Expand Up @@ -253,11 +261,12 @@ func (c *compiler) compileType(y *Type, parent Leafable) error {
}

if y.format == val.FmtIdentityRef {
m, baseIdent, err := rootByIdent(parent, y.base)
prefix, ident := splitIdent(y.base)
m, _, err := findModuleAndIsExternal(parent, prefix)
if err != nil {
return err
}
identity, found := m.Identities()[baseIdent]
identity, found := m.Identities()[ident]
if !found {
return errors.New(SchemaPath(parent) + " - " + y.base + " identity not found")
}
Expand Down Expand Up @@ -313,38 +322,53 @@ func (c *compiler) compileType(y *Type, parent Leafable) error {
return nil
}

func (c *compiler) findScopedTypedef(y *Type, parent Meta, ident string) (*Typedef, error) {
// lazy load grouping
var found *Typedef
xMod, xIdent, err := externalModule(parent, ident)
if err != nil {
goto nomatch
func (c *compiler) findTypedef(y *Type, parent Definition, qualifiedIdent string) (*Typedef, error) {
prefix, ident := splitIdent(qualifiedIdent)

// From RFC
// A reference to an unprefixed type or grouping, or one that uses the
// prefix of the current module, is resolved by locating the matching
// "typedef" or "grouping" statement among the immediate substatements
// of each ancestor statement.
// this means if prefix is local module, then ignore it and follow chain
searchHeirarcy := (prefix == "")
var module *Module
if !searchHeirarcy {
m, isExternal, err := findModuleAndIsExternal(parent, prefix)
if err != nil {
return nil, err
}
if !isExternal {
searchHeirarcy = true
} else {
module = m
}
}
if xMod != nil {
found = xMod.Typedefs()[xIdent]
} else {

var found *Typedef
if searchHeirarcy {
p := parent
for p != nil {
if ptd, ok := p.(HasTypedefs); ok {
if found = ptd.Typedefs()[ident]; found != nil {
break
}
}
if hasScope, ok := p.(cloneable); ok {
p = hasScope.scopedParent()
} else {
p = p.Parent()
}
p = p.getOriginalParent()
}
} else {
found = module.Typedefs()[ident]
}
nomatch:

if found == nil {
return nil, errors.New(SchemaPath(parent) + " - typedef " + y.ident + " not found")
}

// this will recurse if typedef references another typedef
if err := c.compile(found); err != nil {
return nil, err
}

return found, nil
}

Expand Down
Loading

0 comments on commit dcbba9f

Please sign in to comment.