tricu

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

commit 52c81f51df59e3897e6a8c65478438d376a1f633
parent 78b6c3ae61805a259764418d7f33187f00ed19a1
Author: James Eversole <james@eversole.co>
Date:   Wed, 14 Oct 2026 17:53:49 -0500

Compile conformance wrappers with the retained portable compiler

Diffstat:
Mdocs/validation.md | 10++++++++--
Atest/PortableTestCompiler.hs | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/Spec.hs | 174++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mtricu.cabal | 1+
4 files changed, 166 insertions(+), 80 deletions(-)

diff --git a/docs/validation.md b/docs/validation.md @@ -162,8 +162,14 @@ independent of the compiled implementations. Mixed-cohort reuse verification in artifact invocation does not remove that separate provenance dependency. This avoids recompiling libraries on every unit run without silently treating old -executable trees as new source. Ordinary test wrappers may use the Haskell -frontend; production module resolution does not fall back to those wrappers. +executable trees as new source. Compiler conformance wrappers use +`test/PortableTestCompiler.hs`: the retained stable unit compiler receives explicit +published fixture imports and a definition body. This test-only header adapter is +not native module resolution; it returns local definitions, not imported names. +Preparation has a 30-second deadline and checks Result/list/name structure without +forcing unused definition values. Invalid source and import shadowing fail without +fallback. Remaining recovery-specific tests still use the historical frontend; +production module resolution never does. ```sh # Reference-source/bundle fingerprints only; no working-tree freshness claim. diff --git a/test/PortableTestCompiler.hs b/test/PortableTestCompiler.hs @@ -0,0 +1,61 @@ +-- Small test-only adapter for retained compiler fixtures. Not a module resolver: +-- imports select published fixture interfaces, and the caller selects definitions +-- to inspect/pack. No recursive source loading, injected kernels or fallback. +module PortableTestCompiler (compileFixtureDefinitions, compileFixtureFile) where + +import Runtime +import ReferenceFixtures (compiledLibraries, fixtureExports) +import SupportFixture (readTestSource) +import Control.Exception (evaluate) +import Control.Monad (foldM) +import Data.List (isPrefixOf) +import qualified Data.Map as Map +import System.Timeout (timeout) +import Text.Read (readMaybe) + +-- Preserve lazy definition values (including unused divergent bodies). Only the +-- Result/list/name spine is validated, under a fixed preparation deadline. +compileFixtureDefinitions :: Env -> String -> IO Env +compileFixtureDefinitions external source = do + prepared <- timeout (30 * 1000000) $ do + let bindings = ofList [Fork (ofString name) value | (name, value) <- Map.toList external] + answer = foldl apply (fixtureExports "source.unit" Map.! "compileStableModuleDefinitions") + [bindings, ofString source] + decode Leaf env = pure env + decode (Fork (Fork name value) rest) env = do + key <- either (fail . ("invalid compiled name: " ++)) pure (toString name) + if Map.member key env + then fail ("duplicate compiled definition: " ++ key) + else decode rest (Map.insert key value env) + decode _ _ = fail "malformed compiled definition list" + case answer of + Fork (Stem Leaf) (Fork definitions Leaf) -> decode definitions Map.empty >>= evaluate + other -> fail ("portable test compilation failed: " ++ show other) + maybe (fail "portable test compilation exceeded 30 seconds") pure prepared + +compileFixtureFile :: FilePath -> IO Env +compileFixtureFile path = do + source <- readTestSource path + let rows = map words (lines source) + legacyFor alias = case [legacy | (legacy, mapped, _) <- fst compiledLibraries, mapped == alias] of + [legacy] -> pure legacy + _ -> fail ("unknown fixture import: " ++ alias) + select legacy namespace = + let exports = fixtureExports legacy + in pure $ maybe exports (\prefix -> Map.mapKeys ((prefix ++ ".") ++) exports) namespace + imported row = case row of + ["!import", encoded, namespace] | Just legacy <- readMaybe encoded -> + select legacy (if namespace == "!Local" then Nothing else Just namespace) + ["!import", alias, "*"] -> legacyFor alias >>= \legacy -> select legacy Nothing + ["!import", alias, "as", namespace] -> legacyFor alias >>= \legacy -> select legacy (Just namespace) + ["!import", alias] -> legacyFor alias >>= \legacy -> select legacy (Just alias) + _ -> fail ("unsupported fixture test import: " ++ unwords row) + merge env row = do + next <- imported row + if Map.null (Map.intersection env next) + then pure (Map.union env next) + else fail "overlapping fixture test imports" + body = unlines [line | line <- lines source, + not (any (`isPrefixOf` line) ["!import ", "!export ", "!source "])] + external <- foldM merge Map.empty [row | row@(first : _) <- rows, first == "!import"] + compileFixtureDefinitions external body diff --git a/test/Spec.hs b/test/Spec.hs @@ -3,6 +3,7 @@ module Main where import Eval import qualified ParserValueTests import qualified LibraryValueTests +import PortableTestCompiler (compileFixtureFile, compileFixtureDefinitions) import ReferenceFixtures import PackageTests (packageTests) import InteractionInspectionTests (interactionInspectionTests) @@ -3270,7 +3271,7 @@ locatedLexerTests = testGroup "Located character-scanning library" -- -------------------------------------------------------------------------- gateLexerEnv :: Env -gateLexerEnv = unsafePerformIO $ evaluateCompilerFile "./lib/source/lexer.tri" +gateLexerEnv = fixtureExports "source.lexer" {-# NOINLINE gateLexerEnv #-} gatePosition :: Integer -> Integer -> Integer -> T @@ -3445,7 +3446,7 @@ gateLexerTests = testGroup "Feasibility-gate source lexer" ] where check input expected = - result (evalTricu gateLexerEnv (parseTricu ("lexGateSource " ++ show input))) @?= expected + apply (gateLexerEnv Map.! "lexGateSource") (ofString input) @?= expected -- -------------------------------------------------------------------------- -- Single-expression feasibility-gate surface parser @@ -3491,11 +3492,7 @@ evaluateCompilerFile path = case [legacy | (legacy, _, source) <- fst compiledLibraries, source == maybe path id (stripPrefix "./" path)] of [legacy] -> compiledModuleEnv legacy - [] -> do - text <- readTestSource path - imported <- compilerTestImports text - let body = unlines [line | line <- lines text, not (any (`isPrefixOf` line) ["!import ", "!export ", "!source "])] - pure (evalTricu (injectKernel imported) (parseTricu body)) + [] -> compileFixtureFile path _ -> error "ambiguous compiler fixture module" -- Explicit unit-test support bridge for portable libraries. @@ -3595,8 +3592,8 @@ recoveryFoundationBody name = do unless (actual == headers) $ error "unsupported recovery reference foundation headers" pure (unlines body) --- Only ordinary test-wrapper lambdas are host-compiled; library payloads come --- from the checked self-built fixture. Native packing remains a host mechanism. +-- Test wrappers are compiled by the retained portable stable unit API; library +-- payloads come from authenticated fixtures. Packing remains a host mechanism. packCompilerFile :: FilePath -> FilePath -> [Text] -> IO () packCompilerFile input output names = do env <- evaluateCompilerFile input @@ -3682,6 +3679,27 @@ compilerFixtureTests = testGroup "self-built reference compiler fixture" case rejected of Left _ -> pure () Right _ -> assertFailure "unknown fixture module silently accepted" + , testCase "portable wrapper compilation keeps unused definitions lazy" $ do + env <- compileFixtureDefinitions Map.empty + "unused = (x : x x) (x : x x)\nmain = t" + Map.keys env @?= ["main", "unused"] + Map.lookup "main" env @?= Just Leaf + , testCase "portable wrapper compilation rejects invalid source without fallback" $ do + forM_ ["main = missing", "main = t\nmain = t", "t", "main = #"] $ \source -> do + rejected <- try (compileFixtureDefinitions Map.empty source) :: IO (Either SomeException Env) + case rejected of + Left err -> assertBool "expected portable diagnostic" + ("portable test compilation failed" `isInfixOf` show err) + Right _ -> assertFailure ("accepted invalid wrapper: " ++ source) + , testCase "portable wrapper compilation uses only explicit externals" $ do + env <- compileFixtureDefinitions (Map.singleton "outside" (Stem Leaf)) "main = outside t" + Map.keys env @?= ["main"] + Map.lookup "main" env @?= Just (Fork Leaf Leaf) + rejected <- try (compileFixtureDefinitions (Map.singleton "outside" Leaf) "outside = t") + :: IO (Either SomeException Env) + case rejected of + Left _ -> pure () + Right _ -> assertFailure "wrapper shadows an imported name" , testCase "every reference compiler module authors native headers" $ do forM_ (fst compilerFixture) $ \(_, _, path) -> do source <- readTestSource path @@ -3858,7 +3876,7 @@ compilerFixtureTests = testGroup "self-built reference compiler fixture" ] gateParserEnv :: Env -gateParserEnv = unsafePerformIO $ evaluateCompilerFile "./lib/source/parser.tri" +gateParserEnv = fixtureExports "source.parser" {-# NOINLINE gateParserEnv #-} gateAst :: Integer -> T -> T -> T -> T @@ -4056,14 +4074,14 @@ gateParserTests = testGroup "Feasibility-gate source parser" ] where check input expected = - result (evalTricu gateParserEnv (parseTricu ("parseGateSource " ++ show input))) @?= expected + apply (gateParserEnv Map.! "parseGateSource") (ofString input) @?= expected -- -------------------------------------------------------------------------- -- Program-level feasibility-gate parsing (definitions and final expression) -- -------------------------------------------------------------------------- equationHelperEnv :: Env -equationHelperEnv = unsafePerformIO $ evaluateCompilerFile "./lib/source/equations.tri" +equationHelperEnv = fixtureExports "source.equations" {-# NOINLINE equationHelperEnv #-} equationHelperTests :: TestTree @@ -4095,7 +4113,7 @@ equationHelperTests = testGroup "Equation helper pattern adoption" , testCase "improper pattern suffix retains prior non-list termination" $ list (Fork left (Stem Leaf)) @?= joined left nil , testCase "empty pattern list retains an opaque supplied tail" $ - apply (allTestLibsEnv Map.! "fst") + apply (fixtureExports "base" Map.! "fst") (call "sourceEquationList" [Leaf, Fork (ofNumber 23) (error "unused suffix demanded")]) @?= ofNumber 23 ] @@ -4124,7 +4142,7 @@ equationHelperTests = testGroup "Equation helper pattern adoption" list value = call "sourceEquationList" [value, nil] gateProgramEnv :: Env -gateProgramEnv = unsafePerformIO $ evaluateCompilerFile "./lib/source/program.tri" +gateProgramEnv = fixtureExports "source.program" {-# NOINLINE gateProgramEnv #-} gateProgramTests :: TestTree @@ -4171,15 +4189,14 @@ gateProgramTests = testGroup "Feasibility-gate program parser" in portableReply True (pairT (ofList [pairT name body]) (Stem expression)) Leaf True False check input expected = - result (evalTricu gateProgramEnv - (parseTricu ("parseGateProgram " ++ show input))) @?= expected + apply (gateProgramEnv Map.! "parseGateProgram") (ofString input) @?= expected -- -------------------------------------------------------------------------- -- Portable, stable dependency ordering and cycle witnesses -- -------------------------------------------------------------------------- sourceGraphEnv :: Env -sourceGraphEnv = unsafePerformIO $ evaluateCompilerFile "./lib/graph.tri" +sourceGraphEnv = fixtureExports "graph" {-# NOINLINE sourceGraphEnv #-} sourceGraphTests :: TestTree @@ -4189,23 +4206,24 @@ sourceGraphTests = testGroup "Source dependency graph" Map.lookup "main" env @?= Just (parserOk (ofList (map ofString ["leaf", "inner", "outer"])) Leaf) , testCase "sort preserves source order among simultaneously ready nodes" $ - check "[(pair \"b\" []) (pair \"a\" [])]" + check [("b", []), ("a", [])] (parserOk (ofList [ofString "b", ofString "a"]) Leaf) , testCase "cycle witness is in the cycle, not just a dependent" $ - check "[(pair \"outside\" [\"inside\"]) (pair \"inside\" [\"last\"]) (pair \"last\" [\"inside\"])]" + check [("outside", ["inside"]), ("inside", ["last"]), ("last", ["inside"])] (parserErr (ofString "inside") Leaf) ] where check entries expected = - result (evalTricu sourceGraphEnv - (parseTricu ("graphSort " ++ entries))) @?= expected + apply (sourceGraphEnv Map.! "graphSort") + (ofList [Fork (ofString name) (ofList (map ofString dependencies)) + | (name, dependencies) <- entries]) @?= expected -- -------------------------------------------------------------------------- -- Program-level free names and dependency ordering -- -------------------------------------------------------------------------- gateOrderingEnv :: Env -gateOrderingEnv = unsafePerformIO $ evaluateCompilerFile "./lib/source/order.tri" +gateOrderingEnv = fixtureExports "source.order" {-# NOINLINE gateOrderingEnv #-} gateOrderingTests :: TestTree @@ -4216,16 +4234,16 @@ gateOrderingTests = testGroup "Feasibility-gate definition ordering" Map.lookup "main" env @?= Just (parserOk (ofList [ofString "f", ofString "main"]) Leaf) , testCase "unused definitions still have their names checked" $ - check "[]" "main = t\nbroken = u" (parserErr + check Leaf "main = t\nbroken = u" (parserErr (portableDiagnostic (ofNumber 20) (ofString "u") Leaf (gatePosition 2 10 18) Leaf) (gateAst 2 (ofString "u") (gatePosition 2 10 18) (gatePosition 2 11 19))) , testCase "lexical binder shadows a definition and external name" $ - check "[(pair \"x\" t)]" "x = t\nf x = x" (parserOk + check (ofList [Fork (ofString "x") Leaf]) "x = t\nf x = x" (parserOk (ofList [ofString "x", ofString "f"]) Leaf) , testCase "top-level self reference returns a cycle witness" $ - check "[]" "f = f" (parserErr + check Leaf "f = f" (parserErr (portableDiagnostic (ofNumber 31) (ofString "acyclic") (ofString "f") (gatePosition 1 1 0) (ofList [ofString "f"])) Leaf) @@ -4234,12 +4252,12 @@ gateOrderingTests = testGroup "Feasibility-gate definition ordering" (gatePosition 2 1 6) (gatePosition 2 2 7) body = gateAst 1 Leaf (gatePosition 2 5 10) (gatePosition 2 6 11) - in check "[]" "f = t\nf = t" (parserErr + in check Leaf "f = t\nf = t" (parserErr (portableDiagnostic (ofNumber 30) (ofString "f") (ofString "f") (gatePosition 2 1 6) Leaf) (pairT name body)) , testCase "a final expression also checks unresolved names" $ - check "[]" "f = t\nu" (parserErr + check Leaf "f = t\nu" (parserErr (portableDiagnostic (ofNumber 20) (ofString "u") Leaf (gatePosition 2 1 6) Leaf) (gateAst 2 (ofString "u") @@ -4247,8 +4265,7 @@ gateOrderingTests = testGroup "Feasibility-gate definition ordering" ] where check environment source expected = - result (evalTricu gateOrderingEnv - (parseTricu ("orderGateSource " ++ environment ++ " " ++ show source))) + foldl apply (gateOrderingEnv Map.! "orderGateSource") [environment, ofString source] @?= expected -- -------------------------------------------------------------------------- @@ -4536,17 +4553,22 @@ gateUnitTests = testGroup "Feasibility-gate program compiler" env <- evaluateCompilerFile "./test/sourcePublicCompiler.tri" Map.member "matchesSource" env @?= True - let compile environment source = result (evalTricu - (Map.union env allTestLibsEnv) - (parseTricu ("compileSource " ++ environment ++ " " ++ show source))) - compile "[]" "main = value\nvalue = t" @?= - parserOk (pairT Leaf (ofList - [pairT (ofString "value") Leaf, pairT (ofString "main") Leaf])) Leaf - compile "[(pair \"host\" (t t))]" "host" @?= - parserOk (pairT (Stem Leaf) Leaf) Leaf - compile "[]" "helper = t" @?= - parserErr (portableDiagnostic (ofNumber 32) - (ofString "main") Leaf Leaf Leaf) Leaf + let check environment source expected = do + foldl apply (fixtureExports "source.unit" Map.! "compileSource") + [environment, ofString source] @?= expected + foldl apply (env Map.! "matchesSource") + [environment, ofString source, expected] @?= trueT + assertBool "test wrapper leaked imported compiler" (Map.notMember "compileSource" env) + check Leaf "main = value\nvalue = t" + (parserOk (pairT Leaf (ofList + [pairT (ofString "value") Leaf, pairT (ofString "main") Leaf])) Leaf) + check (ofList [Fork (ofString "host") (Stem Leaf)]) "host" + (parserOk (pairT (Stem Leaf) Leaf) Leaf) + check Leaf "helper = t" + (parserErr (portableDiagnostic (ofNumber 32) + (ofString "main") Leaf Leaf Leaf) Leaf) + foldl apply (env Map.! "matchesSource") + [Leaf, ofString "main = t", parserOk (pairT (Stem Leaf) Leaf) Leaf] @?= falseT , testCase "public compileSource is an exportable two-argument bundle" $ withSystemTempDirectory "public-source-artifact" $ \dir -> do let path = dir </> "compile-source.arboricx" @@ -4828,7 +4850,7 @@ gateUnitTests = testGroup "Feasibility-gate program compiler" -- -------------------------------------------------------------------------- gateResolveEnv :: Env -gateResolveEnv = unsafePerformIO $ evaluateCompilerFile "./lib/source/resolve.tri" +gateResolveEnv = fixtureExports "source.resolve" {-# NOINLINE gateResolveEnv #-} gateCore :: Integer -> T -> T -> T -> T @@ -4843,12 +4865,12 @@ gateResolutionTests = testGroup "Feasibility-gate resolution" Map.lookup "main" env @?= Just (parserOk lam Leaf) , testCase "nearest lexical binder has index zero" $ let bound = gateCore 2 (ofNumber 0) (gatePosition 1 5 4) (gatePosition 1 6 5) - in check "[]" "x : x" (parserOk + in check Leaf "x : x" (parserOk (gateCore 4 bound (gatePosition 1 1 0) (gatePosition 1 6 5)) Leaf) , testCase "outer lexical binder has index one" $ let bound = gateCore 2 (ofNumber 1) (gatePosition 1 9 8) (gatePosition 1 10 9) inner = gateCore 4 bound (gatePosition 1 5 4) (gatePosition 1 10 9) - in check "[]" "x : y : x" (parserOk + in check Leaf "x : y : x" (parserOk (gateCore 4 inner (gatePosition 1 1 0) (gatePosition 1 10 9)) Leaf) , testCase "local binding lowers to an applied scoped lambda" $ let value = gateCore 1 Leaf @@ -4857,7 +4879,7 @@ gateResolutionTests = testGroup "Feasibility-gate resolution" (gatePosition 1 14 13) (gatePosition 1 15 14) scoped = gateCore 4 bound (gatePosition 1 1 0) (gatePosition 1 15 14) - in check "[]" "let x = t in x" (parserOk + in check Leaf "let x = t in x" (parserOk (gateCore 3 (pairT scoped value) (gatePosition 1 1 0) (gatePosition 1 15 14)) Leaf) , testCase "forward pipe elaborates to reversed core application" $ @@ -4865,24 +4887,24 @@ gateResolutionTests = testGroup "Feasibility-gate resolution" (gatePosition 1 6 5) (gatePosition 1 7 6) argument = gateCore 6 (ofNumber 2) (gatePosition 1 1 0) (gatePosition 1 2 1) - in check "[(pair \"f\" (t t))]" "2 |> f" (parserOk + in check (ofList [Fork (ofString "f") (Stem Leaf)]) "2 |> f" (parserOk (gateCore 3 (pairT function argument) (gatePosition 1 1 0) (gatePosition 1 7 6)) Leaf) , testCase "number becomes a resolved tree literal" $ - check "[]" "42" (parserOk + check Leaf "42" (parserOk (gateCore 6 (ofNumber 42) (gatePosition 1 1 0) (gatePosition 1 3 2)) Leaf) , testCase "string becomes a resolved tree literal" $ - check "[]" "\"hi\"" (parserOk + check Leaf "\"hi\"" (parserOk (gateCore 7 (ofString "hi") (gatePosition 1 1 0) (gatePosition 1 5 4)) Leaf) , testCase "list elements become individually resolved core nodes" $ let leaf = gateCore 1 Leaf (gatePosition 1 2 1) (gatePosition 1 3 2) number = gateCore 6 (ofNumber 2) (gatePosition 1 4 3) (gatePosition 1 5 4) - in check "[]" "[t 2]" (parserOk + in check Leaf "[t 2]" (parserOk (gateCore 8 (ofList [leaf, number]) (gatePosition 1 1 0) (gatePosition 1 6 5)) Leaf) , testCase "unresolved list element preserves its own span" $ - check "[]" "[u]" (parserErr + check Leaf "[u]" (parserErr (portableDiagnostic (ofNumber 20) (ofString "u") Leaf (gatePosition 1 2 1) Leaf) (gateAst 2 (ofString "u") @@ -4891,37 +4913,36 @@ gateResolutionTests = testGroup "Feasibility-gate resolution" let external = gateCore 5 (Stem Leaf) (gatePosition 1 1 0) (gatePosition 1 2 1) leaf = gateCore 1 Leaf (gatePosition 1 3 2) (gatePosition 1 4 3) - in check "[(pair \"f\" (t t))]" "f t" (parserOk + in check (ofList [Fork (ofString "f") (Stem Leaf)]) "f t" (parserOk (gateCore 3 (pairT external leaf) (gatePosition 1 1 0) (gatePosition 1 4 3)) Leaf) , testCase "lexical binder shadows an external value" $ let bound = gateCore 2 (ofNumber 0) (gatePosition 1 5 4) (gatePosition 1 6 5) - in check "[(pair \"x\" (t t))]" "x : x" (parserOk + in check (ofList [Fork (ofString "x") (Stem Leaf)]) "x : x" (parserOk (gateCore 4 bound (gatePosition 1 1 0) (gatePosition 1 6 5)) Leaf) , testCase "unresolved name reports its original position" $ - check "[]" "u" (parserErr + check Leaf "u" (parserErr (portableDiagnostic (ofNumber 20) (ofString "u") Leaf (gatePosition 1 1 0) Leaf) (gateAst 2 (ofString "u") (gatePosition 1 1 0) (gatePosition 1 2 1))) , testCase "grouping carries its span into the core" $ - check "[]" "(t)" (parserOk + check Leaf "(t)" (parserOk (gateCore 1 Leaf (gatePosition 1 1 0) (gatePosition 1 4 3)) Leaf) ] where check environment input expected = - result (evalTricu gateResolveEnv - (parseTricu ("resolveGateSource " ++ environment ++ " " ++ show input))) @?= expected + foldl apply (gateResolveEnv Map.! "resolveGateSource") [environment, ofString input] @?= expected -- -------------------------------------------------------------------------- -- Reference S/K/I compiler for the feasibility gate -- -------------------------------------------------------------------------- gateCompileEnv :: Env -gateCompileEnv = unsafePerformIO $ evaluateCompilerFile "./lib/source/compile.tri" +gateCompileEnv = fixtureExports "source.compile" {-# NOINLINE gateCompileEnv #-} gateCompileBaseEnv :: Env -gateCompileBaseEnv = unsafePerformIO $ recoveryFoundationEnv "base" +gateCompileBaseEnv = fixtureExports "base" {-# NOINLINE gateCompileBaseEnv #-} gateCompilationTests :: TestTree @@ -5065,15 +5086,13 @@ gateCompilationTests = testGroup "Feasibility-gate source compiler" , testCase "nested lambdas preserve the outer argument" $ checkFunction "x : y : x" [ofNumber 5, ofNumber 8] (ofNumber 5) , testCase "pruned bracket agrees with the retained reference" $ do - let var = "sourceTermVariable 0 t" - leaf = "sourceTermLiteral t t" - terms = [ var, leaf - , "sourceTermApply (" ++ var ++ ") (" ++ leaf ++ ") t" - , "sourceTermApply (" ++ leaf ++ ") (" ++ var ++ ") t" - , "sourceTermApply (" ++ var ++ ") (" ++ var ++ ") t" - ] - compiled method term = result (evalTricu gateCompileEnv (parseTricu - ("sourceRunTerm (" ++ method ++ " (" ++ term ++ "))"))) + let term kind payload = Fork (ofNumber kind) (Fork payload Leaf) + var = term 2 Leaf + leaf = term 1 Leaf + app f x = term 3 (Fork f x) + terms = [var, leaf, app var leaf, app leaf var, app var var] + compiled method value = apply (gateCompileEnv Map.! "sourceRunTerm") + (apply (gateCompileEnv Map.! method) value) forM_ terms $ \term -> case (compiled "sourceBracketReference" term, compiled "sourceBracket" term) of @@ -5084,10 +5103,10 @@ gateCompilationTests = testGroup "Feasibility-gate source compiler" apply optimized argument @?= apply reference argument other -> assertFailure ("Expected two bracketed trees, got " ++ show other) , testCase "star eta and retained B/C reference agree when applied" $ do - let compiled method source = result (evalTricu gateCompileEnv (parseTricu - ("lazyResult (diagnostic rest : err diagnostic rest) " - ++ "(core rest : " ++ method ++ " core) " - ++ "(resolveGateSource [] " ++ show source ++ ")"))) + let compiled method source = + case foldl apply (gateResolveEnv Map.! "resolveGateSource") [Leaf, ofString source] of + Fork tag (Fork core Leaf) | tag == trueT -> apply (gateCompileEnv Map.! method) core + other -> error ("reference corpus failed resolution: " ++ show other) corpus = [ ("x : x", [ofNumber 5], ofNumber 5) , ("x y : x", [ofNumber 5, ofNumber 8], ofNumber 5) @@ -5110,15 +5129,15 @@ gateCompilationTests = testGroup "Feasibility-gate source compiler" , testCase "application inside a lambda behaves correctly" $ checkFunction "f : x : f x" [Stem Leaf, ofNumber 8] (Fork Leaf (ofNumber 8)) , testCase "external tree is applied without host lookup" $ - let input = "compileGateSource [(pair \"f\" (t t))] \"f t\"" - in result (evalTricu gateCompileEnv (parseTricu input)) @?= + foldl apply (gateCompileEnv Map.! "compileGateSource") + [ofList [Fork (ofString "f") (Stem Leaf)], ofString "f t"] @?= parserOk (Fork Leaf Leaf) Leaf , testCase "backend compiles a recursive source function" $ do let source = "xs : y (self : rest : triage t (h : self h) (a : b : self a) rest) xs" - input = "compileGateSource [(pair \"y\" y) (pair \"triage\" triage)] " - ++ show source - env = evalTricu (Map.union gateCompileEnv gateCompileBaseEnv) (parseTricu input) - case result env of + external = ofList [Fork (ofString name) (gateCompileBaseEnv Map.! name) + | name <- ["y", "triage"]] + compiled = foldl apply (gateCompileEnv Map.! "compileGateSource") [external, ofString source] + case compiled of Fork tag (Fork compiled Leaf) | tag == trueT -> do apply compiled Leaf @?= Leaf apply compiled (Stem Leaf) @?= Leaf @@ -5134,8 +5153,7 @@ gateCompilationTests = testGroup "Feasibility-gate source compiler" nestedIdentity depth = iterate (\body -> "(x : x) (" ++ body ++ ")") "t" !! depth nestedBinders depth = "(" ++ concatMap (\i -> "x" ++ show i ++ " : ") [0 .. depth - 1] ++ "x0) " ++ unwords (replicate depth "t") - compile input = result (evalTricu gateCompileEnv - (parseTricu ("compileGateSource [] " ++ show input))) + compile input = foldl apply (gateCompileEnv Map.! "compileGateSource") [Leaf, ofString input] check input expected = compile input @?= expected checkFunction input args expected = case compile input of Fork tag (Fork fn Leaf) | tag == trueT -> foldl apply fn args @?= expected diff --git a/tricu.cabal b/tricu.cabal @@ -208,4 +208,5 @@ test-suite tricu-tests SupportFixture LibraryValueTests ParserValueTests + PortableTestCompiler ReferenceFixtures