-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 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>
- Loading branch information
1 parent
2148d17
commit d576111
Showing
91 changed files
with
1,127 additions
and
361 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.