instance Ord PState where
PState r1 _ _ _ t1 p1 <= PState r2 _ _ _ t2 p2 =
(r1, t1, p1) <= (r2, t2, p2)
instance Show PState where
showsPrec _ (PState r _ _ _ d p) = showChar '{'
. showSepList (showString "") showTok first
. showSepList (showString "") showTok d
where first = take (length v - length d) v
commaTok, parenTok, termTok :: Token
commaTok = mkSimpleId "," -- for list elements
termTok = mkSimpleId termStr
parenTok = mkSimpleId "(..)"
colonTok, asTok, varTok, opTok, predTok, inTok, caseTok, litTok :: Token
colonTok = mkSimpleId ":"
caseTok = mkSimpleId "case"
varTok = mkSimpleId "(v)"
predTok = mkSimpleId "(p)"
stripFinalPlaces :: Id -> Id
stripFinalPlaces (Id ts cs ps) =
Id (fst $ splitMixToken ts) cs ps
mkState :: Int -> (Id, OpInfo) -> State Int PState
do t <- freshInst $ opType info
return $ PState ide t [] []
(getTokenList termStr $ stripFinalPlaces ide) i
mkApplState :: Int -> (Id, OpInfo) -> State Int PState
mkApplState i (ide, info) =
do t <- freshInst $ opType info
return $ PState ide t [] [] (getTokenList place ide) i
-- unique id (usually "[]" yields two tokens)
listId = Id [mkSimpleId "[]"] [] []
listStates :: GlobalAnnos -> Int -> State Int [PState]
-- no empty list (can be written down directly)
let listState toks = PState listId ty [] [] toks i
(b1, b2) = listBrackets g
return $ if null b1 || null b2 then []
else [ listState (b1 ++ [termTok] ++ b2)
, listState (b1 ++ [termTok, commaTok] ++ b2)]
-- these are the possible matches for the nonterminal (T)
-- the same states are used for the predictions
initialState :: GlobalAnnos -> [(Id, OpInfo)] -> Int -> State Int [PState]
l1 <- mapM (mkState i) ids
l2 <- mapM (mkApplState i) ids
let mkTokState toks = PState (Id toks [] []) (MixfixType [])
return (mkTokState [parenTok] :
mkTokState [termTok, colonTok] :
mkTokState [termTok, asTok] :
mkTokState [termTok, inTok] :
mkTokState [termTok, termTok] :
lookUp :: (Ord a, MonadPlus m) =>
Map.Map a (m b) -> a -> (m b)
-- match (and shift) a token (or partially finished term)
scan :: Term -> Int -> ParseMap -> ParseMap
TermToken x -> if isLitToken x then litTok else
foldr (\ (PState o ty b a ts k) l ->
if null ts || head ts /= t then l
else let p = tokPos t : b in
if t == commaTok && o == listId then
-- list elements separator
(termTok : commaTok : tail ts) k)
: (PState o ty p a (termTok : tail ts) k) : l
else if t == parenTok then
(PState o ty b (trm : a) (tail ts) k) : l
else if t == varTok || t == opTok || t == predTok then
(PState o ty b [trm] (tail ts) k) : l
else if t == colonTok || t == asTok then
(PState o ty b [mkTerm $ head a] [] k) : l
else (PState o ty p a (tail ts) k) : l) []
where mkTerm t1 = case trm of
-- construct resulting term from PState
stateToAppl :: PState -> Term
stateToAppl (PState ide _ rs a _ _) =
let vs = getTokenList place ide
in if vs == [termTok, colonTok]
|| vs == [termTok, asTok]
toAppl :: GlobalAnnos -> PState -> Term
toAppl g s@(PState i _ bs a _ _) =
case list_lit $ literal_annos g of
Nothing -> error "toAppl"
let (b1, b2) = listBrackets g
mkList [] ps = asAppl c [] (head ps)
mkList (hd:tl) ps = asAppl f [hd, mkList tl (tail ps)] (head ps)
in if null a then asAppl c [] (if null bs then nullPos else last bs)
else if nb + 1 == nb1 + nb2 + na then
in mkList (reverse a) br1
-- precedence graph stuff
checkArg :: GlobalAnnos -> AssocEither -> Id -> Id -> Bool
then isAssoc dir (assoc_annos g) op || not (isInfix op)
case precRel (prec_annos g) op arg of
ExplGroup BothDirections -> False
ExplGroup NoDirection -> not $ isInfix arg
checkAnyArg :: GlobalAnnos -> Id -> Id -> Bool
case precRel (prec_annos g) op arg of
ExplGroup BothDirections -> isInfix op && op == arg
isLeftArg, isRightArg :: Id -> Int -> Bool
isLeftArg (Id ts _ _) n = n + 1 == (length $ takeWhile isPlace ts)
isRightArg (Id ts _ _) n = n == (length $ filter isPlace ts) -
(length $ takeWhile isPlace (reverse ts))
filterByPrec :: GlobalAnnos -> PState -> PState -> Bool
filterByPrec _ _ (PState _ _ _ _ [] _) = False
filterByPrec g (PState argIde _ _ _ _ _) (PState opIde _ _ args (hd:_) _) =
if opIde == listId || argIde == listId then True
else let n = length args in
if isLeftArg opIde n then
if isPostfix opIde && (isPrefix argIde
|| isInfix argIde) then False
else checkArg g ALeft opIde argIde
else if isRightArg opIde n then
if isPrefix opIde && isInfix argIde then False
else checkArg g ARight opIde argIde
else checkAnyArg g opIde argIde
filterByType :: ParseMap -> PState -> PState -> Bool
filterByType cm pArg pOp = True
-- when a grammar rule (mixfix Id) has been fully matched
collectArg :: GlobalAnnos -> ParseMap -> PState -> [PState]
collectArg g m s@(PState _ _ _ _ _ k) =
foldr (\ (PState o ty b a ts k1) l ->
PState o ty b (toAppl g s : a)
$ filter (filterByType m s)
$ filter (filterByPrec g s)
compl :: GlobalAnnos -> ParseMap -> [PState] -> [PState]
concat $ map (collectArg g m)
$ filter (\ (PState _ _ _ _ ts _) -> null ts) l
complRec :: GlobalAnnos -> ParseMap -> [PState] -> [PState]
complRec g m l = let l1 = compl g m l in
if null l1 then l else complRec g m l1 ++ l
complete :: GlobalAnnos -> Int -> ParseMap -> ParseMap
cm { parseMap =
Map.insert i (complRec g cm $ lookUp m i) m }
-- predict which
rules/ids might match for (the) nonterminal(s) (termTok)
-- provided the "dot" is followed by a nonterminal
data ParseMap = ParseMap { varCount :: Int
predict :: GlobalAnnos -> [(Id, OpInfo)] -> Int -> ParseMap -> ParseMap
if i /= 0 && any (\ (PState _ _ _ _ ts _) -> not (null ts)
then let (ps, c2) = runState (initialState g is i)
type Chart = (Int, [Diagnosis], ParseMap)
nextState :: GlobalAnnos -> [(Id, OpInfo)] -> Term -> Chart -> Chart
nextState g is trm (i, ds, m) =
let cm1 = predict g is i m
in if null (lookUp (parseMap cm2) (i+1)) && null ds
then (i+1, mkDiag Error "unexpected mixfix token" trm
iterateStates :: GlobalAnnos -> [(Id, OpInfo)] -> [Term] -> Chart -> Chart
iterateStates g ops terms c =
let self = iterateStates g ops
_resolveTerm = resolve g ops
MixfixTerm ts -> self (ts ++ tail terms) c
self (expand "[" "]" ts ps ++ tail terms) c
t -> self (tail terms) (nextState g ops t c)
where expand = expandPos TermToken
getAppls :: GlobalAnnos -> Int -> ParseMap -> [Term]
filter (\ (PState _ _ _ _ ts k) -> null ts && k == 0) $
resolve :: GlobalAnnos -> [(Id, OpInfo)] -> ParseMap -> Term -> Result Term
let (ps, c2) = runState (initialState g ops 0) (varCount p)
(i, ds, m) = iterateStates g ops [trm]
(0, [], p { varCount = c2, parseMap =
in if null ts then if null ds then
plain_error trm ("no resolution for term: "
else Result ds (Just trm)
else if null $ tail ts then Result ds (Just (head ts))
else Result (Diag Error ("ambiguous mixfix term\n\t" ++
$ take 5 ts)) (nullPos) : ds) (Just trm)
asAppl :: Id -> [Term] -> Pos -> Term
asAppl f args p = let pos = if null args then [] else [p]
in ApplTerm (QualOp (InstOpId f [] [])
(simpleTypeScheme $ MixfixType [])
[]) (TupleTerm args []) pos