packages feed

cmake-syntax (empty) → 0.1.0.0

raw patch · 8 files changed

+385/−0 lines, 8 filesdep +basedep +bytestringdep +cmake-syntaxsetup-changed

Dependencies added: base, bytestring, cmake-syntax, hspec, raw-strings-qq, trifecta

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Changelog for cmake-syntax++## v0.1.0.0++Initial release
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Georg Rudoy (c) 2019++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Georg Rudoy nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,8 @@+# cmake-syntax++[![Build Status][travis-badge]][travis]++A simple parser for the CMake files.++[travis]:        <https://travis-ci.org/0xd34df00d/can-i-haz>+[travis-badge]:  <https://travis-ci.org/0xd34df00d/can-i-haz.svg?branch=master>
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cmake-syntax.cabal view
@@ -0,0 +1,61 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 26bcc743c2398b409fec017473b905cf77d41b0b8ec9abe5cf6b0ae91e461e2c++name:           cmake-syntax+version:        0.1.0.0+synopsis:       Parser for the CMake syntax (CMakeLists.txt and .cmake files)+description:    Please see the README on GitHub at <https://github.com/0xd34df00d/cmake-syntax#readme>+category:       Language+homepage:       https://github.com/0xd34df00d/cmake-syntax#readme+bug-reports:    https://github.com/0xd34df00d/cmake-syntax/issues+author:         Georg Rudoy+maintainer:     0xd34df00d@gmail.com+copyright:      2019 Georg Rudoy+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    ChangeLog.md++source-repository head+  type: git+  location: https://github.com/0xd34df00d/cmake-syntax++library+  exposed-modules:+      Language.CMake.AST+      Language.CMake.Parser+  other-modules:+      Paths_cmake_syntax+  hs-source-dirs:+      src+  ghc-options: -Wall+  build-depends:+      base >=4.7 && <5+    , bytestring+    , raw-strings-qq+    , trifecta+  default-language: Haskell2010++test-suite cmake-syntax-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Paths_cmake_syntax+  hs-source-dirs:+      test+  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.7 && <5+    , bytestring+    , cmake-syntax+    , hspec+    , raw-strings-qq+    , trifecta+  default-language: Haskell2010
+ src/Language/CMake/AST.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Language.CMake.AST where++import qualified Data.ByteString.Char8 as BS+import Data.String++newtype File = File { fileElements :: [FileElement] } deriving (Eq, Show)++data FileElement+  = CommandElement { commandInvocation :: CommandInvocation }+  | NonCommandElement+  deriving (Eq, Show)++data CommandInvocation = CommandInvocation+  { commandId :: BS.ByteString+  , commandArgs :: [Argument]+  }+  deriving (Eq, Show)++data LiteralElem+  = LiteralString { literalString :: BS.ByteString }+  | VariableReference { variableName :: BS.ByteString }+  deriving (Eq, Show)++newtype Literal = Literal { literalParts :: [LiteralElem] }+  deriving (Eq, Show, Semigroup, Monoid)++instance IsString Literal where+  fromString = Literal . pure . LiteralString . BS.pack++newtype Argument = Argument { argumentLiteral :: Literal }+  deriving (Eq, Show, Semigroup, Monoid)++instance IsString Argument where+  fromString = Argument . fromString
+ src/Language/CMake/Parser.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE RecordWildCards, QuasiQuotes #-}++module Language.CMake.Parser+( fileParser+) where++import qualified Data.ByteString.Char8 as BS+import Control.Applicative+import Data.Char+import Data.Functor+import Data.Maybe+import Data.String+import Text.RawString.QQ+import Text.Trifecta++import Language.CMake.AST hiding(commandInvocation)++fileParser :: Parser File+fileParser = File <$> many fileElement <* eof++fileElement :: Parser FileElement+fileElement = try (many (try bracketComment <|> spaceNonLF) *> lineEnding $> NonCommandElement)+          <|> (CommandElement <$> commandInvocation) <* many spaceNonLF <* lineEnding+  where spaceNonLF = void $ satisfy $ \c -> isSpace c && c /= '\n'++lineEnding :: Parser ()+lineEnding = skipOptional lineComment >> void newline++commandInvocation :: Parser CommandInvocation+commandInvocation = do+  spaces+  commandId <- BS.pack <$> some ('A' ~~ 'Z' <|> 'a' ~~ 'z' <|> char '_' <|> '0' ~~ '9')+  spaces+  commandArgs <- between (char '(') (char ')') arguments+  pure CommandInvocation { .. }+  where (~~) = satisfyRange++arguments :: Parser [Argument]+arguments = do+  arg <- maybeToList <$> optional argument+  rest <- concat <$> many separatedArguments+  pure $ arg <> rest++separatedArguments :: Parser [Argument]+separatedArguments = maybeToList <$> try (some separation *> optional argument)+                 <|> many separation *> between (char '(') (char ')') arguments++separation :: Parser ()+separation = void space <|> lineEnding++argument :: Parser Argument+argument = bracketArgument <|> quotedArgument <|> unquotedArgument++bracketArgument :: Parser Argument+bracketArgument = do+  opening <- char '[' *> many (char '=') <* char '['+  let closing = string $ "]" <> opening <> "]"+  fromString <$> anyChar `manyTill` try closing++quotedArgument :: Parser Argument+quotedArgument = fromString . catMaybes <$> many quotedElement `surroundedBy` char '"'++quotedElement :: Parser (Maybe Char)+quotedElement = Just <$> (noneOf [r|\"|] <|> try escapeSequence)+            <|> (char '\\' *> newline $> Nothing)++unquotedArgument :: Parser Argument+unquotedArgument = fromString <$> some (satisfy unElem <|> escapeSequence)+  where unElem c = c `notElem` [r|()#\"|] && not (isSpace c)++escapeSequence :: Parser Char+escapeSequence = char '\\' >> (self <|> encoded)+  where+    self = oneOf [r|()#" \$@^;|]+    encoded = char 't' $> '\t'+          <|> char 'r' $> '\r'+          <|> char 'n' $> '\n'++bracketComment :: Parser ()+bracketComment = char '#' >> void bracketArgument++lineComment :: Parser ()+lineComment = char '#' >> void (many $ notChar '\n')
+ test/Spec.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE QuasiQuotes, OverloadedStrings #-}+{-# OPTIONS_GHC -Wno-orphans #-}++import Data.Char+import Test.Hspec+import Text.RawString.QQ+import Text.Trifecta.Parser+import Text.Trifecta.Result++import Language.CMake.AST+import Language.CMake.Parser++instance Eq a => Eq (Result a) where+  Success a == Success b = a == b+  Failure _ == Failure _ = True+  _ == _ = False++(~~>) :: HasCallStack => String -> File -> Expectation+(~~>) str res = parseString fileParser mempty (str <> "\n") `shouldBe` Success res++dropLeading :: String -> String+dropLeading str = init $ unlines $ l : (drop numSpaces <$> init ls)+  where+    (l:ls) = lines str+    numSpaces = length $ takeWhile isSpace $ last ls++main :: IO ()+main = hspec $ do+  describe "Parsing simple commands" $ do+    it "without args"+        $ [r|add_executable()|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" [] ]+    it "with leading spaces"+        $ [r|    add_executable()|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" [] ]+    it "empty line"+        $ [r||]+      ~~> File [ NonCommandElement ]+    it "empty line with spaces"+        $ "   \t  "+      ~~> File [ NonCommandElement ]+  describe "Parsing a sequence of commands" $ do+    it "without args"+        $ [r|add_executable()+             add_library()|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" []+               , CommandElement $ CommandInvocation "add_library" []+               ]+    it "with empty lines"+        $ [r|add_executable()++             add_library()|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" []+               , NonCommandElement+               , CommandElement $ CommandInvocation "add_library" []+               ]+  describe "Parsing comments" $ do+    it "parses single whole-line comment"+        $ [r|# this is a comment|]+      ~~> File [NonCommandElement]+    it "parses multiple whole-line comments"+        $ [r|# this is a comment+             # and this is a continuation|]+      ~~> File [NonCommandElement, NonCommandElement]+    it "parses end-of-line comments"+        $ [r|add_library() # this is a comment|]+      ~~> File [CommandElement $ CommandInvocation "add_library" []]+  describe "Bracket comments" $ do+    it "parses simplest empty bracket comments"+        $ [r|#[[]]|]+      ~~> File [NonCommandElement]+    it "parses zero-eq bracket comments with text"+        $ [r|#[[ foobar ]]|]+      ~~> File [NonCommandElement]+    it "parses non-zero-eq bracket comments with text"+        $ [r|#[==[ foobar ]==]|]+      ~~> File [NonCommandElement]+    it "parses non-zero-eq bracket comments with nested eqs (less)"+        $ [r|#[==[ ]=] ]==]|]+      ~~> File [NonCommandElement]+    it "parses non-zero-eq bracket comments with nested eqs (more)"+        $ [r|#[==[ ]===] ]==]|]+      ~~> File [NonCommandElement]+    it "parses multilinenon-zero-eq bracket comments"+        $ [r|#[==[ foobar+             ]=]+             fdsafsdahljkrew hjkfdshafkjlashjk+             ]===]+             ]==]|]+      ~~> File [NonCommandElement]+  describe "Parsing simple command arguments" $ do+    it "parses command with one arg"+        $ [r|add_executable(foo)|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["foo"] ]+    it "parses command with several simple args"+        $ [r|add_executable(foo bar baz)|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["foo", "bar", "baz"] ]+  describe "Parsing bracket command arguments" $ do+    it "parses command with bracket arguments"+        $ dropLeading+          [r|add_executable([==[+            This is a bracket argument+            ]==])+            |]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["\nThis is a bracket argument\n"] ]+    it "parses command with multiline bracket arguments"+        $ dropLeading+          [r|add_executable([==[+            This is a+            bracket+            argument+            ]==])+            |]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["\nThis is a\nbracket\nargument\n"] ]+    it "does not escape in bracket arguments"+        $ dropLeading+          [r|add_executable([==[+            This is \t \; \n a \- bracket argument \meh+            ]==])+            |]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["\nThis is \\t \\; \\n a \\- bracket argument \\meh\n"] ]+    it "does not expand variables in bracket arguments"+        $ dropLeading+          [r|add_executable([==[+            This is a ${bracket} argument+            ]==])+            |]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["\nThis is a ${bracket} argument\n"] ]+  describe "Parsing quoted command arguments" $ do+    it "parses command with one arg"+        $ [r|add_executable("foo")|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["foo"] ]+    it "parses command with multple args"+        $ [r|add_executable("foo" "bar")|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["foo", "bar"] ]+    it "does escaping"+        $ [r|add_executable("foo \n \; bar")|]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["foo \n ; bar"] ]+    it "parses command with multiline arg"+        $ dropLeading+          [r|add_executable("foo+             bar+             baz")+             |]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["foo\nbar\nbaz"] ]+    it "parses command with multiline arg and final line feed"+        $ dropLeading+          [r|add_executable("foo+             bar+             baz+             ")+             |]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["foo\nbar\nbaz\n"] ]+    it "parses command with single-line arg spanning multiple lines"+        $ dropLeading+          [r|add_executable("foo \+             bar \+             baz")+             |]+      ~~> File [ CommandElement $ CommandInvocation "add_executable" ["foo bar baz"] ]