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:
parent
2148d174f5
commit
d576111241
@ -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) };",
|
||||
|
@ -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 =
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
|
118
src/Juvix/Compiler/Core/Transformation/Check/Base.hs
Normal file
118
src/Juvix/Compiler/Core/Transformation/Check/Base.hs
Normal 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
|
||||
}
|
@ -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)
|
13
src/Juvix/Compiler/Core/Transformation/Check/Geb.hs
Normal file
13
src/Juvix/Compiler/Core/Transformation/Check/Geb.hs
Normal 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
|
36
src/Juvix/Compiler/Core/Transformation/Check/VampIR.hs
Normal file
36
src/Juvix/Compiler/Core/Transformation/Check/VampIR.hs
Normal 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
|
@ -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)
|
@ -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 ->
|
||||
|
@ -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"),
|
||||
|
@ -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 ->
|
||||
|
@ -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")
|
||||
]
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
]
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
15
test/VampIR/Compilation/Base.hs
Normal file
15
test/VampIR/Compilation/Base.hs
Normal 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
|
162
test/VampIR/Compilation/Positive.hs
Normal file
162
test/VampIR/Compilation/Positive.hs
Normal 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")
|
||||
]
|
@ -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"))
|
||||
]
|
||||
|
@ -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")
|
||||
]
|
||||
|
@ -1,4 +1,4 @@
|
||||
-- higher-order functions and recursion
|
||||
-- higher-order functions
|
||||
module test019;
|
||||
|
||||
open import Stdlib.Prelude;
|
||||
|
4
tests/VampIR/positive/Compilation/data/test001.json
Normal file
4
tests/VampIR/positive/Compilation/data/test001.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "1",
|
||||
"out": "0"
|
||||
}
|
5
tests/VampIR/positive/Compilation/data/test002.json
Normal file
5
tests/VampIR/positive/Compilation/data/test002.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"in1": "0",
|
||||
"in2": "1",
|
||||
"out": "1"
|
||||
}
|
5
tests/VampIR/positive/Compilation/data/test003.json
Normal file
5
tests/VampIR/positive/Compilation/data/test003.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"in1": "0",
|
||||
"in2": "1",
|
||||
"out": "1"
|
||||
}
|
7
tests/VampIR/positive/Compilation/data/test004.json
Normal file
7
tests/VampIR/positive/Compilation/data/test004.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"in1": "5",
|
||||
"in2": "17",
|
||||
"in3": "0",
|
||||
"in4": "2",
|
||||
"out": "32"
|
||||
}
|
5
tests/VampIR/positive/Compilation/data/test005.json
Normal file
5
tests/VampIR/positive/Compilation/data/test005.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"in1": "3",
|
||||
"in2": "5",
|
||||
"out": "8"
|
||||
}
|
5
tests/VampIR/positive/Compilation/data/test006.json
Normal file
5
tests/VampIR/positive/Compilation/data/test006.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"in1": "1",
|
||||
"in2": "0",
|
||||
"out": "1"
|
||||
}
|
5
tests/VampIR/positive/Compilation/data/test007.json
Normal file
5
tests/VampIR/positive/Compilation/data/test007.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"in1": "1",
|
||||
"in2": "2",
|
||||
"out": "32"
|
||||
}
|
5
tests/VampIR/positive/Compilation/data/test008.json
Normal file
5
tests/VampIR/positive/Compilation/data/test008.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"in1": "5",
|
||||
"in2": "10",
|
||||
"out": "8"
|
||||
}
|
6
tests/VampIR/positive/Compilation/data/test009.json
Normal file
6
tests/VampIR/positive/Compilation/data/test009.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"in1": "7",
|
||||
"in2": "2",
|
||||
"in3": "0",
|
||||
"out": "9"
|
||||
}
|
4
tests/VampIR/positive/Compilation/data/test010.json
Normal file
4
tests/VampIR/positive/Compilation/data/test010.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "1367",
|
||||
"out": "3"
|
||||
}
|
4
tests/VampIR/positive/Compilation/data/test011.json
Normal file
4
tests/VampIR/positive/Compilation/data/test011.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "20",
|
||||
"out": "210"
|
||||
}
|
4
tests/VampIR/positive/Compilation/data/test012.json
Normal file
4
tests/VampIR/positive/Compilation/data/test012.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "20",
|
||||
"out": "210"
|
||||
}
|
4
tests/VampIR/positive/Compilation/data/test013.json
Normal file
4
tests/VampIR/positive/Compilation/data/test013.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "10",
|
||||
"out": "55"
|
||||
}
|
4
tests/VampIR/positive/Compilation/data/test014.json
Normal file
4
tests/VampIR/positive/Compilation/data/test014.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "20",
|
||||
"out": "210"
|
||||
}
|
4
tests/VampIR/positive/Compilation/data/test015.json
Normal file
4
tests/VampIR/positive/Compilation/data/test015.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "20",
|
||||
"out": "210"
|
||||
}
|
5
tests/VampIR/positive/Compilation/data/test016.json
Normal file
5
tests/VampIR/positive/Compilation/data/test016.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"in1": "2",
|
||||
"in2": "4",
|
||||
"out": "11"
|
||||
}
|
4
tests/VampIR/positive/Compilation/data/test017.json
Normal file
4
tests/VampIR/positive/Compilation/data/test017.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "5",
|
||||
"out": "6386010"
|
||||
}
|
4
tests/VampIR/positive/Compilation/data/test018.json
Normal file
4
tests/VampIR/positive/Compilation/data/test018.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"in": "1367",
|
||||
"out": "3"
|
||||
}
|
5
tests/VampIR/positive/Compilation/data/test019.json
Normal file
5
tests/VampIR/positive/Compilation/data/test019.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"in1": "0",
|
||||
"in2": "1",
|
||||
"out": "1"
|
||||
}
|
8
tests/VampIR/positive/Compilation/test001.juvix
Normal file
8
tests/VampIR/positive/Compilation/test001.juvix
Normal 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;
|
18
tests/VampIR/positive/Compilation/test002.juvix
Normal file
18
tests/VampIR/positive/Compilation/test002.juvix
Normal 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));
|
23
tests/VampIR/positive/Compilation/test003.juvix
Normal file
23
tests/VampIR/positive/Compilation/test003.juvix
Normal 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));
|
28
tests/VampIR/positive/Compilation/test004.juvix
Normal file
28
tests/VampIR/positive/Compilation/test004.juvix
Normal 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
|
15
tests/VampIR/positive/Compilation/test005.juvix
Normal file
15
tests/VampIR/positive/Compilation/test005.juvix
Normal 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
|
25
tests/VampIR/positive/Compilation/test006.juvix
Normal file
25
tests/VampIR/positive/Compilation/test006.juvix
Normal 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;
|
13
tests/VampIR/positive/Compilation/test007.juvix
Normal file
13
tests/VampIR/positive/Compilation/test007.juvix
Normal 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;
|
21
tests/VampIR/positive/Compilation/test008.juvix
Normal file
21
tests/VampIR/positive/Compilation/test008.juvix
Normal 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;
|
21
tests/VampIR/positive/Compilation/test009.juvix
Normal file
21
tests/VampIR/positive/Compilation/test009.juvix
Normal 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);
|
106
tests/VampIR/positive/Compilation/test010.juvix
Normal file
106
tests/VampIR/positive/Compilation/test010.juvix
Normal 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;
|
12
tests/VampIR/positive/Compilation/test011.juvix
Normal file
12
tests/VampIR/positive/Compilation/test011.juvix
Normal 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;
|
15
tests/VampIR/positive/Compilation/test012.juvix
Normal file
15
tests/VampIR/positive/Compilation/test012.juvix
Normal 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;
|
15
tests/VampIR/positive/Compilation/test013.juvix
Normal file
15
tests/VampIR/positive/Compilation/test013.juvix
Normal 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;
|
16
tests/VampIR/positive/Compilation/test014.juvix
Normal file
16
tests/VampIR/positive/Compilation/test014.juvix
Normal 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;
|
19
tests/VampIR/positive/Compilation/test015.juvix
Normal file
19
tests/VampIR/positive/Compilation/test015.juvix
Normal 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;
|
16
tests/VampIR/positive/Compilation/test016.juvix
Normal file
16
tests/VampIR/positive/Compilation/test016.juvix
Normal 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;
|
20
tests/VampIR/positive/Compilation/test017.juvix
Normal file
20
tests/VampIR/positive/Compilation/test017.juvix
Normal 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);
|
22
tests/VampIR/positive/Compilation/test018.juvix
Normal file
22
tests/VampIR/positive/Compilation/test018.juvix
Normal 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;
|
9
tests/VampIR/positive/Compilation/test019.juvix
Normal file
9
tests/VampIR/positive/Compilation/test019.juvix
Normal 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;
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"0"
|
||||
],
|
||||
"in": "0",
|
||||
"out": "1"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"0",
|
||||
"1"
|
||||
],
|
||||
"in1": "0",
|
||||
"in2": "1",
|
||||
"out": "1"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"0",
|
||||
"1"
|
||||
],
|
||||
"in1": "0",
|
||||
"in2": "1",
|
||||
"out": "1"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"0",
|
||||
"1"
|
||||
],
|
||||
"in1": "0",
|
||||
"in2": "1",
|
||||
"out": "1"
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
{
|
||||
"in": [
|
||||
"5",
|
||||
"2",
|
||||
"3"
|
||||
],
|
||||
"in1": "5",
|
||||
"in2": "2",
|
||||
"in3": "3",
|
||||
"out": "11"
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
{
|
||||
"in": [
|
||||
"5",
|
||||
"17",
|
||||
"0",
|
||||
"2"
|
||||
],
|
||||
"in1": "5",
|
||||
"in2": "17",
|
||||
"in3": "0",
|
||||
"in4": "2",
|
||||
"out": "32"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"3",
|
||||
"5"
|
||||
],
|
||||
"in1": "3",
|
||||
"in2": "5",
|
||||
"out": "8"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"in1": "1",
|
||||
"in2": "0",
|
||||
"out": "1"
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
{
|
||||
"in": [
|
||||
"3",
|
||||
"0",
|
||||
"1"
|
||||
],
|
||||
"in1": "3",
|
||||
"in2": "0",
|
||||
"in3": "1",
|
||||
"out": "1"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"1",
|
||||
"2"
|
||||
],
|
||||
"in1": "1",
|
||||
"in2": "2",
|
||||
"out": "40"
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
{
|
||||
"in": [
|
||||
"5",
|
||||
"6",
|
||||
"10"
|
||||
],
|
||||
"in1": "5",
|
||||
"in2": "6",
|
||||
"in3": "10",
|
||||
"out": "8"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"7",
|
||||
"3"
|
||||
],
|
||||
"in1": "7",
|
||||
"in2": "3",
|
||||
"out": "5"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"1367"
|
||||
],
|
||||
"in": "1367",
|
||||
"out": "3"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"100"
|
||||
],
|
||||
"in": "100",
|
||||
"out": "5050"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"100"
|
||||
],
|
||||
"in": "100",
|
||||
"out": "5050"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"10"
|
||||
],
|
||||
"in": "10",
|
||||
"out": "55"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"10"
|
||||
],
|
||||
"in": "10",
|
||||
"out": "55"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"100"
|
||||
],
|
||||
"in": "100",
|
||||
"out": "5050"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"2"
|
||||
],
|
||||
"in": "2",
|
||||
"out": "11"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"100"
|
||||
],
|
||||
"in": "100",
|
||||
"out": "5050"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"1",
|
||||
"2"
|
||||
],
|
||||
"in1": "1",
|
||||
"in2": "2",
|
||||
"out": "2"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"5",
|
||||
"10"
|
||||
],
|
||||
"in1": "5",
|
||||
"in2": "10",
|
||||
"out": "901"
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
{
|
||||
"in": [
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"7",
|
||||
"13"
|
||||
],
|
||||
"in1": "2",
|
||||
"in2": "3",
|
||||
"in3": "4",
|
||||
"in4": "7",
|
||||
"in5": "13",
|
||||
"out": "18"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"2",
|
||||
"3"
|
||||
],
|
||||
"in1": "2",
|
||||
"in2": "3",
|
||||
"out": "1"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"1367"
|
||||
],
|
||||
"in": "1367",
|
||||
"out": "3"
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
{
|
||||
"in": [
|
||||
"3",
|
||||
"5",
|
||||
"10",
|
||||
"100"
|
||||
],
|
||||
"in1": "3",
|
||||
"in2": "5",
|
||||
"in3": "10",
|
||||
"in4": "100",
|
||||
"out": "6295"
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
{
|
||||
"in": [
|
||||
"2"
|
||||
],
|
||||
"in": "2",
|
||||
"out": "9"
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"3",
|
||||
"7"
|
||||
],
|
||||
"in1": "3",
|
||||
"in2": "7",
|
||||
"out": "100"
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
{
|
||||
"in": [
|
||||
"3",
|
||||
"7"
|
||||
],
|
||||
"in1": "3",
|
||||
"in2": "7",
|
||||
"out": "120"
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user