JavaScript: Autoformat extractor sources using google-java-format.

No special settings; command:

  find javascript/extractor/src -name "*.java" | xargs java -jar /path/to/google-java-format-1.7-all-deps.jar --replace
This commit is contained in:
Max Schaefer
2019-02-28 14:30:06 +00:00
parent 5478e0da62
commit c4fa29dd0f
304 changed files with 30389 additions and 30395 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,5 @@
package com.semmle.jcorn; package com.semmle.jcorn;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.semmle.jcorn.TokenType.Properties; import com.semmle.jcorn.TokenType.Properties;
import com.semmle.jcorn.jsx.JSXParser; import com.semmle.jcorn.jsx.JSXParser;
import com.semmle.js.ast.BindExpression; import com.semmle.js.ast.BindExpression;
@@ -42,457 +37,460 @@ import com.semmle.js.ast.Statement;
import com.semmle.js.ast.Token; import com.semmle.js.ast.Token;
import com.semmle.util.collections.CollectionUtil; import com.semmle.util.collections.CollectionUtil;
import com.semmle.util.data.Pair; import com.semmle.util.data.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* An extension of the {@link JSXParser} with support for various * An extension of the {@link JSXParser} with support for various unfinished ECMAScript proposals
* unfinished ECMAScript proposals that are not supported by * that are not supported by Acorn/jcorn yet.
* Acorn/jcorn yet.
* *
* Once support becomes available, they should be removed from * <p>Once support becomes available, they should be removed from this class.
* this class.
*/ */
public class ESNextParser extends JSXParser { public class ESNextParser extends JSXParser {
public ESNextParser(Options options, String input, int startPos) { public ESNextParser(Options options, String input, int startPos) {
super(options.allowImportExportEverywhere(true), input, startPos); super(options.allowImportExportEverywhere(true), input, startPos);
} }
/* /*
* Support for proposed language feature "Object Rest/Spread Properties" * Support for proposed language feature "Object Rest/Spread Properties"
* (http://sebmarkbage.github.io/ecmascript-rest-spread/). * (http://sebmarkbage.github.io/ecmascript-rest-spread/).
*/ */
@Override @Override
protected Property parseProperty(boolean isPattern, DestructuringErrors refDestructuringErrors, protected Property parseProperty(
Map<String, PropInfo> propHash) { boolean isPattern,
Position start = this.startLoc; DestructuringErrors refDestructuringErrors,
Map<String, PropInfo> propHash) {
Position start = this.startLoc;
List<Decorator> decorators = parseDecorators(); List<Decorator> decorators = parseDecorators();
Property prop = null; Property prop = null;
if (this.type == TokenType.ellipsis) { if (this.type == TokenType.ellipsis) {
SpreadElement spread = this.parseSpread(null); SpreadElement spread = this.parseSpread(null);
Expression val; Expression val;
if (isPattern) if (isPattern) val = new RestElement(spread.getLoc(), spread.getArgument());
val = new RestElement(spread.getLoc(), spread.getArgument()); else val = spread;
else prop =
val = spread; this.finishNode(
prop = this.finishNode(new Property(new SourceLocation(start), null, val, Property.Kind.INIT.name(), false, false)); new Property(
} new SourceLocation(start), null, val, Property.Kind.INIT.name(), false, false));
}
if (prop == null) if (prop == null) prop = super.parseProperty(isPattern, refDestructuringErrors, propHash);
prop = super.parseProperty(isPattern, refDestructuringErrors, propHash);
prop.addDecorators(decorators); prop.addDecorators(decorators);
return prop; return prop;
} }
@Override @Override
protected INode toAssignable(INode node, boolean isBinding) { protected INode toAssignable(INode node, boolean isBinding) {
if (node instanceof SpreadElement) if (node instanceof SpreadElement)
return new RestElement(node.getLoc(), ((SpreadElement) node).getArgument()); return new RestElement(node.getLoc(), ((SpreadElement) node).getArgument());
return super.toAssignable(node, isBinding); return super.toAssignable(node, isBinding);
} }
@Override @Override
protected void checkLVal(INode expr, boolean isBinding, Set<String> checkClashes) { protected void checkLVal(INode expr, boolean isBinding, Set<String> checkClashes) {
super.checkLVal(expr, isBinding, checkClashes); super.checkLVal(expr, isBinding, checkClashes);
if (expr instanceof ObjectPattern) { if (expr instanceof ObjectPattern) {
ObjectPattern op = (ObjectPattern) expr; ObjectPattern op = (ObjectPattern) expr;
if (op.hasRest()) if (op.hasRest()) checkLVal(op.getRest(), isBinding, checkClashes);
checkLVal(op.getRest(), isBinding, checkClashes); }
} }
}
/* /*
* Support for proposed language feature "Public Class Fields" * Support for proposed language feature "Public Class Fields"
* (http://jeffmo.github.io/es-class-public-fields/). * (http://jeffmo.github.io/es-class-public-fields/).
*/ */
private boolean classProperties() { private boolean classProperties() {
return options.esnext(); return options.esnext();
} }
@Override @Override
protected MemberDefinition<?> parseClassPropertyBody(PropertyInfo pi, protected MemberDefinition<?> parseClassPropertyBody(
boolean hadConstructor, boolean isStatic) { PropertyInfo pi, boolean hadConstructor, boolean isStatic) {
if (classProperties() && !pi.isGenerator && this.isClassProperty()) if (classProperties() && !pi.isGenerator && this.isClassProperty())
return this.parseFieldDefinition(pi, isStatic); return this.parseFieldDefinition(pi, isStatic);
return super.parseClassPropertyBody(pi, hadConstructor, isStatic); return super.parseClassPropertyBody(pi, hadConstructor, isStatic);
} }
protected boolean isClassProperty() { protected boolean isClassProperty() {
return this.type == TokenType.eq || this.type == TokenType.semi || this.canInsertSemicolon(); return this.type == TokenType.eq || this.type == TokenType.semi || this.canInsertSemicolon();
} }
protected FieldDefinition parseFieldDefinition(PropertyInfo pi, boolean isStatic) { protected FieldDefinition parseFieldDefinition(PropertyInfo pi, boolean isStatic) {
Expression value = null; Expression value = null;
if (this.type == TokenType.eq) { if (this.type == TokenType.eq) {
this.next(); this.next();
boolean oldInFunc = this.inFunction; boolean oldInFunc = this.inFunction;
this.inFunction = true; this.inFunction = true;
value = parseMaybeAssign(false, null, null); value = parseMaybeAssign(false, null, null);
this.inFunction = oldInFunc; this.inFunction = oldInFunc;
} }
this.semicolon(); this.semicolon();
int flags = DeclarationFlags.getStatic(isStatic) | DeclarationFlags.getComputed(pi.computed); int flags = DeclarationFlags.getStatic(isStatic) | DeclarationFlags.getComputed(pi.computed);
return this.finishNode(new FieldDefinition(new SourceLocation(pi.startLoc), flags, pi.key, value)); return this.finishNode(
} new FieldDefinition(new SourceLocation(pi.startLoc), flags, pi.key, value));
}
/* /*
* Support for proposed language feature "Generator function.sent Meta Property" * Support for proposed language feature "Generator function.sent Meta Property"
* (https://github.com/allenwb/ESideas/blob/master/Generator%20metaproperty.md) * (https://github.com/allenwb/ESideas/blob/master/Generator%20metaproperty.md)
*/ */
private boolean functionSent() { private boolean functionSent() {
return options.esnext(); return options.esnext();
} }
@Override @Override
protected INode parseFunction(Position startLoc, boolean isStatement, protected INode parseFunction(
boolean allowExpressionBody, boolean isAsync) { Position startLoc, boolean isStatement, boolean allowExpressionBody, boolean isAsync) {
if (isFunctionSent(isStatement)) { if (isFunctionSent(isStatement)) {
Identifier meta = this.finishNode(new Identifier(new SourceLocation(startLoc), "function")); Identifier meta = this.finishNode(new Identifier(new SourceLocation(startLoc), "function"));
this.next(); this.next();
Identifier property = parseIdent(true); Identifier property = parseIdent(true);
if (!property.getName().equals("sent")) if (!property.getName().equals("sent"))
this.raiseRecoverable(property, "The only valid meta property for function is function.sent"); this.raiseRecoverable(
return this.finishNode(new MetaProperty(new SourceLocation(startLoc), meta, property)); property, "The only valid meta property for function is function.sent");
} return this.finishNode(new MetaProperty(new SourceLocation(startLoc), meta, property));
}
return super.parseFunction(startLoc, isStatement, allowExpressionBody, isAsync); return super.parseFunction(startLoc, isStatement, allowExpressionBody, isAsync);
} }
protected boolean isFunctionSent(boolean isStatement) { protected boolean isFunctionSent(boolean isStatement) {
return functionSent() && !isStatement && inGenerator && !inAsync && this.type == TokenType.dot; return functionSent() && !isStatement && inGenerator && !inAsync && this.type == TokenType.dot;
} }
/* /*
* Support for proposed language feature "Class and Property Decorators" * Support for proposed language feature "Class and Property Decorators"
* (https://github.com/wycats/javascript-decorators) * (https://github.com/wycats/javascript-decorators)
*/ */
private boolean decorators() { private boolean decorators() {
return options.esnext(); return options.esnext();
} }
protected TokenType at = new TokenType(new Properties("@").beforeExpr()); protected TokenType at = new TokenType(new Properties("@").beforeExpr());
@Override @Override
protected Token getTokenFromCode(int code) { protected Token getTokenFromCode(int code) {
if (decorators() && code == 64) { if (decorators() && code == 64) {
++this.pos; ++this.pos;
return this.finishToken(at); return this.finishToken(at);
} }
if (functionBind() && code == 58 && charAt(this.pos+1) == 58) { if (functionBind() && code == 58 && charAt(this.pos + 1) == 58) {
this.pos += 2; this.pos += 2;
return this.finishToken(doubleColon); return this.finishToken(doubleColon);
} }
return super.getTokenFromCode(code); return super.getTokenFromCode(code);
} }
@Override @Override
protected Statement parseStatement(boolean declaration, boolean topLevel, protected Statement parseStatement(boolean declaration, boolean topLevel, Set<String> exports) {
Set<String> exports) { List<Decorator> decorators = this.parseDecorators();
List<Decorator> decorators = this.parseDecorators(); Statement stmt = super.parseStatement(declaration, topLevel, exports);
Statement stmt = super.parseStatement(declaration, topLevel, exports);
if (!decorators.isEmpty()) { if (!decorators.isEmpty()) {
if (stmt instanceof ExportDeclaration) { if (stmt instanceof ExportDeclaration) {
Node exported = null; Node exported = null;
if (stmt instanceof ExportDefaultDeclaration) { if (stmt instanceof ExportDefaultDeclaration) {
exported = ((ExportDefaultDeclaration) stmt).getDeclaration(); exported = ((ExportDefaultDeclaration) stmt).getDeclaration();
} else if (stmt instanceof ExportNamedDeclaration) { } else if (stmt instanceof ExportNamedDeclaration) {
exported = ((ExportNamedDeclaration) stmt).getDeclaration(); exported = ((ExportNamedDeclaration) stmt).getDeclaration();
} }
if (exported instanceof ClassDeclaration) { if (exported instanceof ClassDeclaration) {
((ClassDeclaration) exported).addDecorators(decorators); ((ClassDeclaration) exported).addDecorators(decorators);
} else if (exported instanceof ClassExpression) { } else if (exported instanceof ClassExpression) {
((ClassExpression) exported).addDecorators(decorators); ((ClassExpression) exported).addDecorators(decorators);
} else { } else {
this.raise(stmt, "Decorators can only be attached to class exports"); this.raise(stmt, "Decorators can only be attached to class exports");
} }
} else if (stmt instanceof ClassDeclaration) { } else if (stmt instanceof ClassDeclaration) {
((ClassDeclaration) stmt).addDecorators(decorators); ((ClassDeclaration) stmt).addDecorators(decorators);
} else if (stmt != null) { } else if (stmt != null) {
this.raise(stmt, "Leading decorators must be attached to a class declaration"); this.raise(stmt, "Leading decorators must be attached to a class declaration");
} }
} }
return stmt; return stmt;
} }
@Override @Override
protected Expression parseExprAtom(DestructuringErrors refDestructuringErrors) { protected Expression parseExprAtom(DestructuringErrors refDestructuringErrors) {
if (this.type == at) { if (this.type == at) {
List<Decorator> decorators = parseDecorators(); List<Decorator> decorators = parseDecorators();
ClassExpression ce = (ClassExpression) this.parseClass(startLoc, false); ClassExpression ce = (ClassExpression) this.parseClass(startLoc, false);
ce.addDecorators(decorators); ce.addDecorators(decorators);
return ce; return ce;
} }
if (this.type == doubleColon) { if (this.type == doubleColon) {
SourceLocation startLoc = new SourceLocation(this.startLoc); SourceLocation startLoc = new SourceLocation(this.startLoc);
this.next(); this.next();
int innerStart = this.start; int innerStart = this.start;
Position innerStartLoc = this.startLoc; Position innerStartLoc = this.startLoc;
Expression callee = parseSubscripts(parseExprAtom(null), innerStart, innerStartLoc, true); Expression callee = parseSubscripts(parseExprAtom(null), innerStart, innerStartLoc, true);
if (!(callee instanceof MemberExpression)) if (!(callee instanceof MemberExpression))
this.raiseRecoverable(callee, "Binding should be performed on a member expression."); this.raiseRecoverable(callee, "Binding should be performed on a member expression.");
return this.finishNode(new BindExpression(startLoc, null, callee)); return this.finishNode(new BindExpression(startLoc, null, callee));
} }
if (this.type == TokenType._import) { if (this.type == TokenType._import) {
Position startLoc = this.startLoc; Position startLoc = this.startLoc;
this.next(); this.next();
this.expect(TokenType.parenL); this.expect(TokenType.parenL);
return parseDynamicImport(startLoc); return parseDynamicImport(startLoc);
} }
return super.parseExprAtom(refDestructuringErrors); return super.parseExprAtom(refDestructuringErrors);
} }
@Override @Override
protected MemberDefinition<?> parseClassMember(boolean hadConstructor) { protected MemberDefinition<?> parseClassMember(boolean hadConstructor) {
List<Decorator> decorators = parseDecorators(); List<Decorator> decorators = parseDecorators();
MemberDefinition<?> member = super.parseClassMember(hadConstructor); MemberDefinition<?> member = super.parseClassMember(hadConstructor);
if (!decorators.isEmpty() && member.isConstructor()) if (!decorators.isEmpty() && member.isConstructor())
this.raiseRecoverable(member, "Decorators cannot be attached to class constructors."); this.raiseRecoverable(member, "Decorators cannot be attached to class constructors.");
member.addDecorators(decorators); member.addDecorators(decorators);
return member; return member;
} }
public List<Decorator> parseDecorators() { public List<Decorator> parseDecorators() {
List<Decorator> result = new ArrayList<Decorator>(); List<Decorator> result = new ArrayList<Decorator>();
while (this.type == at) while (this.type == at) result.add(this.parseDecorator());
result.add(this.parseDecorator()); return result;
return result; }
}
private Decorator parseDecorator() { private Decorator parseDecorator() {
Position start = startLoc; Position start = startLoc;
this.next(); this.next();
Expression body = parseDecoratorBody(); Expression body = parseDecoratorBody();
Decorator decorator = new Decorator(new SourceLocation(start), body); Decorator decorator = new Decorator(new SourceLocation(start), body);
return this.finishNode(decorator); return this.finishNode(decorator);
} }
protected Expression parseDecoratorBody() { protected Expression parseDecoratorBody() {
Expression base; Expression base;
int startPos = this.start; int startPos = this.start;
Position startLoc = this.startLoc; Position startLoc = this.startLoc;
if (this.type == TokenType.parenL) { if (this.type == TokenType.parenL) {
base = parseParenExpression(); base = parseParenExpression();
} else { } else {
base = parseIdent(true); base = parseIdent(true);
} }
return parseSubscripts(base, startPos, startLoc, false); return parseSubscripts(base, startPos, startLoc, false);
} }
/* /*
* Support for proposed extensions to `export` * Support for proposed extensions to `export`
* (http://leebyron.com/ecmascript-export-ns-from and http://leebyron.com/ecmascript-export-default-from) * (http://leebyron.com/ecmascript-export-ns-from and http://leebyron.com/ecmascript-export-default-from)
*/ */
private boolean exportExtensions() { private boolean exportExtensions() {
return options.esnext(); return options.esnext();
} }
@Override @Override
protected ExportDeclaration parseExportRest(SourceLocation exportStart, Set<String> exports) { protected ExportDeclaration parseExportRest(SourceLocation exportStart, Set<String> exports) {
if (exportExtensions() && this.isExportDefaultSpecifier()) { if (exportExtensions() && this.isExportDefaultSpecifier()) {
Position specStart = this.startLoc; Position specStart = this.startLoc;
Identifier exported = this.parseIdent(true); Identifier exported = this.parseIdent(true);
ExportDefaultSpecifier defaultSpec = this.finishNode(new ExportDefaultSpecifier(new SourceLocation(specStart), exported)); ExportDefaultSpecifier defaultSpec =
List<ExportSpecifier> specifiers = CollectionUtil.makeList(defaultSpec); this.finishNode(new ExportDefaultSpecifier(new SourceLocation(specStart), exported));
if (this.type == TokenType.comma && this.lookahead(1, true).equals("*")) { List<ExportSpecifier> specifiers = CollectionUtil.makeList(defaultSpec);
this.next(); if (this.type == TokenType.comma && this.lookahead(1, true).equals("*")) {
specStart = this.startLoc; this.next();
this.expect(TokenType.star); specStart = this.startLoc;
this.expectContextual("as"); this.expect(TokenType.star);
exported = this.parseIdent(false); this.expectContextual("as");
ExportNamespaceSpecifier nsSpec = this.finishNode(new ExportNamespaceSpecifier(new SourceLocation(specStart), exported)); exported = this.parseIdent(false);
specifiers.add(nsSpec); ExportNamespaceSpecifier nsSpec =
} else { this.finishNode(new ExportNamespaceSpecifier(new SourceLocation(specStart), exported));
this.parseExportSpecifiersMaybe(specifiers, exports); specifiers.add(nsSpec);
} } else {
Literal source = (Literal) this.parseExportFrom(specifiers, null, true); this.parseExportSpecifiersMaybe(specifiers, exports);
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source)); }
} Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source));
}
return super.parseExportRest(exportStart, exports); return super.parseExportRest(exportStart, exports);
} }
@Override @Override
protected ExportDeclaration parseExportAll(SourceLocation exportStart, Position starLoc, Set<String> exports) { protected ExportDeclaration parseExportAll(
if (exportExtensions() && this.eatContextual("as")) { SourceLocation exportStart, Position starLoc, Set<String> exports) {
Identifier exported = this.parseIdent(false); if (exportExtensions() && this.eatContextual("as")) {
ExportNamespaceSpecifier nsSpec = this.finishNode(new ExportNamespaceSpecifier(new SourceLocation(starLoc), exported)); Identifier exported = this.parseIdent(false);
List<ExportSpecifier> specifiers = CollectionUtil.makeList(nsSpec); ExportNamespaceSpecifier nsSpec =
this.parseExportSpecifiersMaybe(specifiers, exports); this.finishNode(new ExportNamespaceSpecifier(new SourceLocation(starLoc), exported));
Literal source = (Literal) this.parseExportFrom(specifiers, null, true); List<ExportSpecifier> specifiers = CollectionUtil.makeList(nsSpec);
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source)); this.parseExportSpecifiersMaybe(specifiers, exports);
} Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source));
}
return super.parseExportAll(exportStart, starLoc, exports); return super.parseExportAll(exportStart, starLoc, exports);
} }
private boolean isExportDefaultSpecifier() { private boolean isExportDefaultSpecifier() {
if (this.type == TokenType.name) { if (this.type == TokenType.name) {
return !this.value.equals("type") && return !this.value.equals("type")
!this.value.equals("async") && && !this.value.equals("async")
!this.value.equals("interface") && && !this.value.equals("interface")
!this.value.equals("let"); && !this.value.equals("let");
} }
if (this.type != TokenType._default) if (this.type != TokenType._default) return false;
return false;
return this.lookahead(1, true).equals(",") || this.lookaheadIsIdent("from", true); return this.lookahead(1, true).equals(",") || this.lookaheadIsIdent("from", true);
} }
private void parseExportSpecifiersMaybe(List<ExportSpecifier> specifiers, Set<String> exports) { private void parseExportSpecifiersMaybe(List<ExportSpecifier> specifiers, Set<String> exports) {
if (this.eat(TokenType.comma)) { if (this.eat(TokenType.comma)) {
specifiers.addAll(this.parseExportSpecifiers(exports)); specifiers.addAll(this.parseExportSpecifiers(exports));
} }
} }
/* /*
* Support for proposed language feature "Function Bind Syntax" * Support for proposed language feature "Function Bind Syntax"
* (https://github.com/tc39/proposal-bind-operator) * (https://github.com/tc39/proposal-bind-operator)
*/ */
private boolean functionBind() { private boolean functionBind() {
return options.esnext(); return options.esnext();
} }
protected TokenType doubleColon = new TokenType(new Properties("::").beforeExpr()); protected TokenType doubleColon = new TokenType(new Properties("::").beforeExpr());
@Override @Override
protected Pair<Expression, Boolean> parseSubscript(Expression base, Position startLoc, boolean noCalls) { protected Pair<Expression, Boolean> parseSubscript(
if (!noCalls && this.eat(doubleColon)) { Expression base, Position startLoc, boolean noCalls) {
Expression callee = parseSubscripts(parseExprAtom(null), this.start, this.startLoc, true); if (!noCalls && this.eat(doubleColon)) {
BindExpression bind = new BindExpression(new SourceLocation(startLoc), base, callee); Expression callee = parseSubscripts(parseExprAtom(null), this.start, this.startLoc, true);
return Pair.make(this.finishNode(bind), true); BindExpression bind = new BindExpression(new SourceLocation(startLoc), base, callee);
} return Pair.make(this.finishNode(bind), true);
return super.parseSubscript(base, startLoc, noCalls); }
} return super.parseSubscript(base, startLoc, noCalls);
}
/* /*
* Support for proposed language feature "Optional Catch Binding" * Support for proposed language feature "Optional Catch Binding"
* (https://github.com/tc39/proposal-optional-catch-binding) * (https://github.com/tc39/proposal-optional-catch-binding)
*/ */
@Override @Override
protected CatchClause parseCatchClause(Position startLoc) { protected CatchClause parseCatchClause(Position startLoc) {
this.next(); this.next();
Expression param = null; Expression param = null;
if (this.eat(TokenType.parenL)) { if (this.eat(TokenType.parenL)) {
param = this.parseBindingAtom(); param = this.parseBindingAtom();
this.checkLVal(param, true, null); this.checkLVal(param, true, null);
this.expect(TokenType.parenR); this.expect(TokenType.parenR);
} else if (!options.esnext()) { } else if (!options.esnext()) {
this.unexpected(); this.unexpected();
} }
BlockStatement catchBody = this.parseBlock(false); BlockStatement catchBody = this.parseBlock(false);
return this.finishNode(new CatchClause(new SourceLocation(startLoc), (IPattern)param, null, catchBody)); return this.finishNode(
} new CatchClause(new SourceLocation(startLoc), (IPattern) param, null, catchBody));
}
/* /*
* Support for proposed language feature "Dynamic import" * Support for proposed language feature "Dynamic import"
* (https://github.com/tc39/proposal-dynamic-import). * (https://github.com/tc39/proposal-dynamic-import).
*/ */
@Override @Override
protected Statement parseImport(Position startLoc) { protected Statement parseImport(Position startLoc) {
if (!options.esnext()) if (!options.esnext()) return super.parseImport(startLoc);
return super.parseImport(startLoc);
int startPos = this.start; int startPos = this.start;
SourceLocation loc = new SourceLocation(startLoc); SourceLocation loc = new SourceLocation(startLoc);
this.next(); this.next();
if (this.eat(TokenType.parenL)) { if (this.eat(TokenType.parenL)) {
DynamicImport di = parseDynamicImport(startLoc); DynamicImport di = parseDynamicImport(startLoc);
Expression expr = parseSubscripts(di, startPos, startLoc, false); Expression expr = parseSubscripts(di, startPos, startLoc, false);
return parseExpressionStatement(false, startLoc, expr); return parseExpressionStatement(false, startLoc, expr);
} else { } else {
return super.parseImportRest(loc); return super.parseImportRest(loc);
} }
} }
/** /**
* Parses a dynamic import, assuming that the keyword `import` and the * Parses a dynamic import, assuming that the keyword `import` and the opening parenthesis have
* opening parenthesis have already been consumed. * already been consumed.
*/ */
private DynamicImport parseDynamicImport(Position startLoc) { private DynamicImport parseDynamicImport(Position startLoc) {
Expression source = parseMaybeAssign(false, null, null); Expression source = parseMaybeAssign(false, null, null);
this.expect(TokenType.parenR); this.expect(TokenType.parenR);
DynamicImport di = this.finishNode(new DynamicImport(new SourceLocation(startLoc), source)); DynamicImport di = this.finishNode(new DynamicImport(new SourceLocation(startLoc), source));
return di; return di;
} }
/* /*
* Support for proposed language feature "Asynchronous iteration" * Support for proposed language feature "Asynchronous iteration"
* (https://github.com/tc39/proposal-async-iteration) * (https://github.com/tc39/proposal-async-iteration)
*/ */
@Override @Override
protected Statement parseForStatement(Position startLoc) { protected Statement parseForStatement(Position startLoc) {
int startPos = this.start; int startPos = this.start;
boolean isAwait = false; boolean isAwait = false;
if (this.inAsync && this.eatContextual("await")) if (this.inAsync && this.eatContextual("await")) isAwait = true;
isAwait = true; Statement forStmt = super.parseForStatement(startLoc);
Statement forStmt = super.parseForStatement(startLoc); if (isAwait) {
if (isAwait) { if (forStmt instanceof ForOfStatement) ((ForOfStatement) forStmt).setAwait(true);
if (forStmt instanceof ForOfStatement) else this.raiseRecoverable(startPos, "Only for-of statements can be annotated with 'await'.");
((ForOfStatement) forStmt).setAwait(true); }
else return forStmt;
this.raiseRecoverable(startPos, "Only for-of statements can be annotated with 'await'."); }
}
return forStmt;
}
@Override @Override
protected boolean parseGeneratorMarker(boolean isAsync) { protected boolean parseGeneratorMarker(boolean isAsync) {
// always allow `*`, even if `isAsync` is true // always allow `*`, even if `isAsync` is true
return this.eat(TokenType.star); return this.eat(TokenType.star);
} }
/* /*
* Support for proposed language feature "Numeric separators" * Support for proposed language feature "Numeric separators"
* (https://github.com/tc39/proposal-numeric-separator) * (https://github.com/tc39/proposal-numeric-separator)
*/ */
@Override @Override
protected Number readInt(int radix, Integer len) { protected Number readInt(int radix, Integer len) {
// implementation mostly copied from super class // implementation mostly copied from super class
int start = this.pos, code = -1; int start = this.pos, code = -1;
double total = 0; double total = 0;
// no leading underscore // no leading underscore
boolean underscoreAllowed = false; boolean underscoreAllowed = false;
for (int i = 0, e = len == null ? Integer.MAX_VALUE : len; i < e; ++i) { for (int i = 0, e = len == null ? Integer.MAX_VALUE : len; i < e; ++i) {
if (this.pos >= this.input.length()) if (this.pos >= this.input.length()) break;
break; code = this.input.charAt(this.pos);
code = this.input.charAt(this.pos);
if (code == '_') { if (code == '_') {
if (underscoreAllowed) { if (underscoreAllowed) {
// no adjacent underscores // no adjacent underscores
underscoreAllowed = false; underscoreAllowed = false;
++this.pos; ++this.pos;
continue; continue;
} }
} else { } else {
underscoreAllowed = true; underscoreAllowed = true;
} }
int val; int val;
if (code >= 97) val = code - 97 + 10; // a if (code >= 97) val = code - 97 + 10; // a
else if (code >= 65) val = code - 65 + 10; // A else if (code >= 65) val = code - 65 + 10; // A
else if (code >= 48 && code <= 57) val = code - 48; // 0-9 else if (code >= 48 && code <= 57) val = code - 48; // 0-9
else val = Integer.MAX_VALUE; else val = Integer.MAX_VALUE;
if (val >= radix) break; if (val >= radix) break;
++this.pos; ++this.pos;
total = total * radix + val; total = total * radix + val;
} }
if (this.pos == start || len != null && this.pos - start != len) return null; if (this.pos == start || len != null && this.pos - start != len) return null;
if (code == '_') if (code == '_')
// no trailing underscore // no trailing underscore
return null; return null;
return total; return total;
} }
} }

View File

@@ -8,110 +8,149 @@ import java.util.regex.Pattern;
/// identifier.js /// identifier.js
public class Identifiers { public class Identifiers {
public static enum Dialect { public static enum Dialect {
ECMA_3, ECMA_5, ECMA_6, ECMA_7, ECMA_8, STRICT, STRICT_BIND ECMA_3,
} ECMA_5,
ECMA_6,
ECMA_7,
ECMA_8,
STRICT,
STRICT_BIND
}
// Reserved word lists for various dialects of the language // Reserved word lists for various dialects of the language
public static final Map<Dialect, Set<String>> reservedWords = new LinkedHashMap<>(); public static final Map<Dialect, Set<String>> reservedWords = new LinkedHashMap<>();
static {
reservedWords.put(Dialect.ECMA_3, stringSet("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"));
reservedWords.put(Dialect.ECMA_5, stringSet("class enum extends super const export import"));
reservedWords.put(Dialect.ECMA_6, stringSet("enum"));
reservedWords.put(Dialect.ECMA_7, stringSet("enum"));
reservedWords.put(Dialect.ECMA_8, stringSet("enum"));
reservedWords.put(Dialect.STRICT, stringSet("implements interface let package private protected public static yield"));
reservedWords.put(Dialect.STRICT_BIND, stringSet("eval arguments"));
}
// And the keywords static {
private static final String ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"; reservedWords.put(
private static final String ecma6Keywords = ecma5AndLessKeywords + " const class extends export import super"; Dialect.ECMA_3,
stringSet(
"abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"));
reservedWords.put(Dialect.ECMA_5, stringSet("class enum extends super const export import"));
reservedWords.put(Dialect.ECMA_6, stringSet("enum"));
reservedWords.put(Dialect.ECMA_7, stringSet("enum"));
reservedWords.put(Dialect.ECMA_8, stringSet("enum"));
reservedWords.put(
Dialect.STRICT,
stringSet("implements interface let package private protected public static yield"));
reservedWords.put(Dialect.STRICT_BIND, stringSet("eval arguments"));
}
public static final Map<Dialect, Set<String>> keywords = new LinkedHashMap<>(); // And the keywords
static { private static final String ecma5AndLessKeywords =
keywords.put(Dialect.ECMA_5, stringSet(ecma5AndLessKeywords)); "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this";
keywords.put(Dialect.ECMA_6, stringSet(ecma6Keywords)); private static final String ecma6Keywords =
} ecma5AndLessKeywords + " const class extends export import super";
private static Set<String> stringSet(String words) { public static final Map<Dialect, Set<String>> keywords = new LinkedHashMap<>();
Set<String> result = new LinkedHashSet<String>();
for (String word : words.split(" "))
result.add(word);
return result;
}
// ## Character categories static {
keywords.put(Dialect.ECMA_5, stringSet(ecma5AndLessKeywords));
keywords.put(Dialect.ECMA_6, stringSet(ecma6Keywords));
}
private static final String nonASCIIidentifierStartChars = private static Set<String> stringSet(String words) {
"\\xaa\\xb5\\xba\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\u02c1\\u02c6-\\u02d1\\u02e0-\\u02e4\\u02ec\\u02ee\\u0370-\\u0374\\u0376\\u0377\\u037a-\\u037d\\u037f\\u0386\\u0388-\\u038a\\u038c\\u038e-\\u03a1\\u03a3-\\u03f5\\u03f7-\\u0481\\u048a-\\u052f\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05d0-\\u05ea\\u05f0-\\u05f2\\u0620-\\u064a\\u066e\\u066f\\u0671-\\u06d3\\u06d5\\u06e5\\u06e6\\u06ee\\u06ef\\u06fa-\\u06fc\\u06ff\\u0710\\u0712-\\u072f\\u074d-\\u07a5\\u07b1\\u07ca-\\u07ea\\u07f4\\u07f5\\u07fa\\u0800-\\u0815\\u081a\\u0824\\u0828\\u0840-\\u0858\\u08a0-\\u08b4\\u08b6-\\u08bd\\u0904-\\u0939\\u093d\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098c\\u098f\\u0990\\u0993-\\u09a8\\u09aa-\\u09b0\\u09b2\\u09b6-\\u09b9\\u09bd\\u09ce\\u09dc\\u09dd\\u09df-\\u09e1\\u09f0\\u09f1\\u0a05-\\u0a0a\\u0a0f\\u0a10\\u0a13-\\u0a28\\u0a2a-\\u0a30\\u0a32\\u0a33\\u0a35\\u0a36\\u0a38\\u0a39\\u0a59-\\u0a5c\\u0a5e\\u0a72-\\u0a74\\u0a85-\\u0a8d\\u0a8f-\\u0a91\\u0a93-\\u0aa8\\u0aaa-\\u0ab0\\u0ab2\\u0ab3\\u0ab5-\\u0ab9\\u0abd\\u0ad0\\u0ae0\\u0ae1\\u0af9\\u0b05-\\u0b0c\\u0b0f\\u0b10\\u0b13-\\u0b28\\u0b2a-\\u0b30\\u0b32\\u0b33\\u0b35-\\u0b39\\u0b3d\\u0b5c\\u0b5d\\u0b5f-\\u0b61\\u0b71\\u0b83\\u0b85-\\u0b8a\\u0b8e-\\u0b90\\u0b92-\\u0b95\\u0b99\\u0b9a\\u0b9c\\u0b9e\\u0b9f\\u0ba3\\u0ba4\\u0ba8-\\u0baa\\u0bae-\\u0bb9\\u0bd0\\u0c05-\\u0c0c\\u0c0e-\\u0c10\\u0c12-\\u0c28\\u0c2a-\\u0c39\\u0c3d\\u0c58-\\u0c5a\\u0c60\\u0c61\\u0c80\\u0c85-\\u0c8c\\u0c8e-\\u0c90\\u0c92-\\u0ca8\\u0caa-\\u0cb3\\u0cb5-\\u0cb9\\u0cbd\\u0cde\\u0ce0\\u0ce1\\u0cf1\\u0cf2\\u0d05-\\u0d0c\\u0d0e-\\u0d10\\u0d12-\\u0d3a\\u0d3d\\u0d4e\\u0d54-\\u0d56\\u0d5f-\\u0d61\\u0d7a-\\u0d7f\\u0d85-\\u0d96\\u0d9a-\\u0db1\\u0db3-\\u0dbb\\u0dbd\\u0dc0-\\u0dc6\\u0e01-\\u0e30\\u0e32\\u0e33\\u0e40-\\u0e46\\u0e81\\u0e82\\u0e84\\u0e87\\u0e88\\u0e8a\\u0e8d\\u0e94-\\u0e97\\u0e99-\\u0e9f\\u0ea1-\\u0ea3\\u0ea5\\u0ea7\\u0eaa\\u0eab\\u0ead-\\u0eb0\\u0eb2\\u0eb3\\u0ebd\\u0ec0-\\u0ec4\\u0ec6\\u0edc-\\u0edf\\u0f00\\u0f40-\\u0f47\\u0f49-\\u0f6c\\u0f88-\\u0f8c\\u1000-\\u102a\\u103f\\u1050-\\u1055\\u105a-\\u105d\\u1061\\u1065\\u1066\\u106e-\\u1070\\u1075-\\u1081\\u108e\\u10a0-\\u10c5\\u10c7\\u10cd\\u10d0-\\u10fa\\u10fc-\\u1248\\u124a-\\u124d\\u1250-\\u1256\\u1258\\u125a-\\u125d\\u1260-\\u1288\\u128a-\\u128d\\u1290-\\u12b0\\u12b2-\\u12b5\\u12b8-\\u12be\\u12c0\\u12c2-\\u12c5\\u12c8-\\u12d6\\u12d8-\\u1310\\u1312-\\u1315\\u1318-\\u135a\\u1380-\\u138f\\u13a0-\\u13f5\\u13f8-\\u13fd\\u1401-\\u166c\\u166f-\\u167f\\u1681-\\u169a\\u16a0-\\u16ea\\u16ee-\\u16f8\\u1700-\\u170c\\u170e-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176c\\u176e-\\u1770\\u1780-\\u17b3\\u17d7\\u17dc\\u1820-\\u1877\\u1880-\\u18a8\\u18aa\\u18b0-\\u18f5\\u1900-\\u191e\\u1950-\\u196d\\u1970-\\u1974\\u1980-\\u19ab\\u19b0-\\u19c9\\u1a00-\\u1a16\\u1a20-\\u1a54\\u1aa7\\u1b05-\\u1b33\\u1b45-\\u1b4b\\u1b83-\\u1ba0\\u1bae\\u1baf\\u1bba-\\u1be5\\u1c00-\\u1c23\\u1c4d-\\u1c4f\\u1c5a-\\u1c7d\\u1c80-\\u1c88\\u1ce9-\\u1cec\\u1cee-\\u1cf1\\u1cf5\\u1cf6\\u1d00-\\u1dbf\\u1e00-\\u1f15\\u1f18-\\u1f1d\\u1f20-\\u1f45\\u1f48-\\u1f4d\\u1f50-\\u1f57\\u1f59\\u1f5b\\u1f5d\\u1f5f-\\u1f7d\\u1f80-\\u1fb4\\u1fb6-\\u1fbc\\u1fbe\\u1fc2-\\u1fc4\\u1fc6-\\u1fcc\\u1fd0-\\u1fd3\\u1fd6-\\u1fdb\\u1fe0-\\u1fec\\u1ff2-\\u1ff4\\u1ff6-\\u1ffc\\u2071\\u207f\\u2090-\\u209c\\u2102\\u2107\\u210a-\\u2113\\u2115\\u2118-\\u211d\\u2124\\u2126\\u2128\\u212a-\\u2139\\u213c-\\u213f\\u2145-\\u2149\\u214e\\u2160-\\u2188\\u2c00-\\u2c2e\\u2c30-\\u2c5e\\u2c60-\\u2ce4\\u2ceb-\\u2cee\\u2cf2\\u2cf3\\u2d00-\\u2d25\\u2d27\\u2d2d\\u2d30-\\u2d67\\u2d6f\\u2d80-\\u2d96\\u2da0-\\u2da6\\u2da8-\\u2dae\\u2db0-\\u2db6\\u2db8-\\u2dbe\\u2dc0-\\u2dc6\\u2dc8-\\u2dce\\u2dd0-\\u2dd6\\u2dd8-\\u2dde\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303c\\u3041-\\u3096\\u309b-\\u309f\\u30a1-\\u30fa\\u30fc-\\u30ff\\u3105-\\u312d\\u3131-\\u318e\\u31a0-\\u31ba\\u31f0-\\u31ff\\u3400-\\u4db5\\u4e00-\\u9fd5\\ua000-\\ua48c\\ua4d0-\\ua4fd\\ua500-\\ua60c\\ua610-\\ua61f\\ua62a\\ua62b\\ua640-\\ua66e\\ua67f-\\ua69d\\ua6a0-\\ua6ef\\ua717-\\ua71f\\ua722-\\ua788\\ua78b-\\ua7ae\\ua7b0-\\ua7b7\\ua7f7-\\ua801\\ua803-\\ua805\\ua807-\\ua80a\\ua80c-\\ua822\\ua840-\\ua873\\ua882-\\ua8b3\\ua8f2-\\ua8f7\\ua8fb\\ua8fd\\ua90a-\\ua925\\ua930-\\ua946\\ua960-\\ua97c\\ua984-\\ua9b2\\ua9cf\\ua9e0-\\ua9e4\\ua9e6-\\ua9ef\\ua9fa-\\ua9fe\\uaa00-\\uaa28\\uaa40-\\uaa42\\uaa44-\\uaa4b\\uaa60-\\uaa76\\uaa7a\\uaa7e-\\uaaaf\\uaab1\\uaab5\\uaab6\\uaab9-\\uaabd\\uaac0\\uaac2\\uaadb-\\uaadd\\uaae0-\\uaaea\\uaaf2-\\uaaf4\\uab01-\\uab06\\uab09-\\uab0e\\uab11-\\uab16\\uab20-\\uab26\\uab28-\\uab2e\\uab30-\\uab5a\\uab5c-\\uab65\\uab70-\\uabe2\\uac00-\\ud7a3\\ud7b0-\\ud7c6\\ud7cb-\\ud7fb\\uf900-\\ufa6d\\ufa70-\\ufad9\\ufb00-\\ufb06\\ufb13-\\ufb17\\ufb1d\\ufb1f-\\ufb28\\ufb2a-\\ufb36\\ufb38-\\ufb3c\\ufb3e\\ufb40\\ufb41\\ufb43\\ufb44\\ufb46-\\ufbb1\\ufbd3-\\ufd3d\\ufd50-\\ufd8f\\ufd92-\\ufdc7\\ufdf0-\\ufdfb\\ufe70-\\ufe74\\ufe76-\\ufefc\\uff21-\\uff3a\\uff41-\\uff5a\\uff66-\\uffbe\\uffc2-\\uffc7\\uffca-\\uffcf\\uffd2-\\uffd7\\uffda-\\uffdc"; Set<String> result = new LinkedHashSet<String>();
private static final String nonASCIIidentifierChars = for (String word : words.split(" ")) result.add(word);
"\\u200c\\u200d\\xb7\\u0300-\\u036f\\u0387\\u0483-\\u0487\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u0669\\u0670\\u06d6-\\u06dc\\u06df-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u06f0-\\u06f9\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07c0-\\u07c9\\u07eb-\\u07f3\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0859-\\u085b\\u08d4-\\u08e1\\u08e3-\\u0903\\u093a-\\u093c\\u093e-\\u094f\\u0951-\\u0957\\u0962\\u0963\\u0966-\\u096f\\u0981-\\u0983\\u09bc\\u09be-\\u09c4\\u09c7\\u09c8\\u09cb-\\u09cd\\u09d7\\u09e2\\u09e3\\u09e6-\\u09ef\\u0a01-\\u0a03\\u0a3c\\u0a3e-\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a66-\\u0a71\\u0a75\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0ae2\\u0ae3\\u0ae6-\\u0aef\\u0b01-\\u0b03\\u0b3c\\u0b3e-\\u0b44\\u0b47\\u0b48\\u0b4b-\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b66-\\u0b6f\\u0b82\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0be6-\\u0bef\\u0c00-\\u0c03\\u0c3e-\\u0c44\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0c66-\\u0c6f\\u0c81-\\u0c83\\u0cbc\\u0cbe-\\u0cc4\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0ce6-\\u0cef\\u0d01-\\u0d03\\u0d3e-\\u0d44\\u0d46-\\u0d48\\u0d4a-\\u0d4d\\u0d57\\u0d62\\u0d63\\u0d66-\\u0d6f\\u0d82\\u0d83\\u0dca\\u0dcf-\\u0dd4\\u0dd6\\u0dd8-\\u0ddf\\u0de6-\\u0def\\u0df2\\u0df3\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0e50-\\u0e59\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0ed0-\\u0ed9\\u0f18\\u0f19\\u0f20-\\u0f29\\u0f35\\u0f37\\u0f39\\u0f3e\\u0f3f\\u0f71-\\u0f84\\u0f86\\u0f87\\u0f8d-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102b-\\u103e\\u1040-\\u1049\\u1056-\\u1059\\u105e-\\u1060\\u1062-\\u1064\\u1067-\\u106d\\u1071-\\u1074\\u1082-\\u108d\\u108f-\\u109d\\u135d-\\u135f\\u1369-\\u1371\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b4-\\u17d3\\u17dd\\u17e0-\\u17e9\\u180b-\\u180d\\u1810-\\u1819\\u18a9\\u1920-\\u192b\\u1930-\\u193b\\u1946-\\u194f\\u19d0-\\u19da\\u1a17-\\u1a1b\\u1a55-\\u1a5e\\u1a60-\\u1a7c\\u1a7f-\\u1a89\\u1a90-\\u1a99\\u1ab0-\\u1abd\\u1b00-\\u1b04\\u1b34-\\u1b44\\u1b50-\\u1b59\\u1b6b-\\u1b73\\u1b80-\\u1b82\\u1ba1-\\u1bad\\u1bb0-\\u1bb9\\u1be6-\\u1bf3\\u1c24-\\u1c37\\u1c40-\\u1c49\\u1c50-\\u1c59\\u1cd0-\\u1cd2\\u1cd4-\\u1ce8\\u1ced\\u1cf2-\\u1cf4\\u1cf8\\u1cf9\\u1dc0-\\u1df5\\u1dfb-\\u1dff\\u203f\\u2040\\u2054\\u20d0-\\u20dc\\u20e1\\u20e5-\\u20f0\\u2cef-\\u2cf1\\u2d7f\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua620-\\ua629\\ua66f\\ua674-\\ua67d\\ua69e\\ua69f\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua823-\\ua827\\ua880\\ua881\\ua8b4-\\ua8c5\\ua8d0-\\ua8d9\\ua8e0-\\ua8f1\\ua900-\\ua909\\ua926-\\ua92d\\ua947-\\ua953\\ua980-\\ua983\\ua9b3-\\ua9c0\\ua9d0-\\ua9d9\\ua9e5\\ua9f0-\\ua9f9\\uaa29-\\uaa36\\uaa43\\uaa4c\\uaa4d\\uaa50-\\uaa59\\uaa7b-\\uaa7d\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uaaeb-\\uaaef\\uaaf5\\uaaf6\\uabe3-\\uabea\\uabec\\uabed\\uabf0-\\uabf9\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe2f\\ufe33\\ufe34\\ufe4d-\\ufe4f\\uff10-\\uff19\\uff3f"; return result;
}
private static Pattern nonASCIIidentifierStartPattern; // ## Character categories
private static Pattern nonASCIIidentifierPattern;
private static Pattern nonASCIIidentifierStart() { private static final String nonASCIIidentifierStartChars =
if (nonASCIIidentifierStartPattern == null) "\\xaa\\xb5\\xba\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\u02c1\\u02c6-\\u02d1\\u02e0-\\u02e4\\u02ec\\u02ee\\u0370-\\u0374\\u0376\\u0377\\u037a-\\u037d\\u037f\\u0386\\u0388-\\u038a\\u038c\\u038e-\\u03a1\\u03a3-\\u03f5\\u03f7-\\u0481\\u048a-\\u052f\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05d0-\\u05ea\\u05f0-\\u05f2\\u0620-\\u064a\\u066e\\u066f\\u0671-\\u06d3\\u06d5\\u06e5\\u06e6\\u06ee\\u06ef\\u06fa-\\u06fc\\u06ff\\u0710\\u0712-\\u072f\\u074d-\\u07a5\\u07b1\\u07ca-\\u07ea\\u07f4\\u07f5\\u07fa\\u0800-\\u0815\\u081a\\u0824\\u0828\\u0840-\\u0858\\u08a0-\\u08b4\\u08b6-\\u08bd\\u0904-\\u0939\\u093d\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098c\\u098f\\u0990\\u0993-\\u09a8\\u09aa-\\u09b0\\u09b2\\u09b6-\\u09b9\\u09bd\\u09ce\\u09dc\\u09dd\\u09df-\\u09e1\\u09f0\\u09f1\\u0a05-\\u0a0a\\u0a0f\\u0a10\\u0a13-\\u0a28\\u0a2a-\\u0a30\\u0a32\\u0a33\\u0a35\\u0a36\\u0a38\\u0a39\\u0a59-\\u0a5c\\u0a5e\\u0a72-\\u0a74\\u0a85-\\u0a8d\\u0a8f-\\u0a91\\u0a93-\\u0aa8\\u0aaa-\\u0ab0\\u0ab2\\u0ab3\\u0ab5-\\u0ab9\\u0abd\\u0ad0\\u0ae0\\u0ae1\\u0af9\\u0b05-\\u0b0c\\u0b0f\\u0b10\\u0b13-\\u0b28\\u0b2a-\\u0b30\\u0b32\\u0b33\\u0b35-\\u0b39\\u0b3d\\u0b5c\\u0b5d\\u0b5f-\\u0b61\\u0b71\\u0b83\\u0b85-\\u0b8a\\u0b8e-\\u0b90\\u0b92-\\u0b95\\u0b99\\u0b9a\\u0b9c\\u0b9e\\u0b9f\\u0ba3\\u0ba4\\u0ba8-\\u0baa\\u0bae-\\u0bb9\\u0bd0\\u0c05-\\u0c0c\\u0c0e-\\u0c10\\u0c12-\\u0c28\\u0c2a-\\u0c39\\u0c3d\\u0c58-\\u0c5a\\u0c60\\u0c61\\u0c80\\u0c85-\\u0c8c\\u0c8e-\\u0c90\\u0c92-\\u0ca8\\u0caa-\\u0cb3\\u0cb5-\\u0cb9\\u0cbd\\u0cde\\u0ce0\\u0ce1\\u0cf1\\u0cf2\\u0d05-\\u0d0c\\u0d0e-\\u0d10\\u0d12-\\u0d3a\\u0d3d\\u0d4e\\u0d54-\\u0d56\\u0d5f-\\u0d61\\u0d7a-\\u0d7f\\u0d85-\\u0d96\\u0d9a-\\u0db1\\u0db3-\\u0dbb\\u0dbd\\u0dc0-\\u0dc6\\u0e01-\\u0e30\\u0e32\\u0e33\\u0e40-\\u0e46\\u0e81\\u0e82\\u0e84\\u0e87\\u0e88\\u0e8a\\u0e8d\\u0e94-\\u0e97\\u0e99-\\u0e9f\\u0ea1-\\u0ea3\\u0ea5\\u0ea7\\u0eaa\\u0eab\\u0ead-\\u0eb0\\u0eb2\\u0eb3\\u0ebd\\u0ec0-\\u0ec4\\u0ec6\\u0edc-\\u0edf\\u0f00\\u0f40-\\u0f47\\u0f49-\\u0f6c\\u0f88-\\u0f8c\\u1000-\\u102a\\u103f\\u1050-\\u1055\\u105a-\\u105d\\u1061\\u1065\\u1066\\u106e-\\u1070\\u1075-\\u1081\\u108e\\u10a0-\\u10c5\\u10c7\\u10cd\\u10d0-\\u10fa\\u10fc-\\u1248\\u124a-\\u124d\\u1250-\\u1256\\u1258\\u125a-\\u125d\\u1260-\\u1288\\u128a-\\u128d\\u1290-\\u12b0\\u12b2-\\u12b5\\u12b8-\\u12be\\u12c0\\u12c2-\\u12c5\\u12c8-\\u12d6\\u12d8-\\u1310\\u1312-\\u1315\\u1318-\\u135a\\u1380-\\u138f\\u13a0-\\u13f5\\u13f8-\\u13fd\\u1401-\\u166c\\u166f-\\u167f\\u1681-\\u169a\\u16a0-\\u16ea\\u16ee-\\u16f8\\u1700-\\u170c\\u170e-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176c\\u176e-\\u1770\\u1780-\\u17b3\\u17d7\\u17dc\\u1820-\\u1877\\u1880-\\u18a8\\u18aa\\u18b0-\\u18f5\\u1900-\\u191e\\u1950-\\u196d\\u1970-\\u1974\\u1980-\\u19ab\\u19b0-\\u19c9\\u1a00-\\u1a16\\u1a20-\\u1a54\\u1aa7\\u1b05-\\u1b33\\u1b45-\\u1b4b\\u1b83-\\u1ba0\\u1bae\\u1baf\\u1bba-\\u1be5\\u1c00-\\u1c23\\u1c4d-\\u1c4f\\u1c5a-\\u1c7d\\u1c80-\\u1c88\\u1ce9-\\u1cec\\u1cee-\\u1cf1\\u1cf5\\u1cf6\\u1d00-\\u1dbf\\u1e00-\\u1f15\\u1f18-\\u1f1d\\u1f20-\\u1f45\\u1f48-\\u1f4d\\u1f50-\\u1f57\\u1f59\\u1f5b\\u1f5d\\u1f5f-\\u1f7d\\u1f80-\\u1fb4\\u1fb6-\\u1fbc\\u1fbe\\u1fc2-\\u1fc4\\u1fc6-\\u1fcc\\u1fd0-\\u1fd3\\u1fd6-\\u1fdb\\u1fe0-\\u1fec\\u1ff2-\\u1ff4\\u1ff6-\\u1ffc\\u2071\\u207f\\u2090-\\u209c\\u2102\\u2107\\u210a-\\u2113\\u2115\\u2118-\\u211d\\u2124\\u2126\\u2128\\u212a-\\u2139\\u213c-\\u213f\\u2145-\\u2149\\u214e\\u2160-\\u2188\\u2c00-\\u2c2e\\u2c30-\\u2c5e\\u2c60-\\u2ce4\\u2ceb-\\u2cee\\u2cf2\\u2cf3\\u2d00-\\u2d25\\u2d27\\u2d2d\\u2d30-\\u2d67\\u2d6f\\u2d80-\\u2d96\\u2da0-\\u2da6\\u2da8-\\u2dae\\u2db0-\\u2db6\\u2db8-\\u2dbe\\u2dc0-\\u2dc6\\u2dc8-\\u2dce\\u2dd0-\\u2dd6\\u2dd8-\\u2dde\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303c\\u3041-\\u3096\\u309b-\\u309f\\u30a1-\\u30fa\\u30fc-\\u30ff\\u3105-\\u312d\\u3131-\\u318e\\u31a0-\\u31ba\\u31f0-\\u31ff\\u3400-\\u4db5\\u4e00-\\u9fd5\\ua000-\\ua48c\\ua4d0-\\ua4fd\\ua500-\\ua60c\\ua610-\\ua61f\\ua62a\\ua62b\\ua640-\\ua66e\\ua67f-\\ua69d\\ua6a0-\\ua6ef\\ua717-\\ua71f\\ua722-\\ua788\\ua78b-\\ua7ae\\ua7b0-\\ua7b7\\ua7f7-\\ua801\\ua803-\\ua805\\ua807-\\ua80a\\ua80c-\\ua822\\ua840-\\ua873\\ua882-\\ua8b3\\ua8f2-\\ua8f7\\ua8fb\\ua8fd\\ua90a-\\ua925\\ua930-\\ua946\\ua960-\\ua97c\\ua984-\\ua9b2\\ua9cf\\ua9e0-\\ua9e4\\ua9e6-\\ua9ef\\ua9fa-\\ua9fe\\uaa00-\\uaa28\\uaa40-\\uaa42\\uaa44-\\uaa4b\\uaa60-\\uaa76\\uaa7a\\uaa7e-\\uaaaf\\uaab1\\uaab5\\uaab6\\uaab9-\\uaabd\\uaac0\\uaac2\\uaadb-\\uaadd\\uaae0-\\uaaea\\uaaf2-\\uaaf4\\uab01-\\uab06\\uab09-\\uab0e\\uab11-\\uab16\\uab20-\\uab26\\uab28-\\uab2e\\uab30-\\uab5a\\uab5c-\\uab65\\uab70-\\uabe2\\uac00-\\ud7a3\\ud7b0-\\ud7c6\\ud7cb-\\ud7fb\\uf900-\\ufa6d\\ufa70-\\ufad9\\ufb00-\\ufb06\\ufb13-\\ufb17\\ufb1d\\ufb1f-\\ufb28\\ufb2a-\\ufb36\\ufb38-\\ufb3c\\ufb3e\\ufb40\\ufb41\\ufb43\\ufb44\\ufb46-\\ufbb1\\ufbd3-\\ufd3d\\ufd50-\\ufd8f\\ufd92-\\ufdc7\\ufdf0-\\ufdfb\\ufe70-\\ufe74\\ufe76-\\ufefc\\uff21-\\uff3a\\uff41-\\uff5a\\uff66-\\uffbe\\uffc2-\\uffc7\\uffca-\\uffcf\\uffd2-\\uffd7\\uffda-\\uffdc";
nonASCIIidentifierStartPattern = Pattern.compile("[" + nonASCIIidentifierStartChars + "]"); private static final String nonASCIIidentifierChars =
return nonASCIIidentifierStartPattern; "\\u200c\\u200d\\xb7\\u0300-\\u036f\\u0387\\u0483-\\u0487\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u0669\\u0670\\u06d6-\\u06dc\\u06df-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u06f0-\\u06f9\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07c0-\\u07c9\\u07eb-\\u07f3\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0859-\\u085b\\u08d4-\\u08e1\\u08e3-\\u0903\\u093a-\\u093c\\u093e-\\u094f\\u0951-\\u0957\\u0962\\u0963\\u0966-\\u096f\\u0981-\\u0983\\u09bc\\u09be-\\u09c4\\u09c7\\u09c8\\u09cb-\\u09cd\\u09d7\\u09e2\\u09e3\\u09e6-\\u09ef\\u0a01-\\u0a03\\u0a3c\\u0a3e-\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a66-\\u0a71\\u0a75\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0ae2\\u0ae3\\u0ae6-\\u0aef\\u0b01-\\u0b03\\u0b3c\\u0b3e-\\u0b44\\u0b47\\u0b48\\u0b4b-\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b66-\\u0b6f\\u0b82\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0be6-\\u0bef\\u0c00-\\u0c03\\u0c3e-\\u0c44\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0c66-\\u0c6f\\u0c81-\\u0c83\\u0cbc\\u0cbe-\\u0cc4\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0ce6-\\u0cef\\u0d01-\\u0d03\\u0d3e-\\u0d44\\u0d46-\\u0d48\\u0d4a-\\u0d4d\\u0d57\\u0d62\\u0d63\\u0d66-\\u0d6f\\u0d82\\u0d83\\u0dca\\u0dcf-\\u0dd4\\u0dd6\\u0dd8-\\u0ddf\\u0de6-\\u0def\\u0df2\\u0df3\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0e50-\\u0e59\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0ed0-\\u0ed9\\u0f18\\u0f19\\u0f20-\\u0f29\\u0f35\\u0f37\\u0f39\\u0f3e\\u0f3f\\u0f71-\\u0f84\\u0f86\\u0f87\\u0f8d-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102b-\\u103e\\u1040-\\u1049\\u1056-\\u1059\\u105e-\\u1060\\u1062-\\u1064\\u1067-\\u106d\\u1071-\\u1074\\u1082-\\u108d\\u108f-\\u109d\\u135d-\\u135f\\u1369-\\u1371\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b4-\\u17d3\\u17dd\\u17e0-\\u17e9\\u180b-\\u180d\\u1810-\\u1819\\u18a9\\u1920-\\u192b\\u1930-\\u193b\\u1946-\\u194f\\u19d0-\\u19da\\u1a17-\\u1a1b\\u1a55-\\u1a5e\\u1a60-\\u1a7c\\u1a7f-\\u1a89\\u1a90-\\u1a99\\u1ab0-\\u1abd\\u1b00-\\u1b04\\u1b34-\\u1b44\\u1b50-\\u1b59\\u1b6b-\\u1b73\\u1b80-\\u1b82\\u1ba1-\\u1bad\\u1bb0-\\u1bb9\\u1be6-\\u1bf3\\u1c24-\\u1c37\\u1c40-\\u1c49\\u1c50-\\u1c59\\u1cd0-\\u1cd2\\u1cd4-\\u1ce8\\u1ced\\u1cf2-\\u1cf4\\u1cf8\\u1cf9\\u1dc0-\\u1df5\\u1dfb-\\u1dff\\u203f\\u2040\\u2054\\u20d0-\\u20dc\\u20e1\\u20e5-\\u20f0\\u2cef-\\u2cf1\\u2d7f\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua620-\\ua629\\ua66f\\ua674-\\ua67d\\ua69e\\ua69f\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua823-\\ua827\\ua880\\ua881\\ua8b4-\\ua8c5\\ua8d0-\\ua8d9\\ua8e0-\\ua8f1\\ua900-\\ua909\\ua926-\\ua92d\\ua947-\\ua953\\ua980-\\ua983\\ua9b3-\\ua9c0\\ua9d0-\\ua9d9\\ua9e5\\ua9f0-\\ua9f9\\uaa29-\\uaa36\\uaa43\\uaa4c\\uaa4d\\uaa50-\\uaa59\\uaa7b-\\uaa7d\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uaaeb-\\uaaef\\uaaf5\\uaaf6\\uabe3-\\uabea\\uabec\\uabed\\uabf0-\\uabf9\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe2f\\ufe33\\ufe34\\ufe4d-\\ufe4f\\uff10-\\uff19\\uff3f";
}
private static Pattern nonASCIIidentifier() { private static Pattern nonASCIIidentifierStartPattern;
if (nonASCIIidentifierPattern == null) private static Pattern nonASCIIidentifierPattern;
nonASCIIidentifierPattern = Pattern.compile("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
return nonASCIIidentifierPattern;
}
// These are a run-length and offset encoded representation of the private static Pattern nonASCIIidentifierStart() {
// >0xffff code points that are a valid part of identifiers. The if (nonASCIIidentifierStartPattern == null)
// offset starts at 0x10000, and each pair of numbers represents an nonASCIIidentifierStartPattern = Pattern.compile("[" + nonASCIIidentifierStartChars + "]");
// offset to the next range, and then a size of the range. They were return nonASCIIidentifierStartPattern;
// generated by bin/generate-identifier-regex.js }
private static final int[] astralIdentifierStartCodes = {0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,17,26,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,26,45,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,785,52,76,44,33,24,27,35,42,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,25,391,63,32,0,449,56,264,8,2,36,18,0,50,29,881,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,881,68,12,0,67,12,65,0,32,6124,20,754,9486,1,3071,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,10591,541};
private static final int[] astralIdentifierCodes = {509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,1306,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,52,0,13,2,49,13,10,2,4,9,83,11,7,0,161,11,6,9,7,3,57,0,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,87,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,423,9,838,7,2,7,17,9,57,21,2,13,19882,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239};
// This has a complexity linear to the value of the code. The private static Pattern nonASCIIidentifier() {
// assumption is that looking up astral identifier characters is if (nonASCIIidentifierPattern == null)
// rare. nonASCIIidentifierPattern =
private static boolean isInAstralSet(int code, int[] set) { Pattern.compile("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
int pos = 0x10000; return nonASCIIidentifierPattern;
for (int i = 0; i < set.length; i += 2) { }
pos += set[i];
if (pos > code)
return false;
pos += set[i + 1];
if (pos >= code)
return true;
}
return false;
}
// Test whether a given character code starts an identifier. // These are a run-length and offset encoded representation of the
// >0xffff code points that are a valid part of identifiers. The
// offset starts at 0x10000, and each pair of numbers represents an
// offset to the next range, and then a size of the range. They were
// generated by bin/generate-identifier-regex.js
private static final int[] astralIdentifierStartCodes = {
0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 17, 26, 6, 37,
11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153,
5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 71, 55, 7, 1,
65, 0, 16, 3, 2, 2, 2, 26, 45, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72,
56, 50, 14, 50, 785, 52, 76, 44, 33, 24, 27, 35, 42, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36,
17, 2, 24, 85, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0,
19, 0, 13, 4, 159, 52, 19, 3, 54, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 86,
25, 391, 63, 32, 0, 449, 56, 264, 8, 2, 36, 18, 0, 50, 29, 881, 921, 103, 110, 18, 195, 2749,
1070, 4050, 582, 8634, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 881, 68, 12, 0, 67,
12, 65, 0, 32, 6124, 20, 754, 9486, 1, 3071, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3,
0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2,
339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 4149, 196, 60,
67, 1213, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2,
1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6,
2, 2, 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 3, 5761, 10591, 541
};
private static final int[] astralIdentifierCodes = {
509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 1306, 2, 54, 14, 32,
9, 16, 3, 46, 10, 54, 9, 7, 2, 37, 13, 2, 9, 52, 0, 13, 2, 49, 13, 10, 2, 4, 9, 83, 11, 7, 0,
161, 11, 6, 9, 7, 3, 57, 0, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 193, 17, 10, 9, 87, 19,
13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 84, 14, 5, 9, 423, 9, 838, 7, 2, 7, 17,
9, 57, 21, 2, 13, 19882, 9, 135, 4, 60, 6, 26, 9, 1016, 45, 17, 3, 19723, 1, 5319, 4, 4, 5, 9,
7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3,
6, 2, 1, 2, 4, 2214, 6, 110, 6, 6, 9, 792487, 239
};
public static boolean isIdentifierStart(int code, boolean astral) { // This has a complexity linear to the value of the code. The
if (code < 65) return code == 36; // assumption is that looking up astral identifier characters is
if (code < 91) return true; // rare.
if (code < 97) return code == 95; private static boolean isInAstralSet(int code, int[] set) {
if (code < 123) return true; int pos = 0x10000;
if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart().matcher(str(code)).matches(); for (int i = 0; i < set.length; i += 2) {
if (!astral) return false; pos += set[i];
return isInAstralSet(code, astralIdentifierStartCodes); if (pos > code) return false;
} pos += set[i + 1];
if (pos >= code) return true;
}
return false;
}
public static boolean isIdentifierChar(int code, boolean astral) { // Test whether a given character code starts an identifier.
if (code < 48) return code == 36;
if (code < 58) return true;
if (code < 65) return false;
if (code < 91) return true;
if (code < 97) return code == 95;
if (code < 123) return true;
if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier().matcher(str(code)).matches();
if (!astral) return false;
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
}
private static String str(int i) { public static boolean isIdentifierStart(int code, boolean astral) {
return new String(Character.toChars(i)); if (code < 65) return code == 36;
} if (code < 91) return true;
if (code < 97) return code == 95;
if (code < 123) return true;
if (code <= 0xffff)
return code >= 0xaa && nonASCIIidentifierStart().matcher(str(code)).matches();
if (!astral) return false;
return isInAstralSet(code, astralIdentifierStartCodes);
}
public static boolean isIdentifierChar(int code, boolean astral) {
if (code < 48) return code == 36;
if (code < 58) return true;
if (code < 65) return false;
if (code < 91) return true;
if (code < 97) return code == 95;
if (code < 123) return true;
if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier().matcher(str(code)).matches();
if (!astral) return false;
return isInAstralSet(code, astralIdentifierStartCodes)
|| isInAstralSet(code, astralIdentifierCodes);
}
private static String str(int i) {
return new String(Character.toChars(i));
}
} }

View File

@@ -1,27 +1,24 @@
package com.semmle.jcorn; package com.semmle.jcorn;
import java.util.regex.Matcher;
import com.semmle.js.ast.Position; import com.semmle.js.ast.Position;
import java.util.regex.Matcher;
/// locutil.js /// locutil.js
public class Locutil { public class Locutil {
/** /**
* The `getLineInfo` function is mostly useful when the * The `getLineInfo` function is mostly useful when the `locations` option is off (for performance
* `locations` option is off (for performance reasons) and you * reasons) and you want to find the line/column position for a given character offset. `input`
* want to find the line/column position for a given character * should be the code string that the offset refers into.
* offset. `input` should be the code string that the offset refers */
* into. public static Position getLineInfo(String input, int offset) {
*/ Matcher lineBreakG = Whitespace.lineBreakG.matcher(input);
public static Position getLineInfo(String input, int offset) { for (int line = 1, cur = 0; ; ) {
Matcher lineBreakG = Whitespace.lineBreakG.matcher(input); if (lineBreakG.find(cur) && lineBreakG.start() < offset) {
for (int line = 1, cur = 0;;) { ++line;
if (lineBreakG.find(cur) && lineBreakG.start() < offset) { cur = lineBreakG.end();
++line; } else {
cur = lineBreakG.end(); return new Position(line, offset - cur, offset);
} else { }
return new Position(line, offset - cur, offset); }
} }
}
}
} }

View File

@@ -1,248 +1,259 @@
package com.semmle.jcorn; package com.semmle.jcorn;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import com.semmle.jcorn.Identifiers.Dialect; import com.semmle.jcorn.Identifiers.Dialect;
import com.semmle.js.ast.Comment; import com.semmle.js.ast.Comment;
import com.semmle.js.ast.Position; import com.semmle.js.ast.Position;
import com.semmle.js.ast.Program; import com.semmle.js.ast.Program;
import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.Token; import com.semmle.js.ast.Token;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
/// options.js /// options.js
public class Options { public class Options {
public enum AllowReserved { public enum AllowReserved {
YES(true), NO(false), NEVER(false); YES(true),
NO(false),
NEVER(false);
private final boolean isTrue; private final boolean isTrue;
private AllowReserved(boolean isTrue) { private AllowReserved(boolean isTrue) {
this.isTrue = isTrue; this.isTrue = isTrue;
} }
public boolean isTrue() { public boolean isTrue() {
return isTrue; return isTrue;
} }
} }
public interface OnCommentCallback { public interface OnCommentCallback {
public void call(boolean block, String input, String text, int start, int end, Position startLoc, Position endLoc); public void call(
} boolean block,
String input,
String text,
int start,
int end,
Position startLoc,
Position endLoc);
}
private boolean allowHashBang, allowReturnOutsideFunction, allowImportExportEverywhere; private boolean allowHashBang, allowReturnOutsideFunction, allowImportExportEverywhere;
private boolean preserveParens, mozExtensions, jscript, esnext, v8Extensions, e4x; private boolean preserveParens, mozExtensions, jscript, esnext, v8Extensions, e4x;
private int ecmaVersion; private int ecmaVersion;
private AllowReserved allowReserved; private AllowReserved allowReserved;
private String sourceType; private String sourceType;
private BiFunction<Integer, Position, Void> onInsertedSemicolon, onTrailingComma; private BiFunction<Integer, Position, Void> onInsertedSemicolon, onTrailingComma;
private Function<Token, Void> onToken; private Function<Token, Void> onToken;
private OnCommentCallback onComment; private OnCommentCallback onComment;
private Program program; private Program program;
private Function<SyntaxError, ?> onRecoverableError; private Function<SyntaxError, ?> onRecoverableError;
public Options() { public Options() {
this.ecmaVersion = 7; this.ecmaVersion = 7;
this.sourceType = "script"; this.sourceType = "script";
this.onInsertedSemicolon = null; this.onInsertedSemicolon = null;
this.onTrailingComma = null; this.onTrailingComma = null;
this.allowReserved = AllowReserved.YES; this.allowReserved = AllowReserved.YES;
this.allowReturnOutsideFunction = false; this.allowReturnOutsideFunction = false;
this.allowImportExportEverywhere = false; this.allowImportExportEverywhere = false;
this.allowHashBang = false; this.allowHashBang = false;
this.onToken = null; this.onToken = null;
this.onComment = null; this.onComment = null;
this.program = null; this.program = null;
this.preserveParens = false; this.preserveParens = false;
this.mozExtensions = false; this.mozExtensions = false;
this.jscript = false; this.jscript = false;
this.esnext = false; this.esnext = false;
this.v8Extensions = false; this.v8Extensions = false;
this.e4x = false; this.e4x = false;
this.onRecoverableError = null; this.onRecoverableError = null;
} }
public Options(Options that) { public Options(Options that) {
this.allowHashBang = that.allowHashBang; this.allowHashBang = that.allowHashBang;
this.allowReturnOutsideFunction = that.allowReturnOutsideFunction; this.allowReturnOutsideFunction = that.allowReturnOutsideFunction;
this.allowImportExportEverywhere = that.allowImportExportEverywhere; this.allowImportExportEverywhere = that.allowImportExportEverywhere;
this.preserveParens = that.preserveParens; this.preserveParens = that.preserveParens;
this.mozExtensions = that.mozExtensions; this.mozExtensions = that.mozExtensions;
this.jscript = that.jscript; this.jscript = that.jscript;
this.esnext = that.esnext; this.esnext = that.esnext;
this.v8Extensions = that.v8Extensions; this.v8Extensions = that.v8Extensions;
this.e4x = that.e4x; this.e4x = that.e4x;
this.ecmaVersion = that.ecmaVersion; this.ecmaVersion = that.ecmaVersion;
this.allowReserved = that.allowReserved; this.allowReserved = that.allowReserved;
this.sourceType = that.sourceType; this.sourceType = that.sourceType;
this.onInsertedSemicolon = that.onInsertedSemicolon; this.onInsertedSemicolon = that.onInsertedSemicolon;
this.onTrailingComma = that.onTrailingComma; this.onTrailingComma = that.onTrailingComma;
this.onToken = that.onToken; this.onToken = that.onToken;
this.onComment = that.onComment; this.onComment = that.onComment;
this.program = that.program; this.program = that.program;
this.onRecoverableError = that.onRecoverableError; this.onRecoverableError = that.onRecoverableError;
} }
public boolean allowHashBang() { public boolean allowHashBang() {
return allowHashBang; return allowHashBang;
} }
public boolean allowReturnOutsideFunction() { public boolean allowReturnOutsideFunction() {
return allowReturnOutsideFunction; return allowReturnOutsideFunction;
} }
public boolean allowImportExportEverywhere() { public boolean allowImportExportEverywhere() {
return allowImportExportEverywhere; return allowImportExportEverywhere;
} }
public boolean preserveParens() { public boolean preserveParens() {
return preserveParens; return preserveParens;
} }
public boolean mozExtensions() { public boolean mozExtensions() {
return mozExtensions; return mozExtensions;
} }
public boolean jscript() { public boolean jscript() {
return jscript; return jscript;
} }
public boolean esnext() { public boolean esnext() {
return esnext; return esnext;
} }
public boolean v8Extensions() { public boolean v8Extensions() {
return v8Extensions; return v8Extensions;
} }
public boolean e4x() { public boolean e4x() {
return e4x; return e4x;
} }
public Identifiers.Dialect getDialect() { public Identifiers.Dialect getDialect() {
switch (ecmaVersion) { switch (ecmaVersion) {
case 3: case 3:
return Dialect.ECMA_3; return Dialect.ECMA_3;
case 5: case 5:
return Dialect.ECMA_5; return Dialect.ECMA_5;
case 6: case 6:
return Dialect.ECMA_6; return Dialect.ECMA_6;
case 8: case 8:
return Dialect.ECMA_8; return Dialect.ECMA_8;
default: default:
return Dialect.ECMA_7; return Dialect.ECMA_7;
} }
} }
public int ecmaVersion() { public int ecmaVersion() {
return ecmaVersion; return ecmaVersion;
} }
public Options ecmaVersion(int ecmaVersion) { public Options ecmaVersion(int ecmaVersion) {
if (ecmaVersion >= 2015) if (ecmaVersion >= 2015) ecmaVersion -= 2009;
ecmaVersion -= 2009;
this.ecmaVersion = ecmaVersion; this.ecmaVersion = ecmaVersion;
if (ecmaVersion >= 5) if (ecmaVersion >= 5) this.allowReserved = AllowReserved.NO;
this.allowReserved = AllowReserved.NO; return this;
return this; }
}
public AllowReserved allowReserved() { public AllowReserved allowReserved() {
return allowReserved; return allowReserved;
} }
public Options onComment(List<Comment> comments) { public Options onComment(List<Comment> comments) {
this.onComment = (block, input, text, start, end, startLoc, endLoc) -> { this.onComment =
String src = input.substring(start, end); (block, input, text, start, end, startLoc, endLoc) -> {
comments.add(new Comment(new SourceLocation(src, startLoc, endLoc), text)); String src = input.substring(start, end);
}; comments.add(new Comment(new SourceLocation(src, startLoc, endLoc), text));
return this; };
} return this;
}
public String sourceType() { public String sourceType() {
return sourceType; return sourceType;
} }
public Options sourceType(String sourceType) { public Options sourceType(String sourceType) {
this.sourceType = sourceType; this.sourceType = sourceType;
return this; return this;
} }
public Options mozExtensions(boolean mozExtensions) { public Options mozExtensions(boolean mozExtensions) {
this.mozExtensions = mozExtensions; this.mozExtensions = mozExtensions;
return this; return this;
} }
public Options jscript(boolean jscript) { public Options jscript(boolean jscript) {
this.jscript = jscript; this.jscript = jscript;
return this; return this;
} }
public Options esnext(boolean esnext) { public Options esnext(boolean esnext) {
this.esnext = esnext; this.esnext = esnext;
return this; return this;
} }
public void v8Extensions(boolean v8Extensions) { public void v8Extensions(boolean v8Extensions) {
this.v8Extensions = v8Extensions; this.v8Extensions = v8Extensions;
} }
public void e4x(boolean e4x) { public void e4x(boolean e4x) {
this.e4x = e4x; this.e4x = e4x;
} }
public Options preserveParens(boolean preserveParens) { public Options preserveParens(boolean preserveParens) {
this.preserveParens = preserveParens; this.preserveParens = preserveParens;
return this; return this;
} }
public Options allowReturnOutsideFunction(boolean allowReturnOutsideFunction) { public Options allowReturnOutsideFunction(boolean allowReturnOutsideFunction) {
this.allowReturnOutsideFunction = allowReturnOutsideFunction; this.allowReturnOutsideFunction = allowReturnOutsideFunction;
return this; return this;
} }
public Options allowImportExportEverywhere(boolean allowImportExportEverywhere) { public Options allowImportExportEverywhere(boolean allowImportExportEverywhere) {
this.allowImportExportEverywhere = allowImportExportEverywhere; this.allowImportExportEverywhere = allowImportExportEverywhere;
return this; return this;
} }
public BiFunction<Integer, Position, Void> onInsertedSemicolon() { public BiFunction<Integer, Position, Void> onInsertedSemicolon() {
return onInsertedSemicolon; return onInsertedSemicolon;
} }
public BiFunction<Integer, Position, Void> onTrailingComma() { public BiFunction<Integer, Position, Void> onTrailingComma() {
return onTrailingComma; return onTrailingComma;
} }
public Function<Token, Void> onToken() { public Function<Token, Void> onToken() {
return onToken; return onToken;
} }
public Options onToken(List<Token> tokens) { public Options onToken(List<Token> tokens) {
return onToken((tk) -> { tokens.add(tk); return null; }); return onToken(
} (tk) -> {
tokens.add(tk);
return null;
});
}
public Options onToken(Function<Token, Void> tmp) { public Options onToken(Function<Token, Void> tmp) {
this.onToken = tmp; this.onToken = tmp;
return this; return this;
} }
public OnCommentCallback onComment() { public OnCommentCallback onComment() {
return onComment; return onComment;
} }
public Program program() { public Program program() {
return program; return program;
} }
public Options onRecoverableError(Function<SyntaxError, ?> onRecoverableError) { public Options onRecoverableError(Function<SyntaxError, ?> onRecoverableError) {
this.onRecoverableError = onRecoverableError; this.onRecoverableError = onRecoverableError;
return this; return this;
} }
public Function<SyntaxError, ?> onRecoverableError() { public Function<SyntaxError, ?> onRecoverableError() {
return onRecoverableError; return onRecoverableError;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -3,16 +3,16 @@ package com.semmle.jcorn;
import com.semmle.js.ast.Position; import com.semmle.js.ast.Position;
public class SyntaxError extends RuntimeException { public class SyntaxError extends RuntimeException {
private static final long serialVersionUID = -4883173648492364902L; private static final long serialVersionUID = -4883173648492364902L;
private final Position position; private final Position position;
public SyntaxError(String msg, Position loc, int raisedAt) { public SyntaxError(String msg, Position loc, int raisedAt) {
super(msg); super(msg);
this.position = loc; this.position = loc;
} }
public Position getPosition() { public Position getPosition() {
return position; return position;
} }
} }

View File

@@ -1,10 +1,9 @@
package com.semmle.jcorn; package com.semmle.jcorn;
import com.semmle.jcorn.Parser.TokContext;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import com.semmle.jcorn.Parser.TokContext;
/// tokentype.js /// tokentype.js
// ## Token types // ## Token types
@@ -31,251 +30,262 @@ import com.semmle.jcorn.Parser.TokContext;
// continue jumps to that label. // continue jumps to that label.
public class TokenType { public class TokenType {
// Map keyword names to token types. // Map keyword names to token types.
public static final Map<String, TokenType> keywords = new LinkedHashMap<>(); public static final Map<String, TokenType> keywords = new LinkedHashMap<>();
public static final TokenType public static final TokenType num = new TokenType(new Properties("num").startsExpr()),
num = new TokenType(new Properties("num").startsExpr()), bigint = new TokenType(new Properties("bigint").startsExpr()),
bigint = new TokenType(new Properties("bigint").startsExpr()), regexp = new TokenType(new Properties("regexp").startsExpr()),
regexp = new TokenType(new Properties("regexp").startsExpr()), string = new TokenType(new Properties("string").startsExpr()),
string = new TokenType(new Properties("string").startsExpr()), name = new TokenType(new Properties("name").startsExpr()),
name = new TokenType(new Properties("name").startsExpr()), eof = new TokenType(new Properties("eof")),
eof = new TokenType(new Properties("eof")),
// Punctuation token types. // Punctuation token types.
bracketL = new TokenType(new Properties("[").beforeExpr().startsExpr()), bracketL = new TokenType(new Properties("[").beforeExpr().startsExpr()),
bracketR = new TokenType(new Properties("]")), bracketR = new TokenType(new Properties("]")),
braceL = new TokenType(new Properties("{").beforeExpr().startsExpr()) { braceL =
@Override new TokenType(new Properties("{").beforeExpr().startsExpr()) {
public void updateContext(Parser parser, TokenType prevType) { @Override
parser.context.push(parser.braceIsBlock(prevType) ? TokContext.b_stat : TokContext.b_expr); public void updateContext(Parser parser, TokenType prevType) {
parser.exprAllowed = true; parser.context.push(
} parser.braceIsBlock(prevType) ? TokContext.b_stat : TokContext.b_expr);
}, parser.exprAllowed = true;
braceR = new TokenType(new Properties("}")) { }
@Override },
public void updateContext(Parser parser, TokenType prevType) { braceR =
updateParenBraceRContext(parser); new TokenType(new Properties("}")) {
} @Override
}, public void updateContext(Parser parser, TokenType prevType) {
parenL = new TokenType(new Properties("(").beforeExpr().startsExpr()) { updateParenBraceRContext(parser);
@Override }
public void updateContext(Parser parser, TokenType prevType) { },
boolean statementParens = prevType == TokenType._if || prevType == TokenType._for || prevType == TokenType._with || prevType == TokenType._while; parenL =
parser.context.push(statementParens ? TokContext.p_stat : TokContext.p_expr); new TokenType(new Properties("(").beforeExpr().startsExpr()) {
parser.exprAllowed = true; @Override
} public void updateContext(Parser parser, TokenType prevType) {
}, boolean statementParens =
parenR = new TokenType(new Properties(")")) { prevType == TokenType._if
@Override || prevType == TokenType._for
public void updateContext(Parser parser, TokenType prevType) { || prevType == TokenType._with
updateParenBraceRContext(parser); || prevType == TokenType._while;
} parser.context.push(statementParens ? TokContext.p_stat : TokContext.p_expr);
}, parser.exprAllowed = true;
comma = new TokenType(new Properties(",").beforeExpr()), }
semi = new TokenType(new Properties(";").beforeExpr()), },
colon = new TokenType(new Properties(":").beforeExpr()), parenR =
dot = new TokenType(new Properties(".")), new TokenType(new Properties(")")) {
questiondot = new TokenType(new Properties("?.")), @Override
question = new TokenType(new Properties("?").beforeExpr()), public void updateContext(Parser parser, TokenType prevType) {
arrow = new TokenType(new Properties("=>").beforeExpr()), updateParenBraceRContext(parser);
template = new TokenType(new Properties("template")), }
invalidTemplate = new TokenType(new Properties("invalidTemplate")), },
ellipsis = new TokenType(new Properties("...").beforeExpr()), comma = new TokenType(new Properties(",").beforeExpr()),
backQuote = new TokenType(new Properties("`").startsExpr()) { semi = new TokenType(new Properties(";").beforeExpr()),
@Override colon = new TokenType(new Properties(":").beforeExpr()),
public void updateContext(Parser parser, TokenType prevType) { dot = new TokenType(new Properties(".")),
if (parser.curContext() == TokContext.q_tmpl) questiondot = new TokenType(new Properties("?.")),
parser.context.pop(); question = new TokenType(new Properties("?").beforeExpr()),
else arrow = new TokenType(new Properties("=>").beforeExpr()),
parser.context.push(TokContext.q_tmpl); template = new TokenType(new Properties("template")),
parser.exprAllowed = false; invalidTemplate = new TokenType(new Properties("invalidTemplate")),
} ellipsis = new TokenType(new Properties("...").beforeExpr()),
}, backQuote =
dollarBraceL = new TokenType(new Properties("${").beforeExpr().startsExpr()) { new TokenType(new Properties("`").startsExpr()) {
@Override @Override
public void updateContext(Parser parser, TokenType prevType) { public void updateContext(Parser parser, TokenType prevType) {
parser.context.push(TokContext.b_tmpl); if (parser.curContext() == TokContext.q_tmpl) parser.context.pop();
parser.exprAllowed = true; else parser.context.push(TokContext.q_tmpl);
} parser.exprAllowed = false;
}, }
},
dollarBraceL =
new TokenType(new Properties("${").beforeExpr().startsExpr()) {
@Override
public void updateContext(Parser parser, TokenType prevType) {
parser.context.push(TokContext.b_tmpl);
parser.exprAllowed = true;
}
},
// Operators. These carry several kinds of properties to help the // Operators. These carry several kinds of properties to help the
// parser use them properly (the presence of these properties is // parser use them properly (the presence of these properties is
// what categorizes them as operators). // what categorizes them as operators).
// //
// `binop`, when present, specifies that this operator is a binary // `binop`, when present, specifies that this operator is a binary
// operator, and will refer to its precedence. // operator, and will refer to its precedence.
// //
// `prefix` and `postfix` mark the operator as a prefix or postfix // `prefix` and `postfix` mark the operator as a prefix or postfix
// unary operator. // unary operator.
// //
// `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as
// binary operators with a very low precedence, that should result // binary operators with a very low precedence, that should result
// in AssignmentExpression nodes. // in AssignmentExpression nodes.
eq = new TokenType(new Properties("=").beforeExpr().isAssign()), eq = new TokenType(new Properties("=").beforeExpr().isAssign()),
assign = new TokenType(new Properties("_=").beforeExpr().isAssign()), assign = new TokenType(new Properties("_=").beforeExpr().isAssign()),
incDec = new TokenType(new Properties("++/--").prefix().postfix().startsExpr()) { incDec =
@Override new TokenType(new Properties("++/--").prefix().postfix().startsExpr()) {
public void updateContext(Parser parser, TokenType prevType) { @Override
// exprAllowed stays unchanged public void updateContext(Parser parser, TokenType prevType) {
} // exprAllowed stays unchanged
}, }
prefix = new TokenType(new Properties("prefix").beforeExpr().prefix().startsExpr()), },
questionquestion = new TokenType(binop("??", 1)), prefix = new TokenType(new Properties("prefix").beforeExpr().prefix().startsExpr()),
logicalOR = new TokenType(binop("||", 1)), questionquestion = new TokenType(binop("??", 1)),
logicalAND = new TokenType(binop("&&", 2)), logicalOR = new TokenType(binop("||", 1)),
bitwiseOR = new TokenType(binop("|", 3)), logicalAND = new TokenType(binop("&&", 2)),
bitwiseXOR = new TokenType(binop("^", 4)), bitwiseOR = new TokenType(binop("|", 3)),
bitwiseAND = new TokenType(binop("&", 5)), bitwiseXOR = new TokenType(binop("^", 4)),
equality = new TokenType(binop("==/!=", 6)), bitwiseAND = new TokenType(binop("&", 5)),
relational = new TokenType(binop("</>", 7)), equality = new TokenType(binop("==/!=", 6)),
bitShift = new TokenType(binop("<</>>", 8)), relational = new TokenType(binop("</>", 7)),
plusMin = new TokenType(new Properties("+/-").beforeExpr().binop(9).prefix().startsExpr()), bitShift = new TokenType(binop("<</>>", 8)),
modulo= new TokenType(binop("%", 10)), plusMin = new TokenType(new Properties("+/-").beforeExpr().binop(9).prefix().startsExpr()),
star= new TokenType(binop("*", 10)), modulo = new TokenType(binop("%", 10)),
slash= new TokenType(binop("/", 10)), star = new TokenType(binop("*", 10)),
starstar = new TokenType(new Properties("**").beforeExpr()), slash = new TokenType(binop("/", 10)),
_break = new TokenType(kw("break")), starstar = new TokenType(new Properties("**").beforeExpr()),
_case = new TokenType(kw("case").beforeExpr()), _break = new TokenType(kw("break")),
_catch = new TokenType(kw("catch")), _case = new TokenType(kw("case").beforeExpr()),
_continue = new TokenType(kw("continue")), _catch = new TokenType(kw("catch")),
_debugger = new TokenType(kw("debugger")), _continue = new TokenType(kw("continue")),
_default = new TokenType(kw("default").beforeExpr()), _debugger = new TokenType(kw("debugger")),
_do = new TokenType(kw("do").isLoop().beforeExpr()), _default = new TokenType(kw("default").beforeExpr()),
_else = new TokenType(kw("else").beforeExpr()), _do = new TokenType(kw("do").isLoop().beforeExpr()),
_finally = new TokenType(kw("finally")), _else = new TokenType(kw("else").beforeExpr()),
_for = new TokenType(kw("for").isLoop()), _finally = new TokenType(kw("finally")),
_function = new TokenType(kw("function").startsExpr()) { _for = new TokenType(kw("for").isLoop()),
@Override _function =
public void updateContext(Parser parser, TokenType prevType) { new TokenType(kw("function").startsExpr()) {
if (prevType.beforeExpr && prevType != TokenType.semi && prevType != TokenType._else && @Override
!((prevType == TokenType.colon || prevType == TokenType.braceL) && parser.curContext() == TokContext.b_stat)) public void updateContext(Parser parser, TokenType prevType) {
parser.context.push(TokContext.f_expr); if (prevType.beforeExpr
parser.exprAllowed = false; && prevType != TokenType.semi
} && prevType != TokenType._else
}, && !((prevType == TokenType.colon || prevType == TokenType.braceL)
_if = new TokenType(kw("if")), && parser.curContext() == TokContext.b_stat))
_return = new TokenType(kw("return").beforeExpr()), parser.context.push(TokContext.f_expr);
_switch = new TokenType(kw("switch")), parser.exprAllowed = false;
_throw = new TokenType(kw("throw").beforeExpr()), }
_try = new TokenType(kw("try")), },
_var = new TokenType(kw("var")), _if = new TokenType(kw("if")),
_const = new TokenType(kw("const")), _return = new TokenType(kw("return").beforeExpr()),
_while = new TokenType(kw("while").isLoop()), _switch = new TokenType(kw("switch")),
_with = new TokenType(kw("with")), _throw = new TokenType(kw("throw").beforeExpr()),
_new = new TokenType(kw("new").beforeExpr().startsExpr()), _try = new TokenType(kw("try")),
_this = new TokenType(kw("this").startsExpr()), _var = new TokenType(kw("var")),
_super = new TokenType(kw("super").startsExpr()), _const = new TokenType(kw("const")),
_class = new TokenType(kw("class")), _while = new TokenType(kw("while").isLoop()),
_extends = new TokenType(kw("extends").beforeExpr()), _with = new TokenType(kw("with")),
_export = new TokenType(kw("export")), _new = new TokenType(kw("new").beforeExpr().startsExpr()),
_import = new TokenType(kw("import")), _this = new TokenType(kw("this").startsExpr()),
_null = new TokenType(kw("null").startsExpr()), _super = new TokenType(kw("super").startsExpr()),
_true = new TokenType(kw("true").startsExpr()), _class = new TokenType(kw("class")),
_false = new TokenType(kw("false").startsExpr()), _extends = new TokenType(kw("extends").beforeExpr()),
_in = new TokenType(kw("in").beforeExpr().binop(7)), _export = new TokenType(kw("export")),
_instanceof = new TokenType(kw("instanceof").beforeExpr().binop(7)), _import = new TokenType(kw("import")),
_typeof = new TokenType(kw("typeof").beforeExpr().prefix().startsExpr()), _null = new TokenType(kw("null").startsExpr()),
_void = new TokenType(kw("void").beforeExpr().prefix().startsExpr()), _true = new TokenType(kw("true").startsExpr()),
_delete = new TokenType(kw("delete").beforeExpr().prefix().startsExpr()); _false = new TokenType(kw("false").startsExpr()),
_in = new TokenType(kw("in").beforeExpr().binop(7)),
_instanceof = new TokenType(kw("instanceof").beforeExpr().binop(7)),
_typeof = new TokenType(kw("typeof").beforeExpr().prefix().startsExpr()),
_void = new TokenType(kw("void").beforeExpr().prefix().startsExpr()),
_delete = new TokenType(kw("delete").beforeExpr().prefix().startsExpr());
public final String label, keyword;
public final boolean beforeExpr, startsExpr, isLoop, isAssign, isPrefix, isPostfix;
public final int binop;
public final String label, keyword; public void updateContext(Parser parser, TokenType prevType) {
public final boolean beforeExpr, startsExpr, isLoop, isAssign, isPrefix, isPostfix; parser.exprAllowed = this.beforeExpr;
public final int binop; }
public void updateContext(Parser parser, TokenType prevType) { // Token-specific context update code
parser.exprAllowed = this.beforeExpr; protected void updateParenBraceRContext(Parser parser) {
} if (parser.context.size() == 1) {
parser.exprAllowed = true;
return;
}
TokContext out = parser.context.pop();
if (out == TokContext.b_stat && parser.curContext() == TokContext.f_expr) {
parser.context.pop();
parser.exprAllowed = false;
} else if (out == TokContext.b_tmpl) {
parser.exprAllowed = true;
} else {
parser.exprAllowed = !out.isExpr;
}
}
// Token-specific context update code public TokenType(Properties prop) {
protected void updateParenBraceRContext(Parser parser) { this.label = prop.label;
if (parser.context.size() == 1) { this.keyword = prop.keyword;
parser.exprAllowed = true; this.beforeExpr = prop.beforeExpr;
return; this.startsExpr = prop.startsExpr;
} this.isLoop = prop.isLoop;
TokContext out = parser.context.pop(); this.isAssign = prop.isAssign;
if (out == TokContext.b_stat && parser.curContext() == TokContext.f_expr) { this.isPrefix = prop.prefix;
parser.context.pop(); this.isPostfix = prop.postfix;
parser.exprAllowed = false; this.binop = prop.binop;
} else if (out == TokContext.b_tmpl) { if (this.keyword != null) keywords.put(this.keyword, this);
parser.exprAllowed = true; }
} else {
parser.exprAllowed = !out.isExpr;
}
}
public TokenType(Properties prop) { public static class Properties {
this.label = prop.label; public String label, keyword;
this.keyword = prop.keyword; public boolean beforeExpr, startsExpr, isLoop, isAssign, prefix, postfix;
this.beforeExpr = prop.beforeExpr; public int binop;
this.startsExpr = prop.startsExpr;
this.isLoop = prop.isLoop;
this.isAssign = prop.isAssign;
this.isPrefix = prop.prefix;
this.isPostfix = prop.postfix;
this.binop = prop.binop;
if (this.keyword != null)
keywords.put(this.keyword, this);
}
public static class Properties { public Properties(String label, String keyword) {
public String label, keyword; this.label = label;
public boolean beforeExpr, startsExpr, isLoop, isAssign, prefix, postfix; this.keyword = keyword;
public int binop; }
public Properties(String label, String keyword) { public Properties(String label) {
this.label = label; this(label, null);
this.keyword = keyword; }
}
public Properties(String label) { public Properties beforeExpr() {
this(label, null); this.beforeExpr = true;
} return this;
}
public Properties beforeExpr() { public Properties startsExpr() {
this.beforeExpr = true; this.startsExpr = true;
return this; return this;
} }
public Properties startsExpr() { public Properties isLoop() {
this.startsExpr = true; this.isLoop = true;
return this; return this;
} }
public Properties isLoop() { public Properties isAssign() {
this.isLoop = true; this.isAssign = true;
return this; return this;
} }
public Properties isAssign() { public Properties prefix() {
this.isAssign = true; this.prefix = true;
return this; return this;
} }
public Properties prefix() { public Properties postfix() {
this.prefix = true; this.postfix = true;
return this; return this;
} }
public Properties postfix() { public Properties binop(int prec) {
this.postfix = true; this.binop = prec;
return this; return this;
} }
}
public Properties binop(int prec) { private static Properties binop(String name, int prec) {
this.binop = prec; return new Properties(name, null).binop(prec).beforeExpr();
return this; }
}
}
private static Properties binop(String name, int prec) { // Succinct definitions of keyword token types
return new Properties(name, null).binop(prec).beforeExpr(); private static Properties kw(String name) {
} return new Properties(name, name);
}
// Succinct definitions of keyword token types
private static Properties kw(String name) {
return new Properties(name, name);
}
} }

View File

@@ -4,15 +4,18 @@ import java.util.regex.Pattern;
/// whitespace.js /// whitespace.js
public class Whitespace { public class Whitespace {
public static final String lineBreak = "\r\n?|\n|\u2028|\u2029"; public static final String lineBreak = "\r\n?|\n|\u2028|\u2029";
public static final Pattern lineBreakG = Pattern.compile(lineBreak); // global public static final Pattern lineBreakG = Pattern.compile(lineBreak); // global
public static boolean isNewLine(int code) { public static boolean isNewLine(int code) {
return code == 10 || code == 13 || code == 0x2028 || code == 0x2029; return code == 10 || code == 13 || code == 0x2028 || code == 0x2029;
} }
public static final String nonASCIIwhitespace = "\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff"; public static final String nonASCIIwhitespace =
"\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff";
public static final Pattern skipWhiteSpace = Pattern.compile("(?:\\s|//.*|/\\*([^*]|\\*(?!/))*\\*/)*"); // global public static final Pattern skipWhiteSpace =
public static final Pattern skipWhiteSpaceNoNewline = Pattern.compile("(?:[ \\t\\x0B\\f]|//.*|/\\*([^*]|\\*(?!/))*\\*/)*"); Pattern.compile("(?:\\s|//.*|/\\*([^*]|\\*(?!/))*\\*/)*"); // global
public static final Pattern skipWhiteSpaceNoNewline =
Pattern.compile("(?:[ \\t\\x0B\\f]|//.*|/\\*([^*]|\\*(?!/))*\\*/)*");
} }

File diff suppressed because it is too large Load Diff

View File

@@ -3,22 +3,21 @@ package com.semmle.jcorn.jsx;
import com.semmle.jcorn.Options; import com.semmle.jcorn.Options;
public class JSXOptions extends Options { public class JSXOptions extends Options {
public boolean allowNamespacedObjects = true, allowNamespaces = true; public boolean allowNamespacedObjects = true, allowNamespaces = true;
public JSXOptions() { public JSXOptions() {}
}
public JSXOptions(Options options) { public JSXOptions(Options options) {
super(options); super(options);
} }
public JSXOptions allowNamespacedObjects(boolean allowNamespacedObjects) { public JSXOptions allowNamespacedObjects(boolean allowNamespacedObjects) {
this.allowNamespacedObjects = allowNamespacedObjects; this.allowNamespacedObjects = allowNamespacedObjects;
return this; return this;
} }
public JSXOptions allowNamespaces(boolean allowNamespaces) { public JSXOptions allowNamespaces(boolean allowNamespaces) {
this.allowNamespaces = allowNamespaces; this.allowNamespaces = allowNamespaces;
return this; return this;
} }
} }

View File

@@ -13,11 +13,6 @@ import static com.semmle.jcorn.TokenType.slash;
import static com.semmle.jcorn.TokenType.string; import static com.semmle.jcorn.TokenType.string;
import static com.semmle.jcorn.Whitespace.isNewLine; import static com.semmle.jcorn.Whitespace.isNewLine;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import com.semmle.jcorn.Identifiers; import com.semmle.jcorn.Identifiers;
import com.semmle.jcorn.Options; import com.semmle.jcorn.Options;
import com.semmle.jcorn.Parser; import com.semmle.jcorn.Parser;
@@ -41,428 +36,416 @@ import com.semmle.js.ast.jsx.JSXNamespacedName;
import com.semmle.js.ast.jsx.JSXOpeningElement; import com.semmle.js.ast.jsx.JSXOpeningElement;
import com.semmle.js.ast.jsx.JSXSpreadAttribute; import com.semmle.js.ast.jsx.JSXSpreadAttribute;
import com.semmle.util.data.Either; import com.semmle.util.data.Either;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
/** /**
* Java port of <a href="https://github.com/RReverser/acorn-jsx">Acorn-JSX</a> as of version * Java port of <a href="https://github.com/RReverser/acorn-jsx">Acorn-JSX</a> as of version <a
* <a href="https://github.com/RReverser/acorn-jsx/commit/05852d8ae9476b7f8a25e417665e2265528d5fb9">3.0.1</a>. * href="https://github.com/RReverser/acorn-jsx/commit/05852d8ae9476b7f8a25e417665e2265528d5fb9">3.0.1</a>.
* *
* Like the plain JavaScript {@link Parser}, the JSX parser is parameterized by an {@link Options} * <p>Like the plain JavaScript {@link Parser}, the JSX parser is parameterized by an {@link
* object. To enable JSX parsing, pass in a {@link JSXOptions} object. * Options} object. To enable JSX parsing, pass in a {@link JSXOptions} object.
*/ */
public class JSXParser extends Parser { public class JSXParser extends Parser {
private static final Pattern hexNumber = Pattern.compile("^[\\da-fA-F]+$"); private static final Pattern hexNumber = Pattern.compile("^[\\da-fA-F]+$");
private static final Pattern decimalNumber = Pattern.compile("^\\d+$"); private static final Pattern decimalNumber = Pattern.compile("^\\d+$");
public JSXParser(Options options, String input, int startPos) { public JSXParser(Options options, String input, int startPos) {
super(options, input, startPos); super(options, input, startPos);
} }
private static final TokContext j_oTag = new TokContext("<tag", false); private static final TokContext j_oTag = new TokContext("<tag", false);
private static final TokContext j_cTag = new TokContext("</tag", false); private static final TokContext j_cTag = new TokContext("</tag", false);
private static final TokContext j_expr = new TokContext("<tag>..</tag>", true, true, null); private static final TokContext j_expr = new TokContext("<tag>..</tag>", true, true, null);
private static final TokenType jsxName = new TokenType(new Properties("jsxName")); private static final TokenType jsxName = new TokenType(new Properties("jsxName"));
public static final TokenType jsxText = new TokenType(new Properties("jsxText").beforeExpr()); public static final TokenType jsxText = new TokenType(new Properties("jsxText").beforeExpr());
protected static final TokenType jsxTagStart = new TokenType(new Properties("jsxTagStart")) { protected static final TokenType jsxTagStart =
@Override new TokenType(new Properties("jsxTagStart")) {
public void updateContext(Parser parser, TokenType prevType) { @Override
parser.pushTokenContext(j_expr); // treat as beginning of JSX expression public void updateContext(Parser parser, TokenType prevType) {
parser.pushTokenContext(j_oTag); // start opening tag context parser.pushTokenContext(j_expr); // treat as beginning of JSX expression
parser.exprAllowed(false); parser.pushTokenContext(j_oTag); // start opening tag context
} parser.exprAllowed(false);
}; }
private static final TokenType jsxTagEnd = new TokenType(new Properties("jsxTagEnd")) { };
@Override private static final TokenType jsxTagEnd =
public void updateContext(Parser parser, TokenType prevType) { new TokenType(new Properties("jsxTagEnd")) {
TokContext out = parser.popTokenContext(); @Override
if (out == j_oTag && prevType == slash || out == j_cTag) { public void updateContext(Parser parser, TokenType prevType) {
parser.popTokenContext(); TokContext out = parser.popTokenContext();
parser.exprAllowed(parser.curContext() == j_expr); if (out == j_oTag && prevType == slash || out == j_cTag) {
} else { parser.popTokenContext();
parser.exprAllowed(true); parser.exprAllowed(parser.curContext() == j_expr);
} } else {
} parser.exprAllowed(true);
}; }
}
};
/** /** Reads inline JSX contents token. */
* Reads inline JSX contents token. private Token jsx_readToken() {
*/ StringBuilder out = new StringBuilder();
private Token jsx_readToken() { int chunkStart = this.pos;
StringBuilder out = new StringBuilder(); for (; ; ) {
int chunkStart = this.pos; if (this.pos >= this.input.length()) this.raise(this.start, "Unterminated JSX contents");
for (;;) { Either<Integer, Token> chunk = jsx_readChunk(out, chunkStart, this.charAt(this.pos));
if (this.pos >= this.input.length()) if (chunk.isRight()) return chunk.getRight();
this.raise(this.start, "Unterminated JSX contents"); chunkStart = chunk.getLeft();
Either<Integer, Token> chunk = jsx_readChunk(out, chunkStart, this.charAt(this.pos)); }
if (chunk.isRight()) }
return chunk.getRight();
chunkStart = chunk.getLeft();
}
}
/** /**
* Reads a chunk of inline JSX content, returning either the start of the next chunk * Reads a chunk of inline JSX content, returning either the start of the next chunk or the
* or the completed content token. * completed content token.
*/ */
protected Either<Integer, Token> jsx_readChunk(StringBuilder out, int chunkStart, int ch) { protected Either<Integer, Token> jsx_readChunk(StringBuilder out, int chunkStart, int ch) {
switch (ch) { switch (ch) {
case 60: // '<' case 60: // '<'
case 123: // '{' case 123: // '{'
if (this.pos == this.start) { if (this.pos == this.start) {
if (ch == 60 && this.exprAllowed) { if (ch == 60 && this.exprAllowed) {
++this.pos; ++this.pos;
return Either.right(this.finishToken(jsxTagStart)); return Either.right(this.finishToken(jsxTagStart));
} }
return Either.right(this.getTokenFromCode(ch)); return Either.right(this.getTokenFromCode(ch));
} }
out.append(inputSubstring(chunkStart, this.pos)); out.append(inputSubstring(chunkStart, this.pos));
return Either.right(this.finishToken(jsxText, out.toString())); return Either.right(this.finishToken(jsxText, out.toString()));
case 38: // '&' case 38: // '&'
out.append(inputSubstring(chunkStart, this.pos)); out.append(inputSubstring(chunkStart, this.pos));
out.append(this.jsx_readEntity()); out.append(this.jsx_readEntity());
chunkStart = this.pos; chunkStart = this.pos;
break; break;
default: default:
if (isNewLine(ch)) { if (isNewLine(ch)) {
out.append(inputSubstring(chunkStart, this.pos)); out.append(inputSubstring(chunkStart, this.pos));
out.append(this.jsx_readNewLine(true)); out.append(this.jsx_readNewLine(true));
chunkStart = this.pos; chunkStart = this.pos;
} else { } else {
++this.pos; ++this.pos;
} }
} }
return Either.left(chunkStart); return Either.left(chunkStart);
} }
private String jsx_readNewLine(boolean normalizeCRLF) { private String jsx_readNewLine(boolean normalizeCRLF) {
int ch = this.charAt(this.pos); int ch = this.charAt(this.pos);
String out; String out;
++this.pos; ++this.pos;
if (ch == 13 && this.charAt(this.pos) == 10) { if (ch == 13 && this.charAt(this.pos) == 10) {
++this.pos; ++this.pos;
out = normalizeCRLF ? "\n" : "\r\n"; out = normalizeCRLF ? "\n" : "\r\n";
} else { } else {
out = String.valueOf((char)ch); out = String.valueOf((char) ch);
} }
++this.curLine; ++this.curLine;
this.lineStart = this.pos; this.lineStart = this.pos;
return out; return out;
} }
private Token jsx_readString(char quote) { private Token jsx_readString(char quote) {
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
int chunkStart = ++this.pos; int chunkStart = ++this.pos;
for (;;) { for (; ; ) {
if (this.pos >= this.input.length()) if (this.pos >= this.input.length()) this.raise(this.start, "Unterminated string constant");
this.raise(this.start, "Unterminated string constant"); int ch = this.charAt(this.pos);
int ch = this.charAt(this.pos); if (ch == quote) break;
if (ch == quote) break; if (ch == 38) { // '&'
if (ch == 38) { // '&' out.append(inputSubstring(chunkStart, this.pos));
out.append(inputSubstring(chunkStart, this.pos)); out.append(this.jsx_readEntity());
out.append(this.jsx_readEntity()); chunkStart = this.pos;
chunkStart = this.pos; } else if (isNewLine(ch)) {
} else if (isNewLine(ch)) { out.append(inputSubstring(chunkStart, this.pos));
out.append(inputSubstring(chunkStart, this.pos)); out.append(this.jsx_readNewLine(false));
out.append(this.jsx_readNewLine(false)); chunkStart = this.pos;
chunkStart = this.pos; } else {
} else { ++this.pos;
++this.pos; }
} }
} out.append(inputSubstring(chunkStart, this.pos++));
out.append(inputSubstring(chunkStart, this.pos++)); return this.finishToken(string, out.toString());
return this.finishToken(string, out.toString()); }
}
private String jsx_readEntity() { private String jsx_readEntity() {
int ch = this.charAt(this.pos); int ch = this.charAt(this.pos);
if (ch != '&') if (ch != '&') this.raise(this.pos, "Entity must start with an ampersand");
this.raise(this.pos, "Entity must start with an ampersand"); int startPos = ++this.pos;
int startPos = ++this.pos; String entity = null;
String entity = null; int semi = this.input.indexOf(';', startPos);
int semi = this.input.indexOf(';', startPos); if (semi != -1) {
if (semi != -1) { String entityName = inputSubstring(startPos, semi);
String entityName = inputSubstring(startPos, semi); if (entityName.startsWith("#x")) {
if (entityName.startsWith("#x")) { entityName = entityName.substring(2);
entityName = entityName.substring(2); if (hexNumber.matcher(entityName).matches())
if (hexNumber.matcher(entityName).matches()) entity = codePointToString(parseInt(entityName, 16).intValue());
entity = codePointToString(parseInt(entityName, 16).intValue()); } else if (entityName.startsWith("#")) {
} else if (entityName.startsWith("#")) { entityName = entityName.substring(1);
entityName = entityName.substring(1); if (decimalNumber.matcher(entityName).matches())
if (decimalNumber.matcher(entityName).matches()) entity = codePointToString(parseInt(entityName, 10).intValue());
entity = codePointToString(parseInt(entityName, 10).intValue()); } else {
} else { Character entityChar = XHTMLEntities.ENTITIES.get(entityName);
Character entityChar = XHTMLEntities.ENTITIES.get(entityName); if (entityChar != null) entity = String.valueOf(entityChar);
if (entityChar != null) }
entity = String.valueOf(entityChar); }
}
}
if (entity == null) { if (entity == null) {
this.pos = startPos; this.pos = startPos;
return "&"; return "&";
} else { } else {
this.pos = semi+1; this.pos = semi + 1;
return entity; return entity;
} }
} }
/** /**
* Read a JSX identifier (valid tag or attribute name). * Read a JSX identifier (valid tag or attribute name).
* *
* Optimized version since JSX identifiers can't contain * <p>Optimized version since JSX identifiers can't contain escape characters and so can be read
* escape characters and so can be read as single slice. * as single slice. Also assumes that first character was already checked by isIdentifierStart in
* Also assumes that first character was already checked * readToken.
* by isIdentifierStart in readToken. */
*/ private Token jsx_readWord() {
private Token jsx_readWord() { int ch, start = this.pos;
int ch, start = this.pos; do {
do { ch = this.charAt(++this.pos);
ch = this.charAt(++this.pos); } while (Identifiers.isIdentifierChar(ch, true) || ch == 45); // '-'
} while (Identifiers.isIdentifierChar(ch, true) || ch == 45); // '-' return this.finishToken(jsxName, inputSubstring(start, this.pos));
return this.finishToken(jsxName, inputSubstring(start, this.pos)); }
}
/** Transforms JSX element name to string; {@code null} is transformed to {@code null}. */ /** Transforms JSX element name to string; {@code null} is transformed to {@code null}. */
private String getQualifiedJSXName(Object object) { private String getQualifiedJSXName(Object object) {
if (object == null) if (object == null) return null;
return null; return ((IJSXName) object).getQualifiedName();
return ((IJSXName) object).getQualifiedName(); }
}
/** Parse next token as JSX identifier */ /** Parse next token as JSX identifier */
private JSXIdentifier jsx_parseIdentifier() { private JSXIdentifier jsx_parseIdentifier() {
SourceLocation loc = new SourceLocation(this.startLoc); SourceLocation loc = new SourceLocation(this.startLoc);
String name = null; String name = null;
if (this.type == jsxName) if (this.type == jsxName) name = String.valueOf(this.value);
name = String.valueOf(this.value); else if (this.type.keyword != null) name = this.type.keyword;
else if (this.type.keyword != null) else this.unexpected();
name = this.type.keyword; this.next();
else return this.finishNode(new JSXIdentifier(loc, name));
this.unexpected(); }
this.next();
return this.finishNode(new JSXIdentifier(loc, name));
}
/** Parse namespaced identifier. */ /** Parse namespaced identifier. */
private IJSXName jsx_parseNamespacedName() { private IJSXName jsx_parseNamespacedName() {
SourceLocation loc = new SourceLocation(this.startLoc); SourceLocation loc = new SourceLocation(this.startLoc);
JSXIdentifier namespace = this.jsx_parseIdentifier(); JSXIdentifier namespace = this.jsx_parseIdentifier();
if (!((JSXOptions)options).allowNamespaces || !this.eat(colon)) if (!((JSXOptions) options).allowNamespaces || !this.eat(colon)) return namespace;
return namespace; return this.finishNode(new JSXNamespacedName(loc, namespace, this.jsx_parseIdentifier()));
return this.finishNode(new JSXNamespacedName(loc, namespace, this.jsx_parseIdentifier())); }
}
/** /**
* Parses element name in any form - namespaced, member * Parses element name in any form - namespaced, member or single identifier. If the next token is
* or single identifier. If the next token is a tag-end token, * a tag-end token, {@code null} is returned; this happens with fragments.
* {@code null} is returned; this happens with fragments. */
*/ private IJSXName jsx_parseElementName() {
private IJSXName jsx_parseElementName () { if (this.type == jsxTagEnd) return null;
if (this.type == jsxTagEnd) Position startPos = this.startLoc;
return null; IJSXName node = this.jsx_parseNamespacedName();
Position startPos = this.startLoc; if (this.type == dot
IJSXName node = this.jsx_parseNamespacedName(); && node instanceof JSXNamespacedName
if (this.type == dot && node instanceof JSXNamespacedName && !((JSXOptions)options).allowNamespacedObjects) { && !((JSXOptions) options).allowNamespacedObjects) {
this.unexpected(); this.unexpected();
} }
while (this.eat(dot)) { while (this.eat(dot)) {
SourceLocation loc = new SourceLocation(startPos); SourceLocation loc = new SourceLocation(startPos);
node = this.finishNode(new JSXMemberExpression(loc, node, this.jsx_parseIdentifier())); node = this.finishNode(new JSXMemberExpression(loc, node, this.jsx_parseIdentifier()));
} }
return node; return node;
} }
/** Parses any type of JSX attribute value. */ /** Parses any type of JSX attribute value. */
private INode jsx_parseAttributeValue() { private INode jsx_parseAttributeValue() {
if (type == braceL) { if (type == braceL) {
JSXExpressionContainer node = this.jsx_parseExpressionContainer(); JSXExpressionContainer node = this.jsx_parseExpressionContainer();
if (node.getExpression() instanceof JSXEmptyExpression) if (node.getExpression() instanceof JSXEmptyExpression)
this.raise(node, "JSX attributes must only be assigned a non-empty expression"); this.raise(node, "JSX attributes must only be assigned a non-empty expression");
return node; return node;
} else if (type == jsxTagStart || type == string) { } else if (type == jsxTagStart || type == string) {
return this.parseExprAtom(null); return this.parseExprAtom(null);
} else { } else {
this.raise(this.start, "JSX value should be either an expression or a quoted JSX text"); this.raise(this.start, "JSX value should be either an expression or a quoted JSX text");
return null; return null;
} }
} }
/** /**
* JSXEmptyExpression is unique type since it doesn't actually parse anything, * JSXEmptyExpression is unique type since it doesn't actually parse anything, and so it should
* and so it should start at the end of last read token (left brace) and finish * start at the end of last read token (left brace) and finish at the beginning of the next one
* at the beginning of the next one (right brace). * (right brace).
*/ */
private JSXEmptyExpression jsx_parseEmptyExpression() { private JSXEmptyExpression jsx_parseEmptyExpression() {
return new JSXEmptyExpression(new SourceLocation("", lastTokEndLoc, startLoc)); return new JSXEmptyExpression(new SourceLocation("", lastTokEndLoc, startLoc));
} }
/** Parses JSX expression enclosed into curly brackets. */ /** Parses JSX expression enclosed into curly brackets. */
private JSXExpressionContainer jsx_parseExpressionContainer() { private JSXExpressionContainer jsx_parseExpressionContainer() {
SourceLocation loc = new SourceLocation(this.startLoc); SourceLocation loc = new SourceLocation(this.startLoc);
this.next(); this.next();
INode expression; INode expression;
if (this.type == braceR) if (this.type == braceR) expression = this.jsx_parseEmptyExpression();
expression = this.jsx_parseEmptyExpression(); else expression = this.parseExpression(false, null);
else this.expect(braceR);
expression = this.parseExpression(false, null); return this.finishNode(new JSXExpressionContainer(loc, expression));
this.expect(braceR); }
return this.finishNode(new JSXExpressionContainer(loc, expression));
}
/** Parses following JSX attribute name-value pair. */ /** Parses following JSX attribute name-value pair. */
private IJSXAttribute jsx_parseAttribute() { private IJSXAttribute jsx_parseAttribute() {
SourceLocation loc = new SourceLocation(this.startLoc); SourceLocation loc = new SourceLocation(this.startLoc);
if (this.eat(braceL)) { if (this.eat(braceL)) {
this.expect(ellipsis); this.expect(ellipsis);
Expression argument = this.parseMaybeAssign(false, null, null); Expression argument = this.parseMaybeAssign(false, null, null);
this.expect(braceR); this.expect(braceR);
return this.finishNode(new JSXSpreadAttribute(loc, argument)); return this.finishNode(new JSXSpreadAttribute(loc, argument));
} }
IJSXName name = this.jsx_parseNamespacedName(); IJSXName name = this.jsx_parseNamespacedName();
INode value = this.eat(eq) ? this.jsx_parseAttributeValue() : null; INode value = this.eat(eq) ? this.jsx_parseAttributeValue() : null;
return this.finishNode(new JSXAttribute(loc, name, value)); return this.finishNode(new JSXAttribute(loc, name, value));
} }
/** Parses JSX opening tag starting after '&lt;'. */ /** Parses JSX opening tag starting after '&lt;'. */
private JSXOpeningElement jsx_parseOpeningElementAt(Position startLoc) { private JSXOpeningElement jsx_parseOpeningElementAt(Position startLoc) {
SourceLocation loc = new SourceLocation(startLoc); SourceLocation loc = new SourceLocation(startLoc);
List<IJSXAttribute> attributes = new ArrayList<>(); List<IJSXAttribute> attributes = new ArrayList<>();
IJSXName name = this.jsx_parseElementName(); IJSXName name = this.jsx_parseElementName();
while (this.type != slash && this.type != jsxTagEnd) while (this.type != slash && this.type != jsxTagEnd) attributes.add(this.jsx_parseAttribute());
attributes.add(this.jsx_parseAttribute()); boolean selfClosing = this.eat(slash);
boolean selfClosing = this.eat(slash); this.expect(jsxTagEnd);
this.expect(jsxTagEnd); return this.finishNode(new JSXOpeningElement(loc, name, attributes, selfClosing));
return this.finishNode(new JSXOpeningElement(loc, name, attributes, selfClosing)); }
}
/** Parses JSX closing tag starting after '&lt;/'. */ /** Parses JSX closing tag starting after '&lt;/'. */
private JSXClosingElement jsx_parseClosingElementAt(Position startLoc) { private JSXClosingElement jsx_parseClosingElementAt(Position startLoc) {
SourceLocation loc = new SourceLocation(startLoc); SourceLocation loc = new SourceLocation(startLoc);
IJSXName name = this.jsx_parseElementName(); IJSXName name = this.jsx_parseElementName();
this.expect(jsxTagEnd); this.expect(jsxTagEnd);
return this.finishNode(new JSXClosingElement(loc, name)); return this.finishNode(new JSXClosingElement(loc, name));
} }
/** /**
* Parses entire JSX element, including its opening tag * Parses entire JSX element, including its opening tag (starting after '&lt;'), attributes,
* (starting after '&lt;'), attributes, contents and closing tag. * contents and closing tag.
*/ */
private JSXElement jsx_parseElementAt(Position startLoc) { private JSXElement jsx_parseElementAt(Position startLoc) {
SourceLocation loc = new SourceLocation(startLoc); SourceLocation loc = new SourceLocation(startLoc);
List<INode> children = new ArrayList<INode>(); List<INode> children = new ArrayList<INode>();
JSXOpeningElement openingElement = this.jsx_parseOpeningElementAt(startLoc); JSXOpeningElement openingElement = this.jsx_parseOpeningElementAt(startLoc);
JSXClosingElement closingElement = null; JSXClosingElement closingElement = null;
if (!openingElement.isSelfClosing()) { if (!openingElement.isSelfClosing()) {
contents: contents:
for (;;) { for (; ; ) {
if (type == jsxTagStart) { if (type == jsxTagStart) {
startLoc = this.startLoc; startLoc = this.startLoc;
this.next(); this.next();
if (this.eat(slash)) { if (this.eat(slash)) {
closingElement = this.jsx_parseClosingElementAt(startLoc); closingElement = this.jsx_parseClosingElementAt(startLoc);
break contents; break contents;
} }
children.add(this.jsx_parseElementAt(startLoc)); children.add(this.jsx_parseElementAt(startLoc));
} else if (type == jsxText) { } else if (type == jsxText) {
children.add(this.parseExprAtom(null)); children.add(this.parseExprAtom(null));
} else if (type == braceL) { } else if (type == braceL) {
children.add(this.jsx_parseExpressionContainer()); children.add(this.jsx_parseExpressionContainer());
} else { } else {
this.unexpected(); this.unexpected();
} }
} }
String closingQualName = getQualifiedJSXName(openingElement.getName()); String closingQualName = getQualifiedJSXName(openingElement.getName());
if (!Objects.equals(getQualifiedJSXName(closingElement.getName()), closingQualName)) { if (!Objects.equals(getQualifiedJSXName(closingElement.getName()), closingQualName)) {
// prettify for error message // prettify for error message
if (closingQualName == null) if (closingQualName == null) closingQualName = "";
closingQualName = ""; this.raise(
this.raise( closingElement, "Expected corresponding JSX closing tag for <" + closingQualName + ">");
closingElement, }
"Expected corresponding JSX closing tag for <" + closingQualName + ">"); }
}
}
if (this.type == relational && "<".equals(this.value)) { if (this.type == relational && "<".equals(this.value)) {
this.raise(this.start, "Adjacent JSX elements must be wrapped in an enclosing tag"); this.raise(this.start, "Adjacent JSX elements must be wrapped in an enclosing tag");
} }
return this.finishNode(new JSXElement(loc, openingElement, children, closingElement)); return this.finishNode(new JSXElement(loc, openingElement, children, closingElement));
} }
/** Parses entire JSX element from current position. */ /** Parses entire JSX element from current position. */
private JSXElement jsx_parseElement() { private JSXElement jsx_parseElement() {
Position startLoc = this.startLoc; Position startLoc = this.startLoc;
this.next(); this.next();
return this.jsx_parseElementAt(startLoc); return this.jsx_parseElementAt(startLoc);
} }
@Override @Override
protected Expression parseExprAtom(DestructuringErrors refDestructuringErrors) { protected Expression parseExprAtom(DestructuringErrors refDestructuringErrors) {
if (this.type == jsxText) { if (this.type == jsxText) {
return this.parseLiteral(this.type, this.value); return this.parseLiteral(this.type, this.value);
} else if (this.type == jsxTagStart) { } else if (this.type == jsxTagStart) {
return this.jsx_parseElement(); return this.jsx_parseElement();
} else { } else {
return super.parseExprAtom(refDestructuringErrors); return super.parseExprAtom(refDestructuringErrors);
} }
} }
@Override @Override
protected Token readToken(int code) { protected Token readToken(int code) {
TokContext context = this.curContext(); TokContext context = this.curContext();
if (context == j_expr)
return this.jsx_readToken();
if (context == j_oTag || context == j_cTag) {
if (Identifiers.isIdentifierStart(code, true))
return this.jsx_readWord();
if (code == 62) {
++this.pos;
return this.finishToken(jsxTagEnd);
}
if ((code == 34 || code == 39) && context == j_oTag)
return this.jsx_readString((char)code);
}
if (options instanceof JSXOptions && code == 60 && this.exprAllowed &&
// avoid getting confused on HTML comments
this.charAt(this.pos+1) != '!') {
++this.pos;
return this.finishToken(jsxTagStart);
}
return super.readToken(code);
}
@Override if (context == j_expr) return this.jsx_readToken();
protected void updateContext(TokenType prevType) {
if (options instanceof JSXOptions) { if (context == j_oTag || context == j_cTag) {
if (type == braceL) { if (Identifiers.isIdentifierStart(code, true)) return this.jsx_readWord();
TokContext curContext = this.curContext();
if (curContext == j_oTag) { if (code == 62) {
this.context.push(b_expr); ++this.pos;
} else if (curContext == j_expr) { return this.finishToken(jsxTagEnd);
this.context.push(b_tmpl); }
} else {
type.updateContext(this, prevType); if ((code == 34 || code == 39) && context == j_oTag) return this.jsx_readString((char) code);
} }
this.exprAllowed = true;
return; if (options instanceof JSXOptions
} else if (type == slash && prevType == jsxTagStart) { && code == 60
this.context.pop(); && this.exprAllowed
this.context.pop(); // do not consider JSX expr -> JSX open tag -> ... anymore &&
this.context.push(j_cTag); // avoid getting confused on HTML comments
this.exprAllowed = false; this.charAt(this.pos + 1) != '!') {
return; ++this.pos;
} return this.finishToken(jsxTagStart);
} }
super.updateContext(prevType);
} return super.readToken(code);
}
@Override
protected void updateContext(TokenType prevType) {
if (options instanceof JSXOptions) {
if (type == braceL) {
TokContext curContext = this.curContext();
if (curContext == j_oTag) {
this.context.push(b_expr);
} else if (curContext == j_expr) {
this.context.push(b_tmpl);
} else {
type.updateContext(this, prevType);
}
this.exprAllowed = true;
return;
} else if (type == slash && prevType == jsxTagStart) {
this.context.pop();
this.context.pop(); // do not consider JSX expr -> JSX open tag -> ... anymore
this.context.push(j_cTag);
this.exprAllowed = false;
return;
}
}
super.updateContext(prevType);
}
} }

View File

@@ -4,260 +4,261 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public class XHTMLEntities { public class XHTMLEntities {
public static final Map<String, Character> ENTITIES = new LinkedHashMap<>(); public static final Map<String, Character> ENTITIES = new LinkedHashMap<>();
static {
ENTITIES.put("quot", '\u0022'); static {
ENTITIES.put("amp", '&'); ENTITIES.put("quot", '\u0022');
ENTITIES.put("apos", '\''); ENTITIES.put("amp", '&');
ENTITIES.put("lt", '<'); ENTITIES.put("apos", '\'');
ENTITIES.put("gt", '>'); ENTITIES.put("lt", '<');
ENTITIES.put("nbsp", '\u00A0'); ENTITIES.put("gt", '>');
ENTITIES.put("iexcl", '\u00A1'); ENTITIES.put("nbsp", '\u00A0');
ENTITIES.put("cent", '\u00A2'); ENTITIES.put("iexcl", '\u00A1');
ENTITIES.put("pound", '\u00A3'); ENTITIES.put("cent", '\u00A2');
ENTITIES.put("curren", '\u00A4'); ENTITIES.put("pound", '\u00A3');
ENTITIES.put("yen", '\u00A5'); ENTITIES.put("curren", '\u00A4');
ENTITIES.put("brvbar", '\u00A6'); ENTITIES.put("yen", '\u00A5');
ENTITIES.put("sect", '\u00A7'); ENTITIES.put("brvbar", '\u00A6');
ENTITIES.put("uml", '\u00A8'); ENTITIES.put("sect", '\u00A7');
ENTITIES.put("copy", '\u00A9'); ENTITIES.put("uml", '\u00A8');
ENTITIES.put("ordf", '\u00AA'); ENTITIES.put("copy", '\u00A9');
ENTITIES.put("laquo", '\u00AB'); ENTITIES.put("ordf", '\u00AA');
ENTITIES.put("not", '\u00AC'); ENTITIES.put("laquo", '\u00AB');
ENTITIES.put("shy", '\u00AD'); ENTITIES.put("not", '\u00AC');
ENTITIES.put("reg", '\u00AE'); ENTITIES.put("shy", '\u00AD');
ENTITIES.put("macr", '\u00AF'); ENTITIES.put("reg", '\u00AE');
ENTITIES.put("deg", '\u00B0'); ENTITIES.put("macr", '\u00AF');
ENTITIES.put("plusmn", '\u00B1'); ENTITIES.put("deg", '\u00B0');
ENTITIES.put("sup2", '\u00B2'); ENTITIES.put("plusmn", '\u00B1');
ENTITIES.put("sup3", '\u00B3'); ENTITIES.put("sup2", '\u00B2');
ENTITIES.put("acute", '\u00B4'); ENTITIES.put("sup3", '\u00B3');
ENTITIES.put("micro", '\u00B5'); ENTITIES.put("acute", '\u00B4');
ENTITIES.put("para", '\u00B6'); ENTITIES.put("micro", '\u00B5');
ENTITIES.put("middot", '\u00B7'); ENTITIES.put("para", '\u00B6');
ENTITIES.put("cedil", '\u00B8'); ENTITIES.put("middot", '\u00B7');
ENTITIES.put("sup1", '\u00B9'); ENTITIES.put("cedil", '\u00B8');
ENTITIES.put("ordm", '\u00BA'); ENTITIES.put("sup1", '\u00B9');
ENTITIES.put("raquo", '\u00BB'); ENTITIES.put("ordm", '\u00BA');
ENTITIES.put("frac14", '\u00BC'); ENTITIES.put("raquo", '\u00BB');
ENTITIES.put("frac12", '\u00BD'); ENTITIES.put("frac14", '\u00BC');
ENTITIES.put("frac34", '\u00BE'); ENTITIES.put("frac12", '\u00BD');
ENTITIES.put("iquest", '\u00BF'); ENTITIES.put("frac34", '\u00BE');
ENTITIES.put("Agrave", '\u00C0'); ENTITIES.put("iquest", '\u00BF');
ENTITIES.put("Aacute", '\u00C1'); ENTITIES.put("Agrave", '\u00C0');
ENTITIES.put("Acirc", '\u00C2'); ENTITIES.put("Aacute", '\u00C1');
ENTITIES.put("Atilde", '\u00C3'); ENTITIES.put("Acirc", '\u00C2');
ENTITIES.put("Auml", '\u00C4'); ENTITIES.put("Atilde", '\u00C3');
ENTITIES.put("Aring", '\u00C5'); ENTITIES.put("Auml", '\u00C4');
ENTITIES.put("AElig", '\u00C6'); ENTITIES.put("Aring", '\u00C5');
ENTITIES.put("Ccedil", '\u00C7'); ENTITIES.put("AElig", '\u00C6');
ENTITIES.put("Egrave", '\u00C8'); ENTITIES.put("Ccedil", '\u00C7');
ENTITIES.put("Eacute", '\u00C9'); ENTITIES.put("Egrave", '\u00C8');
ENTITIES.put("Ecirc", '\u00CA'); ENTITIES.put("Eacute", '\u00C9');
ENTITIES.put("Euml", '\u00CB'); ENTITIES.put("Ecirc", '\u00CA');
ENTITIES.put("Igrave", '\u00CC'); ENTITIES.put("Euml", '\u00CB');
ENTITIES.put("Iacute", '\u00CD'); ENTITIES.put("Igrave", '\u00CC');
ENTITIES.put("Icirc", '\u00CE'); ENTITIES.put("Iacute", '\u00CD');
ENTITIES.put("Iuml", '\u00CF'); ENTITIES.put("Icirc", '\u00CE');
ENTITIES.put("ETH", '\u00D0'); ENTITIES.put("Iuml", '\u00CF');
ENTITIES.put("Ntilde", '\u00D1'); ENTITIES.put("ETH", '\u00D0');
ENTITIES.put("Ograve", '\u00D2'); ENTITIES.put("Ntilde", '\u00D1');
ENTITIES.put("Oacute", '\u00D3'); ENTITIES.put("Ograve", '\u00D2');
ENTITIES.put("Ocirc", '\u00D4'); ENTITIES.put("Oacute", '\u00D3');
ENTITIES.put("Otilde", '\u00D5'); ENTITIES.put("Ocirc", '\u00D4');
ENTITIES.put("Ouml", '\u00D6'); ENTITIES.put("Otilde", '\u00D5');
ENTITIES.put("times", '\u00D7'); ENTITIES.put("Ouml", '\u00D6');
ENTITIES.put("Oslash", '\u00D8'); ENTITIES.put("times", '\u00D7');
ENTITIES.put("Ugrave", '\u00D9'); ENTITIES.put("Oslash", '\u00D8');
ENTITIES.put("Uacute", '\u00DA'); ENTITIES.put("Ugrave", '\u00D9');
ENTITIES.put("Ucirc", '\u00DB'); ENTITIES.put("Uacute", '\u00DA');
ENTITIES.put("Uuml", '\u00DC'); ENTITIES.put("Ucirc", '\u00DB');
ENTITIES.put("Yacute", '\u00DD'); ENTITIES.put("Uuml", '\u00DC');
ENTITIES.put("THORN", '\u00DE'); ENTITIES.put("Yacute", '\u00DD');
ENTITIES.put("szlig", '\u00DF'); ENTITIES.put("THORN", '\u00DE');
ENTITIES.put("agrave", '\u00E0'); ENTITIES.put("szlig", '\u00DF');
ENTITIES.put("aacute", '\u00E1'); ENTITIES.put("agrave", '\u00E0');
ENTITIES.put("acirc", '\u00E2'); ENTITIES.put("aacute", '\u00E1');
ENTITIES.put("atilde", '\u00E3'); ENTITIES.put("acirc", '\u00E2');
ENTITIES.put("auml", '\u00E4'); ENTITIES.put("atilde", '\u00E3');
ENTITIES.put("aring", '\u00E5'); ENTITIES.put("auml", '\u00E4');
ENTITIES.put("aelig", '\u00E6'); ENTITIES.put("aring", '\u00E5');
ENTITIES.put("ccedil", '\u00E7'); ENTITIES.put("aelig", '\u00E6');
ENTITIES.put("egrave", '\u00E8'); ENTITIES.put("ccedil", '\u00E7');
ENTITIES.put("eacute", '\u00E9'); ENTITIES.put("egrave", '\u00E8');
ENTITIES.put("ecirc", '\u00EA'); ENTITIES.put("eacute", '\u00E9');
ENTITIES.put("euml", '\u00EB'); ENTITIES.put("ecirc", '\u00EA');
ENTITIES.put("igrave", '\u00EC'); ENTITIES.put("euml", '\u00EB');
ENTITIES.put("iacute", '\u00ED'); ENTITIES.put("igrave", '\u00EC');
ENTITIES.put("icirc", '\u00EE'); ENTITIES.put("iacute", '\u00ED');
ENTITIES.put("iuml", '\u00EF'); ENTITIES.put("icirc", '\u00EE');
ENTITIES.put("eth", '\u00F0'); ENTITIES.put("iuml", '\u00EF');
ENTITIES.put("ntilde", '\u00F1'); ENTITIES.put("eth", '\u00F0');
ENTITIES.put("ograve", '\u00F2'); ENTITIES.put("ntilde", '\u00F1');
ENTITIES.put("oacute", '\u00F3'); ENTITIES.put("ograve", '\u00F2');
ENTITIES.put("ocirc", '\u00F4'); ENTITIES.put("oacute", '\u00F3');
ENTITIES.put("otilde", '\u00F5'); ENTITIES.put("ocirc", '\u00F4');
ENTITIES.put("ouml", '\u00F6'); ENTITIES.put("otilde", '\u00F5');
ENTITIES.put("divide", '\u00F7'); ENTITIES.put("ouml", '\u00F6');
ENTITIES.put("oslash", '\u00F8'); ENTITIES.put("divide", '\u00F7');
ENTITIES.put("ugrave", '\u00F9'); ENTITIES.put("oslash", '\u00F8');
ENTITIES.put("uacute", '\u00FA'); ENTITIES.put("ugrave", '\u00F9');
ENTITIES.put("ucirc", '\u00FB'); ENTITIES.put("uacute", '\u00FA');
ENTITIES.put("uuml", '\u00FC'); ENTITIES.put("ucirc", '\u00FB');
ENTITIES.put("yacute", '\u00FD'); ENTITIES.put("uuml", '\u00FC');
ENTITIES.put("thorn", '\u00FE'); ENTITIES.put("yacute", '\u00FD');
ENTITIES.put("yuml", '\u00FF'); ENTITIES.put("thorn", '\u00FE');
ENTITIES.put("OElig", '\u0152'); ENTITIES.put("yuml", '\u00FF');
ENTITIES.put("oelig", '\u0153'); ENTITIES.put("OElig", '\u0152');
ENTITIES.put("Scaron", '\u0160'); ENTITIES.put("oelig", '\u0153');
ENTITIES.put("scaron", '\u0161'); ENTITIES.put("Scaron", '\u0160');
ENTITIES.put("Yuml", '\u0178'); ENTITIES.put("scaron", '\u0161');
ENTITIES.put("fnof", '\u0192'); ENTITIES.put("Yuml", '\u0178');
ENTITIES.put("circ", '\u02C6'); ENTITIES.put("fnof", '\u0192');
ENTITIES.put("tilde", '\u02DC'); ENTITIES.put("circ", '\u02C6');
ENTITIES.put("Alpha", '\u0391'); ENTITIES.put("tilde", '\u02DC');
ENTITIES.put("Beta", '\u0392'); ENTITIES.put("Alpha", '\u0391');
ENTITIES.put("Gamma", '\u0393'); ENTITIES.put("Beta", '\u0392');
ENTITIES.put("Delta", '\u0394'); ENTITIES.put("Gamma", '\u0393');
ENTITIES.put("Epsilon", '\u0395'); ENTITIES.put("Delta", '\u0394');
ENTITIES.put("Zeta", '\u0396'); ENTITIES.put("Epsilon", '\u0395');
ENTITIES.put("Eta", '\u0397'); ENTITIES.put("Zeta", '\u0396');
ENTITIES.put("Theta", '\u0398'); ENTITIES.put("Eta", '\u0397');
ENTITIES.put("Iota", '\u0399'); ENTITIES.put("Theta", '\u0398');
ENTITIES.put("Kappa", '\u039A'); ENTITIES.put("Iota", '\u0399');
ENTITIES.put("Lambda", '\u039B'); ENTITIES.put("Kappa", '\u039A');
ENTITIES.put("Mu", '\u039C'); ENTITIES.put("Lambda", '\u039B');
ENTITIES.put("Nu", '\u039D'); ENTITIES.put("Mu", '\u039C');
ENTITIES.put("Xi", '\u039E'); ENTITIES.put("Nu", '\u039D');
ENTITIES.put("Omicron", '\u039F'); ENTITIES.put("Xi", '\u039E');
ENTITIES.put("Pi", '\u03A0'); ENTITIES.put("Omicron", '\u039F');
ENTITIES.put("Rho", '\u03A1'); ENTITIES.put("Pi", '\u03A0');
ENTITIES.put("Sigma", '\u03A3'); ENTITIES.put("Rho", '\u03A1');
ENTITIES.put("Tau", '\u03A4'); ENTITIES.put("Sigma", '\u03A3');
ENTITIES.put("Upsilon", '\u03A5'); ENTITIES.put("Tau", '\u03A4');
ENTITIES.put("Phi", '\u03A6'); ENTITIES.put("Upsilon", '\u03A5');
ENTITIES.put("Chi", '\u03A7'); ENTITIES.put("Phi", '\u03A6');
ENTITIES.put("Psi", '\u03A8'); ENTITIES.put("Chi", '\u03A7');
ENTITIES.put("Omega", '\u03A9'); ENTITIES.put("Psi", '\u03A8');
ENTITIES.put("alpha", '\u03B1'); ENTITIES.put("Omega", '\u03A9');
ENTITIES.put("beta", '\u03B2'); ENTITIES.put("alpha", '\u03B1');
ENTITIES.put("gamma", '\u03B3'); ENTITIES.put("beta", '\u03B2');
ENTITIES.put("delta", '\u03B4'); ENTITIES.put("gamma", '\u03B3');
ENTITIES.put("epsilon", '\u03B5'); ENTITIES.put("delta", '\u03B4');
ENTITIES.put("zeta", '\u03B6'); ENTITIES.put("epsilon", '\u03B5');
ENTITIES.put("eta", '\u03B7'); ENTITIES.put("zeta", '\u03B6');
ENTITIES.put("theta", '\u03B8'); ENTITIES.put("eta", '\u03B7');
ENTITIES.put("iota", '\u03B9'); ENTITIES.put("theta", '\u03B8');
ENTITIES.put("kappa", '\u03BA'); ENTITIES.put("iota", '\u03B9');
ENTITIES.put("lambda", '\u03BB'); ENTITIES.put("kappa", '\u03BA');
ENTITIES.put("mu", '\u03BC'); ENTITIES.put("lambda", '\u03BB');
ENTITIES.put("nu", '\u03BD'); ENTITIES.put("mu", '\u03BC');
ENTITIES.put("xi", '\u03BE'); ENTITIES.put("nu", '\u03BD');
ENTITIES.put("omicron", '\u03BF'); ENTITIES.put("xi", '\u03BE');
ENTITIES.put("pi", '\u03C0'); ENTITIES.put("omicron", '\u03BF');
ENTITIES.put("rho", '\u03C1'); ENTITIES.put("pi", '\u03C0');
ENTITIES.put("sigmaf", '\u03C2'); ENTITIES.put("rho", '\u03C1');
ENTITIES.put("sigma", '\u03C3'); ENTITIES.put("sigmaf", '\u03C2');
ENTITIES.put("tau", '\u03C4'); ENTITIES.put("sigma", '\u03C3');
ENTITIES.put("upsilon", '\u03C5'); ENTITIES.put("tau", '\u03C4');
ENTITIES.put("phi", '\u03C6'); ENTITIES.put("upsilon", '\u03C5');
ENTITIES.put("chi", '\u03C7'); ENTITIES.put("phi", '\u03C6');
ENTITIES.put("psi", '\u03C8'); ENTITIES.put("chi", '\u03C7');
ENTITIES.put("omega", '\u03C9'); ENTITIES.put("psi", '\u03C8');
ENTITIES.put("thetasym", '\u03D1'); ENTITIES.put("omega", '\u03C9');
ENTITIES.put("upsih", '\u03D2'); ENTITIES.put("thetasym", '\u03D1');
ENTITIES.put("piv", '\u03D6'); ENTITIES.put("upsih", '\u03D2');
ENTITIES.put("ensp", '\u2002'); ENTITIES.put("piv", '\u03D6');
ENTITIES.put("emsp", '\u2003'); ENTITIES.put("ensp", '\u2002');
ENTITIES.put("thinsp", '\u2009'); ENTITIES.put("emsp", '\u2003');
ENTITIES.put("zwnj", '\u200C'); ENTITIES.put("thinsp", '\u2009');
ENTITIES.put("zwj", '\u200D'); ENTITIES.put("zwnj", '\u200C');
ENTITIES.put("lrm", '\u200E'); ENTITIES.put("zwj", '\u200D');
ENTITIES.put("rlm", '\u200F'); ENTITIES.put("lrm", '\u200E');
ENTITIES.put("ndash", '\u2013'); ENTITIES.put("rlm", '\u200F');
ENTITIES.put("mdash", '\u2014'); ENTITIES.put("ndash", '\u2013');
ENTITIES.put("lsquo", '\u2018'); ENTITIES.put("mdash", '\u2014');
ENTITIES.put("rsquo", '\u2019'); ENTITIES.put("lsquo", '\u2018');
ENTITIES.put("sbquo", '\u201A'); ENTITIES.put("rsquo", '\u2019');
ENTITIES.put("ldquo", '\u201C'); ENTITIES.put("sbquo", '\u201A');
ENTITIES.put("rdquo", '\u201D'); ENTITIES.put("ldquo", '\u201C');
ENTITIES.put("bdquo", '\u201E'); ENTITIES.put("rdquo", '\u201D');
ENTITIES.put("dagger", '\u2020'); ENTITIES.put("bdquo", '\u201E');
ENTITIES.put("Dagger", '\u2021'); ENTITIES.put("dagger", '\u2020');
ENTITIES.put("bull", '\u2022'); ENTITIES.put("Dagger", '\u2021');
ENTITIES.put("hellip", '\u2026'); ENTITIES.put("bull", '\u2022');
ENTITIES.put("permil", '\u2030'); ENTITIES.put("hellip", '\u2026');
ENTITIES.put("prime", '\u2032'); ENTITIES.put("permil", '\u2030');
ENTITIES.put("Prime", '\u2033'); ENTITIES.put("prime", '\u2032');
ENTITIES.put("lsaquo", '\u2039'); ENTITIES.put("Prime", '\u2033');
ENTITIES.put("rsaquo", '\u203A'); ENTITIES.put("lsaquo", '\u2039');
ENTITIES.put("oline", '\u203E'); ENTITIES.put("rsaquo", '\u203A');
ENTITIES.put("frasl", '\u2044'); ENTITIES.put("oline", '\u203E');
ENTITIES.put("euro", '\u20AC'); ENTITIES.put("frasl", '\u2044');
ENTITIES.put("image", '\u2111'); ENTITIES.put("euro", '\u20AC');
ENTITIES.put("weierp", '\u2118'); ENTITIES.put("image", '\u2111');
ENTITIES.put("real", '\u211C'); ENTITIES.put("weierp", '\u2118');
ENTITIES.put("trade", '\u2122'); ENTITIES.put("real", '\u211C');
ENTITIES.put("alefsym", '\u2135'); ENTITIES.put("trade", '\u2122');
ENTITIES.put("larr", '\u2190'); ENTITIES.put("alefsym", '\u2135');
ENTITIES.put("uarr", '\u2191'); ENTITIES.put("larr", '\u2190');
ENTITIES.put("rarr", '\u2192'); ENTITIES.put("uarr", '\u2191');
ENTITIES.put("darr", '\u2193'); ENTITIES.put("rarr", '\u2192');
ENTITIES.put("harr", '\u2194'); ENTITIES.put("darr", '\u2193');
ENTITIES.put("crarr", '\u21B5'); ENTITIES.put("harr", '\u2194');
ENTITIES.put("lArr", '\u21D0'); ENTITIES.put("crarr", '\u21B5');
ENTITIES.put("uArr", '\u21D1'); ENTITIES.put("lArr", '\u21D0');
ENTITIES.put("rArr", '\u21D2'); ENTITIES.put("uArr", '\u21D1');
ENTITIES.put("dArr", '\u21D3'); ENTITIES.put("rArr", '\u21D2');
ENTITIES.put("hArr", '\u21D4'); ENTITIES.put("dArr", '\u21D3');
ENTITIES.put("forall", '\u2200'); ENTITIES.put("hArr", '\u21D4');
ENTITIES.put("part", '\u2202'); ENTITIES.put("forall", '\u2200');
ENTITIES.put("exist", '\u2203'); ENTITIES.put("part", '\u2202');
ENTITIES.put("empty", '\u2205'); ENTITIES.put("exist", '\u2203');
ENTITIES.put("nabla", '\u2207'); ENTITIES.put("empty", '\u2205');
ENTITIES.put("isin", '\u2208'); ENTITIES.put("nabla", '\u2207');
ENTITIES.put("notin", '\u2209'); ENTITIES.put("isin", '\u2208');
ENTITIES.put("ni", '\u220B'); ENTITIES.put("notin", '\u2209');
ENTITIES.put("prod", '\u220F'); ENTITIES.put("ni", '\u220B');
ENTITIES.put("sum", '\u2211'); ENTITIES.put("prod", '\u220F');
ENTITIES.put("minus", '\u2212'); ENTITIES.put("sum", '\u2211');
ENTITIES.put("lowast", '\u2217'); ENTITIES.put("minus", '\u2212');
ENTITIES.put("radic", '\u221A'); ENTITIES.put("lowast", '\u2217');
ENTITIES.put("prop", '\u221D'); ENTITIES.put("radic", '\u221A');
ENTITIES.put("infin", '\u221E'); ENTITIES.put("prop", '\u221D');
ENTITIES.put("ang", '\u2220'); ENTITIES.put("infin", '\u221E');
ENTITIES.put("and", '\u2227'); ENTITIES.put("ang", '\u2220');
ENTITIES.put("or", '\u2228'); ENTITIES.put("and", '\u2227');
ENTITIES.put("cap", '\u2229'); ENTITIES.put("or", '\u2228');
ENTITIES.put("cup", '\u222A'); ENTITIES.put("cap", '\u2229');
ENTITIES.put("'int'", '\u222B'); ENTITIES.put("cup", '\u222A');
ENTITIES.put("there4", '\u2234'); ENTITIES.put("'int'", '\u222B');
ENTITIES.put("sim", '\u223C'); ENTITIES.put("there4", '\u2234');
ENTITIES.put("cong", '\u2245'); ENTITIES.put("sim", '\u223C');
ENTITIES.put("asymp", '\u2248'); ENTITIES.put("cong", '\u2245');
ENTITIES.put("ne", '\u2260'); ENTITIES.put("asymp", '\u2248');
ENTITIES.put("equiv", '\u2261'); ENTITIES.put("ne", '\u2260');
ENTITIES.put("le", '\u2264'); ENTITIES.put("equiv", '\u2261');
ENTITIES.put("ge", '\u2265'); ENTITIES.put("le", '\u2264');
ENTITIES.put("sub", '\u2282'); ENTITIES.put("ge", '\u2265');
ENTITIES.put("sup", '\u2283'); ENTITIES.put("sub", '\u2282');
ENTITIES.put("nsub", '\u2284'); ENTITIES.put("sup", '\u2283');
ENTITIES.put("sube", '\u2286'); ENTITIES.put("nsub", '\u2284');
ENTITIES.put("supe", '\u2287'); ENTITIES.put("sube", '\u2286');
ENTITIES.put("oplus", '\u2295'); ENTITIES.put("supe", '\u2287');
ENTITIES.put("otimes", '\u2297'); ENTITIES.put("oplus", '\u2295');
ENTITIES.put("perp", '\u22A5'); ENTITIES.put("otimes", '\u2297');
ENTITIES.put("sdot", '\u22C5'); ENTITIES.put("perp", '\u22A5');
ENTITIES.put("lceil", '\u2308'); ENTITIES.put("sdot", '\u22C5');
ENTITIES.put("rceil", '\u2309'); ENTITIES.put("lceil", '\u2308');
ENTITIES.put("lfloor", '\u230A'); ENTITIES.put("rceil", '\u2309');
ENTITIES.put("rfloor", '\u230B'); ENTITIES.put("lfloor", '\u230A');
ENTITIES.put("lang", '\u2329'); ENTITIES.put("rfloor", '\u230B');
ENTITIES.put("rang", '\u232A'); ENTITIES.put("lang", '\u2329');
ENTITIES.put("loz", '\u25CA'); ENTITIES.put("rang", '\u232A');
ENTITIES.put("spades", '\u2660'); ENTITIES.put("loz", '\u25CA');
ENTITIES.put("clubs", '\u2663'); ENTITIES.put("spades", '\u2660');
ENTITIES.put("hearts", '\u2665'); ENTITIES.put("clubs", '\u2663');
ENTITIES.put("diams", '\u2666'); ENTITIES.put("hearts", '\u2665');
} ENTITIES.put("diams", '\u2666');
} }
}

View File

@@ -1,29 +1,30 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* An expression involving an operator and two operands; may be an * An expression involving an operator and two operands; may be an {@link AssignmentExpression}, a
* {@link AssignmentExpression}, a {@link BinaryExpression} or a {@link LogicalExpression}. * {@link BinaryExpression} or a {@link LogicalExpression}.
*/ */
public abstract class ABinaryExpression extends Expression { public abstract class ABinaryExpression extends Expression {
private final String operator; private final String operator;
private final Expression left, right; private final Expression left, right;
public ABinaryExpression(SourceLocation loc, String type, String operator, Expression left, Expression right) { public ABinaryExpression(
super(type, loc); SourceLocation loc, String type, String operator, Expression left, Expression right) {
this.operator = operator; super(type, loc);
this.left = left; this.operator = operator;
this.right = right; this.left = left;
} this.right = right;
}
public String getOperator() { public String getOperator() {
return operator; return operator;
} }
public Expression getLeft() { public Expression getLeft() {
return left; return left;
} }
public Expression getRight() { public Expression getRight() {
return right; return right;
} }
} }

View File

@@ -1,81 +1,82 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.ArrayList;
import java.util.List;
import com.semmle.ts.ast.INodeWithSymbol; import com.semmle.ts.ast.INodeWithSymbol;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.ArrayList;
import java.util.List;
/** /** Common backing class for {@linkplain ClassDeclaration} and {@linkplain ClassExpression}. */
* Common backing class for {@linkplain ClassDeclaration} and {@linkplain ClassExpression}.
*/
public class AClass implements INodeWithSymbol { public class AClass implements INodeWithSymbol {
private final Identifier id; private final Identifier id;
private final List<TypeParameter> typeParameters; private final List<TypeParameter> typeParameters;
private final Expression superClass; private final Expression superClass;
private final List<ITypeExpression> superInterfaces; private final List<ITypeExpression> superInterfaces;
private final ClassBody body; private final ClassBody body;
private final List<Decorator> decorators; private final List<Decorator> decorators;
private int typeSymbol = -1; private int typeSymbol = -1;
public AClass(Identifier id, List<TypeParameter> typeParameters, Expression superClass, List<ITypeExpression> superInterfaces, public AClass(
ClassBody body) { Identifier id,
this.id = id; List<TypeParameter> typeParameters,
this.typeParameters = typeParameters; Expression superClass,
this.superClass = superClass; List<ITypeExpression> superInterfaces,
this.superInterfaces = superInterfaces; ClassBody body) {
this.body = body; this.id = id;
this.decorators = new ArrayList<Decorator>(); this.typeParameters = typeParameters;
} this.superClass = superClass;
this.superInterfaces = superInterfaces;
this.body = body;
this.decorators = new ArrayList<Decorator>();
}
public Identifier getId() { public Identifier getId() {
return id; return id;
} }
public boolean hasId() { public boolean hasId() {
return id != null; return id != null;
} }
public List<TypeParameter> getTypeParameters() { public List<TypeParameter> getTypeParameters() {
return typeParameters; return typeParameters;
} }
public boolean hasTypeParameters() { public boolean hasTypeParameters() {
return !typeParameters.isEmpty(); return !typeParameters.isEmpty();
} }
public Expression getSuperClass() { public Expression getSuperClass() {
return superClass; return superClass;
} }
public boolean hasSuperClass() { public boolean hasSuperClass() {
return superClass != null; return superClass != null;
} }
public List<ITypeExpression> getSuperInterfaces() { public List<ITypeExpression> getSuperInterfaces() {
return superInterfaces; return superInterfaces;
} }
public ClassBody getBody() { public ClassBody getBody() {
return body; return body;
} }
public void addDecorators(List<Decorator> decorators) { public void addDecorators(List<Decorator> decorators) {
this.decorators.addAll(decorators); this.decorators.addAll(decorators);
} }
public List<Decorator> getDecorators() { public List<Decorator> getDecorators() {
return decorators; return decorators;
} }
@Override @Override
public int getSymbol() { public int getSymbol() {
return typeSymbol; return typeSymbol;
} }
@Override @Override
public void setSymbol(int symbol) { public void setSymbol(int symbol) {
this.typeSymbol = symbol; this.typeSymbol = symbol;
} }
} }

View File

@@ -1,144 +1,146 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.ArrayList;
import java.util.List;
import com.semmle.ts.ast.DecoratorList; import com.semmle.ts.ast.DecoratorList;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.ArrayList;
import java.util.List;
public class AFunction<B> { public class AFunction<B> {
private final Identifier id; private final Identifier id;
private final List<IPattern> params, allParams; private final List<IPattern> params, allParams;
private final List<Expression> rawParams, defaults; private final List<Expression> rawParams, defaults;
private final IPattern rest; private final IPattern rest;
private final B body; private final B body;
private final boolean generator, async; private final boolean generator, async;
private final List<TypeParameter> typeParameters; private final List<TypeParameter> typeParameters;
private final ITypeExpression returnType; private final ITypeExpression returnType;
private final List<ITypeExpression> parameterTypes; private final List<ITypeExpression> parameterTypes;
private final ITypeExpression thisParameterType; private final ITypeExpression thisParameterType;
private final List<DecoratorList> parameterDecorators; private final List<DecoratorList> parameterDecorators;
public AFunction(Identifier id, List<Expression> params, B body, boolean generator, boolean async, public AFunction(
List<TypeParameter> typeParameters, List<ITypeExpression> parameterTypes, List<DecoratorList> parameterDecorators, Identifier id,
ITypeExpression returnType, ITypeExpression thisParameterType) { List<Expression> params,
this.id = id; B body,
this.params = new ArrayList<IPattern>(params.size()); boolean generator,
this.defaults = new ArrayList<Expression>(params.size()); boolean async,
this.parameterTypes = parameterTypes; List<TypeParameter> typeParameters,
this.body = body; List<ITypeExpression> parameterTypes,
this.generator = generator; List<DecoratorList> parameterDecorators,
this.async = async; ITypeExpression returnType,
this.rawParams = params; ITypeExpression thisParameterType) {
this.typeParameters = typeParameters; this.id = id;
this.returnType = returnType; this.params = new ArrayList<IPattern>(params.size());
this.thisParameterType = thisParameterType; this.defaults = new ArrayList<Expression>(params.size());
this.parameterDecorators = parameterDecorators; this.parameterTypes = parameterTypes;
this.body = body;
this.generator = generator;
this.async = async;
this.rawParams = params;
this.typeParameters = typeParameters;
this.returnType = returnType;
this.thisParameterType = thisParameterType;
this.parameterDecorators = parameterDecorators;
IPattern rest = null; IPattern rest = null;
for (Expression param : params) { for (Expression param : params) {
if (param instanceof RestElement) { if (param instanceof RestElement) {
rest = (IPattern)((RestElement) param).getArgument(); rest = (IPattern) ((RestElement) param).getArgument();
} else if (param instanceof AssignmentPattern) { } else if (param instanceof AssignmentPattern) {
AssignmentPattern ap = (AssignmentPattern) param; AssignmentPattern ap = (AssignmentPattern) param;
this.params.add((IPattern)ap.getLeft()); this.params.add((IPattern) ap.getLeft());
this.defaults.add(ap.getRight()); this.defaults.add(ap.getRight());
} else { } else {
// workaround for parser bug, which currently (erroneously) accepts // workaround for parser bug, which currently (erroneously) accepts
// async arrow functions with parens around their parameters // async arrow functions with parens around their parameters
param = param.stripParens(); param = param.stripParens();
this.params.add((IPattern) param); this.params.add((IPattern) param);
this.defaults.add(null); this.defaults.add(null);
} }
} }
this.rest = rest; this.rest = rest;
this.allParams = new ArrayList<IPattern>(this.params); this.allParams = new ArrayList<IPattern>(this.params);
if (rest != null) if (rest != null) this.allParams.add(rest);
this.allParams.add(rest); }
}
/** /** Does this function have a name? */
* Does this function have a name? public boolean hasId() {
*/ return id != null;
public boolean hasId() { }
return id != null;
}
public Identifier getId() { public Identifier getId() {
return id; return id;
} }
public List<IPattern> getParams() { public List<IPattern> getParams() {
return params; return params;
} }
public boolean hasDefault(int i) { public boolean hasDefault(int i) {
return i < defaults.size(); return i < defaults.size();
} }
public Expression getDefault(int i) { public Expression getDefault(int i) {
if (i >= defaults.size()) if (i >= defaults.size()) return null;
return null; return defaults.get(i);
return defaults.get(i); }
}
public boolean hasRest() { public boolean hasRest() {
return rest != null; return rest != null;
} }
public IPattern getRest() { public IPattern getRest() {
return rest; return rest;
} }
public B getBody() { public B getBody() {
return body; return body;
} }
public boolean isGenerator() { public boolean isGenerator() {
return generator; return generator;
} }
public boolean isAsync() { public boolean isAsync() {
return async; return async;
} }
public List<IPattern> getAllParams() { public List<IPattern> getAllParams() {
return allParams; return allParams;
} }
public List<Expression> getRawParams() { public List<Expression> getRawParams() {
return rawParams; return rawParams;
} }
public ITypeExpression getReturnType() { public ITypeExpression getReturnType() {
return returnType; return returnType;
} }
public boolean hasParameterType(int i) { public boolean hasParameterType(int i) {
return getParameterType(i) != null; return getParameterType(i) != null;
} }
public ITypeExpression getParameterType(int i) { public ITypeExpression getParameterType(int i) {
if (i >= parameterTypes.size()) if (i >= parameterTypes.size()) return null;
return null; return parameterTypes.get(i);
return parameterTypes.get(i); }
}
public List<ITypeExpression> getParameterTypes() { public List<ITypeExpression> getParameterTypes() {
return parameterTypes; return parameterTypes;
} }
public List<TypeParameter> getTypeParameters() { public List<TypeParameter> getTypeParameters() {
return typeParameters; return typeParameters;
} }
public ITypeExpression getThisParameterType() { public ITypeExpression getThisParameterType() {
return thisParameterType; return thisParameterType;
} }
public List<DecoratorList> getParameterDecorators() { public List<DecoratorList> getParameterDecorators() {
return parameterDecorators; return parameterDecorators;
} }
} }

View File

@@ -1,65 +1,147 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.List;
import com.semmle.ts.ast.DecoratorList; import com.semmle.ts.ast.DecoratorList;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.List;
/** /**
* A function expression, which may be either an {@link ArrowFunctionExpression} or * A function expression, which may be either an {@link ArrowFunctionExpression} or a normal {@link
* a normal {@link FunctionExpression}. * FunctionExpression}.
*/ */
public abstract class AFunctionExpression extends Expression implements IFunction { public abstract class AFunctionExpression extends Expression implements IFunction {
private final AFunction<? extends Node> fn; private final AFunction<? extends Node> fn;
private int symbol = -1; private int symbol = -1;
public AFunctionExpression(String type, SourceLocation loc, Identifier id, public AFunctionExpression(
List<Expression> params, Node body, Boolean generator, Boolean async, String type,
List<TypeParameter> typeParameters, List<ITypeExpression> parameterTypes, List<DecoratorList> parameterDecorators, SourceLocation loc,
ITypeExpression returnType, ITypeExpression thisParameterType) { Identifier id,
super(type, loc); List<Expression> params,
this.fn = new AFunction<Node>(id, params, body, generator == Boolean.TRUE, async == Boolean.TRUE, typeParameters, parameterTypes, Node body,
parameterDecorators, returnType, thisParameterType); Boolean generator,
} Boolean async,
List<TypeParameter> typeParameters,
List<ITypeExpression> parameterTypes,
List<DecoratorList> parameterDecorators,
ITypeExpression returnType,
ITypeExpression thisParameterType) {
super(type, loc);
this.fn =
new AFunction<Node>(
id,
params,
body,
generator == Boolean.TRUE,
async == Boolean.TRUE,
typeParameters,
parameterTypes,
parameterDecorators,
returnType,
thisParameterType);
}
public AFunctionExpression(String type, SourceLocation loc, AFunction<? extends Node> fn) { public AFunctionExpression(String type, SourceLocation loc, AFunction<? extends Node> fn) {
super(type, loc); super(type, loc);
this.fn = fn; this.fn = fn;
} }
@Override public Identifier getId() { return fn.getId(); } @Override
@Override public List<IPattern> getParams() { return fn.getParams(); } public Identifier getId() {
@Override public boolean hasDefault(int i) { return fn.hasDefault(i); } return fn.getId();
@Override public Expression getDefault(int i) { return fn.getDefault(i); } }
@Override public IPattern getRest() { return fn.getRest(); }
@Override public Node getBody() { return fn.getBody(); }
@Override public boolean hasRest() { return fn.hasRest(); }
public boolean hasId() { return fn.hasId(); }
public boolean isGenerator() { return fn.isGenerator(); }
public boolean isAsync() { return fn.isAsync(); }
public List<IPattern> getAllParams() { return fn.getAllParams(); }
@Override public List<Expression> getRawParameters() { return fn.getRawParams(); }
public ITypeExpression getReturnType() { return fn.getReturnType(); }
public boolean hasParameterType(int i) { return fn.hasParameterType(i); }
public ITypeExpression getParameterType(int i) { return fn.getParameterType(i); }
public List<ITypeExpression> getParameterTypes() { return fn.getParameterTypes(); }
public List<TypeParameter> getTypeParameters() { return fn.getTypeParameters(); }
public ITypeExpression getThisParameterType() { return fn.getThisParameterType(); }
public List<DecoratorList> getParameterDecorators() { return fn.getParameterDecorators(); }
@Override @Override
public boolean hasDeclareKeyword() { public List<IPattern> getParams() {
return false; return fn.getParams();
} }
@Override @Override
public int getSymbol() { public boolean hasDefault(int i) {
return symbol; return fn.hasDefault(i);
} }
@Override @Override
public void setSymbol(int symbol) { public Expression getDefault(int i) {
this.symbol = symbol; return fn.getDefault(i);
} }
@Override
public IPattern getRest() {
return fn.getRest();
}
@Override
public Node getBody() {
return fn.getBody();
}
@Override
public boolean hasRest() {
return fn.hasRest();
}
public boolean hasId() {
return fn.hasId();
}
public boolean isGenerator() {
return fn.isGenerator();
}
public boolean isAsync() {
return fn.isAsync();
}
public List<IPattern> getAllParams() {
return fn.getAllParams();
}
@Override
public List<Expression> getRawParameters() {
return fn.getRawParams();
}
public ITypeExpression getReturnType() {
return fn.getReturnType();
}
public boolean hasParameterType(int i) {
return fn.hasParameterType(i);
}
public ITypeExpression getParameterType(int i) {
return fn.getParameterType(i);
}
public List<ITypeExpression> getParameterTypes() {
return fn.getParameterTypes();
}
public List<TypeParameter> getTypeParameters() {
return fn.getTypeParameters();
}
public ITypeExpression getThisParameterType() {
return fn.getThisParameterType();
}
public List<DecoratorList> getParameterDecorators() {
return fn.getParameterDecorators();
}
@Override
public boolean hasDeclareKeyword() {
return false;
}
@Override
public int getSymbol() {
return symbol;
}
@Override
public void setSymbol(int symbol) {
this.symbol = symbol;
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -2,26 +2,22 @@ package com.semmle.js.ast;
import java.util.List; import java.util.List;
/** /** An array expression such as <code>[x, , "hello"]</code>. */
* An array expression such as <code>[x, , "hello"]</code>.
*/
public class ArrayExpression extends Expression { public class ArrayExpression extends Expression {
private final List<Expression> elements; private final List<Expression> elements;
public ArrayExpression(SourceLocation loc, List<Expression> elements) { public ArrayExpression(SourceLocation loc, List<Expression> elements) {
super("ArrayExpression", loc); super("ArrayExpression", loc);
this.elements = elements; this.elements = elements;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The elements of the array; omitted elements are represented by {@literal null}. */
* The elements of the array; omitted elements are represented by {@literal null}. public List<Expression> getElements() {
*/ return elements;
public List<Expression> getElements() { }
return elements;
}
} }

View File

@@ -3,76 +3,68 @@ package com.semmle.js.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /** An array pattern as in <code>var [x, y] = z;</code>. */
* An array pattern as in <code>var [x, y] = z;</code>.
*/
public class ArrayPattern extends Expression implements DestructuringPattern { public class ArrayPattern extends Expression implements DestructuringPattern {
private final List<Expression> elements, rawElements; private final List<Expression> elements, rawElements;
private final List<Expression> defaults; private final List<Expression> defaults;
private final Expression restPattern; private final Expression restPattern;
public ArrayPattern(SourceLocation loc, List<Expression> elements) { public ArrayPattern(SourceLocation loc, List<Expression> elements) {
super("ArrayPattern", loc); super("ArrayPattern", loc);
this.rawElements = elements; this.rawElements = elements;
this.elements = new ArrayList<Expression>(elements.size()); this.elements = new ArrayList<Expression>(elements.size());
this.defaults = new ArrayList<Expression>(elements.size()); this.defaults = new ArrayList<Expression>(elements.size());
Expression rest = null; Expression rest = null;
for (Expression element : elements) { for (Expression element : elements) {
if (element instanceof RestElement) { if (element instanceof RestElement) {
rest = ((RestElement)element).getArgument(); rest = ((RestElement) element).getArgument();
} else { } else {
if (element instanceof AssignmentPattern) { if (element instanceof AssignmentPattern) {
AssignmentPattern assgn = (AssignmentPattern) element; AssignmentPattern assgn = (AssignmentPattern) element;
this.defaults.add(assgn.getRight()); this.defaults.add(assgn.getRight());
this.elements.add(assgn.getLeft()); this.elements.add(assgn.getLeft());
} else { } else {
this.defaults.add(null); this.defaults.add(null);
this.elements.add(element); this.elements.add(element);
} }
} }
} }
this.restPattern = rest; this.restPattern = rest;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /**
* The element patterns of the array pattern; omitted element patterns are * The element patterns of the array pattern; omitted element patterns are represented by
* represented by {@literal null}. * {@literal null}.
*/ */
public List<Expression> getElements() { public List<Expression> getElements() {
return elements; return elements;
} }
/** /** The default expressions for the element patterns of the array pattern. */
* The default expressions for the element patterns of the array pattern. public List<Expression> getDefaults() {
*/ return defaults;
public List<Expression> getDefaults() { }
return defaults;
}
/** /** Return the rest pattern of this array pattern, if any. */
* Return the rest pattern of this array pattern, if any. public Expression getRest() {
*/ return restPattern;
public Expression getRest() { }
return restPattern;
}
/** /** Does this array pattern have a rest pattern? */
* Does this array pattern have a rest pattern? public boolean hasRest() {
*/ return restPattern != null;
public boolean hasRest() { }
return restPattern != null;
}
/** /**
* The raw element patterns of the array pattern; patterns with defaults * The raw element patterns of the array pattern; patterns with defaults are represented as {@link
* are represented as {@link AssignmentPattern}s. * AssignmentPattern}s.
*/ */
public List<Expression> getRawElements() { public List<Expression> getRawElements() {
return rawElements; return rawElements;
} }
} }

View File

@@ -1,30 +1,55 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.Collections;
import java.util.List;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.Collections;
import java.util.List;
/** /** An arrow function expression such as <code>(x) =&gt; x*x</code>. */
* An arrow function expression such as <code>(x) =&gt; x*x</code>.
*/
public class ArrowFunctionExpression extends AFunctionExpression { public class ArrowFunctionExpression extends AFunctionExpression {
public ArrowFunctionExpression(SourceLocation loc, public ArrowFunctionExpression(
List<Expression> params, Node body, Boolean generator, Boolean async) { SourceLocation loc, List<Expression> params, Node body, Boolean generator, Boolean async) {
super("ArrowFunctionExpression", loc, null, params, body, generator, async, Collections.emptyList(), Collections.emptyList(), super(
Collections.emptyList(), null, null); "ArrowFunctionExpression",
} loc,
null,
params,
body,
generator,
async,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
null,
null);
}
public ArrowFunctionExpression(SourceLocation loc, public ArrowFunctionExpression(
List<Expression> params, Node body, Boolean generator, Boolean async, SourceLocation loc,
List<TypeParameter> typeParameters, List<ITypeExpression> parameterTypes, ITypeExpression returnType) { List<Expression> params,
super("ArrowFunctionExpression", loc, null, params, body, generator, async, typeParameters, parameterTypes, Collections.emptyList(), Node body,
returnType, null); Boolean generator,
} Boolean async,
List<TypeParameter> typeParameters,
List<ITypeExpression> parameterTypes,
ITypeExpression returnType) {
super(
"ArrowFunctionExpression",
loc,
null,
params,
body,
generator,
async,
typeParameters,
parameterTypes,
Collections.emptyList(),
returnType,
null);
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,15 +1,14 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** An assignment expression such as <code>x = 23</code> or <code>y += 19</code>. */
* An assignment expression such as <code>x = 23</code> or <code>y += 19</code>.
*/
public class AssignmentExpression extends ABinaryExpression { public class AssignmentExpression extends ABinaryExpression {
public AssignmentExpression(SourceLocation loc, String operator, Expression left, Expression right) { public AssignmentExpression(
super(loc, "AssignmentExpression", operator, left, right); SourceLocation loc, String operator, Expression left, Expression right) {
} super(loc, "AssignmentExpression", operator, left, right);
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,21 +1,20 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* An assignment pattern occurring in an lvalue position. * An assignment pattern occurring in an lvalue position.
* *
* Assignment patterns specify default values for function parameters, for-in/for-of loop variables and * <p>Assignment patterns specify default values for function parameters, for-in/for-of loop
* in destructuring assignments. We normalise them away during AST construction, attaching information * variables and in destructuring assignments. We normalise them away during AST construction,
* about the default value directly to the parameter or variable in question. Hence, assignment patterns * attaching information about the default value directly to the parameter or variable in question.
* are not expected to appear in the AST the extractor works on. * Hence, assignment patterns are not expected to appear in the AST the extractor works on.
*/ */
public class AssignmentPattern extends ABinaryExpression implements IPattern { public class AssignmentPattern extends ABinaryExpression implements IPattern {
public AssignmentPattern(SourceLocation loc, String operator, Expression left, Expression right) { public AssignmentPattern(SourceLocation loc, String operator, Expression left, Expression right) {
super(loc, "AssignmentPattern", operator, left, right); super(loc, "AssignmentPattern", operator, left, right);
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,20 +1,19 @@
package com.semmle.js.ast; package com.semmle.js.ast;
public class AwaitExpression extends Expression { public class AwaitExpression extends Expression {
private Expression argument; private Expression argument;
public AwaitExpression(SourceLocation loc, Expression argument) { public AwaitExpression(SourceLocation loc, Expression argument) {
super("AwaitExpression", loc); super("AwaitExpression", loc);
this.argument = argument; this.argument = argument;
} }
public Expression getArgument() { public Expression getArgument() {
return argument; return argument;
} }
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
} }

View File

@@ -1,15 +1,13 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A binary expression such as <code>x + y</code>. */
* A binary expression such as <code>x + y</code>.
*/
public class BinaryExpression extends ABinaryExpression { public class BinaryExpression extends ABinaryExpression {
public BinaryExpression(SourceLocation loc, String operator, Expression left, Expression right) { public BinaryExpression(SourceLocation loc, String operator, Expression left, Expression right) {
super(loc, "BinaryExpression", operator, left, right); super(loc, "BinaryExpression", operator, left, right);
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,28 +1,28 @@
package com.semmle.js.ast; package com.semmle.js.ast;
public class BindExpression extends Expression { public class BindExpression extends Expression {
private final Expression object, callee; private final Expression object, callee;
public BindExpression(SourceLocation loc, Expression object, Expression callee) { public BindExpression(SourceLocation loc, Expression object, Expression callee) {
super("BindExpression", loc); super("BindExpression", loc);
this.object = object; this.object = object;
this.callee = callee; this.callee = callee;
} }
public boolean hasObject() { public boolean hasObject() {
return object != null; return object != null;
} }
public Expression getObject() { public Expression getObject() {
return object; return object;
} }
public Expression getCallee() { public Expression getCallee() {
return callee; return callee;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -2,26 +2,22 @@ package com.semmle.js.ast;
import java.util.List; import java.util.List;
/** /** A block statement such as <code>{ console.log("Hi"); }</code>. */
* A block statement such as <code>{ console.log("Hi"); }</code>.
*/
public class BlockStatement extends Statement { public class BlockStatement extends Statement {
private final List<Statement> body; private final List<Statement> body;
public BlockStatement(SourceLocation loc, List<Statement> body) { public BlockStatement(SourceLocation loc, List<Statement> body) {
super("BlockStatement", loc); super("BlockStatement", loc);
this.body = body; this.body = body;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The statements in the block. */
* The statements in the block. public List<Statement> getBody() {
*/ return body;
public List<Statement> getBody() { }
return body;
}
} }

View File

@@ -1,15 +1,16 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* A break statement either with a label (<code>break outer;</code>) or without (<code>break;</code>). * A break statement either with a label (<code>break outer;</code>) or without (<code>break;</code>
* ).
*/ */
public class BreakStatement extends JumpStatement { public class BreakStatement extends JumpStatement {
public BreakStatement(SourceLocation loc, Identifier label) { public BreakStatement(SourceLocation loc, Identifier label) {
super("BreakStatement", loc, label); super("BreakStatement", loc, label);
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,19 +1,22 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import com.semmle.ts.ast.ITypeExpression;
import java.util.List; import java.util.List;
import com.semmle.ts.ast.ITypeExpression; /** A function call expression such as <code>f(1, 1)</code>. */
/**
* A function call expression such as <code>f(1, 1)</code>.
*/
public class CallExpression extends InvokeExpression { public class CallExpression extends InvokeExpression {
public CallExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments, Boolean optional, Boolean onOptionalChain) { public CallExpression(
super("CallExpression", loc, callee, typeArguments, arguments, optional, onOptionalChain); SourceLocation loc,
} Expression callee,
List<ITypeExpression> typeArguments,
List<Expression> arguments,
Boolean optional,
Boolean onOptionalChain) {
super("CallExpression", loc, callee, typeArguments, arguments, optional, onOptionalChain);
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,50 +1,40 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A catch clause with or without a guarding expression. */
* A catch clause with or without a guarding expression.
*/
public class CatchClause extends Statement { public class CatchClause extends Statement {
private final IPattern param; private final IPattern param;
private final Expression guard; private final Expression guard;
private final BlockStatement body; private final BlockStatement body;
public CatchClause(SourceLocation loc, IPattern param, Expression guard, BlockStatement body) { public CatchClause(SourceLocation loc, IPattern param, Expression guard, BlockStatement body) {
super("CatchClause", loc); super("CatchClause", loc);
this.param = param; this.param = param;
this.guard = guard; this.guard = guard;
this.body = body; this.body = body;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The parameter of the catch clause. */
* The parameter of the catch clause. public IPattern getParam() {
*/ return param;
public IPattern getParam() { }
return param;
}
/** /** Does this catch clause have a guarding expression? */
* Does this catch clause have a guarding expression? public boolean hasGuard() {
*/ return guard != null;
public boolean hasGuard() { }
return guard != null;
}
/** /** The guarding expression of the catch clause; may be null. */
* The guarding expression of the catch clause; may be null. public Expression getGuard() {
*/ return guard;
public Expression getGuard() { }
return guard;
}
/** /** The body of the catch clause. */
* The body of the catch clause. public BlockStatement getBody() {
*/ return body;
public BlockStatement getBody() { }
return body;
}
} }

View File

@@ -1,16 +1,10 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A chainable expression, such as a member access or function call. */
* A chainable expression, such as a member access or function call.
*/
public interface Chainable { public interface Chainable {
/** /** Is this step of the chain optional? */
* Is this step of the chain optional? abstract boolean isOptional();
*/
abstract boolean isOptional();
/** /** Is this on an optional chain? */
* Is this on an optional chain? abstract boolean isOnOptionalChain();
*/
abstract boolean isOnOptionalChain();
} }

View File

@@ -2,35 +2,30 @@ package com.semmle.js.ast;
import java.util.List; import java.util.List;
/** /** The body of a {@linkplain ClassDeclaration} or {@linkplain ClassExpression}. */
* The body of a {@linkplain ClassDeclaration} or {@linkplain ClassExpression}.
*/
public class ClassBody extends Node { public class ClassBody extends Node {
private final List<MemberDefinition<?>> body; private final List<MemberDefinition<?>> body;
public ClassBody(SourceLocation loc, List<MemberDefinition<?>> body) { public ClassBody(SourceLocation loc, List<MemberDefinition<?>> body) {
super("ClassBody", loc); super("ClassBody", loc);
this.body = body; this.body = body;
} }
public List<MemberDefinition<?>> getBody() { public List<MemberDefinition<?>> getBody() {
return body; return body;
} }
public void addMember(MemberDefinition<?> md) { public void addMember(MemberDefinition<?> md) {
body.add(md); body.add(md);
} }
public MethodDefinition getConstructor() { public MethodDefinition getConstructor() {
for (MemberDefinition<?> md : body) for (MemberDefinition<?> md : body) if (md.isConstructor()) return (MethodDefinition) md;
if (md.isConstructor()) return null;
return (MethodDefinition) md; }
return null;
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
@Override
public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c);
}
} }

View File

@@ -1,10 +1,9 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.Collections;
import java.util.List;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.Collections;
import java.util.List;
/** /**
* A class declaration such as * A class declaration such as
@@ -19,48 +18,61 @@ import com.semmle.ts.ast.TypeParameter;
* </pre> * </pre>
*/ */
public class ClassDeclaration extends Statement { public class ClassDeclaration extends Statement {
private final AClass klass; private final AClass klass;
private final boolean hasDeclareKeyword; private final boolean hasDeclareKeyword;
private final boolean hasAbstractKeyword; private final boolean hasAbstractKeyword;
public ClassDeclaration(SourceLocation loc, Identifier id, Expression superClass, ClassBody body) { public ClassDeclaration(
this(loc, id, Collections.emptyList(), superClass, Collections.emptyList(), body, false, false); SourceLocation loc, Identifier id, Expression superClass, ClassBody body) {
} this(loc, id, Collections.emptyList(), superClass, Collections.emptyList(), body, false, false);
}
public ClassDeclaration(SourceLocation loc, Identifier id, List<TypeParameter> typeParameters, Expression superClass, public ClassDeclaration(
List<ITypeExpression> superInterfaces, ClassBody body, boolean hasDeclareKeyword, boolean hasAbstractKeyword) { SourceLocation loc,
this(loc, new AClass(id, typeParameters, superClass, superInterfaces, body), hasDeclareKeyword, hasAbstractKeyword); Identifier id,
} List<TypeParameter> typeParameters,
Expression superClass,
List<ITypeExpression> superInterfaces,
ClassBody body,
boolean hasDeclareKeyword,
boolean hasAbstractKeyword) {
this(
loc,
new AClass(id, typeParameters, superClass, superInterfaces, body),
hasDeclareKeyword,
hasAbstractKeyword);
}
public ClassDeclaration(SourceLocation loc, AClass klass, boolean hasDeclareKeyword, boolean hasAbstractKeyword) { public ClassDeclaration(
super("ClassDeclaration", loc); SourceLocation loc, AClass klass, boolean hasDeclareKeyword, boolean hasAbstractKeyword) {
this.klass = klass; super("ClassDeclaration", loc);
this.hasDeclareKeyword = hasDeclareKeyword; this.klass = klass;
this.hasAbstractKeyword = hasAbstractKeyword; this.hasDeclareKeyword = hasDeclareKeyword;
} this.hasAbstractKeyword = hasAbstractKeyword;
}
public AClass getClassDef() { public AClass getClassDef() {
return klass; return klass;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
public void addDecorators(List<Decorator> decorators) { public void addDecorators(List<Decorator> decorators) {
klass.addDecorators(decorators); klass.addDecorators(decorators);
} }
public List<Decorator> getDecorators() { public List<Decorator> getDecorators() {
return klass.getDecorators(); return klass.getDecorators();
} }
public boolean hasDeclareKeyword() { public boolean hasDeclareKeyword() {
return hasDeclareKeyword; return hasDeclareKeyword;
} }
public boolean hasAbstractKeyword() { public boolean hasAbstractKeyword() {
return hasAbstractKeyword; return hasAbstractKeyword;
} }
} }

View File

@@ -1,10 +1,9 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.Collections;
import java.util.List;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.Collections;
import java.util.List;
/** /**
* A class expression as in * A class expression as in
@@ -19,36 +18,41 @@ import com.semmle.ts.ast.TypeParameter;
* </pre> * </pre>
*/ */
public class ClassExpression extends Expression { public class ClassExpression extends Expression {
private final AClass klass; private final AClass klass;
public ClassExpression(SourceLocation loc, Identifier id, Expression superClass, ClassBody body) { public ClassExpression(SourceLocation loc, Identifier id, Expression superClass, ClassBody body) {
this(loc, id, Collections.emptyList(), superClass, Collections.emptyList(), body); this(loc, id, Collections.emptyList(), superClass, Collections.emptyList(), body);
} }
public ClassExpression(SourceLocation loc, Identifier id, List<TypeParameter> typeParameters, Expression superClass, public ClassExpression(
List<ITypeExpression> superInterfaces, ClassBody body) { SourceLocation loc,
this(loc, new AClass(id, typeParameters, superClass, superInterfaces, body)); Identifier id,
} List<TypeParameter> typeParameters,
Expression superClass,
List<ITypeExpression> superInterfaces,
ClassBody body) {
this(loc, new AClass(id, typeParameters, superClass, superInterfaces, body));
}
public ClassExpression(SourceLocation loc, AClass klass) { public ClassExpression(SourceLocation loc, AClass klass) {
super("ClassExpression", loc); super("ClassExpression", loc);
this.klass = klass; this.klass = klass;
} }
public AClass getClassDef() { public AClass getClassDef() {
return klass; return klass;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
public void addDecorators(List<Decorator> decorators) { public void addDecorators(List<Decorator> decorators) {
klass.addDecorators(decorators); klass.addDecorators(decorators);
} }
public Iterable<Decorator> getDecorators() { public Iterable<Decorator> getDecorators() {
return klass.getDecorators(); return klass.getDecorators();
} }
} }

View File

@@ -8,71 +8,53 @@ import static com.semmle.js.ast.Comment.Kind.LINE;
/** /**
* A source code comment. * A source code comment.
* *
* This is not part of the SpiderMonkey AST format. * <p>This is not part of the SpiderMonkey AST format.
*/ */
public class Comment extends SourceElement { public class Comment extends SourceElement {
/** /** The kinds of comments recognized by the parser. */
* The kinds of comments recognized by the parser. public static enum Kind {
*/ /** A C++-style line comment starting with two slashes. */
public static enum Kind { LINE,
/**
* A C++-style line comment starting with two slashes.
*/
LINE,
/** /** A C-style block comment starting with slash-star and ending with star-slash. */
* A C-style block comment starting with slash-star and ending with star-slash. BLOCK,
*/
BLOCK,
/** /** The start of an HTML comment (<code>&lt;!--</code>). */
* The start of an HTML comment (<code>&lt;!--</code>). HTML_START,
*/
HTML_START,
/** /** The end of an HTML comment (<code>--&gt;</code>). */
* The end of an HTML comment (<code>--&gt;</code>). HTML_END
*/ };
HTML_END
};
private final String text; private final String text;
private final Kind kind; private final Kind kind;
public Comment(SourceLocation loc, String text) { public Comment(SourceLocation loc, String text) {
super(loc); super(loc);
this.text = text; this.text = text;
String raw = getLoc().getSource(); String raw = getLoc().getSource();
if (raw.startsWith("//")) if (raw.startsWith("//")) this.kind = LINE;
this.kind = LINE; else if (raw.startsWith("/*")) this.kind = BLOCK;
else if (raw.startsWith("/*")) else if (raw.startsWith("<!--")) this.kind = HTML_START;
this.kind = BLOCK; else this.kind = HTML_END;
else if (raw.startsWith("<!--")) }
this.kind = HTML_START;
else
this.kind = HTML_END;
}
/** /** What kind of comment is this? */
* What kind of comment is this? public Kind getKind() {
*/ return kind;
public Kind getKind() { }
return kind;
}
/** /** Is this a JSDoc documentation comment? */
* Is this a JSDoc documentation comment? public boolean isDocComment() {
*/ return kind == BLOCK && text.startsWith("*");
public boolean isDocComment() { }
return kind == BLOCK && text.startsWith("*");
}
/** /**
* The text of the comment, not including its delimiters. * The text of the comment, not including its delimiters.
* *
* For documentation comments, the leading asterisk is included. * <p>For documentation comments, the leading asterisk is included.
*/ */
public String getText() { public String getText() {
return text; return text;
} }
} }

View File

@@ -1,43 +1,35 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A block in a comprehension expression. */
* A block in a comprehension expression.
*/
public class ComprehensionBlock extends Expression { public class ComprehensionBlock extends Expression {
private final IPattern left; private final IPattern left;
private final Expression right; private final Expression right;
private final boolean of; private final boolean of;
public ComprehensionBlock(SourceLocation loc, IPattern left, Expression right, Boolean of) { public ComprehensionBlock(SourceLocation loc, IPattern left, Expression right, Boolean of) {
super("ComprehensionBlock", loc); super("ComprehensionBlock", loc);
this.left = left; this.left = left;
this.right = right; this.right = right;
this.of = of != Boolean.FALSE; this.of = of != Boolean.FALSE;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The iterator variable of this comprehension block. */
* The iterator variable of this comprehension block. public IPattern getLeft() {
*/ return left;
public IPattern getLeft() { }
return left;
}
/** /** The expression this comprehension block iterates over. */
* The expression this comprehension block iterates over. public Expression getRight() {
*/ return right;
public Expression getRight() { }
return right;
}
/** /** Is this a <code>for-of</code> comprehension block? */
* Is this a <code>for-of</code> comprehension block? public boolean isOf() {
*/ return of;
public boolean isOf() { }
return of;
}
} }

View File

@@ -2,60 +2,53 @@ package com.semmle.js.ast;
import java.util.List; import java.util.List;
/** /** A comprehension expression. */
* A comprehension expression.
*/
public class ComprehensionExpression extends Expression { public class ComprehensionExpression extends Expression {
private final Expression body; private final Expression body;
private final List<ComprehensionBlock> blocks; private final List<ComprehensionBlock> blocks;
private final Expression filter; private final Expression filter;
private final boolean generator; private final boolean generator;
public ComprehensionExpression(SourceLocation loc, Expression body, List<ComprehensionBlock> blocks, Expression filter, Boolean generator) { public ComprehensionExpression(
super("ComprehensionExpression", loc); SourceLocation loc,
this.body = body; Expression body,
this.blocks = blocks; List<ComprehensionBlock> blocks,
this.filter = filter; Expression filter,
this.generator = generator == Boolean.TRUE; Boolean generator) {
} super("ComprehensionExpression", loc);
this.body = body;
this.blocks = blocks;
this.filter = filter;
this.generator = generator == Boolean.TRUE;
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The body expression of this comprehension. */
* The body expression of this comprehension. public Expression getBody() {
*/ return body;
public Expression getBody() { }
return body;
}
/** /** The comprehension blocks of this comprehension. */
* The comprehension blocks of this comprehension. public List<ComprehensionBlock> getBlocks() {
*/ return blocks;
public List<ComprehensionBlock> getBlocks() { }
return blocks;
}
/** /** Does this comprehension expression have a filter expression? */
* Does this comprehension expression have a filter expression? public boolean hasFilter() {
*/ return filter != null;
public boolean hasFilter() { }
return filter != null;
}
/** /** The filter expression of this comprehension; may be null. */
* The filter expression of this comprehension; may be null. public Expression getFilter() {
*/ return filter;
public Expression getFilter() { }
return filter;
}
/** /** Is this a generator expression? */
* Is this a generator expression? public boolean isGenerator() {
*/ return generator;
public boolean isGenerator() { }
return generator;
}
} }

View File

@@ -1,42 +1,35 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A conditional expression such as <code>i &gt;= 0 ? a[i] : null</code>. */
* A conditional expression such as <code>i &gt;= 0 ? a[i] : null</code>.
*/
public class ConditionalExpression extends Expression { public class ConditionalExpression extends Expression {
private final Expression test; private final Expression test;
private final Expression consequent, alternate; private final Expression consequent, alternate;
public ConditionalExpression(SourceLocation loc, Expression test, Expression consequent, Expression alternate) { public ConditionalExpression(
super("ConditionalExpression", loc); SourceLocation loc, Expression test, Expression consequent, Expression alternate) {
this.test = test; super("ConditionalExpression", loc);
this.consequent = consequent; this.test = test;
this.alternate = alternate; this.consequent = consequent;
} this.alternate = alternate;
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The test expression of this conditional expression. */
* The test expression of this conditional expression. public Expression getTest() {
*/ return test;
public Expression getTest() { }
return test;
}
/** /** The then-branch of this conditional expression. */
* The then-branch of this conditional expression. public Expression getConsequent() {
*/ return consequent;
public Expression getConsequent() { }
return consequent;
}
/** /** The else-branch of this conditional expression. */
* The else-branch of this conditional expression. public Expression getAlternate() {
*/ return alternate;
public Expression getAlternate() { }
return alternate;
}
} }

View File

@@ -1,15 +1,16 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* A continue statement either with a label (<code>continue outer;</code>) or without (<code>continue;</code>). * A continue statement either with a label (<code>continue outer;</code>) or without (<code>
* continue;</code>).
*/ */
public class ContinueStatement extends JumpStatement { public class ContinueStatement extends JumpStatement {
public ContinueStatement(SourceLocation loc, Identifier label) { public ContinueStatement(SourceLocation loc, Identifier label) {
super("ContinueStatement", loc, label); super("ContinueStatement", loc, label);
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,15 +1,13 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A debugger statement <code>debugger;</code>. */
* A debugger statement <code>debugger;</code>.
*/
public class DebuggerStatement extends Statement { public class DebuggerStatement extends Statement {
public DebuggerStatement(SourceLocation loc) { public DebuggerStatement(SourceLocation loc) {
super("DebuggerStatement", loc); super("DebuggerStatement", loc);
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -4,125 +4,145 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* Defines bitmasks where each bit corresponds to a flag on * Defines bitmasks where each bit corresponds to a flag on {@linkplain MemberDefinition} or
* {@linkplain MemberDefinition} or {@linkplain VariableDeclarator}. * {@linkplain VariableDeclarator}.
*/ */
public class DeclarationFlags { public class DeclarationFlags {
public static final int computed = 1 << 0; public static final int computed = 1 << 0;
public static final int abstract_ = 1 << 1; public static final int abstract_ = 1 << 1;
public static final int static_ = 1 << 2; public static final int static_ = 1 << 2;
public static final int readonly = 1 << 3; public static final int readonly = 1 << 3;
public static final int public_ = 1 << 4; public static final int public_ = 1 << 4;
public static final int private_ = 1 << 5; public static final int private_ = 1 << 5;
public static final int protected_ = 1 << 6; public static final int protected_ = 1 << 6;
public static final int optional = 1 << 7; public static final int optional = 1 << 7;
public static final int definiteAssignmentAssertion = 1 << 8; public static final int definiteAssignmentAssertion = 1 << 8;
public static final int none = 0; public static final int none = 0;
public static final int numberOfFlags = 9; public static final int numberOfFlags = 9;
public static final List<String> names = Arrays.asList("computed", "abstract", "static", "readonly", "public", "private", "protected", public static final List<String> names =
"optional", "definiteAssignmentAssertion"); Arrays.asList(
"computed",
"abstract",
"static",
"readonly",
"public",
"private",
"protected",
"optional",
"definiteAssignmentAssertion");
public static final List<String> relationNames = Arrays.asList("isComputed", "isAbstractMember", "isStatic", "hasReadonlyKeyword", public static final List<String> relationNames =
"hasPublicKeyword", "hasPrivateKeyword", "hasProtectedKeyword", "isOptionalMember", "hasDefiniteAssignmentAssertion"); Arrays.asList(
"isComputed",
"isAbstractMember",
"isStatic",
"hasReadonlyKeyword",
"hasPublicKeyword",
"hasPrivateKeyword",
"hasProtectedKeyword",
"isOptionalMember",
"hasDefiniteAssignmentAssertion");
public static boolean isComputed(int flags) { public static boolean isComputed(int flags) {
return (flags & computed) != 0; return (flags & computed) != 0;
} }
public static boolean isAbstract(int flags) { public static boolean isAbstract(int flags) {
return (flags & abstract_) != 0; return (flags & abstract_) != 0;
} }
public static boolean isStatic(int flags) { public static boolean isStatic(int flags) {
return (flags & static_) != 0; return (flags & static_) != 0;
} }
public static boolean isReadonly(int flags) { public static boolean isReadonly(int flags) {
return (flags & readonly) != 0; return (flags & readonly) != 0;
} }
public static boolean isPublic(int flags) { public static boolean isPublic(int flags) {
return (flags & public_) != 0; return (flags & public_) != 0;
} }
public static boolean isPrivate(int flags) { public static boolean isPrivate(int flags) {
return (flags & private_) != 0; return (flags & private_) != 0;
} }
public static boolean isProtected(int flags) { public static boolean isProtected(int flags) {
return (flags & protected_) != 0; return (flags & protected_) != 0;
} }
public static boolean isOptional(int flags) { public static boolean isOptional(int flags) {
return (flags & optional) != 0; return (flags & optional) != 0;
} }
public static boolean hasDefiniteAssignmentAssertion(int flags) { public static boolean hasDefiniteAssignmentAssertion(int flags) {
return (flags & definiteAssignmentAssertion) != 0; return (flags & definiteAssignmentAssertion) != 0;
} }
/** Returns a mask with the computed bit set to the value of <tt>enable</tt>. */ /** Returns a mask with the computed bit set to the value of <tt>enable</tt>. */
public static int getComputed(boolean enable) { public static int getComputed(boolean enable) {
return enable ? computed : 0; return enable ? computed : 0;
} }
/** Returns a mask with the abstract bit set to the value of <tt>enable</tt>. */ /** Returns a mask with the abstract bit set to the value of <tt>enable</tt>. */
public static int getAbstract(boolean enable) { public static int getAbstract(boolean enable) {
return enable ? abstract_ : 0; return enable ? abstract_ : 0;
} }
/** Returns a mask with the static bit set to the value of <tt>enable</tt>. */ /** Returns a mask with the static bit set to the value of <tt>enable</tt>. */
public static int getStatic(boolean enable) { public static int getStatic(boolean enable) {
return enable ? static_ : 0; return enable ? static_ : 0;
} }
/** Returns a mask with the public bit set to the value of <tt>enable</tt>. */ /** Returns a mask with the public bit set to the value of <tt>enable</tt>. */
public static int getPublic(boolean enable) { public static int getPublic(boolean enable) {
return enable ? public_ : 0; return enable ? public_ : 0;
} }
/** Returns a mask with the readonly bit set to the value of <tt>enable</tt>. */ /** Returns a mask with the readonly bit set to the value of <tt>enable</tt>. */
public static int getReadonly(boolean enable) { public static int getReadonly(boolean enable) {
return enable ? readonly : 0; return enable ? readonly : 0;
} }
/** Returns a mask with the private bit set to the value of <tt>enable</tt>. */ /** Returns a mask with the private bit set to the value of <tt>enable</tt>. */
public static int getPrivate(boolean enable) { public static int getPrivate(boolean enable) {
return enable ? private_ : 0; return enable ? private_ : 0;
} }
/** Returns a mask with the protected bit set to the value of <tt>enable</tt>. */ /** Returns a mask with the protected bit set to the value of <tt>enable</tt>. */
public static int getProtected(boolean enable) { public static int getProtected(boolean enable) {
return enable ? protected_ : 0; return enable ? protected_ : 0;
} }
/** Returns a mask with the optional bit set to the value of <tt>enable</tt>. */ /** Returns a mask with the optional bit set to the value of <tt>enable</tt>. */
public static int getOptional(boolean enable) { public static int getOptional(boolean enable) {
return enable ? optional : 0; return enable ? optional : 0;
} }
/** Returns a mask with the definite assignment assertion bit set to the value of <tt>enable</tt>. */ /**
public static int getDefiniteAssignmentAssertion(boolean enable) { * Returns a mask with the definite assignment assertion bit set to the value of <tt>enable</tt>.
return enable ? definiteAssignmentAssertion : 0; */
} public static int getDefiniteAssignmentAssertion(boolean enable) {
return enable ? definiteAssignmentAssertion : 0;
}
/** Returns true if the <tt>n</tt>th bit is set in <tt>flags</tt>. */ /** Returns true if the <tt>n</tt>th bit is set in <tt>flags</tt>. */
public static boolean hasNthFlag(int flags, int n) { public static boolean hasNthFlag(int flags, int n) {
return (flags & (1 << n)) != 0; return (flags & (1 << n)) != 0;
} }
public static String getFlagNames(int flags) { public static String getFlagNames(int flags) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
for (int i = 0; i < numberOfFlags; ++i) { for (int i = 0; i < numberOfFlags; ++i) {
if (hasNthFlag(flags, i)) { if (hasNthFlag(flags, i)) {
if (b.length() > 0) { if (b.length() > 0) {
b.append(", "); b.append(", ");
} }
b.append(names.get(i)); b.append(names.get(i));
} }
} }
return b.toString(); return b.toString();
} }
} }

View File

@@ -1,19 +1,19 @@
package com.semmle.js.ast; package com.semmle.js.ast;
public class Decorator extends Expression { public class Decorator extends Expression {
private final Expression expression; private final Expression expression;
public Decorator(SourceLocation loc, Expression expression) { public Decorator(SourceLocation loc, Expression expression) {
super("Decorator", loc); super("Decorator", loc);
this.expression = expression; this.expression = expression;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
public Expression getExpression() { public Expression getExpression() {
return expression; return expression;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,4 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** An array or object pattern. */
* An array or object pattern. public interface DestructuringPattern extends IPattern {}
*/
public interface DestructuringPattern extends IPattern {
}

View File

@@ -1,30 +1,26 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A do-while statement of the form <code>do { ... } while(...);</code>. */
* A do-while statement of the form <code>do { ... } while(...);</code>.
*/
public class DoWhileStatement extends Loop { public class DoWhileStatement extends Loop {
private final Expression test; private final Expression test;
public DoWhileStatement(SourceLocation loc, Expression test, Statement body) { public DoWhileStatement(SourceLocation loc, Expression test, Statement body) {
super("DoWhileStatement", loc, body); super("DoWhileStatement", loc, body);
this.test = test; this.test = test;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The test expression of this loop. */
* The test expression of this loop. public Expression getTest() {
*/ return test;
public Expression getTest() { }
return test;
}
@Override @Override
public Node getContinueTarget() { public Node getContinueTarget() {
return test; return test;
} }
} }

View File

@@ -1,19 +1,19 @@
package com.semmle.js.ast; package com.semmle.js.ast;
public class DynamicImport extends Expression { public class DynamicImport extends Expression {
private final Expression source; private final Expression source;
public DynamicImport(SourceLocation loc, Expression source) { public DynamicImport(SourceLocation loc, Expression source) {
super("DynamicImport", loc); super("DynamicImport", loc);
this.source = source; this.source = source;
} }
public Expression getSource() { public Expression getSource() {
return source; return source;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -1,15 +1,13 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** An empty statement <code>;</code>. */
* An empty statement <code>;</code>.
*/
public class EmptyStatement extends Statement { public class EmptyStatement extends Statement {
public EmptyStatement(SourceLocation loc) { public EmptyStatement(SourceLocation loc) {
super("EmptyStatement", loc); super("EmptyStatement", loc);
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -4,55 +4,49 @@ package com.semmle.js.ast;
* An enhanced for statement, that is, either a {@link ForInStatement} or a {@link ForOfStatement}. * An enhanced for statement, that is, either a {@link ForInStatement} or a {@link ForOfStatement}.
*/ */
public abstract class EnhancedForStatement extends Loop { public abstract class EnhancedForStatement extends Loop {
private final Node left; private final Node left;
private final Expression defaultValue; private final Expression defaultValue;
private final Expression right; private final Expression right;
public EnhancedForStatement(String type, SourceLocation loc, Node left, public EnhancedForStatement(
Expression right, Statement body) { String type, SourceLocation loc, Node left, Expression right, Statement body) {
super(type, loc, body); super(type, loc, body);
if (left instanceof AssignmentPattern) { if (left instanceof AssignmentPattern) {
AssignmentPattern ap = (AssignmentPattern) left; AssignmentPattern ap = (AssignmentPattern) left;
this.left = ap.getLeft(); this.left = ap.getLeft();
this.defaultValue = ap.getRight(); this.defaultValue = ap.getRight();
} else { } else {
this.left = left; this.left = left;
this.defaultValue = null; this.defaultValue = null;
} }
this.right = right; this.right = right;
} }
/** /**
* The iterator variable of this statement; may be either a {@link VariableDeclaration} statement, * The iterator variable of this statement; may be either a {@link VariableDeclaration} statement,
* or an lvalue {@link Expression}. * or an lvalue {@link Expression}.
*/ */
public Node getLeft() { public Node getLeft() {
return left; return left;
} }
/** /** Does the iterator variable of this statement have a default value? */
* Does the iterator variable of this statement have a default value? public boolean hasDefaultValue() {
*/ return defaultValue != null;
public boolean hasDefaultValue() { }
return defaultValue != null;
}
/** /** Get the default value of the iterator variable of this statement. */
* Get the default value of the iterator variable of this statement. public Expression getDefaultValue() {
*/ return defaultValue;
public Expression getDefaultValue() { }
return defaultValue;
}
/** /** The expression this loop iterates over. */
* The expression this loop iterates over. public Expression getRight() {
*/ return right;
public Expression getRight() { }
return right;
}
@Override @Override
public Node getContinueTarget() { public Node getContinueTarget() {
return this; return this;
} }
} }

View File

@@ -8,19 +8,19 @@ package com.semmle.js.ast;
* </pre> * </pre>
*/ */
public class ExportAllDeclaration extends ExportDeclaration { public class ExportAllDeclaration extends ExportDeclaration {
private final Literal source; private final Literal source;
public ExportAllDeclaration(SourceLocation loc, Literal source) { public ExportAllDeclaration(SourceLocation loc, Literal source) {
super("ExportAllDeclaration", loc); super("ExportAllDeclaration", loc);
this.source = source; this.source = source;
} }
public Literal getSource() { public Literal getSource() {
return source; return source;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -2,8 +2,7 @@ package com.semmle.js.ast;
public abstract class ExportDeclaration extends Statement { public abstract class ExportDeclaration extends Statement {
public ExportDeclaration(String type, SourceLocation loc) { public ExportDeclaration(String type, SourceLocation loc) {
super(type, loc); super(type, loc);
} }
} }

View File

@@ -14,23 +14,23 @@ package com.semmle.js.ast;
* </pre> * </pre>
*/ */
public class ExportDefaultDeclaration extends ExportDeclaration { public class ExportDefaultDeclaration extends ExportDeclaration {
/** /**
* Either an {@linkplain Expression} or a {@linkplain FunctionDeclaration} or * Either an {@linkplain Expression} or a {@linkplain FunctionDeclaration} or a {@linkplain
* a {@linkplain ClassDeclaration}. * ClassDeclaration}.
*/ */
private final Node declaration; private final Node declaration;
public ExportDefaultDeclaration(SourceLocation loc, Node declaration) { public ExportDefaultDeclaration(SourceLocation loc, Node declaration) {
super("ExportDefaultDeclaration", loc); super("ExportDefaultDeclaration", loc);
this.declaration = declaration; this.declaration = declaration;
} }
public Node getDeclaration() { public Node getDeclaration() {
return declaration; return declaration;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -1,16 +1,13 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A default export specifier, such as <code>f</code> in <code>export f from 'foo';</code>. */
* A default export specifier, such as <code>f</code> in
* <code>export f from 'foo';</code>.
*/
public class ExportDefaultSpecifier extends ExportSpecifier { public class ExportDefaultSpecifier extends ExportSpecifier {
public ExportDefaultSpecifier(SourceLocation loc, Identifier exported) { public ExportDefaultSpecifier(SourceLocation loc, Identifier exported) {
super("ExportDefaultSpecifier", loc, null, exported); super("ExportDefaultSpecifier", loc, null, exported);
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -6,45 +6,46 @@ import java.util.List;
* A named export declaration, which can be of one of the following forms: * A named export declaration, which can be of one of the following forms:
* *
* <ul> * <ul>
* <li><code>export var x = 23;</code></li> * <li><code>export var x = 23;</code>
* <li><code>export { x, y } from 'foo';</code></li> * <li><code>export { x, y } from 'foo';</code>
* <li><code>export { x, y };</code></li> * <li><code>export { x, y };</code>
* </ul> * </ul>
*/ */
public class ExportNamedDeclaration extends ExportDeclaration { public class ExportNamedDeclaration extends ExportDeclaration {
private final Statement declaration; private final Statement declaration;
private final List<ExportSpecifier> specifiers; private final List<ExportSpecifier> specifiers;
private final Literal source; private final Literal source;
public ExportNamedDeclaration(SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source) { public ExportNamedDeclaration(
super("ExportNamedDeclaration", loc); SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source) {
this.declaration = declaration; super("ExportNamedDeclaration", loc);
this.specifiers = specifiers; this.declaration = declaration;
this.source = source; this.specifiers = specifiers;
} this.source = source;
}
public Statement getDeclaration() { public Statement getDeclaration() {
return declaration; return declaration;
} }
public boolean hasDeclaration() { public boolean hasDeclaration() {
return declaration != null; return declaration != null;
} }
public List<ExportSpecifier> getSpecifiers() { public List<ExportSpecifier> getSpecifiers() {
return specifiers; return specifiers;
} }
public Literal getSource() { public Literal getSource() {
return source; return source;
} }
public boolean hasSource() { public boolean hasSource() {
return source != null; return source != null;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -1,16 +1,16 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* A namespace export specifier such as <code>* as foo</code> in * A namespace export specifier such as <code>* as foo</code> in <code>export * as foo from 'foo';
* <code>export * as foo from 'foo';</code>. * </code>.
*/ */
public class ExportNamespaceSpecifier extends ExportSpecifier { public class ExportNamespaceSpecifier extends ExportSpecifier {
public ExportNamespaceSpecifier(SourceLocation loc, Identifier exported) { public ExportNamespaceSpecifier(SourceLocation loc, Identifier exported) {
super("ExportNamespaceSpecifier", loc, null, exported); super("ExportNamespaceSpecifier", loc, null, exported);
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -1,32 +1,32 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* An export specifier in an {@linkplain ExportNamedDeclaration}; may either be a plain * An export specifier in an {@linkplain ExportNamedDeclaration}; may either be a plain identifier
* identifier <code>x</code>, or a rename export <code>x as y</code>. * <code>x</code>, or a rename export <code>x as y</code>.
*/ */
public class ExportSpecifier extends Expression { public class ExportSpecifier extends Expression {
private final Identifier local, exported; private final Identifier local, exported;
public ExportSpecifier(SourceLocation loc, Identifier local, Identifier exported) { public ExportSpecifier(SourceLocation loc, Identifier local, Identifier exported) {
this("ExportSpecifier", loc, local, exported); this("ExportSpecifier", loc, local, exported);
} }
public ExportSpecifier(String type, SourceLocation loc, Identifier local, Identifier exported) { public ExportSpecifier(String type, SourceLocation loc, Identifier local, Identifier exported) {
super(type, loc); super(type, loc);
this.local = local; this.local = local;
this.exported = exported == local ? new NodeCopier().copy(exported) : exported; this.exported = exported == local ? new NodeCopier().copy(exported) : exported;
} }
public Identifier getLocal() { public Identifier getLocal() {
return local; return local;
} }
public Identifier getExported() { public Identifier getExported() {
return exported; return exported;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -2,30 +2,26 @@ package com.semmle.js.ast;
import com.semmle.ts.ast.ITypedAstNode; import com.semmle.ts.ast.ITypedAstNode;
/** /** Common superclass of all expressions. */
* Common superclass of all expressions.
*/
public abstract class Expression extends Node implements ITypedAstNode { public abstract class Expression extends Node implements ITypedAstNode {
private int staticTypeId = -1; private int staticTypeId = -1;
public Expression(String type, SourceLocation loc) { public Expression(String type, SourceLocation loc) {
super(type, loc); super(type, loc);
} }
/** /** This expression, but with any surrounding parentheses stripped off. */
* This expression, but with any surrounding parentheses stripped off. public Expression stripParens() {
*/ return this;
public Expression stripParens() { }
return this;
}
@Override @Override
public int getStaticTypeId() { public int getStaticTypeId() {
return staticTypeId; return staticTypeId;
} }
@Override @Override
public void setStaticTypeId(int staticTypeId) { public void setStaticTypeId(int staticTypeId) {
this.staticTypeId = staticTypeId; this.staticTypeId = staticTypeId;
} }
} }

View File

@@ -1,25 +1,21 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** An expression statement such as <code>alert("Hi!");</code>. */
* An expression statement such as <code>alert("Hi!");</code>.
*/
public class ExpressionStatement extends Statement { public class ExpressionStatement extends Statement {
private final Expression expression; private final Expression expression;
public ExpressionStatement(SourceLocation loc, Expression expression) { public ExpressionStatement(SourceLocation loc, Expression expression) {
super("ExpressionStatement", loc); super("ExpressionStatement", loc);
this.expression = expression; this.expression = expression;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The expression wrapped by this expression statement. */
* The expression wrapped by this expression statement. public Expression getExpression() {
*/ return expression;
public Expression getExpression() { }
return expression;
}
} }

View File

@@ -3,51 +3,60 @@ package com.semmle.js.ast;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
public class FieldDefinition extends MemberDefinition<Expression> { public class FieldDefinition extends MemberDefinition<Expression> {
private final ITypeExpression typeAnnotation; private final ITypeExpression typeAnnotation;
private final int fieldParameterIndex; private final int fieldParameterIndex;
private static final int notFieldParameter = -1; private static final int notFieldParameter = -1;
public FieldDefinition(SourceLocation loc, int flags, Expression key, Expression value) { public FieldDefinition(SourceLocation loc, int flags, Expression key, Expression value) {
this(loc, flags, key, value, null); this(loc, flags, key, value, null);
} }
public FieldDefinition(SourceLocation loc, int flags, public FieldDefinition(
Expression key, Expression value, ITypeExpression typeAnnotation) { SourceLocation loc,
this(loc, flags, key, value, typeAnnotation, notFieldParameter); int flags,
} Expression key,
Expression value,
ITypeExpression typeAnnotation) {
this(loc, flags, key, value, typeAnnotation, notFieldParameter);
}
public FieldDefinition(SourceLocation loc, int flags, Expression key, Expression value, ITypeExpression typeAnnotation, public FieldDefinition(
int fieldParameterIndex) { SourceLocation loc,
super("FieldDefinition", loc, flags, key, value); int flags,
this.typeAnnotation = typeAnnotation; Expression key,
this.fieldParameterIndex = fieldParameterIndex; Expression value,
} ITypeExpression typeAnnotation,
int fieldParameterIndex) {
super("FieldDefinition", loc, flags, key, value);
this.typeAnnotation = typeAnnotation;
this.fieldParameterIndex = fieldParameterIndex;
}
public ITypeExpression getTypeAnnotation() { public ITypeExpression getTypeAnnotation() {
return typeAnnotation; return typeAnnotation;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
@Override @Override
public boolean isConcrete() { public boolean isConcrete() {
return !isAbstract(); return !isAbstract();
} }
@Override @Override
public boolean isParameterField() { public boolean isParameterField() {
return fieldParameterIndex != notFieldParameter; return fieldParameterIndex != notFieldParameter;
} }
/** /**
* If this is a field parameter, returns the index of the parameter that * If this is a field parameter, returns the index of the parameter that generated it, or -1 if
* generated it, or -1 if this is not a field parameter. * this is not a field parameter.
*/ */
public int getFieldParameterIndex() { public int getFieldParameterIndex() {
return fieldParameterIndex; return fieldParameterIndex;
} }
} }

View File

@@ -11,19 +11,20 @@ package com.semmle.js.ast;
* This also includes legacy for-each statements. * This also includes legacy for-each statements.
*/ */
public class ForInStatement extends EnhancedForStatement { public class ForInStatement extends EnhancedForStatement {
private final boolean each; private final boolean each;
public ForInStatement(SourceLocation loc, Node left, Expression right, Statement body, Boolean each) { public ForInStatement(
super("ForInStatement", loc, left, right, body); SourceLocation loc, Node left, Expression right, Statement body, Boolean each) {
this.each = each == Boolean.TRUE; super("ForInStatement", loc, left, right, body);
} this.each = each == Boolean.TRUE;
}
public boolean isEach() { public boolean isEach() {
return each; return each;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -9,22 +9,22 @@ package com.semmle.js.ast;
* </pre> * </pre>
*/ */
public class ForOfStatement extends EnhancedForStatement { public class ForOfStatement extends EnhancedForStatement {
private boolean isAwait; private boolean isAwait;
public ForOfStatement(SourceLocation loc, Node left, Expression right, Statement body) { public ForOfStatement(SourceLocation loc, Node left, Expression right, Statement body) {
super("ForOfStatement", loc, left, right, body); super("ForOfStatement", loc, left, right, body);
} }
public void setAwait(boolean isAwait) { public void setAwait(boolean isAwait) {
this.isAwait = isAwait; this.isAwait = isAwait;
} }
public boolean isAwait() { public boolean isAwait() {
return isAwait; return isAwait;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -10,70 +10,59 @@ package com.semmle.js.ast;
* </pre> * </pre>
*/ */
public class ForStatement extends Loop { public class ForStatement extends Loop {
private final Node init; private final Node init;
private final Expression test, update; private final Expression test, update;
public ForStatement(SourceLocation loc, Node init, Expression test, Expression update, Statement body) { public ForStatement(
super("ForStatement", loc, body); SourceLocation loc, Node init, Expression test, Expression update, Statement body) {
this.init = init; super("ForStatement", loc, body);
this.test = test; this.init = init;
this.update = update; this.test = test;
} this.update = update;
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** Does this for statement have an initialization part? */
* Does this for statement have an initialization part? public boolean hasInit() {
*/ return init != null;
public boolean hasInit() { }
return init != null;
}
/** /**
* The initialization part of this for statement; may be a {@link VariableDeclaration} * The initialization part of this for statement; may be a {@link VariableDeclaration} statement,
* statement, an {@link Expression}, or {@literal null}. * an {@link Expression}, or {@literal null}.
*/ */
public Node getInit() { public Node getInit() {
return init; return init;
} }
/** /** Does this for statement have a test? */
* Does this for statement have a test? public boolean hasTest() {
*/ return test != null;
public boolean hasTest() { }
return test != null;
}
/** /** The test expression of this for statement; may be null. */
* The test expression of this for statement; may be null. public Expression getTest() {
*/ return test;
public Expression getTest() { }
return test;
}
/** /** Does this for statement have an update expression? */
* Does this for statement have an update expression? public boolean hasUpdate() {
*/ return update != null;
public boolean hasUpdate() { }
return update != null;
}
/** /** The update expression of this for statement; may be null. */
* The update expression of this for statement; may be null. public Expression getUpdate() {
*/ return update;
public Expression getUpdate() { }
return update;
}
@Override @Override
public Node getContinueTarget() { public Node getContinueTarget() {
if (update != null) if (update != null) return update;
return update; if (test != null) return test;
if (test != null) return body;
return test; }
return body;
}
} }

View File

@@ -1,11 +1,10 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.Collections;
import java.util.List;
import com.semmle.ts.ast.DecoratorList; import com.semmle.ts.ast.DecoratorList;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.Collections;
import java.util.List;
/** /**
* A function declaration such as * A function declaration such as
@@ -17,71 +16,173 @@ import com.semmle.ts.ast.TypeParameter;
* </pre> * </pre>
*/ */
public class FunctionDeclaration extends Statement implements IFunction { public class FunctionDeclaration extends Statement implements IFunction {
private final AFunction<? extends Node> fn; private final AFunction<? extends Node> fn;
private final boolean hasDeclareKeyword; private final boolean hasDeclareKeyword;
private int symbol = -1; private int symbol = -1;
public FunctionDeclaration(SourceLocation loc, Identifier id, List<Expression> params, Node body, boolean generator, public FunctionDeclaration(
boolean async) { SourceLocation loc,
this(loc, new AFunction<>(id, params, body, generator, async, Collections.emptyList(), Collections.emptyList(), Identifier id,
Collections.emptyList(), null, null), List<Expression> params,
false); Node body,
} boolean generator,
boolean async) {
this(
loc,
new AFunction<>(
id,
params,
body,
generator,
async,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
null,
null),
false);
}
public FunctionDeclaration(SourceLocation loc, Identifier id, public FunctionDeclaration(
List<Expression> params, Node body, boolean generator, boolean async, boolean hasDeclareKeyword, SourceLocation loc,
List<TypeParameter> typeParameters, List<ITypeExpression> parameterTypes, ITypeExpression returnType, Identifier id,
ITypeExpression thisParameterType) { List<Expression> params,
this(loc, new AFunction<>(id, params, body, generator, async, typeParameters, parameterTypes, Collections.emptyList(), Node body,
returnType, thisParameterType), hasDeclareKeyword); boolean generator,
} boolean async,
boolean hasDeclareKeyword,
List<TypeParameter> typeParameters,
List<ITypeExpression> parameterTypes,
ITypeExpression returnType,
ITypeExpression thisParameterType) {
this(
loc,
new AFunction<>(
id,
params,
body,
generator,
async,
typeParameters,
parameterTypes,
Collections.emptyList(),
returnType,
thisParameterType),
hasDeclareKeyword);
}
private FunctionDeclaration(SourceLocation loc, AFunction<Node> fn, boolean hasDeclareKeyword) { private FunctionDeclaration(SourceLocation loc, AFunction<Node> fn, boolean hasDeclareKeyword) {
super("FunctionDeclaration", loc); super("FunctionDeclaration", loc);
this.fn = fn; this.fn = fn;
this.hasDeclareKeyword = hasDeclareKeyword; this.hasDeclareKeyword = hasDeclareKeyword;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
public FunctionExpression asFunctionExpression() { public FunctionExpression asFunctionExpression() {
return new FunctionExpression(getLoc(), fn); return new FunctionExpression(getLoc(), fn);
} }
@Override public Identifier getId() { return fn.getId(); } @Override
@Override public List<IPattern> getParams() { return fn.getParams(); } public Identifier getId() {
@Override public boolean hasDefault(int i) { return fn.hasDefault(i); } return fn.getId();
@Override public Expression getDefault(int i) { return fn.getDefault(i); } }
@Override public IPattern getRest() { return fn.getRest(); }
@Override public Node getBody() { return fn.getBody(); }
@Override public boolean hasRest() { return fn.hasRest(); }
public boolean hasId() { return fn.hasId(); }
public boolean isGenerator() { return fn.isGenerator(); }
public boolean isAsync() { return fn.isAsync(); }
public List<IPattern> getAllParams() { return fn.getAllParams(); }
@Override public List<Expression> getRawParameters() { return fn.getRawParams(); }
public ITypeExpression getReturnType() { return fn.getReturnType(); }
@Override public boolean hasParameterType(int i) { return fn.hasParameterType(i); }
@Override public ITypeExpression getParameterType(int i) { return fn.getParameterType(i); }
public List<ITypeExpression> getParameterTypes() { return fn.getParameterTypes(); }
public List<TypeParameter> getTypeParameters() { return fn.getTypeParameters(); }
public ITypeExpression getThisParameterType() { return fn.getThisParameterType(); }
public List<DecoratorList> getParameterDecorators() { return fn.getParameterDecorators(); }
public boolean hasDeclareKeyword() { @Override
return hasDeclareKeyword; public List<IPattern> getParams() {
} return fn.getParams();
}
@Override @Override
public int getSymbol() { public boolean hasDefault(int i) {
return this.symbol; return fn.hasDefault(i);
} }
@Override @Override
public void setSymbol(int symbol) { public Expression getDefault(int i) {
this.symbol = symbol; return fn.getDefault(i);
} }
@Override
public IPattern getRest() {
return fn.getRest();
}
@Override
public Node getBody() {
return fn.getBody();
}
@Override
public boolean hasRest() {
return fn.hasRest();
}
public boolean hasId() {
return fn.hasId();
}
public boolean isGenerator() {
return fn.isGenerator();
}
public boolean isAsync() {
return fn.isAsync();
}
public List<IPattern> getAllParams() {
return fn.getAllParams();
}
@Override
public List<Expression> getRawParameters() {
return fn.getRawParams();
}
public ITypeExpression getReturnType() {
return fn.getReturnType();
}
@Override
public boolean hasParameterType(int i) {
return fn.hasParameterType(i);
}
@Override
public ITypeExpression getParameterType(int i) {
return fn.getParameterType(i);
}
public List<ITypeExpression> getParameterTypes() {
return fn.getParameterTypes();
}
public List<TypeParameter> getTypeParameters() {
return fn.getTypeParameters();
}
public ITypeExpression getThisParameterType() {
return fn.getThisParameterType();
}
public List<DecoratorList> getParameterDecorators() {
return fn.getParameterDecorators();
}
public boolean hasDeclareKeyword() {
return hasDeclareKeyword;
}
@Override
public int getSymbol() {
return this.symbol;
}
@Override
public void setSymbol(int symbol) {
this.symbol = symbol;
}
} }

View File

@@ -1,36 +1,68 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.Collections;
import java.util.List;
import com.semmle.ts.ast.DecoratorList; import com.semmle.ts.ast.DecoratorList;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.Collections;
import java.util.List;
/** /** A plain function expression. */
* A plain function expression.
*/
public class FunctionExpression extends AFunctionExpression { public class FunctionExpression extends AFunctionExpression {
public FunctionExpression(SourceLocation loc, Identifier id, public FunctionExpression(
List<Expression> params, Node body, Boolean generator, Boolean async) { SourceLocation loc,
super("FunctionExpression", loc, id, params, body, generator, async, Collections.emptyList(), Collections.emptyList(), Identifier id,
Collections.emptyList(), null, null); List<Expression> params,
} Node body,
Boolean generator,
Boolean async) {
super(
"FunctionExpression",
loc,
id,
params,
body,
generator,
async,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
null,
null);
}
public FunctionExpression(SourceLocation loc, Identifier id, public FunctionExpression(
List<Expression> params, Node body, Boolean generator, Boolean async, SourceLocation loc,
List<TypeParameter> typeParameters, List<ITypeExpression> parameterTypes, List<DecoratorList> parameterDecorators, Identifier id,
ITypeExpression returnType, ITypeExpression thisParameterType) { List<Expression> params,
super("FunctionExpression", loc, id, params, body, generator, async, typeParameters, parameterTypes, parameterDecorators, Node body,
returnType, thisParameterType); Boolean generator,
} Boolean async,
List<TypeParameter> typeParameters,
List<ITypeExpression> parameterTypes,
List<DecoratorList> parameterDecorators,
ITypeExpression returnType,
ITypeExpression thisParameterType) {
super(
"FunctionExpression",
loc,
id,
params,
body,
generator,
async,
typeParameters,
parameterTypes,
parameterDecorators,
returnType,
thisParameterType);
}
public FunctionExpression(SourceLocation loc, AFunction<? extends Node> fn) { public FunctionExpression(SourceLocation loc, AFunction<? extends Node> fn) {
super("FunctionExpression", loc, fn); super("FunctionExpression", loc, fn);
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,94 +1,66 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.List;
import com.semmle.ts.ast.DecoratorList; import com.semmle.ts.ast.DecoratorList;
import com.semmle.ts.ast.INodeWithSymbol; import com.semmle.ts.ast.INodeWithSymbol;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import com.semmle.ts.ast.TypeParameter; import com.semmle.ts.ast.TypeParameter;
import java.util.List;
/** /** A function declaration or expression. */
* A function declaration or expression.
*/
public interface IFunction extends IStatementContainer, INodeWithSymbol { public interface IFunction extends IStatementContainer, INodeWithSymbol {
/** /** The function name; may be null for function expressions. */
* The function name; may be null for function expressions. public Identifier getId();
*/
public Identifier getId();
/** /** The parameters of the function, not including the rest parameter. */
* The parameters of the function, not including the rest parameter. public List<IPattern> getParams();
*/
public List<IPattern> getParams();
/** /** The parameters of the function, including the rest parameter. */
* The parameters of the function, including the rest parameter. public List<IPattern> getAllParams();
*/
public List<IPattern> getAllParams();
/** /** Does the i'th parameter have a default expression? */
* Does the i'th parameter have a default expression? public boolean hasDefault(int i);
*/
public boolean hasDefault(int i);
/** /** The default expression for the i'th parameter; may be null. */
* The default expression for the i'th parameter; may be null. public Expression getDefault(int i);
*/
public Expression getDefault(int i);
/** /** The rest parameter of this function; may be null. */
* The rest parameter of this function; may be null. public IPattern getRest();
*/
public IPattern getRest();
/** /**
* The body of the function; usually a {@link BlockStatement}, but may * The body of the function; usually a {@link BlockStatement}, but may be an {@link Expression}
* be an {@link Expression} for function expressions. * for function expressions.
*/ */
public Node getBody(); public Node getBody();
/** /** Does this function have a rest parameter? */
* Does this function have a rest parameter? public boolean hasRest();
*/
public boolean hasRest();
/** /** Is this function a generator function? */
* Is this function a generator function? public boolean isGenerator();
*/
public boolean isGenerator();
/** /**
* The raw parameters of this function; parameters with defaults are * The raw parameters of this function; parameters with defaults are represented as {@link
* represented as {@link AssignmentPattern}s and the rest parameter * AssignmentPattern}s and the rest parameter (if any) as a {@link RestElement}.
* (if any) as a {@link RestElement}. */
*/ public List<Expression> getRawParameters();
public List<Expression> getRawParameters();
/** /** Is this function an asynchronous function? */
* Is this function an asynchronous function? public boolean isAsync();
*/
public boolean isAsync();
/** /** The return type of the function, if any. */
* The return type of the function, if any. public ITypeExpression getReturnType();
*/
public ITypeExpression getReturnType();
/** /** Does the i'th parameter have a type annotation? */
* Does the i'th parameter have a type annotation? public boolean hasParameterType(int i);
*/
public boolean hasParameterType(int i);
/** /** The type annotation for the i'th parameter; may be null. */
* The type annotation for the i'th parameter; may be null. public ITypeExpression getParameterType(int i);
*/
public ITypeExpression getParameterType(int i);
public List<TypeParameter> getTypeParameters(); public List<TypeParameter> getTypeParameters();
public ITypeExpression getThisParameterType(); public ITypeExpression getThisParameterType();
public List<DecoratorList> getParameterDecorators(); public List<DecoratorList> getParameterDecorators();
public boolean hasDeclareKeyword(); public boolean hasDeclareKeyword();
} }

View File

@@ -1,16 +1,10 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** The common interface implemented by all AST node types. */
* The common interface implemented by all AST node types.
*/
public interface INode extends ISourceElement { public interface INode extends ISourceElement {
/** /** Accept a visitor object. */
* Accept a visitor object. public <C, R> R accept(Visitor<C, R> v, C c);
*/
public <C, R> R accept(Visitor<C, R> v, C c);
/** /** Return the node's type tag. */
* Return the node's type tag. public String getType();
*/
public String getType();
} }

View File

@@ -1,8 +1,7 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* A marker interface encompassing variables ({@link Identifier}) and complex patterns * A marker interface encompassing variables ({@link Identifier}) and complex patterns used in
* used in destructuring assignments ({@link ArrayPattern}, {@link ObjectPattern}). * destructuring assignments ({@link ArrayPattern}, {@link ObjectPattern}).
*/ */
public interface IPattern extends INode { public interface IPattern extends INode {}
}

View File

@@ -1,11 +1,7 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A source code element potentially associated with a location. */
* A source code element potentially associated with a location.
*/
public interface ISourceElement { public interface ISourceElement {
/** /** Get the source location of this element; may be null. */
* Get the source location of this element; may be null. public SourceLocation getLoc();
*/
public SourceLocation getLoc();
} }

View File

@@ -1,7 +1,4 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A statement container, that is, either a {@link Program} or a {@link IFunction}. */
* A statement container, that is, either a {@link Program} or a {@link IFunction}. public interface IStatementContainer extends INode {}
*/
public interface IStatementContainer extends INode {
}

View File

@@ -6,40 +6,37 @@ import com.semmle.ts.ast.ITypeExpression;
/** /**
* An identifier. * An identifier.
* *
* Identifiers can either be variable declarations (like <code>x</code> in <code>var x;</code>), * <p>Identifiers can either be variable declarations (like <code>x</code> in <code>var x;</code>),
* variable references (like <code>x</code> in <code>x = 42</code>), property names * variable references (like <code>x</code> in <code>x = 42</code>), property names (like <code>f
* (like <code>f</code> in <code>e.f</code>), statement labels (like <code>l</code> in * </code> in <code>e.f</code>), statement labels (like <code>l</code> in <code>l: while(true);
* <code>l: while(true);</code>), or statement label references (like <code>l</code> in * </code>), or statement label references (like <code>l</code> in <code>break l;</code>).
* <code>break l;</code>).
*/ */
public class Identifier extends Expression implements IPattern, ITypeExpression, INodeWithSymbol { public class Identifier extends Expression implements IPattern, ITypeExpression, INodeWithSymbol {
private final String name; private final String name;
private int symbol = -1; private int symbol = -1;
public Identifier(SourceLocation loc, String name) { public Identifier(SourceLocation loc, String name) {
super("Identifier", loc); super("Identifier", loc);
this.name = name; this.name = name;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The name of this identifier. */
* The name of this identifier. public String getName() {
*/ return name;
public String getName() { }
return name;
}
@Override @Override
public int getSymbol() { public int getSymbol() {
return symbol; return symbol;
} }
@Override @Override
public void setSymbol(int symbol) { public void setSymbol(int symbol) {
this.symbol = symbol; this.symbol = symbol;
} }
} }

View File

@@ -1,49 +1,40 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** An if statement. */
* An if statement.
*/
public class IfStatement extends Statement { public class IfStatement extends Statement {
private final Expression test; private final Expression test;
private final Statement consequent, alternate; private final Statement consequent, alternate;
public IfStatement(SourceLocation loc, Expression test, Statement consequent, Statement alternate) { public IfStatement(
super("IfStatement", loc); SourceLocation loc, Expression test, Statement consequent, Statement alternate) {
this.test = test; super("IfStatement", loc);
this.consequent = consequent; this.test = test;
this.alternate = alternate; this.consequent = consequent;
} this.alternate = alternate;
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The test expression of this if statement. */
* The test expression of this if statement. public Expression getTest() {
*/ return test;
public Expression getTest() { }
return test;
}
/** /** The then-branch of this if statement. */
* The then-branch of this if statement. public Statement getConsequent() {
*/ return consequent;
public Statement getConsequent() { }
return consequent;
}
/** /** The else-branch of this if statement; may be null. */
* The else-branch of this if statement; may be null. public Statement getAlternate() {
*/ return alternate;
public Statement getAlternate() { }
return alternate;
}
/** /** Does this if statement have an else branch? */
* Does this if statement have an else branch? public boolean hasAlternate() {
*/ return alternate != null;
public boolean hasAlternate() { }
return alternate != null;
}
} }

View File

@@ -15,28 +15,28 @@ import java.util.List;
* </pre> * </pre>
*/ */
public class ImportDeclaration extends Statement { public class ImportDeclaration extends Statement {
/** List of import specifiers detailing how declarations are imported; may be empty. */ /** List of import specifiers detailing how declarations are imported; may be empty. */
private final List<ImportSpecifier> specifiers; private final List<ImportSpecifier> specifiers;
/** The module from which declarations are imported. */ /** The module from which declarations are imported. */
private final Literal source; private final Literal source;
public ImportDeclaration(SourceLocation loc, List<ImportSpecifier> specifiers, Literal source) { public ImportDeclaration(SourceLocation loc, List<ImportSpecifier> specifiers, Literal source) {
super("ImportDeclaration", loc); super("ImportDeclaration", loc);
this.specifiers = specifiers; this.specifiers = specifiers;
this.source = source; this.source = source;
} }
public Literal getSource() { public Literal getSource() {
return source; return source;
} }
public List<ImportSpecifier> getSpecifiers() { public List<ImportSpecifier> getSpecifiers() {
return specifiers; return specifiers;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -1,19 +1,19 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* A default import specifier, such as <code>f</code> in * A default import specifier, such as <code>f</code> in <code>import f, { x, y } from 'foo';</code>
* <code>import f, { x, y } from 'foo';</code>. * .
* *
* Default import specifiers do not have an explicit imported name * <p>Default import specifiers do not have an explicit imported name (the imported name is,
* (the imported name is, implicitly, <code>default</code>). * implicitly, <code>default</code>).
*/ */
public class ImportDefaultSpecifier extends ImportSpecifier { public class ImportDefaultSpecifier extends ImportSpecifier {
public ImportDefaultSpecifier(SourceLocation loc, Identifier local) { public ImportDefaultSpecifier(SourceLocation loc, Identifier local) {
super("ImportDefaultSpecifier", loc, null, local); super("ImportDefaultSpecifier", loc, null, local);
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -1,18 +1,18 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* A namespace import specifier such as <code>* as foo</code> in * A namespace import specifier such as <code>* as foo</code> in <code>import * as foo from 'foo';
* <code>import * as foo from 'foo';</code>. * </code>.
* *
* Namespace import specifiers do not have an imported name. * <p>Namespace import specifiers do not have an imported name.
*/ */
public class ImportNamespaceSpecifier extends ImportSpecifier { public class ImportNamespaceSpecifier extends ImportSpecifier {
public ImportNamespaceSpecifier(SourceLocation loc, Identifier local) { public ImportNamespaceSpecifier(SourceLocation loc, Identifier local) {
super("ImportNamespaceSpecifier", loc, null, local); super("ImportNamespaceSpecifier", loc, null, local);
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -1,36 +1,36 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* An import specifier such as <code>x</code> and <code>y as z</code> in * An import specifier such as <code>x</code> and <code>y as z</code> in <code>
* <code>import { x, y as z } from 'foo';</code>. * import { x, y as z } from 'foo';</code>.
* *
* An import specifier has a local name and an imported name; for instance, * <p>An import specifier has a local name and an imported name; for instance, <code>y as z</code>
* <code>y as z</code> has local name <code>z</code> and imported name <code>y</code>, * has local name <code>z</code> and imported name <code>y</code>, while <code>x</code> has both
* while <code>x</code> has both local and imported name <code>x</code>. * local and imported name <code>x</code>.
*/ */
public class ImportSpecifier extends Expression { public class ImportSpecifier extends Expression {
private final Identifier imported, local; private final Identifier imported, local;
public ImportSpecifier(SourceLocation loc, Identifier imported, Identifier local) { public ImportSpecifier(SourceLocation loc, Identifier imported, Identifier local) {
this("ImportSpecifier", loc, imported, local); this("ImportSpecifier", loc, imported, local);
} }
public ImportSpecifier(String type, SourceLocation loc, Identifier imported, Identifier local) { public ImportSpecifier(String type, SourceLocation loc, Identifier imported, Identifier local) {
super(type, loc); super(type, loc);
this.imported = imported; this.imported = imported;
this.local = local == imported ? new NodeCopier().copy(local) : local; this.local = local == imported ? new NodeCopier().copy(local) : local;
} }
public Identifier getImported() { public Identifier getImported() {
return imported; return imported;
} }
public Identifier getLocal() { public Identifier getLocal() {
return local; return local;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
} }

View File

@@ -1,87 +1,84 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import java.util.List;
import com.semmle.ts.ast.INodeWithSymbol; import com.semmle.ts.ast.INodeWithSymbol;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
import java.util.List;
/** /** An invocation, that is, either a {@link CallExpression} or a {@link NewExpression}. */
* An invocation, that is, either a {@link CallExpression} or a {@link NewExpression}.
*/
public abstract class InvokeExpression extends Expression implements INodeWithSymbol, Chainable { public abstract class InvokeExpression extends Expression implements INodeWithSymbol, Chainable {
private final Expression callee; private final Expression callee;
private final List<ITypeExpression> typeArguments; private final List<ITypeExpression> typeArguments;
private final List<Expression> arguments; private final List<Expression> arguments;
private final boolean optional; private final boolean optional;
private final boolean onOptionalChain; private final boolean onOptionalChain;
private int resolvedSignatureId = -1; private int resolvedSignatureId = -1;
private int overloadIndex = -1; private int overloadIndex = -1;
private int symbol = -1; private int symbol = -1;
public InvokeExpression(String type, SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, public InvokeExpression(
List<Expression> arguments, Boolean optional, Boolean onOptionalChain) { String type,
super(type, loc); SourceLocation loc,
this.callee = callee; Expression callee,
this.typeArguments = typeArguments; List<ITypeExpression> typeArguments,
this.arguments = arguments; List<Expression> arguments,
this.optional = optional == Boolean.TRUE; Boolean optional,
this.onOptionalChain = onOptionalChain == Boolean.TRUE; Boolean onOptionalChain) {
} super(type, loc);
this.callee = callee;
this.typeArguments = typeArguments;
this.arguments = arguments;
this.optional = optional == Boolean.TRUE;
this.onOptionalChain = onOptionalChain == Boolean.TRUE;
}
/** /** The callee expression of this invocation. */
* The callee expression of this invocation. public Expression getCallee() {
*/ return callee;
public Expression getCallee() { }
return callee;
}
/** /** The type arguments of this invocation. */
* The type arguments of this invocation. public List<ITypeExpression> getTypeArguments() {
*/ return typeArguments;
public List<ITypeExpression> getTypeArguments() { }
return typeArguments;
}
/** /** The argument expressions of this invocation. */
* The argument expressions of this invocation. public List<Expression> getArguments() {
*/ return arguments;
public List<Expression> getArguments() { }
return arguments;
}
@Override @Override
public boolean isOptional() { public boolean isOptional() {
return optional; return optional;
} }
@Override @Override
public boolean isOnOptionalChain() { public boolean isOnOptionalChain() {
return onOptionalChain; return onOptionalChain;
} }
public int getResolvedSignatureId() { public int getResolvedSignatureId() {
return resolvedSignatureId; return resolvedSignatureId;
} }
public void setResolvedSignatureId(int resolvedSignatureId) { public void setResolvedSignatureId(int resolvedSignatureId) {
this.resolvedSignatureId = resolvedSignatureId; this.resolvedSignatureId = resolvedSignatureId;
} }
public int getOverloadIndex() { public int getOverloadIndex() {
return overloadIndex; return overloadIndex;
} }
public void setOverloadIndex(int overloadIndex) { public void setOverloadIndex(int overloadIndex) {
this.overloadIndex = overloadIndex; this.overloadIndex = overloadIndex;
} }
@Override @Override
public int getSymbol() { public int getSymbol() {
return symbol; return symbol;
} }
@Override @Override
public void setSymbol(int symbol) { public void setSymbol(int symbol) {
this.symbol = symbol; this.symbol = symbol;
} }
} }

View File

@@ -1,27 +1,21 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A jump statement, that is, either a {@link BreakStatement} or a {@link ContinueStatement}. */
* A jump statement, that is, either a {@link BreakStatement} or a {@link ContinueStatement}.
*/
public abstract class JumpStatement extends Statement { public abstract class JumpStatement extends Statement {
private final Identifier label; private final Identifier label;
public JumpStatement(String type, SourceLocation loc, Identifier label) { public JumpStatement(String type, SourceLocation loc, Identifier label) {
super(type, loc); super(type, loc);
this.label = label; this.label = label;
} }
/** /** Does this jump have an explicit target label? */
* Does this jump have an explicit target label? public boolean hasLabel() {
*/ return label != null;
public boolean hasLabel() { }
return label != null;
}
/** /** Get the target label of this jump; may be null. */
* Get the target label of this jump; may be null. public Identifier getLabel() {
*/ return label;
public Identifier getLabel() { }
return label;
}
} }

View File

@@ -1,34 +1,28 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A labeled statement. */
* A labeled statement.
*/
public class LabeledStatement extends Statement { public class LabeledStatement extends Statement {
private final Identifier label; private final Identifier label;
private final Statement body; private final Statement body;
public LabeledStatement(SourceLocation loc, Identifier label, Statement body) { public LabeledStatement(SourceLocation loc, Identifier label, Statement body) {
super("LabeledStatement", loc); super("LabeledStatement", loc);
this.label = label; this.label = label;
this.body = body; this.body = body;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The label of the labeled statement. */
* The label of the labeled statement. public Identifier getLabel() {
*/ return label;
public Identifier getLabel() { }
return label;
}
/** /** The statement wrapped by this labeled statement. */
* The statement wrapped by this labeled statement. public Statement getBody() {
*/ return body;
public Statement getBody() { }
return body;
}
} }

View File

@@ -2,29 +2,27 @@ package com.semmle.js.ast;
import java.util.List; import java.util.List;
/** /** An old-style let expression of the form <code>let (vardecls) expr</code>. */
* An old-style let expression of the form <code>let (vardecls) expr</code>.
*/
public class LetExpression extends Expression { public class LetExpression extends Expression {
private final List<VariableDeclarator> head; private final List<VariableDeclarator> head;
private final Expression body; private final Expression body;
public LetExpression(SourceLocation loc, List<VariableDeclarator> head, Expression body) { public LetExpression(SourceLocation loc, List<VariableDeclarator> head, Expression body) {
super("LetExpression", loc); super("LetExpression", loc);
this.head = head; this.head = head;
this.body = body; this.body = body;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
public List<VariableDeclarator> getHead() { public List<VariableDeclarator> getHead() {
return head; return head;
} }
public Expression getBody() { public Expression getBody() {
return body; return body;
} }
} }

View File

@@ -2,29 +2,27 @@ package com.semmle.js.ast;
import java.util.List; import java.util.List;
/** /** An old-style let statement of the form <code>let(vardecls) stmt</code>. */
* An old-style let statement of the form <code>let(vardecls) stmt</code>.
*/
public class LetStatement extends Statement { public class LetStatement extends Statement {
private final List<VariableDeclarator> head; private final List<VariableDeclarator> head;
private final Statement body; private final Statement body;
public LetStatement(SourceLocation loc, List<VariableDeclarator> head, Statement body) { public LetStatement(SourceLocation loc, List<VariableDeclarator> head, Statement body) {
super("LetStatement", loc); super("LetStatement", loc);
this.head = head; this.head = head;
this.body = body; this.body = body;
} }
@Override @Override
public <C, R> R accept(Visitor<C, R> v, C c) { public <C, R> R accept(Visitor<C, R> v, C c) {
return v.visit(this, c); return v.visit(this, c);
} }
public List<VariableDeclarator> getHead() { public List<VariableDeclarator> getHead() {
return head; return head;
} }
public Statement getBody() { public Statement getBody() {
return body; return body;
} }
} }

View File

@@ -5,92 +5,78 @@ import com.semmle.ts.ast.ITypeExpression;
/** /**
* A literal constant. * A literal constant.
* <p> *
* A <tt>null</tt> literal may occur as a TypeScript type annotation - other * <p>A <tt>null</tt> literal may occur as a TypeScript type annotation - other literals are always
* literals are always expressions. * expressions.
*/ */
public class Literal extends Expression implements ITypeExpression { public class Literal extends Expression implements ITypeExpression {
private final TokenType tokenType; private final TokenType tokenType;
private final Object value; private final Object value;
private final String raw; private final String raw;
public Literal(SourceLocation loc, TokenType tokenType, Object value) { public Literal(SourceLocation loc, TokenType tokenType, Object value) {
super("Literal", loc); super("Literal", loc);
// for numbers, check whether they can be represented as integers // for numbers, check whether they can be represented as integers
if (value instanceof Double) { if (value instanceof Double) {
Double dvalue = (Double)value; Double dvalue = (Double) value;
if (dvalue >= Long.MIN_VALUE && dvalue <= Long.MAX_VALUE && (dvalue%1) == 0) if (dvalue >= Long.MIN_VALUE && dvalue <= Long.MAX_VALUE && (dvalue % 1) == 0)
value = dvalue.longValue(); value = dvalue.longValue();
} else if (value instanceof CharSequence) { } else if (value instanceof CharSequence) {
value = value.toString(); value = value.toString();
} }
this.tokenType = tokenType; this.tokenType = tokenType;
this.value = value; this.value = value;
this.raw = getLoc().getSource(); this.raw = getLoc().getSource();
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The type of the token corresponding to this literal. */
* The type of the token corresponding to this literal. public TokenType getTokenType() {
*/ return tokenType;
public TokenType getTokenType() { }
return tokenType;
}
/** /**
* The value of this literal; may be null if this is a null literal or a literal whose value * The value of this literal; may be null if this is a null literal or a literal whose value
* cannot be represented by the parser. * cannot be represented by the parser.
*/ */
public Object getValue() { public Object getValue() {
return value; return value;
} }
/** /** The source text of this literal. */
* The source text of this literal. public String getRaw() {
*/ return raw;
public String getRaw() { }
return raw;
}
/** /** Is this a regular expression literal? */
* Is this a regular expression literal? public boolean isRegExp() {
*/ return tokenType == TokenType.regexp;
public boolean isRegExp() { }
return tokenType == TokenType.regexp;
}
/** /** The value of this literal expressed as a string. */
* The value of this literal expressed as a string. public String getStringValue() {
*/ // regular expressions may have a null value; use the raw value instead
public String getStringValue() { if (isRegExp()) return raw;
// regular expressions may have a null value; use the raw value instead return String.valueOf(value);
if (isRegExp()) }
return raw;
return String.valueOf(value);
}
/** /** Is the value of this literal falsy? */
* Is the value of this literal falsy? public boolean isFalsy() {
*/ if (isRegExp()) return false;
public boolean isFalsy() { return value == null
if (isRegExp()) || value instanceof Number && ((Number) value).intValue() == 0
return false; || value == Boolean.FALSE
return value == null || || value instanceof String && ((String) value).isEmpty();
value instanceof Number && ((Number)value).intValue() == 0 || }
value == Boolean.FALSE ||
value instanceof String && ((String)value).isEmpty();
}
/** /** Is the value of this literal truthy? */
* Is the value of this literal truthy? public boolean isTruthy() {
*/ return !isFalsy();
public boolean isTruthy() { }
return !isFalsy();
}
} }

View File

@@ -4,12 +4,12 @@ package com.semmle.js.ast;
* A short-circuiting binary expression, i.e., either <code>&amp;&amp;</code> or <code>||</code>. * A short-circuiting binary expression, i.e., either <code>&amp;&amp;</code> or <code>||</code>.
*/ */
public class LogicalExpression extends ABinaryExpression { public class LogicalExpression extends ABinaryExpression {
public LogicalExpression(SourceLocation loc, String operator, Expression left, Expression right) { public LogicalExpression(SourceLocation loc, String operator, Expression left, Expression right) {
super(loc, "LogicalExpression", operator, left, right); super(loc, "LogicalExpression", operator, left, right);
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,26 +1,24 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /**
* A loop statement, that is, a {@link WhileStatement}, a {@link DoWhileStatement}, a {@link ForStatement}, * A loop statement, that is, a {@link WhileStatement}, a {@link DoWhileStatement}, a {@link
* or a {@link EnhancedForStatement}. * ForStatement}, or a {@link EnhancedForStatement}.
*/ */
public abstract class Loop extends Statement { public abstract class Loop extends Statement {
protected final Statement body; protected final Statement body;
public Loop(String type, SourceLocation loc, Statement body) { public Loop(String type, SourceLocation loc, Statement body) {
super(type, loc); super(type, loc);
this.body = body; this.body = body;
} }
/** /** The loop body. */
* The loop body. public final Statement getBody() {
*/ return body;
public final Statement getBody() { }
return body;
}
/** /**
* The child node of this loop where execution resumes after a <code>continue</code> statement. * The child node of this loop where execution resumes after a <code>continue</code> statement.
*/ */
public abstract Node getContinueTarget(); public abstract Node getContinueTarget();
} }

View File

@@ -6,126 +6,119 @@ import java.util.List;
/** /**
* A member definition in a {@linkplain ClassBody}. * A member definition in a {@linkplain ClassBody}.
* *
* A member definition has a name and an optional initial value, whose type is * <p>A member definition has a name and an optional initial value, whose type is given by the type
* given by the type parameter {@code V}. * parameter {@code V}.
*/ */
public abstract class MemberDefinition<V extends Expression> extends Node { public abstract class MemberDefinition<V extends Expression> extends Node {
/** /** A bitmask of flags defined in {@linkplain DeclarationFlags}. */
* A bitmask of flags defined in {@linkplain DeclarationFlags}. private final int flags;
*/
private final int flags;
/** /**
* The name of the member. * The name of the member.
* *
* If {@link #isComputed()} is false, this must be an {@link Identifier}, otherwise * <p>If {@link #isComputed()} is false, this must be an {@link Identifier}, otherwise it can be
* it can be an arbitrary expression. * an arbitrary expression.
*/ */
private final Expression key; private final Expression key;
/** The initial value of the member. */ /** The initial value of the member. */
private final V value; private final V value;
/** The decorators applied to this member, if any. */ /** The decorators applied to this member, if any. */
private final List<Decorator> decorators; private final List<Decorator> decorators;
public MemberDefinition(String type, SourceLocation loc, int flags, Expression key, V value) { public MemberDefinition(String type, SourceLocation loc, int flags, Expression key, V value) {
super(type, loc); super(type, loc);
this.flags = flags; this.flags = flags;
this.key = key; this.key = key;
this.value = value; this.value = value;
this.decorators = new ArrayList<Decorator>(); this.decorators = new ArrayList<Decorator>();
} }
/** Returns the flags, as defined by {@linkplain DeclarationFlags}. */ /** Returns the flags, as defined by {@linkplain DeclarationFlags}. */
public int getFlags() { public int getFlags() {
return flags; return flags;
} }
/** Returns true if this has the <tt>static</tt> modifier. */ /** Returns true if this has the <tt>static</tt> modifier. */
public boolean isStatic() { public boolean isStatic() {
return DeclarationFlags.isStatic(flags); return DeclarationFlags.isStatic(flags);
} }
/** Returns true if the member name is computed. */ /** Returns true if the member name is computed. */
public boolean isComputed() { public boolean isComputed() {
return DeclarationFlags.isComputed(flags); return DeclarationFlags.isComputed(flags);
} }
/** Returns true if this is an abstract member. */ /** Returns true if this is an abstract member. */
public boolean isAbstract() { public boolean isAbstract() {
return DeclarationFlags.isAbstract(flags); return DeclarationFlags.isAbstract(flags);
} }
/** /** Returns true if has the <tt>public</tt> modifier (not true for implicitly public members). */
* Returns true if has the <tt>public</tt> modifier (not true for implicitly public boolean hasPublicKeyword() {
* public members). return DeclarationFlags.isPublic(flags);
*/ }
public boolean hasPublicKeyword() {
return DeclarationFlags.isPublic(flags);
}
/** Returns true if this is a private member. */ /** Returns true if this is a private member. */
public boolean hasPrivateKeyword() { public boolean hasPrivateKeyword() {
return DeclarationFlags.isPrivate(flags); return DeclarationFlags.isPrivate(flags);
} }
/** Returns true if this is a protected member. */ /** Returns true if this is a protected member. */
public boolean hasProtectedKeyword() { public boolean hasProtectedKeyword() {
return DeclarationFlags.isProtected(flags); return DeclarationFlags.isProtected(flags);
} }
/** Returns true if this is a readonly member. */ /** Returns true if this is a readonly member. */
public boolean hasReadonlyKeyword() { public boolean hasReadonlyKeyword() {
return DeclarationFlags.isReadonly(flags); return DeclarationFlags.isReadonly(flags);
} }
/** /**
* Returns the expression denoting the name of the member, or {@code null} if * Returns the expression denoting the name of the member, or {@code null} if this is a
* this is a call/construct signature. * call/construct signature.
*/ */
public Expression getKey() { public Expression getKey() {
return key; return key;
} }
public V getValue() { public V getValue() {
return value; return value;
} }
/** The name of the method, if it can be determined. */ /** The name of the method, if it can be determined. */
public String getName() { public String getName() {
if (!isComputed() && key instanceof Identifier) if (!isComputed() && key instanceof Identifier) return ((Identifier) key).getName();
return ((Identifier)key).getName(); if (key instanceof Literal) return ((Literal) key).getStringValue();
if (key instanceof Literal) return null;
return ((Literal)key).getStringValue(); }
return null;
}
/** True if this is a constructor; does not hold for construct signatures. */ /** True if this is a constructor; does not hold for construct signatures. */
public boolean isConstructor() { public boolean isConstructor() {
return false; return false;
} }
/** True if this is a non-abstract field or a method with a body. */ /** True if this is a non-abstract field or a method with a body. */
public abstract boolean isConcrete(); public abstract boolean isConcrete();
public boolean isCallSignature() { public boolean isCallSignature() {
return false; return false;
} }
public boolean isIndexSignature() { public boolean isIndexSignature() {
return false; return false;
} }
public void addDecorators(List<Decorator> decorators) { public void addDecorators(List<Decorator> decorators) {
this.decorators.addAll(decorators); this.decorators.addAll(decorators);
} }
public List<Decorator> getDecorators() { public List<Decorator> getDecorators() {
return this.decorators; return this.decorators;
} }
public boolean isParameterField() { public boolean isParameterField() {
return false; return false;
} }
} }

View File

@@ -3,69 +3,70 @@ package com.semmle.js.ast;
import com.semmle.ts.ast.INodeWithSymbol; import com.semmle.ts.ast.INodeWithSymbol;
import com.semmle.ts.ast.ITypeExpression; import com.semmle.ts.ast.ITypeExpression;
/** /** A member expression, either computed (<code>e[f]</code>) or static (<code>e.f</code>). */
* A member expression, either computed (<code>e[f]</code>) or static (<code>e.f</code>). public class MemberExpression extends Expression
*/ implements ITypeExpression, INodeWithSymbol, Chainable {
public class MemberExpression extends Expression implements ITypeExpression, INodeWithSymbol, Chainable { private final Expression object, property;
private final Expression object, property; private final boolean computed;
private final boolean computed; private final boolean optional;
private final boolean optional; private final boolean onOptionalChain;
private final boolean onOptionalChain; private int symbol = -1;
private int symbol = -1;
public MemberExpression(SourceLocation loc, Expression object, Expression property, Boolean computed, Boolean optional, Boolean onOptionalChain) { public MemberExpression(
super("MemberExpression", loc); SourceLocation loc,
this.object = object; Expression object,
this.property = property; Expression property,
this.computed = computed == Boolean.TRUE; Boolean computed,
this.optional = optional == Boolean.TRUE; Boolean optional,
this.onOptionalChain = onOptionalChain == Boolean.TRUE; Boolean onOptionalChain) {
} super("MemberExpression", loc);
this.object = object;
this.property = property;
this.computed = computed == Boolean.TRUE;
this.optional = optional == Boolean.TRUE;
this.onOptionalChain = onOptionalChain == Boolean.TRUE;
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The base expression of this member expression. */
* The base expression of this member expression. public Expression getObject() {
*/ return object;
public Expression getObject() { }
return object;
}
/** /**
* The property expression of this member expression; for static member expressions this is always * The property expression of this member expression; for static member expressions this is always
* an {@link Identifier}. * an {@link Identifier}.
*/ */
public Expression getProperty() { public Expression getProperty() {
return property; return property;
} }
/** /** Is this a computed member expression? */
* Is this a computed member expression? public boolean isComputed() {
*/ return computed;
public boolean isComputed() { }
return computed;
}
@Override @Override
public boolean isOptional() { public boolean isOptional() {
return optional; return optional;
} }
@Override @Override
public boolean isOnOptionalChain() { public boolean isOnOptionalChain() {
return onOptionalChain; return onOptionalChain;
} }
@Override @Override
public int getSymbol() { public int getSymbol() {
return symbol; return symbol;
} }
@Override @Override
public void setSymbol(int symbol) { public void setSymbol(int symbol) {
this.symbol = symbol; this.symbol = symbol;
} }
} }

View File

@@ -3,30 +3,28 @@ package com.semmle.js.ast;
/** /**
* A meta property access (cf. ECMAScript 2015 Language Specification, Chapter 12.3.8). * A meta property access (cf. ECMAScript 2015 Language Specification, Chapter 12.3.8).
* *
* <p> * <p>Currently the only recognised meta properties are <code>new.target</code> and <code>
* Currently the only recognised meta properties are <code>new.target</code> and * function.sent</code>.
* <code>function.sent</code>.
* </p>
*/ */
public class MetaProperty extends Expression { public class MetaProperty extends Expression {
private final Identifier meta, property; private final Identifier meta, property;
public MetaProperty(SourceLocation loc, Identifier meta, Identifier property) { public MetaProperty(SourceLocation loc, Identifier meta, Identifier property) {
super("MetaProperty", loc); super("MetaProperty", loc);
this.meta = meta; this.meta = meta;
this.property = property; this.property = property;
} }
public Identifier getMeta() { public Identifier getMeta() {
return meta; return meta;
} }
public Identifier getProperty() { public Identifier getProperty() {
return property; return property;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -4,62 +4,73 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class MethodDefinition extends MemberDefinition<FunctionExpression> { public class MethodDefinition extends MemberDefinition<FunctionExpression> {
public enum Kind { public enum Kind {
CONSTRUCTOR, METHOD, GET, SET, FUNCTION_CALL_SIGNATURE, CONSTRUCTOR_CALL_SIGNATURE, INDEX_SIGNATURE CONSTRUCTOR,
}; METHOD,
GET,
SET,
FUNCTION_CALL_SIGNATURE,
CONSTRUCTOR_CALL_SIGNATURE,
INDEX_SIGNATURE
};
private final Kind kind; private final Kind kind;
private final List<FieldDefinition> parameterFields; private final List<FieldDefinition> parameterFields;
public MethodDefinition(SourceLocation loc, int flags, Kind kind, Expression key, FunctionExpression value) { public MethodDefinition(
this(loc, flags, kind, key, value, new ArrayList<>()); SourceLocation loc, int flags, Kind kind, Expression key, FunctionExpression value) {
} this(loc, flags, kind, key, value, new ArrayList<>());
}
public MethodDefinition(SourceLocation loc, int flags, Kind kind, Expression key, FunctionExpression value, public MethodDefinition(
List<FieldDefinition> parameterFields) { SourceLocation loc,
super("MethodDefinition", loc, flags, key, value); int flags,
this.kind = kind; Kind kind,
this.parameterFields = parameterFields; Expression key,
} FunctionExpression value,
List<FieldDefinition> parameterFields) {
super("MethodDefinition", loc, flags, key, value);
this.kind = kind;
this.parameterFields = parameterFields;
}
public Kind getKind() {
return kind;
}
public Kind getKind() { @Override
return kind; public boolean isCallSignature() {
} return kind == Kind.FUNCTION_CALL_SIGNATURE || kind == Kind.CONSTRUCTOR_CALL_SIGNATURE;
}
@Override @Override
public boolean isCallSignature() { public boolean isIndexSignature() {
return kind == Kind.FUNCTION_CALL_SIGNATURE || kind == Kind.CONSTRUCTOR_CALL_SIGNATURE; return kind == Kind.INDEX_SIGNATURE;
} }
@Override @Override
public boolean isIndexSignature() { public boolean isConstructor() {
return kind == Kind.INDEX_SIGNATURE; return !isStatic() && !isComputed() && "constructor".equals(getName());
} }
@Override @Override
public boolean isConstructor() { public boolean isConcrete() {
return !isStatic() && !isComputed() && "constructor".equals(getName()); return getValue().getBody() != null;
} }
@Override @Override
public boolean isConcrete() { public <C, R> R accept(Visitor<C, R> v, C c) {
return getValue().getBody() != null; return v.visit(this, c);
} }
@Override /**
public <C, R> R accept(Visitor<C, R> v, C c) { * Returns the parameter fields synthesized for initializing constructor parameters, if this is a
return v.visit(this, c); * constructor, or an empty list otherwise.
} *
* <p>The index in this list does not correspond to the parameter index, as there can be ordinary
/** * parameters interleaved with parameter fields.
* Returns the parameter fields synthesized for initializing constructor */
* parameters, if this is a constructor, or an empty list otherwise. public List<FieldDefinition> getParameterFields() {
* <p> return parameterFields;
* The index in this list does not correspond to the parameter index, as there }
* can be ordinary parameters interleaved with parameter fields.
*/
public List<FieldDefinition> getParameterFields() {
return parameterFields;
}
} }

View File

@@ -1,19 +1,20 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import com.semmle.ts.ast.ITypeExpression;
import java.util.List; import java.util.List;
import com.semmle.ts.ast.ITypeExpression; /** A <code>new</code> expression. */
/**
* A <code>new</code> expression.
*/
public class NewExpression extends InvokeExpression { public class NewExpression extends InvokeExpression {
public NewExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments) { public NewExpression(
super("NewExpression", loc, callee, typeArguments, arguments, false, false); SourceLocation loc,
} Expression callee,
List<ITypeExpression> typeArguments,
List<Expression> arguments) {
super("NewExpression", loc, callee, typeArguments, arguments, false, false);
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
} }

View File

@@ -1,17 +1,15 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** Common superclass of all AST node types. */
* Common superclass of all AST node types.
*/
public abstract class Node extends SourceElement implements INode { public abstract class Node extends SourceElement implements INode {
private final String type; private final String type;
public Node(String type, SourceLocation loc) { public Node(String type, SourceLocation loc) {
super(loc); super(loc);
this.type = type; this.type = type;
} }
public final String getType() { public final String getType() {
return type; return type;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -2,26 +2,22 @@ package com.semmle.js.ast;
import java.util.List; import java.util.List;
/** /** An object literal. */
* An object literal.
*/
public class ObjectExpression extends Expression { public class ObjectExpression extends Expression {
private final List<Property> properties; private final List<Property> properties;
public ObjectExpression(SourceLocation loc, List<Property> properties) { public ObjectExpression(SourceLocation loc, List<Property> properties) {
super("ObjectExpression", loc); super("ObjectExpression", loc);
this.properties = properties; this.properties = properties;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The properties in this literal. */
* The properties in this literal. public List<Property> getProperties() {
*/ return properties;
public List<Property> getProperties() { }
return properties;
}
} }

View File

@@ -3,60 +3,52 @@ package com.semmle.js.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /** An object pattern. */
* An object pattern.
*/
public class ObjectPattern extends Expression implements DestructuringPattern { public class ObjectPattern extends Expression implements DestructuringPattern {
private final List<Property> rawProperties, properties; private final List<Property> rawProperties, properties;
private final Expression restPattern; private final Expression restPattern;
public ObjectPattern(SourceLocation loc, List<Property> properties) { public ObjectPattern(SourceLocation loc, List<Property> properties) {
super("ObjectPattern", loc); super("ObjectPattern", loc);
this.rawProperties = properties; this.rawProperties = properties;
this.properties = new ArrayList<Property>(properties.size()); this.properties = new ArrayList<Property>(properties.size());
Expression rest = null; Expression rest = null;
for (Property prop : properties) { for (Property prop : properties) {
Expression val = prop.getValue(); Expression val = prop.getValue();
if (val instanceof RestElement) { if (val instanceof RestElement) {
rest = ((RestElement)val).getArgument(); rest = ((RestElement) val).getArgument();
} else { } else {
this.properties.add(prop); this.properties.add(prop);
} }
} }
this.restPattern = rest; this.restPattern = rest;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The property patterns in this literal. */
* The property patterns in this literal. public List<Property> getProperties() {
*/ return properties;
public List<Property> getProperties() { }
return properties;
}
/** /** Does this object pattern have a rest pattern? */
* Does this object pattern have a rest pattern? public boolean hasRest() {
*/ return restPattern != null;
public boolean hasRest() { }
return restPattern != null;
}
/** /** The rest pattern of this literal, if any. */
* The rest pattern of this literal, if any. public Expression getRest() {
*/ return restPattern;
public Expression getRest() { }
return restPattern;
}
/** /**
* The raw property patterns in this literal; the rest * The raw property patterns in this literal; the rest pattern (if any) is represented as a {@link
* pattern (if any) is represented as a {@link RestElement}. * RestElement}.
*/ */
public List<Property> getRawProperties() { public List<Property> getRawProperties() {
return rawProperties; return rawProperties;
} }
} }

View File

@@ -1,30 +1,26 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A parenthesized expression. */
* A parenthesized expression.
*/
public class ParenthesizedExpression extends Expression { public class ParenthesizedExpression extends Expression {
private final Expression expression; private final Expression expression;
public ParenthesizedExpression(SourceLocation loc, Expression expression) { public ParenthesizedExpression(SourceLocation loc, Expression expression) {
super("ParenthesizedExpression", loc); super("ParenthesizedExpression", loc);
this.expression = expression; this.expression = expression;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The expression between parentheses. */
* The expression between parentheses. public Expression getExpression() {
*/ return expression;
public Expression getExpression() { }
return expression;
}
@Override @Override
public Expression stripParens() { public Expression stripParens() {
return expression.stripParens(); return expression.stripParens();
} }
} }

View File

@@ -1,81 +1,65 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A source position identifying a single character. */
* A source position identifying a single character.
*/
public class Position implements Comparable<Position> { public class Position implements Comparable<Position> {
private final int line, column, offset; private final int line, column, offset;
public Position(int line, int column, int offset) { public Position(int line, int column, int offset) {
this.line = line; this.line = line;
this.column = column; this.column = column;
this.offset = offset; this.offset = offset;
} }
/** /** The line number (1-based) of this position. */
* The line number (1-based) of this position. public int getLine() {
*/ return line;
public int getLine() { }
return line;
}
/** /** The column number (1-based) of this position. */
* The column number (1-based) of this position. public int getColumn() {
*/ return column;
public int getColumn() { }
return column;
}
/** /**
* The offset (0-based) of this position from the start * The offset (0-based) of this position from the start of the file, that is, the number of
* of the file, that is, the number of characters that * characters that precede it.
* precede it. */
*/ public int getOffset() {
public int getOffset() { return offset;
return offset; }
}
@Override @Override
public int compareTo(Position that) { public int compareTo(Position that) {
if (this.line < that.line) if (this.line < that.line) return -1;
return -1; if (this.line == that.line)
if (this.line == that.line) if (this.column < that.column) return -1;
if (this.column < that.column) else if (this.column == that.column) return 0;
return -1; else return 1;
else if (this.column == that.column) return 1;
return 0; }
else
return 1;
return 1;
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + column; result = prime * result + column;
result = prime * result + line; result = prime * result + line;
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj) return true;
return true; if (obj == null) return false;
if (obj == null) if (getClass() != obj.getClass()) return false;
return false; Position other = (Position) obj;
if (getClass() != obj.getClass()) if (column != other.column) return false;
return false; if (line != other.line) return false;
Position other = (Position) obj; return true;
if (column != other.column) }
return false;
if (line != other.line)
return false;
return true;
}
@Override @Override
public String toString() { public String toString() {
return line + ":" + column; return line + ":" + column;
} }
} }

View File

@@ -1,44 +1,39 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import com.semmle.ts.ast.INodeWithSymbol;
import java.util.List; import java.util.List;
import com.semmle.ts.ast.INodeWithSymbol; /** A top-level program entity forming the root of an AST. */
/**
* A top-level program entity forming the root of an AST.
*/
public class Program extends Node implements IStatementContainer, INodeWithSymbol { public class Program extends Node implements IStatementContainer, INodeWithSymbol {
private final List<Statement> body; private final List<Statement> body;
private final String sourceType; private final String sourceType;
private int symbolId = -1; private int symbolId = -1;
public Program(SourceLocation loc, List<Statement> body, String sourceType) { public Program(SourceLocation loc, List<Statement> body, String sourceType) {
super("Program", loc); super("Program", loc);
this.body = body; this.body = body;
this.sourceType = sourceType; this.sourceType = sourceType;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The statements in this program. */
* The statements in this program. public List<Statement> getBody() {
*/ return body;
public List<Statement> getBody() { }
return body;
}
public String getSourceType() { public String getSourceType() {
return sourceType; return sourceType;
} }
public int getSymbol() { public int getSymbol() {
return this.symbolId; return this.symbolId;
} }
public void setSymbol(int symbolId) { public void setSymbol(int symbolId) {
this.symbolId = symbolId; this.symbolId = symbolId;
} }
} }

View File

@@ -1,137 +1,131 @@
package com.semmle.js.ast; package com.semmle.js.ast;
import com.semmle.util.data.StringUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.semmle.util.data.StringUtil;
/** /**
* A property in an object literal or an object pattern. * A property in an object literal or an object pattern.
* *
* This includes both regular properties as well as accessor properties, method properties, * <p>This includes both regular properties as well as accessor properties, method properties,
* properties with computed names, and spread/rest properties. * properties with computed names, and spread/rest properties.
*/ */
public class Property extends Node { public class Property extends Node {
public static enum Kind { public static enum Kind {
/** Either a normal property or a spread/rest property. */ /** Either a normal property or a spread/rest property. */
INIT(false), INIT(false),
/** Getter property. */ /** Getter property. */
GET(true), GET(true),
/** Setter property. */ /** Setter property. */
SET(true); SET(true);
public final boolean isAccessor; public final boolean isAccessor;
private Kind(boolean isAccessor) { private Kind(boolean isAccessor) {
this.isAccessor = isAccessor; this.isAccessor = isAccessor;
} }
}; };
private final Expression key; private final Expression key;
private final Expression value, rawValue; private final Expression value, rawValue;
private final Expression defaultValue; // only applies to property patterns private final Expression defaultValue; // only applies to property patterns
private final Kind kind; private final Kind kind;
private final boolean computed, method; private final boolean computed, method;
private final List<Decorator> decorators; private final List<Decorator> decorators;
public Property(SourceLocation loc, Expression key, Expression rawValue, String kind, Boolean computed, Boolean method) { public Property(
super("Property", loc); SourceLocation loc,
this.key = key; Expression key,
if (rawValue instanceof AssignmentPattern) { Expression rawValue,
AssignmentPattern ap = (AssignmentPattern) rawValue; String kind,
if (ap.getLeft() == key) Boolean computed,
rawValue = ap = new AssignmentPattern(ap.getLoc(), ap.getOperator(), new NodeCopier().copy(key), ap.getRight()); Boolean method) {
this.value = ap.getLeft(); super("Property", loc);
this.defaultValue = ap.getRight(); this.key = key;
} else { if (rawValue instanceof AssignmentPattern) {
this.value = rawValue == key ? new NodeCopier().copy(rawValue) : rawValue; AssignmentPattern ap = (AssignmentPattern) rawValue;
this.defaultValue = null; if (ap.getLeft() == key)
} rawValue =
this.rawValue = rawValue; ap =
this.kind = Kind.valueOf(StringUtil.uc(kind)); new AssignmentPattern(
this.computed = computed == Boolean.TRUE; ap.getLoc(), ap.getOperator(), new NodeCopier().copy(key), ap.getRight());
this.method = method == Boolean.TRUE; this.value = ap.getLeft();
this.decorators = new ArrayList<Decorator>(); this.defaultValue = ap.getRight();
} } else {
this.value = rawValue == key ? new NodeCopier().copy(rawValue) : rawValue;
this.defaultValue = null;
}
this.rawValue = rawValue;
this.kind = Kind.valueOf(StringUtil.uc(kind));
this.computed = computed == Boolean.TRUE;
this.method = method == Boolean.TRUE;
this.decorators = new ArrayList<Decorator>();
}
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /**
* The key of this property; usually a {@link Literal} or an {@link Identifier}, but may * The key of this property; usually a {@link Literal} or an {@link Identifier}, but may be an
* be an arbitrary expression for properties with computed names. For spread/rest properties * arbitrary expression for properties with computed names. For spread/rest properties this method
* this method returns {@code null}. * returns {@code null}.
*/ */
public Expression getKey() { public Expression getKey() {
return key; return key;
} }
/** /** The value expression of this property. */
* The value expression of this property. public Expression getValue() {
*/ return value;
public Expression getValue() { }
return value;
}
/** /** The default value of this property pattern. */
* The default value of this property pattern. public Expression getDefaultValue() {
*/ return defaultValue;
public Expression getDefaultValue() { }
return defaultValue;
}
/** /** Is this a property pattern with a default value? */
* Is this a property pattern with a default value? public boolean hasDefaultValue() {
*/ return defaultValue != null;
public boolean hasDefaultValue() { }
return defaultValue != null;
}
/** /** The kind of this property. */
* The kind of this property. public Kind getKind() {
*/ return kind;
public Kind getKind() { }
return kind;
}
/** /** Is the name of this property computed? */
* Is the name of this property computed? public boolean isComputed() {
*/ return computed;
public boolean isComputed() { }
return computed;
}
/** /** Is this property declared using method syntax? */
* Is this property declared using method syntax? public boolean isMethod() {
*/ return method;
public boolean isMethod() { }
return method;
}
/** /** Is this property declared using shorthand syntax? */
* Is this property declared using shorthand syntax? public boolean isShorthand() {
*/ return key != null && key.getLoc().equals(value.getLoc());
public boolean isShorthand() { }
return key != null && key.getLoc().equals(value.getLoc());
}
/** /**
* The raw value expression of this property; if this property is a property * The raw value expression of this property; if this property is a property pattern with a
* pattern with a default value, this method returns an {@link AssignmentPattern}. * default value, this method returns an {@link AssignmentPattern}.
*/ */
public Expression getRawValue() { public Expression getRawValue() {
return rawValue; return rawValue;
} }
public void addDecorators(List<Decorator> decorators) { public void addDecorators(List<Decorator> decorators) {
this.decorators.addAll(decorators); this.decorators.addAll(decorators);
} }
public List<Decorator> getDecorators() { public List<Decorator> getDecorators() {
return this.decorators; return this.decorators;
} }
} }

View File

@@ -3,27 +3,25 @@ package com.semmle.js.ast;
/** /**
* A rest element <code>...xs</code> in lvalue position. * A rest element <code>...xs</code> in lvalue position.
* *
* Rest elements can only appear as part of a function's parameter list or in an array * <p>Rest elements can only appear as part of a function's parameter list or in an array pattern;
* pattern; they are rewritten away by the constructors of {@linkplain AFunction} and * they are rewritten away by the constructors of {@linkplain AFunction} and {@link ArrayPattern},
* {@link ArrayPattern}, and don't appear in the AST the extractor works on. * and don't appear in the AST the extractor works on.
*/ */
public class RestElement extends Expression implements IPattern { public class RestElement extends Expression implements IPattern {
private final Expression argument; private final Expression argument;
public RestElement(SourceLocation loc, Expression argument) { public RestElement(SourceLocation loc, Expression argument) {
super("RestElement", loc); super("RestElement", loc);
this.argument = argument; this.argument = argument;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The argument expression of this spread element. */
* The argument expression of this spread element. public Expression getArgument() {
*/ return argument;
public Expression getArgument() { }
return argument;
}
} }

View File

@@ -1,32 +1,26 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A return statement. */
* A return statement.
*/
public class ReturnStatement extends Statement { public class ReturnStatement extends Statement {
private final Expression argument; private final Expression argument;
public ReturnStatement(SourceLocation loc, Expression argument) { public ReturnStatement(SourceLocation loc, Expression argument) {
super("ReturnStatement", loc); super("ReturnStatement", loc);
this.argument = argument; this.argument = argument;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** Does this return statement have an argument expression? */
* Does this return statement have an argument expression? public boolean hasArgument() {
*/ return argument != null;
public boolean hasArgument() { }
return argument != null;
}
/** /** The argument expression of this return statement; may be null. */
* The argument expression of this return statement; may be null. public Expression getArgument() {
*/ return argument;
public Expression getArgument() { }
return argument;
}
} }

View File

@@ -2,26 +2,22 @@ package com.semmle.js.ast;
import java.util.List; import java.util.List;
/** /** A comma expression containing two or more expressions evaluated in sequence. */
* A comma expression containing two or more expressions evaluated in sequence.
*/
public class SequenceExpression extends Expression { public class SequenceExpression extends Expression {
private final List<Expression> expressions; private final List<Expression> expressions;
public SequenceExpression(SourceLocation loc, List<Expression> expressions) { public SequenceExpression(SourceLocation loc, List<Expression> expressions) {
super("SequenceExpression", loc); super("SequenceExpression", loc);
this.expressions = expressions; this.expressions = expressions;
} }
@Override @Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) { public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q); return v.visit(this, q);
} }
/** /** The expressions in this sequence. */
* The expressions in this sequence. public List<Expression> getExpressions() {
*/ return expressions;
public List<Expression> getExpressions() { }
return expressions;
}
} }

View File

@@ -1,21 +1,19 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** Common superclass of all source elements. */
* Common superclass of all source elements.
*/
public class SourceElement implements ISourceElement { public class SourceElement implements ISourceElement {
private final SourceLocation loc; private final SourceLocation loc;
public SourceElement(SourceLocation loc) { public SourceElement(SourceLocation loc) {
this.loc = loc; this.loc = loc;
} }
public boolean hasLoc() { public boolean hasLoc() {
return loc != null; return loc != null;
} }
@Override @Override
public final SourceLocation getLoc() { public final SourceLocation getLoc() {
return loc; return loc;
} }
} }

View File

@@ -1,100 +1,79 @@
package com.semmle.js.ast; package com.semmle.js.ast;
/** /** A source location representing a range of characters. */
* A source location representing a range of characters.
*/
public class SourceLocation { public class SourceLocation {
private String source; private String source;
private Position start, end; private Position start, end;
public SourceLocation(String source, Position start, Position end) { public SourceLocation(String source, Position start, Position end) {
this.source = source; this.source = source;
this.start = start; this.start = start;
this.end = end; this.end = end;
} }
public SourceLocation(Position start) { public SourceLocation(Position start) {
this(null, start, null); this(null, start, null);
} }
public SourceLocation(String source, Position start) { public SourceLocation(String source, Position start) {
this(source, start, null); this(source, start, null);
} }
public SourceLocation(SourceLocation that) { public SourceLocation(SourceLocation that) {
this(that.source, that.start, that.end); this(that.source, that.start, that.end);
} }
/** /** The source code contained in this location. */
* The source code contained in this location. public String getSource() {
*/ return source;
public String getSource() { }
return source;
}
/** /** Set the source code contain in this location. */
* Set the source code contain in this location. public void setSource(String source) {
*/ this.source = source;
public void setSource(String source) { }
this.source = source;
}
/** /** The start position of the location. */
* The start position of the location. public Position getStart() {
*/ return start;
public Position getStart() { }
return start;
}
/** /** Set the start position of this location. */
* Set the start position of this location. public void setStart(Position start) {
*/ this.start = start;
public void setStart(Position start) { }
this.start = start;
}
/** /** The end position of the location. */
* The end position of the location. public Position getEnd() {
*/ return end;
public Position getEnd() { }
return end;
}
/** /** Set the end position of this location. */
* Set the end position of this location. public void setEnd(Position end) {
*/ this.end = end;
public void setEnd(Position end) { }
this.end = end;
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((end == null) ? 0 : end.hashCode()); result = prime * result + ((end == null) ? 0 : end.hashCode());
result = prime * result + ((start == null) ? 0 : start.hashCode()); result = prime * result + ((start == null) ? 0 : start.hashCode());
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj) return true;
return true; if (obj == null) return false;
if (obj == null) if (getClass() != obj.getClass()) return false;
return false; SourceLocation other = (SourceLocation) obj;
if (getClass() != obj.getClass()) if (end == null) {
return false; if (other.end != null) return false;
SourceLocation other = (SourceLocation) obj; } else if (!end.equals(other.end)) return false;
if (end == null) { if (start == null) {
if (other.end != null) if (other.start != null) return false;
return false; } else if (!start.equals(other.start)) return false;
} else if (!end.equals(other.end)) return true;
return false; }
if (start == null) {
if (other.start != null)
return false;
} else if (!start.equals(other.start))
return false;
return true;
}
} }

Some files were not shown because too many files have changed in this diff Show More