diff --git a/README.md b/README.md index 3ab2adc..0bcc8f6 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,6 @@ Example `glualint.json` with the default options: "prettyprint_removeRedundantParens": true, "prettyprint_minimizeParens": false, "prettyprint_assumeOperatorAssociativity": true, - "prettyprint_rejectInvalidCode": false, "prettyprint_indentation": " ", "log_format": "auto" @@ -140,7 +139,6 @@ Option | Description `prettyprint_removeRedundantParens` | Whether to remove unnecessary parentheses (e.g. `x = (1 + 2)`, `if ((1) + (2) == 3) then`) `prettyprint_minimizeParens` | Removes parentheses which are unnecessary due to operator precedence (e.g. `(1 * 2) + 3`). This option also removes redundant parameters, regardless of whether `prettyprint_removeRedundantParens` is enabled. `prettyprint_assumeOperatorAssociativity` | Only takes effect when `prettyprint_minimizeParens` is `true`. It decides whether parameters can be removed when the involved operators are assumed associative. Examples: `a * (b * c)`, `a and (b and c)`. This assumption is generally true, except for floating point numbers, where removing parentheses can actually change the outcome of the calculation. See [Stack Overflow](https://stackoverflow.com/a/10371890). This option is set to `true` by default, because the expectation is that this will not be problematic even if it affects your code. In a very rare case, this might cause trouble, though. You might want to consider turning this off if you have floating point code that heavily relies on evaluation order. You may also choose to leave this option on and ensure evaluation order by explicitly setting variables. -`prettyprint_rejectInvalidCode` | Whether not to pretty print when the code is syntactically invalid ### Other options diff --git a/app/GLuaFixer/Effects/Run.hs b/app/GLuaFixer/Effects/Run.hs index 9d93459..480c69a 100644 --- a/app/GLuaFixer/Effects/Run.hs +++ b/app/GLuaFixer/Effects/Run.hs @@ -10,7 +10,7 @@ module GLuaFixer.Effects.Run where -import Control.Monad (unless, when) +import Control.Monad (when) import qualified Data.Aeson as JSON import qualified Data.ByteString.Lazy.Char8 as BL8 import Effectful (Eff, (:>)) @@ -20,7 +20,6 @@ import GLua.AG.AST (AST) import GLua.AG.Token (MToken) import GLua.ASTInstances () import qualified GLua.PSParser as PSP -import qualified GLua.Parser as UUP import GLuaFixer.Cli (Command (..), Options (..), OverriddenSettings, SettingsPath) import GLuaFixer.Effects.AnalyseGlobals (analyseFile, execAnalysis, reportAnalysis) import GLuaFixer.Effects.Cli (Cli, CliParseResult (..), parseCliOptions) @@ -97,7 +96,7 @@ runOptions options = worstExitCode exitCode <$> lint lintSettings filepath contents (PrettyPrint, UseStdIn) -> do (lintSettings, contents) <- getStdIn options.optsConfigFile options.optsOverridden - case prettyprint lintSettings contents of + case prettyprint lintSettings "stdin" contents of Nothing -> pure $ ExitFailure 1 Just prettyprinted -> do putStrStdOut prettyprinted @@ -110,7 +109,7 @@ runOptions options = files $ \exitCode lintSettings filepath contents -> do putStrLnStdOut $ "Pretty printing " <> filepath - case prettyprint lintSettings contents of + case prettyprint lintSettings filepath contents of Nothing -> pure $ ExitFailure 1 Just prettyprinted -> do writeFile filepath prettyprinted @@ -256,16 +255,15 @@ lint lintSettings filepath contents = do -- | Pretty print a file prettyprint :: LintSettings + -> FilePath -> String -> Maybe String -prettyprint lintSettings contents = do - if lintSettings.prettyprint_rejectInvalidCode && hasErrors - then Nothing - else Just $ Interface.prettyprint lintSettings ast +prettyprint lintSettings filepath contents = + case eAst of + Left _errors -> Nothing + Right ast -> Just $ Interface.prettyprint lintSettings ast where - (tokens, lexErrors) = Interface.lexUU lintSettings contents - (ast, parseErrors) = Interface.parseUU tokens - hasErrors = not (null lexErrors) || not (null parseErrors) + eAst = Interface.lex lintSettings filepath contents >>= Interface.parse lintSettings filepath -- | Test glualint itself against a file. TODO: Refactor this into a nicer command test @@ -277,23 +275,6 @@ test -> Eff es ExitCode test exitCode lintSettings filepath contents = do putStrLnStdOut $ "Testing " <> filepath - let - (uu_lex, uu_lex_errors) = Interface.lexUU lintSettings contents - (_uu_ast, uu_parseErrs) = Interface.parseUU uu_lex - - unless (null uu_lex_errors) $ do - putStrLnStdOut $ - "Errors when trying to lex '" - ++ filepath - ++ "' with uu-parsinglib lexer!" - mapM_ (putStrLnStdOut . show) uu_lex_errors - - unless (null uu_parseErrs) $ do - putStrLnStdOut $ - "Errors when trying to parse '" - ++ filepath - ++ "' with uu-parsinglib parser!" - mapM_ (putStrLnStdOut . show) uu_parseErrs logFormat <- getLogFormat lintSettings.log_format @@ -305,25 +286,17 @@ test exitCode lintSettings filepath contents = do case Interface.parse lintSettings filepath tokens of Left msgs -> do putStrLnStdOut $ - "Errors when trying to parse '" ++ filepath ++ "' with parsec parser!" + "Errors when trying to parse '" ++ filepath mapM_ (emitLintMessage logFormat) msgs pure $ ExitFailure 1 Right ast -> do let prettyprinted = Interface.prettyprint lintSettings ast - (_uu_ast_pp, uu_parseErrs_pp) = UUP.parseGLuaFromString prettyprinted - - unless (null uu_parseErrs_pp) $ do - putStrLnStdOut $ - "Errors when trying to parse '" - ++ filepath - ++ "' with uu-parsinglib parser after pretty print!" - mapM_ (putStrLnStdOut . show) uu_parseErrs_pp case PSP.parseGLuaFromString prettyprinted of Left err -> do putStrLnStdOut $ - "Errors when trying to parse '" ++ filepath ++ "' with parsec parser after pretty print!" + "Errors when trying to parse '" ++ filepath ++ "' after pretty print!" putStrLnStdOut $ show err pure $ ExitFailure 1 diff --git a/glualint.cabal b/glualint.cabal index 0dd7c55..90e2c3c 100644 --- a/glualint.cabal +++ b/glualint.cabal @@ -42,9 +42,7 @@ library GLua.AG.PrettyPrint GLua.AG.Token GLua.ASTInstances - GLua.Lexer GLua.LineLimitParser - GLua.Parser GLua.PSLexer GLua.PSParser GLua.TokenTypes diff --git a/src/GLua/Lexer.hs b/src/GLua/Lexer.hs deleted file mode 100644 index 8a705c4..0000000 --- a/src/GLua/Lexer.hs +++ /dev/null @@ -1,436 +0,0 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE Rank2Types #-} -{-# LANGUAGE NoMonomorphismRestriction #-} - --- | Lex GLua into MTokens -module GLua.Lexer where - -import GLua.AG.Token (MToken (..), Region (..), Token (..)) - -import Data.Char (ord) -import Text.ParserCombinators.UU ( - ExtAlternative (opt, (<<|>)), - P, - micro, - pEnd, - pErrors, - pMany, - pPos, - pReturn, - pSome, - parse, - (<$$>), - (<**>), - ) -import Text.ParserCombinators.UU.BasicInstances ( - Error, - Insertion (Insertion), - LineColPos (..), - Str, - createStr, - pMunch, - pSatisfy, - pSym, - pToken, - ) -import Text.ParserCombinators.UU.Utils (pDigit) - --- | String parser that maintains positions. -type LParser a = P (Str Char String LineColPos) a - --- | Whitespace parser that requires at least one whitespace character -parseWhitespace :: LParser String -parseWhitespace = pSome $ pSatisfy (`elem` " \r\n\t") (Insertion "Whitespace" ' ' 5) - --- | Whitespace parser that requires 0 or more whitespace characters -parseOptionalWhitespace :: LParser String -parseOptionalWhitespace = pMany $ pSatisfy (`elem` " \r\n\t") (Insertion "Whitespace" ' ' 5) - --- | Blanco parser. Parses anything. Used in parsing comments. -parseAnyChar :: LParser Char -parseAnyChar = pSatisfy (const True) (Insertion "Any character" 'y' 5) - --- See luajit's src/lj_char.c and src/lj_char.h -pIdentifierCharacter :: LParser Char -pIdentifierCharacter = pSatisfy validChar (Insertion "Identifying character (letter, number, emoji)" 'a' 5) - where - validChar :: Char -> Bool - validChar c = - between c '0' '9' - || between c 'A' 'Z' - || c == '_' - || between c 'a' 'z' - || ord c >= 128 - -pNonDigitIdentifierCharacter :: LParser Char -pNonDigitIdentifierCharacter = pSatisfy validChar (Insertion "Identifying character (letter, emoji)" 'a' 5) - where - validChar :: Char -> Bool - validChar c = - between c 'A' 'Z' - || c == '_' - || between c 'a' 'z' - || ord c >= 128 - -between :: Char -> Char -> Char -> Bool -between c left right = c >= left && c <= right - --- | Parses a C-style block comment. -parseCBlockComment :: LParser String -parseCBlockComment = - const "" - <$> pToken "*/" - <<|> (:) - <$> parseAnyChar - <*> parseCBlockComment - --- | Try to parse a block comment. --- Might actually return a single line Dash comment, because for example --- the following line is a line comment, rather than a block comment --- [===== <- missing the last '[' bracket. -parseBlockComment :: LParser Token -parseBlockComment = pToken "[" *> nested 0 - where - -- The amount of =-signs in the string delimiter is n - nested :: Int -> LParser Token - nested n = - pToken "=" - *> nested (n + 1) - <<|> DashBlockComment n - <$ pToken "[" - <*> restString n - <<|> lineComment n - <$> pUntilEnd - - -- Turns out we were describing a line comment all along, cheeky bastard! - -- (the last [ of the block comment start token is missing) - lineComment :: Int -> String -> Token - lineComment n str = DashComment $ '[' : replicate n '=' ++ str - - -- Right-recursive grammar. This part searches for the rest of the string until it finds the ]=^n] token - restString :: Int -> LParser String - restString n = - const "" - <$> pToken ("]" ++ replicate n '=' ++ "]") - <<|> (:) - <$> parseAnyChar - <*> restString n - --- | Parse the string until the end. Used in parseLineComment among others. -pUntilEnd :: LParser String -pUntilEnd = pMunch (\c -> c /= '\n' && c /= '\r') - --- | A comment that spans until the end of the line. -parseLineComment :: String -> LParser String -parseLineComment prefix = flip const <$> pToken prefix <*> pUntilEnd - --- | Parses a multiline string except for its first character (e.g. =[ string ]=]) --- This is because the first [ could also just be parsed as a square bracket. -nestedString :: LParser String -nestedString = nested 0 - where - -- The amount of =-signs in the string delimiter is n - nested :: Int -> LParser String - nested n = - (\str -> "=" ++ str) - <$ pToken "=" - <*> nested (n + 1) - <<|> ('[' :) - <$ pToken "[" - <*> restString n - - -- Right-recursive grammar. This part searches for the rest of the string until it finds the ]=^n] token - restString :: Int -> LParser String - restString n = - pToken ("]" ++ replicate n '=' ++ "]") - <<|> (:) - <$> parseAnyChar - <*> restString n - --- | Parse any kind of comment. -parseComment :: LParser Token -parseComment = - pToken "--" - <**> (const <$> (parseBlockComment <<|> DashComment <$> pUntilEnd)) -- Dash block comment and dash comment both start with "--" - <<|> pToken "/" - <**> ( const - <$> ( SlashBlockComment - <$ pToken "*" - <*> parseCBlockComment - <<|> SlashComment - <$> parseLineComment "/" - <<|> pReturn Divide -- The /-sign is here because it also starts with '/' - ) - ) - --- | Parse single line strings e.g. "sdf", 'werf'. -parseLineString :: Char -> LParser String -parseLineString c = pSym c *> innerString - where - innerString :: LParser String - innerString = - pSym '\\' - <**> ((\c' str esc -> esc : c' ++ str) <$> escapeSequence <*> innerString) -- Escaped character in string always starts with backslash - <<|> const "" - <$> pSym c - <<|> (:) - <$> pNoNewline - <*> innerString -- the end of the string - -- the next character in the string - escapeSequence :: LParser String - escapeSequence = (:) <$> pSym 'z' <*> parseOptionalWhitespace <<|> (: []) <$> parseAnyChar - - pNoNewline :: LParser Char - pNoNewline = pSatisfy (/= '\n') (Insertion "Anything but a newline" c 5) - --- | Single and multiline strings. -parseString :: LParser Token -parseString = - DQString - <$> parseLineString '"' - <<|> SQString - <$> parseLineString '\'' - <<|> - -- Parse either a multiline string or just a bracket. - -- Placed here because they have the first token '[' in common - pSym '[' - <**> ( (\_ -> MLString . (:) '[') - <$$> nestedString - <<|> const - <$> pReturn LSquare - ) - --- | Parse any kind of number. -parseNumber :: LParser Token -parseNumber = TNumber <$> ((++) <$> (pZeroPrefixedNumber <<|> pNumber) <*> (pLLULL <<|> opt parseNumberSuffix "")) - where - -- Numbers starting with 0 can be regular numbers, hexadecimals or binary - pZeroPrefixedNumber :: LParser String - pZeroPrefixedNumber = - pSym '0' - <**> ( (\hex _0 -> _0 : hex) - <$> pHexadecimal - <<|> (\bin _0 -> _0 : bin) - <$> pBinary - <<|> (\digits _0 -> _0 : digits) - <$> (pDecimal <<|> pNumber) - <<|> pure (: []) - ) - - pNumber :: LParser String - pNumber = (++) <$> pSome pDigit <*> opt pDecimal "" - - pDecimal :: LParser String - pDecimal = (:) <$> pSym '.' <*> pMany pDigit - - pHexDecimal :: LParser String - pHexDecimal = (:) <$> pSym '.' <*> pMany pHex - - pHexadecimal :: LParser String - pHexadecimal = (:) <$> (pSym 'x' <<|> pSym 'X') <*> ((++) <$> pSome pHex <*> opt pHexDecimal "") - - pBinary :: LParser String - pBinary = (:) <$> (pSym 'b' <<|> pSym 'B') <*> ((++) <$> pSome pBin <*> opt pDecimal "") - - pHex :: LParser Char - pHex = - pDigit - <<|> pSym 'a' - <<|> pSym 'b' - <<|> pSym 'c' - <<|> pSym 'd' - <<|> pSym 'e' - <<|> pSym 'f' - <<|> pSym 'A' - <<|> pSym 'B' - <<|> pSym 'C' - <<|> pSym 'D' - <<|> pSym 'E' - <<|> pSym 'F' - - pBin :: LParser Char - pBin = pSym '0' <<|> pSym '1' - - -- LL/ULL suffix of a number, making it signed/unsigned int64 respectively - -- http://luajit.org/ext_ffi_api.html#literals - pLLULL :: LParser String - pLLULL = pULL <<|> pLL - - pLL :: LParser String - pLL = "LL" <$ (pSym 'L' <<|> pSym 'l') <* (pSym 'L' <<|> pSym 'l') - - pULL :: LParser String - pULL = "ULL" <$ (pSym 'U' <<|> pSym 'u') <* pLL - --- Parse the suffix of a number -parseNumberSuffix :: LParser String -parseNumberSuffix = imaginary <<|> extension - where - imaginary = (: []) <$> (pSym 'i' <<|> pSym 'I') - - extension = - (\e s d -> e : s ++ d) - <$> (pSym 'e' <<|> pSym 'E' <<|> pSym 'p' <<|> pSym 'P') - <*> opt (pToken "+" <<|> pToken "-") "" - <*> pSome pDigit - --- | Parse a keyword. Note: It must really a key/word/! This parser makes sure to return an identifier when --- it's actually an identifier that starts with that keyword. -parseKeyword :: Token -> String -> LParser Token -parseKeyword tok word = - pToken word - <**> ((\k -> Identifier . (++) k) <$$> pSome pIdentifierCharacter <<|> const <$> pReturn tok) - --- | Parse just an identifier. -parseIdentifier :: LParser String -parseIdentifier = (:) <$> pNonDigitIdentifierCharacter <*> pMany pIdentifierCharacter - --- | Parse a label. -parseLabel :: LParser Token -parseLabel = - Label - <$ pToken "::" - <*> parseOptionalWhitespace - <*> parseIdentifier - <*> parseOptionalWhitespace - <* pToken "::" - --- | Parse anything to do with dots. Indexaction (.), concatenation (..) or varargs (...) -parseDots :: LParser Token -parseDots = - pToken "." - <**> ( -- A dot means it's either a VarArg (...), concatenation (..) or just a dot (.) - const - <$> ( pToken "." - <**> ( const VarArg - <$ pToken "." - <<|> const - <$> pReturn Concatenate - ) - ) - <<|> (\ds sfx dot -> TNumber $ dot ++ ds ++ sfx) - <$> pSome pDigit - <*> opt parseNumberSuffix "" - <<|> const - <$> pReturn Dot - ) - --- | Parse any kind of token. -parseToken :: LParser Token -parseToken = - parseComment - <<|> - -- Constants - parseString - <<|> parseNumber - <<|> parseKeyword TTrue "true" - <<|> parseKeyword TFalse "false" - <<|> parseKeyword Nil "nil" - <<|> parseKeyword Not "not" - <<|> parseKeyword And "and" - <<|> parseKeyword Or "or" - <<|> parseKeyword Function "function" - <<|> parseKeyword Local "local" - <<|> parseKeyword If "if" - <<|> parseKeyword Then "then" - <<|> parseKeyword Elseif "elseif" - <<|> parseKeyword Else "else" - <<|> parseKeyword For "for" - <<|> parseKeyword In "in" - <<|> parseKeyword Do "do" - <<|> parseKeyword While "while" - <<|> parseKeyword Until "until" - <<|> parseKeyword Repeat "repeat" - <<|> parseKeyword Continue "continue" - <<|> parseKeyword Break "break" - <<|> parseKeyword Return "return" - <<|> parseKeyword End "end" - <<|> Identifier - <$> parseIdentifier - <<|> Semicolon - <$ pToken ";" - <<|> parseDots - <<|> - -- Operators - Plus - <$ pToken "+" - <<|> Minus - <$ pToken "-" - <<|> Multiply - <$ pToken "*" - <<|> Modulus - <$ pToken "%" - <<|> Power - <$ pToken "^" - <<|> TEq - <$ pToken "==" - <<|> Equals - <$ pToken "=" - <<|> TNEq - <$ pToken "~=" - <<|> TCNEq - <$ pToken "!=" - <<|> CNot - <$ pToken "!" - <<|> TLEQ - <$ pToken "<=" - <<|> TLT - <$ pToken "<" - <<|> TGEQ - <$ pToken ">=" - <<|> TGT - <$ pToken ">" - <<|> parseLabel - <<|> Colon - <$ pToken ":" - <<|> Comma - <$ pToken "," - <<|> Hash - <$ pToken "#" - `micro` 10 - <<|> CAnd -- Add micro cost to prevent conflict with parseHashBang - <$ pToken "&&" - <<|> COr - <$ pToken "||" - <<|> LRound - <$ pToken "(" - <<|> RRound - <$ pToken ")" - <<|> LCurly - <$ pToken "{" - <<|> RCurly - <$ pToken "}" - <<|> - -- Other square bracket is parsed in parseString - RSquare - <$ pToken "]" - <<|> Whitespace - <$> parseWhitespace - --- | A thing of which the region is to be parsed -annotated :: (Region -> a -> b) -> LParser a -> LParser b -annotated f p = (\s t e -> f (Region s e) t) <$> pPos <*> p <*> pPos - --- | parse located MToken -parseMToken :: LParser MToken -parseMToken = annotated MToken parseToken - --- | Parse a list of tokens and turn them into MTokens. -parseTokens :: LParser [MToken] -parseTokens = pMany parseMToken - --- | Parse the potential #!comment on the first line --- Lua ignores the first line if it starts with # -parseHashBang :: LParser String -parseHashBang = opt (pToken "#" <* pUntilEnd) "" - --- | Lex a string with a given lexer -lexFromString :: LParser a -> String -> (a, [Error LineColPos]) -lexFromString p = parse ((,) <$> p <*> pErrors <* pEnd) . createStr (LineColPos 0 0 0) - --- | Parse a string into MTokens. Also returns parse errors. -execParseTokens :: String -> ([MToken], [Error LineColPos]) -execParseTokens = parse ((,) <$ parseHashBang <*> parseTokens <*> pErrors <* pEnd) . createStr (LineColPos 0 0 0) diff --git a/src/GLua/PSParser.hs b/src/GLua/PSParser.hs index 8b4b2d0..6c945c6 100644 --- a/src/GLua/PSParser.hs +++ b/src/GLua/PSParser.hs @@ -30,7 +30,7 @@ import GLua.AG.Token ( Region (..), Token (..), ) -import qualified GLua.Lexer as Lex +import qualified GLua.PSLexer as Lex import GLua.TokenTypes ( isWhitespace, mpos, @@ -77,10 +77,6 @@ type AParser = Parsec [MToken] LineColPos execAParser :: SourceName -> AParser a -> [MToken] -> Either ParseError a execAParser name p = runParser p (LineColPos 0 0 0) name --- | Parse a string directly -parseFromString :: AParser a -> String -> Either ParseError a -parseFromString p = execAParser "source.lua" p . filter (not . isWhitespace) . fst . Lex.execParseTokens - -- | Parse Garry's mod Lua tokens to an abstract syntax tree. -- Also returns parse errors parseGLua :: [MToken] -> Either ParseError AST @@ -92,7 +88,9 @@ parseGLua mts = parseGLuaFromString :: String -> Either ParseError AST parseGLuaFromString contents = - parseGLua $ filter (not . isWhitespace) $ fst $ Lex.execParseTokens contents + case Lex.execParseTokens contents of + Left parseErrors -> Left parseErrors + Right lexicon -> parseGLua $ filter (not . isWhitespace) lexicon -- | Region start to SourcePos rgStart2sp :: Region -> SourcePos diff --git a/src/GLua/Parser.hs b/src/GLua/Parser.hs deleted file mode 100644 index 87ead69..0000000 --- a/src/GLua/Parser.hs +++ /dev/null @@ -1,660 +0,0 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE Rank2Types #-} -{-# LANGUAGE NoMonomorphismRestriction #-} - --- | Parser based on -module GLua.Parser where - -import GLua.AG.AST -import GLua.AG.Token -import qualified GLua.Lexer as Lex -import GLua.TokenTypes - -import Text.ParserCombinators.UU -import Text.ParserCombinators.UU.BasicInstances - --- | MTokens with the positions of the next MToken (used in the advance of parser) -data MTokenPos = MTokenPos MToken Region - -data RegionProgression = RegionProgression {lastRegion :: Region, nextRegion :: Region} - deriving (Show) - -emptyRgPrgs :: RegionProgression -emptyRgPrgs = RegionProgression emptyRg emptyRg - -instance Show MTokenPos where - show (MTokenPos tok _) = show tok - --- | Custom parser that parses MTokens -type AParser a = P (Str MTokenPos [MTokenPos] RegionProgression) a - --- | RegionProgression is a location that can be updated by MTokens -instance IsLocationUpdatedBy RegionProgression MTokenPos where - -- advance :: RegionProgression -> MToken -> RegionProgression - -- Assume the position of the next MToken - advance _ (MTokenPos mt p) = RegionProgression (mpos mt) p - -resultsToRegion :: (a, [Error RegionProgression]) -> (a, [Error Region]) -resultsToRegion (a, errs) = (a, map errorToRegion errs) - --- | Parse Garry's mod Lua tokens to an abstract syntax tree. --- Also returns parse errors -parseGLua :: [MToken] -> (AST, [Error Region]) -parseGLua mts = - let - (cms, ts) = splitComments . filter (not . isWhitespace) $ mts - in - resultsToRegion $ execAParser (parseChunk cms) ts - --- | Parse a string directly into an AST -parseGLuaFromString :: String -> (AST, [Error Region]) -parseGLuaFromString = parseGLua . filter (not . isWhitespace) . fst . Lex.execParseTokens - --- | Parse a string directly -parseFromString :: AParser a -> String -> (a, [Error Region]) -parseFromString p = resultsToRegion . execAParser p . filter (not . isWhitespace) . fst . Lex.execParseTokens - --- | Create a parsable string from MTokens -createString :: [MToken] -> Str MTokenPos [MTokenPos] RegionProgression -createString [] = createStr emptyRgPrgs [] -createString mts@(MToken p _ : xs) = createStr (RegionProgression p (nextRg mts')) mtpos - where - mts' = xs ++ [last mts] -- Repeat last element of mts - mkMtPos mt (MToken p' _) = MTokenPos mt p' - mtpos = zipWith mkMtPos mts mts' - - nextRg (MToken p' _ : _) = p' - nextRg [] = undefined - -errorToRegion :: Error RegionProgression -> Error Region -errorToRegion (Inserted a p b) = Inserted a (nextRegion p) b -errorToRegion (Deleted a p b) = Deleted a (nextRegion p) b -errorToRegion (Replaced a b p c) = Replaced a b (nextRegion p) c -errorToRegion (DeletedAtEnd s) = DeletedAtEnd s - --- | Position in Region (as opposed to RegionProgression) -pPos' :: AParser Region -pPos' = nextRegion <$> pPos - --- | Text.ParserCombinators.UU.Utils.execParser modified to parse MTokens --- The first MToken might not be on the first line, so use the first MToken's position to start -execAParser :: AParser a -> [MToken] -> (a, [Error RegionProgression]) -execAParser p mts@[] = parse_h ((,) <$> p <*> pEnd) . createString $ mts -execAParser p mts@(_ : _) = parse_h ((,) <$> p <*> pEnd) . createString $ mts -- createStr (mpos m) $ mts - -pMSatisfy :: (MToken -> Bool) -> Token -> String -> AParser MToken -pMSatisfy f t ins = getToken <$> pSatisfy f' (Insertion ins (MTokenPos (MToken ep t) ep) 5) - where - f' :: MTokenPos -> Bool - f' (MTokenPos tok _) = f tok - - getToken :: MTokenPos -> MToken - getToken (MTokenPos t' _) = t' - - ep = Region (LineColPos 0 0 0) (LineColPos 0 0 0) - --- | Parse a single Metatoken, based on a positionless token (much like pSym) -pMTok :: Token -> AParser MToken -pMTok t = pMSatisfy isToken t $ "'" ++ show t ++ "'" - where - isToken :: MToken -> Bool - isToken (MToken _ tok) = t == tok - --- | Parse a list of identifiers -parseNameList :: AParser [MToken] -parseNameList = (:) <$> pName <*> pMany (pMTok Comma *> pName) - --- | Parse list of function parameters -parseParList :: AParser [MToken] -parseParList = - (pMTok VarArg <<|> pName) - <**> ( pMTok Comma - <**> ( (\a _ c -> [c, a]) - <$> pMTok VarArg - <<|> (\a _ c -> c : a) - <$> parseParList - ) - `opt` (: []) - ) - `opt` [] - --- | Parses the full AST --- Its first parameter contains all comments --- Assumes the mtokens fed to the AParser have no comments -parseChunk :: [MToken] -> AParser AST -parseChunk cms = AST cms <$> parseBlock - --- | Parse a block with an optional return value -parseBlock :: AParser Block -parseBlock = Block <$> pInterleaved (pMTok Semicolon) parseMStat <*> (parseReturn <<|> pReturn NoReturn) - --- | A thing of which the region is to be parsed -annotated :: (Region -> a -> b) -> AParser a -> AParser b -annotated f p = (\s t e -> f (Region (rgStart s) (rgEnd $ lastRegion $ pos $ e)) t) <$> pPos' <*> p <*> pState - -parseMStat :: AParser MStat -parseMStat = annotated MStat parseStat - --- | Parser that is interleaved with 0 or more of the other parser -pInterleaved :: AParser a -> AParser b -> AParser [b] -pInterleaved sep q = pMany sep *> pMany (q <* pMany sep) - --- | Behemoth parser that parses either function call statements or global declaration statements --- Big in size and complexity because prefix expressions are BITCHES --- The problem lies in the complexity of prefix expressions: --- hotten.totten["tenten"](tentoonstelling) -- This is a function call --- hotten.totten["tenten"] = tentoonstelling -- This is a declaration. --- hotten.totten["tenten"], tentoonstelling = 1, 2 -- This is also a declaration. --- One may find an arbitrary amount of expression suffixes (indexations/calls) before --- finding a comma or equals sign that proves that it is a declaration. --- Also, goto can be an identifier -parseCallDef :: AParser Stat -parseCallDef = - parseGoto - <<|> ( PFVar - <$> pName - <<|> ExprVar - <$ pMTok LRound - <*> parseExpression - <* pMTok RRound -- Statemens begin with either a simple name or parenthesised expression - ) - <**> ( - -- Either there are more suffixes yet to be found (contSearch) - -- or there aren't and we will find either a comma or =-sign (varDecl namedVarDecl) - contSearch - <<|> varDecl namedVarDecl - ) - where - -- Try to parse a goto statement - parseGoto :: AParser Stat - parseGoto = - (PFVar <$> pMTok (Identifier "goto")) - <**> ( (\n _ -> AGoto n) - <$> pName - <<|> contSearch - <<|> varDecl namedVarDecl - ) - - -- Simple direct declaration: varName, ... = 1, ... - namedVarDecl :: [PrefixExp] -> [MExpr] -> (ExprSuffixList -> PrefixExp) -> Stat - namedVarDecl vars exprs pfe = let pfes = (pfe []) : vars in Def (zip pfes $ map Just exprs ++ repeat Nothing) - - -- This is where we know it's a variable declaration - -- Takes a function that turns it into a proper Def Stat - varDecl :: ([PrefixExp] -> [MExpr] -> b) -> AParser b - varDecl f = - f - <$> opt (pMTok Comma *> parseVarList) [] - <* pMTok Equals - <*> parseExpressionList - - -- We know that there is at least one suffix (indexation or call). - -- Search for more suffixes and make either a call or declaration from it - contSearch :: AParser ((ExprSuffixList -> PrefixExp) -> Stat) - contSearch = (\(ss, mkStat) pfe -> mkStat $ pfe ss) <$> searchDeeper - - -- We either find a call suffix or an indexation suffix - -- When it's a function call, try searching for more suffixes, if that doesn't work, it's a function call. - -- When it's an indexation suffix, search for more suffixes or know that it's a declaration. - searchDeeper :: AParser ([PFExprSuffix], PrefixExp -> Stat) - searchDeeper = - (pPFExprCallSuffix <**> (mergeDeeperSearch <$> searchDeeper <<|> pReturn (\s -> ([s], AFuncCall)))) - <<|> (pPFExprIndexSuffix <**> (mergeDeeperSearch <$> searchDeeper <<|> varDecl complexDecl)) - - -- Merge the finding of more suffixes with the currently found suffix - mergeDeeperSearch :: ([PFExprSuffix], PrefixExp -> Stat) -> PFExprSuffix -> ([PFExprSuffix], PrefixExp -> Stat) - mergeDeeperSearch (ss, f) s = (s : ss, f) - - -- Multiple suffixes have been found, and proof has been found that this must be a declaration. - -- Now to give all the collected suffixes and a function that creates the declaration - complexDecl :: [PrefixExp] -> [MExpr] -> PFExprSuffix -> ([PFExprSuffix], PrefixExp -> Stat) - complexDecl vars exprs s = ([s], \pf -> Def (zip (pf : vars) $ map Just exprs ++ repeat Nothing)) - --- | Parse a single statement -parseStat :: AParser Stat -parseStat = - parseCallDef - <<|> ALabel - <$> parseLabel - <<|> ABreak - <$ pMTok Break - <<|> AContinue - <$ pMTok Continue - <<|> - -- AGoto <$ pMTok (Identifier "goto") <*> pName <|> - ADo - <$ pMTok Do - <*> parseBlock - <* pMTok End - <<|> AWhile - <$ pMTok While - <*> parseExpression - <* pMTok Do - <*> parseBlock - <* pMTok End - <<|> ARepeat - <$ pMTok Repeat - <*> parseBlock - <* pMTok Until - <*> parseExpression - <<|> parseIf - <<|> parseFor - <<|> AFunc - <$ pMTok Function - <*> parseFuncName - <*> pPacked (pMTok LRound) (pMTok RRound) parseParList - <*> parseBlock - <* pMTok End - <<|> - -- local function and local vars both begin with "local" - pMTok Local - <**> ( - -- local function - (\n p b _l -> ALocFunc n p b) - <$ pMTok Function - <*> parseLocFuncName - <*> pPacked (pMTok LRound) (pMTok RRound) parseParList - <*> parseBlock - <* pMTok End - <<|> - -- local variables - (\v (_p, e) _l -> LocDef (zip v $ map Just e ++ repeat Nothing)) - <$> parseLocalVarList - <*> ((,) <$ pMTok Equals <*> pPos' <*> parseExpressionList <<|> (,) <$> pPos' <*> pReturn []) - ) - --- | Parse if then elseif then else end expressions -parseIf :: AParser Stat -parseIf = - AIf - <$ pMTok If - <*> parseExpression - <* pMTok Then - <*> parseBlock - <*> - -- elseif - pMany (annotated MElseIf $ (,) <$ pMTok Elseif <*> parseExpression <* pMTok Then <*> parseBlock) - <*> - -- else - optional (annotated MElse $ pMTok Else *> parseBlock) - <* pMTok End - --- | Parse numeric and generic for loops -parseFor :: AParser Stat -parseFor = do - pMTok For - firstName <- pName - -- If you see an =-sign, it's a numeric for loop. It'll be a generic for loop otherwise - isNumericLoop <- (const True <$> pMTok Equals <<|> const False <$> pReturn ()) - if isNumericLoop - then do - startExp <- parseExpression - pMTok Comma - toExp <- parseExpression - step <- pMTok Comma *> parseExpression <<|> MExpr <$> pPos' <*> pReturn (ANumber "1") - pMTok Do - block <- parseBlock - pMTok End - pReturn $ ANFor firstName startExp toExp step block - else do - vars <- (:) firstName <$ pMTok Comma <*> parseNameList <<|> pReturn [firstName] - pMTok In - exprs <- parseExpressionList - pMTok Do - block <- parseBlock - pMTok End - pReturn $ AGFor vars exprs block - --- | Parse a return value -parseReturn :: AParser AReturn -parseReturn = AReturn <$> pPos' <* pMTok Return <*> opt parseExpressionList [] <* pMany (pMTok Semicolon) - --- | Label -parseLabel :: AParser MToken -parseLabel = pMSatisfy isLabel (Label "" "someLabel" "") "Some label" - where - isLabel :: MToken -> Bool - isLabel (MToken _ (Label{})) = True - isLabel _ = False - --- | Function name (includes dot indices and meta indices) -parseFuncName :: AParser FuncName -parseFuncName = - (\a b c -> FuncName (a : b) c) - <$> pName - <*> pMany (pMTok Dot *> pName) - <*> opt (Just <$ pMTok Colon <*> pName) Nothing - --- | Local function name. Does not include dot and meta indices, since they're not allowed in meta functions -parseLocFuncName :: AParser FuncName -parseLocFuncName = (\a -> FuncName [a] Nothing) <$> pName - --- | Parse a number into an expression -parseNumber :: AParser Expr -parseNumber = toAnumber <$> pMSatisfy isNumber (TNumber "0") "Number" - where - isNumber :: MToken -> Bool - isNumber (MToken _ (TNumber _)) = True - isNumber _ = False - - -- A better solution would be to have a single `MToken -> Maybe Expr` function, but I am too - -- lazy to write that. - toAnumber :: MToken -> Expr - toAnumber = \case - (MToken _ (TNumber str)) -> ANumber str - _ -> error "unreachable" - --- | Parse any kind of string -parseString :: AParser MToken -parseString = pMSatisfy isString (DQString "someString") "String" - where - isString :: MToken -> Bool - isString (MToken _ (DQString _)) = True - isString (MToken _ (SQString _)) = True - isString (MToken _ (MLString _)) = True - isString _ = False - --- | Parse an identifier -pName :: AParser MToken -pName = pMSatisfy isName (Identifier "someVariable") "Variable" - where - isName :: MToken -> Bool - isName (MToken _ (Identifier _)) = True - isName _ = False - --- | Parse variable list (var1, var2, var3) -parseVarList :: AParser [PrefixExp] -parseVarList = pList1Sep (pMTok Comma) parseVar - --- | Parse local variable list (var1, var2, var3), without suffixes -parseLocalVarList :: AParser [PrefixExp] -parseLocalVarList = pList1Sep (pMTok Comma) (PFVar <$> pName <*> pure []) - --- | list of expressions -parseExpressionList :: AParser [MExpr] -parseExpressionList = pList1Sep (pMTok Comma) parseExpression - --- | Subexpressions, i.e. without operators -parseSubExpression :: AParser Expr -parseSubExpression = - ANil - <$ pMTok Nil - <<|> AFalse - <$ pMTok TFalse - <<|> ATrue - <$ pMTok TTrue - <<|> parseNumber - <<|> AString - <$> parseString - <<|> AVarArg - <$ pMTok VarArg - <<|> parseAnonymFunc - <<|> APrefixExpr - <$> parsePrefixExp - <<|> ATableConstructor - <$> parseTableConstructor - --- | Separate parser for anonymous function subexpression -parseAnonymFunc :: AParser Expr -parseAnonymFunc = - AnonymousFunc - <$ pMTok Function - <*> pPacked (pMTok LRound) (pMTok RRound) parseParList - <*> parseBlock - <* pMTok End - --- | Parse operators of the same precedence in a chain -samePrioL :: [(Token, BinOp)] -> AParser MExpr -> AParser MExpr -samePrioL ops pr = pChainl (choice (map f ops)) pr - where - choice = foldr (<<|>) pFail - f :: (Token, BinOp) -> AParser (MExpr -> MExpr -> MExpr) - f (t, at) = (\p e1 e2 -> MExpr p (BinOpExpr at e1 e2)) <$> pPos' <* pMTok t - -samePrioR :: [(Token, BinOp)] -> AParser MExpr -> AParser MExpr -samePrioR ops pr = pChainr (choice (map f ops)) pr - where - choice = foldr (<<|>) pFail - f :: (Token, BinOp) -> AParser (MExpr -> MExpr -> MExpr) - f (t, at) = (\p e1 e2 -> MExpr p (BinOpExpr at e1 e2)) <$> pPos' <* pMTok t - --- | Parse unary operator (-, not, #) -parseUnOp :: AParser UnOp -parseUnOp = - UnMinus - <$ pMTok Minus - <<|> ANot - <$ pMTok Not - <<|> ANot - <$ pMTok CNot - <<|> AHash - <$ pMTok Hash - --- | Operators, sorted by priority --- Priority from: http://www.lua.org/manual/5.2/manual.html#3.4.7 -lvl1, lvl2, lvl3, lvl4, lvl5, lvl6, lvl8 :: [(Token, BinOp)] -lvl1 = [(Or, AOr), (COr, AOr)] -lvl2 = [(And, AAnd), (CAnd, AAnd)] -lvl3 = [(TLT, ALT), (TGT, AGT), (TLEQ, ALEQ), (TGEQ, AGEQ), (TNEq, ANEq), (TCNEq, ANEq), (TEq, AEq)] -lvl4 = [(Concatenate, AConcatenate)] -lvl5 = [(Plus, APlus), (Minus, BinMinus)] -lvl6 = [(Multiply, AMultiply), (Divide, ADivide), (Modulus, AModulus)] --- lvl7 is unary operators -lvl8 = [(Power, APower)] - --- | Parse chains of binary and unary operators -parseExpression :: AParser MExpr -parseExpression = - samePrioL lvl1 $ - samePrioL lvl2 $ - samePrioL lvl3 $ - samePrioR lvl4 $ - samePrioL lvl5 $ - samePrioL lvl6 $ - MExpr - <$> pPos' - <*> (UnOpExpr <$> parseUnOp <*> parseExpression) - <<|> samePrioR lvl8 (MExpr <$> pPos' <*> (parseSubExpression <|> UnOpExpr <$> parseUnOp <*> parseExpression)) -- lvl7 - --- | Parses a binary operator -parseBinOp :: AParser BinOp -parseBinOp = - const AOr - <$> pMTok Or - <<|> const AOr - <$> pMTok COr - <<|> const AAnd - <$> pMTok And - <<|> const AAnd - <$> pMTok CAnd - <<|> const ALT - <$> pMTok TLT - <<|> const AGT - <$> pMTok TGT - <<|> const ALEQ - <$> pMTok TLEQ - <<|> const AGEQ - <$> pMTok TGEQ - <<|> const ANEq - <$> pMTok TNEq - <<|> const ANEq - <$> pMTok TCNEq - <<|> const AEq - <$> pMTok TEq - <<|> const AConcatenate - <$> pMTok Concatenate - <<|> const APlus - <$> pMTok Plus - <<|> const BinMinus - <$> pMTok Minus - <<|> const AMultiply - <$> pMTok Multiply - <<|> const ADivide - <$> pMTok Divide - <<|> const AModulus - <$> pMTok Modulus - <<|> const APower - <$> pMTok Power - --- | Prefix expressions --- can have any arbitrary list of expression suffixes -parsePrefixExp :: AParser PrefixExp -parsePrefixExp = pPrefixExp (pMany pPFExprSuffix) - --- | Prefix expressions --- The suffixes define rules on the allowed suffixes -pPrefixExp :: AParser [PFExprSuffix] -> AParser PrefixExp -pPrefixExp suffixes = - PFVar - <$> pName - <*> suffixes - <<|> ExprVar - <$ pMTok LRound - <*> parseExpression - <* pMTok RRound - <*> suffixes - --- | Parse any expression suffix -pPFExprSuffix :: AParser PFExprSuffix -pPFExprSuffix = pPFExprCallSuffix <<|> pPFExprIndexSuffix - --- | Parse an indexing expression suffix -pPFExprCallSuffix :: AParser PFExprSuffix -pPFExprCallSuffix = - Call - <$> parseArgs - <<|> MetaCall - <$ pMTok Colon - <*> pName - <*> parseArgs - --- | Parse an indexing expression suffix -pPFExprIndexSuffix :: AParser PFExprSuffix -pPFExprIndexSuffix = - ExprIndex - <$ pMTok LSquare - <*> parseExpression - <* pMTok RSquare - <<|> DotIndex - <$ pMTok Dot - <*> pName - --- | Function calls are prefix expressions, but the last suffix MUST be either a function call or a metafunction call -pFunctionCall :: AParser PrefixExp -pFunctionCall = pPrefixExp suffixes - where - suffixes = - concat - <$> pSome - ( (\ix c -> ix ++ [c]) - <$> pSome pPFExprIndexSuffix - <*> pPFExprCallSuffix - <<|> (: []) - <$> pPFExprCallSuffix - ) - --- | single variable. Note: definition differs from reference to circumvent the left recursion --- var ::= Name [{PFExprSuffix}* indexation] | '(' exp ')' {PFExprSuffix}* indexation --- where "{PFExprSuffix}* indexation" is any arbitrary sequence of prefix expression suffixes that end with an indexation -parseVar :: AParser PrefixExp -parseVar = pPrefixExp suffixes - where - suffixes = - concat - <$> pMany - ( (\c ix -> c ++ [ix]) - <$> pSome pPFExprCallSuffix - <*> pPFExprIndexSuffix - <<|> (: []) - <$> pPFExprIndexSuffix - ) - --- | Arguments of a function call (including brackets) -parseArgs :: AParser Args -parseArgs = - ListArgs - <$ pMTok LRound - <*> opt parseExpressionList [] - <* pMTok RRound - <<|> TableArg - <$> parseTableConstructor - <<|> StringArg - <$> parseString - --- | Table constructor -parseTableConstructor :: AParser [Field] -parseTableConstructor = pMTok LCurly *> parseFieldList <* pMTok RCurly - --- | A list of table entries --- Grammar: field {separator field} [separator] -parseFieldList :: AParser [Field] -parseFieldList = - parseField - <**> ( parseFieldSep - <**> ((\rest sep field -> field sep : rest) <$> (parseFieldList <<|> pure [])) - <<|> pure (\field -> [field NoSep]) - ) - <<|> pure [] - --- | Makes an unnamed field out of a list of suffixes, a position and a name. --- This function gets called when we know a field is unnamed and contains an expression that --- starts with a PrefixExp --- See the parseField parser where it is used -makeUnNamedField :: Maybe (BinOp, MExpr) -> ExprSuffixList -> (Region, MToken) -> (FieldSep -> Field) -makeUnNamedField Nothing sfs (p, nm) = UnnamedField $ MExpr p $ APrefixExpr $ PFVar nm sfs -makeUnNamedField (Just (op, mexpr)) sfs (p, nm) = UnnamedField $ MExpr p $ (merge (APrefixExpr $ PFVar nm sfs) mexpr) - where - -- Merge the first prefixExpr into the expression tree - merge :: Expr -> MExpr -> Expr - merge pf e@(MExpr _ (BinOpExpr op' l r)) = - if op > op' - then BinOpExpr op' (MExpr p $ (merge pf l)) r - else BinOpExpr op (MExpr p pf) e - merge pf e = BinOpExpr op (MExpr p pf) e - --- | A field in a table -parseField :: AParser (FieldSep -> Field) -parseField = - ExprField - <$ pMTok LSquare - <*> parseExpression - <* pMTok RSquare - <* pMTok Equals - <*> parseExpression - <<|> ( (,) - <$> pPos' - <*> pName - <**> - -- Named field has equals sign immediately after the name - ( ((\e (_, n) -> NamedField n e) <$ pMTok Equals <*> parseExpression) - <<|> - -- The lack of equals sign means it's an unnamed field. - -- The expression of the unnamed field must be starting with a PFVar Prefix expression - pMany pPFExprSuffix - <**> ( makeUnNamedField - <$> ( - -- There are operators, so the expression goes on beyond the prefixExpression - curry Just - <$> parseBinOp - <*> parseExpression - <<|> - -- There are no operators after the prefix expression - pReturn Nothing - ) - ) - ) - ) - <<|> UnnamedField - <$> parseExpression - --- | Field separator -parseFieldSep :: AParser FieldSep -parseFieldSep = - CommaSep - <$ pMTok Comma - <<|> SemicolonSep - <$ pMTok Semicolon diff --git a/src/GLuaFixer/Interface.hs b/src/GLuaFixer/Interface.hs index dd5f762..329c4d1 100644 --- a/src/GLuaFixer/Interface.hs +++ b/src/GLuaFixer/Interface.hs @@ -2,19 +2,16 @@ module GLuaFixer.Interface where import GLua.AG.AST (AST) import GLua.AG.PrettyPrint (prettyprintConf) -import GLua.AG.Token (MToken, Region) -import qualified GLua.Lexer as UUL +import GLua.AG.Token (MToken) import GLua.LineLimitParser (LineLimit (..), execParseLineLimits) import qualified GLua.PSLexer as PSL import qualified GLua.PSParser as PSP -import qualified GLua.Parser as UUP import GLuaFixer.AG.ASTLint (astWarnings) import GLuaFixer.AG.LexLint (fixedLexPositions, lintWarnings) import GLuaFixer.BadSequenceFinder (sequenceWarnings) import GLuaFixer.LintMessage (Issue (..), LintMessage (..), Severity (..)) import GLuaFixer.LintSettings (LintSettings (..), lint2ppSetting) import Text.Parsec.Error (errorPos) -import Text.ParserCombinators.UU.BasicInstances (Error, LineColPos) -- | Run the linters that apply to the source code of a file sourceLint :: LintSettings -> FilePath -> String -> [LintMessage] @@ -29,14 +26,6 @@ lex lintSettings filepath contents = Left [LintMessage LintError (PSL.sp2Rg $ errorPos lexErr) (IssueParseError lexErr) filepath | lint_syntaxErrors lintSettings] Right tokens -> Right $ fixedLexPositions tokens --- | Use the (slower, but error-correcting) UU-parsinglib lexer to generate the lexicon -lexUU :: LintSettings -> String -> ([MToken], [Error LineColPos]) -lexUU lintSettings contents = case UUL.execParseTokens contents of - (tokens, errors) -> - ( fixedLexPositions tokens - , [err | lint_syntaxErrors lintSettings, err <- errors] - ) - -- | Run the linting functions that inspect the lexicon lexiconLint :: FilePath -> LintSettings -> [MToken] -> [LintMessage] lexiconLint filepath lintSettings tokens = @@ -52,11 +41,6 @@ parse lintSettings filepath tokens = Left [LintMessage LintError (PSL.sp2Rg $ errorPos err) (IssueParseError err) filepath | lint_syntaxErrors lintSettings] Right ast -> Right ast --- | Parse a lexicon into an Abstract Syntax Tree using the slower, but error-correcting --- uu-parsinglib -parseUU :: [MToken] -> (AST, [Error Region]) -parseUU = UUP.parseGLua - -- | Run the linters that inspect the AST astLint :: FilePath -> LintSettings -> AST -> [LintMessage] astLint filepath lintSettings ast = diff --git a/src/GLuaFixer/LintSettings.hs b/src/GLuaFixer/LintSettings.hs index cfb6358..eadeae6 100644 --- a/src/GLuaFixer/LintSettings.hs +++ b/src/GLuaFixer/LintSettings.hs @@ -78,7 +78,6 @@ data LintSettings = LintSettings , prettyprint_removeRedundantParens :: !Bool , prettyprint_minimizeParens :: !Bool , prettyprint_assumeOperatorAssociativity :: !Bool - , prettyprint_rejectInvalidCode :: !Bool , prettyprint_indentation :: !String , log_format :: !LogFormatChoice } @@ -127,7 +126,6 @@ defaultLintSettings = , prettyprint_removeRedundantParens = True , prettyprint_minimizeParens = False , prettyprint_assumeOperatorAssociativity = True - , prettyprint_rejectInvalidCode = False , prettyprint_indentation = " " , log_format = AutoLogFormatChoice } @@ -190,7 +188,6 @@ instance FromJSON LintSettings where <*> v .:? "prettyprint_removeRedundantParens" .!= prettyprint_removeRedundantParens defaultLintSettings <*> v .:? "prettyprint_minimizeParens" .!= prettyprint_minimizeParens defaultLintSettings <*> v .:? "prettyprint_assumeOperatorAssociativity" .!= prettyprint_assumeOperatorAssociativity defaultLintSettings - <*> v .:? "prettyprint_rejectInvalidCode" .!= prettyprint_rejectInvalidCode defaultLintSettings <*> v .:? "prettyprint_indentation" .!= prettyprint_indentation defaultLintSettings <*> v .:? "log_format" .!= log_format defaultLintSettings parseJSON _ = mzero @@ -255,7 +252,6 @@ instance ToJSON LintSettings where , "prettyprint_removeRedundantParens" .= prettyprint_removeRedundantParens ls , "prettyprint_minimizeParens" .= prettyprint_minimizeParens ls , "prettyprint_assumeOperatorAssociativity" .= prettyprint_assumeOperatorAssociativity ls - , "prettyprint_rejectInvalidCode" .= prettyprint_rejectInvalidCode ls , "prettyprint_indentation" .= prettyprint_indentation ls , "log_format" .= log_format ls ]