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) )
|
||||
{
|
||||
int parenDepth = 0;
|
||||
|
||||
readToken (token);
|
||||
|
||||
/* rvalue might be surrounded with parentheses */
|
||||
while (isType (token, TOKEN_OPEN_PAREN))
|
||||
{
|
||||
parenDepth++;
|
||||
readToken (token);
|
||||
}
|
||||
|
||||
if ( isKeyword (token, KEYWORD_function) )
|
||||
{
|
||||
readToken (token);
|
||||
@ -1426,37 +1435,9 @@ static boolean parseStatement (tokenInfo *const token, boolean is_inside_class)
|
||||
|
||||
if ( vStringLength(secondary_name->string) > 0 )
|
||||
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))
|
||||
{
|
||||
/*
|
||||
@ -1506,11 +1487,7 @@ static boolean parseStatement (tokenInfo *const token, boolean is_inside_class)
|
||||
if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
|
||||
! stringListHas(ClassNames, vStringValue (fulltag)) )
|
||||
{
|
||||
readToken (token);
|
||||
if ( ! isType (token, TOKEN_SEMICOLON))
|
||||
findCmdTerm (token);
|
||||
if (isType (token, TOKEN_SEMICOLON))
|
||||
makeJsTag (name, JSTAG_VARIABLE);
|
||||
makeJsTag (name, JSTAG_VARIABLE);
|
||||
}
|
||||
vStringDelete (fulltag);
|
||||
}
|
||||
@ -1598,13 +1575,25 @@ static boolean parseStatement (tokenInfo *const token, boolean is_inside_class)
|
||||
if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
|
||||
! stringListHas(ClassNames, vStringValue (fulltag)) )
|
||||
{
|
||||
findCmdTerm (token);
|
||||
if (isType (token, TOKEN_SEMICOLON))
|
||||
makeJsTag (name, JSTAG_VARIABLE);
|
||||
makeJsTag (name, JSTAG_VARIABLE);
|
||||
}
|
||||
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
|
||||
|
||||
@ -200,6 +200,7 @@ test_sources = \
|
||||
objectivec_protocol.mm \
|
||||
Package.pm \
|
||||
php5_5_class_kw.php \
|
||||
parenthesis-rvalue.js \
|
||||
preprocessor.f90 \
|
||||
procedure_pointer_module.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() {}
|
||||
|
||||
// unnamed method
|
||||
this.validMethodFour = () {}
|
||||
this.validMethodFour = function() {}
|
||||
}
|
||||
|
||||
var my_global_var4 = document.getElementsByTagName("input");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user