From 026015954abc5ec65ba021f6926f854f1f536e26 Mon Sep 17 00:00:00 2001 From: Matt Hargett Date: Wed, 7 Sep 2022 19:29:55 -0700 Subject: [PATCH] Move rules from lexer to parser. Fix some bugs found in manual testing. Add bugs found via manual testing to new lua test file. --- .../sourceforge/pmd/lang/lua/antlr4/Lua.g4 | 92 +++++++++-------- .../pmd/lang/lua/cpd/testdata/luauTypes.lua | 4 + .../pmd/lang/lua/cpd/testdata/luauTypes.txt | 99 ++++++++++++++----- 3 files changed, 128 insertions(+), 67 deletions(-) diff --git a/pmd-lua/src/main/antlr4/net/sourceforge/pmd/lang/lua/antlr4/Lua.g4 b/pmd-lua/src/main/antlr4/net/sourceforge/pmd/lang/lua/antlr4/Lua.g4 index 62ac80363d..1f84395d51 100644 --- a/pmd-lua/src/main/antlr4/net/sourceforge/pmd/lang/lua/antlr4/Lua.g4 +++ b/pmd-lua/src/main/antlr4/net/sourceforge/pmd/lang/lua/antlr4/Lua.g4 @@ -91,7 +91,7 @@ stat | 'function' funcname funcbody | 'local' 'function' NAME funcbody | 'local' bindinglist ('=' explist)? - | ('export')? 'type' NAME ('<' GenericTypeParameterList '>')? '=' Type + | ('export')? 'type' NAME ('<' genericTypeParameterList '>')? '=' type ; attnamelist @@ -115,7 +115,7 @@ funcname ; funcbody - : ('<' GenericTypeParameterList '>')? '(' parlist? ')' (':' '...'? ReturnType ) block 'end' // GenericTypeParameterList and ReturnType + : ('<' genericTypeParameterList '>')? '(' parlist? ')' (':' '...'? returnType ) block 'end' // genericTypeParameterList and returnType ; parlist @@ -131,7 +131,7 @@ namelist ; binding - : NAME (':' Type ('?')?)? + : NAME (':' type ('?')?)? ; bindinglist: binding (',' bindinglist)?; @@ -158,10 +158,10 @@ exp ifelseexp: 'if' exp 'then' exp ('elseif' exp 'then' exp)* 'else' exp; -asexp: simpleexp ('::' Type)?; +asexp: simpleexp ('::' type)?; simpleexp - : 'nil' | 'false' | 'true' + : NIL | BOOLEAN | number | string | '...' @@ -242,73 +242,81 @@ number ; string - : NORMALSTRING | CHARSTRING | LONGSTRING + : NORMALSTRING | LONGSTRING ; -SimpleType - : 'nil' - | SingletonType - | NAME /* ('.' NAME)? */ ('<' TypeParams '>')? +simpleType + : NIL + | singletonType + | NAME ('.' NAME)? ('<' typeParams '>')? | 'typeof' '(' NAME ('(' ')')? | '...' ')' // can't use `exp`, manually handle common cases - | TableType - | FunctionType + | tableType + | functionType ; -SingletonType - : NORMALSTRING | CHARSTRING - | 'true' - | 'false' +singletonType + : NORMALSTRING | BOOLEAN ; -Type - : SimpleType ('?')? - | SimpleType ('?')? ('|' Type) // can't use Type because it's mutually left-recursive - | SimpleType ('?')? ('&' Type) // can't use Type because it's mutually left-recursive +type + : simpleType ('?')? + | simpleType ('?')? ('|' type) // can't use type because it's mutually left-recursive + | simpleType ('?')? ('&' type) // can't use type because it's mutually left-recursive ; -GenericTypePackParameter: NAME '...' ('=' (('(' (TypeList)? ')') | VariadicTypePack | GenericTypePack))?; // TypePack must be inlined here +genericTypePackParameter: NAME '...' ('=' (('(' (typeList)? ')') | variadicTypePack | genericTypePack))?; // typePack must be inlined here -GenericTypeParameterList: NAME ('=' Type)? (',' GenericTypeParameterList)? | GenericTypePackParameter (',' GenericTypePackParameter)*; +genericTypeParameterList: NAME ('=' type)? (',' genericTypeParameterList)? | genericTypePackParameter (',' genericTypePackParameter)*; -TypeList: Type (',' Type)? | VariadicTypePack; +typeList: type (',' type)? | variadicTypePack; -TypeParams: (Type | VariadicTypePack | GenericTypePack) (',' TypeParams)?; // had to remove TypePack +typeParams: (type | variadicTypePack | genericTypePack) (',' typeParams)?; // had to remove typePack -// TypePack: inlined everywhere to avoid overly greedy match when out-of-context +// typePack: inlined everywhere to avoid overly greedy match when out-of-context -GenericTypePack: NAME '...'; +genericTypePack: NAME '...'; -VariadicTypePack: '...' Type; +variadicTypePack: '...' type; -ReturnType: Type | '(' Type ',' Type ')' | '(' ')'; // can't use TypePack, inline common cases +returnType: variadicTypePack | '(' typeList ')' | '(' ')'; // can't use typePack, inline common cases -TableIndexer: '[' Type ']' ':' Type; +tableIndexer: '[' type ']' ':' type; -TableProp: NAME ':' Type; +tableProp: NAME ':' type; -TablePropOrIndexer - : TableProp | TableIndexer; +tablePropOrIndexer + : tableProp | tableIndexer; -PropList - : TablePropOrIndexer ((','|';') TablePropOrIndexer)* (','|';')?; +propList + : tablePropOrIndexer ((','|';') tablePropOrIndexer)* (','|';')?; -TableType - : '{' PropList '}'; +tableType + : '{' propList '}'; + +functionType: ('<' genericTypeParameterList '>')? '(' (typeList)? ')' '->' returnType; + +require + : 'require' '(' (NAME ('.' NAME)*) | NORMALSTRING ')' ('::' type)? + ; -FunctionType: ('<' GenericTypeParameterList '>')? '(' (TypeList)? ')' '->' (Type | '(' ')' | '(' (TypeList) ')'); // inline ReturnType to avoid greediness // LEXER +NIL + : 'nil' + ; + +BOOLEAN + : 'true' | 'false' + ; + NAME : [a-zA-Z_][a-zA-Z_0-9]* ; NORMALSTRING : '"' ( EscapeSequence | ~('\\'|'"') )* '"' - ; - -CHARSTRING - : '\'' ( EscapeSequence | ~('\''|'\\') )* '\'' + | '\'' ( EscapeSequence | ~('\\'|'\'') )* '\'' ; LONGSTRING @@ -401,7 +409,7 @@ LINE_COMMENT ; WS - : [ \t\u000C\r\n]+ -> skip + : [ \n\r\t\u000B\u000C\u0000]+ -> channel(HIDDEN) ; SHEBANG diff --git a/pmd-lua/src/test/resources/net/sourceforge/pmd/lang/lua/cpd/testdata/luauTypes.lua b/pmd-lua/src/test/resources/net/sourceforge/pmd/lang/lua/cpd/testdata/luauTypes.lua index 1c391a37a6..2294030324 100644 --- a/pmd-lua/src/test/resources/net/sourceforge/pmd/lang/lua/cpd/testdata/luauTypes.lua +++ b/pmd-lua/src/test/resources/net/sourceforge/pmd/lang/lua/cpd/testdata/luauTypes.lua @@ -7,6 +7,10 @@ local _notLiteral = not true local _notVariable = not x local _length = #{x} export type Function = (...any) -> T... +local _PlatformService = nil +local game = require(script.Parent.game) :: any +pcall(function() _PlatformService = game:GetService('PlatformService') end) + return function (req, ...: boolean): ({[string|number]: T}, string, Function<...any>) local body = string.format("%s %s\n", req.method, req.path) diff --git a/pmd-lua/src/test/resources/net/sourceforge/pmd/lang/lua/cpd/testdata/luauTypes.txt b/pmd-lua/src/test/resources/net/sourceforge/pmd/lang/lua/cpd/testdata/luauTypes.txt index 2be84bbb8a..7eb53efa9e 100644 --- a/pmd-lua/src/test/resources/net/sourceforge/pmd/lang/lua/cpd/testdata/luauTypes.txt +++ b/pmd-lua/src/test/resources/net/sourceforge/pmd/lang/lua/cpd/testdata/luauTypes.txt @@ -53,18 +53,56 @@ L9 [type] 8 11 [Function] 13 20 [<] 21 21 - [T...] 22 25 + [T] 22 22 + [...] 23 25 [=] 27 27 - [...any] 29 34 + [...] 29 31 + [any] 32 34 [>] 35 35 [=] 37 37 [(] 39 39 - [...any] 40 45 + [...] 40 42 + [any] 43 45 [)] 46 46 - [-] 48 48 - [>] 49 49 - [T...] 51 54 + [->] 48 49 + [T] 51 51 + [...] 52 54 +L10 + [local] 1 5 + [_PlatformService] 7 22 + [=] 24 24 + [nil] 26 28 L11 + [local] 1 5 + [game] 7 10 + [=] 12 12 + [require] 14 20 + [(] 21 21 + [script] 22 27 + [.] 28 28 + [Parent] 29 34 + [.] 35 35 + [game] 36 39 + [)] 40 40 + [::] 42 43 + [any] 45 47 +L12 + [pcall] 1 5 + [(] 6 6 + [function] 7 14 + [(] 15 15 + [)] 16 16 + [_PlatformService] 18 33 + [=] 35 35 + [game] 37 40 + [:] 41 41 + [GetService] 42 51 + [(] 52 52 + ['PlatformService'] 53 69 + [)] 70 70 + [end] 72 74 + [)] 75 75 +L15 [return] 1 6 [function] 8 15 [<] 17 17 @@ -81,7 +119,9 @@ L11 [(] 41 41 [{] 42 42 [\[] 43 43 - [string|number] 44 56 + [string] 44 49 + [|] 50 50 + [number] 51 56 [\]] 57 57 [:] 58 58 [T] 60 60 @@ -89,9 +129,13 @@ L11 [,] 62 62 [string] 64 69 [,] 70 70 - [Function<...any>] 72 87 + [Function] 72 79 + [<] 80 80 + [...] 81 83 + [any] 84 86 + [>] 87 87 [)] 88 88 -L12 +L16 [local] 3 7 [body] 9 12 [=] 14 14 @@ -109,24 +153,24 @@ L12 [.] 56 56 [path] 57 60 [)] 61 61 -L13 +L17 [local] 3 7 [res] 9 11 [=] 13 13 [{] 15 15 -L14 +L18 [code] 5 8 [=] 10 10 [200] 12 14 [,] 15 15 -L15 +L19 [{] 5 5 ["Content-Type"] 7 20 [,] 21 21 ["text/plain"] 23 34 [}] 36 36 [,] 37 37 -L16 +L20 [{] 5 5 ["Content-Length"] 7 22 [,] 23 23 @@ -134,9 +178,12 @@ L16 [body] 26 29 [}] 31 31 [::] 33 34 - [Array] 36 45 + [Array] 36 40 + [<] 41 41 + [any] 42 44 + [>] 45 45 [,] 46 46 -L17 +L21 [}] 3 3 [::] 5 6 [{] 8 8 @@ -153,7 +200,7 @@ L17 [boolean] 41 47 [>] 48 48 [}] 50 50 -L18 +L22 [if] 3 4 [(] 6 6 [req] 7 9 @@ -163,7 +210,7 @@ L18 [.] 18 18 [keepAlive] 19 27 [then] 29 32 -L19 +L23 [local] 5 9 [socketType] 11 20 [:] 21 21 @@ -176,13 +223,13 @@ L19 [""] 56 57 [::] 59 60 [""] 62 63 -L20 +L24 [socketType] 5 14 [=] 16 16 ["Connection"] 18 29 [::] 31 32 ["Connection"] 34 45 -L21 +L25 [res] 5 7 [\[] 8 8 [#] 9 9 @@ -198,7 +245,7 @@ L21 [,] 43 43 ["Keep-Alive"] 45 56 [}] 58 58 -L22 +L26 [res] 5 7 [\[] 8 8 [#] 9 9 @@ -210,9 +257,9 @@ L22 [{] 21 21 [...] 23 25 [}] 27 27 -L23 +L27 [end] 3 5 -L25 +L29 [return] 3 8 [(] 10 10 [res] 11 13 @@ -228,12 +275,14 @@ L25 [,] 37 37 [function] 39 46 [(] 47 47 - [...)] 48 51 + [...] 48 50 + [)] 51 51 [:] 52 52 - [...any] 54 59 + [...] 54 56 + [any] 57 59 [return] 61 66 [...] 68 70 [end] 72 74 -L26 +L30 [end] 1 3 EOF