mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
acpi: refactor scope lookup code and move it into the entity pkg
This commit is contained in:
parent
44896b1680
commit
89882545f2
@ -1,68 +1,14 @@
|
|||||||
package aml
|
package entity
|
||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
// Visitor is a function invoked by the VM for each AML tree entity that matches
|
// ResolveScopedPath examines a path expression and attempts to break it down
|
||||||
// a particular type. The return value controls whether the children of this
|
|
||||||
// entity should also be visited.
|
|
||||||
type Visitor func(depth int, obj Entity) (keepRecursing bool)
|
|
||||||
|
|
||||||
// EntityType defines the type of entity that visitors should inspect.
|
|
||||||
type EntityType uint8
|
|
||||||
|
|
||||||
// The list of supported EntityType values. EntityTypeAny works as a wildcard
|
|
||||||
// allowing the visitor to inspect all entities in the AML tree.
|
|
||||||
const (
|
|
||||||
EntityTypeAny EntityType = iota
|
|
||||||
EntityTypeDevice
|
|
||||||
EntityTypeProcessor
|
|
||||||
EntityTypePowerResource
|
|
||||||
EntityTypeThermalZone
|
|
||||||
EntityTypeMethod
|
|
||||||
)
|
|
||||||
|
|
||||||
// scopeVisit descends a scope hierarchy and invokes visitorFn for each entity
|
|
||||||
// that matches entType.
|
|
||||||
func scopeVisit(depth int, ent Entity, entType EntityType, visitorFn Visitor) bool {
|
|
||||||
op := ent.getOpcode()
|
|
||||||
switch {
|
|
||||||
case (entType == EntityTypeAny) ||
|
|
||||||
(entType == EntityTypeDevice && op == opDevice) ||
|
|
||||||
(entType == EntityTypeProcessor && op == opProcessor) ||
|
|
||||||
(entType == EntityTypePowerResource && op == opPowerRes) ||
|
|
||||||
(entType == EntityTypeThermalZone && op == opThermalZone) ||
|
|
||||||
(entType == EntityTypeMethod && op == opMethod):
|
|
||||||
// If the visitor returned false we should not visit the children
|
|
||||||
if !visitorFn(depth, ent) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visit any args that are also entities
|
|
||||||
for _, arg := range ent.getArgs() {
|
|
||||||
if argEnt, isEnt := arg.(Entity); isEnt && !scopeVisit(depth+1, argEnt, entType, visitorFn) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch typ := ent.(type) {
|
|
||||||
case ScopeEntity:
|
|
||||||
// If the entity defines a scope we need to visit the child entities.
|
|
||||||
for _, child := range typ.Children() {
|
|
||||||
_ = scopeVisit(depth+1, child, entType, visitorFn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// scopeResolvePath examines a path expression and attempts to break it down
|
|
||||||
// into a parent and child segment. The parent segment is looked up via the
|
// into a parent and child segment. The parent segment is looked up via the
|
||||||
// regular scope rules specified in page 252 of the ACPI 6.2 spec. If the
|
// regular scope rules specified in page 252 of the ACPI 6.2 spec. If the
|
||||||
// parent scope is found then the function returns back the parent entity and
|
// parent scope is found then the function returns back the parent entity and
|
||||||
// the name of the child that should be appended to it. If the expression
|
// the name of the child that should be appended to it. If the expression
|
||||||
// lookup fails then the function returns nil, "".
|
// lookup fails then the function returns nil, "".
|
||||||
func scopeResolvePath(curScope, rootScope ScopeEntity, expr string) (parent ScopeEntity, name string) {
|
func ResolveScopedPath(curScope, rootScope Container, expr string) (parent Container, name string) {
|
||||||
if len(expr) <= 1 {
|
if len(expr) <= 1 {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
@ -75,8 +21,8 @@ func scopeResolvePath(curScope, rootScope ScopeEntity, expr string) (parent Scop
|
|||||||
return rootScope, expr[1:]
|
return rootScope, expr[1:]
|
||||||
case '^':
|
case '^':
|
||||||
lastHatIndex := strings.LastIndexByte(expr, '^')
|
lastHatIndex := strings.LastIndexByte(expr, '^')
|
||||||
if target := scopeFind(curScope, rootScope, expr[:lastHatIndex+1]); target != nil {
|
if target := FindInScope(curScope, rootScope, expr[:lastHatIndex+1]); target != nil {
|
||||||
return target.(ScopeEntity), expr[lastHatIndex+1:]
|
return target.(Container), expr[lastHatIndex+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ""
|
return nil, ""
|
||||||
@ -86,14 +32,14 @@ func scopeResolvePath(curScope, rootScope ScopeEntity, expr string) (parent Scop
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pattern looks like: \FOO.BAR.BAZ or ^+FOO.BAR.BAZ or FOO.BAR.BAZ
|
// Pattern looks like: \FOO.BAR.BAZ or ^+FOO.BAR.BAZ or FOO.BAR.BAZ
|
||||||
if target := scopeFind(curScope, rootScope, expr[:lastDotIndex]); target != nil {
|
if target := FindInScope(curScope, rootScope, expr[:lastDotIndex]); target != nil {
|
||||||
return target.(ScopeEntity), expr[lastDotIndex+1:]
|
return target.(Container), expr[lastDotIndex+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// scopeFind attempts to find an object with the given name using the rules
|
// FindInScope attempts to find an object with the given name using the rules
|
||||||
// specified in page 252 of the ACPI 6.2 spec:
|
// specified in page 252 of the ACPI 6.2 spec:
|
||||||
//
|
//
|
||||||
// There are two types of namespace paths: an absolute namespace path (that is,
|
// There are two types of namespace paths: an absolute namespace path (that is,
|
||||||
@ -104,7 +50,7 @@ func scopeResolvePath(curScope, rootScope ScopeEntity, expr string) (parent Scop
|
|||||||
// or Parent Prefixes, ‘^’, the search rules do not apply. If the search rules
|
// or Parent Prefixes, ‘^’, the search rules do not apply. If the search rules
|
||||||
// do not apply to a relative namespace path, the namespace object is looked up
|
// do not apply to a relative namespace path, the namespace object is looked up
|
||||||
// relative to the current namespace
|
// relative to the current namespace
|
||||||
func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
func FindInScope(curScope, rootScope Container, name string) Entity {
|
||||||
nameLen := len(name)
|
nameLen := len(name)
|
||||||
if nameLen == 0 {
|
if nameLen == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -113,7 +59,7 @@ func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
|||||||
switch {
|
switch {
|
||||||
case name[0] == '\\': // relative to the root scope
|
case name[0] == '\\': // relative to the root scope
|
||||||
if nameLen > 1 {
|
if nameLen > 1 {
|
||||||
return scopeFindRelative(rootScope, name[1:])
|
return findRelativeToScope(rootScope, name[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name was just `\`; this matches the root namespace
|
// Name was just `\`; this matches the root namespace
|
||||||
@ -130,7 +76,7 @@ func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Found the start of the name. Look it up relative to curNs
|
// Found the start of the name. Look it up relative to curNs
|
||||||
return scopeFindRelative(curScope, name[startIndex:])
|
return findRelativeToScope(curScope, name[startIndex:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +85,7 @@ func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
|||||||
case strings.ContainsRune(name, '.'):
|
case strings.ContainsRune(name, '.'):
|
||||||
// If the name contains any '.' then we still need to look it
|
// If the name contains any '.' then we still need to look it
|
||||||
// up relative to the current scope
|
// up relative to the current scope
|
||||||
return scopeFindRelative(curScope, name)
|
return findRelativeToScope(curScope, name)
|
||||||
default:
|
default:
|
||||||
// We can apply the search rules described by the spec
|
// We can apply the search rules described by the spec
|
||||||
for s := curScope; s != nil; s = s.Parent() {
|
for s := curScope; s != nil; s = s.Parent() {
|
||||||
@ -155,11 +101,11 @@ func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// scopeFindRelative returns the Entity referenced by path relative
|
// findRelativeToScope returns the Entity referenced by path relative
|
||||||
// to the provided Namespace. If the name contains dots, each segment
|
// to the provided Namespace. If the name contains dots, each segment
|
||||||
// is used to access a nested namespace. If the path does not point
|
// is used to access a nested namespace. If the path does not point
|
||||||
// to a NamedObject then lookupRelativeTo returns back nil.
|
// to a NamedObject then lookupRelativeTo returns back nil.
|
||||||
func scopeFindRelative(ns ScopeEntity, path string) Entity {
|
func findRelativeToScope(ns Container, path string) Entity {
|
||||||
var matchName string
|
var matchName string
|
||||||
matchNextPathSegment:
|
matchNextPathSegment:
|
||||||
for {
|
for {
|
||||||
@ -170,12 +116,7 @@ matchNextPathSegment:
|
|||||||
|
|
||||||
// Search for a scoped child named "matchName"
|
// Search for a scoped child named "matchName"
|
||||||
for _, child := range ns.Children() {
|
for _, child := range ns.Children() {
|
||||||
childNs, ok := child.(ScopeEntity)
|
if childNs, ok := child.(Container); ok && childNs.Name() == matchName {
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if childNs.Name() == matchName {
|
|
||||||
ns = childNs
|
ns = childNs
|
||||||
continue matchNextPathSegment
|
continue matchNextPathSegment
|
||||||
}
|
}
|
215
src/gopheros/device/acpi/aml/entity/scope_test.go
Normal file
215
src/gopheros/device/acpi/aml/entity/scope_test.go
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolveScopedPath(t *testing.T) {
|
||||||
|
scopeMap := genTestScopes()
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
curScope Container
|
||||||
|
pathExpr string
|
||||||
|
wantParent Entity
|
||||||
|
wantName string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`\_SB_`,
|
||||||
|
scopeMap[`\`],
|
||||||
|
"_SB_",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`^FOO`,
|
||||||
|
scopeMap[`PCI0`],
|
||||||
|
"FOO",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`^^FOO`,
|
||||||
|
scopeMap[`_SB_`],
|
||||||
|
"FOO",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`_ADR`,
|
||||||
|
scopeMap[`IDE0`],
|
||||||
|
"_ADR",
|
||||||
|
},
|
||||||
|
// Paths with dots
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`\_SB_.PCI0.IDE0._ADR`,
|
||||||
|
scopeMap[`IDE0`],
|
||||||
|
"_ADR",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`IDE0._ADR`,
|
||||||
|
scopeMap[`IDE0`],
|
||||||
|
"_ADR",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`_CRS`,
|
||||||
|
scopeMap[`PCI0`],
|
||||||
|
"_CRS",
|
||||||
|
},
|
||||||
|
// Bad queries
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`FOO.BAR.BAZ`,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
``,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`\`,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`^^^^^^^^^BADPATH`,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
root := scopeMap[`\`].(Container)
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
gotParent, gotName := ResolveScopedPath(spec.curScope, root, spec.pathExpr)
|
||||||
|
if !reflect.DeepEqual(gotParent, spec.wantParent) {
|
||||||
|
t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.wantParent, gotParent)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotName != spec.wantName {
|
||||||
|
t.Errorf("[spec %d] expected lookup to return node name %q; got %q", specIndex, spec.wantName, gotName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindInScope(t *testing.T) {
|
||||||
|
scopeMap := genTestScopes()
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
curScope Container
|
||||||
|
lookup string
|
||||||
|
want Entity
|
||||||
|
}{
|
||||||
|
// Search rules do not apply for these cases
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`\`,
|
||||||
|
scopeMap[`\`],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
"IDE0._ADR",
|
||||||
|
scopeMap["_ADR"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"^^PCI0.IDE0._ADR",
|
||||||
|
scopeMap["_ADR"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`\_SB_.PCI0.IDE0._ADR`,
|
||||||
|
scopeMap["_ADR"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`\_SB_.PCI0`,
|
||||||
|
scopeMap["PCI0"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`^`,
|
||||||
|
scopeMap["PCI0"],
|
||||||
|
},
|
||||||
|
// Bad queries
|
||||||
|
{
|
||||||
|
scopeMap["_SB_"].(Container),
|
||||||
|
"PCI0.USB._CRS",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"^^^^^^^^^^^^^^^^^^^",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`^^^^^^^^^^^FOO`,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"FOO",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
// Search rules apply for these cases
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"_CRS",
|
||||||
|
scopeMap["_CRS"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
root := scopeMap[`\`].(Container)
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
if got := FindInScope(spec.curScope, root, spec.lookup); !reflect.DeepEqual(got, spec.want) {
|
||||||
|
t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func genTestScopes() map[string]Entity {
|
||||||
|
// Setup the example tree from page 252 of the acpi 6.2 spec
|
||||||
|
// \
|
||||||
|
// SB
|
||||||
|
// \
|
||||||
|
// PCI0
|
||||||
|
// | _CRS
|
||||||
|
// \
|
||||||
|
// IDE0
|
||||||
|
// | _ADR
|
||||||
|
ideScope := NewScope(OpScope, 42, `IDE0`)
|
||||||
|
pciScope := NewScope(OpScope, 42, `PCI0`)
|
||||||
|
sbScope := NewScope(OpScope, 42, `_SB_`)
|
||||||
|
rootScope := NewScope(OpScope, 42, `\`)
|
||||||
|
|
||||||
|
adr := NewMethod(42, `_ADR`)
|
||||||
|
crs := NewMethod(42, `_CRS`)
|
||||||
|
|
||||||
|
// Setup tree
|
||||||
|
ideScope.Append(adr)
|
||||||
|
pciScope.Append(crs)
|
||||||
|
pciScope.Append(ideScope)
|
||||||
|
sbScope.Append(pciScope)
|
||||||
|
rootScope.Append(sbScope)
|
||||||
|
|
||||||
|
return map[string]Entity{
|
||||||
|
"IDE0": ideScope,
|
||||||
|
"PCI0": pciScope,
|
||||||
|
"_SB_": sbScope,
|
||||||
|
"\\": rootScope,
|
||||||
|
"_ADR": adr,
|
||||||
|
"_CRS": crs,
|
||||||
|
}
|
||||||
|
}
|
@ -1,294 +0,0 @@
|
|||||||
package aml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestScopeVisit(t *testing.T) {
|
|
||||||
scopeMap := genTestScopes()
|
|
||||||
root := scopeMap[`\`].(*scopeEntity)
|
|
||||||
|
|
||||||
keepRecursing := func(Entity) bool { return true }
|
|
||||||
stopRecursing := func(Entity) bool { return false }
|
|
||||||
|
|
||||||
// Append special entities under IDE0
|
|
||||||
ide := scopeMap["IDE0"].(*scopeEntity)
|
|
||||||
ide.Append(&Device{})
|
|
||||||
ide.Append(&namedEntity{op: opProcessor})
|
|
||||||
ide.Append(&namedEntity{op: opProcessor})
|
|
||||||
ide.Append(&namedEntity{op: opPowerRes})
|
|
||||||
ide.Append(&namedEntity{op: opPowerRes})
|
|
||||||
ide.Append(&namedEntity{op: opPowerRes})
|
|
||||||
ide.Append(&namedEntity{op: opThermalZone})
|
|
||||||
ide.Append(&namedEntity{op: opThermalZone})
|
|
||||||
ide.Append(&namedEntity{op: opThermalZone})
|
|
||||||
ide.Append(&namedEntity{op: opThermalZone})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&methodInvocationEntity{
|
|
||||||
unnamedEntity: unnamedEntity{
|
|
||||||
args: []interface{}{
|
|
||||||
&constEntity{val: uint64(1)},
|
|
||||||
&constEntity{val: uint64(2)},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
specs := []struct {
|
|
||||||
searchType EntityType
|
|
||||||
keepRecursingFn func(Entity) bool
|
|
||||||
wantHits int
|
|
||||||
}{
|
|
||||||
{EntityTypeAny, keepRecursing, 24},
|
|
||||||
{EntityTypeAny, stopRecursing, 1},
|
|
||||||
{
|
|
||||||
EntityTypeAny,
|
|
||||||
func(ent Entity) bool {
|
|
||||||
// Stop recursing after visiting the methodInvocationEntity
|
|
||||||
_, isInv := ent.(*methodInvocationEntity)
|
|
||||||
return !isInv
|
|
||||||
},
|
|
||||||
22,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
EntityTypeAny,
|
|
||||||
func(ent Entity) bool {
|
|
||||||
// Stop recursing after visiting the first constEntity
|
|
||||||
_, isConst := ent.(*constEntity)
|
|
||||||
return !isConst
|
|
||||||
},
|
|
||||||
23,
|
|
||||||
},
|
|
||||||
{EntityTypeDevice, keepRecursing, 1},
|
|
||||||
{EntityTypeProcessor, keepRecursing, 2},
|
|
||||||
{EntityTypePowerResource, keepRecursing, 3},
|
|
||||||
{EntityTypeThermalZone, keepRecursing, 4},
|
|
||||||
{EntityTypeMethod, keepRecursing, 5},
|
|
||||||
}
|
|
||||||
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
var hits int
|
|
||||||
scopeVisit(0, root, spec.searchType, func(_ int, obj Entity) bool {
|
|
||||||
hits++
|
|
||||||
return spec.keepRecursingFn(obj)
|
|
||||||
})
|
|
||||||
|
|
||||||
if hits != spec.wantHits {
|
|
||||||
t.Errorf("[spec %d] expected visitor to be called %d times; got %d", specIndex, spec.wantHits, hits)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScopeResolvePath(t *testing.T) {
|
|
||||||
scopeMap := genTestScopes()
|
|
||||||
|
|
||||||
specs := []struct {
|
|
||||||
curScope ScopeEntity
|
|
||||||
pathExpr string
|
|
||||||
wantParent Entity
|
|
||||||
wantName string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`\_SB_`,
|
|
||||||
scopeMap[`\`],
|
|
||||||
"_SB_",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`^FOO`,
|
|
||||||
scopeMap[`PCI0`],
|
|
||||||
"FOO",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`^^FOO`,
|
|
||||||
scopeMap[`_SB_`],
|
|
||||||
"FOO",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`_ADR`,
|
|
||||||
scopeMap[`IDE0`],
|
|
||||||
"_ADR",
|
|
||||||
},
|
|
||||||
// Paths with dots
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`\_SB_.PCI0.IDE0._ADR`,
|
|
||||||
scopeMap[`IDE0`],
|
|
||||||
"_ADR",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`IDE0._ADR`,
|
|
||||||
scopeMap[`IDE0`],
|
|
||||||
"_ADR",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`_CRS`,
|
|
||||||
scopeMap[`PCI0`],
|
|
||||||
"_CRS",
|
|
||||||
},
|
|
||||||
// Bad queries
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`FOO.BAR.BAZ`,
|
|
||||||
nil,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
``,
|
|
||||||
nil,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`\`,
|
|
||||||
nil,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`^^^^^^^^^BADPATH`,
|
|
||||||
nil,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
root := scopeMap[`\`].(*scopeEntity)
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
gotParent, gotName := scopeResolvePath(spec.curScope, root, spec.pathExpr)
|
|
||||||
if !reflect.DeepEqual(gotParent, spec.wantParent) {
|
|
||||||
t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.wantParent, gotParent)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if gotName != spec.wantName {
|
|
||||||
t.Errorf("[spec %d] expected lookup to return node name %q; got %q", specIndex, spec.wantName, gotName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScopeFind(t *testing.T) {
|
|
||||||
scopeMap := genTestScopes()
|
|
||||||
|
|
||||||
specs := []struct {
|
|
||||||
curScope ScopeEntity
|
|
||||||
lookup string
|
|
||||||
want Entity
|
|
||||||
}{
|
|
||||||
// Search rules do not apply for these cases
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`\`,
|
|
||||||
scopeMap[`\`],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
"IDE0._ADR",
|
|
||||||
scopeMap["_ADR"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"^^PCI0.IDE0._ADR",
|
|
||||||
scopeMap["_ADR"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`\_SB_.PCI0.IDE0._ADR`,
|
|
||||||
scopeMap["_ADR"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`\_SB_.PCI0`,
|
|
||||||
scopeMap["PCI0"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`^`,
|
|
||||||
scopeMap["PCI0"],
|
|
||||||
},
|
|
||||||
// Bad queries
|
|
||||||
{
|
|
||||||
scopeMap["_SB_"].(*scopeEntity),
|
|
||||||
"PCI0.USB._CRS",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"^^^^^^^^^^^^^^^^^^^",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`^^^^^^^^^^^FOO`,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"FOO",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
// Search rules apply for these cases
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"_CRS",
|
|
||||||
scopeMap["_CRS"],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
root := scopeMap[`\`].(*scopeEntity)
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
if got := scopeFind(spec.curScope, root, spec.lookup); !reflect.DeepEqual(got, spec.want) {
|
|
||||||
t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func genTestScopes() map[string]Entity {
|
|
||||||
// Setup the example tree from page 252 of the acpi 6.2 spec
|
|
||||||
// \
|
|
||||||
// SB
|
|
||||||
// \
|
|
||||||
// PCI0
|
|
||||||
// | _CRS
|
|
||||||
// \
|
|
||||||
// IDE0
|
|
||||||
// | _ADR
|
|
||||||
ideScope := &scopeEntity{name: `IDE0`}
|
|
||||||
pciScope := &scopeEntity{name: `PCI0`}
|
|
||||||
sbScope := &scopeEntity{name: `_SB_`}
|
|
||||||
rootScope := &scopeEntity{name: `\`}
|
|
||||||
|
|
||||||
adr := &namedEntity{name: `_ADR`}
|
|
||||||
crs := &namedEntity{name: `_CRS`}
|
|
||||||
|
|
||||||
// Setup tree
|
|
||||||
ideScope.Append(adr)
|
|
||||||
pciScope.Append(crs)
|
|
||||||
pciScope.Append(ideScope)
|
|
||||||
sbScope.Append(pciScope)
|
|
||||||
rootScope.Append(sbScope)
|
|
||||||
|
|
||||||
return map[string]Entity{
|
|
||||||
"IDE0": ideScope,
|
|
||||||
"PCI0": pciScope,
|
|
||||||
"_SB_": sbScope,
|
|
||||||
"\\": rootScope,
|
|
||||||
"_ADR": adr,
|
|
||||||
"_CRS": crs,
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user