1
1
mirror of https://github.com/github/semantic.git synced 2024-12-01 17:59:10 +03:00
semantic/semantic-python/test/Directive.hs

81 lines
2.7 KiB
Haskell
Raw Normal View History

2019-08-16 19:34:56 +03:00
module Directive ( Directive (..)
2019-08-29 15:52:38 +03:00
, parseDirectives
, describe
2019-08-16 19:34:56 +03:00
, toProcess
) where
import Control.Applicative
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
{- |
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
@
# CHECK-JQ: has("mach")
@
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.
-}
data Directive = JQ ByteString -- | @# CHECK-JQ: expr@
| Tree (Term Core Name) -- | @# CHECK-TREE: core@
| Fails -- | @# CHECK-FAILS@ fails unless translation fails.
deriving (Eq, Show)
2019-08-16 19:34:56 +03:00
describe :: Directive -> String
describe Fails = "<expect failure>"
describe (Tree t) = Core.Pretty.showCore t
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")
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
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]
toProcess x = error ("can't call toProcess on " <> show x)