| 1 | import Tok |
|---|
| 2 | |
|---|
| 3 | -- | resolve all tokens to an expression |
|---|
| 4 | resolve :: [Tok] -> Maybe Exp |
|---|
| 5 | resolve ts = do |
|---|
| 6 | (e, rs) <- resolveExpr Nothing ts |
|---|
| 7 | if null rs then return e else error "trailing tokens" |
|---|
| 8 | |
|---|
| 9 | -- | resolve tokens following an optional operator |
|---|
| 10 | resolveExpr :: Maybe Op -> [Tok] -> Maybe (Exp, [Tok]) |
|---|
| 11 | resolveExpr op1 ts = case ts of |
|---|
| 12 | [] -> error "missing right argument" |
|---|
| 13 | t : r -> case t of |
|---|
| 14 | TNeg -> do |
|---|
| 15 | (n, s) <- resolveNegExpr r |
|---|
| 16 | resolveInfix op1 n s |
|---|
| 17 | TExp e1 -> resolveInfix op1 e1 r |
|---|
| 18 | _ -> error "two consecutive operators" |
|---|
| 19 | |
|---|
| 20 | -- | resolve tokens following prefix minus |
|---|
| 21 | resolveNegExpr :: [Tok] -> Maybe (Exp, [Tok]) |
|---|
| 22 | resolveNegExpr ts = do |
|---|
| 23 | -- take all tokens as long as infix operators have higher precedence than - |
|---|
| 24 | let (nts, rs) = span (\ t -> case t of |
|---|
| 25 | TOp (Op _ prec _) -> prec > 6 |
|---|
| 26 | _ -> True) ts |
|---|
| 27 | e <- resolve nts |
|---|
| 28 | return (Neg e, rs) |
|---|
| 29 | |
|---|
| 30 | -- | try to extend an expression by looking at the next infix operator |
|---|
| 31 | resolveInfix :: Maybe Op -> Exp -> [Tok] -> Maybe (Exp, [Tok]) |
|---|
| 32 | resolveInfix mop1 e1 ts = case ts of |
|---|
| 33 | [] -> Just (e1, []) |
|---|
| 34 | t : r -> case t of |
|---|
| 35 | TOp op2@(Op _ prec2 fix2) -> |
|---|
| 36 | let cmp = case mop1 of |
|---|
| 37 | Nothing -> GT |
|---|
| 38 | Just (Op _ prec1 fix1) -> case compare prec2 prec1 of |
|---|
| 39 | EQ -> if fix1 == fix2 then |
|---|
| 40 | case fix1 of |
|---|
| 41 | Leftfix -> LT -- finish |
|---|
| 42 | Nonfix -> EQ -- fail |
|---|
| 43 | Rightfix -> GT -- recurse |
|---|
| 44 | else EQ |
|---|
| 45 | c -> c |
|---|
| 46 | in case cmp of |
|---|
| 47 | LT -> Just (e1, ts) -- finished with expression |
|---|
| 48 | EQ -> Nothing -- illegal expression |
|---|
| 49 | GT -> do -- enlarge left expression |
|---|
| 50 | (e2, r') <- resolveExpr (Just op2) r |
|---|
| 51 | resolveInfix mop1 (OpApp e1 op2 e2) r' |
|---|
| 52 | _ -> error $ "unexpected expression: " ++ show t |
|---|
| 53 | |
|---|
| 54 | main = test resolve |
|---|