Schedule sibling inheritance by dependency readiness
This commit is contained in:
@@ -25,84 +25,6 @@ type inheritanceGraph struct {
|
||||
byName map[string]int
|
||||
}
|
||||
|
||||
// depthFirstTemplateOrder preserves the currently wired parent-first order
|
||||
// while the loading path adopts the graph/application boundary.
|
||||
func (graph *inheritanceGraph) depthFirstTemplateOrder() ([]int, []Diagnostic) {
|
||||
const (
|
||||
unvisited = uint8(0)
|
||||
active = uint8(1)
|
||||
finished = uint8(2)
|
||||
)
|
||||
state := make([]uint8, len(graph.nodes))
|
||||
order := make([]int, 0, len(graph.nodes))
|
||||
for start := range graph.nodes {
|
||||
if state[start] != unvisited {
|
||||
continue
|
||||
}
|
||||
stack := []int{start}
|
||||
for len(stack) != 0 {
|
||||
index := stack[len(stack)-1]
|
||||
if state[index] == unvisited {
|
||||
state[index] = active
|
||||
node := graph.nodes[index]
|
||||
if node.hasParent {
|
||||
parent := node.parent
|
||||
switch state[parent] {
|
||||
case active:
|
||||
referencePath := node.path.Key(inheritanceKey)
|
||||
location := publicLocation(node.directive.Value.Location)
|
||||
return nil, []Diagnostic{inheritanceDiagnostic(CodeInheritanceCycle, referencePath, location,
|
||||
[]Location{publicLocation(graph.nodes[parent].entry.Value.Location)}, "sibling inheritance contains a cycle")}
|
||||
case unvisited:
|
||||
stack = append(stack, parent)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
state[index] = finished
|
||||
order = append(order, index)
|
||||
stack = stack[:len(stack)-1]
|
||||
}
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (graph *inheritanceGraph) depthFirstControls() []inheritanceControl {
|
||||
visited := make([]bool, len(graph.nodes))
|
||||
controls := make([]inheritanceControl, 0, len(graph.nodes))
|
||||
type frame struct {
|
||||
index int
|
||||
entered bool
|
||||
}
|
||||
for start := range graph.nodes {
|
||||
if visited[start] {
|
||||
continue
|
||||
}
|
||||
stack := []frame{{index: start}}
|
||||
for len(stack) != 0 {
|
||||
current := &stack[len(stack)-1]
|
||||
node := graph.nodes[current.index]
|
||||
if !current.entered {
|
||||
current.entered = true
|
||||
visited[current.index] = true
|
||||
if node.hasDirective {
|
||||
controls = append(controls, inheritanceControl{
|
||||
path: node.path.Key(inheritanceKey),
|
||||
locations: []Location{publicLocation(node.directive.Value.Location)},
|
||||
cancelled: node.cancelled,
|
||||
})
|
||||
}
|
||||
if node.hasParent && !visited[node.parent] {
|
||||
stack = append(stack, frame{index: node.parent})
|
||||
continue
|
||||
}
|
||||
}
|
||||
stack = stack[:len(stack)-1]
|
||||
}
|
||||
}
|
||||
return controls
|
||||
}
|
||||
|
||||
// analyzeInheritanceGraph retains only direct mapping siblings as graph nodes.
|
||||
// It validates declarations separately from applying their templates, leaving
|
||||
// nested scopes for the existing destination-local walk.
|
||||
@@ -197,15 +119,11 @@ func expandSiblingDefinitionsWithOrigins(scope *document.Node, scopePath Path, l
|
||||
if len(diagnostics) != 0 {
|
||||
return nil, diagnostics
|
||||
}
|
||||
order, diagnostics := graph.depthFirstTemplateOrder()
|
||||
order, diagnostics := graph.schedule()
|
||||
if len(diagnostics) != 0 {
|
||||
return nil, diagnostics
|
||||
}
|
||||
result, diagnostics := applyInheritanceTemplates(graph, order, limits, inputOrigins, budget...)
|
||||
if len(diagnostics) == 0 {
|
||||
result.controls = graph.depthFirstControls()
|
||||
}
|
||||
return result, diagnostics
|
||||
return applyInheritanceTemplates(graph, order, limits, inputOrigins, budget...)
|
||||
}
|
||||
|
||||
// applyInheritanceTemplates builds detached templates in the supplied
|
||||
|
||||
Reference in New Issue
Block a user