Skip to content

Commit

Permalink
JavaScript: capture function objects in Self-Invoking Anonymous Funct…
Browse files Browse the repository at this point in the history
…ion Statements

Signed-off-by: Masatake YAMATO <[email protected]>
  • Loading branch information
masatake committed Jul 11, 2022
1 parent 56813d1 commit 2973fa8
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--sort=no
10 changes: 10 additions & 0 deletions Units/parser-javascript.r/self-invoking-anon-func.d/expected.tags
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
anonymousFunction204aa80e0100 input.js /^(function(x) {$/;" f
a input.js /^ var a = function (o) { return o; };$/;" f function:anonymousFunction204aa80e0100
anonymousFunction204aa80e0200 input.js /^(function(y) {$/;" f
b input.js /^ const b = function (p) { return p; };$/;" f function:anonymousFunction204aa80e0200
anonymousFunction204aa80e0300 input.js /^!function(z) {$/;" f
c input.js /^ const c = function (r) { return r; };$/;" f function:anonymousFunction204aa80e0300
anonymousFunction204aa80e0400 input.js /^console.log("a" + (function (A) {$/;" f
anonymousFunction204aa80e0500 input.js /^}((function (B) {$/;" f
anonymousFunction204aa80e0600 input.js /^}(!function(C) {$/;" f
f input.js /^ var f = function (t) {$/;" f function:anonymousFunction204aa80e0600
26 changes: 26 additions & 0 deletions Units/parser-javascript.r/self-invoking-anon-func.d/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
(function(x) {
var a = function (o) { return o; };
return x + a (1);
})(1);

(function(y) {
const b = function (p) { return p; };
return y - b (1);
}(1));

!function(z) {
const c = function (r) { return r; };
return z * c (1);
}(1);

console.log("a" + (function (A) {
return A;
}((function (B) {
return B;
}(!function(C) {
var f = function (t) {
return !t;
}
return f(C);
}(true)
)))));
133 changes: 109 additions & 24 deletions parsers/jscript.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ typedef enum eTokenType {
TOKEN_BINARY_OPERATOR,
TOKEN_ARROW,
TOKEN_DOTS, /* ... */
TOKEN_BANG, /* ! */
} tokenType;

typedef struct sTokenInfo {
Expand Down Expand Up @@ -1096,6 +1097,9 @@ static void readTokenFullRaw (tokenInfo *const token, bool include_newlines, vSt
case '*':
token->type = TOKEN_STAR;
break;
case '!':
token->type = TOKEN_BANG;
break;
case '%':
case '?':
case '>':
Expand Down Expand Up @@ -2954,6 +2958,83 @@ static bool parseLine (tokenInfo *const token, bool is_inside_class)
break;
}
}
else if (isType (token, TOKEN_BANG))
{
/*
* Try to handle "Self-Invoking Anonymous Function Statements" like:
*
* !function(z) { # case A.
* return z * 1;
* }(1);
*
* case A is nothing special; just consuming the token for ! is enough.
*/
readToken (token);
is_terminated = parseLine (token, is_inside_class);
}
else if (isType (token, TOKEN_OPEN_PAREN))
{
/*
* Try to handle "Self-Invoking Anonymous Function Statements" like:
*
* (function(x) { # case B.
* return x + 1;
* })(1);
*
* (function(y) { # case C.
* return y - 1;
* }(1));
*
*/
readToken (token);
is_terminated = parseLine (token, is_inside_class);

/*
* In case B, next ')' should be consumed here.
* In case C, the last ')' after an argument list should be consumed here.
* In case B and C, this function returns true.
*/
if (is_terminated)
{
tokenType last_token_type = token->type;

readToken (token);
if (isType (token, TOKEN_CLOSE_PAREN))
{
/* case B. */
is_terminated = true;
}
else if (last_token_type == TOKEN_CLOSE_CURLY && isType (token, TOKEN_OPEN_PAREN))
{
/*
* maybe case C.
* Parse the argument list if there is.
*/
is_terminated = parseStatement (token, is_inside_class);
if (is_terminated)
{
readToken (token);
if (!isType (token, TOKEN_CLOSE_PAREN) && !isType (token, TOKEN_EOF))
{
/*
* In case B, ')' terminates the statement.
* If the token is not ')', the statement is
* not a "Self-Invoking Anonymous Function Statement".
*/
Assert (NextToken == NULL);
NextToken = newToken ();
copyToken (NextToken, token, false);
}
}
}
else if (!isType (token, TOKEN_EOF))
{
Assert (NextToken == NULL);
NextToken = newToken ();
copyToken (NextToken, token, false);
}
}
}
else
{
/*
Expand Down Expand Up @@ -3051,32 +3132,36 @@ static const char *kindName(jsKind kind)
}

static const char *tokenTypeName(enum eTokenType e)
{ /* Generated by misc/enumstr.sh with cmdline "parsers/jscript.c" "eTokenType" "tokenTypeName" */
{ /* Generated by misc/enumstr.sh with cmdline:
parsers/jscript.c eTokenType tokenTypeName */
switch (e)
{
case TOKEN_BINARY_OPERATOR: return "TOKEN_BINARY_OPERATOR";
case TOKEN_CHARACTER: return "TOKEN_CHARACTER";
case TOKEN_CLOSE_CURLY: return "TOKEN_CLOSE_CURLY";
case TOKEN_CLOSE_PAREN: return "TOKEN_CLOSE_PAREN";
case TOKEN_CLOSE_SQUARE: return "TOKEN_CLOSE_SQUARE";
case TOKEN_COLON: return "TOKEN_COLON";
case TOKEN_COMMA: return "TOKEN_COMMA";
case TOKEN_EOF: return "TOKEN_EOF";
case TOKEN_EQUAL_SIGN: return "TOKEN_EQUAL_SIGN";
case TOKEN_IDENTIFIER: return "TOKEN_IDENTIFIER";
case TOKEN_KEYWORD: return "TOKEN_KEYWORD";
case TOKEN_OPEN_CURLY: return "TOKEN_OPEN_CURLY";
case TOKEN_OPEN_PAREN: return "TOKEN_OPEN_PAREN";
case TOKEN_OPEN_SQUARE: return "TOKEN_OPEN_SQUARE";
case TOKEN_PERIOD: return "TOKEN_PERIOD";
case TOKEN_POSTFIX_OPERATOR: return "TOKEN_POSTFIX_OPERATOR";
case TOKEN_REGEXP: return "TOKEN_REGEXP";
case TOKEN_SEMICOLON: return "TOKEN_SEMICOLON";
case TOKEN_STAR: return "TOKEN_STAR";
case TOKEN_STRING: return "TOKEN_STRING";
case TOKEN_TEMPLATE_STRING: return "TOKEN_TEMPLATE_STRING";
case TOKEN_UNDEFINED: return "TOKEN_UNDEFINED";
default: return "UNKNOWN";
case TOKEN_UNDEFINED: return "TOKEN_UNDEFINED";
case TOKEN_EOF: return "TOKEN_EOF";
case TOKEN_CHARACTER: return "TOKEN_CHARACTER";
case TOKEN_CLOSE_PAREN: return "TOKEN_CLOSE_PAREN";
case TOKEN_SEMICOLON: return "TOKEN_SEMICOLON";
case TOKEN_COLON: return "TOKEN_COLON";
case TOKEN_COMMA: return "TOKEN_COMMA";
case TOKEN_KEYWORD: return "TOKEN_KEYWORD";
case TOKEN_OPEN_PAREN: return "TOKEN_OPEN_PAREN";
case TOKEN_IDENTIFIER: return "TOKEN_IDENTIFIER";
case TOKEN_STRING: return "TOKEN_STRING";
case TOKEN_TEMPLATE_STRING: return "TOKEN_TEMPLATE_STRING";
case TOKEN_PERIOD: return "TOKEN_PERIOD";
case TOKEN_OPEN_CURLY: return "TOKEN_OPEN_CURLY";
case TOKEN_CLOSE_CURLY: return "TOKEN_CLOSE_CURLY";
case TOKEN_EQUAL_SIGN: return "TOKEN_EQUAL_SIGN";
case TOKEN_OPEN_SQUARE: return "TOKEN_OPEN_SQUARE";
case TOKEN_CLOSE_SQUARE: return "TOKEN_CLOSE_SQUARE";
case TOKEN_REGEXP: return "TOKEN_REGEXP";
case TOKEN_POSTFIX_OPERATOR: return "TOKEN_POSTFIX_OPERATOR";
case TOKEN_STAR: return "TOKEN_STAR";
case TOKEN_ATMARK: return "TOKEN_ATMARK";
case TOKEN_BINARY_OPERATOR: return "TOKEN_BINARY_OPERATOR";
case TOKEN_ARROW: return "TOKEN_ARROW";
case TOKEN_DOTS: return "TOKEN_DOTS";
default: return "UNKNOWN";
}
}
#endif
Expand Down

0 comments on commit 2973fa8

Please sign in to comment.