Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77f2f900d8 | ||
|
|
ff5a5af9bc | ||
|
|
7a6518583f | ||
|
|
dda0e17358 | ||
|
|
46f0393a03 | ||
|
|
1803a1e058 | ||
|
|
ccf17faff8 | ||
|
|
14df00039f |
@@ -23,7 +23,7 @@ $ cabal test --test-show-details=direct
|
||||
$ rlpc -ddump-eval examples/factorial.hs
|
||||
# Compile and evaluate t.hs, with evaluation info dumped to t.log
|
||||
$ rlpc -ddump-eval -l t.log t.hs
|
||||
# Print the raw structure describing the compiler options and die
|
||||
# Print the raw structure describing the compiler options
|
||||
# (option parsing still must succeed in order to print)
|
||||
$ rlpc -ddump-opts t.hs
|
||||
```
|
||||
|
||||
17
app/CoreDriver.hs
Normal file
17
app/CoreDriver.hs
Normal file
@@ -0,0 +1,17 @@
|
||||
module CoreDriver
|
||||
( driver
|
||||
)
|
||||
where
|
||||
--------------------------------------------------------------------------------
|
||||
import Compiler.RLPC
|
||||
import Control.Monad
|
||||
|
||||
import Core.Lex
|
||||
import Core.Parse
|
||||
import GM
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
driver :: RLPCIO ()
|
||||
driver = forFiles_ $ \f ->
|
||||
withSource f (lexCoreR >=> parseCoreProgR >=> evalProgR)
|
||||
|
||||
105
app/Main.hs
105
app/Main.hs
@@ -10,12 +10,16 @@ import Data.HashSet qualified as S
|
||||
import Data.Text (Text)
|
||||
import Data.Text qualified as T
|
||||
import Data.Text.IO qualified as TIO
|
||||
import Data.List
|
||||
import System.IO
|
||||
import System.Exit (exitSuccess)
|
||||
import Core
|
||||
import TI
|
||||
import GM
|
||||
import Lens.Micro.Mtl
|
||||
|
||||
import CoreDriver qualified
|
||||
import RlpDriver qualified
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
optParser :: ParserInfo RLPCOptions
|
||||
@@ -37,9 +41,15 @@ options = RLPCOptions
|
||||
{- -d -}
|
||||
<*> fmap S.fromList # many # option debugFlagReader
|
||||
( short 'd'
|
||||
<> help "dump evaluation logs"
|
||||
<> help "pass debug flags"
|
||||
<> metavar "DEBUG FLAG"
|
||||
)
|
||||
{- -f -}
|
||||
<*> fmap S.fromList # many # option compilerFlagReader
|
||||
( short 'f'
|
||||
<> help "pass compilation flags"
|
||||
<> metavar "COMPILATION FLAG"
|
||||
)
|
||||
{- --evaluator, -e -}
|
||||
<*> option evaluatorReader
|
||||
( long "evaluator"
|
||||
@@ -55,11 +65,27 @@ options = RLPCOptions
|
||||
\triggering the garbage collector"
|
||||
<> value 50
|
||||
)
|
||||
<*> option languageReader
|
||||
( long "language"
|
||||
<> short 'x'
|
||||
)
|
||||
<*> some (argument str $ metavar "FILES...")
|
||||
where
|
||||
infixr 9 #
|
||||
f # x = f x
|
||||
|
||||
languageReader :: ReadM Language
|
||||
languageReader = maybeReader $ \case
|
||||
"rlp" -> Just LanguageRlp
|
||||
"core" -> Just LanguageCore
|
||||
_ -> Nothing
|
||||
|
||||
debugFlagReader :: ReadM DebugFlag
|
||||
debugFlagReader = str
|
||||
|
||||
compilerFlagReader :: ReadM CompilerFlag
|
||||
compilerFlagReader = str
|
||||
|
||||
evaluatorReader :: ReadM Evaluator
|
||||
evaluatorReader = maybeReader $ \case
|
||||
"gm" -> Just EvaluatorGM
|
||||
@@ -69,82 +95,15 @@ evaluatorReader = maybeReader $ \case
|
||||
mmany :: (Alternative f, Monoid m) => f m -> f m
|
||||
mmany v = liftA2 (<>) v (mmany v)
|
||||
|
||||
debugFlagReader :: ReadM DebugFlag
|
||||
debugFlagReader = maybeReader $ \case
|
||||
"dump-eval" -> Just DDumpEval
|
||||
"dump-opts" -> Just DDumpOpts
|
||||
"dump-ast" -> Just DDumpAST
|
||||
_ -> Nothing
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
-- temp
|
||||
data CompilerError = CompilerError String
|
||||
deriving Show
|
||||
|
||||
instance Exception CompilerError
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
opts <- execParser optParser
|
||||
(_, es) <- evalRLPCIO opts driver
|
||||
forM_ es $ \ (CompilerError e) -> print $ "warning: " <> e
|
||||
pure ()
|
||||
void $ evalRLPCIO opts driver
|
||||
|
||||
driver :: RLPCIO CompilerError ()
|
||||
driver = sequence_
|
||||
[ dshowFlags
|
||||
, ddumpAST
|
||||
, ddumpEval
|
||||
]
|
||||
|
||||
dshowFlags :: RLPCIO CompilerError ()
|
||||
dshowFlags = whenFlag flagDDumpOpts do
|
||||
ask >>= liftIO . print
|
||||
|
||||
ddumpAST :: RLPCIO CompilerError ()
|
||||
ddumpAST = whenFlag flagDDumpAST $ forFiles_ \o f -> do
|
||||
liftIO $ withFile f ReadMode $ \h -> do
|
||||
s <- TIO.hGetContents h
|
||||
case parseProg o s of
|
||||
Right (a,_) -> hPutStrLn stderr $ show a
|
||||
Left e -> error "todo errors lol"
|
||||
|
||||
ddumpEval :: RLPCIO CompilerError ()
|
||||
ddumpEval = whenFlag flagDDumpEval do
|
||||
fs <- view rlpcInputFiles
|
||||
forM_ fs $ \f -> liftIO (TIO.readFile f) >>= doProg
|
||||
|
||||
where
|
||||
doProg :: Text -> RLPCIO CompilerError ()
|
||||
doProg s = ask >>= \o -> case parseProg o s of
|
||||
-- TODO: error handling
|
||||
Left e -> addFatal . CompilerError $ show e
|
||||
Right (a,_) -> do
|
||||
log <- view rlpcLogFile
|
||||
dumpEval <- chooseEval
|
||||
case log of
|
||||
Just f -> liftIO $ withFile f WriteMode $ dumpEval a
|
||||
Nothing -> liftIO $ dumpEval a stderr
|
||||
|
||||
-- choose the appropriate model based on the compiler opts
|
||||
chooseEval = do
|
||||
ev <- view rlpcEvaluator
|
||||
pure $ case ev of
|
||||
EvaluatorGM -> v GM.hdbgProg
|
||||
EvaluatorTI -> v TI.hdbgProg
|
||||
where v f p h = f p h *> pure ()
|
||||
|
||||
parseProg :: RLPCOptions
|
||||
-> Text
|
||||
-> Either SrcError (Program', [SrcError])
|
||||
parseProg o = evalRLPC o . (lexCore >=> parseCoreProg)
|
||||
|
||||
forFiles_ :: (Monad m)
|
||||
=> (RLPCOptions -> FilePath -> RLPCT e m a)
|
||||
-> RLPCT e m ()
|
||||
forFiles_ k = do
|
||||
fs <- view rlpcInputFiles
|
||||
o <- ask
|
||||
forM_ fs (k o)
|
||||
driver :: RLPCIO ()
|
||||
driver = view rlpcLanguage >>= \case
|
||||
LanguageCore -> CoreDriver.driver
|
||||
LanguageRlp -> RlpDriver.driver
|
||||
|
||||
|
||||
11
app/RlpDriver.hs
Normal file
11
app/RlpDriver.hs
Normal file
@@ -0,0 +1,11 @@
|
||||
module RlpDriver
|
||||
( driver
|
||||
)
|
||||
where
|
||||
--------------------------------------------------------------------------------
|
||||
import Compiler.RLPC
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
driver :: RLPCIO ()
|
||||
driver = undefined
|
||||
|
||||
@@ -38,8 +38,7 @@ library
|
||||
, Rlp.Lex
|
||||
, Rlp.Parse.Types
|
||||
, Compiler.Types
|
||||
|
||||
other-modules: Data.Heap
|
||||
, Data.Heap
|
||||
, Data.Pretty
|
||||
, Core.Parse
|
||||
, Core.Lex
|
||||
@@ -73,6 +72,7 @@ library
|
||||
, semigroupoids
|
||||
, comonad
|
||||
, lens
|
||||
, text-ansi
|
||||
|
||||
hs-source-dirs: src
|
||||
default-language: GHC2021
|
||||
@@ -85,8 +85,9 @@ library
|
||||
executable rlpc
|
||||
import: warnings
|
||||
main-is: Main.hs
|
||||
-- other-modules:
|
||||
-- other-extensions:
|
||||
other-modules: RlpDriver
|
||||
, CoreDriver
|
||||
|
||||
build-depends: base >=4.17.0.0 && <4.20.0.0
|
||||
, rlp
|
||||
, optparse-applicative >= 0.18.1 && < 0.19
|
||||
|
||||
@@ -11,31 +11,32 @@ errors and the family of RLPC monads.
|
||||
-- only used for mtl instances
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
{-# LANGUAGE DeriveGeneric, DerivingStrategies, DerivingVia #-}
|
||||
{-# LANGUAGE BlockArguments, ViewPatterns #-}
|
||||
module Compiler.RLPC
|
||||
( RLPC
|
||||
, RLPCT(..)
|
||||
, RLPCIO
|
||||
, RLPCOptions(RLPCOptions)
|
||||
, IsRlpcError(..)
|
||||
, RlpcError(..)
|
||||
, MsgEnvelope(..)
|
||||
, addFatal
|
||||
, addWound
|
||||
, MonadErrorful
|
||||
, Severity(..)
|
||||
, Evaluator(..)
|
||||
, evalRLPCT
|
||||
, evalRLPCIO
|
||||
, evalRLPC
|
||||
, rlpcLogFile
|
||||
, rlpcDFlags
|
||||
, rlpcEvaluator
|
||||
, rlpcInputFiles
|
||||
, DebugFlag(..)
|
||||
, whenDFlag
|
||||
, whenFFlag
|
||||
, def
|
||||
, liftErrorful
|
||||
(
|
||||
-- * Rlpc Monad transformer
|
||||
RLPCT(RLPCT),
|
||||
-- ** Special cases
|
||||
RLPC, RLPCIO
|
||||
-- ** Running
|
||||
, runRLPCT
|
||||
, evalRLPCT, evalRLPCIO, evalRLPC
|
||||
-- * Rlpc options
|
||||
, Language(..), Evaluator(..)
|
||||
, DebugFlag(..), CompilerFlag(..)
|
||||
-- ** Lenses
|
||||
, rlpcLogFile, rlpcDFlags, rlpcEvaluator, rlpcInputFiles, rlpcLanguage
|
||||
-- * Misc. MTL-style functions
|
||||
, liftErrorful, hoistRlpcT
|
||||
-- * Misc. Rlpc Monad -related types
|
||||
, RLPCOptions(RLPCOptions), IsRlpcError(..), RlpcError(..)
|
||||
, MsgEnvelope(..), Severity(..)
|
||||
, addDebugMsg
|
||||
, whenDFlag, whenFFlag
|
||||
-- * Misc. Utilities
|
||||
, forFiles_, withSource
|
||||
-- * Convenient re-exports
|
||||
, addFatal, addWound, def
|
||||
)
|
||||
where
|
||||
----------------------------------------------------------------------------------
|
||||
@@ -45,7 +46,9 @@ import Control.Monad
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.State (MonadState(state))
|
||||
import Control.Monad.Errorful
|
||||
import Control.Monad.IO.Class
|
||||
import Compiler.RlpcError
|
||||
import Compiler.Types
|
||||
import Data.Functor.Identity
|
||||
import Data.Default.Class
|
||||
import Data.Foldable
|
||||
@@ -55,19 +58,34 @@ import Data.Hashable (Hashable)
|
||||
import Data.HashSet (HashSet)
|
||||
import Data.HashSet qualified as S
|
||||
import Data.Coerce
|
||||
import Data.Text (Text)
|
||||
import Data.Text qualified as T
|
||||
import Data.Text.IO qualified as T
|
||||
import Text.ANSI qualified as Ansi
|
||||
import Text.PrettyPrint hiding ((<>))
|
||||
import Lens.Micro.Platform
|
||||
import Lens.Micro.Platform.Internal
|
||||
import System.Exit
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
newtype RLPCT m a = RLPCT {
|
||||
runRLPCT :: ReaderT RLPCOptions (ErrorfulT (MsgEnvelope RlpcError) m) a
|
||||
}
|
||||
deriving (Functor, Applicative, Monad, MonadReader RLPCOptions)
|
||||
deriving ( Functor, Applicative, Monad
|
||||
, MonadReader RLPCOptions, MonadErrorful (MsgEnvelope RlpcError))
|
||||
|
||||
rlpc :: (IsRlpcError e, Monad m)
|
||||
=> (RLPCOptions -> (Maybe a, [MsgEnvelope e]))
|
||||
-> RLPCT m a
|
||||
rlpc f = RLPCT . ReaderT $ \opt ->
|
||||
ErrorfulT . pure $ f opt & _2 . each . mapped %~ liftRlpcError
|
||||
|
||||
type RLPC = RLPCT Identity
|
||||
|
||||
type RLPCIO = RLPCT IO
|
||||
|
||||
instance (MonadIO m) => MonadIO (RLPCT m) where
|
||||
|
||||
evalRLPC :: RLPCOptions
|
||||
-> RLPC a
|
||||
-> (Maybe a, [MsgEnvelope RlpcError])
|
||||
@@ -75,32 +93,28 @@ evalRLPC opt r = runRLPCT r
|
||||
& flip runReaderT opt
|
||||
& runErrorful
|
||||
|
||||
evalRLPCT :: (Monad m)
|
||||
=> RLPCOptions
|
||||
evalRLPCT :: RLPCOptions
|
||||
-> RLPCT m a
|
||||
-> m (Maybe a, [MsgEnvelope RlpcError])
|
||||
evalRLPCT = undefined
|
||||
|
||||
evalRLPCIO :: RLPCOptions -> RLPCIO a -> IO a
|
||||
evalRLPCIO opt r = do
|
||||
(ma,es) <- evalRLPCT opt r
|
||||
putRlpcErrs es
|
||||
case ma of
|
||||
Just x -> pure x
|
||||
Nothing -> die "Failed, no code compiled."
|
||||
|
||||
putRlpcErrs :: [MsgEnvelope RlpcError] -> IO ()
|
||||
putRlpcErrs = traverse_ print
|
||||
evalRLPCT opt r = runRLPCT r
|
||||
& flip runReaderT opt
|
||||
& runErrorfulT
|
||||
|
||||
liftErrorful :: (Monad m, IsRlpcError e) => ErrorfulT (MsgEnvelope e) m a -> RLPCT m a
|
||||
liftErrorful e = RLPCT $ lift (fmap liftRlpcError `mapErrorful` e)
|
||||
|
||||
hoistRlpcT :: (forall a. m a -> n a)
|
||||
-> RLPCT m a -> RLPCT n a
|
||||
hoistRlpcT f rma = RLPCT $ ReaderT $ \opt ->
|
||||
ErrorfulT $ f $ evalRLPCT opt rma
|
||||
|
||||
data RLPCOptions = RLPCOptions
|
||||
{ _rlpcLogFile :: Maybe FilePath
|
||||
, _rlpcDFlags :: HashSet DebugFlag
|
||||
, _rlpcFFlags :: HashSet CompilerFlag
|
||||
, _rlpcEvaluator :: Evaluator
|
||||
, _rlpcHeapTrigger :: Int
|
||||
, _rlpcLanguage :: Language
|
||||
, _rlpcInputFiles :: [FilePath]
|
||||
}
|
||||
deriving Show
|
||||
@@ -108,6 +122,9 @@ data RLPCOptions = RLPCOptions
|
||||
data Evaluator = EvaluatorGM | EvaluatorTI
|
||||
deriving Show
|
||||
|
||||
data Language = LanguageRlp | LanguageCore
|
||||
deriving Show
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
instance Default RLPCOptions where
|
||||
@@ -118,16 +135,20 @@ instance Default RLPCOptions where
|
||||
, _rlpcEvaluator = EvaluatorGM
|
||||
, _rlpcHeapTrigger = 200
|
||||
, _rlpcInputFiles = []
|
||||
, _rlpcLanguage = LanguageRlp
|
||||
}
|
||||
|
||||
-- debug flags are passed with -dFLAG
|
||||
type DebugFlag = String
|
||||
type DebugFlag = Text
|
||||
|
||||
type CompilerFlag = String
|
||||
type CompilerFlag = Text
|
||||
|
||||
makeLenses ''RLPCOptions
|
||||
pure []
|
||||
|
||||
addDebugMsg :: (Monad m, IsText e) => Text -> e -> RLPCT m ()
|
||||
addDebugMsg tag e = addWound . debugMsg tag $ Text [e ^. unpacked . packed]
|
||||
|
||||
-- TODO: rewrite this with prisms once microlens-pro drops :3
|
||||
whenDFlag :: (Monad m) => DebugFlag -> RLPCT m () -> RLPCT m ()
|
||||
whenDFlag f m = do
|
||||
@@ -143,3 +164,75 @@ whenFFlag f m = do
|
||||
let a = S.member f fs
|
||||
when a m
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
evalRLPCIO :: RLPCOptions -> RLPCIO a -> IO a
|
||||
evalRLPCIO opt r = do
|
||||
(ma,es) <- evalRLPCT opt r
|
||||
putRlpcErrs opt es
|
||||
case ma of
|
||||
Just x -> pure x
|
||||
Nothing -> die "Failed, no code compiled."
|
||||
|
||||
putRlpcErrs :: RLPCOptions -> [MsgEnvelope RlpcError] -> IO ()
|
||||
putRlpcErrs opts = filter byTag
|
||||
>>> traverse_ (putStrLn . ('\n':) . prettyRlpcMsg)
|
||||
where
|
||||
dflags = opts ^. rlpcDFlags
|
||||
|
||||
byTag :: MsgEnvelope RlpcError -> Bool
|
||||
byTag (view msgSeverity -> SevDebug t) =
|
||||
t `S.member` dflags
|
||||
|
||||
prettyRlpcMsg :: MsgEnvelope RlpcError -> String
|
||||
prettyRlpcMsg m@(view msgSeverity -> SevDebug _) = prettyRlpcDebugMsg m
|
||||
prettyRlpcMsg m = render $ docRlpcErr m
|
||||
|
||||
prettyRlpcDebugMsg :: MsgEnvelope RlpcError -> String
|
||||
prettyRlpcDebugMsg msg =
|
||||
T.unpack . foldMap mkLine $ [ t' | t <- ts, t' <- T.lines t ]
|
||||
where
|
||||
mkLine s = "-d" <> tag <> ": " <> s <> "\n"
|
||||
Text ts = msg ^. msgDiagnostic
|
||||
SevDebug tag = msg ^. msgSeverity
|
||||
|
||||
docRlpcErr :: MsgEnvelope RlpcError -> Doc
|
||||
docRlpcErr msg = header
|
||||
$$ nest 2 bullets
|
||||
$$ source
|
||||
where
|
||||
source = vcat $ zipWith (<+>) rule srclines
|
||||
where
|
||||
rule = repeat (ttext . Ansi.blue . Ansi.bold $ "|")
|
||||
srclines = ["", "<problematic source code>", ""]
|
||||
filename = msgColour "<input>"
|
||||
pos = msgColour $ tshow (msg ^. msgSpan . srcspanLine)
|
||||
<> ":"
|
||||
<> tshow (msg ^. msgSpan . srcspanColumn)
|
||||
|
||||
header = ttext $ filename <> msgColour ":" <> pos <> msgColour ": "
|
||||
<> errorColour "error" <> msgColour ":"
|
||||
|
||||
bullets = let Text ts = msg ^. msgDiagnostic
|
||||
in vcat $ hang "•" 2 . ttext . msgColour <$> ts
|
||||
|
||||
msgColour = Ansi.white . Ansi.bold
|
||||
errorColour = Ansi.red . Ansi.bold
|
||||
ttext = text . T.unpack
|
||||
tshow :: (Show a) => a -> Text
|
||||
tshow = T.pack . show
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
forFiles_ :: (Monad m)
|
||||
=> (FilePath -> RLPCT m a)
|
||||
-> RLPCT m ()
|
||||
forFiles_ k = do
|
||||
fs <- view rlpcInputFiles
|
||||
forM_ fs k
|
||||
|
||||
-- TODO: catch any exceptions, i.e. non-existent files should be handled by the
|
||||
-- compiler
|
||||
withSource :: (MonadIO m) => FilePath -> (Text -> RLPCT m a) -> RLPCT m a
|
||||
withSource f k = liftIO (T.readFile f) >>= k
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ module Compiler.RlpcError
|
||||
, msgSeverity
|
||||
, liftRlpcErrors
|
||||
, errorMsg
|
||||
, debugMsg
|
||||
-- * Located Comonad
|
||||
, Located(..)
|
||||
, SrcSpan(..)
|
||||
@@ -46,6 +47,7 @@ instance IsRlpcError RlpcError where
|
||||
|
||||
data Severity = SevWarning
|
||||
| SevError
|
||||
| SevDebug Text
|
||||
deriving Show
|
||||
|
||||
makeLenses ''MsgEnvelope
|
||||
@@ -65,3 +67,11 @@ errorMsg s e = MsgEnvelope
|
||||
, _msgSeverity = SevError
|
||||
}
|
||||
|
||||
debugMsg :: Text -> e -> MsgEnvelope e
|
||||
debugMsg tag e = MsgEnvelope
|
||||
-- TODO: not pretty, but it is a debug message after all
|
||||
{ _msgSpan = SrcSpan 0 0 0 0
|
||||
, _msgDiagnostic = e
|
||||
, _msgSeverity = SevDebug tag
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module Compiler.Types
|
||||
( SrcSpan(..)
|
||||
, srcspanLine, srcspanColumn, srcspanAbs, srcspanLen
|
||||
, Located(..)
|
||||
, (<<~), (<~>)
|
||||
|
||||
@@ -13,6 +14,7 @@ module Compiler.Types
|
||||
import Control.Comonad
|
||||
import Data.Functor.Apply
|
||||
import Data.Functor.Bind
|
||||
import Control.Lens hiding ((<<~))
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- | Token wrapped with a span (line, column, absolute, length)
|
||||
@@ -39,6 +41,16 @@ data SrcSpan = SrcSpan
|
||||
!Int -- ^ Length
|
||||
deriving Show
|
||||
|
||||
tupling :: Iso' SrcSpan (Int, Int, Int, Int)
|
||||
tupling = iso (\ (SrcSpan a b c d) -> (a,b,c,d))
|
||||
(\ (a,b,c,d) -> SrcSpan a b c d)
|
||||
|
||||
srcspanLine, srcspanColumn, srcspanAbs, srcspanLen :: Lens' SrcSpan Int
|
||||
srcspanLine = tupling . _1
|
||||
srcspanColumn = tupling . _2
|
||||
srcspanAbs = tupling . _3
|
||||
srcspanLen = tupling . _4
|
||||
|
||||
instance Semigroup SrcSpan where
|
||||
SrcSpan la ca aa sa <> SrcSpan lb cb ab sb = SrcSpan l c a s where
|
||||
l = min la lb
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE FunctionalDependencies #-}
|
||||
{-# LANGUAGE TupleSections, PatternSynonyms #-}
|
||||
{-# LANGUAGE PatternSynonyms #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
module Control.Monad.Errorful
|
||||
( ErrorfulT
|
||||
, runErrorfulT
|
||||
( ErrorfulT(..)
|
||||
, Errorful
|
||||
, pattern Errorful
|
||||
, errorful
|
||||
, runErrorful
|
||||
, mapErrorful
|
||||
, MonadErrorful(..)
|
||||
@@ -13,6 +13,7 @@ module Control.Monad.Errorful
|
||||
where
|
||||
----------------------------------------------------------------------------------
|
||||
import Control.Monad.State.Strict
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans
|
||||
import Data.Functor.Identity
|
||||
import Data.Coerce
|
||||
@@ -28,6 +29,9 @@ type Errorful e = ErrorfulT e Identity
|
||||
pattern Errorful :: (Maybe a, [e]) -> Errorful e a
|
||||
pattern Errorful a = ErrorfulT (Identity a)
|
||||
|
||||
errorful :: (Applicative m) => (Maybe a, [e]) -> ErrorfulT e m a
|
||||
errorful = ErrorfulT . pure
|
||||
|
||||
runErrorful :: Errorful e a -> (Maybe a, [e])
|
||||
runErrorful m = coerce (runErrorfulT m)
|
||||
|
||||
@@ -67,13 +71,13 @@ mapErrorful f (ErrorfulT m) = ErrorfulT $
|
||||
m & mapped . _2 . mapped %~ f
|
||||
|
||||
-- when microlens-pro drops we can write this as
|
||||
-- mapErrorful f = coerced . mapped . _2 . mappd %~ f
|
||||
-- mapErrorful f = coerced . mapped . _2 . mapped %~ f
|
||||
-- lol
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- daily dose of n^2 instances
|
||||
|
||||
instance (Monad m, MonadErrorful e m) => MonadErrorful e (StateT s m) where
|
||||
addWound = undefined
|
||||
addFatal = undefined
|
||||
instance (Monad m, MonadErrorful e m) => MonadErrorful e (ReaderT r m) where
|
||||
addWound = lift . addWound
|
||||
addFatal = lift . addFatal
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ checkCoreProg p = scDefs
|
||||
where scname = sc ^. _lhs._1
|
||||
|
||||
-- | @checkCoreProgR p@ returns @p@ if @p@ successfully typechecks.
|
||||
checkCoreProgR :: Program' -> RLPC Program'
|
||||
checkCoreProgR :: (Applicative m) => Program' -> RLPCT m Program'
|
||||
checkCoreProgR p = undefined
|
||||
|
||||
{-# WARNING checkCoreProgR "unimpl" #-}
|
||||
|
||||
@@ -20,6 +20,7 @@ import Debug.Trace
|
||||
import Data.Text (Text)
|
||||
import Data.Text qualified as T
|
||||
import Data.String (IsString(..))
|
||||
import Data.Functor.Identity
|
||||
import Core.Syntax
|
||||
import Compiler.RLPC
|
||||
-- TODO: unify Located definitions
|
||||
@@ -180,8 +181,11 @@ lexCore s = case m of
|
||||
where
|
||||
m = runAlex s lexStream
|
||||
|
||||
lexCoreR :: Text -> RLPC [Located CoreToken]
|
||||
lexCoreR = lexCore
|
||||
lexCoreR :: forall m. (Applicative m) => Text -> RLPCT m [Located CoreToken]
|
||||
lexCoreR = hoistRlpcT generalise . lexCore
|
||||
where
|
||||
generalise :: forall a. Identity a -> m a
|
||||
generalise (Identity a) = pure a
|
||||
|
||||
-- | @lexCore@, but the tokens are stripped of location info. Useful for
|
||||
-- debugging
|
||||
|
||||
@@ -17,9 +17,11 @@ module Core.Parse
|
||||
|
||||
import Control.Monad ((>=>))
|
||||
import Data.Foldable (foldl')
|
||||
import Data.Functor.Identity
|
||||
import Core.Syntax
|
||||
import Core.Lex
|
||||
import Compiler.RLPC
|
||||
import Control.Monad
|
||||
import Lens.Micro
|
||||
import Data.Default.Class (def)
|
||||
import Data.Hashable (Hashable)
|
||||
@@ -224,8 +226,16 @@ insScDef sc = programScDefs %~ (sc:)
|
||||
singletonScDef :: (Hashable b) => ScDef b -> Program b
|
||||
singletonScDef sc = insScDef sc mempty
|
||||
|
||||
parseCoreProgR :: [Located CoreToken] -> RLPC Program'
|
||||
parseCoreProgR = parseCoreProg
|
||||
parseCoreProgR :: forall m. (Monad m) => [Located CoreToken] -> RLPCT m Program'
|
||||
parseCoreProgR = ddumpast <=< (hoistRlpcT generalise . parseCoreProg)
|
||||
where
|
||||
generalise :: forall a. Identity a -> m a
|
||||
generalise (Identity a) = pure a
|
||||
|
||||
ddumpast :: Program' -> RLPCT m Program'
|
||||
ddumpast p = do
|
||||
addDebugMsg "dump-ast" . show $ p
|
||||
pure p
|
||||
|
||||
happyBind :: RLPC a -> (a -> RLPC b) -> RLPC b
|
||||
happyBind m k = m >>= k
|
||||
|
||||
@@ -103,7 +103,7 @@ data Binding b = Binding b (Expr b)
|
||||
deriving instance (Eq b) => Eq (Binding b)
|
||||
|
||||
infixl 1 :=
|
||||
pattern (:=) :: b -> (Expr b) -> (Binding b)
|
||||
pattern (:=) :: b -> Expr b -> Binding b
|
||||
pattern k := v = Binding k v
|
||||
|
||||
data Alter b = Alter AltCon [b] (Expr b)
|
||||
@@ -123,7 +123,7 @@ data AltCon = AltData Name
|
||||
| Default
|
||||
deriving (Show, Read, Eq, Lift)
|
||||
|
||||
data Lit = IntL Int
|
||||
newtype Lit = IntL Int
|
||||
deriving (Show, Read, Eq, Lift)
|
||||
|
||||
type Name = T.Text
|
||||
@@ -201,7 +201,7 @@ instance HasLHS (Alter b) (Alter b) (AltCon, [b]) (AltCon, [b]) where
|
||||
instance HasLHS (ScDef b) (ScDef b) (b, [b]) (b, [b]) where
|
||||
_lhs = lens
|
||||
(\ (ScDef n as _) -> (n,as))
|
||||
(\ (ScDef _ _ e) (n',as') -> (ScDef n' as' e))
|
||||
(\ (ScDef _ _ e) (n',as') -> ScDef n' as' e)
|
||||
|
||||
instance HasLHS (Binding b) (Binding b) b b where
|
||||
_lhs = lens
|
||||
|
||||
17
src/GM.hs
17
src/GM.hs
@@ -8,6 +8,7 @@ Description : The G-Machine
|
||||
module GM
|
||||
( hdbgProg
|
||||
, evalProg
|
||||
, evalProgR
|
||||
, Node(..)
|
||||
, gmEvalProg
|
||||
, finalStateOf
|
||||
@@ -34,6 +35,7 @@ import System.IO (Handle, hPutStrLn)
|
||||
import Data.String (IsString)
|
||||
import Data.Heap
|
||||
import Debug.Trace
|
||||
import Compiler.RLPC
|
||||
import Core2Core
|
||||
import Core
|
||||
----------------------------------------------------------------------------------
|
||||
@@ -156,6 +158,21 @@ hdbgProg p hio = do
|
||||
[resAddr] = final ^. gmStack
|
||||
res = hLookupUnsafe resAddr h
|
||||
|
||||
evalProgR :: (Monad m) => Program' -> RLPCT m (Node, Stats)
|
||||
evalProgR p = do
|
||||
(renderOut . showState) `traverse_` states
|
||||
renderOut . showStats $ sts
|
||||
pure (res, sts)
|
||||
where
|
||||
renderOut r = addDebugMsg "dump-eval" $ render r ++ "\n"
|
||||
states = eval . compile $ p
|
||||
final = last states
|
||||
|
||||
sts = final ^. gmStats
|
||||
-- the address of the result should be the one and only stack entry
|
||||
[resAddr] = final ^. gmStack
|
||||
res = hLookupUnsafe resAddr (final ^. gmHeap)
|
||||
|
||||
eval :: GmState -> [GmState]
|
||||
eval st = st : rest
|
||||
where
|
||||
|
||||
@@ -11,6 +11,8 @@ module Rlp.Lex
|
||||
, lexDebug
|
||||
, lexCont
|
||||
, popLexState
|
||||
, programInitState
|
||||
, runP'
|
||||
)
|
||||
where
|
||||
import Codec.Binary.UTF8.String (encodeChar)
|
||||
@@ -236,27 +238,9 @@ alexEOF = do
|
||||
pos <- getPos
|
||||
pure (Located (spanFromPos pos 0) TokenEOF)
|
||||
|
||||
initParseState :: Text -> ParseState
|
||||
initParseState s = ParseState
|
||||
{ _psLayoutStack = []
|
||||
-- IMPORTANT: the initial state is `bol` to begin the top-level layout,
|
||||
-- which then returns to state 0 which continues the normal lexing process.
|
||||
, _psLexState = [layout_top,0]
|
||||
, _psInput = initAlexInput s
|
||||
, _psOpTable = mempty
|
||||
}
|
||||
|
||||
initAlexInput :: Text -> AlexInput
|
||||
initAlexInput s = AlexInput
|
||||
{ _aiPrevChar = '\0'
|
||||
, _aiSource = s
|
||||
, _aiBytes = []
|
||||
, _aiPos = (1,1,0)
|
||||
}
|
||||
|
||||
runP' :: P a -> Text -> (ParseState, [MsgEnvelope RlpParseError], Maybe a)
|
||||
runP' p s = runP p st where
|
||||
st = initParseState s
|
||||
st = initParseState [layout_top,0] s
|
||||
|
||||
lexToken :: P (Located RlpToken)
|
||||
lexToken = do
|
||||
@@ -310,7 +294,7 @@ popLayout = do
|
||||
psLayoutStack %= (drop 1)
|
||||
case ctx of
|
||||
Just l -> pure l
|
||||
Nothing -> error "uhh"
|
||||
Nothing -> error "popLayout: layout stack empty! this is a bug."
|
||||
|
||||
pushLayout :: Layout -> P ()
|
||||
pushLayout l = do
|
||||
@@ -368,10 +352,13 @@ explicitRBrace inp l = do
|
||||
doLayout :: LexerAction (Located RlpToken)
|
||||
doLayout _ _ = do
|
||||
i <- indentLevel
|
||||
traceM $ "doLayout: i: " <> show i
|
||||
-- traceM $ "doLayout: i: " <> show i
|
||||
pushLayout (Implicit i)
|
||||
popLexState
|
||||
insertLBrace
|
||||
|
||||
programInitState :: Text -> ParseState
|
||||
programInitState = initParseState [layout_top,0]
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
{-# LANGUAGE LambdaCase, ViewPatterns #-}
|
||||
module Rlp.Parse
|
||||
( parseRlpProg
|
||||
, parseRlpProgR
|
||||
, parseRlpExpr
|
||||
, parseRlpExprR
|
||||
)
|
||||
where
|
||||
import Compiler.RlpcError
|
||||
import Compiler.RLPC
|
||||
import Rlp.Lex
|
||||
import Rlp.Syntax
|
||||
import Rlp.Parse.Types
|
||||
@@ -19,6 +22,7 @@ import Data.Functor.Bind
|
||||
import Control.Comonad
|
||||
import Data.Functor
|
||||
import Data.Semigroup.Traversable
|
||||
import Data.Text (Text)
|
||||
import Data.Text qualified as T
|
||||
import Data.Void
|
||||
}
|
||||
@@ -29,6 +33,7 @@ import Data.Void
|
||||
%monad { P }
|
||||
%lexer { lexCont } { Located _ TokenEOF }
|
||||
%error { parseError }
|
||||
%errorhandlertype explist
|
||||
%tokentype { Located RlpToken }
|
||||
|
||||
%token
|
||||
@@ -85,6 +90,7 @@ DeclsV :: { [Decl' RlpcPs] }
|
||||
DeclsV : Decl VS Decls { $1 : $3 }
|
||||
| Decl VS { [$1] }
|
||||
| Decl { [$1] }
|
||||
| {- epsilon -} { [] }
|
||||
|
||||
VS :: { Located RlpToken }
|
||||
VS : ';' { $1 }
|
||||
@@ -187,6 +193,13 @@ Con :: { Located PsName }
|
||||
|
||||
{
|
||||
|
||||
parseRlpExprR = undefined
|
||||
|
||||
parseRlpProgR :: (Monad m) => Text -> RLPCT m (RlpProgram RlpcPs)
|
||||
parseRlpProgR s = liftErrorful $ pToErrorful parseRlpProg st
|
||||
where
|
||||
st = programInitState s
|
||||
|
||||
mkPsName :: Located RlpToken -> Located PsName
|
||||
mkPsName = fmap extractName
|
||||
|
||||
@@ -207,9 +220,9 @@ mkProgram ds = do
|
||||
pt <- use psOpTable
|
||||
pure $ RlpProgram (associate pt <$> ds)
|
||||
|
||||
parseError :: Located RlpToken -> P a
|
||||
parseError (Located ss t) = addFatal $
|
||||
errorMsg ss RlpParErrUnexpectedToken
|
||||
parseError :: (Located RlpToken, [String]) -> P a
|
||||
parseError ((Located ss t), exp) = addFatal $
|
||||
errorMsg ss (RlpParErrUnexpectedToken t exp)
|
||||
|
||||
mkInfixD :: Assoc -> Int -> PsName -> P (Decl' RlpcPs)
|
||||
mkInfixD a p n = do
|
||||
@@ -228,3 +241,4 @@ intOfToken :: Located RlpToken -> Int
|
||||
intOfToken (Located _ (TokenLitInt n)) = n
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ module Rlp.Parse.Types
|
||||
|
||||
-- * Parser monad and state
|
||||
, P(..), ParseState(..), Layout(..), OpTable, OpInfo
|
||||
, initParseState, initAlexInput
|
||||
, pToErrorful
|
||||
-- ** Lenses
|
||||
, psLayoutStack, psLexState, psInput, psOpTable
|
||||
|
||||
@@ -39,6 +41,7 @@ import Data.Functor.Classes
|
||||
import Data.HashMap.Strict qualified as H
|
||||
import Data.Void
|
||||
import Data.Word (Word8)
|
||||
import Data.Text qualified as T
|
||||
import Lens.Micro.TH
|
||||
import Lens.Micro
|
||||
import Rlp.Syntax
|
||||
@@ -145,6 +148,11 @@ newtype P a = P {
|
||||
}
|
||||
deriving (Functor)
|
||||
|
||||
pToErrorful :: (Applicative m)
|
||||
=> P a -> ParseState -> ErrorfulT (MsgEnvelope RlpParseError) m a
|
||||
pToErrorful p st = ErrorfulT $ pure (ma,es) where
|
||||
(_,es,ma) = runP p st
|
||||
|
||||
instance Applicative P where
|
||||
pure a = P $ \st -> (st, [], pure a)
|
||||
liftA2 = liftM2
|
||||
@@ -188,10 +196,28 @@ type OpInfo = (Assoc, Int)
|
||||
data RlpParseError = RlpParErrOutOfBoundsPrecedence Int
|
||||
| RlpParErrDuplicateInfixD Name
|
||||
| RlpParErrLexical
|
||||
| RlpParErrUnexpectedToken
|
||||
deriving (Eq, Ord, Show)
|
||||
| RlpParErrUnexpectedToken RlpToken [String]
|
||||
deriving (Show)
|
||||
|
||||
instance IsRlpcError RlpParseError where
|
||||
liftRlpcError = \case
|
||||
RlpParErrOutOfBoundsPrecedence n ->
|
||||
Text [ "Illegal precedence in infixity declaration"
|
||||
, "rl' currently only allows precedences between 0 and 9."
|
||||
]
|
||||
RlpParErrDuplicateInfixD s ->
|
||||
Text [ "Conflicting infixity declarations for operator "
|
||||
<> tshow s
|
||||
]
|
||||
RlpParErrLexical ->
|
||||
Text [ "Unknown lexical error :(" ]
|
||||
RlpParErrUnexpectedToken t exp ->
|
||||
Text [ "Unexpected token " <> tshow t
|
||||
, "Expected: " <> tshow exp
|
||||
]
|
||||
where
|
||||
tshow :: (Show a) => a -> T.Text
|
||||
tshow = T.pack . show
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
@@ -224,3 +250,21 @@ addFatalHere l e = P $ \st ->
|
||||
}
|
||||
in (st, [e'], Nothing)
|
||||
|
||||
initParseState :: [Int] -> Text -> ParseState
|
||||
initParseState ls s = ParseState
|
||||
{ _psLayoutStack = []
|
||||
-- IMPORTANT: the initial state is `bol` to begin the top-level layout,
|
||||
-- which then returns to state 0 which continues the normal lexing process.
|
||||
, _psLexState = ls
|
||||
, _psInput = initAlexInput s
|
||||
, _psOpTable = mempty
|
||||
}
|
||||
|
||||
initAlexInput :: Text -> AlexInput
|
||||
initAlexInput s = AlexInput
|
||||
{ _aiPrevChar = '\0'
|
||||
, _aiSource = s
|
||||
, _aiBytes = []
|
||||
, _aiPos = (1,1,0)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user