module Tests.LiteralParser ( testLiteralParser ) where import Test.Hspec import Control.Monad (forM_) import Data.Char (chr, isPrint) import Language.JavaScript.Parser import Language.JavaScript.Parser.Grammar5 import Language.JavaScript.Parser.Parser testLiteralParser :: Spec testLiteralParser = describe "Parse literals:" $ do it "null/true/false" $ do testLiteral "null" `shouldBe` "Right (JSAstLiteral (JSLiteral 'null'))" testLiteral "false" `shouldBe` "Right (JSAstLiteral (JSLiteral 'false'))" testLiteral "true" `shouldBe` "Right (JSAstLiteral (JSLiteral 'true'))" it "hex numbers" $ do testLiteral "0x1234fF" `shouldBe` "Right (JSAstLiteral (JSHexInteger '0x1234fF'))" testLiteral "0X1234fF" `shouldBe` "Right (JSAstLiteral (JSHexInteger '0X1234fF'))" it "decimal numbers" $ do testLiteral "1.0e4" `shouldBe` "Right (JSAstLiteral (JSDecimal '1.0e4'))" testLiteral "2.3E6" `shouldBe` "Right (JSAstLiteral (JSDecimal '2.3E6'))" testLiteral "4.5" `shouldBe` "Right (JSAstLiteral (JSDecimal '4.5'))" testLiteral "0.7e8" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.7e8'))" testLiteral "0.7E8" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.7E8'))" testLiteral "10" `shouldBe` "Right (JSAstLiteral (JSDecimal '10'))" testLiteral "0" `shouldBe` "Right (JSAstLiteral (JSDecimal '0'))" testLiteral "0.03" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.03'))" testLiteral "0.7e+8" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.7e+8'))" testLiteral "0.7e-18" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.7e-18'))" testLiteral "1.0e+4" `shouldBe` "Right (JSAstLiteral (JSDecimal '1.0e+4'))" testLiteral "1.0e-4" `shouldBe` "Right (JSAstLiteral (JSDecimal '1.0e-4'))" testLiteral "1e18" `shouldBe` "Right (JSAstLiteral (JSDecimal '1e18'))" testLiteral "1e+18" `shouldBe` "Right (JSAstLiteral (JSDecimal '1e+18'))" testLiteral "1e-18" `shouldBe` "Right (JSAstLiteral (JSDecimal '1e-18'))" testLiteral "1E-01" `shouldBe` "Right (JSAstLiteral (JSDecimal '1E-01'))" it "octal numbers" $ do testLiteral "070" `shouldBe` "Right (JSAstLiteral (JSOctal '070'))" testLiteral "010234567" `shouldBe` "Right (JSAstLiteral (JSOctal '010234567'))" it "strings" $ do testLiteral "'cat'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral 'cat'))" testLiteral "\"cat\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"cat\"))" testLiteral "'\\u1234'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral '\\u1234'))" testLiteral "'\\uabcd'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral '\\uabcd'))" testLiteral "\"\\r\\n\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\r\\n\"))" testLiteral "\"\\b\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\b\"))" testLiteral "\"\\f\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\f\"))" testLiteral "\"\\t\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\t\"))" testLiteral "\"\\v\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\v\"))" testLiteral "\"\\0\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\0\"))" testLiteral "\"hello\\nworld\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"hello\\nworld\"))" testLiteral "'hello\\nworld'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral 'hello\\nworld'))" testLiteral "'char \n'" `shouldBe` "Left (\"lexical error @ line 1 and column 7\")" forM_ (mkTestStrings SingleQuote) $ \ str -> testLiteral str `shouldBe` ("Right (JSAstLiteral (JSStringLiteral " ++ str ++ "))") forM_ (mkTestStrings DoubleQuote) $ \ str -> testLiteral str `shouldBe` ("Right (JSAstLiteral (JSStringLiteral " ++ str ++ "))") it "strings with escaped quotes" $ do testLiteral "'\"'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral '\"'))" testLiteral "\"\\\"\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\\"\"))" data Quote = SingleQuote | DoubleQuote deriving Eq mkTestStrings :: Quote -> [String] mkTestStrings quote = map mkString [0 .. 255] where mkString :: Int -> String mkString i = quoteString $ "char #" ++ show i ++ " " ++ showCh i showCh :: Int -> String showCh ch | ch == 34 = if quote == DoubleQuote then "\\\"" else "\"" | ch == 39 = if quote == SingleQuote then "\\\'" else "'" | ch == 92 = "\\\\" | ch < 127 && isPrint (chr ch) = [chr ch] | otherwise = let str = "000" ++ show ch slen = length str in "\\" ++ drop (slen - 3) str quoteString s = if quote == SingleQuote then '\'' : (s ++ "'") else '"' : (s ++ ['"']) testLiteral :: String -> String testLiteral str = showStrippedMaybe $ parseUsing parseLiteral str "src"