on master help sign in
Minor code changes to help allow custom infix precedence and associativity.
commitf5bdb2ca7e3f269d366876558078b3f29dfbfb78 authorevancz <info@elm-lang.org> dateWed 5 Jun 2013, 14:22 (13 years ago) parent2d1e06b
4 files changed+81−61
compiler/Initialize.hs+2−2 compiler/Parse/Binops.hs+66−53 compiler/Parse/Expr.hs+1−1 compiler/Parse/Parser.hs+12−5
compiler/Initialize.hs+2−2
@@ -8,7 +8,7 @@ import qualified Data.Map as Map
88import Ast
99import Data.Either (lefts,rights)
1010import Data.List (intercalate,partition)
11−import Parse.Parser (parseProgram, preParse)
11+import Parse.Parser (parseProgram, parseDependencies)
1212import Rename
1313import qualified Libraries as Libs
1414import Types.Types ((-:))
@@ -60,7 +60,7 @@ sortDeps deps = go [] (nub deps)
6060readDeps :: [FilePath] -> FilePath -> IO [Deps]
6161readDeps seen root = do
6262 txt <- readFile root
63− case preParse txt of
63+ case parseDependencies txt of
6464 Left err ->
6565 let msg = "Error resolving dependencies in " ++ root ++ ":\n" in
6666 putStrLn (msg ++ err) >> exitFailure
compiler/Parse/Binops.hs+66−53
@@ -1,4 +1,4 @@
1−module Parse.Binops (binops) where
1+module Parse.Binops (binops, infixStmt, OpTable) where
22
33import Ast
44import Control.Monad (liftM,guard)
@@ -16,54 +16,57 @@ data Assoc = L | N | R deriving (Eq,Show)
1616
1717type OpTable = [(Int, Assoc, String)]
1818
19−table :: OpTable
20−table = [ (9, R, ".")
21− , (8, R, "^")
22− , (7, L, "*"), (7, L, "/"), (7, L, "mod"), (7, L, "div"), (7, L, "rem")
23− , (6, L, "+"), (6, L, "-")
24− , (5, R, "::"), (5, R, "++")
25− , (4, N, "<="), (4, N, ">="), (4, N, "<")
26− , (4, N, "=="), (4, N, "/="), (4, N, ">")
27− , (4, L, "~"), (4, L, "<~")
28− , (3, R, "&&")
29− , (2, R, "||")
30− , (0, R, "$")
31− , (0, R, "<|"), (0, L, "|>")
32− ]
33−
34−opLevel op = Map.findWithDefault 9 op dict
19+preludeTable :: OpTable
20+preludeTable =
21+ [ (9, R, ".")
22+ , (8, R, "^")
23+ , (7, L, "*"), (7, L, "/"), (7, L, "mod"), (7, L, "div"), (7, L, "rem")
24+ , (6, L, "+"), (6, L, "-")
25+ , (5, R, "::"), (5, R, "++")
26+ , (4, N, "<="), (4, N, ">="), (4, N, "<")
27+ , (4, N, "=="), (4, N, "/="), (4, N, ">")
28+ , (4, L, "~"), (4, L, "<~")
29+ , (3, R, "&&")
30+ , (2, R, "||")
31+ , (0, R, "<|"), (0, L, "|>")
32+ ]
33+
34+opLevel :: OpTable -> String -> Int
35+opLevel table op = Map.findWithDefault 9 op dict
3536 where dict = Map.fromList (map (\(lvl,_,op) -> (op,lvl)) table)
3637
37−opAssoc op = Map.findWithDefault R op dict
38+opAssoc :: OpTable -> String -> Assoc
39+opAssoc table op = Map.findWithDefault R op dict
3840 where dict = Map.fromList (map (\(_,assoc,op) -> (op,assoc)) table)
3941
40−hasLevel n (op,e) = opLevel op == n
41−
42−sortOps :: OpTable -> OpTable
43−sortOps = sortBy (\(i,_,_) (j,_,_) -> compare i j)
44−
45−binops :: IParser CExpr -> IParser String -> IParser CExpr
46−binops term anyOp = do
47− e <- term
48− split 0 e =<< many (commitIf (whitespace >> anyOp) $ do
49− whitespace ; op <- anyOp
50− whitespace ; e <- term
51− return (op,e))
52−
53−split :: Int -> CExpr -> [(String, CExpr)] -> IParser CExpr
54−split _ e [] = return e
55−split n e eops = do
56− assoc <- getAssoc n eops
57− es <- sequence (splitLevel n e eops)
58− let ops = map fst (filter (hasLevel n) eops)
42+hasLevel :: OpTable -> Int -> (String,CExpr) -> Bool
43+hasLevel table n (op,_) = opLevel table op == n
44+
45+binops :: OpTable -> IParser CExpr -> IParser String -> IParser CExpr
46+binops table term anyOp =
47+ do e <- term
48+ split (table ++ preludeTable) 0 e =<< many nextOp
49+ where
50+ nextOp = commitIf (whitespace >> anyOp) $ do
51+ whitespace ; op <- anyOp
52+ whitespace ; e <- term
53+ return (op,e)
54+
55+split :: OpTable -> Int -> CExpr -> [(String, CExpr)] -> IParser CExpr
56+split _ _ e [] = return e
57+split table n e eops = do
58+ assoc <- getAssoc table n eops
59+ es <- sequence (splitLevel table n e eops)
60+ let ops = map fst (filter (hasLevel table n) eops)
5961 case assoc of R -> joinR es ops
6062 _ -> joinL es ops
6163
62−splitLevel :: Int -> CExpr -> [(String, CExpr)] -> [IParser CExpr]
63−splitLevel n e eops =
64− case break (hasLevel n) eops of
65− (lops, (op,e'):rops) -> split (n+1) e lops : splitLevel n e' rops
66− (lops, []) -> [ split (n+1) e lops ]
64+splitLevel :: OpTable -> Int -> CExpr -> [(String, CExpr)] -> [IParser CExpr]
65+splitLevel table n e eops =
66+ case break (hasLevel table n) eops of
67+ (lops, (op,e'):rops) ->
68+ split table (n+1) e lops : splitLevel table n e' rops
69+ (lops, []) -> [ split table (n+1) e lops ]
6770
6871joinL :: [CExpr] -> [String] -> IParser CExpr
6972joinL [e] [] = return e
@@ -76,14 +79,24 @@ joinR (a:b:es) (op:ops) = do e <- joinR (b:es) ops
7679 return (epos a e (Binop op a e))
7780joinR _ _ = fail "Ill-formed binary expression. Report a compiler bug."
7881
79−getAssoc :: Int -> [(String,CExpr)] -> IParser Assoc
80−getAssoc n eops | all (==L) assocs = return L
81− | all (==R) assocs = return R
82− | all (==N) assocs = case assocs of [_] -> return N
83− _ -> fail msg
84− where levelOps = filter (hasLevel n) eops
85− assocs = map (opAssoc . fst) levelOps
86− msg = concat [ "Conflicting precedence for binary operators ("
87− , intercalate ", " (map fst eops), "). "
88− , "Consider adding parentheses to disambiguate." ]
89−
82+getAssoc :: OpTable -> Int -> [(String,CExpr)] -> IParser Assoc
83+getAssoc table n eops
84+ | all (==L) assocs = return L
85+ | all (==R) assocs = return R
86+ | all (==N) assocs = case assocs of [_] -> return N
87+ _ -> fail msg
88+ where levelOps = filter (hasLevel table n) eops
89+ assocs = map (opAssoc table . fst) levelOps
90+ msg = concat [ "Conflicting precedence for binary operators ("
91+ , intercalate ", " (map fst eops), "). "
92+ , "Consider adding parentheses to disambiguate." ]
93+
94+infixStmt :: IParser (Int, Assoc, String)
95+infixStmt =
96+ let infx str assoc = try (reserved ("infix" ++ str) >> return assoc) in
97+ do assoc <- choice [ infx "l" L, infx "r" R, infx "" N ]
98+ whitespace
99+ prec <- do n <- digit ; return (read [n] :: Int)
100+ whitespace
101+ op <- anyOp
102+ return (prec, assoc, op)
compiler/Parse/Expr.hs+1−1
@@ -141,7 +141,7 @@ appExpr = do
141141-------- Normal Expressions --------
142142
143143binaryExpr :: IParser CExpr
144−binaryExpr = binops appExpr anyOp
144+binaryExpr = binops [] appExpr anyOp
145145
146146ifExpr :: IParser Expr
147147ifExpr = reserved "if" >> whitespace >> (normal <|> multiIf)
compiler/Parse/Parser.hs+12−5
@@ -1,4 +1,4 @@
1−module Parse.Parser (parseProgram, preParse) where
1+module Parse.Parser (parseProgram, parseDependencies, parseInfix) where
22
33import Ast
44import Control.Applicative ((<$>), (<*>))
@@ -8,6 +8,7 @@ import Data.List (foldl',intercalate)
88import Text.Parsec hiding (newline,spaces)
99
1010import Parse.Library
11+import Parse.Binops (infixStmt, OpTable)
1112import Parse.Expr
1213import Parse.Types
1314import Parse.Modules
@@ -35,10 +36,11 @@ program = do
3536
3637parseProgram = setupParser program
3738
38−preParse :: String -> Either String (String, [String])
39−preParse = setupParser $ do
40− optional skip
41− (,) <$> option "Main" moduleName <*> option [] imprts
39+parseDependencies :: String -> Either String (String, [String])
40+parseDependencies =
41+ setupParser $ do
42+ optional skip
43+ (,) <$> option "Main" moduleName <*> option [] imprts
4244 where
4345 skip = try (manyTill anyChar (try (string "/**")))
4446 imprts = fmap (map fst) imports `followedBy` freshLine
@@ -46,6 +48,11 @@ preParse = setupParser $ do
4648 moduleName = do optional freshLine
4749 getName <$> moduleDef `followedBy` freshLine
4850
51+parseInfix :: String -> Either String OpTable
52+parseInfix = setupParser . many $ do
53+ manyTill (whitespace <|> (anyChar >> return ())) freshLine
54+ infixStmt
55+
4956setupParser p source =
5057 case iParse p "" source of
5158 Right result -> Right result