--
module Parser where
import qualified System.IO
import Data.Char(digitToInt,isUpper)
import GHC.Float(double2Float)
-- These are for defining parsers
import Text.Parsec hiding (State)
import Text.Parsec.Expr(Operator(..),Assoc(..),buildExpressionParser)
-- Replaces Text.Parsec.Token
import qualified LayoutToken as Token
-- This is for possible Monads underlying the Parsing Monad
import Control.Monad.State
import Data.Functor.Identity(Identity(..))
-- This is to catch errors when Parsing
import qualified Control.Exception
import Debug.Trace
-- import the Hughes Pretty Printing library qualified
import qualified Text.PrettyPrint.HughesPJ as PP
-- import a few widely used operations without qualification
import Text.PrettyPrint.HughesPJ(Doc,text,int,(<>),(<+>),($$),($+$),render)
-----------------------------------------------
-- running parsers
-- Extract a computation from the Parser Monad
runMParser parser parserState name tokens =
runIdentity (runParserT parser parserState name tokens)
-- Skip whitespace before you begin
parse1 file x = runMParser (whiteSp >> x) initColumns file
-- Raise an Haskell error if a parsing error occurs
parseWithName file x s =
case parse1 file x s of
Right(ans) -> ans
Left message -> error (show message)
-- Parse with a default name for the input
parse2 x s = parseWithName "keyboard input" x s
-- Parse and return the internal state
parse3 p s = putStrLn (show state) >> return object
where (object,state) = parse2 (do { x <- p; st <- getState; return(x,st)}) s
-- Parse an t-object, return
-- (t,rest-of-input-not-parsed)
parse4 p s =
parse2 (do { x <- p
; rest <- getInput
; return (x,rest)}) s
-- Parse a string in an arbitray monad
parseString x s =
case parse1 s x s of
Right(ans) -> return ans
Left message -> fail (show message)
-- Parse a File in the IO monad
parseFile parser file =
do possible <- Control.Exception.try (readFile file)
case possible of
Right contents ->
case parse1 file parser contents of
Right ans -> return ans
Left message -> error(show message)
Left err -> error(show (err::IOError))
--------------------------------------------
-- A parser with internal state of a list of columns
-- use (updateState,setState,getState) to access the [Column]
-- for debugging only
traceP p = do { ((c,vs),_) <- getState; ans <- p; ((d,us),_) <- getState
; trace ("In "++show c++"\nOut "++show d) (return ans)}
initColumns = []
type MParser a = ParsecT
String -- The input is a sequence of Char
[Column] -- The internal state for Layout tabs
(Identity) -- The underlying monad is simple
a -- the type of the object being parsed
-- Based on Parsec's haskellStyle (which we can not use directly since
-- Parsec gives it a too specific type).
lbStyle = Token.LanguageDef
{ Token.commentStart = "{-"
, Token.commentEnd = "-}"
, Token.commentLine = "--"
, Token.nestedComments = True
, Token.identStart = lower
, Token.identLetter = alphaNum <|> oneOf "_'"
, Token.opStart = oneOf ":!#$%&*+./<=>?@\\^|-~"
, Token.opLetter = oneOf ":!#$%&*+./<=>?@\\^|-~"
, Token.caseSensitive = True
, Token.reservedOpNames =
["!","?","\\",":",".", "<", "=", "+", "-", "^", "()", "_", "@"]
, Token.reservedNames =
["if","then","else","case","of","let","in"]
}
(haskellTP,Token.LayFun layout) = Token.makeTokenParser lbStyle "{" ";" "}"
lexemE p = Token.lexeme haskellTP p
arrow = lexemE(string "->")
larrow = lexemE(string "<-")
dot = lexemE(char '.')
parenS p = between (symboL "(") (symboL ")") p
braceS p = between (symboL "{") (symboL "}") p
bracketS p = between (symboL "[") (symboL "]") p
symboL = Token.symbol haskellTP
natural = lexemE(number 10 digit)
whiteSp = Token.whiteSpace haskellTP
idenT = Token.identifier haskellTP
keyworD = Token.reserved haskellTP
commA = Token.comma haskellTP
resOp = Token.reservedOp haskellTP
opeR = Token.operator haskellTP
character c = lexemE(char c)
---------------------------------------------------------------
number :: Integer -> MParser Char -> MParser Integer
number base baseDigit
= do{ digits <- many1 baseDigit
; let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits
; seq n (return n)
}
signed p = do { f <- sign; n <- p ; return(f n)}
where sign = (character '-' >> return (* (-1))) <|>
(character '+' >> return id) <|>
(return id)
int32:: MParser Int
int32 = do { n <- signed natural; return(fromInteger n)} > ""
float32:: MParser Float
float32 = do { n <- Token.float haskellTP ; return(double2Float n)} > ""
letParser declP expP =
do { pos <- getPosition -- This gets the SourcePos
; keyworD "let"
; ds <- layout declP (keyworD "in")
; exp <- expP
; return(ds,exp)}
------------------------------------------------------------------
type Var = (SourcePos,String) -- Starts lowercase
type Con = (SourcePos,String) -- Starts with Upper case
type Name = (SourcePos,String) -- Starts with either lower case or uppercase
data Lit
= Int Int
| Char Char
| Unit
| Float Float
data Pat
= Plit Lit -- { 5 or 'c' }
| Pvar Var -- { x }
| Pprod [Pat] -- { (p1,p2,p3) }
| Paspat Var Pat -- { x @ p }
| Pwild -- { _ }
| Pcon Con [Pat] -- C x y (z,a)
data Exp
= Var Name -- { x or Nil }
| Lit Lit -- { 5 or 'c' or 5.6 }
| Prod [Exp] -- { (e1,e2,e3) }
| App Exp Exp -- { f x }
| Lam [Pat] Exp -- { \ p1 p2 -> e }
| Let [Dec] Exp -- { let { x=e1; y=e2 } in e3 }
| Case Exp [Match Pat Exp Dec] -- { case e of { m1; m2 }}
| Do [Stmt Pat Exp Dec] -- { do { p <- e1; e2 } }
-- Let, Case, Do, all use layout
type Match p e d = (SourcePos,p,Body e,[d]) -- case e of { p -> b where decs }
data Body e
= Guarded [(e,e)] -- f p { | e1 = e2 | e3 = e4 } where ds
| Normal e -- f p = { e } where ds
-- Where uses layout
data Stmt p e d
= BindSt SourcePos p e
| LetSt SourcePos [d]
| NoBindSt SourcePos e
data Dec
= Fun SourcePos Var [Match [Pat] Exp Dec] -- { f p1 p2 = b where decs }
| Val SourcePos Pat (Body Exp) [Dec] -- { p = b where decs }
------------------------------
-- Parsing code here
---------------------------------
-- Pretty printing code here
ppDec:: Dec -> Doc
ppDec = undefined
ppLit:: Lit -> Doc
ppLit = undefined
ppExp:: Exp -> Doc
ppExp = undefined
ppPat:: Pat -> Doc
ppPat = undefined
ppBody:: (e -> Doc) -> Body e -> Doc
ppBody = undefined
ppStmt :: (p -> Doc) -> (e -> Doc) -> (d -> Doc) -> Stmt p e d -> Doc
ppStmt = undefined
ppProg :: [Dec] -> Doc
ppProg = undefined
--------------------------------
-- The main functions here
main :: IO()
main = undefined
test:: IO()
test = undefined
--