{-| Module : Functional.Parser Copyright : (c) Miguel Vilaça 2007 Maintainer : jmvilaca@di.uminho.pt Stability : experimental Portability : portable Small Functional Language: Parser -} module Functional.Parser (parse) where import Functional.Language import Data.Char parse :: String -> Either FuncLang String parse str = case filter (nul.snd) res of [(term, _)] -> Left term _ -> case res of [] -> Right "Null result" l -> Right $ "Ambiguous parsing.\n" ++ show l where res = reads $ map f str f c | isControl c = ' ' | otherwise = c nul = all (\c -> isControl c || isSpace c) instance Read FuncLang where -- readsPrec :: Int -> String -> [(a, String)] readsPrec d str = map (\(v,s) -> (Var v,s)) (readVar str) -- variables ++ readParen (d > abst_prec) -- abstraction - allow [x,y]t (\r -> [(vs t, r4) | ("[",r2) <- lex r, (vs,r3) <- readVars r2, (t,r4) <- readsPrec (abst_prec+1) r3 ]) str ++ readParen (d > app_prec) (\r -> [(Appl t u, r2) | (t,r1) <- readsPrec (app_prec+1) r, (u,r2) <- readsPrec (app_prec+1) r1 ]) str ++ readTerminal TT "tt" str ++ readTerminal FF "ff" str ++ readParen (d > iter_prec) -- iterbool (\r -> [(IterBool v f b, r8) | ("iterbool",r1) <- lex r, ("(",r2) <- lex r1, (v,r3) <- readsPrec 0 r2, (",",r4) <- lex r3, (f,r5) <- readsPrec 0 r4, (",",r6) <- lex r5, (b,r7) <- readsPrec 0 r6, (")",r8) <- lex r7]) str ++ readTerminal Zero "0" str ++ readParen (d > const_prec) -- suc (\r -> [(Succ m, r4) | ("suc",r1) <- lex r, ("(",r2) <- lex r1, (m,r3) <- readsPrec 0 r2, (")",r4) <- lex r3]) str ++ readParen (d > iter_prec) -- iternat (\r -> [(IterNat x s z t, r8) | ("iternat",r1) <- lex r, ("(",r2) <- lex r1, (Abst x s,r3) <- readsPrec 0 r2, (",",r4) <- lex r3, (z,r5) <- readsPrec 0 r4, (",",r6) <- lex r5, (t,r7) <- readsPrec 0 r6, (")",r8) <- lex r7]) str ++ readTerminal Nil "nil" str ++ readParen (d > const_prec) -- cons (\r -> [(Cons a as, r6) | ("cons(",r1) <- lex r, ("(",r2) <- lex r1, (a,r3) <- readsPrec 0 r2, (",",r4) <- lex r3, (as,r5) <- readsPrec 0 r4, (")",r6) <- lex r5]) str ++ readParen (d > iter_prec) -- iterlist (\r -> [(IterList x y c n l, r8) | ("iterlist",r1) <- lex r, ("(",r2) <- lex r1, (Abst x (Abst y c),r3) <- readsPrec 0 r2, (",",r4) <- lex r3, (n,r5) <- readsPrec 0 r4, (",",r6) <- lex r5, (l,r7) <- readsPrec 0 r6, (")",r8) <- lex r7]) str where abst_prec = 5 app_prec = 5 terminal_prec = 10 iter_prec = 10 const_prec = 10 readTerminal term symb str = readParen (d > terminal_prec) (\r -> [(term,t) | (symb1,t) <- lex r, symb1 == symb]) str readVar str = readParen False (\r -> [(v,t) | (v,t) <- lex r, isVariable v]) str readVars str = [ (Abst v, r1) | (v,r) <- readVar str , ("]",r1) <- lex r] ++ [ (Abst v . lv, r2) | (v,r) <- readVar str , (",",r1) <- lex r , (lv, r2) <- readVars r1] reservedWords :: [String] reservedWords = ["tt","ff","iterbool","0","suc","iternat","nil","cons","iterlist"] isVariable :: String -> Bool isVariable str = not (null str) && str `notElem` reservedWords && all isAlphaNum str && not (isDigit $ head str) -- Examples str = " [x,y,z,a,b](" ++ "(iterbool(x,y,tt) iterlist([x,y]y (x (a z)), (a z), nil) )" ++ "(iternat([x]x,x,0) iterbool(y,y,tt)))" term = Left $ Abst "x" $ Abst "y" $ Abst "z" $ Abst "a" $ Abst "b" $ Appl (Appl (IterBool x y TT) (IterList "x" "y" (Appl y $ Appl x $ Appl a z) (Appl a z) Nil) ) (Appl (IterNat "x" x x Zero) (IterBool y y TT) ) x = Var "x" y = Var "y" z = Var "z" a = Var "a"