1
1
mirror of https://github.com/anoma/juvix.git synced 2025-01-05 22:46:08 +03:00

VampIR integration (#2103)

* Closes #2035 
* Depends on #2086 
* Depends on #2096 
* Adds end-to-end tests for the Juvix-to-VampIR compilation pipeline.

---------

Co-authored-by: Jonathan Cubides <jonathan.cubides@uib.no>
This commit is contained in:
Łukasz Czajka 2023-05-22 20:18:18 +02:00 committed by GitHub
parent 2148d174f5
commit d576111241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
91 changed files with 1127 additions and 361 deletions

View File

@ -58,7 +58,7 @@ instance PrettyCode LocalDef where
ppCode LocalDef {..} = do
n <- ppName KNameLocal _localDefName
v <- ppCode _localDefValue
return $ kwDef <+> n <+> kwEq <+> v <> semi <> line
return $ kwDef <+> n <+> kwEq <+> v <> semi
instance PrettyCode Function where
ppCode Function {..} = do
@ -71,9 +71,9 @@ instance PrettyCode Function where
ppEquation :: Function -> Sem r (Doc Ann)
ppEquation Function {..} = do
let n = length _functionArguments
args = if n == 1 then ["in"] else map (\k -> "in" <> show k) [1 .. n]
args = if n == 1 then ["(in + 0)"] else map (\k -> "(in" <> show k <> " + 0)") [1 .. n]
fn <- ppName KNameFunction _functionName
return $ fn <+> hsep args <+> kwEq <+> "out" <> semi
return $ fn <+> hsep args <+> kwEq <+> "(out + 0)" <> semi
instance PrettyCode Program where
ppCode Program {..} = do
@ -92,11 +92,8 @@ vampIRDefs =
"def mul x y = x * y;",
"def isZero x = {def xi = fresh (1 | x); x * (1 - xi * x) = 0; 1 - xi * x};",
"def equal x y = isZero (x - y);",
"def bool x = {x * (x - 1) = 0; x};",
"def range32 a = {def a0 = bool (fresh ((a \\ 1) % 2)); def a1 = bool (fresh ((a \\ 2) % 2)); def a2 = bool (fresh ((a \\ 4) % 2)); def a3 = bool (fresh ((a \\ 8) % 2)); def a4 = bool (fresh ((a \\ 16) % 2)); def a5 = bool (fresh ((a \\ 32) % 2)); def a6 = bool (fresh ((a \\ 64) % 2)); def a7 = bool (fresh ((a \\ 128) % 2)); def a8 = bool (fresh ((a \\ 256) % 2)); def a9 = bool (fresh ((a \\ 512) % 2)); def a10 = bool (fresh ((a \\ 1024) % 2)); def a11 = bool (fresh ((a \\ 2048) % 2)); def a12 = bool (fresh ((a \\ 4096) % 2)); def a13 = bool (fresh ((a \\ 8192) % 2)); def a14 = bool (fresh ((a \\ 16384) % 2)); def a15 = bool (fresh ((a \\ 32768) % 2)); def a16 = bool (fresh ((a \\ 65536) % 2)); def a17 = bool (fresh ((a \\ 131072) % 2)); def a18 = bool (fresh ((a \\ 262144) % 2)); def a19 = bool (fresh ((a \\ 524288) % 2)); def a20 = bool (fresh ((a \\ 1048576) % 2)); def a21 = bool (fresh ((a \\ 2097152) % 2)); def a22 = bool (fresh ((a \\ 4194304) % 2)); def a23 = bool (fresh ((a \\ 8388608) % 2)); def a24 = bool (fresh ((a \\ 16777216) % 2)); def a25 = bool (fresh ((a \\ 33554432) % 2)); def a26 = bool (fresh ((a \\ 67108864) % 2)); def a27 = bool (fresh ((a \\ 134217728) % 2)); def a28 = bool (fresh ((a \\ 268435456) % 2)); def a29 = bool (fresh ((a \\ 536870912) % 2)); def a30 = bool (fresh ((a \\ 1073741824) % 2)); def a31 = bool (fresh ((a \\ 2147483648) % 2)); a = ((((((((((((((((((((((((((((((a0 + (2 * a1)) + (4 * a2)) + (8 * a3)) + (16 * a4)) + (32 * a5)) + (64 * a6)) + (128 * a7)) + (256 * a8)) + (512 * a9)) + (1024 * a10)) + (2048 * a11)) + (4096 * a12)) + (8192 * a13)) + (16384 * a14)) + (32768 * a15)) + (65536 * a16)) + (131072 * a17)) + (262144 * a18)) + (524288 * a19)) + (1048576 * a20)) + (2097152 * a21)) + (4194304 * a22)) + (8388608 * a23)) + (16777216 * a24)) + (33554432 * a25)) + (67108864 * a26)) + (134217728 * a27)) + (268435456 * a28)) + (536870912 * a29)) + (1073741824 * a30)) + (2147483648 * a31); (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, ())};",
"def intrange32 a = {range32 (a + 2147483648)};",
"def negative32 a = {def (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, ()) = intrange32 a; a31};",
"def isNegative x = negative32 x;",
"def isBool x = (x * (x - 1) = 0);",
"def isNegative a = {def e = 2^30; def b = a + e; def b0 = fresh (b % e); def b1 = fresh (b \\ e); isBool b1; b = b0 + e * b1; 1 - b1};",
"def lessThan x y = isNegative (x - y);",
"def lessOrEqual x y = lessThan x (y + 1);",
"def divRem a b = {def q = fresh (a\\b); def r = fresh (a%b); isNegative r = 0; lessThan r b = 1; a = b * q + r; (q, r) };",

View File

@ -20,6 +20,7 @@ data TransformationId
| DisambiguateNames
| CheckGeb
| CheckExec
| CheckVampIR
| Normalize
| LetFolding
| LambdaFolding
@ -68,7 +69,7 @@ toNormalizeTransformations :: [TransformationId]
toNormalizeTransformations = toEvalTransformations ++ [LetRecLifting, LetFolding, UnrollRecursion]
toVampIRTransformations :: [TransformationId]
toVampIRTransformations = toNormalizeTransformations ++ [Normalize, LetHoisting]
toVampIRTransformations = toEvalTransformations ++ [CheckVampIR, LetRecLifting, LetFolding, UnrollRecursion, Normalize, LetHoisting]
toStrippedTransformations :: [TransformationId]
toStrippedTransformations =

View File

@ -80,6 +80,7 @@ transformationText = \case
DisambiguateNames -> strDisambiguateNames
CheckGeb -> strCheckGeb
CheckExec -> strCheckExec
CheckVampIR -> strCheckVampIR
Normalize -> strNormalize
LetFolding -> strLetFolding
LambdaFolding -> strLambdaFolding
@ -169,6 +170,9 @@ strCheckGeb = "check-geb"
strCheckExec :: Text
strCheckExec = "check-exec"
strCheckVampIR :: Text
strCheckVampIR = "check-vampir"
strNormalize :: Text
strNormalize = "normalize"

View File

@ -12,8 +12,9 @@ import Juvix.Compiler.Core.Data.TransformationId
import Juvix.Compiler.Core.Error
import Juvix.Compiler.Core.Options
import Juvix.Compiler.Core.Transformation.Base
import Juvix.Compiler.Core.Transformation.CheckExec
import Juvix.Compiler.Core.Transformation.CheckGeb
import Juvix.Compiler.Core.Transformation.Check.Exec
import Juvix.Compiler.Core.Transformation.Check.Geb
import Juvix.Compiler.Core.Transformation.Check.VampIR
import Juvix.Compiler.Core.Transformation.ComputeTypeInfo
import Juvix.Compiler.Core.Transformation.ConvertBuiltinTypes
import Juvix.Compiler.Core.Transformation.DisambiguateNames
@ -61,6 +62,7 @@ applyTransformations ts tbl = foldM (flip appTrans) tbl ts
DisambiguateNames -> return . disambiguateNames
CheckGeb -> mapError (JuvixError @CoreError) . checkGeb
CheckExec -> mapError (JuvixError @CoreError) . checkExec
CheckVampIR -> mapError (JuvixError @CoreError) . checkVampIR
Normalize -> return . normalize
LetFolding -> return . letFolding
LambdaFolding -> return . lambdaFolding

View File

@ -0,0 +1,118 @@
module Juvix.Compiler.Core.Transformation.Check.Base where
import Juvix.Compiler.Core.Data.InfoTable
import Juvix.Compiler.Core.Data.TypeDependencyInfo (createTypeDependencyInfo)
import Juvix.Compiler.Core.Error
import Juvix.Compiler.Core.Extra
import Juvix.Compiler.Core.Info.LocationInfo (getInfoLocation)
import Juvix.Compiler.Core.Info.TypeInfo qualified as Info
import Juvix.Compiler.Core.Language
import Juvix.Data.PPOutput
dynamicTypeError :: Node -> Maybe Location -> CoreError
dynamicTypeError node loc =
CoreError
{ _coreErrorMsg = ppOutput $ "compilation for this target requires full type information",
_coreErrorNode = Just node,
_coreErrorLoc = fromMaybe defaultLoc loc
}
unsupportedError :: Text -> Node -> Maybe Location -> CoreError
unsupportedError what node loc =
CoreError
{ _coreErrorMsg = ppOutput $ pretty what <> " not supported for this target",
_coreErrorNode = Just node,
_coreErrorLoc = fromMaybe defaultLoc loc
}
defaultLoc :: Interval
defaultLoc = singletonInterval (mkInitialLoc mockFile)
where
mockFile :: Path Abs File
mockFile = $(mkAbsFile "/core-check")
checkBuiltins :: forall r. Member (Error CoreError) r => Bool -> Node -> Sem r Node
checkBuiltins allowUntypedFail = dmapRM go
where
go :: Node -> Sem r Recur
go node = case node of
NPrim TypePrim {..}
| _typePrimPrimitive == PrimString ->
throw $ unsupportedError "strings" node (getInfoLocation _typePrimInfo)
NBlt BuiltinApp {..} ->
case _builtinAppOp of
OpShow -> throw $ unsupportedError "strings" node (getInfoLocation _builtinAppInfo)
OpStrConcat -> throw $ unsupportedError "strings" node (getInfoLocation _builtinAppInfo)
OpStrToInt -> throw $ unsupportedError "strings" node (getInfoLocation _builtinAppInfo)
OpTrace -> throw $ unsupportedError "tracing" node (getInfoLocation _builtinAppInfo)
OpFail | not allowUntypedFail -> do
let ty = Info.getInfoType _builtinAppInfo
when (isDynamic ty) $
throw $
unsupportedError "failing without type info" node (getInfoLocation _builtinAppInfo)
return $ Recur node
OpFail -> do
return $ End node
_ -> return $ Recur node
_ -> return $ Recur node
checkNoIO :: forall r. Member (Error CoreError) r => Node -> Sem r Node
checkNoIO = dmapM go
where
go :: Node -> Sem r Node
go node = case node of
NCtr Constr {..} ->
case _constrTag of
BuiltinTag TagReturn -> throw $ unsupportedError "IO" node (getInfoLocation _constrInfo)
BuiltinTag TagBind -> throw $ unsupportedError "IO" node (getInfoLocation _constrInfo)
BuiltinTag TagReadLn -> throw $ unsupportedError "IO" node (getInfoLocation _constrInfo)
BuiltinTag TagWrite -> throw $ unsupportedError "IO" node (getInfoLocation _constrInfo)
_ -> return node
_ -> return node
checkTypes :: forall r. Member (Error CoreError) r => Bool -> InfoTable -> Node -> Sem r Node
checkTypes allowPolymorphism tab = dmapM go
where
go :: Node -> Sem r Node
go node = case node of
NIdt Ident {..}
| isDynamic (lookupIdentifierInfo tab _identSymbol ^. identifierType) ->
throw (dynamicTypeError node (getInfoLocation _identInfo))
NLam Lambda {..}
| isDynamic (_lambdaBinder ^. binderType) ->
throw (dynamicTypeError node (_lambdaBinder ^. binderLocation))
NLet Let {..}
| isDynamic (_letItem ^. letItemBinder . binderType) ->
throw (dynamicTypeError node (_letItem ^. letItemBinder . binderLocation))
NRec LetRec {..}
| any (isDynamic . (^. letItemBinder . binderType)) _letRecValues ->
throw (dynamicTypeError node (head _letRecValues ^. letItemBinder . binderLocation))
NPi Pi {..}
| not allowPolymorphism && isTypeConstr tab (_piBinder ^. binderType) ->
throw
CoreError
{ _coreErrorMsg = ppOutput "polymorphism not supported for this target",
_coreErrorNode = Just node,
_coreErrorLoc = fromMaybe defaultLoc (_piBinder ^. binderLocation)
}
_ -> return node
checkNoRecursiveTypes :: forall r. Member (Error CoreError) r => InfoTable -> Sem r ()
checkNoRecursiveTypes tab =
when (isCyclic (createTypeDependencyInfo tab)) $
throw
CoreError
{ _coreErrorMsg = ppOutput "recursive types not supported for the GEB target",
_coreErrorNode = Nothing,
_coreErrorLoc = defaultLoc
}
checkMainExists :: forall r. Member (Error CoreError) r => InfoTable -> Sem r ()
checkMainExists tab =
when (isNothing (tab ^. infoMain)) $
throw
CoreError
{ _coreErrorMsg = ppOutput "no `main` function",
_coreErrorNode = Nothing,
_coreErrorLoc = defaultLoc
}

View File

@ -1,14 +1,21 @@
module Juvix.Compiler.Core.Transformation.CheckExec where
module Juvix.Compiler.Core.Transformation.Check.Exec where
import Juvix.Compiler.Core.Error
import Juvix.Compiler.Core.Extra
import Juvix.Compiler.Core.Transformation.Base
import Juvix.Compiler.Core.Transformation.Check.Base
import Juvix.Data.PPOutput
checkExec :: forall r. Member (Error CoreError) r => InfoTable -> Sem r InfoTable
checkExec tab =
case tab ^. infoMain of
Nothing -> return tab
Nothing ->
throw
CoreError
{ _coreErrorMsg = ppOutput "no `main` function",
_coreErrorNode = Nothing,
_coreErrorLoc = defaultLoc
}
Just sym ->
case ii ^. identifierType of
NPi {} ->
@ -31,9 +38,3 @@ checkExec tab =
where
ii = lookupIdentifierInfo tab sym
loc = fromMaybe defaultLoc (ii ^. identifierLocation)
mockFile :: Path Abs File
mockFile = $(mkAbsFile "/core-to-exec")
defaultLoc :: Interval
defaultLoc = singletonInterval (mkInitialLoc mockFile)

View File

@ -0,0 +1,13 @@
module Juvix.Compiler.Core.Transformation.Check.Geb where
import Juvix.Compiler.Core.Error
import Juvix.Compiler.Core.Transformation.Base
import Juvix.Compiler.Core.Transformation.Check.Base
checkGeb :: forall r. Member (Error CoreError) r => InfoTable -> Sem r InfoTable
checkGeb tab =
checkMainExists tab
>> checkNoRecursiveTypes tab
>> mapAllNodesM checkNoIO tab
>> mapAllNodesM (checkBuiltins False) tab
>> mapAllNodesM (checkTypes False tab) tab

View File

@ -0,0 +1,36 @@
module Juvix.Compiler.Core.Transformation.Check.VampIR where
import Juvix.Compiler.Core.Error
import Juvix.Compiler.Core.Extra
import Juvix.Compiler.Core.Transformation.Base
import Juvix.Compiler.Core.Transformation.Check.Base
import Juvix.Data.PPOutput
checkVampIR :: forall r. Member (Error CoreError) r => InfoTable -> Sem r InfoTable
checkVampIR tab =
checkMainExists tab
>> checkMainType
>> mapAllNodesM checkNoIO tab
>> mapAllNodesM (checkBuiltins True) tab
where
checkMainType :: Sem r ()
checkMainType =
unless (checkType (ii ^. identifierType)) $
throw
CoreError
{ _coreErrorMsg = ppOutput "for this target the arguments and the result of the `main` function must be numbers",
_coreErrorLoc = fromMaybe defaultLoc (ii ^. identifierLocation),
_coreErrorNode = Nothing
}
where
ii = lookupIdentifierInfo tab (fromJust (tab ^. infoMain))
checkType :: Node -> Bool
checkType ty =
let (tyargs, tgt) = unfoldPi' ty
in all isPrimInteger (tgt : tyargs)
where
isPrimInteger ty' = case ty' of
NPrim (TypePrim _ (PrimInteger _)) -> True
NDyn _ -> True
_ -> False

View File

@ -1,112 +0,0 @@
module Juvix.Compiler.Core.Transformation.CheckGeb where
import Juvix.Compiler.Core.Data.TypeDependencyInfo
import Juvix.Compiler.Core.Error
import Juvix.Compiler.Core.Extra
import Juvix.Compiler.Core.Info.LocationInfo (getInfoLocation)
import Juvix.Compiler.Core.Info.TypeInfo qualified as Info
import Juvix.Compiler.Core.Transformation.Base
import Juvix.Data.PPOutput
checkGeb :: forall r. Member (Error CoreError) r => InfoTable -> Sem r InfoTable
checkGeb tab =
checkNoRecursiveTypes
>> mapAllNodesM checkNoIO tab
>> mapAllNodesM checkBuiltins tab
>> mapAllNodesM checkTypes tab
where
checkTypes :: Node -> Sem r Node
checkTypes = dmapM go
where
go :: Node -> Sem r Node
go node = case node of
NIdt Ident {..}
| isDynamic (lookupIdentifierInfo tab _identSymbol ^. identifierType) ->
throw (dynamicTypeError node (getInfoLocation _identInfo))
NLam Lambda {..}
| isDynamic (_lambdaBinder ^. binderType) ->
throw (dynamicTypeError node (_lambdaBinder ^. binderLocation))
NLet Let {..}
| isDynamic (_letItem ^. letItemBinder . binderType) ->
throw (dynamicTypeError node (_letItem ^. letItemBinder . binderLocation))
NRec LetRec {..}
| any (isDynamic . (^. letItemBinder . binderType)) _letRecValues ->
throw (dynamicTypeError node (head _letRecValues ^. letItemBinder . binderLocation))
NPi Pi {..}
| isTypeConstr tab (_piBinder ^. binderType) ->
throw
CoreError
{ _coreErrorMsg = ppOutput "polymorphism not supported for the GEB target",
_coreErrorNode = Just node,
_coreErrorLoc = fromMaybe defaultLoc (_piBinder ^. binderLocation)
}
_ -> return node
checkBuiltins :: Node -> Sem r Node
checkBuiltins = dmapM go
where
go :: Node -> Sem r Node
go node = case node of
NPrim TypePrim {..}
| _typePrimPrimitive == PrimString ->
throw $ unsupportedError "strings" node (getInfoLocation _typePrimInfo)
NBlt BuiltinApp {..} ->
case _builtinAppOp of
OpShow -> throw $ unsupportedError "strings" node (getInfoLocation _builtinAppInfo)
OpStrConcat -> throw $ unsupportedError "strings" node (getInfoLocation _builtinAppInfo)
OpStrToInt -> throw $ unsupportedError "strings" node (getInfoLocation _builtinAppInfo)
OpTrace -> throw $ unsupportedError "tracing" node (getInfoLocation _builtinAppInfo)
OpFail -> do
let ty = Info.getInfoType _builtinAppInfo
when (isDynamic ty) $
throw $
unsupportedError "failing without type info" node (getInfoLocation _builtinAppInfo)
return node
_ -> return node
_ -> return node
checkNoIO :: Node -> Sem r Node
checkNoIO = dmapM go
where
go :: Node -> Sem r Node
go node = case node of
NCtr Constr {..} ->
case _constrTag of
BuiltinTag TagReturn -> throw $ unsupportedError "IO" node (getInfoLocation _constrInfo)
BuiltinTag TagBind -> throw $ unsupportedError "IO" node (getInfoLocation _constrInfo)
BuiltinTag TagReadLn -> throw $ unsupportedError "IO" node (getInfoLocation _constrInfo)
BuiltinTag TagWrite -> throw $ unsupportedError "IO" node (getInfoLocation _constrInfo)
_ -> return node
_ -> return node
checkNoRecursiveTypes :: Sem r ()
checkNoRecursiveTypes =
when (isCyclic (createTypeDependencyInfo tab)) $
throw
CoreError
{ _coreErrorMsg = ppOutput "recursive types not supported for the GEB target",
_coreErrorNode = Nothing,
_coreErrorLoc = defaultLoc
}
dynamicTypeError :: Node -> Maybe Location -> CoreError
dynamicTypeError node loc =
CoreError
{ _coreErrorMsg = ppOutput "compilation for the GEB target requires full type information",
_coreErrorNode = Just node,
_coreErrorLoc = fromMaybe defaultLoc loc
}
unsupportedError :: Text -> Node -> Maybe Location -> CoreError
unsupportedError what node loc =
CoreError
{ _coreErrorMsg = ppOutput $ pretty what <> " not supported for the GEB target",
_coreErrorNode = Just node,
_coreErrorLoc = fromMaybe defaultLoc loc
}
mockFile :: Path Abs File
mockFile = $(mkAbsFile "/core-to-geb")
defaultLoc :: Interval
defaultLoc = singletonInterval (mkInitialLoc mockFile)

View File

@ -100,6 +100,12 @@ upToMiniC ::
Sem r C.MiniCResult
upToMiniC = upToAsm >>= asmToMiniC
upToVampIR ::
(Members '[HighlightBuilder, Reader EntryPoint, Files, NameIdGen, Error JuvixError, Builtins, PathResolver] r) =>
Sem r VampIR.Result
upToVampIR =
upToCore >>= \Core.CoreResult {..} -> coreToVampIR _coreResultTable
upToGeb ::
(Members '[HighlightBuilder, Reader EntryPoint, Files, NameIdGen, Error JuvixError, Builtins, PathResolver] r) =>
Geb.ResultSpec ->

View File

@ -125,7 +125,7 @@ tests =
$(mkRelFile "test018.juvix")
$(mkRelFile "out/test018.geb"),
PosTest
"Test019: higher-order functions and recursion"
"Test019: higher-order functions"
$(mkRelDir ".")
$(mkRelFile "test019.juvix")
$(mkRelFile "out/test019.geb"),

View File

@ -37,10 +37,24 @@ instance FromJSON EvalData where
where
parseEvalData :: Parse PragmaError EvalData
parseEvalData = do
_evalDataInput <- key "in" (eachInArray asText)
_evalDataInput <- parseInputs
_evalDataOutput <- key "out" asText
return EvalData {..}
parseInputs :: Parse PragmaError [Text]
parseInputs = do
mi <- keyMay "in" asText
case mi of
Nothing -> parseInputs' 1
Just i -> return [i]
parseInputs' :: Int -> Parse PragmaError [Text]
parseInputs' n = do
mi <- keyMay ("in" <> show n) asText
case mi of
Nothing -> return []
Just i -> (i :) <$> parseInputs' (n + 1)
coreEvalAssertion' ::
EvalMode ->
InfoTable ->

View File

@ -4,22 +4,27 @@ import Base
import Core.Normalize.Base
data PosTest = PosTest
{ _name :: String,
{ _paramsNum :: Int,
_name :: String,
_relDir :: Path Rel Dir,
_file :: Path Rel File,
_expectedFile :: Path Rel File
_dataFile :: Path Rel File
}
makeLenses ''PosTest
filterOutTests :: [String] -> [PosTest] -> [PosTest]
filterOutTests out = filter (\PosTest {..} -> _name `notElem` out)
fromTest :: PosTest -> TestTree
fromTest = mkTest . toTestDescr
root :: Path Abs Dir
root = relToProject $(mkRelDir "tests/VampIR/positive/Core")
root = relToProject $(mkRelDir "tests/VampIR/positive")
toTestDescr' ::
( Path Abs File ->
( Int ->
Path Abs File ->
Path Abs File ->
(String -> IO ()) ->
Assertion
@ -29,15 +34,15 @@ toTestDescr' ::
toTestDescr' assertion PosTest {..} =
let tRoot = root <//> _relDir
file' = tRoot <//> _file
expected' = tRoot <//> _expectedFile
expected' = tRoot <//> _dataFile
in TestDescr
{ _testName = _name,
_testRoot = tRoot,
_testAssertion = Steps $ assertion file' expected'
_testAssertion = Steps $ assertion _paramsNum file' expected'
}
toTestDescr :: PosTest -> TestDescr
toTestDescr = toTestDescr' coreNormalizeAssertion
toTestDescr = toTestDescr' (const coreNormalizeAssertion)
allTests :: TestTree
allTests =
@ -48,148 +53,177 @@ allTests =
tests :: [PosTest]
tests =
[ PosTest
5
"Test001: not function"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test001.jvc")
$(mkRelFile "data/test001.json"),
PosTest
5
"Test002: pattern matching"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test002.jvc")
$(mkRelFile "data/test002.json"),
PosTest
5
"Test003: inductive types"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test003.jvc")
$(mkRelFile "data/test003.json"),
PosTest
5
"Test004: definitions"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test004.jvc")
$(mkRelFile "data/test004.json"),
PosTest
5
"Test005: basic arithmetic"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test005.jvc")
$(mkRelFile "data/test005.json"),
PosTest
6
"Test006: arithmetic"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test006.jvc")
$(mkRelFile "data/test006.json"),
PosTest
5
"Test007: single-constructor inductive types"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test007.jvc")
$(mkRelFile "data/test007.json"),
PosTest
5
"Test008: higher-order inductive types"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test008.jvc")
$(mkRelFile "data/test008.json"),
PosTest
5
"Test009: comparisons"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test009.jvc")
$(mkRelFile "data/test009.json"),
PosTest
5
"Test010: let"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test010.jvc")
$(mkRelFile "data/test010.json"),
PosTest
7
"Test011: functions returning functions with variable capture"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test011.jvc")
$(mkRelFile "data/test011.json"),
PosTest
5
"Test012: partial application"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test012.jvc")
$(mkRelFile "data/test012.json"),
PosTest
10
"Test013: mid-square hashing (unrolled)"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test013.jvc")
$(mkRelFile "data/test013.json"),
PosTest
11
"Test014: recursion"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test014.jvc")
$(mkRelFile "data/test014.json"),
PosTest
11
"Test015: tail recursion"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test015.jvc")
$(mkRelFile "data/test015.json"),
PosTest
11
"Test016: tail recursion: Fibonacci numbers in linear time"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test016.jvc")
$(mkRelFile "data/test016.json"),
PosTest
11
"Test017: recursion through higher-order functions"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test017.jvc")
$(mkRelFile "data/test017.json"),
PosTest
11
"Test018: tail recursion through higher-order functions"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test018.jvc")
$(mkRelFile "data/test018.json"),
PosTest
"Test019: higher-order functions and recursion"
$(mkRelDir ".")
5
"Test019: higher-order functions"
$(mkRelDir "Core")
$(mkRelFile "test019.jvc")
$(mkRelFile "data/test019.json"),
PosTest
5
"Test020: functional queues"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test020.jvc")
$(mkRelFile "data/test020.json"),
PosTest
5
"Test021: polymorphism"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test021.jvc")
$(mkRelFile "data/test021.json"),
PosTest
12
"Test022: mutual recursion"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test022.jvc")
$(mkRelFile "data/test022.json"),
PosTest
5
"Test023: eta-expansion"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test023.jvc")
$(mkRelFile "data/test023.json"),
PosTest
5
"Test024: eta-expansion of polymorphic constructors"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test024.jvc")
$(mkRelFile "data/test024.json"),
PosTest
10
"Test025: mid-square hashing"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test025.jvc")
$(mkRelFile "data/test025.json"),
PosTest
5
"Test026: letrec"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test026.jvc")
$(mkRelFile "data/test026.json"),
PosTest
5
"Test027: type synonyms"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test027.jvc")
$(mkRelFile "data/test027.json"),
PosTest
5
"Test028: let hoisting"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test028.jvc")
$(mkRelFile "data/test028.json"),
PosTest
6
"Test029: let hoisting"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test029.jvc")
$(mkRelFile "data/test029.json")
]

View File

@ -21,16 +21,25 @@ coreVampIRAssertion transforms mainFile expectedFile step = do
Left err -> assertFailure (show (pretty err))
Right (_, Nothing) -> assertFailure "Empty program"
Right (tabIni, Just node) -> do
step "Transform"
let tab = setupMainFunction tabIni node
case run . runReader defaultCoreOptions . runError @JuvixError $
applyTransformations transforms tab of
Left err -> assertFailure (show (pretty (fromJuvixError @GenericError err)))
Right tab' -> do
step "Check let-hoisted"
walkT checkHoisted tab'
coreEvalAssertion' EvalModeJSON tab' mainFile expectedFile step
where
checkHoisted :: Symbol -> Node -> IO ()
checkHoisted s n =
unless (isLetHoisted n) (assertFailure $ "node not hoisted: " <> show s)
coreVampIRAssertion' (setupMainFunction tabIni node) transforms mainFile expectedFile step
coreVampIRAssertion' ::
InfoTable ->
[TransformationId] ->
Path Abs File ->
Path Abs File ->
(String -> IO ()) ->
Assertion
coreVampIRAssertion' tab transforms mainFile expectedFile step = do
step "Transform and normalize"
case run . runReader defaultCoreOptions . runError @JuvixError $
applyTransformations transforms tab of
Left err -> assertFailure (show (pretty (fromJuvixError @GenericError err)))
Right tab' -> do
step "Check let-hoisted"
walkT checkHoisted tab'
coreEvalAssertion' EvalModeJSON tab' mainFile expectedFile step
where
checkHoisted :: Symbol -> Node -> IO ()
checkHoisted s n =
unless (isLetHoisted n) (assertFailure $ "node not hoisted: " <> show s)

View File

@ -10,7 +10,7 @@ fromTest :: PosTest -> TestTree
fromTest = mkTest . toTestDescr
toTestDescr :: PosTest -> TestDescr
toTestDescr = Normalize.toTestDescr' (coreVampIRAssertion [LetHoisting])
toTestDescr = Normalize.toTestDescr' (const (coreVampIRAssertion [LetHoisting]))
allTests :: TestTree
allTests =
@ -21,18 +21,21 @@ allTests =
tests :: [PosTest]
tests =
[ PosTest
5
"Test010: Lets"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test010.jvc")
$(mkRelFile "data/test010.json"),
PosTest
5
"Test028: Let hoisting"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test028.jvc")
$(mkRelFile "data/test028.json"),
PosTest
5
"Test029: Let hoisting"
$(mkRelDir ".")
$(mkRelDir "Core")
$(mkRelFile "test029.jvc")
$(mkRelFile "data/test029.json")
]

View File

@ -10,7 +10,7 @@ fromTest :: PosTest -> TestTree
fromTest = mkTest . toTestDescr
toTestDescr :: PosTest -> TestDescr
toTestDescr = Normalize.toTestDescr' (coreVampIRAssertion toVampIRTransformations)
toTestDescr = Normalize.toTestDescr' (const (coreVampIRAssertion toVampIRTransformations))
allTests :: TestTree
allTests =

View File

@ -16,6 +16,7 @@ import Runtime qualified
import Scope qualified
import Termination qualified
import Typecheck qualified
import VampIR qualified
slowTests :: TestTree
slowTests =
@ -27,7 +28,8 @@ slowTests =
Core.allTests,
Internal.allTests,
Compilation.allTests,
Examples.allTests
Examples.allTests,
VampIR.allTests
]
fastTests :: TestTree

View File

@ -1,7 +1,8 @@
module VampIR where
import Base
import VampIR.Compilation.Positive qualified as PC
import VampIR.Core.Positive qualified as PT
allTests :: TestTree
allTests = testGroup "VampIR tests" [PT.allTests]
allTests = testGroup "VampIR tests" [PT.allTests, PC.allTests]

View File

@ -0,0 +1,15 @@
module VampIR.Compilation.Base where
import Base
import Core.VampIR.Base (coreVampIRAssertion')
import Juvix.Compiler.Core
import Juvix.Compiler.Core.Data.TransformationId
import VampIR.Core.Base (vampirAssertion')
vampirCompileAssertion :: Int -> Path Abs File -> Path Abs File -> (String -> IO ()) -> Assertion
vampirCompileAssertion paramsNum mainFile dataFile step = do
step "Translate to JuvixCore"
entryPoint <- defaultEntryPointCwdIO mainFile
tab <- (^. coreResultTable) . snd <$> runIO' entryPoint upToCore
coreVampIRAssertion' tab toVampIRTransformations mainFile dataFile step
vampirAssertion' paramsNum tab dataFile step

View File

@ -0,0 +1,162 @@
module VampIR.Compilation.Positive where
import Base
import VampIR.Compilation.Base
data PosTest = PosTest
{ _paramsNum :: Int,
_name :: String,
_dir :: Path Abs Dir,
_file :: Path Abs File,
_dataFile :: Path Abs File
}
makeLenses ''PosTest
fromTest :: PosTest -> TestTree
fromTest = mkTest . toTestDescr
root :: Path Abs Dir
root = relToProject $(mkRelDir "tests/VampIR/positive/Compilation")
toTestDescr :: PosTest -> TestDescr
toTestDescr PosTest {..} =
let tRoot = _dir
file' = _file
data' = _dataFile
in TestDescr
{ _testName = _name,
_testRoot = tRoot,
_testAssertion = Steps $ vampirCompileAssertion _paramsNum file' data'
}
allTests :: TestTree
allTests =
testGroup
"Juvix compilation pipeline positive tests"
(map (mkTest . toTestDescr) tests)
posTest :: Int -> String -> Path Rel Dir -> Path Rel File -> Path Rel File -> PosTest
posTest _paramsNum _name rdir rfile routfile =
let _dir = root <//> rdir
_file = _dir <//> rfile
_dataFile = root <//> routfile
in PosTest {..}
tests :: [PosTest]
tests =
[ posTest
5
"Test001: not function"
$(mkRelDir ".")
$(mkRelFile "test001.juvix")
$(mkRelFile "data/test001.json"),
posTest
5
"Test002: pattern matching"
$(mkRelDir ".")
$(mkRelFile "test002.juvix")
$(mkRelFile "data/test002.json"),
posTest
5
"Test003: inductive types"
$(mkRelDir ".")
$(mkRelFile "test003.juvix")
$(mkRelFile "data/test003.json"),
posTest
7
"Test004: arithmetic"
$(mkRelDir ".")
$(mkRelFile "test004.juvix")
$(mkRelFile "data/test004.json"),
posTest
5
"Test005: single-constructor inductive types"
$(mkRelDir ".")
$(mkRelFile "test005.juvix")
$(mkRelFile "data/test005.json"),
posTest
5
"Test006: higher-order inductive types"
$(mkRelDir ".")
$(mkRelFile "test006.juvix")
$(mkRelFile "data/test006.json"),
posTest
5
"Test007: let"
$(mkRelDir ".")
$(mkRelFile "test007.juvix")
$(mkRelFile "data/test007.json"),
posTest
8
"Test008: functions returning functions with variable capture"
$(mkRelDir ".")
$(mkRelFile "test008.juvix")
$(mkRelFile "data/test008.json"),
posTest
6
"Test009: applications with lets and cases in function position"
$(mkRelDir ".")
$(mkRelFile "test009.juvix")
$(mkRelFile "data/test009.json"),
posTest
10
"Test010: mid-square hashing (unrolled)"
$(mkRelDir ".")
$(mkRelFile "test010.juvix")
$(mkRelFile "data/test010.json"),
posTest
9
"Test011: recursion"
$(mkRelDir ".")
$(mkRelFile "test011.juvix")
$(mkRelFile "data/test011.json"),
posTest
9
"Test012: tail recursion"
$(mkRelDir ".")
$(mkRelFile "test012.juvix")
$(mkRelFile "data/test012.json"),
posTest
9
"Test013: tail recursion: Fibonacci numbers in linear time"
$(mkRelDir ".")
$(mkRelFile "test013.juvix")
$(mkRelFile "data/test013.json"),
posTest
9
"Test014: recursion through higher-order functions"
$(mkRelDir ".")
$(mkRelFile "test014.juvix")
$(mkRelFile "data/test014.json"),
posTest
9
"Test015: tail recursion through higher-order functions"
$(mkRelDir ".")
$(mkRelFile "test015.juvix")
$(mkRelFile "data/test015.json"),
posTest
5
"Test016: higher-order functions"
$(mkRelDir ".")
$(mkRelFile "test016.juvix")
$(mkRelFile "data/test016.json"),
posTest
11
"Test017: mutual recursion"
$(mkRelDir ".")
$(mkRelFile "test017.juvix")
$(mkRelFile "data/test017.json"),
posTest
10
"Test018: mid-square hashing"
$(mkRelDir ".")
$(mkRelFile "test018.juvix")
$(mkRelFile "data/test018.json"),
posTest
3
"Test019: polymorphism"
$(mkRelDir ".")
$(mkRelFile "test019.juvix")
$(mkRelFile "data/test019.json")
]

View File

@ -7,45 +7,44 @@ import Juvix.Compiler.Core
import Juvix.Prelude.Pretty
import System.Process qualified as P
vampirAssertion :: Path Abs File -> Path Abs File -> (String -> IO ()) -> Assertion
vampirAssertion mainFile dataFile step = do
vampirAssertion :: Int -> Path Abs File -> Path Abs File -> (String -> IO ()) -> Assertion
vampirAssertion paramsNum mainFile dataFile step = do
step "Parse"
s <- readFile (toFilePath mainFile)
case runParserMain mainFile emptyInfoTable s of
Left err -> assertFailure (show err)
Right tab -> do
withTempDir'
( \dirPath -> do
step "Translate to VampIR"
let vampirFile = dirPath <//> $(mkRelFile "program.pir")
case run (runReader defaultCoreOptions (runError @JuvixError (coreToVampIR' tab))) of
Left err -> assertFailure (show (pretty (fromJuvixError @GenericError err)))
Right VampIR.Result {..} -> do
TIO.writeFile (toFilePath vampirFile) _resultCode
vampirAssertion' vampirFile dataFile step
)
vampirAssertion' :: Path Abs File -> Path Abs File -> (String -> IO ()) -> Assertion
vampirAssertion' inputFile dataFile step = do
step "Check vamp-ir on path"
assertCmdExists $(mkRelFile "vamp-ir")
Right tab -> vampirAssertion' paramsNum tab dataFile step
vampirAssertion' :: Int -> InfoTable -> Path Abs File -> (String -> IO ()) -> Assertion
vampirAssertion' paramsNum tab dataFile step = do
withTempDir'
( \dirPath -> do
step "VampIR setup parameters"
P.callProcess "vamp-ir" (setupParamsArgs dirPath)
step "VampIR compile"
P.callProcess "vamp-ir" (compileArgs inputFile dirPath)
step "VampIR prove"
P.callProcess "vamp-ir" (proveArgs dataFile dirPath)
step "VampIR verify"
P.callProcess "vamp-ir" (verifyArgs dirPath)
step "Translate to VampIR"
let vampirFile = dirPath <//> $(mkRelFile "program.pir")
case run (runReader defaultCoreOptions (runError @JuvixError (coreToVampIR' tab))) of
Left err -> assertFailure (show (pretty (fromJuvixError @GenericError err)))
Right VampIR.Result {..} -> do
TIO.writeFile (toFilePath vampirFile) _resultCode
step "Check vamp-ir on path"
assertCmdExists $(mkRelFile "vamp-ir")
step "VampIR setup parameters"
P.callProcess "vamp-ir" (setupParamsArgs paramsNum dirPath)
step "VampIR compile"
P.callProcess "vamp-ir" (compileArgs vampirFile dirPath)
step "VampIR prove"
P.callProcess "vamp-ir" (proveArgs dataFile dirPath)
step "VampIR verify"
P.callProcess "vamp-ir" (verifyArgs dirPath)
)
setupParamsArgs :: Path Abs Dir -> [String]
setupParamsArgs dirPath =
setupParamsArgs :: Int -> Path Abs Dir -> [String]
setupParamsArgs paramsNum dirPath =
[ "plonk",
"setup",
"-m",
show paramsNum,
"-o",
toFilePath (dirPath <//> $(mkRelFile "params.pp"))
]

View File

@ -1,47 +1,55 @@
module VampIR.Core.Positive where
import Base
import Core.Normalize.Positive (PosTest (..))
import Core.Normalize.Positive qualified as Normalize
import VampIR.Core.Base
data PosTest = PosTest
{ _name :: String,
_relDir :: Path Rel Dir,
_file :: Path Rel File,
_dataFile :: Path Rel File
}
fromTest :: PosTest -> TestTree
fromTest = mkTest . toTestDescr
makeLenses ''PosTest
root :: Path Abs Dir
root = relToProject $(mkRelDir "tests/VampIR/positive/translation")
testDescr :: PosTest -> TestDescr
testDescr PosTest {..} =
let tRoot = root <//> _relDir
file' = tRoot <//> _file
data' = tRoot <//> _dataFile
in TestDescr
{ _testName = _name,
_testRoot = tRoot,
_testAssertion = Steps $ vampirAssertion file' data'
}
toTestDescr :: PosTest -> TestDescr
toTestDescr = Normalize.toTestDescr' vampirAssertion
allTests :: TestTree
allTests =
testGroup
"VampIR translation positive tests"
(map (mkTest . testDescr) tests)
( map
(mkTest . toTestDescr)
( tests
++ ( Normalize.filterOutTests
( -- VampIR stack overflow
[ "Test020: functional queues",
"Test026: letrec"
]
++
-- recursion takes too long
[ "Test014: recursion",
"Test015: tail recursion",
"Test016: tail recursion: Fibonacci numbers in linear time",
"Test017: recursion through higher-order functions",
"Test018: tail recursion through higher-order functions",
"Test022: mutual recursion"
]
)
Normalize.tests
)
)
)
tests :: [PosTest]
tests =
[ PosTest
5
"Test001"
$(mkRelDir ".")
$(mkRelDir "translation")
$(mkRelFile "test001.jvc")
$(mkRelFile "data/test001.json"),
PosTest
5
"Test002"
$(mkRelDir ".")
$(mkRelDir "translation")
$(mkRelFile "test002.jvc")
$(mkRelFile "data/test002.json")
]

View File

@ -1,4 +1,4 @@
-- higher-order functions and recursion
-- higher-order functions
module test019;
open import Stdlib.Prelude;

View File

@ -0,0 +1,4 @@
{
"in": "1",
"out": "0"
}

View File

@ -0,0 +1,5 @@
{
"in1": "0",
"in2": "1",
"out": "1"
}

View File

@ -0,0 +1,5 @@
{
"in1": "0",
"in2": "1",
"out": "1"
}

View File

@ -0,0 +1,7 @@
{
"in1": "5",
"in2": "17",
"in3": "0",
"in4": "2",
"out": "32"
}

View File

@ -0,0 +1,5 @@
{
"in1": "3",
"in2": "5",
"out": "8"
}

View File

@ -0,0 +1,5 @@
{
"in1": "1",
"in2": "0",
"out": "1"
}

View File

@ -0,0 +1,5 @@
{
"in1": "1",
"in2": "2",
"out": "32"
}

View File

@ -0,0 +1,5 @@
{
"in1": "5",
"in2": "10",
"out": "8"
}

View File

@ -0,0 +1,6 @@
{
"in1": "7",
"in2": "2",
"in3": "0",
"out": "9"
}

View File

@ -0,0 +1,4 @@
{
"in": "1367",
"out": "3"
}

View File

@ -0,0 +1,4 @@
{
"in": "20",
"out": "210"
}

View File

@ -0,0 +1,4 @@
{
"in": "20",
"out": "210"
}

View File

@ -0,0 +1,4 @@
{
"in": "10",
"out": "55"
}

View File

@ -0,0 +1,4 @@
{
"in": "20",
"out": "210"
}

View File

@ -0,0 +1,4 @@
{
"in": "20",
"out": "210"
}

View File

@ -0,0 +1,5 @@
{
"in1": "2",
"in2": "4",
"out": "11"
}

View File

@ -0,0 +1,4 @@
{
"in": "5",
"out": "6386010"
}

View File

@ -0,0 +1,4 @@
{
"in": "1367",
"out": "3"
}

View File

@ -0,0 +1,5 @@
{
"in1": "0",
"in2": "1",
"out": "1"
}

View File

@ -0,0 +1,8 @@
-- not function
module test001;
open import Stdlib.Prelude;
open import Stdlib.Data.Nat.Ord;
main : Nat -> Nat;
main x := if (x == 0) 1 0;

View File

@ -0,0 +1,18 @@
-- pattern matching
module test002;
open import Stdlib.Prelude;
open import Stdlib.Data.Nat.Ord;
type optbool :=
| Just : Bool -> optbool
| Nothing : optbool;
natToBool : Nat -> Bool;
natToBool x := if (x == 0) false true;
boolToNat : Bool -> Nat;
boolToNat x := if x 1 0;
main : Nat -> Nat -> Nat;
main a b := boolToNat $ λ{ x (Just b) := if x false b | _ Nothing := false } (natToBool a) (Just (natToBool b));

View File

@ -0,0 +1,23 @@
-- inductive types
module test003;
open import Stdlib.Prelude;
open import Stdlib.Data.Nat.Ord;
type enum :=
| opt0 : enum
| opt1 : Bool -> enum
| opt2 : Bool -> Bool -> enum;
natToBool : Nat -> Bool;
natToBool x := if (x == 0) false true;
boolToNat : Bool -> Nat;
boolToNat x := if x 1 0;
main : Nat -> Nat -> Nat;
main x y := boolToNat $ λ{
| opt0 := false
| (opt1 b) := b
| (opt2 b c) := if b b c
} (opt2 (natToBool x) (natToBool y));

View File

@ -0,0 +1,28 @@
-- arithmetic
module test004;
open import Stdlib.Prelude;
f : Nat -> Nat -> Nat;
f x y := x + y;
g : Nat -> Nat -> Nat;
g x y := sub (3 * x) y;
h : (Nat -> Nat -> Nat) -> Nat -> Nat -> Nat;
h f y z := f y y * z;
func : Nat -> Nat := λ{x := x + 4};
vx : Nat := 30;
vy : Nat := 7;
main : Nat -> Nat -> Nat -> Nat -> Nat;
main x y z u :=
sub
(func (div y x) + -- 17 div 5 + 4 = 7
(z * x + y) + -- 17
(vx + vy * (z + 1)) + -- 37
f (h g u 3) 4) -- 16
45;
-- result: 32

View File

@ -0,0 +1,15 @@
-- single-constructor inductive types
module test005;
open import Stdlib.Prelude;
type Box2 :=
box2 : Nat -> Nat -> Box2;
type Box :=
box : Box2 -> Box;
main : Nat -> Nat -> Nat;
main x y := case box (box2 x y)
| box (box2 x y) := x + y;
-- result: 8

View File

@ -0,0 +1,25 @@
-- higher-order inductive types
module test006;
open import Stdlib.Prelude;
open import Stdlib.Data.Nat.Ord;
type enum :=
| opt0 : enum
| opt1 : Bool -> enum
| opt2 : Bool -> (Bool -> Bool) -> enum
| opt3 : Bool -> (Bool -> Bool -> Bool) -> Bool -> enum;
natToBool : Nat -> Bool;
natToBool x := if (x == 0) false true;
boolToNat : Bool -> Nat;
boolToNat x := if x 1 0;
main : Nat -> Nat -> Nat;
main x y := boolToNat $
case (opt3 (natToBool x) (λ{ x y := if y false x }) (natToBool y))
| opt0 := false
| opt1 b := b
| opt2 b f := f b
| opt3 b1 f b2 := f b1 b2;

View File

@ -0,0 +1,13 @@
-- let
module test007;
open import Stdlib.Prelude;
main : Nat -> Nat -> Nat;
main a b :=
let x : Nat := a in
let x1 : Nat := x + let x2 : Nat := 2 in x2 in
let x3 : Nat := x1 * x1 in
let y : Nat := x3 + b in -- 11
let z : Nat := x3 + y in -- 20
x + y + z;

View File

@ -0,0 +1,21 @@
-- functions returning functions with variable capture
module test008;
open import Stdlib.Prelude;
open import Stdlib.Data.Nat.Ord;
f : Nat → Nat → Nat;
f x := if (x == 6)
λ{_ := 0}
(if (x == 5)
λ{_ := 1}
(if (x == 10)
λ{_ := λ{x := x} 2}
λ{x := x}));
main : Nat -> Nat -> Nat;
main x y :=
f x (x + 1) +
f (x + 1) x +
f y x +
f (y + 1) x;

View File

@ -0,0 +1,21 @@
-- applications with lets and cases in function position
module test009;
open import Stdlib.Prelude;
f : Nat -> ((Nat -> Nat) -> Nat -> Nat) × Nat → Nat;
f a l := (case l
| (x, zero) := x
| _ := id)
(let
y : Nat → Nat;
y := id;
in (let
z : (Nat → Nat) → Nat → Nat;
z := id;
in (case l | (_, zero) := id | _ := id) z)
y)
a;
main : Nat -> Nat -> Nat -> Nat;
main a b c := f a (λ{| x y := x y + b}, c);

View File

@ -0,0 +1,106 @@
-- mid-square hashing (unrolled)
module test010;
open import Stdlib.Prelude;
open import Stdlib.Data.Nat.Ord;
pow0 : Nat := 1;
pow1 : Nat := 2 * pow0;
pow2 : Nat := 2 * pow1;
pow3 : Nat := 2 * pow2;
pow4 : Nat := 2 * pow3;
pow5 : Nat := 2 * pow4;
pow6 : Nat := 2 * pow5;
pow7 : Nat := 2 * pow6;
pow8 : Nat := 2 * pow7;
pow9 : Nat := 2 * pow8;
pow10 : Nat := 2 * pow9;
pow11 : Nat := 2 * pow10;
pow12 : Nat := 2 * pow11;
pow13 : Nat := 2 * pow12;
pow14 : Nat := 2 * pow13;
pow15 : Nat := 2 * pow14;
pow16 : Nat := 2 * pow15;
hash0 : Nat -> Nat;
hash0 x := 0;
hash1 : Nat -> Nat;
hash1 x := x * x;
hash2 : Nat -> Nat;
hash2 x := x * x;
hash3 : Nat -> Nat;
hash3 x := x * x;
hash4 : Nat -> Nat;
hash4 x :=
if (x < pow3) (hash3 x) (mod (div (x * x) pow1) pow6);
hash5 : Nat -> Nat;
hash5 x :=
if (x < pow4) (hash4 x) (mod (div (x * x) pow2) pow6);
hash6 : Nat -> Nat;
hash6 x :=
if (x < pow5) (hash5 x) (mod (div (x * x) pow3) pow6);
hash7 : Nat -> Nat;
hash7 x :=
if (x < pow6) (hash6 x) (mod (div (x * x) pow4) pow6);
hash8 : Nat -> Nat;
hash8 x :=
if (x < pow7) (hash7 x) (mod (div (x * x) pow5) pow6);
hash9 : Nat -> Nat;
hash9 x :=
if (x < pow8) (hash8 x) (mod (div (x * x) pow6) pow6);
hash10 : Nat -> Nat;
hash10 x :=
if (x < pow9) (hash9 x) (mod (div (x * x) pow7) pow6);
hash11 : Nat -> Nat;
hash11 x :=
if (x < pow10) (hash10 x) (mod (div (x * x) pow8) pow6);
hash12 : Nat -> Nat;
hash12 x :=
if (x < pow11) (hash11 x) (mod (div (x * x) pow9) pow6);
hash13 : Nat -> Nat;
hash13 x :=
if (x < pow12) (hash12 x) (mod (div (x * x) pow10) pow6);
hash14 : Nat -> Nat;
hash14 x :=
if (x < pow13) (hash13 x) (mod (div (x * x) pow11) pow6);
hash15 : Nat -> Nat;
hash15 x :=
if (x < pow14) (hash14 x) (mod (div (x * x) pow12) pow6);
hash16 : Nat -> Nat;
hash16 x :=
if (x < pow15) (hash15 x) (mod (div (x * x) pow13) pow6);
main : Nat -> Nat;
main := hash16;

View File

@ -0,0 +1,12 @@
-- recursion
module test011;
open import Stdlib.Prelude;
{-# unroll: 21 #-}
sum : Nat → Nat;
sum zero := 0;
sum (suc x) := suc x + sum x;
main : Nat -> Nat;
main := sum;

View File

@ -0,0 +1,15 @@
-- tail recursion
module test012;
open import Stdlib.Prelude;
{-# unroll: 21 #-}
sum' : Nat → Nat → Nat;
sum' acc zero := acc;
sum' acc (suc x) := sum' (suc x + acc) x;
sum : Nat → Nat;
sum := sum' 0;
main : Nat -> Nat;
main := sum;

View File

@ -0,0 +1,15 @@
-- tail recursion: Fibonacci numbers in linear time
module test013;
open import Stdlib.Prelude;
{-# unroll: 11 #-}
fib' : Nat → Nat → Nat → Nat;
fib' x y zero := x;
fib' x y (suc n) := fib' y (x + y) n;
fib : Nat → Nat;
fib := fib' 0 1;
main : Nat -> Nat;
main := fib;

View File

@ -0,0 +1,16 @@
-- recursion through higher-order functions
module test014;
open import Stdlib.Prelude;
g : (Nat → Nat) → Nat → Nat;
g f zero := 0;
g f (suc x) := f x;
{-# unroll: 21 #-}
terminating
f : Nat → Nat;
f x := x + g f x;
main : Nat -> Nat;
main := f;

View File

@ -0,0 +1,19 @@
-- tail recursion through higher-order functions
module test015;
open import Stdlib.Prelude;
sumb : Nat → (Nat → Nat → Nat) → Nat → Nat;
sumb acc f zero := acc;
sumb acc f (suc x) := f acc x;
{-# unroll: 21 #-}
terminating
sum' : Nat → Nat → Nat;
sum' acc x := sumb (x + acc) sum' x;
sum : Nat → Nat;
sum := sum' 0;
main : Nat -> Nat;
main := sum;

View File

@ -0,0 +1,16 @@
-- higher-order functions
module test016;
open import Stdlib.Prelude;
f : (Nat → Nat) → Nat;
f g := g 5;
h : Nat → Nat → Nat;
h x z := x + z;
u : Nat → Nat → Nat;
u x y := f (h y) + x;
main : Nat → Nat → Nat;
main := u;

View File

@ -0,0 +1,20 @@
-- mutual recursion
module test017;
open import Stdlib.Prelude;
open import Stdlib.Data.Nat.Ord;
{-# unroll: 21 #-}
terminating
f : Nat → Nat;
terminating
g : Nat → Nat;
terminating
h : Nat → Nat;
f x := if (x < 1) 1 (2 * x + g (sub x 1));
g x := if (x < 1) 1 (x + h (sub x 1));
h x := if (x < 1) 1 (x * f (sub x 1));
main : Nat → Nat;
main x := f x + f (2 * x) + f (4 * x);

View File

@ -0,0 +1,22 @@
-- mid-square hashing
module test018;
open import Stdlib.Prelude;
open import Stdlib.Data.Nat.Ord;
pow : Nat -> Nat;
pow zero := 1;
pow (suc n) := 2 * pow n;
hash' : Nat -> Nat -> Nat;
hash' (suc n@(suc (suc m))) x :=
if
(x < pow n)
(hash' n x)
(mod (div (x * x) (pow m)) (pow 6));
hash' _ x := x * x;
hash : Nat -> Nat := hash' 16;
main : Nat -> Nat;
main := hash;

View File

@ -0,0 +1,9 @@
-- polymorphism
module test019;
open import Stdlib.Prelude;
main : Nat -> Nat -> Nat;
main x y := case tail (id (x :: y :: nil))
| nil := 0
| h :: _ := h;

View File

@ -1,6 +1,4 @@
{
"in": [
"0"
],
"in": "0",
"out": "1"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"0",
"1"
],
"in1": "0",
"in2": "1",
"out": "1"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"0",
"1"
],
"in1": "0",
"in2": "1",
"out": "1"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"0",
"1"
],
"in1": "0",
"in2": "1",
"out": "1"
}

View File

@ -1,8 +1,6 @@
{
"in": [
"5",
"2",
"3"
],
"in1": "5",
"in2": "2",
"in3": "3",
"out": "11"
}

View File

@ -1,9 +1,7 @@
{
"in": [
"5",
"17",
"0",
"2"
],
"in1": "5",
"in2": "17",
"in3": "0",
"in4": "2",
"out": "32"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"3",
"5"
],
"in1": "3",
"in2": "5",
"out": "8"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"1",
"0"
],
"in1": "1",
"in2": "0",
"out": "1"
}

View File

@ -1,8 +1,6 @@
{
"in": [
"3",
"0",
"1"
],
"in1": "3",
"in2": "0",
"in3": "1",
"out": "1"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"1",
"2"
],
"in1": "1",
"in2": "2",
"out": "40"
}

View File

@ -1,8 +1,6 @@
{
"in": [
"5",
"6",
"10"
],
"in1": "5",
"in2": "6",
"in3": "10",
"out": "8"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"7",
"3"
],
"in1": "7",
"in2": "3",
"out": "5"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"1367"
],
"in": "1367",
"out": "3"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"100"
],
"in": "100",
"out": "5050"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"100"
],
"in": "100",
"out": "5050"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"10"
],
"in": "10",
"out": "55"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"10"
],
"in": "10",
"out": "55"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"100"
],
"in": "100",
"out": "5050"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"2"
],
"in": "2",
"out": "11"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"100"
],
"in": "100",
"out": "5050"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"1",
"2"
],
"in1": "1",
"in2": "2",
"out": "2"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"5",
"10"
],
"in1": "5",
"in2": "10",
"out": "901"
}

View File

@ -1,10 +1,8 @@
{
"in": [
"2",
"3",
"4",
"7",
"13"
],
"in1": "2",
"in2": "3",
"in3": "4",
"in4": "7",
"in5": "13",
"out": "18"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"2",
"3"
],
"in1": "2",
"in2": "3",
"out": "1"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"1367"
],
"in": "1367",
"out": "3"
}

View File

@ -1,9 +1,7 @@
{
"in": [
"3",
"5",
"10",
"100"
],
"in1": "3",
"in2": "5",
"in3": "10",
"in4": "100",
"out": "6295"
}

View File

@ -1,6 +1,4 @@
{
"in": [
"2"
],
"in": "2",
"out": "9"
}

View File

@ -1,7 +1,5 @@
{
"in": [
"3",
"7"
],
"in1": "3",
"in2": "7",
"out": "100"
}
}

View File

@ -1,7 +1,5 @@
{
"in": [
"3",
"7"
],
"in1": "3",
"in2": "7",
"out": "120"
}
}

View File

@ -1,4 +1,4 @@
-- higher-order functions and recursion
-- higher-order functions
def f : (Int -> Int) -> Int := \(g : Int -> Int) g 5;
def h : Int -> Int -> Int := \(x : Int) \(z : Int) x + z;