Skip to content

Commit

Permalink
Allow parsing of 'static' in class properties
Browse files Browse the repository at this point in the history
Summary:
Original Author: [email protected]
Original Git: 0d01268

`static` can be used as a property name as well as a method name now.
Modify the checks in `parseClassElement` which special-case `static`
to see whether it's a modifier or the property name to also check for
class properties.

Original Reviewed By: tmikov

Original Revision: D42562106

Reviewed By: jpporto

Differential Revision: D43197056

fbshipit-source-id: 5d07d9843c5303ca72f497c24d4dabda068cf70c
  • Loading branch information
avp authored and facebook-github-bot committed Feb 15, 2023
1 parent 95209da commit ccdac85
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 4 deletions.
30 changes: 26 additions & 4 deletions lib/Parser/JSParserImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4666,6 +4666,28 @@ Optional<ESTree::Node *> JSParserImpl::parseClassElement(
// function names instead of as getter/setter specifiers.
bool doParsePropertyName = true;

/// \return true when the current token indicates that `static` was actually
/// the property name and not a modifier.
/// e.g. `static() {}` returns true when the current tok is '(',
/// but `static x;` returns false when the current tok is 'x'.
/// When this returns `true`, we're done parsing the property name,
/// and we might have to use `static` as the property name if it was given in.
const auto staticIsPropertyName = [this]() -> bool {
if (checkN(
TokenKind::l_paren,
TokenKind::equal,
TokenKind::r_brace,
TokenKind::semi)) {
return true;
}
#if HERMES_PARSE_FLOW || HERMES_PARSE_TS
if (context_.getParseTypes() && check(TokenKind::less, TokenKind::colon)) {
return true;
}
#endif
return false;
};

ESTree::Node *prop = nullptr;
if (check(getIdent_)) {
SMRange range = advance();
Expand Down Expand Up @@ -4727,10 +4749,10 @@ Optional<ESTree::Node *> JSParserImpl::parseClassElement(
}
} else if (checkAndEat(TokenKind::star)) {
special = SpecialKind::Generator;
} else if (check(TokenKind::l_paren, TokenKind::less) && isStatic) {
// We've already parsed 'static', but there is nothing between 'static'
// and the '(', so it must be used as the PropertyName and not as an
// indicator for a static function.
} else if (isStatic && staticIsPropertyName()) {
// This is the name of the property/method.
// We've already parsed 'static', but it must be used as the
// PropertyName and not as an indicator for a static function.
prop = setLocation(
startRange,
startRange,
Expand Down
163 changes: 163 additions & 0 deletions test/Parser/es6/class-props-reserved.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

// RUN: %hermesc -dump-ast -pretty-json %s | %FileCheck %s --match-full-lines

// CHECK-LABEL: {
// CHECK-NEXT: "type": "Program",
// CHECK-NEXT: "body": [

class Foo {
static = 1;
}
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassDeclaration",
// CHECK-NEXT: "id": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "Foo"
// CHECK-NEXT: },
// CHECK-NEXT: "superClass": null,
// CHECK-NEXT: "body": {
// CHECK-NEXT: "type": "ClassBody",
// CHECK-NEXT: "body": [
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassProperty",
// CHECK-NEXT: "key": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "static"
// CHECK-NEXT: },
// CHECK-NEXT: "value": {
// CHECK-NEXT: "type": "NumericLiteral",
// CHECK-NEXT: "value": 1,
// CHECK-NEXT: "raw": "1"
// CHECK-NEXT: },
// CHECK-NEXT: "computed": false,
// CHECK-NEXT: "static": false,
// CHECK-NEXT: "declare": false
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: },

class Foo {
static;
}
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassDeclaration",
// CHECK-NEXT: "id": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "Foo"
// CHECK-NEXT: },
// CHECK-NEXT: "superClass": null,
// CHECK-NEXT: "body": {
// CHECK-NEXT: "type": "ClassBody",
// CHECK-NEXT: "body": [
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassProperty",
// CHECK-NEXT: "key": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "static"
// CHECK-NEXT: },
// CHECK-NEXT: "value": null,
// CHECK-NEXT: "computed": false,
// CHECK-NEXT: "static": false,
// CHECK-NEXT: "declare": false
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: },

class Foo {
public;
}
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassDeclaration",
// CHECK-NEXT: "id": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "Foo"
// CHECK-NEXT: },
// CHECK-NEXT: "superClass": null,
// CHECK-NEXT: "body": {
// CHECK-NEXT: "type": "ClassBody",
// CHECK-NEXT: "body": [
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassProperty",
// CHECK-NEXT: "key": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "public"
// CHECK-NEXT: },
// CHECK-NEXT: "value": null,
// CHECK-NEXT: "computed": false,
// CHECK-NEXT: "static": false,
// CHECK-NEXT: "declare": false
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: },

class Foo {
protected = 1;
}
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassDeclaration",
// CHECK-NEXT: "id": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "Foo"
// CHECK-NEXT: },
// CHECK-NEXT: "superClass": null,
// CHECK-NEXT: "body": {
// CHECK-NEXT: "type": "ClassBody",
// CHECK-NEXT: "body": [
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassProperty",
// CHECK-NEXT: "key": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "protected"
// CHECK-NEXT: },
// CHECK-NEXT: "value": {
// CHECK-NEXT: "type": "NumericLiteral",
// CHECK-NEXT: "value": 1,
// CHECK-NEXT: "raw": "1"
// CHECK-NEXT: },
// CHECK-NEXT: "computed": false,
// CHECK-NEXT: "static": false,
// CHECK-NEXT: "declare": false
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: },

class Foo {
static static;
}
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassDeclaration",
// CHECK-NEXT: "id": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "Foo"
// CHECK-NEXT: },
// CHECK-NEXT: "superClass": null,
// CHECK-NEXT: "body": {
// CHECK-NEXT: "type": "ClassBody",
// CHECK-NEXT: "body": [
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassProperty",
// CHECK-NEXT: "key": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "static"
// CHECK-NEXT: },
// CHECK-NEXT: "value": null,
// CHECK-NEXT: "computed": false,
// CHECK-NEXT: "static": true,
// CHECK-NEXT: "declare": false
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: }

// CHECK-NEXT: ]
// CHECK-NEXT: }
66 changes: 66 additions & 0 deletions test/Parser/flow/class-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,72 @@ class C {
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: },

class C {
static: number;
}
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassDeclaration",
// CHECK-NEXT: "id": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "C"
// CHECK-NEXT: },
// CHECK-NEXT: "superClass": null,
// CHECK-NEXT: "body": {
// CHECK-NEXT: "type": "ClassBody",
// CHECK-NEXT: "body": [
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassProperty",
// CHECK-NEXT: "key": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "static"
// CHECK-NEXT: },
// CHECK-NEXT: "value": null,
// CHECK-NEXT: "computed": false,
// CHECK-NEXT: "static": false,
// CHECK-NEXT: "declare": false,
// CHECK-NEXT: "typeAnnotation": {
// CHECK-NEXT: "type": "TypeAnnotation",
// CHECK-NEXT: "typeAnnotation": {
// CHECK-NEXT: "type": "NumberTypeAnnotation"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: },

class C {
static +x;
}
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassDeclaration",
// CHECK-NEXT: "id": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "C"
// CHECK-NEXT: },
// CHECK-NEXT: "superClass": null,
// CHECK-NEXT: "body": {
// CHECK-NEXT: "type": "ClassBody",
// CHECK-NEXT: "body": [
// CHECK-NEXT: {
// CHECK-NEXT: "type": "ClassProperty",
// CHECK-NEXT: "key": {
// CHECK-NEXT: "type": "Identifier",
// CHECK-NEXT: "name": "x"
// CHECK-NEXT: },
// CHECK-NEXT: "value": null,
// CHECK-NEXT: "computed": false,
// CHECK-NEXT: "static": true,
// CHECK-NEXT: "declare": false,
// CHECK-NEXT: "variance": {
// CHECK-NEXT: "type": "Variance",
// CHECK-NEXT: "kind": "plus"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: }

// CHECK-NEXT: ]
Expand Down

0 comments on commit ccdac85

Please sign in to comment.