mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-12-01 15:53:00 +03:00
880 lines
37 KiB
Elm
880 lines
37 KiB
Elm
module Simplify.NormalizeTest exposing (all)
|
|
|
|
import Dict
|
|
import Elm.Dependency
|
|
import Elm.Interface as Interface
|
|
import Elm.Parser as Parser
|
|
import Elm.Processing
|
|
import Elm.Syntax.Declaration as Declaration exposing (Declaration)
|
|
import Elm.Syntax.Expression exposing (Expression(..), LetDeclaration(..))
|
|
import Elm.Syntax.File exposing (File)
|
|
import Elm.Syntax.Infix as Infix exposing (InfixDirection(..))
|
|
import Elm.Syntax.ModuleName exposing (ModuleName)
|
|
import Elm.Syntax.Node as Node exposing (Node(..))
|
|
import Elm.Syntax.Pattern exposing (Pattern(..))
|
|
import Elm.Syntax.Range as Range exposing (Range)
|
|
import Expect
|
|
import Review.ModuleNameLookupTable as ModuleNameLookupTable
|
|
import Simplify.Infer as Infer
|
|
import Simplify.Normalize as Normalize
|
|
import Test exposing (Test, describe, test)
|
|
|
|
|
|
all : Test
|
|
all =
|
|
describe "Normalize"
|
|
[ simpleNormalizationTests
|
|
, moduleNameTests
|
|
, inferTests
|
|
]
|
|
|
|
|
|
simpleNormalizationTests : Test
|
|
simpleNormalizationTests =
|
|
describe "Simple normalizations"
|
|
[ test "should remove parentheses" <|
|
|
\() ->
|
|
"(1)"
|
|
|> normalizeAndExpect (Integer 1)
|
|
, test "should remove ranges of 'f a'" <|
|
|
\() ->
|
|
"f a"
|
|
|> normalizeAndExpect
|
|
(Application
|
|
[ n (FunctionOrValue [] "f")
|
|
, n (FunctionOrValue [] "a")
|
|
]
|
|
)
|
|
, test "should turn '.field a' into 'a.field'" <|
|
|
\() ->
|
|
".field a"
|
|
|> normalizeAndExpect
|
|
(RecordAccess
|
|
(n (FunctionOrValue [] "a"))
|
|
(n "field")
|
|
)
|
|
, test "should turn '.field <| a' into 'a.field'" <|
|
|
\() ->
|
|
"(.field) <| (a)"
|
|
|> normalizeAndExpect
|
|
(RecordAccess
|
|
(n (FunctionOrValue [] "a"))
|
|
(n "field")
|
|
)
|
|
, test "should turn '(a).field' into 'a.field'" <|
|
|
\() ->
|
|
"(a).field"
|
|
|> normalizeAndExpect
|
|
(RecordAccess
|
|
(n (FunctionOrValue [] "a"))
|
|
(n "field")
|
|
)
|
|
, test "should turn '.field a b' into 'a.field b'" <|
|
|
\() ->
|
|
".field a b"
|
|
|> normalizeAndExpect
|
|
(Application
|
|
[ n
|
|
(RecordAccess
|
|
(n (FunctionOrValue [] "a"))
|
|
(n "field")
|
|
)
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
, test "should normalize a function and function arguments" <|
|
|
\() ->
|
|
"(a) (b) (c)"
|
|
|> normalizeAndExpect
|
|
(Application
|
|
[ n (FunctionOrValue [] "a")
|
|
, n (FunctionOrValue [] "b")
|
|
, n (FunctionOrValue [] "c")
|
|
]
|
|
)
|
|
, test "should remove <|" <|
|
|
\() ->
|
|
"a b <| c"
|
|
|> normalizeAndExpect
|
|
(Application
|
|
[ n (FunctionOrValue [] "a")
|
|
, n (FunctionOrValue [] "b")
|
|
, n (FunctionOrValue [] "c")
|
|
]
|
|
)
|
|
, test "should remove |>" <|
|
|
\() ->
|
|
"c |> a b"
|
|
|> normalizeAndExpect
|
|
(Application
|
|
[ n (FunctionOrValue [] "a")
|
|
, n (FunctionOrValue [] "b")
|
|
, n (FunctionOrValue [] "c")
|
|
]
|
|
)
|
|
, test "should remove <| when the left is not already an application " <|
|
|
\() ->
|
|
"(a) <| (b)"
|
|
|> normalizeAndExpect
|
|
(Application
|
|
[ n (FunctionOrValue [] "a")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
, test "should remove <| when the left is a let expression" <|
|
|
\() ->
|
|
"(let a = (fn) in a) <| (b)"
|
|
|> normalizeAndExpect
|
|
(LetExpression
|
|
{ declarations =
|
|
[ n
|
|
(LetFunction
|
|
{ declaration =
|
|
n
|
|
{ arguments = []
|
|
, expression = n (FunctionOrValue [] "fn")
|
|
, name = n "a"
|
|
}
|
|
, documentation = Nothing
|
|
, signature = Nothing
|
|
}
|
|
)
|
|
]
|
|
, expression =
|
|
n
|
|
(Application
|
|
[ n (FunctionOrValue [] "a")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
}
|
|
)
|
|
, test "should remove <| when the left is an if expression" <|
|
|
\() ->
|
|
"(if (cond) then (fn1) else (fn2)) <| (b)"
|
|
|> normalizeAndExpect
|
|
(IfBlock (n (FunctionOrValue [] "cond"))
|
|
(n
|
|
(Application
|
|
[ n (FunctionOrValue [] "fn1")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
)
|
|
(n
|
|
(Application
|
|
[ n (FunctionOrValue [] "fn2")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
)
|
|
)
|
|
, test "should remove <| when the left is a case expression" <|
|
|
\() ->
|
|
"""
|
|
(case (x) of
|
|
1 -> (fn1)
|
|
2 -> (fn2)
|
|
) <| (b)
|
|
"""
|
|
|> normalizeAndExpect
|
|
(CaseExpression
|
|
{ expression = n (FunctionOrValue [] "x")
|
|
, cases =
|
|
[ ( n (IntPattern 1)
|
|
, n
|
|
(Application
|
|
[ n (FunctionOrValue [] "fn1")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
)
|
|
, ( n (IntPattern 2)
|
|
, n
|
|
(Application
|
|
[ n (FunctionOrValue [] "fn2")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
)
|
|
]
|
|
}
|
|
)
|
|
, test "should normalize an operator application" <|
|
|
\() ->
|
|
"""
|
|
[ (a) < (b)
|
|
, (a) <= (b)
|
|
, (a) == (b)
|
|
, (a) /= (b)
|
|
, (a) ++ (b)
|
|
, (a) + (b)
|
|
, (a) - (b)
|
|
, (a) * (b)
|
|
, (a) / (b)
|
|
, (a) // (b)
|
|
, (a) ^ (b)
|
|
, (a) && (b)
|
|
, (a) || (b)
|
|
, (a) </> (b)
|
|
, (a) <?> (b)
|
|
, (a) |. (b)
|
|
, (a) |= (b)
|
|
]"""
|
|
|> normalizeAndExpect
|
|
(ListExpr
|
|
[ n (OperatorApplication "<" Infix.Non (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "<=" Infix.Non (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "==" Infix.Non (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "/=" Infix.Non (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "++" Infix.Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "+" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "-" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "*" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "/" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "//" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "^" Infix.Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "&&" Infix.Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "||" Infix.Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "</>" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "<?>" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "|." Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "|=" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
]
|
|
)
|
|
, test "should re-order operands of '+', '*', '||', '&&', '==', '/=' alphabetically" <|
|
|
\() ->
|
|
"""
|
|
[ (b) + (a)
|
|
, (b) * (a)
|
|
, (b) || (a)
|
|
, (b) && (a)
|
|
, (b) == (a)
|
|
, (b) /= (a)
|
|
]"""
|
|
|> normalizeAndExpect
|
|
(ListExpr
|
|
[ n (OperatorApplication "+" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "*" Infix.Left (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "||" Infix.Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "&&" Infix.Right (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "==" Infix.Non (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
, n (OperatorApplication "/=" Infix.Non (n (FunctionOrValue [] "a")) (n (FunctionOrValue [] "b")))
|
|
]
|
|
)
|
|
, test "should replace > by <" <|
|
|
\() ->
|
|
"(a) > (b)"
|
|
|> normalizeAndExpect
|
|
(OperatorApplication
|
|
"<"
|
|
Infix.Non
|
|
(n (FunctionOrValue [] "b"))
|
|
(n (FunctionOrValue [] "a"))
|
|
)
|
|
, test "should replace >= by <=" <|
|
|
\() ->
|
|
"(a) >= (b)"
|
|
|> normalizeAndExpect
|
|
(OperatorApplication
|
|
"<="
|
|
Infix.Non
|
|
(n (FunctionOrValue [] "b"))
|
|
(n (FunctionOrValue [] "a"))
|
|
)
|
|
, test "should normalize uncons with a list literal into a list literal" <|
|
|
\() ->
|
|
"(a) :: [(b)]"
|
|
|> normalizeAndExpect
|
|
(ListExpr
|
|
[ n (FunctionOrValue [] "a")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
, test "should normalize uncons with a non-list literal into a cons operation still" <|
|
|
\() ->
|
|
"(a) :: (b)"
|
|
|> normalizeAndExpect
|
|
(OperatorApplication
|
|
"::"
|
|
Infix.Right
|
|
(n (FunctionOrValue [] "a"))
|
|
(n (FunctionOrValue [] "b"))
|
|
)
|
|
, test "should normalize an if expression" <|
|
|
\() ->
|
|
"if (a) then (b) else (c)"
|
|
|> normalizeAndExpect
|
|
(IfBlock
|
|
(n (FunctionOrValue [] "a"))
|
|
(n (FunctionOrValue [] "b"))
|
|
(n (FunctionOrValue [] "c"))
|
|
)
|
|
, test "should remove the `not` calls in the condition by switching the branches" <|
|
|
\() ->
|
|
"if (Basics.not a) then (b) else (c)"
|
|
|> normalizeAndExpect
|
|
(IfBlock
|
|
(n (FunctionOrValue [] "a"))
|
|
(n (FunctionOrValue [] "c"))
|
|
(n (FunctionOrValue [] "b"))
|
|
)
|
|
, test "should remove the `not` calls in the condition by switching the branches multiple times" <|
|
|
\() ->
|
|
"if (Basics.not <| Basics.not a) then (b) else (c)"
|
|
|> normalizeAndExpect
|
|
(IfBlock
|
|
(n (FunctionOrValue [] "a"))
|
|
(n (FunctionOrValue [] "b"))
|
|
(n (FunctionOrValue [] "c"))
|
|
)
|
|
, test "should normalize an integer negation" <|
|
|
\() ->
|
|
"-1"
|
|
|> normalizeAndExpect (Integer -1)
|
|
, test "should normalize a float negation" <|
|
|
\() ->
|
|
"-1.1"
|
|
|> normalizeAndExpect (Floatable -1.1)
|
|
, test "should normalize negations of something else" <|
|
|
\() ->
|
|
"-(a)"
|
|
|> normalizeAndExpect
|
|
(Negation (n (FunctionOrValue [] "a")))
|
|
, test "should normalize tuples" <|
|
|
\() ->
|
|
"( (a), (b) )"
|
|
|> normalizeAndExpect
|
|
(TupledExpression
|
|
[ n (FunctionOrValue [] "a")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
, test "should normalize lists" <|
|
|
\() ->
|
|
"[ (a), (b) ]"
|
|
|> normalizeAndExpect
|
|
(ListExpr
|
|
[ n (FunctionOrValue [] "a")
|
|
, n (FunctionOrValue [] "b")
|
|
]
|
|
)
|
|
, test "should normalize lambdas" <|
|
|
\() ->
|
|
"\\(a) -> (a)"
|
|
|> normalizeAndExpect
|
|
(LambdaExpression
|
|
{ args = [ n (VarPattern "a") ]
|
|
, expression = n (FunctionOrValue [] "a")
|
|
}
|
|
)
|
|
, test "should normalize records, and sort fields alphabetically" <|
|
|
\() ->
|
|
"{ field = (2), a = (1), z = (3) }"
|
|
|> normalizeAndExpect
|
|
(RecordExpr
|
|
[ n ( n "a", n (Integer 1) )
|
|
, n ( n "field", n (Integer 2) )
|
|
, n ( n "z", n (Integer 3) )
|
|
]
|
|
)
|
|
, test "should normalize record updates, and sort fields alphabetically" <|
|
|
\() ->
|
|
"{ record | field = (2), a = (1), z = (3) }"
|
|
|> normalizeAndExpect
|
|
(RecordUpdateExpression
|
|
(n "record")
|
|
[ n ( n "a", n (Integer 1) )
|
|
, n ( n "field", n (Integer 2) )
|
|
, n ( n "z", n (Integer 3) )
|
|
]
|
|
)
|
|
, test "should normalize hex literals to integers" <|
|
|
\() ->
|
|
"0x100"
|
|
|> normalizeAndExpect
|
|
(Integer 256)
|
|
, test "should normalize let expressions" <|
|
|
\() ->
|
|
"""
|
|
let
|
|
(a) = (1)
|
|
f : toBeRemoved
|
|
f (n) = (2)
|
|
in
|
|
(2)
|
|
"""
|
|
|> normalizeAndExpect
|
|
(LetExpression
|
|
{ declarations =
|
|
[ n
|
|
(LetDestructuring
|
|
(n (VarPattern "a"))
|
|
(n (Integer 1))
|
|
)
|
|
, n
|
|
(LetFunction
|
|
{ declaration =
|
|
n
|
|
{ arguments =
|
|
[ n (VarPattern "n")
|
|
]
|
|
, expression = n (Integer 2)
|
|
, name = n "f"
|
|
}
|
|
, documentation = Nothing
|
|
, signature = Nothing
|
|
}
|
|
)
|
|
]
|
|
, expression = n (Integer 2)
|
|
}
|
|
)
|
|
, test "should normalize case expressions" <|
|
|
\() ->
|
|
"""case (x) of
|
|
( (0x100), (b) ) :: (c) -> (1)
|
|
a :: [ (b) ] -> (2)
|
|
{ field, a, z } -> (3)
|
|
Basics.Just True -> (4)
|
|
((a) as b) -> (5)
|
|
"""
|
|
|> normalizeAndExpect
|
|
(CaseExpression
|
|
{ cases =
|
|
[ ( n
|
|
(UnConsPattern
|
|
(n
|
|
(TuplePattern
|
|
[ n (IntPattern 256)
|
|
, n (VarPattern "b")
|
|
]
|
|
)
|
|
)
|
|
(n (VarPattern "c"))
|
|
)
|
|
, n (Integer 1)
|
|
)
|
|
, ( n
|
|
(ListPattern
|
|
[ n (VarPattern "a")
|
|
, n (VarPattern "b")
|
|
]
|
|
)
|
|
, n (Integer 2)
|
|
)
|
|
, ( n
|
|
(RecordPattern
|
|
[ n "a"
|
|
, n "field"
|
|
, n "z"
|
|
]
|
|
)
|
|
, n (Integer 3)
|
|
)
|
|
, ( n
|
|
(NamedPattern
|
|
{ moduleName = [ "Basics" ]
|
|
, name = "Just"
|
|
}
|
|
[ n (NamedPattern { moduleName = [], name = "True" } []) ]
|
|
)
|
|
, n (Integer 4)
|
|
)
|
|
, ( n (AsPattern (n (VarPattern "a")) (n "b"))
|
|
, n (Integer 5)
|
|
)
|
|
]
|
|
, expression = n (FunctionOrValue [] "x")
|
|
}
|
|
)
|
|
, test "should not change anything about >>" <|
|
|
\() ->
|
|
"a >> b >> c >> d"
|
|
|> normalizeAndExpect
|
|
(OperatorApplication ">>"
|
|
Right
|
|
(n (FunctionOrValue [] "a"))
|
|
(n
|
|
(OperatorApplication ">>"
|
|
Right
|
|
(n (FunctionOrValue [] "b"))
|
|
(n
|
|
(OperatorApplication ">>"
|
|
Right
|
|
(n (FunctionOrValue [] "c"))
|
|
(n (FunctionOrValue [] "d"))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
, test "should switch << to use >>" <|
|
|
\() ->
|
|
normalizeSourceCode [] Infer.empty "d << c << b << a"
|
|
|> Expect.equal (normalizeSourceCode [] Infer.empty "a >> b >> c >> d")
|
|
]
|
|
|
|
|
|
moduleNameTests : Test
|
|
moduleNameTests =
|
|
describe "Module name normalization"
|
|
[ test "should normalize module name in expression (unknown)" <|
|
|
\() ->
|
|
"A.b"
|
|
|> normalizeWithModuleNamesAndExpect []
|
|
(FunctionOrValue [ "A" ] "b")
|
|
, test "should normalize module name in expression (unchanged)" <|
|
|
\() ->
|
|
"A.b"
|
|
|> normalizeWithModuleNamesAndExpect
|
|
[ ( { start = { row = 2, column = 9 }, end = { row = 2, column = 12 } }
|
|
, [ "A" ]
|
|
)
|
|
]
|
|
(FunctionOrValue [ "A" ] "b")
|
|
, test "should normalize module name in expression (aliased)" <|
|
|
\() ->
|
|
"A.b"
|
|
|> normalizeWithModuleNamesAndExpect
|
|
[ ( { start = { row = 2, column = 9 }, end = { row = 2, column = 12 } }
|
|
, [ "Something", "Else" ]
|
|
)
|
|
]
|
|
(FunctionOrValue [ "Something", "Else" ] "b")
|
|
, test "should normalize module name in expression (unqualified)" <|
|
|
\() ->
|
|
"b"
|
|
|> normalizeWithModuleNamesAndExpect
|
|
[ ( { start = { row = 2, column = 9 }, end = { row = 2, column = 10 } }
|
|
, [ "A" ]
|
|
)
|
|
]
|
|
(FunctionOrValue [ "A" ] "b")
|
|
, test "should normalize module name in patterns" <|
|
|
\() ->
|
|
"""case x of
|
|
B.Just (a) -> (1)
|
|
Nothing -> (2)
|
|
_ -> (3)
|
|
"""
|
|
|> normalizeWithModuleNamesAndExpect
|
|
[ ( { start = { row = 3, column = 3 }, end = { row = 3, column = 13 } }
|
|
, [ "Basics" ]
|
|
)
|
|
, ( { start = { row = 4, column = 3 }, end = { row = 4, column = 10 } }
|
|
, [ "Basics" ]
|
|
)
|
|
]
|
|
(CaseExpression
|
|
{ cases =
|
|
[ ( n (NamedPattern { moduleName = [ "Basics" ], name = "Just" } [ n (VarPattern "a") ])
|
|
, n (Integer 1)
|
|
)
|
|
, ( n (NamedPattern { moduleName = [ "Basics" ], name = "Nothing" } [])
|
|
, n (Integer 2)
|
|
)
|
|
, ( n AllPattern
|
|
, n (Integer 3)
|
|
)
|
|
]
|
|
, expression = n (FunctionOrValue [] "x")
|
|
}
|
|
)
|
|
]
|
|
|
|
|
|
inferTests : Test
|
|
inferTests =
|
|
describe "Normalization through inferred values"
|
|
[ test "should not replace anything when nothing has been inferred" <|
|
|
\() ->
|
|
"a"
|
|
|> normalizeWithInferredAndExpect
|
|
[]
|
|
[]
|
|
(FunctionOrValue [] "a")
|
|
, test "should replace reference when its value is known" <|
|
|
\() ->
|
|
"a"
|
|
|> normalizeWithInferredAndExpect
|
|
[ ( { start = { row = 2, column = 9 }, end = { row = 2, column = 10 } }
|
|
, [ "A" ]
|
|
)
|
|
]
|
|
[ ( FunctionOrValue [ "A" ] "a", Infer.DTrue ) ]
|
|
(FunctionOrValue [ "Basics" ] "True")
|
|
, test "should not replace reference when module name is unknown" <|
|
|
\() ->
|
|
"a"
|
|
|> normalizeWithInferredAndExpect
|
|
[]
|
|
[ ( FunctionOrValue [ "A" ] "a", Infer.DTrue ) ]
|
|
(FunctionOrValue [] "a")
|
|
, test "should not replace reference when module name is not the same" <|
|
|
\() ->
|
|
"a"
|
|
|> normalizeWithInferredAndExpect
|
|
[ ( { start = { row = 2, column = 9 }, end = { row = 2, column = 10 } }
|
|
, [ "B" ]
|
|
)
|
|
]
|
|
[ ( FunctionOrValue [ "A" ] "a", Infer.DTrue ) ]
|
|
(FunctionOrValue [ "B" ] "a")
|
|
]
|
|
|
|
|
|
n : a -> Node a
|
|
n =
|
|
Node Range.emptyRange
|
|
|
|
|
|
normalizeAndExpect : Expression -> String -> Expect.Expectation
|
|
normalizeAndExpect expected source =
|
|
normalizeBase [] Infer.empty expected source
|
|
|
|
|
|
normalizeWithModuleNamesAndExpect : List ( Range, ModuleName ) -> Expression -> String -> Expect.Expectation
|
|
normalizeWithModuleNamesAndExpect moduleNames expected source =
|
|
normalizeBase moduleNames Infer.empty expected source
|
|
|
|
|
|
normalizeWithInferredAndExpect : List ( Range, ModuleName ) -> List ( Expression, Infer.DeducedValue ) -> Expression -> String -> Expect.Expectation
|
|
normalizeWithInferredAndExpect moduleNames inferredList expected source =
|
|
normalizeBase moduleNames (Infer.fromList inferredList) expected source
|
|
|
|
|
|
normalizeBase : List ( Range, ModuleName ) -> Infer.Inferred -> Expression -> String -> Expect.Expectation
|
|
normalizeBase moduleNames inferred expected source =
|
|
normalizeSourceCode moduleNames inferred source
|
|
|> Expect.equal expected
|
|
|
|
|
|
normalizeSourceCode : List ( Range, ModuleName ) -> Infer.Inferred -> String -> Expression
|
|
normalizeSourceCode moduleNames inferred source =
|
|
("module A exposing (..)\nvalue = " ++ source)
|
|
|> parse
|
|
|> getValue
|
|
|> Normalize.normalize
|
|
{ lookupTable = ModuleNameLookupTable.createForTests [ "A" ] moduleNames
|
|
, inferredConstants = ( inferred, [] )
|
|
}
|
|
|> Node.value
|
|
|
|
|
|
{-| Parse source code into a AST.
|
|
-}
|
|
parse : String -> File
|
|
parse source =
|
|
case Parser.parse source of
|
|
Ok ast ->
|
|
Elm.Processing.process elmProcessContext ast
|
|
|
|
Err _ ->
|
|
Debug.todo "Source code given to test contained invalid syntax"
|
|
|
|
|
|
getValue : File -> Node Expression
|
|
getValue file =
|
|
case findValueDeclaration file.declarations of
|
|
Just expression ->
|
|
expression
|
|
|
|
Nothing ->
|
|
Debug.todo "Source code did not contain a value declaration"
|
|
|
|
|
|
findValueDeclaration : List (Node Declaration) -> Maybe (Node Expression)
|
|
findValueDeclaration declarations =
|
|
findMap
|
|
(\node ->
|
|
case Node.value node of
|
|
Declaration.FunctionDeclaration { declaration } ->
|
|
if Node.value (Node.value declaration).name == "value" then
|
|
Just (Node.value declaration).expression
|
|
|
|
else
|
|
Nothing
|
|
|
|
_ ->
|
|
Nothing
|
|
)
|
|
declarations
|
|
|
|
|
|
elmProcessContext : Elm.Processing.ProcessContext
|
|
elmProcessContext =
|
|
Elm.Processing.init
|
|
|> Elm.Processing.addDependency elmCore
|
|
|
|
|
|
elmCore : Elm.Dependency.Dependency
|
|
elmCore =
|
|
{ name = "elm/core"
|
|
, version = "1.0.0"
|
|
, interfaces =
|
|
Dict.fromList
|
|
[ ( [ "Basics" ]
|
|
, [ -- infix right 0 (<|) = apL
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Right
|
|
, precedence = Node.Node Range.emptyRange 0
|
|
, operator = Node.Node Range.emptyRange "<|"
|
|
, function = Node.Node Range.emptyRange "apL"
|
|
}
|
|
, -- infix left 0 (|>) = apR
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Left
|
|
, precedence = Node.Node Range.emptyRange 0
|
|
, operator = Node.Node Range.emptyRange "|>"
|
|
, function = Node.Node Range.emptyRange "apR"
|
|
}
|
|
, -- infix right 2 (||) = or
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Right
|
|
, precedence = Node.Node Range.emptyRange 2
|
|
, operator = Node.Node Range.emptyRange "||"
|
|
, function = Node.Node Range.emptyRange "or"
|
|
}
|
|
, -- infix right 3 (&&) = and
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Right
|
|
, precedence = Node.Node Range.emptyRange 3
|
|
, operator = Node.Node Range.emptyRange "&&"
|
|
, function = Node.Node Range.emptyRange "and"
|
|
}
|
|
, -- infix non 4 (==) = eq
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Non
|
|
, precedence = Node.Node Range.emptyRange 4
|
|
, operator = Node.Node Range.emptyRange "=="
|
|
, function = Node.Node Range.emptyRange "eq"
|
|
}
|
|
, -- infix non 4 (/=) = neq
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Non
|
|
, precedence = Node.Node Range.emptyRange 4
|
|
, operator = Node.Node Range.emptyRange "/="
|
|
, function = Node.Node Range.emptyRange "neq"
|
|
}
|
|
, -- infix non 4 (<) = lt
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Non
|
|
, precedence = Node.Node Range.emptyRange 4
|
|
, operator = Node.Node Range.emptyRange "<"
|
|
, function = Node.Node Range.emptyRange "lt"
|
|
}
|
|
, -- infix non 4 (>) = gt
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Non
|
|
, precedence = Node.Node Range.emptyRange 4
|
|
, operator = Node.Node Range.emptyRange ">"
|
|
, function = Node.Node Range.emptyRange "gt"
|
|
}
|
|
, -- infix non 4 (<=) = le
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Non
|
|
, precedence = Node.Node Range.emptyRange 4
|
|
, operator = Node.Node Range.emptyRange "<="
|
|
, function = Node.Node Range.emptyRange "le"
|
|
}
|
|
, -- infix non 4 (>=) = ge
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Non
|
|
, precedence = Node.Node Range.emptyRange 4
|
|
, operator = Node.Node Range.emptyRange ">="
|
|
, function = Node.Node Range.emptyRange "ge"
|
|
}
|
|
, -- infix right 5 (++) = append
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Right
|
|
, precedence = Node.Node Range.emptyRange 5
|
|
, operator = Node.Node Range.emptyRange "++"
|
|
, function = Node.Node Range.emptyRange "append"
|
|
}
|
|
, -- infix left 6 (+) = add
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Left
|
|
, precedence = Node.Node Range.emptyRange 6
|
|
, operator = Node.Node Range.emptyRange "+"
|
|
, function = Node.Node Range.emptyRange "add"
|
|
}
|
|
, -- infix left 6 (-) = sub
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Left
|
|
, precedence = Node.Node Range.emptyRange 6
|
|
, operator = Node.Node Range.emptyRange "-"
|
|
, function = Node.Node Range.emptyRange "sub"
|
|
}
|
|
, -- infix left 7 (*) = mul
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Left
|
|
, precedence = Node.Node Range.emptyRange 7
|
|
, operator = Node.Node Range.emptyRange "*"
|
|
, function = Node.Node Range.emptyRange "mul"
|
|
}
|
|
, -- infix left 7 (/) = fdiv
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Left
|
|
, precedence = Node.Node Range.emptyRange 7
|
|
, operator = Node.Node Range.emptyRange "/"
|
|
, function = Node.Node Range.emptyRange "fdiv"
|
|
}
|
|
, -- infix left 7 (//) = idiv
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Left
|
|
, precedence = Node.Node Range.emptyRange 7
|
|
, operator = Node.Node Range.emptyRange "//"
|
|
, function = Node.Node Range.emptyRange "idiv"
|
|
}
|
|
, -- infix right 8 (^) = pow
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Right
|
|
, precedence = Node.Node Range.emptyRange 8
|
|
, operator = Node.Node Range.emptyRange "^"
|
|
, function = Node.Node Range.emptyRange "pow"
|
|
}
|
|
, -- infix left 9 (<<) = composeL
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Left
|
|
, precedence = Node.Node Range.emptyRange 9
|
|
, operator = Node.Node Range.emptyRange "<<"
|
|
, function = Node.Node Range.emptyRange "composeL"
|
|
}
|
|
, -- infix right 9 (>>) = composeR
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Right
|
|
, precedence = Node.Node Range.emptyRange 9
|
|
, operator = Node.Node Range.emptyRange ">>"
|
|
, function = Node.Node Range.emptyRange "composeR"
|
|
}
|
|
]
|
|
)
|
|
, ( [ "List" ]
|
|
, [ -- infix right 5 (::) = cons
|
|
Interface.Operator
|
|
{ direction = Node.Node Range.emptyRange Infix.Right
|
|
, precedence = Node.Node Range.emptyRange 5
|
|
, operator = Node.Node Range.emptyRange "::"
|
|
, function = Node.Node Range.emptyRange "cons"
|
|
}
|
|
]
|
|
)
|
|
]
|
|
}
|
|
|
|
|
|
findMap : (a -> Maybe b) -> List a -> Maybe b
|
|
findMap mapper nodes =
|
|
case nodes of
|
|
[] ->
|
|
Nothing
|
|
|
|
node :: rest ->
|
|
case mapper node of
|
|
Just value ->
|
|
Just value
|
|
|
|
Nothing ->
|
|
findMap mapper rest
|