JavaScript: fix handling of parentheses around an rvalue
Properly skip parentheses around an rvalue, and then properly recognize
the surrounded value. This allows to properly recognize e.g. rvalue
`({...})` as an object, or `(function(){})` as a function. As the
implementation is tolerant regarding garbage after the statement,
function expressions called straight away (`(function(){})()`) are
implicitly supported.
This however removes support for the following invalid JavaScript
syntax that was previously supported as a function/method declaration:
var func = () {}
This syntax is not present in the ECMA standard nor is supported by
popular JavaScript engines.
See:
* http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
section 13, "Function Definition"
* http://ecma262-5.com/ELS5_HTML.htm#Section_13
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope#Defining_functions
This commit is contained in:
parent
35e8fbbe28
commit
8341228ffa
@ -1368,8 +1368,17 @@ static boolean parseStatement (tokenInfo *const token, boolean is_inside_class)
|
|||||||
|
|
||||||
if ( isType (token, TOKEN_EQUAL_SIGN) )
|
if ( isType (token, TOKEN_EQUAL_SIGN) )
|
||||||
{
|
{
|
||||||
|
int parenDepth = 0;
|
||||||
|
|
||||||
readToken (token);
|
readToken (token);
|
||||||
|
|
||||||
|
/* rvalue might be surrounded with parentheses */
|
||||||
|
while (isType (token, TOKEN_OPEN_PAREN))
|
||||||
|
{
|
||||||
|
parenDepth++;
|
||||||
|
readToken (token);
|
||||||
|
}
|
||||||
|
|
||||||
if ( isKeyword (token, KEYWORD_function) )
|
if ( isKeyword (token, KEYWORD_function) )
|
||||||
{
|
{
|
||||||
readToken (token);
|
readToken (token);
|
||||||
@ -1426,37 +1435,9 @@ static boolean parseStatement (tokenInfo *const token, boolean is_inside_class)
|
|||||||
|
|
||||||
if ( vStringLength(secondary_name->string) > 0 )
|
if ( vStringLength(secondary_name->string) > 0 )
|
||||||
makeFunctionTag (secondary_name);
|
makeFunctionTag (secondary_name);
|
||||||
|
|
||||||
/*
|
|
||||||
* Find to the end of the statement
|
|
||||||
*/
|
|
||||||
goto cleanUp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isType (token, TOKEN_OPEN_PAREN))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Handle nameless functions
|
|
||||||
* this.method_name = () {}
|
|
||||||
* Also assignments starting with parentheses
|
|
||||||
* var foo = (1 + 2) * 3;
|
|
||||||
*/
|
|
||||||
skipArgumentList(token);
|
|
||||||
|
|
||||||
if (isType (token, TOKEN_OPEN_CURLY))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Nameless functions are only setup as methods.
|
|
||||||
*/
|
|
||||||
makeJsTag (name, JSTAG_METHOD);
|
|
||||||
parseBlock (token, name);
|
|
||||||
}
|
|
||||||
else if (isType (token, TOKEN_CLOSE_CURLY))
|
|
||||||
is_terminated = FALSE;
|
|
||||||
else if (token->nestLevel == 0 && is_global)
|
|
||||||
makeJsTag (name, JSTAG_VARIABLE);
|
|
||||||
}
|
|
||||||
else if (isType (token, TOKEN_OPEN_CURLY))
|
else if (isType (token, TOKEN_OPEN_CURLY))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -1506,11 +1487,7 @@ static boolean parseStatement (tokenInfo *const token, boolean is_inside_class)
|
|||||||
if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
|
if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
|
||||||
! stringListHas(ClassNames, vStringValue (fulltag)) )
|
! stringListHas(ClassNames, vStringValue (fulltag)) )
|
||||||
{
|
{
|
||||||
readToken (token);
|
makeJsTag (name, JSTAG_VARIABLE);
|
||||||
if ( ! isType (token, TOKEN_SEMICOLON))
|
|
||||||
findCmdTerm (token);
|
|
||||||
if (isType (token, TOKEN_SEMICOLON))
|
|
||||||
makeJsTag (name, JSTAG_VARIABLE);
|
|
||||||
}
|
}
|
||||||
vStringDelete (fulltag);
|
vStringDelete (fulltag);
|
||||||
}
|
}
|
||||||
@ -1598,13 +1575,25 @@ static boolean parseStatement (tokenInfo *const token, boolean is_inside_class)
|
|||||||
if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
|
if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
|
||||||
! stringListHas(ClassNames, vStringValue (fulltag)) )
|
! stringListHas(ClassNames, vStringValue (fulltag)) )
|
||||||
{
|
{
|
||||||
findCmdTerm (token);
|
makeJsTag (name, JSTAG_VARIABLE);
|
||||||
if (isType (token, TOKEN_SEMICOLON))
|
|
||||||
makeJsTag (name, JSTAG_VARIABLE);
|
|
||||||
}
|
}
|
||||||
vStringDelete (fulltag);
|
vStringDelete (fulltag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parenDepth > 0)
|
||||||
|
{
|
||||||
|
while (parenDepth > 0)
|
||||||
|
{
|
||||||
|
if (isType (token, TOKEN_OPEN_PAREN))
|
||||||
|
parenDepth++;
|
||||||
|
else if (isType (token, TOKEN_CLOSE_PAREN))
|
||||||
|
parenDepth--;
|
||||||
|
readToken (token);
|
||||||
|
}
|
||||||
|
if (isType (token, TOKEN_CLOSE_CURLY))
|
||||||
|
is_terminated = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we aren't already at the cmd end, advance to it and check whether
|
/* if we aren't already at the cmd end, advance to it and check whether
|
||||||
|
|||||||
@ -200,6 +200,7 @@ test_sources = \
|
|||||||
objectivec_protocol.mm \
|
objectivec_protocol.mm \
|
||||||
Package.pm \
|
Package.pm \
|
||||||
php5_5_class_kw.php \
|
php5_5_class_kw.php \
|
||||||
|
parenthesis-rvalue.js \
|
||||||
preprocessor.f90 \
|
preprocessor.f90 \
|
||||||
procedure_pointer_module.f90 \
|
procedure_pointer_module.f90 \
|
||||||
procpoint.f90 \
|
procpoint.f90 \
|
||||||
|
|||||||
35
tests/ctags/parenthesis-rvalue.js
Normal file
35
tests/ctags/parenthesis-rvalue.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
// plain values
|
||||||
|
var a1 = 42;
|
||||||
|
var a2 = (42);
|
||||||
|
|
||||||
|
// functions
|
||||||
|
var b1 = function(){
|
||||||
|
function b1sub(){}
|
||||||
|
};
|
||||||
|
var b2 = (function(){
|
||||||
|
function b2sub(){}
|
||||||
|
});
|
||||||
|
var b3 = ((function(){
|
||||||
|
function b3sub(){}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// objects
|
||||||
|
var c1 = {};
|
||||||
|
var c2 = ({});
|
||||||
|
var d1 = {a:'hello',b:'hi'};
|
||||||
|
var d2 = ({a:'hello',b:'hi'});
|
||||||
|
|
||||||
|
// function expressions called straight away
|
||||||
|
var e1 = function(){
|
||||||
|
function e1sub(){}
|
||||||
|
return 42;
|
||||||
|
}();
|
||||||
|
var e2 = (function(){
|
||||||
|
function e2sub(){}
|
||||||
|
return 42
|
||||||
|
})();
|
||||||
|
var e3 = ((function(){
|
||||||
|
function e3sub(){}
|
||||||
|
return 42
|
||||||
|
})());
|
||||||
23
tests/ctags/parenthesis-rvalue.js.tags
Normal file
23
tests/ctags/parenthesis-rvalue.js.tags
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# format=tagmanager
|
||||||
|
aÌ64Îd1Ö0
|
||||||
|
aÌ64Îd2Ö0
|
||||||
|
a1Ì16384Ö0
|
||||||
|
a2Ì16384Ö0
|
||||||
|
bÌ64Îd1Ö0
|
||||||
|
bÌ64Îd2Ö0
|
||||||
|
b1Ì16Ö0
|
||||||
|
b1subÌ16Îb1Ö0
|
||||||
|
b2Ì16Ö0
|
||||||
|
b2subÌ16Îb2Ö0
|
||||||
|
b3Ì16Ö0
|
||||||
|
b3subÌ16Îb3Ö0
|
||||||
|
c1Ì16384Ö0
|
||||||
|
c2Ì16384Ö0
|
||||||
|
d1Ì1Ö0
|
||||||
|
d2Ì1Ö0
|
||||||
|
e1Ì16Ö0
|
||||||
|
e1subÌ16Îe1Ö0
|
||||||
|
e2Ì16Ö0
|
||||||
|
e2subÌ16Îe2Ö0
|
||||||
|
e3Ì16Ö0
|
||||||
|
e3subÌ16Îe3Ö0
|
||||||
@ -69,7 +69,7 @@ ValidClassTwo = function ()
|
|||||||
this.validMethodThree = function() {}
|
this.validMethodThree = function() {}
|
||||||
|
|
||||||
// unnamed method
|
// unnamed method
|
||||||
this.validMethodFour = () {}
|
this.validMethodFour = function() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
var my_global_var4 = document.getElementsByTagName("input");
|
var my_global_var4 = document.getElementsByTagName("input");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user