Skip to content

Commit

Permalink
JavaScript: extract variables and constants in destructuring assignment
Browse files Browse the repository at this point in the history
Close universal-ctags#1112.

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
  • Loading branch information
masatake committed Jul 9, 2022
1 parent 9f4db32 commit 2edf82b
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--sort=no
Empty file.
56 changes: 56 additions & 0 deletions Units/parser-javascript.r/js-destructural-binding.d/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Derrived from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
const [x] = [1];
const [y, z] = [1, 2, 3, 4, 5];
let [a=5, b=7] = [1];

let [c, , d] = [1, 2, 3];
let [e, f = 0, , g] = [1, 2, 3, 4];

let [,,] = [1, 2, 3];
let [,] = [1, 2, 3];
let [] = [1, 2, 3];

const [h, i, ...[j, k]] = [1, 2, 3, 4];
const [l, m, ...[n, o, ...[p, q]]] = [1, 2, 3, 4, 5, 6];

const [A, B, ...{ C, D }] = []

const user = {
E: 42,
F: true
};

const {E, F} = user;

const {E: G, F: H} = user;


const {I = 10, J = 5} = {I: 3};

let {a: K = 10, b: L = 5} = {a: 3};

let {M, N, ...O} = {M: 10, N: 20, c: 30, d: 40}


const metadata = {
title: 'Scratchpad',
translations: [
{
locale: 'de',
localization_tags: [],
last_edit: '2014-04-14T08:43:37',
url: '/de/docs/Tools/Scratchpad',
title: 'JavaScript-Umgebung'
}
],
url: '/en-US/docs/Tools/Scratchpad'
};

let {
title: englishTitle, // rename
translations: [
{
title: localeTitle, // rename
},
],
} = metadata;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node
129 changes: 127 additions & 2 deletions parsers/jscript.c
Original file line number Diff line number Diff line change
Expand Up @@ -2252,6 +2252,121 @@ static bool parseES6Class (tokenInfo *const token, const tokenInfo *targetName)
return true;
}

static void parseObjectDestructuring (tokenInfo *const token, bool is_const);
static void parseArrayDestructuring (tokenInfo *const token, bool is_const)
{
int nest_level = 1;
bool in_left_side = true;

while (nest_level > 0 && ! isType (token, TOKEN_EOF))
{
readToken (token);
if (isType (token, TOKEN_OPEN_SQUARE))
{
in_left_side = true;
nest_level++;
}
else if (isType (token, TOKEN_CLOSE_SQUARE))
{
in_left_side = false;
nest_level--;
}
else if (isType (token, TOKEN_OPEN_CURLY))
{
in_left_side = false;
parseObjectDestructuring (token, is_const);
}
else if (isType (token, TOKEN_COMMA)
|| isType (token, TOKEN_DOTS))
in_left_side = true;
else if (in_left_side && isType (token, TOKEN_IDENTIFIER))
{
in_left_side = false;
makeJsTag (token, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
}
else if (isType (token, TOKEN_EQUAL_SIGN))
{
in_left_side = false;
/* TODO: SKIP */
}
else
in_left_side = false;
}
}

static void parseObjectDestructuring (tokenInfo *const token, bool is_const)
{
tokenInfo *const name = newToken ();

/*
* let { k0: v0, k1: v1 = 0, v3 };
* | | || | | |
* ^...|..|^...|..|....^.....: start
* ....^..|....^..|..........: colon
* .......^.......^..........: emitted (made a tag for an id after colon)
*/
enum objDestructuringState {
OBJ_DESTRUCTURING_START,
OBJ_DESTRUCTURING_COLON,
OBJ_DESTRUCTURING_EMITTED,
} state = OBJ_DESTRUCTURING_START;

while (! isType (token, TOKEN_EOF))
{
readToken (token);
if (isType (token, TOKEN_OPEN_CURLY))
{
parseObjectDestructuring (token, is_const);
if (state == OBJ_DESTRUCTURING_COLON)
state = OBJ_DESTRUCTURING_EMITTED;
}
else if (isType (token, TOKEN_CLOSE_CURLY))
{
if (!vStringIsEmpty(name->string))
makeJsTag (name, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
break;
}
else if (isType (token, TOKEN_OPEN_SQUARE))
{
parseArrayDestructuring (token, is_const);
if (state == OBJ_DESTRUCTURING_COLON)
state = OBJ_DESTRUCTURING_EMITTED;
}
else if (isType (token, TOKEN_IDENTIFIER))
{
if (state == OBJ_DESTRUCTURING_COLON)
{
makeJsTag (token, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
state = OBJ_DESTRUCTURING_EMITTED;
}
else if (state == OBJ_DESTRUCTURING_START
&& vStringIsEmpty(name->string))
copyToken(name, token, true);
}
else if (isType (token, TOKEN_COMMA))
{
if (!vStringIsEmpty(name->string))
{
makeJsTag (name, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
vStringClear (name->string);
}
state = OBJ_DESTRUCTURING_START;
}
else if (isType (token, TOKEN_COLON))
{
vStringClear (name->string);
state = OBJ_DESTRUCTURING_COLON;
}
else
{
if (state == OBJ_DESTRUCTURING_COLON)
state = OBJ_DESTRUCTURING_EMITTED;
}
}

deleteToken (name);
}

static bool parseStatement (tokenInfo *const token, bool is_inside_class)
{
TRACE_ENTER_TEXT("is_inside_class: %s", is_inside_class? "yes": "no");
Expand Down Expand Up @@ -2322,6 +2437,14 @@ static bool parseStatement (tokenInfo *const token, bool is_inside_class)
is_global = true;
}
readToken(token);

if (is_global)
{
if (isType (token, TOKEN_OPEN_CURLY))
parseObjectDestructuring (token, is_const);
else if (isType (token, TOKEN_OPEN_SQUARE))
parseArrayDestructuring (token, is_const);
}
}

nextVar:
Expand Down Expand Up @@ -2530,7 +2653,8 @@ static bool parseStatement (tokenInfo *const token, bool is_inside_class)
* Handles this syntax:
* var g_var2;
*/
indexForName = makeJsTag (name, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
if (! vStringIsEmpty (name->string))
indexForName = makeJsTag (name, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
}
/*
* Statement has ended.
Expand Down Expand Up @@ -2749,7 +2873,8 @@ static bool parseStatement (tokenInfo *const token, bool is_inside_class)
}
}
else if (! isType (token, TOKEN_KEYWORD) &&
token->nestLevel == 0 && is_global )
token->nestLevel == 0 && is_global &&
(! vStringIsEmpty (name->string)))
{
/*
* Only create variables for global scope
Expand Down

0 comments on commit 2edf82b

Please sign in to comment.