| // Copyright 2017 The Wuffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| // |
| // SPDX-License-Identifier: Apache-2.0 OR MIT |
| |
| package ast |
| |
| import ( |
| t "github.com/google/wuffs/lang/token" |
| ) |
| |
| func TopologicalSortStructs(ns []*Struct) (sorted []*Struct, ok bool) { |
| // Algorithm is a depth-first search as per |
| // https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search |
| sorted = make([]*Struct, 0, len(ns)) |
| byQID := map[t.QID]*Struct{} |
| for _, n := range ns { |
| byQID[n.QID()] = n |
| } |
| marks := map[*Struct]uint8{} |
| for _, n := range ns { |
| if _, ok := marks[n]; !ok { |
| sorted, ok = tssVisit(sorted, n, byQID, marks) |
| if !ok { |
| return nil, false |
| } |
| } |
| } |
| return sorted, true |
| } |
| |
| func tssVisit(dst []*Struct, n *Struct, byQID map[t.QID]*Struct, marks map[*Struct]uint8) ([]*Struct, bool) { |
| const ( |
| unmarked = 0 |
| temporary = 1 |
| permanent = 2 |
| ) |
| switch marks[n] { |
| case temporary: |
| return nil, false |
| case permanent: |
| return dst, true |
| } |
| marks[n] = temporary |
| |
| for _, f := range n.Fields() { |
| x := f.AsField().XType().Innermost() |
| if o := byQID[x.QID()]; o != nil { |
| var ok bool |
| dst, ok = tssVisit(dst, o, byQID, marks) |
| if !ok { |
| return nil, false |
| } |
| } |
| } |
| |
| marks[n] = permanent |
| return append(dst, n), true |
| } |