2019-08-16 19:34:56 +03:00
|
|
|
module Directive ( Directive (..)
|
2019-08-29 15:52:38 +03:00
|
|
|
, parseDirectives
|
2019-08-29 16:20:13 +03:00
|
|
|
, describe
|
2019-08-16 19:34:56 +03:00
|
|
|
, toProcess
|
|
|
|
) where
|
|
|
|
|
2019-08-16 22:54:17 +03:00
|
|
|
import Control.Applicative
|
2019-09-19 01:07:43 +03:00
|
|
|
import Control.Monad
|
|
|
|
import Data.Name (Name)
|
|
|
|
import Data.Term (Term)
|
|
|
|
import Data.Core (Core)
|
|
|
|
import qualified Data.Core.Parser as Core.Parser
|
|
|
|
import qualified Data.Core.Pretty as Core.Pretty
|
2019-08-16 19:34:56 +03:00
|
|
|
import Data.ByteString.Char8 (ByteString)
|
|
|
|
import qualified Data.ByteString.Char8 as ByteString
|
2019-08-29 15:52:38 +03:00
|
|
|
import Data.List.NonEmpty (NonEmpty)
|
2019-08-16 19:34:56 +03:00
|
|
|
import Data.Coerce
|
|
|
|
import System.Process
|
|
|
|
import qualified Text.Trifecta as Trifecta
|
|
|
|
|
2019-08-27 17:25:21 +03:00
|
|
|
{- |
|
|
|
|
|
|
|
|
Directives are parsed from magic comments in test files and
|
|
|
|
describe to the test suite how to query the results of a given test
|
|
|
|
case. A directive that looks like this:
|
2019-08-16 19:34:56 +03:00
|
|
|
|
2019-08-16 22:54:17 +03:00
|
|
|
@
|
|
|
|
# CHECK-JQ: has("mach")
|
|
|
|
@
|
|
|
|
|
2019-08-27 17:25:21 +03:00
|
|
|
would, after converting the contents of the file to a Core expression,
|
|
|
|
dump that expression to JSON and pipe said JSON to @jq -e
|
|
|
|
'has("mach")@, which will return an error code unless the passed JSON
|
|
|
|
is a hash containing the @"mach"@ key.
|
|
|
|
|
|
|
|
This syntax was inspired by LLVM's
|
|
|
|
[FileCheck](https://llvm.org/docs/CommandGuide/FileCheck.html). This
|
|
|
|
approach is less direct than tests that pattern-match over an AST, but
|
|
|
|
enable us to keep the text of test cases in close proximity to the
|
|
|
|
assertions we want to make, which improves maintainability
|
|
|
|
significantly and has been a successful strategy for the LLVM and Rust
|
|
|
|
projects.
|
2019-08-16 22:54:17 +03:00
|
|
|
|
|
|
|
-}
|
|
|
|
data Directive = JQ ByteString -- | @# CHECK-JQ: expr@
|
2019-09-19 01:07:43 +03:00
|
|
|
| Tree (Term Core Name) -- | @# CHECK-TREE: core@
|
2019-08-16 22:54:17 +03:00
|
|
|
| Fails -- | @# CHECK-FAILS@ fails unless translation fails.
|
|
|
|
deriving (Eq, Show)
|
2019-08-16 19:34:56 +03:00
|
|
|
|
2019-08-29 16:20:13 +03:00
|
|
|
describe :: Directive -> String
|
|
|
|
describe Fails = "<expect failure>"
|
2019-09-19 01:07:43 +03:00
|
|
|
describe (Tree t) = Core.Pretty.showCore t
|
2019-08-29 16:20:13 +03:00
|
|
|
describe (JQ b) = ByteString.unpack b
|
|
|
|
|
2019-08-16 20:20:08 +03:00
|
|
|
fails :: Trifecta.Parser Directive
|
|
|
|
fails = Fails <$ Trifecta.string "# CHECK-FAILS"
|
|
|
|
|
|
|
|
jq :: Trifecta.Parser Directive
|
|
|
|
jq = do
|
2019-08-16 19:34:56 +03:00
|
|
|
Trifecta.string "# CHECK-JQ: "
|
2019-08-16 20:20:08 +03:00
|
|
|
JQ . ByteString.pack <$> many (Trifecta.noneOf "\n")
|
|
|
|
|
2019-09-19 01:07:43 +03:00
|
|
|
tree :: Trifecta.Parser Directive
|
|
|
|
tree = do
|
|
|
|
void $ Trifecta.string "# CHECK-TREE: "
|
|
|
|
Tree <$> (Core.Parser.record <|> Core.Parser.comp)
|
|
|
|
|
2019-08-16 20:20:08 +03:00
|
|
|
directive :: Trifecta.Parser Directive
|
2019-09-19 01:07:43 +03:00
|
|
|
directive = Trifecta.choice [ fails, jq, tree ]
|
2019-08-16 19:34:56 +03:00
|
|
|
|
2019-08-29 15:52:38 +03:00
|
|
|
toplevel :: Trifecta.Parser (NonEmpty Directive)
|
|
|
|
toplevel = directive `Trifecta.sepEndByNonEmpty` Trifecta.char '\n'
|
|
|
|
|
|
|
|
parseDirectives :: ByteString -> Either String (NonEmpty Directive)
|
|
|
|
parseDirectives = Trifecta.foldResult (Left . show) Right
|
|
|
|
. Trifecta.parseByteString toplevel mempty
|
2019-08-16 19:34:56 +03:00
|
|
|
|
|
|
|
toProcess :: Directive -> CreateProcess
|
|
|
|
toProcess (JQ d) = proc "jq" ["-e", ByteString.unpack d]
|
2019-08-16 22:54:17 +03:00
|
|
|
toProcess x = error ("can't call toProcess on " <> show x)
|