Skip to content

JavaScript: # indicates a private class field or method #4269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Tmain/list-fields-with-prefix.d/stdout-expected.txt
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ x UCTAGSxpath no NONE s-- no -- xpath for
- UCTAGSpackage yes Go s-- no -- the real package specified by the package name
- UCTAGSpackageName yes Go s-- no -- the name for referring the package
- UCTAGSimplements yes Inko s-- no rw Trait being implemented
- UCTAGSproperties no JavaScript s-- no -- properties (static)
- UCTAGSassignment yes LdScript s-- no -- how a value is assigned to the symbol
- UCTAGSdefiner yes Lisp s-- no -- the name of the function or macro that defines the unknown/Y-kind object
- UCTAGSsectionMarker no Markdown s-- no -- character used for declaring section(#, ##, =, or -)
1 change: 1 addition & 0 deletions Tmain/list-fields.d/stdout-expected.txt
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@ z kind no NONE s-- no r- [tags output] prepend "kind:" to k/ (or K/) field outpu
- package yes Go s-- no -- the real package specified by the package name
- packageName yes Go s-- no -- the name for referring the package
- implements yes Inko s-- no rw Trait being implemented
- properties no JavaScript s-- no -- properties (static)
- assignment yes LdScript s-- no -- how a value is assigned to the symbol
- definer yes Lisp s-- no -- the name of the function or macro that defines the unknown/Y-kind object
- sectionMarker no Markdown s-- no -- character used for declaring section(#, ##, =, or -)
3 changes: 3 additions & 0 deletions Units/parser-javascript.r/js-es6-class-private.d/args.ctags
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--fields=+a
--fields-javascript=+{properties}
--sort=no
25 changes: 25 additions & 0 deletions Units/parser-javascript.r/js-es6-class-private.d/expected.tags
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Class1 input.js /^class Class1$/;" c
#value1 input.js /^ #value1$/;" M class:Class1 access:private
#value2 input.js /^ static #value2$/;" M class:Class1 access:private properties:static
method1 input.js /^ method1(arg1,arg2)$/;" m class:Class1
#method2 input.js /^ #method2(arg1,arg2)$/;" m class:Class1 access:private
Class2 input.js /^class Class2$/;" c
#method3 input.js /^ static #method3(arg = 10)$/;" m class:Class2 access:private properties:static
Class3 input.js /^var Class3 = class {$/;" c
#method4 input.js /^ #method4(){}$/;" m class:Class3 access:private
method5 input.js /^ static method5(){}$/;" m class:Class3 properties:static
Class4 input.js /^var Class4 = class Class4_2 {$/;" c
Class4_2 input.js /^var Class4 = class Class4_2 {$/;" c
method6 input.js /^ method6(){}$/;" m class:Class4
method7 input.js /^ static method7(){}$/;" m class:Class4 properties:static
AnonymousClass1fa6c9a30101 input.js /^class {$/;" c
method8 input.js /^ method8(n) { return n * n; }$/;" m class:AnonymousClass1fa6c9a30101
func1 input.js /^function func1() {$/;" f
InnerClass1 input.js /^ class InnerClass1 {$/;" c function:func1
#method9 input.js /^ #method9() {$/;" m class:func1.InnerClass1 access:private
InnerClass2 input.js /^ class InnerClass2 {$/;" c function:func1
method10 input.js /^ method10() {$/;" m class:func1.InnerClass2
Class5 input.js /^class Class5 {$/;" c
method11 input.js /^ method11() {};$/;" m class:Class5
#method12 input.js /^ #method12() {};$/;" m class:Class5 access:private
func2 input.js /^function func2() {$/;" f
54 changes: 54 additions & 0 deletions Units/parser-javascript.r/js-es6-class-private.d/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

class Class1
{
#value1
static #value2

method1(arg1,arg2)
{
}

#method2(arg1,arg2)
{
}
}

class Class2
{
static #method3(arg = 10)
{
}
}

var Class3 = class {
#method4(){}
static method5(){}
}

var Class4 = class Class4_2 {
method6(){}
static method7(){}
}

class {
method8(n) { return n * n; }
}

function func1() {
class InnerClass1 {
#method9() {
}
}
class InnerClass2 {
method10() {
}
}
}

class Class5 {
method11() {};
#method12() {};
}

function func2() {
}
4 changes: 4 additions & 0 deletions docs/news/HEAD.rst
Original file line number Diff line number Diff line change
@@ -14,6 +14,10 @@ Incompatible changes

Parser related changes
---------------------------------------------------------------------
JavaScript:
* A new field "properties" was added to indicate that a field or
member of a class is static.
* Class member names prefixed with # are recognized as private.

New parsers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
75 changes: 60 additions & 15 deletions parsers/jscript.c
Original file line number Diff line number Diff line change
@@ -123,6 +123,7 @@
TOKEN_REGEXP,
TOKEN_POSTFIX_OPERATOR,
TOKEN_STAR,
TOKEN_HASH,
/* To handle Babel's decorators.
* Used only in readTokenFull or lower functions. */
TOKEN_ATMARK,
@@ -144,6 +145,10 @@
int c;
} tokenInfo;

typedef enum {
F_STATIC,
} jsField;

/*
* DATA DEFINITIONS
*/
@@ -279,6 +284,14 @@
{ true, 'M', "field", "fields" },
};

static fieldDefinition JsFields[] = {
{
.name = "properties",
.description = "properties (static)",
.enabled = false,
},
};

static const keywordTable JsKeywordTable [] = {
/* keyword keyword ID */
{ "function", KEYWORD_function },
@@ -487,7 +500,7 @@

static int makeJsTagCommon (const tokenInfo *const token, const jsKind kind,
vString *const signature, vString *const inheritance,
bool anonymous, bool nulltag)
bool anonymous, bool is_static, bool is_private, bool nulltag)
{
int index = CORK_NIL;
const char *name = vStringValue (token->string);
@@ -526,6 +539,12 @@
updateTagLine (&e, token->lineNumber, token->filePosition);
e.extensionFields.scopeIndex = scope;

if (is_private)
e.extensionFields.access = "private";

if (is_static)
attachParserField (&e, JsFields[F_STATIC].ftype, "static");

#ifdef DO_TRACING
{
const char *scope_str = getNameStringForCorkIndex (scope);
@@ -573,19 +592,33 @@
static int makeJsTag (const tokenInfo *const token, const jsKind kind,
vString *const signature, vString *const inheritance)
{
return makeJsTagCommon (token, kind, signature, inheritance, false, false);
return makeJsTagCommon (token, kind, signature, inheritance, false, false, false, false);
}

static int makeJsTagMaybePrivate (const tokenInfo *const token, const jsKind kind,
vString *const signature, vString *const inheritance,
const bool is_static, const bool is_private)
{
if (is_private) {
vString * s = vStringNewInit ("#");
vStringCat (s, token->string);
vStringCopy (token->string, s);
vStringDelete (s);
}

return makeJsTagCommon (token, kind, signature, inheritance, false, is_static, is_private, false);
}

static int makeJsNullTag (const tokenInfo *const token, const jsKind kind,
vString *const signature, vString *const inheritance)
{
return makeJsTagCommon (token, kind, signature, inheritance, false, true);
return makeJsTagCommon (token, kind, signature, inheritance, false, false, false, true);
}

static int makeClassTagCommon (tokenInfo *const token, vString *const signature,
vString *const inheritance, bool anonymous)
{
return makeJsTagCommon (token, JSTAG_CLASS, signature, inheritance, anonymous, false);
return makeJsTagCommon (token, JSTAG_CLASS, signature, inheritance, anonymous, false, false, false);
}

static int makeClassTag (tokenInfo *const token, vString *const signature,
@@ -598,7 +631,7 @@
bool generator, bool anonymous)
{
return makeJsTagCommon (token, generator ? JSTAG_GENERATOR : JSTAG_FUNCTION, signature, NULL,
anonymous, false);
anonymous, false, false, false);
}

static int makeFunctionTag (tokenInfo *const token, vString *const signature, bool generator)
@@ -1300,11 +1333,11 @@
case '#':
/* skip shebang in case of e.g. Node.js scripts */
if (token->lineNumber > 1)
token->type = TOKEN_UNDEFINED;
token->type = TOKEN_HASH;
else if ((c = getcFromInputFile ()) != '!')
{
ungetcToInputFile (c);
token->type = TOKEN_UNDEFINED;
token->type = TOKEN_HASH;

Check warning on line 1340 in parsers/jscript.c

Codecov / codecov/patch

parsers/jscript.c#L1340

Added line #L1340 was not covered by tests
}
else
{
@@ -1530,7 +1563,7 @@
anonGenerate (anon_object->string, "anonymousObject", JSTAG_VARIABLE);
anon_object->type = TOKEN_IDENTIFIER;

index = makeJsTagCommon (anon_object, JSTAG_VARIABLE, NULL, NULL, true, false);
index = makeJsTagCommon (anon_object, JSTAG_VARIABLE, NULL, NULL, true, false, false, false);
if (! parseMethods (token, index, false))
{
/* If no method is found, the anonymous object
@@ -2162,6 +2195,7 @@
{
bool is_setter = false;
bool is_getter = false;
bool is_static = false;

if (!dont_read)
readToken (token);
@@ -2204,6 +2238,9 @@
else if (isKeyword (saved_token, KEYWORD_async) ||
isKeyword (saved_token, KEYWORD_static))
{
if (isKeyword (saved_token, KEYWORD_static))
is_static = true;

/* can be a qualifier for another "keyword", so start over */
deleteToken (saved_token);
goto start;
@@ -2222,6 +2259,7 @@
! isType (token, TOKEN_SEMICOLON))
{
bool is_generator = false;
bool is_private = false;
bool is_shorthand = false; /* ES6 shorthand syntax */
bool is_computed_name = false; /* ES6 computed property name */
bool is_dynamic_prop = false;
@@ -2235,6 +2273,11 @@
is_generator = true;
readToken (token);
}
else if (isType (token, TOKEN_HASH))
{
is_private = true;
readToken (token);
}

if (isType (token, TOKEN_OPEN_SQUARE))
{
@@ -2352,7 +2395,7 @@
else if (is_setter)
kind = JSTAG_SETTER;

index_for_name = makeJsTag (name, kind, signature, NULL);
index_for_name = makeJsTagMaybePrivate (name, kind, signature, NULL, is_static, is_private);
parseBlock (token, index_for_name);

/*
@@ -2448,7 +2491,7 @@
else
{
bool is_property = isType (token, TOKEN_COMMA);
makeJsTag (name, is_property ? JSTAG_PROPERTY : JSTAG_FIELD, NULL, NULL);
makeJsTagMaybePrivate (name, is_property ? JSTAG_PROPERTY : JSTAG_FIELD, NULL, NULL, is_static, is_private);
if (!isType (token, TOKEN_SEMICOLON) && !is_property)
dont_read = true;
}
@@ -2517,7 +2560,7 @@
TRACE_PRINT("Emitting tag for class '%s'", vStringValue(target_name->string));

int r = makeJsTagCommon (target_name, JSTAG_CLASS, NULL, inheritance,
(is_anonymous && (target_name == class_name)), false);
(is_anonymous && (target_name == class_name)), false, false, false);

if (! is_anonymous && target_name != class_name)
{
@@ -2855,7 +2898,7 @@
if ( parseMethods(token, p, false) )
{
jsKind kind = state->foundThis || strchr (vStringValue(name->string), '.') != NULL ? JSTAG_PROPERTY : JSTAG_VARIABLE;
state->indexForName = makeJsTagCommon (name, kind, NULL, NULL, anon_object, false);
state->indexForName = makeJsTagCommon (name, kind, NULL, NULL, anon_object, false, false, false);
moveChildren (p, state->indexForName);
}
else if ( token->nestLevel == 0 && state->isGlobal )
@@ -2902,7 +2945,7 @@
*/
if ( ( token->nestLevel == 0 && state->isGlobal ) || kind == JSTAG_PROPERTY )
{
state->indexForName = makeJsTagCommon (name, kind, NULL, NULL, false, false);
state->indexForName = makeJsTagCommon (name, kind, NULL, NULL, false, false, false, false);
}
}
else if (isKeyword (token, KEYWORD_new))
@@ -3762,6 +3805,8 @@
*/
def->kindTable = JsKinds;
def->kindCount = ARRAY_SIZE (JsKinds);
def->fieldTable = JsFields;
def->fieldCount = ARRAY_SIZE (JsFields);
def->parser = findJsTags;
def->initialize = initialize;
def->finalize = finalize;
@@ -3773,8 +3818,8 @@
def->dependencies = dependencies;
def->dependencyCount = ARRAY_SIZE (dependencies);

def->versionCurrent = 1;
def->versionAge = 1;
def->versionCurrent = 2;
def->versionAge = 2;

return def;
}