descript-lang-0.2.0.0: src/Descript/Sugar/Parse.hs
{-# LANGUAGE OverloadedStrings #-}
module Descript.Sugar.Parse
( parse
, parseInputVal
, parseOutputVal
) where
import Descript.Sugar.Parse.Refine
import Descript.Sugar.Data.Source hiding (query, amodule, importCtx, recordCtx, reduceCtx)
import Descript.Sugar.Data.Reducer hiding (input, output)
import qualified Descript.Sugar.Data.Value.In as In
import qualified Descript.Sugar.Data.Value.Out as Out
import Descript.Sugar.Data.Type
import Descript.Sugar.Data.Import hiding (moduleDecl)
import Descript.Free.Error
import qualified Descript.Free.Data as Free
import Descript.Misc
import Text.Megaparsec hiding (ParseError, parse)
import Core.Text.Megaparsec
import Data.Foldable
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.Set as Set
import Prelude hiding (any)
type Parser a = Parsec RangedError (RangeStream Free.TopLevel) a
type RParser a = Parser (a Range)
-- | Parses a source file from the given file and contents.
parse :: ParseAction (RangeStream Free.TopLevel) (Source Range)
parse file = runLaterParser (source file) file
-- | Parses an individual input value from the given file and contents.
parseInputVal :: ParseAction (Free.Value Range) (In.Value Range)
parseInputVal file = refineResToParseRes file . freeToInput
-- | Parses an individual output value from the given file and contents.
parseOutputVal :: ParseAction (Free.Value Range) (Out.Value Range)
parseOutputVal file = refineResToParseRes file . freeToOutput
source :: SFile -> RParser Source
source file
= ranged $ label "source"
$ mkSource <$@> bmodule file <*@> optional query
bmodule :: SFile -> RParser BModule
bmodule file
= ranged $ label "module"
$ BModule <$@> importCtx file <*@> amodule
amodule :: RParser AModule
amodule
= ranged
$ AModule <$@> recordCtx <*@> reduceCtx
importCtx :: SFile -> RParser ImportCtx
importCtx file
= ranged $ label "all imports"
$ mkImportCtx file <$@> optional moduleDecl <*@> many importDecl
recordCtx :: RParser RecordCtx
recordCtx
= ranged $ label "all record type declarations"
$ RecordCtx <$@> many recordDecl
reduceCtx :: RParser ReduceCtx
reduceCtx
= ranged $ label "all reducers"
$ ReduceCtx <$@> phaseCtx `someSepBy` satisfy Free.topLevelIsPhaseSep
phaseCtx :: RParser PhaseCtx
phaseCtx
= ranged $ label "all reducers in a particular phase"
$ PhaseCtx <$@> many reducer
moduleDecl :: RParser ModuleDecl
moduleDecl
= label "module declaration"
$ mapSatisfy Free.topLevelToModuleDecl
importDecl :: Parser (AbsScope -> ImportDecl Range)
importDecl
= label "import declaration"
$ flip freeToImportDeclIn <$> mapSatisfy Free.topLevelToImportDecl
recordDecl :: RParser RecordDecl
recordDecl
= absorbError $ label "record type eclaration"
$ freeToRecordDecl <$> mapSatisfy Free.topLevelToRecordDecl
reducer :: RParser Reducer
reducer
= absorbError $ label "reducer"
$ freeToReducer <$> mapSatisfy Free.topLevelToReducer
query :: RParser Query
query
= absorbError $ label "query"
$ freeToQuery <$> mapSatisfy Free.topLevelToQuery
absorbError :: Parser (RefineResult (a Range)) -> RParser a
absorbError x = x >>= refineResToParser
refineResToParser :: RefineResult (a Range) -> RParser a
refineResToParser (Failure err) = refineDiffToParser err
refineResToParser (Success x) = pure x
refineResToParseRes :: SFile -> RefineResult a -> ParseResult a
refineResToParseRes = mapError . refineDiffToParseErr
refineDiffToParser :: RefineDiff -> Parser a
refineDiffToParser (RefineDiff diffs) = do
filename <- sourceName <$> getPosition
setPosition $ locToPos filename $ indivDiffsErrLoc diffs
fancyFailure $ Set.fromList $ map indivDiffToFancyErr diffs
refineDiffToParseErr :: (Ord t) => SFile -> RefineDiff -> (ParseError t)
refineDiffToParseErr file (RefineDiff diffs)
= FancyError posStack $ Set.fromList $ map indivDiffToFancyErr diffs
where posStack = locToPos (sfileName file) (indivDiffsErrLoc diffs) :| []
indivDiffToFancyErr :: IndivRefineDiff -> ErrorFancy RangedError
indivDiffToFancyErr = ErrorCustom . indivDiffToRangedErr
indivDiffToRangedErr :: IndivRefineDiff -> RangedError
indivDiffToRangedErr (IndivRefineDiff range' local)
= RangedError
{ errorRange = range'
, rangedErrorExpected = expected local
-- Don't want full summary - print handled by range
, rangedErrorActual = actual local
}
indivDiffsErrLoc :: [IndivRefineDiff] -> Loc
indivDiffsErrLoc = minimum . map (start . range)