add support for private fields in classes

This commit is contained in:
Erik Krogh Kristensen
2020-01-29 13:06:45 +01:00
parent fb90c2ba52
commit b8834ffcad
9 changed files with 201 additions and 4 deletions

View File

@@ -5,6 +5,7 @@ import static com.semmle.jcorn.Whitespace.lineBreak;
import com.semmle.jcorn.Identifiers.Dialect;
import com.semmle.jcorn.Options.AllowReserved;
import com.semmle.jcorn.TokenType.Properties;
import com.semmle.js.ast.ArrayExpression;
import com.semmle.js.ast.ArrayPattern;
import com.semmle.js.ast.ArrowFunctionExpression;
@@ -44,6 +45,7 @@ import com.semmle.js.ast.INode;
import com.semmle.js.ast.IPattern;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.IfStatement;
import com.semmle.js.ast.FieldDefinition;
import com.semmle.js.ast.ImportDeclaration;
import com.semmle.js.ast.ImportDefaultSpecifier;
import com.semmle.js.ast.ImportNamespaceSpecifier;
@@ -124,6 +126,7 @@ public class Parser {
private boolean inModule;
protected boolean inFunction;
protected boolean inGenerator;
protected boolean inClass;
protected boolean inAsync;
protected boolean inTemplateElement;
protected int pos;
@@ -240,8 +243,8 @@ public class Parser {
// Used to signify the start of a potential arrow function
this.potentialArrowAt = -1;
// Flags to track whether we are in a function, a generator, an async function.
this.inFunction = this.inGenerator = this.inAsync = false;
// Flags to track whether we are in a function, a generator, an async function, a class.
this.inFunction = this.inGenerator = this.inAsync = this.inClass = false;
// Positions to delayed-check that yield/await does not exist in default parameters.
this.yieldPos = this.awaitPos = 0;
// Labels in scope.
@@ -651,6 +654,9 @@ public class Parser {
case 58:
++this.pos;
return this.finishToken(TokenType.colon);
case 35:
++this.pos;
return this.finishToken(TokenType.pound);
case 63:
return this.readToken_question();
@@ -2191,6 +2197,7 @@ public class Parser {
// identifiers.
protected Identifier parseIdent(boolean liberal) {
Position startLoc = this.startLoc;
boolean isPrivateField = liberal && this.eat(TokenType.pound);
if (liberal && this.options.allowReserved() == AllowReserved.NEVER) liberal = false;
String name = null;
if (this.type == TokenType.name) {
@@ -2199,9 +2206,9 @@ public class Parser {
&& (this.options.ecmaVersion() >= 6
|| inputSubstring(this.start, this.end).indexOf("\\") == -1))
this.raiseRecoverable(this.start, "The keyword '" + this.value + "' is reserved");
if (this.inGenerator && this.value.equals("yield"))
if (!isPrivateField && this.inGenerator && this.value.equals("yield"))
this.raiseRecoverable(this.start, "Can not use 'yield' as identifier inside a generator");
if (this.inAsync && this.value.equals("await"))
if (!isPrivateField && this.inAsync && this.value.equals("await"))
this.raiseRecoverable(
this.start, "Can not use 'await' as identifier inside an async function");
name = String.valueOf(this.value);
@@ -2213,6 +2220,12 @@ public class Parser {
this.unexpected();
}
this.next();
if (isPrivateField) {
if (!this.inClass) {
this.raiseRecoverable(this.start, "Cannot use private fields outside a class");
}
name = "#" + name;
}
Identifier node = new Identifier(new SourceLocation(startLoc), name);
return this.finishNode(node);
}
@@ -3127,6 +3140,8 @@ public class Parser {
// Parse a class declaration or literal (depending on the
// `isStatement` parameter).
protected Node parseClass(Position startLoc, boolean isStatement) {
boolean oldInClass = this.inClass;
this.inClass = true;
SourceLocation loc = new SourceLocation(startLoc);
this.next();
Identifier id = this.parseClassId(isStatement);
@@ -3145,6 +3160,8 @@ public class Parser {
Node node;
if (isStatement) node = new ClassDeclaration(loc, id, superClass, classBody);
else node = new ClassExpression(loc, id, superClass, classBody);
this.inClass = oldInClass;
return this.finishNode(node);
}

View File

@@ -85,6 +85,7 @@ public class TokenType {
dot = new TokenType(new Properties(".")),
questiondot = new TokenType(new Properties("?.")),
question = new TokenType(new Properties("?").beforeExpr()),
pound = new TokenType(kw("#")),
arrow = new TokenType(new Properties("=>").beforeExpr()),
template = new TokenType(new Properties("template")),
invalidTemplate = new TokenType(new Properties("invalidTemplate")),