1
1
mirror of https://github.com/github/semantic.git synced 2024-12-01 00:33:59 +03:00

Store CallStack information in Errors directly.

Adds a `makeError` constructor that provides a HasCallStack
constraint. One should generally use this instead of the Error
constructor.
This commit is contained in:
Patrick Thomson 2018-07-17 13:47:31 -04:00
parent aab70bd697
commit 1bf1b33819
4 changed files with 26 additions and 21 deletions

View File

@ -1,4 +1,4 @@
{-# LANGUAGE DataKinds, GADTs, InstanceSigs, MultiParamTypeClasses, RankNTypes, ScopedTypeVariables, StandaloneDeriving, TypeFamilies, TypeOperators #-}
{-# LANGUAGE DataKinds, GADTs, InstanceSigs, MultiParamTypeClasses, RankNTypes, ScopedTypeVariables, StandaloneDeriving, TypeFamilies, TypeOperators, ImplicitParams #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-} -- For HasCallStack
-- | Assignment of AST onto some other structure (typically terms).
--
@ -83,7 +83,6 @@ module Assigning.Assignment
, putLocals
-- Results
, Error(..)
, errorCallStack
, nodeError
, firstSet
-- Running
@ -225,7 +224,7 @@ manyThrough step stop = go
nodeError :: HasCallStack => [Either String grammar] -> Node grammar -> Error (Either String grammar)
nodeError expected Node{..} = Error nodeSpan expected (Just (Right nodeSymbol))
nodeError expected Node{..} = Error nodeSpan expected (Just (Right nodeSymbol)) ?callStack
firstSet :: (Enum grammar, Ix grammar) => Assignment ast grammar a -> [grammar]
@ -279,15 +278,15 @@ runAssignment source = \ assignment state -> go assignment state >>= requireExha
Many rule -> fix (\ recur state -> (go rule state >>= \ (a, state') -> first (a:) <$> if state == state' then pure ([], state') else recur state') `catchError` const (pure ([], state))) state >>= uncurry yield
Alt (a:as) -> sconcat (flip yield state <$> a:|as)
Label child label -> go child state `catchError` (\ err -> throwError err { errorExpected = [Left label] }) >>= uncurry yield
Fail s -> throwError ((makeError node) { errorActual = Just (Left s) })
Fail s -> throwError ((makeError' node) { errorActual = Just (Left s) })
Choose _ (Just atEnd) _ | Nothing <- node -> go atEnd state >>= uncurry yield
_ -> Left (makeError node)
_ -> Left (makeError' node)
state@State{..} = case (runTracing t, initialState) of
(Choose table _ _, State { stateNodes = Term (In node _) : _ }) | symbolType (nodeSymbol node) /= Regular, symbols@(_:_) <- Table.tableAddresses table, all ((== Regular) . symbolType) symbols -> skipTokens initialState
_ -> initialState
expectedSymbols = firstSet (t `Then` return)
makeError = withStateCallStack (tracingCallSite t) state $ maybe (Error (Span statePos statePos) (fmap Right expectedSymbols) Nothing) (nodeError (fmap Right expectedSymbols))
makeError' = withStateCallStack (tracingCallSite t) state $ maybe (makeError (Span statePos statePos) (fmap Right expectedSymbols) Nothing) (nodeError (fmap Right expectedSymbols))
requireExhaustive :: Symbol grammar => Maybe (String, SrcLoc) -> (result, State ast grammar) -> Either (Error (Either String grammar)) (result, State ast grammar)
requireExhaustive callSite (a, state) = let state' = skipTokens state in case stateNodes state' of

View File

@ -1,4 +1,4 @@
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FunctionalDependencies, ImplicitParams #-}
-- | Deterministic assignment, à la _Deterministic, Error-Correcting Combinator Parsers_, S. Doaitse Swierstra & Luc Duponcheel: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.80.9967&rep=rep1&type=pdf
module Assigning.Assignment.Deterministic
( Assigning(..)
@ -60,13 +60,13 @@ choose :: (Enum symbol, HasCallStack)
choose nullable firstSet table src state follow = case stateInput state of
[] -> case nullable of
Nullable f -> Right (state, f state)
_ -> Left (withFrozenCallStack (Error (stateSpan state) (Right . toEnum <$> IntSet.toList firstSet) Nothing))
_ -> Left (withFrozenCallStack (Error (stateSpan state) (Right . toEnum <$> IntSet.toList firstSet) Nothing ?callStack))
s:_ -> case fromEnum (astSymbol s) `IntMap.lookup` table of
Just k -> k src state follow
_ -> notFound (astSymbol s) state follow
where notFound s state follow = case nullable of
Nullable f | any (fromEnum s `IntSet.member`) follow -> Right (state, f state)
_ -> Left (withFrozenCallStack (Error (stateSpan state) (Right . toEnum <$> IntSet.toList firstSet) (Just (Right s))))
_ -> Left (withFrozenCallStack (Error (stateSpan state) (Right . toEnum <$> IntSet.toList firstSet) (Just (Right s)) ?callStack))
instance (Enum symbol, Ord symbol) => Applicative (Assignment symbol) where
pure a = Assignment (pure a) lowerBound []
@ -99,15 +99,15 @@ instance (Enum symbol, Ord symbol) => Alternative (Assignment symbol) where
instance (Enum symbol, Ord symbol, Show symbol) => Assigning symbol (Assignment symbol) where
leafNode s = Assignment NotNullable (IntSet.singleton (fromEnum s))
[ (s, \ src state _ -> case stateInput state of
[] -> Left (withFrozenCallStack (Error (stateSpan state) [Right s] Nothing))
[] -> Left (withFrozenCallStack (Error (stateSpan state) [Right s] Nothing ?callStack))
s:_ -> case decodeUtf8' (sourceBytes (Source.slice (astRange s) src)) of
Left err -> Left (withFrozenCallStack (Error (astSpan s) [Left "valid utf-8"] (Just (Left (show err)))))
Left err -> Left (withFrozenCallStack (Error (astSpan s) [Left "valid utf-8"] (Just (Left (show err))) ?callStack))
Right text -> Right (advanceState state, text))
]
branchNode s a = Assignment NotNullable (IntSet.singleton (fromEnum s))
[ (s, \ src state _ -> case stateInput state of
[] -> Left (withFrozenCallStack (Error (stateSpan state) [Right s] Nothing))
[] -> Left (withFrozenCallStack (Error (stateSpan state) [Right s] Nothing ?callStack))
s:_ -> first (const (advanceState state)) <$> runAssignment a src state { stateInput = astChildren s })
]
@ -132,7 +132,7 @@ runAssignment (Assignment nullable firstSet table) src input
Left err -> Left err
Right (state', a') -> case stateInput state' of
[] -> Right (state', a')
s':_ -> Left (withFrozenCallStack (Error (stateSpan state') [] (Just (Right (astSymbol s')))))
s':_ -> Left (withFrozenCallStack (Error (stateSpan state') [] (Just (Right (astSymbol s'))) ?callStack))
data Nullable symbol a

View File

@ -11,19 +11,25 @@ import Data.Source
import Data.Span
import System.Console.ANSI
data Error grammar = HasCallStack => Error { errorSpan :: Span, errorExpected :: [grammar], errorActual :: Maybe grammar }
deriving (Typeable)
data Error grammar = Error
{ errorSpan :: Span
, errorExpected :: [grammar]
, errorActual :: Maybe grammar
, errorCallStack :: CallStack
} deriving (Typeable)
-- | This instance does not take into account the call stack.
instance Eq grammar => Eq (Error grammar) where
(Error s e a _) == (Error s' e' a' _) = all id [s == s', e == e', a == a']
deriving instance Eq grammar => Eq (Error grammar)
deriving instance Foldable Error
deriving instance Functor Error
deriving instance Show grammar => Show (Error grammar)
deriving instance Traversable Error
instance Exception (Error String)
errorCallStack :: Error grammar -> CallStack
errorCallStack Error{} = callStack
makeError :: HasCallStack => Span -> [grammar] -> Maybe grammar -> Error grammar
makeError s e a = Error s e a ?callStack
withCallStack :: CallStack -> (HasCallStack => a) -> a
withCallStack cs action = let ?callStack = cs in action

View File

@ -220,8 +220,8 @@ instance Message String where
errorSyntax :: Error.Error String -> [a] -> Error a
errorSyntax Error.Error{..} = Error (ErrorStack $ errorSite <$> getCallStack callStack) errorExpected errorActual
unError :: Span -> Error a -> Error.Error String
unError span Error{..} = Error.withCallStack (freezeCallStack (fromCallSiteList $ unErrorSite <$> unErrorStack errorCallStack)) (Error.Error span errorExpected errorActual)
unError :: HasCallStack => Span -> Error a -> Error.Error String
unError span Error{..} = Error.withCallStack (freezeCallStack (fromCallSiteList $ unErrorSite <$> unErrorStack errorCallStack)) (Error.makeError span errorExpected errorActual)
data ErrorSite = ErrorSite { errorMessage :: String, errorLocation :: SrcLoc }
deriving (Eq, Show, Generic, Named, Message)