1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

acpi: move entity visitor code to the entity pkg

This commit is contained in:
Achilleas Anagnostopoulos 2017-12-17 16:59:08 +00:00
parent 38143ab510
commit 7e419ae20e
2 changed files with 157 additions and 0 deletions

View File

@ -0,0 +1,64 @@
package entity
// Visitor is a function invoked by the VM for each AML tree entity that matches
// 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)
// Type defines the type of entity that visitors should inspect.
type Type uint8
// The list of supported Type values. TypeAny works as a wildcard
// allowing the visitor to inspect all entities in the AML tree.
const (
TypeAny Type = iota
TypeDevice
TypeProcessor
TypePowerResource
TypeThermalZone
TypeMethod
TypeMutex
TypeEvent
TypeField
TypeIndexField
TypeBankField
)
// Visit descends a scope hierarchy and invokes visitorFn for each entity
// that matches entType.
func Visit(depth int, ent Entity, entType Type, visitorFn Visitor) bool {
op := ent.Opcode()
switch {
case (entType == TypeAny) ||
(entType == TypeDevice && op == OpDevice) ||
(entType == TypeProcessor && op == OpProcessor) ||
(entType == TypePowerResource && op == OpPowerRes) ||
(entType == TypeThermalZone && op == OpThermalZone) ||
(entType == TypeMethod && op == OpMethod) ||
(entType == TypeMutex && op == OpMutex) ||
(entType == TypeEvent && op == OpEvent) ||
(entType == TypeField && op == OpField) ||
(entType == TypeIndexField && op == OpIndexField) ||
(entType == TypeBankField && op == OpBankField):
// 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.Args() {
if argEnt, isEnt := arg.(Entity); isEnt && !Visit(depth+1, argEnt, entType, visitorFn) {
return false
}
}
}
// If the entity defines a scope we need to visit the child entities.
if container, isContainer := ent.(Container); isContainer {
for _, child := range container.Children() {
_ = Visit(depth+1, child, entType, visitorFn)
}
}
return true
}

View File

@ -0,0 +1,93 @@
package entity
import "testing"
func TestScopeVisit(t *testing.T) {
tableHandle := uint8(42)
keepRecursing := func(Entity) bool { return true }
stopRecursing := func(Entity) bool { return false }
// Append special entities under IDE0
root := NewScope(tableHandle, "IDE0")
root.Append(NewDevice(tableHandle, "DEV0"))
root.Append(NewProcessor(tableHandle, "FOO0"))
root.Append(NewProcessor(tableHandle, "FOO0"))
root.Append(NewPowerResource(tableHandle, "FOO0"))
root.Append(NewPowerResource(tableHandle, "FOO0"))
root.Append(NewPowerResource(tableHandle, "FOO0"))
root.Append(NewThermalZone(tableHandle, "FOO0"))
root.Append(NewThermalZone(tableHandle, "FOO0"))
root.Append(NewThermalZone(tableHandle, "FOO0"))
root.Append(NewThermalZone(tableHandle, "FOO0"))
root.Append(NewMethod(tableHandle, "MTH0"))
root.Append(NewMethod(tableHandle, "MTH1"))
root.Append(NewMethod(tableHandle, "MTH2"))
root.Append(NewMethod(tableHandle, "MTH3"))
root.Append(NewMethod(tableHandle, "MTH4"))
root.Append(NewMutex(tableHandle))
root.Append(NewMutex(tableHandle))
root.Append(NewEvent(tableHandle))
root.Append(NewEvent(tableHandle))
root.Append(NewEvent(tableHandle))
root.Append(NewField(tableHandle))
root.Append(NewIndexField(tableHandle))
root.Append(NewBankField(tableHandle))
root.Append(&Invocation{
Generic: Generic{
op: OpMethodInvocation,
args: []interface{}{
NewConst(OpOne, tableHandle, uint64(1)),
NewConst(OpDwordPrefix, tableHandle, uint64(2)),
},
},
})
specs := []struct {
searchType Type
keepRecursingFn func(Entity) bool
wantHits int
}{
{TypeAny, keepRecursing, 27},
{TypeAny, stopRecursing, 1},
{
TypeAny,
func(ent Entity) bool {
// Stop recursing after visiting the Invocation entity
_, isInv := ent.(*Invocation)
return !isInv
},
25,
},
{
TypeAny,
func(ent Entity) bool {
// Stop recursing after visiting the first Const entity
_, isConst := ent.(*Const)
return !isConst
},
26,
},
{TypeDevice, keepRecursing, 1},
{TypeProcessor, keepRecursing, 2},
{TypePowerResource, keepRecursing, 3},
{TypeThermalZone, keepRecursing, 4},
{TypeMethod, keepRecursing, 5},
{TypeMutex, keepRecursing, 2},
{TypeEvent, keepRecursing, 3},
{TypeField, keepRecursing, 1},
{TypeIndexField, keepRecursing, 1},
{TypeBankField, keepRecursing, 1},
}
for specIndex, spec := range specs {
var hits int
Visit(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)
}
}
}