diff --git a/haskell-experiments/haskell-experiments.cabal b/haskell-experiments/haskell-experiments.cabal index 48a3e43..0d244db 100644 --- a/haskell-experiments/haskell-experiments.cabal +++ b/haskell-experiments/haskell-experiments.cabal @@ -82,7 +82,7 @@ test-suite haskell-exps-test Test.SimpleParserSpec library langfeatures - build-depends: base, containers, megaparsec + build-depends: base, containers, megaparsec, parser-combinators hs-source-dirs: src exposed-modules: Ologs, SimpleParser ghc-options: -Wall diff --git a/haskell-experiments/src/SimpleParser.hs b/haskell-experiments/src/SimpleParser.hs index be76cfd..adf46b8 100644 --- a/haskell-experiments/src/SimpleParser.hs +++ b/haskell-experiments/src/SimpleParser.hs @@ -15,13 +15,16 @@ {-# LANGUAGE NoMonomorphismRestriction #-} {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} -module SimpleParser - ( eval, Expr (..), BinaryOp (..), UnaryOp (..), parseExpr ) -- literalParser +module SimpleParser (eval, Expr (..), BinaryOp (..), UnaryOp (..), parseExpr) -- literalParser where -import Text.Megaparsec + +import Control.Monad.Combinators.Expr +import Data.Functor (($>)) import Data.Void (Void) +import Text.Megaparsec +import Text.Megaparsec.Byte.Lexer (lexeme) +import Text.Megaparsec.Char (char, space) import Text.Megaparsec.Char.Lexer (decimal) -import Text.Megaparsec.Char (char) type Parser = Parsec Void String @@ -29,11 +32,11 @@ data BinaryOp = Add | Subtract | Multiply | Divide deriving (Show, Eq) data UnaryOp = Negate deriving (Show, Eq) -data Expr = - BinaryExpr BinaryOp Expr Expr | - UnaryExpr UnaryOp Expr | - Literal Int - deriving (Show, Eq) +data Expr + = BinaryExpr BinaryOp Expr Expr + | UnaryExpr UnaryOp Expr + | Literal Int + deriving (Show, Eq) lookUpBinaryOp :: BinaryOp -> Int -> Int -> Int lookUpBinaryOp Add = (+) @@ -47,31 +50,21 @@ lookUpUnaryOp Negate x = -x eval :: Expr -> Int eval (Literal n) = n eval (BinaryExpr binOp a b) = lookUpBinaryOp binOp (eval a) (eval b) -eval (UnaryExpr unaryOp a) = lookUpUnaryOp unaryOp (eval a) +eval (UnaryExpr unaryOp a) = lookUpUnaryOp unaryOp (eval a) parseExpr :: Parser Expr -parseExpr = choice [ - try parseBinaryExpr, - parseLiteral - -- bracketedExpParser, - -- negatedExp - ] - +parseExpr = + makeExprParser + parseLiteral + [ [InfixL (char '/' $> BinaryExpr Divide)] + , [InfixL (char '*' $> BinaryExpr Multiply)] + , [InfixL (char '+' $> BinaryExpr Add)] + , [InfixL (char '-' $> BinaryExpr Subtract)] + ] + parseLiteral :: Parser Expr -parseLiteral = Literal <$> decimal - -parseBinaryExpr :: Parser Expr -parseBinaryExpr = do - lhs <- parseExpr - binOp <- parseOp - rhs <- parseExpr - pure (BinaryExpr binOp lhs rhs) - -parseOp :: Parser BinaryOp -parseOp = choice [ - char '+' >> pure Add, - char '-' >> pure Subtract, - char '/' >> pure Divide, - char '*' >> pure Multiply - ] - +parseLiteral = + choice + [ Literal <$> decimal + , between (char '(') (char ')') parseExpr + ] diff --git a/haskell-experiments/test/Test/SimpleParserSpec.hs b/haskell-experiments/test/Test/SimpleParserSpec.hs index a6622ca..8c8853c 100644 --- a/haskell-experiments/test/Test/SimpleParserSpec.hs +++ b/haskell-experiments/test/Test/SimpleParserSpec.hs @@ -36,5 +36,8 @@ spec = do checkParse "2" (Literal 2) checkParse "2+3" (BinaryExpr Add (Literal 2) (Literal 3)) checkParse "2+3+5" (BinaryExpr Add (BinaryExpr Add (Literal 2) (Literal 3)) (Literal 5)) + checkParse "2+3*5" (BinaryExpr Add (Literal 2) (BinaryExpr Multiply (Literal 3) (Literal 5))) + checkParse "(2+3)*5" (BinaryExpr Multiply (BinaryExpr Add (Literal 2) (Literal 3)) (Literal 5) ) + checkParse "((2+3))*5" (BinaryExpr Multiply (BinaryExpr Add (Literal 2) (Literal 3)) (Literal 5) )