INblobs-0.1.1: src/Functional/Parser.hs
{-|
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"