tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

PortableTestCompiler.hs (3340B)


      1 -- Small test-only adapter for retained compiler fixtures. Not a module resolver:
      2 -- imports select published fixture interfaces, and the caller selects definitions
      3 -- to inspect/pack. No recursive source loading, injected kernels or fallback.
      4 module PortableTestCompiler (compileFixtureDefinitions, compileFixtureFile) where
      5 
      6 import Runtime
      7 import ReferenceFixtures (compiledLibraries, fixtureExports)
      8 import SupportFixture (readTestSource)
      9 import Control.Exception (evaluate)
     10 import Control.Monad (foldM)
     11 import Data.List (isPrefixOf)
     12 import qualified Data.Map as Map
     13 import System.Timeout (timeout)
     14 import Text.Read (readMaybe)
     15 
     16 -- Preserve lazy definition values (including unused divergent bodies). Only the
     17 -- Result/list/name spine is validated, under a fixed preparation deadline.
     18 compileFixtureDefinitions :: Env -> String -> IO Env
     19 compileFixtureDefinitions external source = do
     20   prepared <- timeout (30 * 1000000) $ do
     21     let bindings = ofList [Fork (ofString name) value | (name, value) <- Map.toList external]
     22         answer = foldl apply (fixtureExports "source.unit" Map.! "compileStableModuleDefinitions")
     23           [bindings, ofString source]
     24         decode Leaf env = pure env
     25         decode (Fork (Fork name value) rest) env = do
     26           key <- either (fail . ("invalid compiled name: " ++)) pure (toString name)
     27           if Map.member key env
     28             then fail ("duplicate compiled definition: " ++ key)
     29             else decode rest (Map.insert key value env)
     30         decode _ _ = fail "malformed compiled definition list"
     31     case answer of
     32       Fork (Stem Leaf) (Fork definitions Leaf) -> decode definitions Map.empty >>= evaluate
     33       other -> fail ("portable test compilation failed: " ++ show other)
     34   maybe (fail "portable test compilation exceeded 30 seconds") pure prepared
     35 
     36 compileFixtureFile :: FilePath -> IO Env
     37 compileFixtureFile path = do
     38   source <- readTestSource path
     39   let rows = map words (lines source)
     40       legacyFor alias = case [legacy | (legacy, mapped, _) <- fst compiledLibraries, mapped == alias] of
     41         [legacy] -> pure legacy
     42         _ -> fail ("unknown fixture import: " ++ alias)
     43       select legacy namespace =
     44         let exports = fixtureExports legacy
     45         in pure $ maybe exports (\prefix -> Map.mapKeys ((prefix ++ ".") ++) exports) namespace
     46       imported row = case row of
     47         ["!import", encoded, namespace] | Just legacy <- readMaybe encoded ->
     48           select legacy (if namespace == "!Local" then Nothing else Just namespace)
     49         ["!import", alias, "*"] -> legacyFor alias >>= \legacy -> select legacy Nothing
     50         ["!import", alias, "as", namespace] -> legacyFor alias >>= \legacy -> select legacy (Just namespace)
     51         ["!import", alias] -> legacyFor alias >>= \legacy -> select legacy (Just alias)
     52         _ -> fail ("unsupported fixture test import: " ++ unwords row)
     53       merge env row = do
     54         next <- imported row
     55         if Map.null (Map.intersection env next)
     56           then pure (Map.union env next)
     57           else fail "overlapping fixture test imports"
     58       body = unlines [line | line <- lines source,
     59                        not (any (`isPrefixOf` line) ["!import ", "!export ", "!source "])]
     60   external <- foldM merge Map.empty [row | row@(first : _) <- rows, first == "!import"]
     61   compileFixtureDefinitions external body