|
| 1 | +module Main where |
| 2 | + |
| 3 | +import qualified Text.Parsec.Expr as Ex |
| 4 | +import qualified Text.Parsec.Token as Tok |
| 5 | + |
| 6 | +import Text.Parsec.Language (haskellStyle) |
| 7 | + |
| 8 | +import Data.List |
| 9 | +import Data.Function |
| 10 | + |
| 11 | +import Control.Monad.Identity (Identity) |
| 12 | + |
| 13 | +import Text.Parsec |
| 14 | +import qualified Text.Parsec as P |
| 15 | + |
| 16 | +type Name = String |
| 17 | + |
| 18 | +data Expr |
| 19 | + = Var Name |
| 20 | + | Lam Name Expr |
| 21 | + | App Expr Expr |
| 22 | + | Let Name Expr Expr |
| 23 | + | BinOp Name Expr Expr |
| 24 | + | UnOp Name Expr |
| 25 | + deriving (Show) |
| 26 | + |
| 27 | +data Assoc |
| 28 | + = OpLeft |
| 29 | + | OpRight |
| 30 | + | OpNone |
| 31 | + | OpPrefix |
| 32 | + | OpPostfix |
| 33 | + deriving Show |
| 34 | + |
| 35 | +data Decl |
| 36 | + = LetDecl Expr |
| 37 | + | OpDecl OperatorDef |
| 38 | + deriving (Show) |
| 39 | + |
| 40 | +type Op x = Ex.Operator String ParseState Identity x |
| 41 | +type Parser a = Parsec String ParseState a |
| 42 | +data ParseState = ParseState [OperatorDef] deriving Show |
| 43 | + |
| 44 | +data OperatorDef = OperatorDef { |
| 45 | + oassoc :: Assoc |
| 46 | + , oprec :: Integer |
| 47 | + , otok :: Name |
| 48 | + } deriving Show |
| 49 | + |
| 50 | +lexer :: Tok.GenTokenParser String u Identity |
| 51 | +lexer = Tok.makeTokenParser style |
| 52 | + where ops = ["->","\\","+","*","<","=","[","]","_"] |
| 53 | + names = ["let","in","infixl", "infixr", "infix", "postfix", "prefix"] |
| 54 | + style = haskellStyle { Tok.reservedOpNames = ops |
| 55 | + , Tok.reservedNames = names |
| 56 | + , Tok.identLetter = alphaNum <|> oneOf "#'_" |
| 57 | + , Tok.commentLine = "--" |
| 58 | + } |
| 59 | + |
| 60 | +reserved = Tok.reserved lexer |
| 61 | +reservedOp = Tok.reservedOp lexer |
| 62 | +identifier = Tok.identifier lexer |
| 63 | +parens = Tok.parens lexer |
| 64 | +brackets = Tok.brackets lexer |
| 65 | +braces = Tok.braces lexer |
| 66 | +commaSep = Tok.commaSep lexer |
| 67 | +semi = Tok.semi lexer |
| 68 | +integer = Tok.integer lexer |
| 69 | +chr = Tok.charLiteral lexer |
| 70 | +str = Tok.stringLiteral lexer |
| 71 | +operator = Tok.operator lexer |
| 72 | + |
| 73 | +contents :: Parser a -> Parser a |
| 74 | +contents p = do |
| 75 | + Tok.whiteSpace lexer |
| 76 | + r <- p |
| 77 | + eof |
| 78 | + return r |
| 79 | + |
| 80 | +expr :: Parser Expr |
| 81 | +expr = do |
| 82 | + es <- many1 term |
| 83 | + return (foldl1 App es) |
| 84 | + |
| 85 | +lambda :: Parser Expr |
| 86 | +lambda = do |
| 87 | + reservedOp "\\" |
| 88 | + args <- identifier |
| 89 | + reservedOp "->" |
| 90 | + body <- expr |
| 91 | + return $ Lam args body |
| 92 | + |
| 93 | +letin :: Parser Expr |
| 94 | +letin = do |
| 95 | + reserved "let" |
| 96 | + x <- identifier |
| 97 | + reservedOp "=" |
| 98 | + e1 <- expr |
| 99 | + reserved "in" |
| 100 | + e2 <- expr |
| 101 | + return (Let x e1 e2) |
| 102 | + |
| 103 | +variable :: Parser Expr |
| 104 | +variable = do |
| 105 | + x <- identifier |
| 106 | + return (Var x) |
| 107 | + |
| 108 | + |
| 109 | +addOperator :: OperatorDef -> Parser () |
| 110 | +addOperator a = P.modifyState $ \(ParseState ops) -> ParseState (a : ops) |
| 111 | + |
| 112 | +mkTable :: ParseState -> [[Op Expr]] |
| 113 | +mkTable (ParseState ops) = |
| 114 | + map (map toParser) $ |
| 115 | + groupBy ((==) `on` oprec) $ |
| 116 | + reverse $ sortBy (compare `on` oprec) $ ops |
| 117 | + |
| 118 | +toParser :: OperatorDef -> Op Expr |
| 119 | +toParser (OperatorDef ass _ tok) = case ass of |
| 120 | + OpLeft -> infixOp tok (BinOp tok) (toAssoc ass) |
| 121 | + OpRight -> infixOp tok (BinOp tok) (toAssoc ass) |
| 122 | + OpNone -> infixOp tok (BinOp tok) (toAssoc ass) |
| 123 | + OpPrefix -> prefixOp tok (UnOp tok) |
| 124 | + OpPostfix -> postfixOp tok (UnOp tok) |
| 125 | + where |
| 126 | + toAssoc OpLeft = Ex.AssocLeft |
| 127 | + toAssoc OpRight = Ex.AssocRight |
| 128 | + toAssoc OpNone = Ex.AssocNone |
| 129 | + toAssoc _ = error "no associativity" |
| 130 | + |
| 131 | +infixOp :: String -> (a -> a -> a) -> Ex.Assoc -> Op a |
| 132 | +infixOp x f = Ex.Infix (reservedOp x >> return f) |
| 133 | + |
| 134 | +prefixOp :: String -> (a -> a) -> Ex.Operator String u Identity a |
| 135 | +prefixOp name f = Ex.Prefix (reservedOp name >> return f) |
| 136 | + |
| 137 | +postfixOp :: String -> (a -> a) -> Ex.Operator String u Identity a |
| 138 | +postfixOp name f = Ex.Postfix (reservedOp name >> return f) |
| 139 | + |
| 140 | +term :: Parser Expr |
| 141 | +term = do |
| 142 | + tbl <- getState |
| 143 | + let table = mkTable tbl |
| 144 | + Ex.buildExpressionParser table aexp |
| 145 | + |
| 146 | +aexp :: Parser Expr |
| 147 | +aexp = letin |
| 148 | + <|> lambda |
| 149 | + <|> variable |
| 150 | + <|> parens expr |
| 151 | + |
| 152 | +letdecl :: Parser Decl |
| 153 | +letdecl = do |
| 154 | + e <- expr |
| 155 | + return $ LetDecl e |
| 156 | + |
| 157 | + |
| 158 | +opleft :: Parser Decl |
| 159 | +opleft = do |
| 160 | + reserved "infixl" |
| 161 | + prec <- integer |
| 162 | + sym <- parens operator |
| 163 | + let op = (OperatorDef OpLeft prec sym) |
| 164 | + addOperator op |
| 165 | + return $ OpDecl op |
| 166 | + |
| 167 | +opright :: Parser Decl |
| 168 | +opright = do |
| 169 | + reserved "infixr" |
| 170 | + prec <- integer |
| 171 | + sym <- parens operator |
| 172 | + let op = (OperatorDef OpRight prec sym) |
| 173 | + addOperator op |
| 174 | + return $ OpDecl op |
| 175 | + |
| 176 | +opnone :: Parser Decl |
| 177 | +opnone = do |
| 178 | + reserved "infix" |
| 179 | + prec <- integer |
| 180 | + sym <- parens operator |
| 181 | + let op = (OperatorDef OpNone prec sym) |
| 182 | + addOperator op |
| 183 | + return $ OpDecl op |
| 184 | + |
| 185 | +opprefix :: Parser Decl |
| 186 | +opprefix = do |
| 187 | + reserved "prefix" |
| 188 | + prec <- integer |
| 189 | + sym <- parens operator |
| 190 | + let op = OperatorDef OpPrefix prec sym |
| 191 | + addOperator op |
| 192 | + return $ OpDecl op |
| 193 | + |
| 194 | +oppostfix :: Parser Decl |
| 195 | +oppostfix = do |
| 196 | + reserved "postfix" |
| 197 | + prec <- integer |
| 198 | + sym <- parens operator |
| 199 | + let op = OperatorDef OpPostfix prec sym |
| 200 | + addOperator op |
| 201 | + return $ OpDecl op |
| 202 | + |
| 203 | +decl :: Parser Decl |
| 204 | +decl = |
| 205 | + try letdecl |
| 206 | + <|> opleft |
| 207 | + <|> opright |
| 208 | + <|> opnone |
| 209 | + <|> opprefix |
| 210 | + <|> oppostfix |
| 211 | + |
| 212 | +top :: Parser Decl |
| 213 | +top = do |
| 214 | + x <- decl |
| 215 | + P.optional semi |
| 216 | + return x |
| 217 | + |
| 218 | + |
| 219 | +modl :: Parser [Decl] |
| 220 | +modl = many top |
| 221 | + |
| 222 | +parseModule :: SourceName -> String -> Either ParseError [Decl] |
| 223 | +parseModule filePath = P.runParser (contents modl) (ParseState []) filePath |
| 224 | + |
| 225 | +main :: IO () |
| 226 | +main = do |
| 227 | + input <- readFile "test.in" |
| 228 | + let res = parseModule "<stdin>" input |
| 229 | + case res of |
| 230 | + Left err -> print err |
| 231 | + Right ast -> mapM_ print ast |
0 commit comments