module UU.Parsing.Offside( parseOffside , pBlock , pBlock1 , pOffside , pOpen , pClose , pSeparator , scanOffside , OffsideSymbol(..) , OffsideInput , Stream , OffsideParser(..) ) where import UU.Parsing.Interface import UU.Parsing.Machine import UU.Parsing.Derived(opt, pFoldr1Sep,pList,pList1, pList1Sep) import UU.Scanner.Position data OffsideSymbol s = Symbol s | SemiColon | CloseBrace | OpenBrace deriving (Ord,Eq,Show) scanOffside :: (InputState i s p, Position p, Eq s) => s -> s -> s -> [s] -> i -> OffsideInput i s p scanOffside mod open close triggers ts = start ts [] where isModule t = t == mod isOpen t = t == open isClose t = t == close isTrigger t = t `elem` triggers end ts = Off (getPosition ts) (End ts) cons :: p -> OffsideSymbol s -> OffsideInput i s p -> OffsideInput i s p cons p s r = Off p (Cons s r) Nothing start = case splitStateE ts of Left' t _ | not (isModule t || isOpen t) -> implicitL 0 (column (getPosition ts) ) _ -> layoutL 0 -- L (:ts) (m:ms) = ; : (L ts (m:ms)) if m = n -- = } : (L (:ts) ms) if n < m -- L (:ts) ms = L ts ms startlnL l n ts (m:ms) | m == n = cons (getPosition ts) SemiColon (layoutL (line (getPosition ts)) ts (m:ms)) | n < m = cons (getPosition ts) CloseBrace (startlnL l n ts ms) startlnL l n ts ms = layoutL (line (getPosition ts)) ts ms -- L ({n}:ts) (m:ms) = { : (L ts (n:m:ms)) if n > m (Note 1) -- L ({n}:ts) [] = { : (L ts [n]) if n > 0 (Note 1) -- L ({n}:ts) ms = { : } : (L (:ts) ms) (Note 2) implicitL l n ts (m:ms) | n > m = cons (getPosition ts) OpenBrace (layoutL (line (getPosition ts)) ts (n:m:ms)) implicitL l n ts [] | n > 0 = cons (getPosition ts) OpenBrace (layoutL (line (getPosition ts)) ts [n]) implicitL l n ts ms = cons (getPosition ts) OpenBrace (cons (getPosition ts) CloseBrace (startlnL l n ts ms)) layoutL ln ts ms | ln /= sln = startln (column pos) ts ms | otherwise = sameln ts ms where sln = line pos pos = getPosition ts layout = layoutL ln implicit = implicitL ln startln = startlnL ln -- If a let ,where ,do , or of keyword is not followed by the lexeme {, -- the token {n} is inserted after the keyword, where nis the indentation of -- the next lexeme if there is one, or 0 if the end of file has been reached. aftertrigger ts ms = case splitStateE ts of Left' t _ | isOpen t -> layout ts ms | otherwise -> implicit (column(getPosition ts)) ts ms Right' _ -> implicit 0 ts ms -- L ( }:ts) (0:ms) = } : (L ts ms) (Note 3) -- L ( }:ts) ms = parse-error (Note 3), matching of implicit/explicit braces is handled by parser -- L ( {:ts) ms = {: (L ts (0:ms)) (Note 4) -- L (t:ts) (m:ms) = }: (L (t:ts) ms) if m /= 0 and parse-error(t) (Note 5) -- L (t:ts) ms = t : (L ts ms) sameln tts ms = case splitStateE tts of Left' t ts | isTrigger t -> cons pos (Symbol t) (aftertrigger ts ms) | isClose t -> cons pos (Symbol t) (case ms of 0:ms -> layout ts ms _ -> layout ts ms ) | isOpen t -> cons pos (Symbol t) (layout ts (0:ms)) | otherwise -> let parseError = case ms of m:ms | m /= 0 -> Just (layout tts ms) _ -> Nothing in Off pos (Cons (Symbol t) (layout ts ms)) parseError Right' rest -> endofinput pos rest ms where pos = getPosition tts -- L [] [] = [] -- L [] (m:ms) = } : L [] ms if m /=0 (Note 6) -- = L [] ms, if m == 0 (this is an error, the parser should yield a parse error, if this situation occurs) endofinput pos rest [] = Off pos (End rest) Nothing endofinput pos rest (m:ms) | m /= 0 = cons pos CloseBrace (endofinput pos rest ms) | otherwise = endofinput pos rest ms data Stream inp s p = Cons (OffsideSymbol s) (OffsideInput inp s p) | End inp data OffsideInput inp s p = Off p (Stream inp s p) (Maybe (OffsideInput inp s p)) instance InputState inp s p => InputState (OffsideInput inp s p) (OffsideSymbol s) p where splitStateE inp@(Off p stream _) = case stream of Cons s rest -> Left' s rest _ -> Right' inp splitState (Off _ stream _) = case stream of Cons s rest -> (s ,rest) getPosition (Off pos _ _ ) = pos instance Symbol s => Symbol (OffsideSymbol s) where deleteCost s = case s of Symbol s -> deleteCost s SemiColon -> 5 OpenBrace -> 5 CloseBrace -> 5 symBefore s = case s of Symbol s -> Symbol (symBefore s) SemiColon -> error "Symbol.symBefore SemiColon" OpenBrace -> error "Symbol.symBeforeOpenBrace" CloseBrace -> error "Symbol.symBefore CloseBrace" symAfter s = case s of Symbol s -> Symbol (symAfter s) SemiColon -> error "Symbol.symAfter SemiColon" OpenBrace -> error "Symbol.symAfter OpenBrace" CloseBrace -> error "Symbol.symAfter CloseBrace" newtype OffsideParser i o s p a = OP (AnaParser (OffsideInput i s p) o (OffsideSymbol s) p a) instance (Symbol s, Ord s, InputState i s p, OutputState o) => IsParser (OffsideParser i o s p) s where (<*>) = operator (<*>) (<* ) = operator (<* ) ( *>) = operator ( *>) (<|>) = operator (<|>) (<$>) = operatorr (<$>) (<$ ) = operatorr (<$ ) pSucceed = OP . pSucceed pLow = OP . pLow pFail = OP pFail pCostRange c s (Range l r) = OP (getSymbol <$> pCostRange c (Symbol s) (Range (Symbol l)(Symbol r))) pCostSym c s t = OP (getSymbol <$> pCostSym c (Symbol s) (Symbol t)) pSym s = OP (getSymbol <$> pSym (Symbol s)) pRange s (Range l r) = OP (getSymbol <$> pRange (Symbol s) (Range (Symbol l)(Symbol r))) getfirsts (OP p) = removeSymbol (getfirsts p) setfirsts exp (OP p) = OP (setfirsts (addSymbol exp) p) getzerop (OP p) = fmap OP (getzerop p) getonep (OP p) = fmap OP (getonep p) removeSymbol exp = case exp of ESym (Range (Symbol l) (Symbol r)) -> ESym (Range l r) ESym _ -> EOr [] EStr txt -> EStr txt EOr exps -> EOr (map removeSymbol exps) ESeq exps -> ESeq (map removeSymbol exps) addSymbol exp = case exp of ESym (Range l r) -> ESym (Range (Symbol l) (Symbol r)) EStr txt -> EStr txt EOr exps -> EOr (map addSymbol exps) ESeq exps -> ESeq (map addSymbol exps) getSymbol (Symbol s) = s operator f (OP p) (OP q) = OP (f p q) operatorr f g (OP p) = OP (f g p) pSeparator :: (OutputState o, InputState i s p, Position p, Symbol s, Ord s) => OffsideParser i o s p () pSeparator = OP (() <$ pCostSym 5 SemiColon SemiColon) pClose, pOpen :: (OutputState o, InputState i s p, Position p, Symbol s, Ord s) => OffsideParser i o s p () pClose = OP (pWrap f g ( () <$ pSym CloseBrace) ) where g state steps1 k = (state,ar,k) where ar = case state of Off _ _ (Just state') -> let steps2 = k state' in if not (hasSuccess steps1) && hasSuccess steps2 then steps2 else steps1 _ -> steps1 f acc state steps k = let (stl,ar,str2rr) = g state (val snd steps) k in (stl ,val (acc ()) ar , str2rr ) pOpen = OP (() <$ pSym OpenBrace) pOffside :: (InputState i s p, OutputState o, Position p, Symbol s, Ord s) => OffsideParser i o s p x -> OffsideParser i o s p y -> OffsideParser i o s p a -> OffsideParser i o s p a -> OffsideParser i o s p a pOffside open close bodyE bodyI = open *> bodyE <* close <|> pOpen *> bodyI <* pClose pBlock :: (InputState i s p, OutputState o, Position p, Symbol s, Ord s) => OffsideParser i o s p x -> OffsideParser i o s p y -> OffsideParser i o s p z -> OffsideParser i o s p a -> OffsideParser i o s p [a] pBlock open sep close p = pOffside open close explicit implicit where elem = (:) <$> p `opt` id sep' = () <$ sep elems s = ($[]) <$> pFoldr1Sep ((.),id) s elem explicit = elems sep' implicit = elems (sep' <|> pSeparator) pBlock1 :: (InputState i s p, OutputState o, Position p, Symbol s, Ord s) => OffsideParser i o s p x -> OffsideParser i o s p y -> OffsideParser i o s p z -> OffsideParser i o s p a -> OffsideParser i o s p [a] pBlock1 open sep close p = pOffside open close explicit implicit where sep' = () <$ sep elems s = pList s *> pList1Sep (pList1 s) p <* pList s explicit = elems sep' implicit = elems (sep' <|> pSeparator) parseOffside :: (Symbol s, InputState i s p, Position p) => OffsideParser i Pair s p a -> OffsideInput i s p -> Steps (a, OffsideInput i s p) (OffsideSymbol s) p parseOffside (OP p) inp = val fromPair (parse p inp) where fromPair (Pair x (Pair y _)) = (x,y)