never executed always true always false
1 module ElmFormat.AST.BinaryOperatorPrecedence (parseElm0_19, parsePrecedence, Tree(..), Precedence(..), Associativity(..)) where
2
3 import ElmFormat.AST.Shared
4 import Data.Map.Strict (Map)
5 import qualified Data.Map.Strict as Map
6 import Data.Maybe (fromMaybe)
7 import Data.Text (Text)
8
9
10 data Tree op e
11 = Leaf e
12 | Branch op (Tree op e) (Tree op e)
13 deriving (Eq, Show, Functor)
14
15 data Precedence
16 = Precedence
17 { precedence :: Int
18 , associativity :: Associativity
19 }
20
21 data Associativity
22 = LeftAssociate
23 | RightAssociate
24 | NonAssociate
25 deriving (Eq)
26
27
28 elm0_19 :: Ord ns => Map (Ref ns) Precedence
29 elm0_19 =
30 Map.fromList $ fmap (\(op, p, a) -> (OpRef $ SymbolIdentifier op, Precedence p a))
31 -- From https://github.com/elm/core/blob/1.0.5/src/Basics.elm#L68-L89
32 [ ( "<|", 0, RightAssociate )
33 , ( "|>", 0, LeftAssociate )
34 , ( "||", 2, RightAssociate )
35 , ( "&&", 3, RightAssociate )
36 , ( "==", 4, NonAssociate )
37 , ( "/=", 4, NonAssociate )
38 , ( "<", 4, NonAssociate )
39 , ( ">", 4, NonAssociate )
40 , ( "<=", 4, NonAssociate )
41 , ( ">=", 4, NonAssociate )
42 , ( "++", 5, RightAssociate )
43 , ( "+", 6, LeftAssociate )
44 , ( "-", 6, LeftAssociate )
45 , ( "*", 7, LeftAssociate )
46 , ( "/", 7, LeftAssociate )
47 , ( "//", 7, LeftAssociate )
48 , ( "^", 8, RightAssociate )
49 , ( "<<", 9, LeftAssociate )
50 , ( ">>", 9, RightAssociate )
51
52 -- From https://github.com/elm/core/blob/1.0.5/src/List.elm#L41
53 , ( "::", 5, RightAssociate )
54
55 -- From https://github.com/elm/url/blob/1.0.0/src/Url/Parser.elm#L46-L50
56 , ( "</>", 7, RightAssociate )
57 , ( "<?>", 8, LeftAssociate )
58
59 -- From https://github.com/elm/parser/blob/1.1.0/src/Parser.elm#L55-L59
60 , ( "|=", 5, LeftAssociate )
61 , ( "|.", 6, LeftAssociate )
62 ]
63
64 parseElm0_19 :: (Ord ns, Show ns) => e -> List (Ref ns, e) -> Either Text (Tree (Ref ns) e)
65 parseElm0_19 = parsePrecedence elm0_19
66
67
68 parsePrecedence :: (Ord op, Show op) => Map op Precedence -> e -> List (op, e) -> Either Text (Tree op e)
69 parsePrecedence precedenceMap first = parsePrecedence' precedenceMap (Leaf first) []
70
71 -- https://en.wikipedia.org/wiki/Shunting-yard_algorithm
72 parsePrecedence' :: (Ord op, Show op) => Map op Precedence -> Tree op e -> List (Tree op e, op) -> List (op, e) -> Either Text (Tree op e)
73 parsePrecedence' precedenceMap b ((a, op) : rest) [] =
74 parsePrecedence' precedenceMap (Branch op a b) rest []
75 parsePrecedence' _ last [] [] = Right last
76 parsePrecedence' precedenceMap prev stack ((op, next) : rest) =
77 let
78 prec o = fromMaybe (error ("operator is not defined: " <> show o)) $ Map.lookup o precedenceMap
79 in
80 case stack of
81 (a, opPrev) : restStack
82 | precedence (prec opPrev) > precedence (prec op)
83 || (precedence (prec opPrev) == precedence (prec op)
84 && associativity (prec op) == LeftAssociate
85 && associativity (prec opPrev) == LeftAssociate)
86 ->
87 parsePrecedence' precedenceMap
88 (Branch opPrev a prev)
89 restStack
90 ((op, next) : rest)
91
92 (_, opPrev) : _
93 | precedence (prec opPrev) == precedence (prec op)
94 && (associativity (prec op) == NonAssociate
95 || associativity (prec opPrev) /= associativity (prec op))
96 ->
97 Left "conflicting associativity"
98
99 _ ->
100 parsePrecedence' precedenceMap
101 (Leaf next)
102 ((prev, op) : stack)
103 rest