packages feed

ministg-0.1: src/Ministg/Parser.hs

-----------------------------------------------------------------------------
-- |
-- Module      : Ministg.Parser
-- Copyright   : (c) 2009 Bernie Pope 
-- License     : BSD-style
-- Maintainer  : bjpop@csse.unimelb.edu.au
-- Stability   : experimental
-- Portability : ghc
--
-- Parsing for ministg programs.
-----------------------------------------------------------------------------
module Ministg.Parser (parser) where

import Prelude hiding (exp, subtract)
import Text.ParserCombinators.Parsec hiding (Parser)
import qualified Ministg.Lexer as Lex
import Ministg.AST hiding (rightArrow)
import Control.Applicative hiding ((<|>), many)

type Parser a = GenParser Lex.Token () a

tokenParser :: (Lex.Symbol -> Maybe a) -> Parser a
tokenParser test
   = token showToken posToken testToken
   where
   showToken (Lex.Token (pos,tok)) = show tok
   posToken  (Lex.Token (pos,tok)) = pos
   testToken (Lex.Token (pos,tok)) = test tok

symbol :: Lex.Symbol -> Parser ()
symbol tok
   = tokenParser $ 
        \next -> if next == tok then Just () else Nothing

parser :: FilePath -> String -> Either ParseError Program 
parser source input
   = case Lex.lexer source input of
        Left err -> Left err
        Right toks -> parse program source toks 

program :: Parser Program
program = Program <$> sepEndBy decl semiColon <* eof

decl :: Parser Decl
decl = Decl <$> var <*> (equals *> object)

exp :: Parser Exp
exp = funCallOrVar <|> 
      expAtomLiteral <|> 
      primApp <|> 
      letExp <|> 
      caseExp <|>
      stack

stack :: Parser Exp
stack = Stack <$> (symbol Lex.Stack *> quotedString) <*> exp

quotedString :: Parser String 
quotedString = tokenParser getString
   where
   getString (Lex.QuotedString s) = Just s
   getString other = Nothing 

funCallOrVar :: Parser Exp
funCallOrVar = do
   v <- var
   args <- many atom
   return $ if null args
      then Atom $ Variable v
      -- we don't know the arity of the function yet.
      else FunApp Nothing v args 

expAtomLiteral :: Parser Exp
expAtomLiteral = Atom <$> atomLiteral 

expAtom :: Parser Exp
expAtom = Atom <$> atom

primApp :: Parser Exp
primApp = PrimApp <$> primOp <*> many1 atom 

primOp, add, subtract, multiply, eq, lessThan, greaterThan, lessThanEquals, greaterThanEquals :: Parser Prim

primOp = 
   add <|> 
   subtract <|> 
   multiply <|> 
   eq <|> 
   lessThan <|> 
   greaterThan <|> 
   lessThanEquals <|> 
   greaterThanEquals <|> 
   intToBool

add = const Add <$> symbol Lex.Plus
subtract = const Subtract <$> symbol Lex.Minus
multiply = const Multiply <$> symbol Lex.Times
eq = const Equality <$> symbol Lex.Equality
lessThan = const LessThan <$> symbol Lex.LessThan
lessThanEquals = const LessThanEquals <$> symbol Lex.LessThanEquals
greaterThan = const GreaterThan <$> symbol Lex.GreaterThan
greaterThanEquals = const GreaterThanEquals <$> symbol Lex.GreaterThanEquals
intToBool = const IntToBool <$> symbol Lex.IntToBool

letExp :: Parser Exp
letExp = flattenLet <$> (symbol Lex.Let *> leftBrace *> sepEndBy1 decl semiColon <* rightBrace) <*> (symbol Lex.In *> exp)

flattenLet :: [Decl] -> Exp -> Exp
flattenLet [Decl var obj] body = Let var obj body
flattenLet (Decl var obj : decls) body = Let var obj $ flattenLet decls body 

caseExp :: Parser Exp
caseExp = Case <$> (symbol Lex.Case *> exp) <*> (symbol Lex.Of *> leftBrace *> sepEndBy1 alt semiColon <* rightBrace)

atom, atomLiteral, atomVariable :: Parser Atom
atom = atomLiteral <|> atomVariable
atomLiteral = Literal <$> literal
atomVariable = Variable <$> var

literal :: Parser Literal
literal = Integer <$> natural 

alt :: Parser Alt
alt = patAlt <|> defaultAlt

patAlt :: Parser Alt
patAlt = PatAlt <$> constructor <*> many var <*> (rightArrow *> exp)

defaultAlt :: Parser Alt
defaultAlt = DefaultAlt <$> var <*> (rightArrow *> exp)

object :: Parser Object
object = fun <|> pap <|> con <|> thunk <|> errorObj

fun, pap, con, thunk, errorObj  :: Parser Object
fun = Fun <$> (symbol Lex.Fun *> leftParen *> many1 var) <*> (rightArrow *> exp <* rightParen)
pap = Pap <$> (symbol Lex.Pap *> leftParen *> var) <*> (many1 atom <* rightParen)
con = Con <$> (symbol Lex.Con *> leftParen *> constructor) <*> (many atom <* rightParen)
thunk = Thunk <$> (symbol Lex.Thunk *> leftParen *> exp <* rightParen) <*> pure []
errorObj = const Error <$> symbol Lex.Error

var :: Parser Var 
var = tokenParser getIdent
   where
   getIdent (Lex.Variable s) = Just s
   getIdent other = Nothing 

constructor :: Parser Constructor 
constructor = tokenParser getIdent
   where
   getIdent (Lex.Constructor s) = Just s
   getIdent other = Nothing 

equals :: Parser ()
equals = symbol Lex.Equals 

semiColon :: Parser ()
semiColon = symbol Lex.SemiColon 

rightArrow :: Parser ()
rightArrow = symbol Lex.RightArrow

leftParen, rightParen :: Parser ()
leftParen = symbol Lex.LeftParen
rightParen = symbol Lex.RightParen

leftBrace, rightBrace :: Parser ()
leftBrace = symbol Lex.LeftBrace
rightBrace = symbol Lex.RightBrace

natural :: Parser Integer 
natural = 
   tokenParser getNat
   where
   getNat :: Lex.Symbol -> Maybe Integer 
   getNat (Lex.Natural n) = Just n 
   getNat other = Nothing