@@ -652,7 +652,8 @@ local function expectAssign(isAction)
652652 return false
653653end
654654
655- local function parseLocalAttrs ()
655+ --- @param kind ? ' "prefix"' | ' "suffix"'
656+ local function parseLocalAttrs (kind )
656657 local attrs
657658 while true do
658659 skipSpace ()
@@ -672,6 +673,7 @@ local function parseLocalAttrs()
672673 parent = attrs ,
673674 start = getPosition (Tokens [Index ], ' left' ),
674675 finish = getPosition (Tokens [Index ], ' right' ),
676+ kind = kind or ' suffix' ,
675677 }
676678 attrs [# attrs + 1 ] = attr
677679 Index = Index + 2
@@ -725,6 +727,20 @@ local function parseLocalAttrs()
725727 return attrs
726728end
727729
730+ local function mergeLocalAttrs (attrsBefore , attrsAfter )
731+ if not attrsBefore then
732+ return attrsAfter
733+ end
734+ if not attrsAfter then
735+ return attrsBefore
736+ end
737+ for i = 1 , # attrsAfter do
738+ attrsBefore [# attrsBefore + 1 ] = attrsAfter [i ]
739+ end
740+ attrsBefore .finish = attrsAfter [# attrsAfter ].finish
741+ return attrsBefore
742+ end
743+
728744--- @param obj table
729745local function createLocal (obj , attrs )
730746 obj .type = ' local'
@@ -951,6 +967,79 @@ local function hasAttr(attrs, attrName)
951967 return false
952968end
953969
970+ local function hasAttrKind (attrs , attrName , attrKind )
971+ if not attrs then
972+ return false
973+ end
974+ for i = 1 , # attrs do
975+ if attrs [i ][1 ] == attrName and attrs [i ].kind == attrKind then
976+ return true
977+ end
978+ end
979+ return false
980+ end
981+
982+ local function checkLocalCloseList (n1 , n2 , nrest )
983+ if State .version ~= ' Lua 5.4' and State .version ~= ' Lua 5.5' then
984+ return
985+ end
986+
987+ if State .version == ' Lua 5.5' and hasAttrKind (n1 and n1 .attrs , ' close' , ' prefix' ) then
988+ local extra
989+ if n2 and not n2 .attrs then
990+ extra = n2
991+ elseif nrest then
992+ for i = 1 , # nrest do
993+ if not nrest [i ].attrs then
994+ extra = nrest [i ]
995+ break
996+ end
997+ end
998+ end
999+ if extra then
1000+ pushError {
1001+ type = ' MULTI_CLOSE' ,
1002+ start = extra .start ,
1003+ finish = extra .finish ,
1004+ }
1005+ return
1006+ end
1007+ end
1008+
1009+ local function collectCloseAttrs (node , list )
1010+ local attrs = node and node .attrs
1011+ if not attrs then
1012+ return
1013+ end
1014+ for i = 1 , # attrs do
1015+ local a = attrs [i ]
1016+ if a [1 ] == ' close' then
1017+ list [# list + 1 ] = a
1018+ end
1019+ end
1020+ end
1021+
1022+ local closeList = {}
1023+ collectCloseAttrs (n1 , closeList )
1024+ if n2 then
1025+ collectCloseAttrs (n2 , closeList )
1026+ end
1027+ if nrest then
1028+ for i = 1 , # nrest do
1029+ collectCloseAttrs (nrest [i ], closeList )
1030+ end
1031+ end
1032+
1033+ if # closeList > 1 then
1034+ local second = closeList [2 ]
1035+ pushError {
1036+ type = ' MULTI_CLOSE' ,
1037+ start = second .start ,
1038+ finish = second .finish ,
1039+ }
1040+ end
1041+ end
1042+
9541043local function resolveLable (label , obj )
9551044 if not label .ref then
9561045 label .ref = {}
@@ -3208,43 +3297,8 @@ local function parseMultiVars(n1, parser, isLocal)
32083297 end
32093298 end
32103299
3211- do
3212- -- Lua 5.4: only one <close> attribute allowed across a local declaration
3213- -- Lua 5.5: multiple <close> are allowed
3214- if State .version == ' Lua 5.4' then
3215- local function collectCloseAttrs (node , list )
3216- local attrs = node and node .attrs
3217- if not attrs then
3218- return
3219- end
3220- for i = 1 , # attrs do
3221- local a = attrs [i ]
3222- if a [1 ] == ' close' then
3223- list [# list + 1 ] = a
3224- end
3225- end
3226- end
3227-
3228- local closeList = {}
3229- collectCloseAttrs (n1 , closeList )
3230- if n2 then
3231- collectCloseAttrs (n2 , closeList )
3232- end
3233- if nrest then
3234- for i = 1 , # nrest do
3235- collectCloseAttrs (nrest [i ], closeList )
3236- end
3237- end
3238-
3239- if # closeList > 1 then
3240- local second = closeList [2 ]
3241- pushError {
3242- type = ' MULTI_CLOSE' ,
3243- start = second .start ,
3244- finish = second .finish ,
3245- }
3246- end
3247- end
3300+ if isLocal then
3301+ checkLocalCloseList (n1 , n2 , nrest )
32483302 end
32493303
32503304 if v2 and not n2 then
@@ -3343,13 +3397,30 @@ local function parseLocal()
33433397 local locPos = getPosition (Tokens [Index ], ' left' )
33443398 Index = Index + 2
33453399 skipSpace ()
3346- local word = peekWord ()
3400+ local attrsBefore = parseLocalAttrs (' prefix' )
3401+ if attrsBefore and State .version ~= ' Lua 5.5' then
3402+ pushError {
3403+ type = ' UNSUPPORT_SYMBOL' ,
3404+ start = attrsBefore .start ,
3405+ finish = attrsBefore .finish ,
3406+ version = ' Lua 5.5' ,
3407+ }
3408+ end
3409+ skipSpace ()
3410+ local word , wstart , wfinish = peekWord ()
33473411 if not word then
33483412 missName ()
33493413 return nil
33503414 end
33513415
33523416 if word == ' function' then
3417+ if attrsBefore then
3418+ pushError {
3419+ type = ' MISS_NAME' ,
3420+ start = wstart ,
3421+ finish = wfinish ,
3422+ }
3423+ end
33533424 local func = parseFunction (' local' , true )
33543425 local name = func .name
33553426 if name then
@@ -3373,7 +3444,9 @@ local function parseLocal()
33733444 missName ()
33743445 return nil
33753446 end
3376- local loc = createLocal (name , parseLocalAttrs ())
3447+ local attrsAfter = parseLocalAttrs (' suffix' )
3448+ local attrs = mergeLocalAttrs (attrsBefore , attrsAfter )
3449+ local loc = createLocal (name , attrs )
33773450 loc .locPos = locPos
33783451 loc .effect = maxinteger
33793452 pushActionIntoCurrentChunk (loc )
0 commit comments