Small dependency ordering optimizations

This commit is contained in:
James Eversole 2025-01-26 16:06:40 -06:00 committed by James Eversole
parent c9d0d04630
commit 72291c652d
2 changed files with 30 additions and 26 deletions

View File

@ -62,4 +62,4 @@ jobs:
./tricu ./tricu
token: '${{ secrets.RELEASE_TOKEN }}' token: '${{ secrets.RELEASE_TOKEN }}'
body: '${{ gitea.event.head_commit.message }}' body: '${{ gitea.event.head_commit.message }}'
pre_release: true prerelease: true

View File

@ -3,7 +3,7 @@ module Eval where
import Parser import Parser
import Research import Research
import Data.List (partition) import Data.List (partition, (\\))
import Data.Map (Map) import Data.Map (Map)
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
@ -122,17 +122,20 @@ reorderDefs env defs
| otherwise = orderedDefs ++ others | otherwise = orderedDefs ++ others
where where
(defsOnly, others) = partition isDef defs (defsOnly, others) = partition isDef defs
graph = buildDepGraph defsOnly defNames = [ name | SDef name _ _ <- defsOnly ]
sortedDefs = sortDeps graph
defMap = Map.fromList [(name, def) | def@(SDef name _ _) <- defsOnly] defsWithFreeVars = [(def, freeVars body) | def@(SDef _ _ body) <- defsOnly]
orderedDefs = map (\name -> defMap Map.! name) sortedDefs
topDefNames = Set.fromList (Map.keys defMap) graph = buildDepGraph defsOnly
envNames = Set.fromList (Map.keys env) sortedDefs = sortDeps graph
freeVarsDefs = foldMap (\(SDef _ _ body) -> freeVars body) defsOnly defMap = Map.fromList [(name, def) | def@(SDef name _ _) <- defsOnly]
freeVarsOthers = foldMap freeVars others orderedDefs = map (\name -> defMap Map.! name) sortedDefs
allFreeVars = freeVarsDefs <> freeVarsOthers
validNames = topDefNames `Set.union` envNames freeVarsDefs = foldMap snd defsWithFreeVars
missingDeps = Set.toList (allFreeVars `Set.difference` validNames) freeVarsOthers = foldMap freeVars others
allFreeVars = freeVarsDefs <> freeVarsOthers
validNames = Set.fromList defNames `Set.union` Set.fromList (Map.keys env)
missingDeps = Set.toList (allFreeVars `Set.difference` validNames)
isDef (SDef _ _ _) = True isDef (SDef _ _ _) = True
isDef _ = False isDef _ = False
@ -153,20 +156,21 @@ buildDepGraph topDefs
countOccurrences = foldr (\x -> Map.insertWith (+) x 1) Map.empty countOccurrences = foldr (\x -> Map.insertWith (+) x 1) Map.empty
sortDeps :: Map.Map String (Set.Set String) -> [String] sortDeps :: Map.Map String (Set.Set String) -> [String]
sortDeps graph = go [] (Map.keys graph) sortDeps graph = go [] Set.empty (Map.keys graph)
where where
go sorted [] = sorted go sorted sortedSet [] = sorted
go sorted remaining go sorted sortedSet remaining =
| null ready = let ready = [ name | name <- remaining
errorWithoutStackTrace , let deps = Map.findWithDefault Set.empty name graph
"ERROR: Top-level cyclic dependency detected and prohibited\n\ , Set.isSubsetOf deps sortedSet ]
\RESOLVE: Use nested lambdas" notReady = remaining \\ ready
| otherwise = go (sorted ++ ready) notReady in if null ready
where then errorWithoutStackTrace
ready = [ name | name <- remaining "ERROR: Cyclic dependency detected and prohibited.\n\
, all (`elem` sorted) (Set.toList (graph Map.! name))] \RESOLVE: Use nested lambdas."
notReady = else go (sorted ++ ready)
[ name | name <- remaining , name `notElem` ready] (Set.union sortedSet (Set.fromList ready))
notReady
depends :: [TricuAST] -> TricuAST -> Set.Set String depends :: [TricuAST] -> TricuAST -> Set.Set String
depends topDefs (SDef _ _ body) = depends topDefs (SDef _ _ body) =