Skip to content

Commit 9f822c6

Browse files
committed
Extended Eval Plugin (additional changes)
1 parent 9848239 commit 9f822c6

28 files changed

+792
-634
lines changed

Diff for: haskell-language-server.cabal

+4-3
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,12 @@ executable haskell-language-server
154154
, time
155155
, transformers
156156
, unordered-containers
157-
-- , ghc-exactprint
158157
, parser-combinators
159158
, pretty-simple
160-
, Diff == 0.4.*
161-
-- , ghc-paths
159+
, Diff
162160
, QuickCheck
161+
, ghc-paths
162+
163163

164164
if flag(agpl)
165165
build-depends: brittany
@@ -247,6 +247,7 @@ test-suite func-test
247247
, tasty-expected-failure
248248
, tasty-golden
249249
, tasty-rerun
250+
, QuickCheck
250251

251252
hs-source-dirs: test/functional plugins/tactics/src
252253

Diff for: plugins/default/src/Ide/Plugin/Eval/Code.hs

+66-59
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,46 @@
22
{-# OPTIONS_GHC -Wwarn -fno-warn-orphans #-}
33

44
-- | Expression execution
5-
module Ide.Plugin.Eval.Code(Statement,testRanges,resultRange,evalExtensions,evalSetup,evalExpr,propSetup,testCheck,asStatements) where
6-
7-
import Data.Algorithm.Diff (Diff,PolyDiff(..),getDiff)
8-
import qualified Data.List.NonEmpty as NE
9-
import Data.String (IsString)
10-
import qualified Data.Text as T
11-
import Development.IDE.Types.Location (Position (..), Range (..))
12-
import GHC (compileExpr)
13-
import GHC.LanguageExtensions.Type (Extension (..))
14-
import GhcMonad (Ghc, GhcMonad, liftIO)
15-
import Ide.Plugin.Eval.Types (Language (Plain), Loc,
16-
Located (Located),
17-
Section (sectionLanguage),
18-
Test (Example, Property, testOutput),
19-
Txt, locate, locate0)
20-
import InteractiveEval (runDecls)
21-
import Unsafe.Coerce (unsafeCoerce)
5+
module Ide.Plugin.Eval.Code (Statement, testRanges, resultRange, evalExtensions, evalSetup, evalExpr, propSetup, testCheck, asStatements) where
6+
7+
import Data.Algorithm.Diff (Diff, PolyDiff (..), getDiff)
8+
import qualified Data.List.NonEmpty as NE
9+
import Data.String (IsString)
10+
import qualified Data.Text as T
11+
import Development.IDE.Types.Location (Position (..), Range (..))
12+
import GHC (compileExpr)
13+
import GHC.LanguageExtensions.Type (Extension (..))
14+
import GhcMonad (Ghc, GhcMonad, liftIO)
15+
import Ide.Plugin.Eval.Types (
16+
Language (Plain),
17+
Loc,
18+
Located (Located),
19+
Section (sectionLanguage),
20+
Test (Example, Property, testOutput),
21+
Txt,
22+
locate,
23+
locate0,
24+
)
25+
import InteractiveEval (runDecls)
26+
import Unsafe.Coerce (unsafeCoerce)
2227

2328
-- | Return the ranges of the expression and result parts of the given test
2429
testRanges :: Loc Test -> (Range, Range)
2530
testRanges (Located line tst) =
26-
let startLine = line
27-
(exprLines, resultLines) = testLenghts tst
28-
resLine = startLine + exprLines
29-
in ( Range
30-
(Position startLine 0)
31-
--(Position (startLine + exprLines + resultLines) 0),
32-
(Position resLine 0),
33-
Range (Position resLine 0) (Position (resLine + resultLines) 0)
34-
)
35-
36-
-- |The document range where a test is defined
37-
-- testRange :: Loc Test -> Range
38-
-- testRange = fst . testRanges
31+
let startLine = line
32+
(exprLines, resultLines) = testLenghts tst
33+
resLine = startLine + exprLines
34+
in ( Range
35+
(Position startLine 0)
36+
--(Position (startLine + exprLines + resultLines) 0),
37+
(Position resLine 0)
38+
, Range (Position resLine 0) (Position (resLine + resultLines) 0)
39+
)
40+
41+
{- |The document range where a test is defined
42+
testRange :: Loc Test -> Range
43+
testRange = fst . testRanges
44+
-}
3945

4046
-- |The document range where the result of the test is defined
4147
resultRange :: Loc Test -> Range
@@ -50,17 +56,17 @@ showDiffs :: (Semigroup a, IsString a) => [Diff a] -> [a]
5056
showDiffs = map showDiff
5157

5258
showDiff :: (Semigroup a, IsString a) => Diff a -> a
53-
showDiff (First w) = "WAS " <> w
59+
showDiff (First w) = "WAS " <> w
5460
showDiff (Second w) = "NOW " <> w
5561
showDiff (Both w _) = w
5662

5763
testCheck :: (Section, Test) -> [T.Text] -> [T.Text]
5864
testCheck (section, test) out
59-
| null (testOutput test) || sectionLanguage section == Plain = out
60-
| otherwise = showDiffs $ getDiff (map T.pack $ testOutput test) out
65+
| null (testOutput test) || sectionLanguage section == Plain = out
66+
| otherwise = showDiffs $ getDiff (map T.pack $ testOutput test) out
6167

6268
testLenghts :: Test -> (Int, Int)
63-
testLenghts (Example e r) = (NE.length e, length r)
69+
testLenghts (Example e r) = (NE.length e, length r)
6470
testLenghts (Property _ r) = (1, length r)
6571

6672
-- |A one-line Haskell statement
@@ -72,48 +78,49 @@ asStatements lt = locate (asStmts <$> lt)
7278
asStmts :: Test -> [Txt]
7379
asStmts (Example e _) = NE.toList e
7480
asStmts (Property t _) =
75-
["prop11 = " ++ t, "(propEvaluation prop11 :: IO String)"]
81+
["prop11 = " ++ t, "(propEvaluation prop11 :: IO String)"]
7682

7783
-- |Evaluate an expression (either a pure expression or an IO a)
7884
evalExpr :: GhcMonad m => [Char] -> m String
7985
evalExpr e = do
80-
res <- compileExpr $ "asPrint (" ++ e ++ ")"
81-
liftIO (unsafeCoerce res :: IO String)
86+
res <- compileExpr $ "asPrint (" ++ e ++ ")"
87+
liftIO (unsafeCoerce res :: IO String)
8288

8389
-- |GHC extensions required for expression evaluation
8490
evalExtensions :: [Extension]
8591
evalExtensions =
86-
[ OverlappingInstances,
87-
UndecidableInstances,
88-
FlexibleInstances,
89-
IncoherentInstances,
90-
TupleSections
91-
]
92+
[ OverlappingInstances
93+
, UndecidableInstances
94+
, FlexibleInstances
95+
, IncoherentInstances
96+
, TupleSections
97+
]
9298

9399
-- |GHC declarations required for expression evaluation
94100
evalSetup :: Ghc ()
95101
evalSetup =
96-
mapM_
97-
runDecls
98-
[ "class Print f where asPrint :: f -> IO String",
99-
"instance Show a => Print (IO a) where asPrint io = io >>= return . show",
100-
"instance Show a => Print a where asPrint a = return (show a)"
101-
]
102+
mapM_
103+
runDecls
104+
[ "class Print f where asPrint :: f -> IO String"
105+
, "instance Show a => Print (IO a) where asPrint io = io >>= return . show"
106+
, "instance Show a => Print a where asPrint a = return (show a)"
107+
]
102108

103-
-- |GHC declarations required to execute test properties
104-
propSetup :: [Loc [Char]]
105-
propSetup =
106-
locate0
107-
[ ":set -XScopedTypeVariables -XExplicitForAll",
108-
"import qualified Test.QuickCheck as Q11",
109-
"propEvaluation p = Q11.quickCheckWithResult Q11.stdArgs p >>= error . Q11.output" -- uses `error` to get a multi-line display
110-
]
109+
{- |GHC declarations required to execute test properties
110+
111+
Example:
111112
112-
{-
113113
prop> \(l::[Bool]) -> reverse (reverse l) == l
114114
+++ OK, passed 100 tests.
115115
116116
prop> \(l::[Bool]) -> reverse l == l
117-
*** Failed! Falsified (after 3 tests):
117+
*** Failed! Falsified (after 6 tests and 2 shrinks):
118118
[True,False]
119119
-}
120+
propSetup :: [Loc [Char]]
121+
propSetup =
122+
locate0
123+
[ ":set -XScopedTypeVariables -XExplicitForAll"
124+
, "import qualified Test.QuickCheck as Q11"
125+
, "propEvaluation p = Q11.quickCheckWithResult Q11.stdArgs p >>= error . Q11.output" -- uses `error` to get a multi-line display
126+
]

0 commit comments

Comments
 (0)