mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
Merge master into next.
JavaScript semantic conflicts fixed by referring to the `LegacyLanguage` enum. C++ conflicts fixed by accepting Qltest output.
This commit is contained in:
323
javascript/extractor/src/com/semmle/jcorn/CustomParser.java
Normal file
323
javascript/extractor/src/com/semmle/jcorn/CustomParser.java
Normal file
@@ -0,0 +1,323 @@
|
||||
package com.semmle.jcorn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import com.semmle.jcorn.flow.FlowParser;
|
||||
import com.semmle.js.ast.ArrayExpression;
|
||||
import com.semmle.js.ast.AssignmentExpression;
|
||||
import com.semmle.js.ast.BlockStatement;
|
||||
import com.semmle.js.ast.CallExpression;
|
||||
import com.semmle.js.ast.CatchClause;
|
||||
import com.semmle.js.ast.ComprehensionBlock;
|
||||
import com.semmle.js.ast.ComprehensionExpression;
|
||||
import com.semmle.js.ast.Expression;
|
||||
import com.semmle.js.ast.ExpressionStatement;
|
||||
import com.semmle.js.ast.ForInStatement;
|
||||
import com.semmle.js.ast.FunctionDeclaration;
|
||||
import com.semmle.js.ast.IFunction;
|
||||
import com.semmle.js.ast.INode;
|
||||
import com.semmle.js.ast.IPattern;
|
||||
import com.semmle.js.ast.Identifier;
|
||||
import com.semmle.js.ast.LetExpression;
|
||||
import com.semmle.js.ast.LetStatement;
|
||||
import com.semmle.js.ast.MemberExpression;
|
||||
import com.semmle.js.ast.NewExpression;
|
||||
import com.semmle.js.ast.Node;
|
||||
import com.semmle.js.ast.Position;
|
||||
import com.semmle.js.ast.SourceLocation;
|
||||
import com.semmle.js.ast.Statement;
|
||||
import com.semmle.js.ast.TryStatement;
|
||||
import com.semmle.js.ast.VariableDeclaration;
|
||||
import com.semmle.util.data.Pair;
|
||||
|
||||
/**
|
||||
* An extension of the standard jcorn parser with support for Mozilla-specific
|
||||
* language extension (most of JavaScript 1.8.5) and JScript language extensions.
|
||||
*/
|
||||
public class CustomParser extends FlowParser {
|
||||
public CustomParser(Options options, String input, int startPos) {
|
||||
super(options, input, startPos);
|
||||
|
||||
// recognise `const` as a keyword, irrespective of options.ecmaVersion
|
||||
this.keywords.add("const");
|
||||
}
|
||||
|
||||
// add parsing of guarded `catch` clauses
|
||||
@Override
|
||||
protected TryStatement parseTryStatement(Position startLoc) {
|
||||
if (!options.mozExtensions())
|
||||
return super.parseTryStatement(startLoc);
|
||||
|
||||
this.next();
|
||||
BlockStatement block = this.parseBlock(false);
|
||||
CatchClause handler = null;
|
||||
List<CatchClause> guardedHandlers = new ArrayList<CatchClause>();
|
||||
while (this.type == TokenType._catch) {
|
||||
Position catchStartLoc = this.startLoc;
|
||||
CatchClause katch = this.parseCatchClause(catchStartLoc);
|
||||
if (handler != null)
|
||||
this.raise(catchStartLoc, "Catch after unconditional catch");
|
||||
if (katch.getGuard() != null)
|
||||
guardedHandlers.add(katch);
|
||||
else
|
||||
handler = katch;
|
||||
}
|
||||
BlockStatement finalizer = this.eat(TokenType._finally) ? this.parseBlock(false) : null;
|
||||
if (handler == null && finalizer == null && guardedHandlers.isEmpty())
|
||||
this.raise(startLoc, "Missing catch or finally clause");
|
||||
return this.finishNode(new TryStatement(new SourceLocation(startLoc), block, handler, guardedHandlers, finalizer));
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for guarded `catch` clauses and omitted catch bindings.
|
||||
*/
|
||||
@Override
|
||||
protected CatchClause parseCatchClause(Position startLoc) {
|
||||
if (!options.mozExtensions())
|
||||
return super.parseCatchClause(startLoc);
|
||||
|
||||
this.next();
|
||||
Expression param = null;
|
||||
Expression guard = null;
|
||||
if (this.eat(TokenType.parenL)) {
|
||||
param = this.parseBindingAtom();
|
||||
this.checkLVal(param, true, null);
|
||||
if (this.eat(TokenType._if))
|
||||
guard = this.parseExpression(false, null);
|
||||
this.expect(TokenType.parenR);
|
||||
} else if (!options.esnext()) {
|
||||
this.unexpected();
|
||||
}
|
||||
BlockStatement catchBody = this.parseBlock(false);
|
||||
return this.finishNode(new CatchClause(new SourceLocation(startLoc), (IPattern)param, guard, catchBody));
|
||||
}
|
||||
|
||||
// add parsing of `let` statements and expressions
|
||||
@Override
|
||||
protected boolean mayFollowLet(int c) {
|
||||
return options.mozExtensions() && c == '(' || super.mayFollowLet(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Statement parseVarStatement(Position startLoc, String kind) {
|
||||
if (!options.mozExtensions())
|
||||
return super.parseVarStatement(startLoc, kind);
|
||||
|
||||
this.next();
|
||||
|
||||
if ("let".equals(kind) && this.eat(TokenType.parenL)) {
|
||||
// this is a `let` statement or expression
|
||||
return (LetStatement) this.parseLetExpression(startLoc, true);
|
||||
}
|
||||
|
||||
VariableDeclaration node = this.parseVar(startLoc, false, kind);
|
||||
this.semicolon();
|
||||
return this.finishNode(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Expression parseExprAtom(DestructuringErrors refDestructuringErrors) {
|
||||
Position startLoc = this.startLoc;
|
||||
if (options.mozExtensions() && this.isContextual("let")) {
|
||||
this.next();
|
||||
this.expect(TokenType.parenL);
|
||||
return (Expression) this.parseLetExpression(startLoc, false);
|
||||
} else if (options.mozExtensions() && this.type == TokenType.bracketL) {
|
||||
this.next();
|
||||
// check whether this is array comprehension or regular array
|
||||
if (this.type == TokenType._for) {
|
||||
return (Expression) this.parseComprehension(startLoc, false, null);
|
||||
}
|
||||
List<Expression> elements;
|
||||
if (this.type == TokenType.comma || this.type == TokenType.bracketR ||
|
||||
this.type == TokenType.ellipsis) {
|
||||
elements = this.parseExprList(TokenType.bracketR, true, true, refDestructuringErrors);
|
||||
} else {
|
||||
Expression firstExpr = this.parseMaybeAssign(true, refDestructuringErrors, null);
|
||||
// check whether this is a postfix array comprehension
|
||||
if (this.type == TokenType._for || this.type == TokenType._if) {
|
||||
return (Expression) this.parseComprehension(startLoc, false, firstExpr);
|
||||
} else {
|
||||
this.eat(TokenType.comma);
|
||||
elements = new ArrayList<Expression>();
|
||||
elements.add(firstExpr);
|
||||
elements.addAll(this.parseExprList(TokenType.bracketR, true, true, refDestructuringErrors));
|
||||
}
|
||||
}
|
||||
return this.finishNode(new ArrayExpression(new SourceLocation(startLoc), elements));
|
||||
} else if (options.v8Extensions() && this.type == TokenType.modulo) {
|
||||
// parse V8 native
|
||||
this.next();
|
||||
Identifier name = this.parseIdent(true);
|
||||
this.expect(TokenType.parenL);
|
||||
List<Expression> args = this.parseExprList(TokenType.parenR, false, false, null);
|
||||
CallExpression node = new CallExpression(new SourceLocation(startLoc), name, new ArrayList<>(), args);
|
||||
return this.finishNode(node);
|
||||
} else {
|
||||
return super.parseExprAtom(refDestructuringErrors);
|
||||
}
|
||||
}
|
||||
|
||||
protected Node parseLetExpression(Position startLoc, boolean maybeStatement) {
|
||||
// this method assumes that the keyword `let` and the opening parenthesis have already been
|
||||
// consumed
|
||||
VariableDeclaration decl = this.parseVar(startLoc, false, "let");
|
||||
this.expect(TokenType.parenR);
|
||||
|
||||
if (this.type == TokenType.braceL) {
|
||||
if (!maybeStatement)
|
||||
this.unexpected();
|
||||
BlockStatement body = this.parseBlock(false);
|
||||
return this.finishNode(new LetStatement(new SourceLocation(startLoc), decl.getDeclarations(), body));
|
||||
} else if (maybeStatement) {
|
||||
Position pos = startLoc;
|
||||
Statement body = this.parseStatement(true, false);
|
||||
if (body == null)
|
||||
this.unexpected(pos);
|
||||
return this.finishNode(new LetStatement(new SourceLocation(startLoc), decl.getDeclarations(), body));
|
||||
} else {
|
||||
Expression body = this.parseExpression(false, null);
|
||||
return this.finishNode(new LetExpression(new SourceLocation(startLoc), decl.getDeclarations(), body));
|
||||
}
|
||||
}
|
||||
|
||||
// add parsing of expression closures and JScript methods
|
||||
@Override
|
||||
protected INode parseFunction(Position startLoc, boolean isStatement, boolean allowExpressionBody, boolean isAsync) {
|
||||
if (isFunctionSent(isStatement))
|
||||
return super.parseFunction(startLoc, isStatement, allowExpressionBody, isAsync);
|
||||
allowExpressionBody = allowExpressionBody || options.mozExtensions() && !isStatement;
|
||||
boolean oldInGen = this.inGenerator, oldInAsync = this.inAsync;
|
||||
int oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos;
|
||||
Pair<Boolean, Identifier> p = parseFunctionName(isStatement, isAsync);
|
||||
boolean generator = p.fst();
|
||||
Identifier id = p.snd(), iface = null;
|
||||
if (options.jscript()) {
|
||||
if (isStatement && this.eatDoubleColon()) {
|
||||
iface = p.snd();
|
||||
id = this.parseIdent(false);
|
||||
}
|
||||
}
|
||||
IFunction result = parseFunctionRest(startLoc, isStatement, allowExpressionBody, oldInGen, oldInAsync,
|
||||
oldYieldPos, oldAwaitPos, generator, id);
|
||||
if (iface != null) {
|
||||
/* Translate JScript double colon method declarations into normal method definitions:
|
||||
*
|
||||
* function A::f(...) { ... }
|
||||
*
|
||||
* becomes
|
||||
*
|
||||
* A.f = function f(...) { ... };
|
||||
*/
|
||||
SourceLocation memloc = new SourceLocation(iface.getName() + "::" + id.getName(), iface.getLoc().getStart(), id.getLoc().getEnd());
|
||||
MemberExpression mem = new MemberExpression(memloc, iface, new Identifier(id.getLoc(), id.getName()), false);
|
||||
AssignmentExpression assgn = new AssignmentExpression(result.getLoc(), "=", mem, ((FunctionDeclaration)result).asFunctionExpression());
|
||||
return new ExpressionStatement(result.getLoc(), assgn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean eatDoubleColon() {
|
||||
if (this.eat(TokenType.colon)) {
|
||||
this.expect(TokenType.colon);
|
||||
return true;
|
||||
} else {
|
||||
return this.eat(doubleColon);
|
||||
}
|
||||
}
|
||||
|
||||
// accept `yield` in non-generator functions
|
||||
@Override
|
||||
protected Expression parseMaybeAssign(boolean noIn,
|
||||
DestructuringErrors refDestructuringErrors,
|
||||
AfterLeftParse afterLeftParse) {
|
||||
if (options.mozExtensions() && isContextual("yield")) {
|
||||
if (!this.inFunction)
|
||||
this.raise(this.startLoc, "Yield not in function");
|
||||
return this.parseYield();
|
||||
}
|
||||
return super.parseMaybeAssign(noIn, refDestructuringErrors, afterLeftParse);
|
||||
}
|
||||
|
||||
// add parsing of comprehensions
|
||||
protected Node parseComprehension(Position startLoc, boolean isGenerator, Expression body) {
|
||||
List<ComprehensionBlock> blocks = new ArrayList<ComprehensionBlock>();
|
||||
while (this.type == TokenType._for) {
|
||||
SourceLocation blockStart = new SourceLocation(this.startLoc);
|
||||
this.next();
|
||||
this.expect(TokenType.parenL);
|
||||
Expression left = this.parseBindingAtom();
|
||||
this.checkLVal(left, true, null);
|
||||
boolean of;
|
||||
if (this.eatContextual("of")) {
|
||||
of = true;
|
||||
} else {
|
||||
this.expect(TokenType._in);
|
||||
of = false;
|
||||
}
|
||||
Expression right = this.parseExpression(false, null);
|
||||
this.expect(TokenType.parenR);
|
||||
blocks.add(this.finishNode(new ComprehensionBlock(blockStart, (IPattern)left, right, of)));
|
||||
}
|
||||
Expression filter = this.eat(TokenType._if) ? this.parseParenExpression() : null;
|
||||
if (body == null)
|
||||
body = this.parseExpression(false, null);
|
||||
this.expect(isGenerator ? TokenType.parenR : TokenType.bracketR);
|
||||
|
||||
return this.finishNode(new ComprehensionExpression(new SourceLocation(startLoc), body, blocks, filter, isGenerator));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Expression parseParenAndDistinguishExpression(boolean canBeArrow) {
|
||||
if (options.mozExtensions()) {
|
||||
// check whether next token is `for`, suggesting a generator comprehension
|
||||
Position startLoc = this.startLoc;
|
||||
Matcher m = Whitespace.skipWhiteSpace.matcher(this.input);
|
||||
if (m.find(this.pos)) {
|
||||
if (m.end()+3 < input.length() &&
|
||||
"for".equals(input.substring(m.end(), m.end()+3)) &&
|
||||
!Identifiers.isIdentifierChar(input.charAt(m.end()+3), true)) {
|
||||
next();
|
||||
return (Expression) parseComprehension(startLoc, true, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.parseParenAndDistinguishExpression(canBeArrow);
|
||||
}
|
||||
|
||||
// add parsing of for-each loops
|
||||
@Override
|
||||
protected Statement parseForStatement(Position startLoc) {
|
||||
boolean each = false;
|
||||
if (options.mozExtensions() && this.isContextual("each")) {
|
||||
this.next();
|
||||
each = true;
|
||||
}
|
||||
Position afterEach = this.startLoc;
|
||||
Statement result = super.parseForStatement(startLoc);
|
||||
if (each) {
|
||||
if (result instanceof ForInStatement) {
|
||||
ForInStatement fis = (ForInStatement) result;
|
||||
result = new ForInStatement(fis.getLoc(), fis.getLeft(), fis.getRight(), fis.getBody(), true);
|
||||
} else {
|
||||
raise(afterEach, "Bad for-each statement.");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// add parsing of Rhino/Nashorn-style `new` expressions with last argument after `)`
|
||||
@Override
|
||||
protected Expression parseNew() {
|
||||
Expression res = super.parseNew();
|
||||
if (res instanceof NewExpression &&
|
||||
options.mozExtensions() && !canInsertSemicolon() && this.type == TokenType.braceL) {
|
||||
((NewExpression) res).getArguments().add(this.parseObj(false, null));
|
||||
res = this.finishNode(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
485
javascript/extractor/src/com/semmle/jcorn/ESNextParser.java
Normal file
485
javascript/extractor/src/com/semmle/jcorn/ESNextParser.java
Normal file
@@ -0,0 +1,485 @@
|
||||
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.jsx.JSXParser;
|
||||
import com.semmle.js.ast.BindExpression;
|
||||
import com.semmle.js.ast.BlockStatement;
|
||||
import com.semmle.js.ast.CatchClause;
|
||||
import com.semmle.js.ast.ClassDeclaration;
|
||||
import com.semmle.js.ast.ClassExpression;
|
||||
import com.semmle.js.ast.DeclarationFlags;
|
||||
import com.semmle.js.ast.Decorator;
|
||||
import com.semmle.js.ast.DynamicImport;
|
||||
import com.semmle.js.ast.ExportDeclaration;
|
||||
import com.semmle.js.ast.ExportDefaultDeclaration;
|
||||
import com.semmle.js.ast.ExportDefaultSpecifier;
|
||||
import com.semmle.js.ast.ExportNamedDeclaration;
|
||||
import com.semmle.js.ast.ExportNamespaceSpecifier;
|
||||
import com.semmle.js.ast.ExportSpecifier;
|
||||
import com.semmle.js.ast.Expression;
|
||||
import com.semmle.js.ast.FieldDefinition;
|
||||
import com.semmle.js.ast.ForOfStatement;
|
||||
import com.semmle.js.ast.INode;
|
||||
import com.semmle.js.ast.IPattern;
|
||||
import com.semmle.js.ast.Identifier;
|
||||
import com.semmle.js.ast.Literal;
|
||||
import com.semmle.js.ast.MemberDefinition;
|
||||
import com.semmle.js.ast.MemberExpression;
|
||||
import com.semmle.js.ast.MetaProperty;
|
||||
import com.semmle.js.ast.Node;
|
||||
import com.semmle.js.ast.ObjectPattern;
|
||||
import com.semmle.js.ast.Position;
|
||||
import com.semmle.js.ast.Property;
|
||||
import com.semmle.js.ast.RestElement;
|
||||
import com.semmle.js.ast.SourceLocation;
|
||||
import com.semmle.js.ast.SpreadElement;
|
||||
import com.semmle.js.ast.Statement;
|
||||
import com.semmle.js.ast.Token;
|
||||
import com.semmle.util.collections.CollectionUtil;
|
||||
import com.semmle.util.data.Pair;
|
||||
|
||||
/**
|
||||
* An extension of the {@link JSXParser} with support for various
|
||||
* unfinished ECMAScript proposals that are not supported by
|
||||
* Acorn/jcorn yet.
|
||||
*
|
||||
* Once support becomes available, they should be removed from
|
||||
* this class.
|
||||
*/
|
||||
public class ESNextParser extends JSXParser {
|
||||
public ESNextParser(Options options, String input, int startPos) {
|
||||
super(options.allowImportExportEverywhere(true), input, startPos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Object Rest/Spread Properties"
|
||||
* (http://sebmarkbage.github.io/ecmascript-rest-spread/).
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected Property parseProperty(boolean isPattern, DestructuringErrors refDestructuringErrors,
|
||||
Map<String, PropInfo> propHash) {
|
||||
Position start = this.startLoc;
|
||||
|
||||
List<Decorator> decorators = parseDecorators();
|
||||
|
||||
Property prop = null;
|
||||
if (this.type == TokenType.ellipsis) {
|
||||
SpreadElement spread = this.parseSpread(null);
|
||||
Expression val;
|
||||
if (isPattern)
|
||||
val = new RestElement(spread.getLoc(), spread.getArgument());
|
||||
else
|
||||
val = spread;
|
||||
prop = this.finishNode(new Property(new SourceLocation(start), null, val, Property.Kind.INIT.name(), false, false));
|
||||
}
|
||||
|
||||
if (prop == null)
|
||||
prop = super.parseProperty(isPattern, refDestructuringErrors, propHash);
|
||||
|
||||
prop.addDecorators(decorators);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected INode toAssignable(INode node, boolean isBinding) {
|
||||
if (node instanceof SpreadElement)
|
||||
return new RestElement(node.getLoc(), ((SpreadElement) node).getArgument());
|
||||
return super.toAssignable(node, isBinding);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkLVal(INode expr, boolean isBinding, Set<String> checkClashes) {
|
||||
super.checkLVal(expr, isBinding, checkClashes);
|
||||
if (expr instanceof ObjectPattern) {
|
||||
ObjectPattern op = (ObjectPattern) expr;
|
||||
if (op.hasRest())
|
||||
checkLVal(op.getRest(), isBinding, checkClashes);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Public Class Fields"
|
||||
* (http://jeffmo.github.io/es-class-public-fields/).
|
||||
*/
|
||||
|
||||
private boolean classProperties() {
|
||||
return options.esnext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemberDefinition<?> parseClassPropertyBody(PropertyInfo pi,
|
||||
boolean hadConstructor, boolean isStatic) {
|
||||
if (classProperties() && !pi.isGenerator && this.isClassProperty())
|
||||
return this.parseFieldDefinition(pi, isStatic);
|
||||
return super.parseClassPropertyBody(pi, hadConstructor, isStatic);
|
||||
}
|
||||
|
||||
protected boolean isClassProperty() {
|
||||
return this.type == TokenType.eq || this.type == TokenType.semi || this.canInsertSemicolon();
|
||||
}
|
||||
|
||||
protected FieldDefinition parseFieldDefinition(PropertyInfo pi, boolean isStatic) {
|
||||
Expression value = null;
|
||||
if (this.type == TokenType.eq) {
|
||||
this.next();
|
||||
boolean oldInFunc = this.inFunction;
|
||||
this.inFunction = true;
|
||||
value = parseMaybeAssign(false, null, null);
|
||||
this.inFunction = oldInFunc;
|
||||
}
|
||||
this.semicolon();
|
||||
int flags = DeclarationFlags.getStatic(isStatic) | DeclarationFlags.getComputed(pi.computed);
|
||||
return this.finishNode(new FieldDefinition(new SourceLocation(pi.startLoc), flags, pi.key, value));
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Generator function.sent Meta Property"
|
||||
* (https://github.com/allenwb/ESideas/blob/master/Generator%20metaproperty.md)
|
||||
*/
|
||||
private boolean functionSent() {
|
||||
return options.esnext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected INode parseFunction(Position startLoc, boolean isStatement,
|
||||
boolean allowExpressionBody, boolean isAsync) {
|
||||
if (isFunctionSent(isStatement)) {
|
||||
Identifier meta = this.finishNode(new Identifier(new SourceLocation(startLoc), "function"));
|
||||
this.next();
|
||||
Identifier property = parseIdent(true);
|
||||
if (!property.getName().equals("sent"))
|
||||
this.raiseRecoverable(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);
|
||||
}
|
||||
|
||||
protected boolean isFunctionSent(boolean isStatement) {
|
||||
return functionSent() && !isStatement && inGenerator && !inAsync && this.type == TokenType.dot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Class and Property Decorators"
|
||||
* (https://github.com/wycats/javascript-decorators)
|
||||
*/
|
||||
private boolean decorators() {
|
||||
return options.esnext();
|
||||
}
|
||||
|
||||
protected TokenType at = new TokenType(new Properties("@").beforeExpr());
|
||||
|
||||
@Override
|
||||
protected Token getTokenFromCode(int code) {
|
||||
if (decorators() && code == 64) {
|
||||
++this.pos;
|
||||
return this.finishToken(at);
|
||||
}
|
||||
if (functionBind() && code == 58 && charAt(this.pos+1) == 58) {
|
||||
this.pos += 2;
|
||||
return this.finishToken(doubleColon);
|
||||
}
|
||||
return super.getTokenFromCode(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Statement parseStatement(boolean declaration, boolean topLevel,
|
||||
Set<String> exports) {
|
||||
List<Decorator> decorators = this.parseDecorators();
|
||||
Statement stmt = super.parseStatement(declaration, topLevel, exports);
|
||||
|
||||
if (!decorators.isEmpty()) {
|
||||
if (stmt instanceof ExportDeclaration) {
|
||||
Node exported = null;
|
||||
if (stmt instanceof ExportDefaultDeclaration) {
|
||||
exported = ((ExportDefaultDeclaration) stmt).getDeclaration();
|
||||
} else if (stmt instanceof ExportNamedDeclaration) {
|
||||
exported = ((ExportNamedDeclaration) stmt).getDeclaration();
|
||||
}
|
||||
if (exported instanceof ClassDeclaration) {
|
||||
((ClassDeclaration) exported).addDecorators(decorators);
|
||||
} else if (exported instanceof ClassExpression) {
|
||||
((ClassExpression) exported).addDecorators(decorators);
|
||||
} else {
|
||||
this.raise(stmt, "Decorators can only be attached to class exports");
|
||||
}
|
||||
} else if (stmt instanceof ClassDeclaration) {
|
||||
((ClassDeclaration) stmt).addDecorators(decorators);
|
||||
} else if (stmt != null) {
|
||||
this.raise(stmt, "Leading decorators must be attached to a class declaration");
|
||||
}
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Expression parseExprAtom(DestructuringErrors refDestructuringErrors) {
|
||||
if (this.type == at) {
|
||||
List<Decorator> decorators = parseDecorators();
|
||||
ClassExpression ce = (ClassExpression) this.parseClass(startLoc, false);
|
||||
ce.addDecorators(decorators);
|
||||
return ce;
|
||||
}
|
||||
if (this.type == doubleColon) {
|
||||
SourceLocation startLoc = new SourceLocation(this.startLoc);
|
||||
this.next();
|
||||
int innerStart = this.start;
|
||||
Position innerStartLoc = this.startLoc;
|
||||
Expression callee = parseSubscripts(parseExprAtom(null), innerStart, innerStartLoc, true);
|
||||
if (!(callee instanceof MemberExpression))
|
||||
this.raiseRecoverable(callee, "Binding should be performed on a member expression.");
|
||||
return this.finishNode(new BindExpression(startLoc, null, callee));
|
||||
}
|
||||
if (this.type == TokenType._import) {
|
||||
Position startLoc = this.startLoc;
|
||||
this.next();
|
||||
this.expect(TokenType.parenL);
|
||||
return parseDynamicImport(startLoc);
|
||||
}
|
||||
return super.parseExprAtom(refDestructuringErrors);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MemberDefinition<?> parseClassMember(boolean hadConstructor) {
|
||||
List<Decorator> decorators = parseDecorators();
|
||||
MemberDefinition<?> member = super.parseClassMember(hadConstructor);
|
||||
if (!decorators.isEmpty() && member.isConstructor())
|
||||
this.raiseRecoverable(member, "Decorators cannot be attached to class constructors.");
|
||||
member.addDecorators(decorators);
|
||||
return member;
|
||||
}
|
||||
|
||||
private List<Decorator> parseDecorators() {
|
||||
List<Decorator> result = new ArrayList<Decorator>();
|
||||
while (this.type == at)
|
||||
result.add(this.parseDecorator());
|
||||
return result;
|
||||
}
|
||||
|
||||
private Decorator parseDecorator() {
|
||||
Position start = startLoc;
|
||||
this.next();
|
||||
Decorator decorator = new Decorator(new SourceLocation(start), this.parseMaybeAssign(false, null, null));
|
||||
return this.finishNode(decorator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed extensions to `export`
|
||||
* (http://leebyron.com/ecmascript-export-ns-from and http://leebyron.com/ecmascript-export-default-from)
|
||||
*/
|
||||
private boolean exportExtensions() {
|
||||
return options.esnext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExportDeclaration parseExportRest(SourceLocation exportStart, Set<String> exports) {
|
||||
if (exportExtensions() && this.isExportDefaultSpecifier()) {
|
||||
Position specStart = this.startLoc;
|
||||
Identifier exported = this.parseIdent(true);
|
||||
ExportDefaultSpecifier defaultSpec = this.finishNode(new ExportDefaultSpecifier(new SourceLocation(specStart), exported));
|
||||
List<ExportSpecifier> specifiers = CollectionUtil.makeList(defaultSpec);
|
||||
if (this.type == TokenType.comma && this.lookahead(1, true).equals("*")) {
|
||||
this.next();
|
||||
specStart = this.startLoc;
|
||||
this.expect(TokenType.star);
|
||||
this.expectContextual("as");
|
||||
exported = this.parseIdent(false);
|
||||
ExportNamespaceSpecifier nsSpec = this.finishNode(new ExportNamespaceSpecifier(new SourceLocation(specStart), exported));
|
||||
specifiers.add(nsSpec);
|
||||
} else {
|
||||
this.parseExportSpecifiersMaybe(specifiers, exports);
|
||||
}
|
||||
Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
|
||||
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source));
|
||||
}
|
||||
|
||||
return super.parseExportRest(exportStart, exports);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExportDeclaration parseExportAll(SourceLocation exportStart, Position starLoc, Set<String> exports) {
|
||||
if (exportExtensions() && this.eatContextual("as")) {
|
||||
Identifier exported = this.parseIdent(false);
|
||||
ExportNamespaceSpecifier nsSpec = this.finishNode(new ExportNamespaceSpecifier(new SourceLocation(starLoc), exported));
|
||||
List<ExportSpecifier> specifiers = CollectionUtil.makeList(nsSpec);
|
||||
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);
|
||||
}
|
||||
|
||||
private boolean isExportDefaultSpecifier() {
|
||||
if (this.type == TokenType.name) {
|
||||
return !this.value.equals("type") &&
|
||||
!this.value.equals("async") &&
|
||||
!this.value.equals("interface") &&
|
||||
!this.value.equals("let");
|
||||
}
|
||||
|
||||
if (this.type != TokenType._default)
|
||||
return false;
|
||||
|
||||
return this.lookahead(1, true).equals(",") || this.lookaheadIsIdent("from", true);
|
||||
}
|
||||
|
||||
private void parseExportSpecifiersMaybe(List<ExportSpecifier> specifiers, Set<String> exports) {
|
||||
if (this.eat(TokenType.comma)) {
|
||||
specifiers.addAll(this.parseExportSpecifiers(exports));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Function Bind Syntax"
|
||||
* (https://github.com/tc39/proposal-bind-operator)
|
||||
*/
|
||||
private boolean functionBind() {
|
||||
return options.esnext();
|
||||
}
|
||||
|
||||
protected TokenType doubleColon = new TokenType(new Properties("::").beforeExpr());
|
||||
|
||||
@Override
|
||||
protected Pair<Expression, Boolean> parseSubscript(Expression base, Position startLoc, boolean noCalls) {
|
||||
if (!noCalls && this.eat(doubleColon)) {
|
||||
Expression callee = parseSubscripts(parseExprAtom(null), this.start, this.startLoc, true);
|
||||
BindExpression bind = new BindExpression(new SourceLocation(startLoc), base, callee);
|
||||
return Pair.make(this.finishNode(bind), true);
|
||||
}
|
||||
return super.parseSubscript(base, startLoc, noCalls);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Optional Catch Binding"
|
||||
* (https://github.com/tc39/proposal-optional-catch-binding)
|
||||
*/
|
||||
@Override
|
||||
protected CatchClause parseCatchClause(Position startLoc) {
|
||||
this.next();
|
||||
Expression param = null;
|
||||
if (this.eat(TokenType.parenL)) {
|
||||
param = this.parseBindingAtom();
|
||||
this.checkLVal(param, true, null);
|
||||
this.expect(TokenType.parenR);
|
||||
} else if (!options.esnext()) {
|
||||
this.unexpected();
|
||||
}
|
||||
BlockStatement catchBody = this.parseBlock(false);
|
||||
return this.finishNode(new CatchClause(new SourceLocation(startLoc), (IPattern)param, null, catchBody));
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Dynamic import"
|
||||
* (https://github.com/tc39/proposal-dynamic-import).
|
||||
*/
|
||||
@Override
|
||||
protected Statement parseImport(Position startLoc) {
|
||||
if (!options.esnext())
|
||||
return super.parseImport(startLoc);
|
||||
|
||||
int startPos = this.start;
|
||||
SourceLocation loc = new SourceLocation(startLoc);
|
||||
this.next();
|
||||
if (this.eat(TokenType.parenL)) {
|
||||
DynamicImport di = parseDynamicImport(startLoc);
|
||||
Expression expr = parseSubscripts(di, startPos, startLoc, false);
|
||||
return parseExpressionStatement(false, startLoc, expr);
|
||||
} else {
|
||||
return super.parseImportRest(loc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a dynamic import, assuming that the keyword `import` and the
|
||||
* opening parenthesis have already been consumed.
|
||||
*/
|
||||
private DynamicImport parseDynamicImport(Position startLoc) {
|
||||
Expression source = parseMaybeAssign(false, null, null);
|
||||
this.expect(TokenType.parenR);
|
||||
DynamicImport di = this.finishNode(new DynamicImport(new SourceLocation(startLoc), source));
|
||||
return di;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Asynchronous iteration"
|
||||
* (https://github.com/tc39/proposal-async-iteration)
|
||||
*/
|
||||
@Override
|
||||
protected Statement parseForStatement(Position startLoc) {
|
||||
int startPos = this.start;
|
||||
boolean isAwait = false;
|
||||
if (this.inAsync && this.eatContextual("await"))
|
||||
isAwait = true;
|
||||
Statement forStmt = super.parseForStatement(startLoc);
|
||||
if (isAwait) {
|
||||
if (forStmt instanceof ForOfStatement)
|
||||
((ForOfStatement) forStmt).setAwait(true);
|
||||
else
|
||||
this.raiseRecoverable(startPos, "Only for-of statements can be annotated with 'await'.");
|
||||
}
|
||||
return forStmt;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean parseGeneratorMarker(boolean isAsync) {
|
||||
// always allow `*`, even if `isAsync` is true
|
||||
return this.eat(TokenType.star);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for proposed language feature "Numeric separators"
|
||||
* (https://github.com/tc39/proposal-numeric-separator)
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected Number readInt(int radix, Integer len) {
|
||||
// implementation mostly copied from super class
|
||||
int start = this.pos, code = -1;
|
||||
double total = 0;
|
||||
// no leading underscore
|
||||
boolean underscoreAllowed = false;
|
||||
|
||||
for (int i = 0, e = len == null ? Integer.MAX_VALUE : len; i < e; ++i) {
|
||||
if (this.pos >= this.input.length())
|
||||
break;
|
||||
code = this.input.charAt(this.pos);
|
||||
|
||||
if (code == '_') {
|
||||
if (underscoreAllowed) {
|
||||
// no adjacent underscores
|
||||
underscoreAllowed = false;
|
||||
++this.pos;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
underscoreAllowed = true;
|
||||
}
|
||||
|
||||
int val;
|
||||
if (code >= 97) val = code - 97 + 10; // a
|
||||
else if (code >= 65) val = code - 65 + 10; // A
|
||||
else if (code >= 48 && code <= 57) val = code - 48; // 0-9
|
||||
else val = Integer.MAX_VALUE;
|
||||
if (val >= radix) break;
|
||||
|
||||
++this.pos;
|
||||
total = total * radix + val;
|
||||
}
|
||||
if (this.pos == start || len != null && this.pos - start != len) return null;
|
||||
|
||||
if (code == '_')
|
||||
// no trailing underscore
|
||||
return null;
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
117
javascript/extractor/src/com/semmle/jcorn/Identifiers.java
Normal file
117
javascript/extractor/src/com/semmle/jcorn/Identifiers.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package com.semmle.jcorn;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/// identifier.js
|
||||
public class Identifiers {
|
||||
public static enum Dialect {
|
||||
ECMA_3, ECMA_5, ECMA_6, ECMA_7, ECMA_8, STRICT, STRICT_BIND
|
||||
}
|
||||
|
||||
// Reserved word lists for various dialects of the language
|
||||
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
|
||||
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";
|
||||
private static final String ecma6Keywords = ecma5AndLessKeywords + " const class extends export import super";
|
||||
|
||||
public static final Map<Dialect, Set<String>> keywords = new LinkedHashMap<>();
|
||||
static {
|
||||
keywords.put(Dialect.ECMA_5, stringSet(ecma5AndLessKeywords));
|
||||
keywords.put(Dialect.ECMA_6, stringSet(ecma6Keywords));
|
||||
}
|
||||
|
||||
private static Set<String> stringSet(String words) {
|
||||
Set<String> result = new LinkedHashSet<String>();
|
||||
for (String word : words.split(" "))
|
||||
result.add(word);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ## Character categories
|
||||
|
||||
private static final String nonASCIIidentifierStartChars =
|
||||
"\\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";
|
||||
private static final String nonASCIIidentifierChars =
|
||||
"\\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 nonASCIIidentifierStartPattern;
|
||||
private static Pattern nonASCIIidentifierPattern;
|
||||
|
||||
private static Pattern nonASCIIidentifierStart() {
|
||||
if (nonASCIIidentifierStartPattern == null)
|
||||
nonASCIIidentifierStartPattern = Pattern.compile("[" + nonASCIIidentifierStartChars + "]");
|
||||
return nonASCIIidentifierStartPattern;
|
||||
}
|
||||
|
||||
private static Pattern nonASCIIidentifier() {
|
||||
if (nonASCIIidentifierPattern == null)
|
||||
nonASCIIidentifierPattern = Pattern.compile("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
|
||||
return nonASCIIidentifierPattern;
|
||||
}
|
||||
|
||||
// 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};
|
||||
|
||||
// This has a complexity linear to the value of the code. The
|
||||
// assumption is that looking up astral identifier characters is
|
||||
// rare.
|
||||
private static boolean isInAstralSet(int code, int[] set) {
|
||||
int pos = 0x10000;
|
||||
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.
|
||||
|
||||
public static boolean isIdentifierStart(int code, boolean astral) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
27
javascript/extractor/src/com/semmle/jcorn/Locutil.java
Normal file
27
javascript/extractor/src/com/semmle/jcorn/Locutil.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.semmle.jcorn;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import com.semmle.js.ast.Position;
|
||||
|
||||
/// locutil.js
|
||||
public class Locutil {
|
||||
/**
|
||||
* The `getLineInfo` function is mostly useful when the
|
||||
* `locations` option is off (for performance reasons) and you
|
||||
* want to find the line/column position for a given character
|
||||
* 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);
|
||||
for (int line = 1, cur = 0;;) {
|
||||
if (lineBreakG.find(cur) && lineBreakG.start() < offset) {
|
||||
++line;
|
||||
cur = lineBreakG.end();
|
||||
} else {
|
||||
return new Position(line, offset - cur, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
238
javascript/extractor/src/com/semmle/jcorn/Options.java
Normal file
238
javascript/extractor/src/com/semmle/jcorn/Options.java
Normal file
@@ -0,0 +1,238 @@
|
||||
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.js.ast.Comment;
|
||||
import com.semmle.js.ast.Position;
|
||||
import com.semmle.js.ast.Program;
|
||||
import com.semmle.js.ast.SourceLocation;
|
||||
import com.semmle.js.ast.Token;
|
||||
|
||||
/// options.js
|
||||
public class Options {
|
||||
public enum AllowReserved {
|
||||
YES(true), NO(false), NEVER(false);
|
||||
|
||||
private final boolean isTrue;
|
||||
|
||||
private AllowReserved(boolean isTrue) {
|
||||
this.isTrue = isTrue;
|
||||
}
|
||||
|
||||
public boolean isTrue() {
|
||||
return isTrue;
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnCommentCallback {
|
||||
public void call(boolean block, String input, String text, int start, int end, Position startLoc, Position endLoc);
|
||||
}
|
||||
|
||||
private boolean allowHashBang, allowReturnOutsideFunction, allowImportExportEverywhere;
|
||||
private boolean preserveParens, mozExtensions, jscript, esnext, v8Extensions;
|
||||
private int ecmaVersion;
|
||||
private AllowReserved allowReserved;
|
||||
private String sourceType;
|
||||
private BiFunction<Integer, Position, Void> onInsertedSemicolon, onTrailingComma;
|
||||
private Function<Token, Void> onToken;
|
||||
private OnCommentCallback onComment;
|
||||
private Program program;
|
||||
private Function<SyntaxError, ?> onRecoverableError;
|
||||
|
||||
public Options() {
|
||||
this.ecmaVersion = 7;
|
||||
this.sourceType = "script";
|
||||
this.onInsertedSemicolon = null;
|
||||
this.onTrailingComma = null;
|
||||
this.allowReserved = AllowReserved.YES;
|
||||
this.allowReturnOutsideFunction = false;
|
||||
this.allowImportExportEverywhere = false;
|
||||
this.allowHashBang = false;
|
||||
this.onToken = null;
|
||||
this.onComment = null;
|
||||
this.program = null;
|
||||
this.preserveParens = false;
|
||||
this.mozExtensions = false;
|
||||
this.jscript = false;
|
||||
this.esnext = false;
|
||||
this.v8Extensions = false;
|
||||
this.onRecoverableError = null;
|
||||
}
|
||||
|
||||
public Options(Options that) {
|
||||
this.allowHashBang = that.allowHashBang;
|
||||
this.allowReturnOutsideFunction = that.allowReturnOutsideFunction;
|
||||
this.allowImportExportEverywhere = that.allowImportExportEverywhere;
|
||||
this.preserveParens = that.preserveParens;
|
||||
this.mozExtensions = that.mozExtensions;
|
||||
this.jscript = that.jscript;
|
||||
this.esnext = that.esnext;
|
||||
this.v8Extensions = that.v8Extensions;
|
||||
this.ecmaVersion = that.ecmaVersion;
|
||||
this.allowReserved = that.allowReserved;
|
||||
this.sourceType = that.sourceType;
|
||||
this.onInsertedSemicolon = that.onInsertedSemicolon;
|
||||
this.onTrailingComma = that.onTrailingComma;
|
||||
this.onToken = that.onToken;
|
||||
this.onComment = that.onComment;
|
||||
this.program = that.program;
|
||||
this.onRecoverableError = that.onRecoverableError;
|
||||
}
|
||||
|
||||
public boolean allowHashBang() {
|
||||
return allowHashBang;
|
||||
}
|
||||
|
||||
public boolean allowReturnOutsideFunction() {
|
||||
return allowReturnOutsideFunction;
|
||||
}
|
||||
|
||||
public boolean allowImportExportEverywhere() {
|
||||
return allowImportExportEverywhere;
|
||||
}
|
||||
|
||||
public boolean preserveParens() {
|
||||
return preserveParens;
|
||||
}
|
||||
|
||||
public boolean mozExtensions() {
|
||||
return mozExtensions;
|
||||
}
|
||||
|
||||
public boolean jscript() {
|
||||
return jscript;
|
||||
}
|
||||
|
||||
public boolean esnext() {
|
||||
return esnext;
|
||||
}
|
||||
|
||||
public boolean v8Extensions() {
|
||||
return v8Extensions;
|
||||
}
|
||||
|
||||
public Identifiers.Dialect getDialect() {
|
||||
switch (ecmaVersion) {
|
||||
case 3:
|
||||
return Dialect.ECMA_3;
|
||||
case 5:
|
||||
return Dialect.ECMA_5;
|
||||
case 6:
|
||||
return Dialect.ECMA_6;
|
||||
case 8:
|
||||
return Dialect.ECMA_8;
|
||||
default:
|
||||
return Dialect.ECMA_7;
|
||||
}
|
||||
}
|
||||
|
||||
public int ecmaVersion() {
|
||||
return ecmaVersion;
|
||||
}
|
||||
|
||||
public Options ecmaVersion(int ecmaVersion) {
|
||||
if (ecmaVersion >= 2015)
|
||||
ecmaVersion -= 2009;
|
||||
|
||||
this.ecmaVersion = ecmaVersion;
|
||||
if (ecmaVersion >= 5)
|
||||
this.allowReserved = AllowReserved.NO;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AllowReserved allowReserved() {
|
||||
return allowReserved;
|
||||
}
|
||||
|
||||
public Options onComment(List<Comment> comments) {
|
||||
this.onComment = (block, input, text, start, end, startLoc, endLoc) -> {
|
||||
String src = input.substring(start, end);
|
||||
comments.add(new Comment(new SourceLocation(src, startLoc, endLoc), text));
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public String sourceType() {
|
||||
return sourceType;
|
||||
}
|
||||
|
||||
public Options sourceType(String sourceType) {
|
||||
this.sourceType = sourceType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options mozExtensions(boolean mozExtensions) {
|
||||
this.mozExtensions = mozExtensions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options jscript(boolean jscript) {
|
||||
this.jscript = jscript;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options esnext(boolean esnext) {
|
||||
this.esnext = esnext;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void v8Extensions(boolean v8Extensions) {
|
||||
this.v8Extensions = v8Extensions;
|
||||
}
|
||||
|
||||
public Options preserveParens(boolean preserveParens) {
|
||||
this.preserveParens = preserveParens;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options allowReturnOutsideFunction(boolean allowReturnOutsideFunction) {
|
||||
this.allowReturnOutsideFunction = allowReturnOutsideFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options allowImportExportEverywhere(boolean allowImportExportEverywhere) {
|
||||
this.allowImportExportEverywhere = allowImportExportEverywhere;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BiFunction<Integer, Position, Void> onInsertedSemicolon() {
|
||||
return onInsertedSemicolon;
|
||||
}
|
||||
|
||||
public BiFunction<Integer, Position, Void> onTrailingComma() {
|
||||
return onTrailingComma;
|
||||
}
|
||||
|
||||
public Function<Token, Void> onToken() {
|
||||
return onToken;
|
||||
}
|
||||
|
||||
public Options onToken(List<Token> tokens) {
|
||||
return onToken((tk) -> { tokens.add(tk); return null; });
|
||||
}
|
||||
|
||||
public Options onToken(Function<Token, Void> tmp) {
|
||||
this.onToken = tmp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OnCommentCallback onComment() {
|
||||
return onComment;
|
||||
}
|
||||
|
||||
public Program program() {
|
||||
return program;
|
||||
}
|
||||
|
||||
public Options onRecoverableError(Function<SyntaxError, ?> onRecoverableError) {
|
||||
this.onRecoverableError = onRecoverableError;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Function<SyntaxError, ?> onRecoverableError() {
|
||||
return onRecoverableError;
|
||||
}
|
||||
}
|
||||
3547
javascript/extractor/src/com/semmle/jcorn/Parser.java
Normal file
3547
javascript/extractor/src/com/semmle/jcorn/Parser.java
Normal file
File diff suppressed because it is too large
Load Diff
1
javascript/extractor/src/com/semmle/jcorn/README.md
Normal file
1
javascript/extractor/src/com/semmle/jcorn/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This directory contains the source code of the JavaScript parser used by the JavaScript extractor, which is essentially a Java port of [acorn](https://github.com/acornjs/acorn) and [acorn-jsx](https://github.com/RReverser/acorn-jsx) (both developed under an MIT license) with a few custom extensions.
|
||||
18
javascript/extractor/src/com/semmle/jcorn/SyntaxError.java
Normal file
18
javascript/extractor/src/com/semmle/jcorn/SyntaxError.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.semmle.jcorn;
|
||||
|
||||
import com.semmle.js.ast.Position;
|
||||
|
||||
public class SyntaxError extends RuntimeException {
|
||||
private static final long serialVersionUID = -4883173648492364902L;
|
||||
|
||||
private final Position position;
|
||||
|
||||
public SyntaxError(String msg, Position loc, int raisedAt) {
|
||||
super(msg);
|
||||
this.position = loc;
|
||||
}
|
||||
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
279
javascript/extractor/src/com/semmle/jcorn/TokenType.java
Normal file
279
javascript/extractor/src/com/semmle/jcorn/TokenType.java
Normal file
@@ -0,0 +1,279 @@
|
||||
package com.semmle.jcorn;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.semmle.jcorn.Parser.TokContext;
|
||||
|
||||
/// tokentype.js
|
||||
|
||||
// ## Token types
|
||||
|
||||
// The assignment of fine-grained, information-carrying type objects
|
||||
// allows the tokenizer to store the information it has about a
|
||||
// token in a way that is very cheap for the parser to look up.
|
||||
|
||||
// All token type variables start with an underscore, to make them
|
||||
// easy to recognize.
|
||||
|
||||
// The `beforeExpr` property is used to disambiguate between regular
|
||||
// expressions and divisions. It is set on all token types that can
|
||||
// be followed by an expression (thus, a slash after them would be a
|
||||
// regular expression).
|
||||
//
|
||||
// The `startsExpr` property is used to check if the token ends a
|
||||
// `yield` expression. It is set on all token types that either can
|
||||
// directly start an expression (like a quotation mark) or can
|
||||
// continue an expression (like the body of a string).
|
||||
//
|
||||
// `isLoop` marks a keyword as starting a loop, which is important
|
||||
// to know when parsing a label, in order to allow or disallow
|
||||
// continue jumps to that label.
|
||||
|
||||
public class TokenType {
|
||||
// Map keyword names to token types.
|
||||
public static final Map<String, TokenType> keywords = new LinkedHashMap<>();
|
||||
|
||||
public static final TokenType
|
||||
num = new TokenType(new Properties("num").startsExpr()),
|
||||
bigint = new TokenType(new Properties("bigint").startsExpr()),
|
||||
regexp = new TokenType(new Properties("regexp").startsExpr()),
|
||||
string = new TokenType(new Properties("string").startsExpr()),
|
||||
name = new TokenType(new Properties("name").startsExpr()),
|
||||
eof = new TokenType(new Properties("eof")),
|
||||
|
||||
// Punctuation token types.
|
||||
bracketL = new TokenType(new Properties("[").beforeExpr().startsExpr()),
|
||||
bracketR = new TokenType(new Properties("]")),
|
||||
braceL = new TokenType(new Properties("{").beforeExpr().startsExpr()) {
|
||||
@Override
|
||||
public void updateContext(Parser parser, TokenType prevType) {
|
||||
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) {
|
||||
updateParenBraceRContext(parser);
|
||||
}
|
||||
},
|
||||
parenL = new TokenType(new Properties("(").beforeExpr().startsExpr()) {
|
||||
@Override
|
||||
public void updateContext(Parser parser, TokenType prevType) {
|
||||
boolean statementParens = prevType == TokenType._if || prevType == TokenType._for || prevType == TokenType._with || prevType == TokenType._while;
|
||||
parser.context.push(statementParens ? TokContext.p_stat : TokContext.p_expr);
|
||||
parser.exprAllowed = true;
|
||||
}
|
||||
},
|
||||
parenR = new TokenType(new Properties(")")) {
|
||||
@Override
|
||||
public void updateContext(Parser parser, TokenType prevType) {
|
||||
updateParenBraceRContext(parser);
|
||||
}
|
||||
},
|
||||
comma = new TokenType(new Properties(",").beforeExpr()),
|
||||
semi = new TokenType(new Properties(";").beforeExpr()),
|
||||
colon = new TokenType(new Properties(":").beforeExpr()),
|
||||
dot = new TokenType(new Properties(".")),
|
||||
question = new TokenType(new Properties("?").beforeExpr()),
|
||||
arrow = new TokenType(new Properties("=>").beforeExpr()),
|
||||
template = new TokenType(new Properties("template")),
|
||||
invalidTemplate = new TokenType(new Properties("invalidTemplate")),
|
||||
ellipsis = new TokenType(new Properties("...").beforeExpr()),
|
||||
backQuote = new TokenType(new Properties("`").startsExpr()) {
|
||||
@Override
|
||||
public void updateContext(Parser parser, TokenType prevType) {
|
||||
if (parser.curContext() == TokContext.q_tmpl)
|
||||
parser.context.pop();
|
||||
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
|
||||
// parser use them properly (the presence of these properties is
|
||||
// what categorizes them as operators).
|
||||
//
|
||||
// `binop`, when present, specifies that this operator is a binary
|
||||
// operator, and will refer to its precedence.
|
||||
//
|
||||
// `prefix` and `postfix` mark the operator as a prefix or postfix
|
||||
// unary operator.
|
||||
//
|
||||
// `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as
|
||||
// binary operators with a very low precedence, that should result
|
||||
// in AssignmentExpression nodes.
|
||||
|
||||
eq = new TokenType(new Properties("=").beforeExpr().isAssign()),
|
||||
assign = new TokenType(new Properties("_=").beforeExpr().isAssign()),
|
||||
incDec = new TokenType(new Properties("++/--").prefix().postfix().startsExpr()) {
|
||||
@Override
|
||||
public void updateContext(Parser parser, TokenType prevType) {
|
||||
// exprAllowed stays unchanged
|
||||
}
|
||||
},
|
||||
prefix = new TokenType(new Properties("prefix").beforeExpr().prefix().startsExpr()),
|
||||
logicalOR = new TokenType(binop("||", 1)),
|
||||
logicalAND = new TokenType(binop("&&", 2)),
|
||||
bitwiseOR = new TokenType(binop("|", 3)),
|
||||
bitwiseXOR = new TokenType(binop("^", 4)),
|
||||
bitwiseAND = new TokenType(binop("&", 5)),
|
||||
equality = new TokenType(binop("==/!=", 6)),
|
||||
relational = new TokenType(binop("</>", 7)),
|
||||
bitShift = new TokenType(binop("<</>>", 8)),
|
||||
plusMin = new TokenType(new Properties("+/-").beforeExpr().binop(9).prefix().startsExpr()),
|
||||
modulo= new TokenType(binop("%", 10)),
|
||||
star= new TokenType(binop("*", 10)),
|
||||
slash= new TokenType(binop("/", 10)),
|
||||
starstar = new TokenType(new Properties("**").beforeExpr()),
|
||||
_break = new TokenType(kw("break")),
|
||||
_case = new TokenType(kw("case").beforeExpr()),
|
||||
_catch = new TokenType(kw("catch")),
|
||||
_continue = new TokenType(kw("continue")),
|
||||
_debugger = new TokenType(kw("debugger")),
|
||||
_default = new TokenType(kw("default").beforeExpr()),
|
||||
_do = new TokenType(kw("do").isLoop().beforeExpr()),
|
||||
_else = new TokenType(kw("else").beforeExpr()),
|
||||
_finally = new TokenType(kw("finally")),
|
||||
_for = new TokenType(kw("for").isLoop()),
|
||||
_function = new TokenType(kw("function").startsExpr()) {
|
||||
@Override
|
||||
public void updateContext(Parser parser, TokenType prevType) {
|
||||
if (prevType.beforeExpr && prevType != TokenType.semi && prevType != TokenType._else &&
|
||||
!((prevType == TokenType.colon || prevType == TokenType.braceL) && parser.curContext() == TokContext.b_stat))
|
||||
parser.context.push(TokContext.f_expr);
|
||||
parser.exprAllowed = false;
|
||||
}
|
||||
},
|
||||
_if = new TokenType(kw("if")),
|
||||
_return = new TokenType(kw("return").beforeExpr()),
|
||||
_switch = new TokenType(kw("switch")),
|
||||
_throw = new TokenType(kw("throw").beforeExpr()),
|
||||
_try = new TokenType(kw("try")),
|
||||
_var = new TokenType(kw("var")),
|
||||
_const = new TokenType(kw("const")),
|
||||
_while = new TokenType(kw("while").isLoop()),
|
||||
_with = new TokenType(kw("with")),
|
||||
_new = new TokenType(kw("new").beforeExpr().startsExpr()),
|
||||
_this = new TokenType(kw("this").startsExpr()),
|
||||
_super = new TokenType(kw("super").startsExpr()),
|
||||
_class = new TokenType(kw("class")),
|
||||
_extends = new TokenType(kw("extends").beforeExpr()),
|
||||
_export = new TokenType(kw("export")),
|
||||
_import = new TokenType(kw("import")),
|
||||
_null = new TokenType(kw("null").startsExpr()),
|
||||
_true = new TokenType(kw("true").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 void updateContext(Parser parser, TokenType prevType) {
|
||||
parser.exprAllowed = this.beforeExpr;
|
||||
}
|
||||
|
||||
// Token-specific context update code
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public TokenType(Properties prop) {
|
||||
this.label = prop.label;
|
||||
this.keyword = prop.keyword;
|
||||
this.beforeExpr = prop.beforeExpr;
|
||||
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 String label, keyword;
|
||||
public boolean beforeExpr, startsExpr, isLoop, isAssign, prefix, postfix;
|
||||
public int binop;
|
||||
|
||||
public Properties(String label, String keyword) {
|
||||
this.label = label;
|
||||
this.keyword = keyword;
|
||||
}
|
||||
|
||||
public Properties(String label) {
|
||||
this(label, null);
|
||||
}
|
||||
|
||||
public Properties beforeExpr() {
|
||||
this.beforeExpr = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Properties startsExpr() {
|
||||
this.startsExpr = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Properties isLoop() {
|
||||
this.isLoop = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Properties isAssign() {
|
||||
this.isAssign = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Properties prefix() {
|
||||
this.prefix = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Properties postfix() {
|
||||
this.postfix = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Properties binop(int prec) {
|
||||
this.binop = prec;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static Properties binop(String name, int prec) {
|
||||
return new Properties(name, null).binop(prec).beforeExpr();
|
||||
}
|
||||
|
||||
// Succinct definitions of keyword token types
|
||||
private static Properties kw(String name) {
|
||||
return new Properties(name, name);
|
||||
}
|
||||
}
|
||||
18
javascript/extractor/src/com/semmle/jcorn/Whitespace.java
Normal file
18
javascript/extractor/src/com/semmle/jcorn/Whitespace.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.semmle.jcorn;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/// whitespace.js
|
||||
public class Whitespace {
|
||||
public static final String lineBreak = "\r\n?|\n|\u2028|\u2029";
|
||||
public static final Pattern lineBreakG = Pattern.compile(lineBreak); // global
|
||||
|
||||
public static boolean isNewLine(int code) {
|
||||
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 Pattern skipWhiteSpace = Pattern.compile("(?:\\s|//.*|/\\*([^*]|\\*(?!/))*\\*/)*"); // global
|
||||
public static final Pattern skipWhiteSpaceNoNewline = Pattern.compile("(?:[ \\t\\x0B\\f]|//.*|/\\*([^*]|\\*(?!/))*\\*/)*");
|
||||
}
|
||||
1161
javascript/extractor/src/com/semmle/jcorn/flow/FlowParser.java
Normal file
1161
javascript/extractor/src/com/semmle/jcorn/flow/FlowParser.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
package com.semmle.jcorn.jsx;
|
||||
|
||||
import com.semmle.jcorn.Options;
|
||||
|
||||
public class JSXOptions extends Options {
|
||||
public boolean allowNamespacedObjects = true, allowNamespaces = true;
|
||||
|
||||
public JSXOptions() {
|
||||
}
|
||||
|
||||
public JSXOptions(Options options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
public JSXOptions allowNamespacedObjects(boolean allowNamespacedObjects) {
|
||||
this.allowNamespacedObjects = allowNamespacedObjects;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSXOptions allowNamespaces(boolean allowNamespaces) {
|
||||
this.allowNamespaces = allowNamespaces;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
457
javascript/extractor/src/com/semmle/jcorn/jsx/JSXParser.java
Normal file
457
javascript/extractor/src/com/semmle/jcorn/jsx/JSXParser.java
Normal file
@@ -0,0 +1,457 @@
|
||||
package com.semmle.jcorn.jsx;
|
||||
|
||||
import static com.semmle.jcorn.Parser.TokContext.b_expr;
|
||||
import static com.semmle.jcorn.Parser.TokContext.b_tmpl;
|
||||
import static com.semmle.jcorn.TokenType.braceL;
|
||||
import static com.semmle.jcorn.TokenType.braceR;
|
||||
import static com.semmle.jcorn.TokenType.colon;
|
||||
import static com.semmle.jcorn.TokenType.dot;
|
||||
import static com.semmle.jcorn.TokenType.ellipsis;
|
||||
import static com.semmle.jcorn.TokenType.eq;
|
||||
import static com.semmle.jcorn.TokenType.relational;
|
||||
import static com.semmle.jcorn.TokenType.slash;
|
||||
import static com.semmle.jcorn.TokenType.string;
|
||||
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.Options;
|
||||
import com.semmle.jcorn.Parser;
|
||||
import com.semmle.jcorn.TokenType;
|
||||
import com.semmle.jcorn.TokenType.Properties;
|
||||
import com.semmle.js.ast.Expression;
|
||||
import com.semmle.js.ast.INode;
|
||||
import com.semmle.js.ast.Position;
|
||||
import com.semmle.js.ast.SourceLocation;
|
||||
import com.semmle.js.ast.Token;
|
||||
import com.semmle.js.ast.jsx.IJSXAttribute;
|
||||
import com.semmle.js.ast.jsx.IJSXName;
|
||||
import com.semmle.js.ast.jsx.JSXAttribute;
|
||||
import com.semmle.js.ast.jsx.JSXClosingElement;
|
||||
import com.semmle.js.ast.jsx.JSXElement;
|
||||
import com.semmle.js.ast.jsx.JSXEmptyExpression;
|
||||
import com.semmle.js.ast.jsx.JSXExpressionContainer;
|
||||
import com.semmle.js.ast.jsx.JSXIdentifier;
|
||||
import com.semmle.js.ast.jsx.JSXMemberExpression;
|
||||
import com.semmle.js.ast.jsx.JSXNamespacedName;
|
||||
import com.semmle.js.ast.jsx.JSXOpeningElement;
|
||||
import com.semmle.js.ast.jsx.JSXSpreadAttribute;
|
||||
|
||||
/**
|
||||
* Java port of <a href="https://github.com/RReverser/acorn-jsx">Acorn-JSX</a> as of version
|
||||
* <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}
|
||||
* object. To enable JSX parsing, pass in a {@link JSXOptions} object.
|
||||
*/
|
||||
public class JSXParser extends Parser {
|
||||
private static final Pattern hexNumber = Pattern.compile("^[\\da-fA-F]+$");
|
||||
private static final Pattern decimalNumber = Pattern.compile("^\\d+$");
|
||||
|
||||
public JSXParser(Options options, String input, int startPos) {
|
||||
super(options, input, startPos);
|
||||
}
|
||||
|
||||
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_expr = new TokContext("<tag>..</tag>", true, true, null);
|
||||
|
||||
private static final TokenType jsxName = new TokenType(new Properties("jsxName"));
|
||||
public static final TokenType jsxText = new TokenType(new Properties("jsxText").beforeExpr());
|
||||
protected static final TokenType jsxTagStart = new TokenType(new Properties("jsxTagStart")) {
|
||||
@Override
|
||||
public void updateContext(Parser parser, TokenType prevType) {
|
||||
parser.pushTokenContext(j_expr); // treat as beginning of JSX expression
|
||||
parser.pushTokenContext(j_oTag); // start opening tag context
|
||||
parser.exprAllowed(false);
|
||||
}
|
||||
};
|
||||
private static final TokenType jsxTagEnd = new TokenType(new Properties("jsxTagEnd")) {
|
||||
@Override
|
||||
public void updateContext(Parser parser, TokenType prevType) {
|
||||
TokContext out = parser.popTokenContext();
|
||||
if (out == j_oTag && prevType == slash || out == j_cTag) {
|
||||
parser.popTokenContext();
|
||||
parser.exprAllowed(parser.curContext() == j_expr);
|
||||
} else {
|
||||
parser.exprAllowed(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads inline JSX contents token.
|
||||
*/
|
||||
private Token jsx_readToken() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
int chunkStart = this.pos;
|
||||
for (;;) {
|
||||
if (this.pos >= this.input.length())
|
||||
this.raise(this.start, "Unterminated JSX contents");
|
||||
int ch = this.charAt(this.pos);
|
||||
|
||||
switch (ch) {
|
||||
case 60: // '<'
|
||||
case 123: // '{'
|
||||
if (this.pos == this.start) {
|
||||
if (ch == 60 && this.exprAllowed) {
|
||||
++this.pos;
|
||||
return this.finishToken(jsxTagStart);
|
||||
}
|
||||
return this.getTokenFromCode(ch);
|
||||
}
|
||||
out.append(inputSubstring(chunkStart, this.pos));
|
||||
return this.finishToken(jsxText, out.toString());
|
||||
|
||||
case 38: // '&'
|
||||
out.append(inputSubstring(chunkStart, this.pos));
|
||||
out.append(this.jsx_readEntity());
|
||||
chunkStart = this.pos;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isNewLine(ch)) {
|
||||
out.append(inputSubstring(chunkStart, this.pos));
|
||||
out.append(this.jsx_readNewLine(true));
|
||||
chunkStart = this.pos;
|
||||
} else {
|
||||
++this.pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String jsx_readNewLine(boolean normalizeCRLF) {
|
||||
int ch = this.charAt(this.pos);
|
||||
String out;
|
||||
++this.pos;
|
||||
if (ch == 13 && this.charAt(this.pos) == 10) {
|
||||
++this.pos;
|
||||
out = normalizeCRLF ? "\n" : "\r\n";
|
||||
} else {
|
||||
out = String.valueOf((char)ch);
|
||||
}
|
||||
++this.curLine;
|
||||
this.lineStart = this.pos;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private Token jsx_readString(char quote) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
int chunkStart = ++this.pos;
|
||||
for (;;) {
|
||||
if (this.pos >= this.input.length())
|
||||
this.raise(this.start, "Unterminated string constant");
|
||||
int ch = this.charAt(this.pos);
|
||||
if (ch == quote) break;
|
||||
if (ch == 38) { // '&'
|
||||
out.append(inputSubstring(chunkStart, this.pos));
|
||||
out.append(this.jsx_readEntity());
|
||||
chunkStart = this.pos;
|
||||
} else if (isNewLine(ch)) {
|
||||
out.append(inputSubstring(chunkStart, this.pos));
|
||||
out.append(this.jsx_readNewLine(false));
|
||||
chunkStart = this.pos;
|
||||
} else {
|
||||
++this.pos;
|
||||
}
|
||||
}
|
||||
out.append(inputSubstring(chunkStart, this.pos++));
|
||||
return this.finishToken(string, out.toString());
|
||||
}
|
||||
|
||||
private String jsx_readEntity() {
|
||||
int ch = this.charAt(this.pos);
|
||||
if (ch != '&')
|
||||
this.raise(this.pos, "Entity must start with an ampersand");
|
||||
int startPos = ++this.pos;
|
||||
String entity = null;
|
||||
int semi = this.input.indexOf(';', startPos);
|
||||
if (semi != -1) {
|
||||
String entityName = inputSubstring(startPos, semi);
|
||||
if (entityName.startsWith("#x")) {
|
||||
entityName = entityName.substring(2);
|
||||
if (hexNumber.matcher(entityName).matches())
|
||||
entity = codePointToString(parseInt(entityName, 16).intValue());
|
||||
} else if (entityName.startsWith("#")) {
|
||||
entityName = entityName.substring(1);
|
||||
if (decimalNumber.matcher(entityName).matches())
|
||||
entity = codePointToString(parseInt(entityName, 10).intValue());
|
||||
} else {
|
||||
Character entityChar = XHTMLEntities.ENTITIES.get(entityName);
|
||||
if (entityChar != null)
|
||||
entity = String.valueOf(entityChar);
|
||||
}
|
||||
}
|
||||
|
||||
if (entity == null) {
|
||||
this.pos = startPos;
|
||||
return "&";
|
||||
} else {
|
||||
this.pos = semi+1;
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a JSX identifier (valid tag or attribute name).
|
||||
*
|
||||
* Optimized version since JSX identifiers can't contain
|
||||
* escape characters and so can be read as single slice.
|
||||
* Also assumes that first character was already checked
|
||||
* by isIdentifierStart in readToken.
|
||||
*/
|
||||
private Token jsx_readWord() {
|
||||
int ch, start = this.pos;
|
||||
do {
|
||||
ch = this.charAt(++this.pos);
|
||||
} while (Identifiers.isIdentifierChar(ch, true) || ch == 45); // '-'
|
||||
return this.finishToken(jsxName, inputSubstring(start, this.pos));
|
||||
}
|
||||
|
||||
/** Transforms JSX element name to string; {@code null} is transformed to {@code null}. */
|
||||
private String getQualifiedJSXName(Object object) {
|
||||
if (object == null)
|
||||
return null;
|
||||
return ((IJSXName) object).getQualifiedName();
|
||||
}
|
||||
|
||||
/** Parse next token as JSX identifier */
|
||||
private JSXIdentifier jsx_parseIdentifier() {
|
||||
SourceLocation loc = new SourceLocation(this.startLoc);
|
||||
String name = null;
|
||||
if (this.type == jsxName)
|
||||
name = String.valueOf(this.value);
|
||||
else if (this.type.keyword != null)
|
||||
name = this.type.keyword;
|
||||
else
|
||||
this.unexpected();
|
||||
this.next();
|
||||
return this.finishNode(new JSXIdentifier(loc, name));
|
||||
}
|
||||
|
||||
/** Parse namespaced identifier. */
|
||||
private IJSXName jsx_parseNamespacedName() {
|
||||
SourceLocation loc = new SourceLocation(this.startLoc);
|
||||
JSXIdentifier namespace = this.jsx_parseIdentifier();
|
||||
if (!((JSXOptions)options).allowNamespaces || !this.eat(colon))
|
||||
return namespace;
|
||||
return this.finishNode(new JSXNamespacedName(loc, namespace, this.jsx_parseIdentifier()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses element name in any form - namespaced, member
|
||||
* or single identifier. If the next token is a tag-end token,
|
||||
* {@code null} is returned; this happens with fragments.
|
||||
*/
|
||||
private IJSXName jsx_parseElementName () {
|
||||
if (this.type == jsxTagEnd)
|
||||
return null;
|
||||
Position startPos = this.startLoc;
|
||||
IJSXName node = this.jsx_parseNamespacedName();
|
||||
if (this.type == dot && node instanceof JSXNamespacedName && !((JSXOptions)options).allowNamespacedObjects) {
|
||||
this.unexpected();
|
||||
}
|
||||
while (this.eat(dot)) {
|
||||
SourceLocation loc = new SourceLocation(startPos);
|
||||
node = this.finishNode(new JSXMemberExpression(loc, node, this.jsx_parseIdentifier()));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/** Parses any type of JSX attribute value. */
|
||||
private INode jsx_parseAttributeValue() {
|
||||
if (type == braceL) {
|
||||
JSXExpressionContainer node = this.jsx_parseExpressionContainer();
|
||||
if (node.getExpression() instanceof JSXEmptyExpression)
|
||||
this.raise(node, "JSX attributes must only be assigned a non-empty expression");
|
||||
return node;
|
||||
} else if (type == jsxTagStart || type == string) {
|
||||
return this.parseExprAtom(null);
|
||||
} else {
|
||||
this.raise(this.start, "JSX value should be either an expression or a quoted JSX text");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSXEmptyExpression is unique type since it doesn't actually parse anything,
|
||||
* and so it should start at the end of last read token (left brace) and finish
|
||||
* at the beginning of the next one (right brace).
|
||||
*/
|
||||
private JSXEmptyExpression jsx_parseEmptyExpression() {
|
||||
return new JSXEmptyExpression(new SourceLocation("", lastTokEndLoc, startLoc));
|
||||
}
|
||||
|
||||
/** Parses JSX expression enclosed into curly brackets. */
|
||||
private JSXExpressionContainer jsx_parseExpressionContainer() {
|
||||
SourceLocation loc = new SourceLocation(this.startLoc);
|
||||
this.next();
|
||||
INode expression;
|
||||
if (this.type == braceR)
|
||||
expression = this.jsx_parseEmptyExpression();
|
||||
else
|
||||
expression = this.parseExpression(false, null);
|
||||
this.expect(braceR);
|
||||
return this.finishNode(new JSXExpressionContainer(loc, expression));
|
||||
}
|
||||
|
||||
/** Parses following JSX attribute name-value pair. */
|
||||
private IJSXAttribute jsx_parseAttribute() {
|
||||
SourceLocation loc = new SourceLocation(this.startLoc);
|
||||
if (this.eat(braceL)) {
|
||||
this.expect(ellipsis);
|
||||
Expression argument = this.parseMaybeAssign(false, null, null);
|
||||
this.expect(braceR);
|
||||
return this.finishNode(new JSXSpreadAttribute(loc, argument));
|
||||
}
|
||||
IJSXName name = this.jsx_parseNamespacedName();
|
||||
INode value = this.eat(eq) ? this.jsx_parseAttributeValue() : null;
|
||||
return this.finishNode(new JSXAttribute(loc, name, value));
|
||||
}
|
||||
|
||||
/** Parses JSX opening tag starting after '<'. */
|
||||
private JSXOpeningElement jsx_parseOpeningElementAt(Position startLoc) {
|
||||
SourceLocation loc = new SourceLocation(startLoc);
|
||||
List<IJSXAttribute> attributes = new ArrayList<>();
|
||||
IJSXName name = this.jsx_parseElementName();
|
||||
while (this.type != slash && this.type != jsxTagEnd)
|
||||
attributes.add(this.jsx_parseAttribute());
|
||||
boolean selfClosing = this.eat(slash);
|
||||
this.expect(jsxTagEnd);
|
||||
return this.finishNode(new JSXOpeningElement(loc, name, attributes, selfClosing));
|
||||
}
|
||||
|
||||
/** Parses JSX closing tag starting after '</'. */
|
||||
private JSXClosingElement jsx_parseClosingElementAt(Position startLoc) {
|
||||
SourceLocation loc = new SourceLocation(startLoc);
|
||||
IJSXName name = this.jsx_parseElementName();
|
||||
this.expect(jsxTagEnd);
|
||||
return this.finishNode(new JSXClosingElement(loc, name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses entire JSX element, including its opening tag
|
||||
* (starting after '<'), attributes, contents and closing tag.
|
||||
*/
|
||||
private JSXElement jsx_parseElementAt(Position startLoc) {
|
||||
SourceLocation loc = new SourceLocation(startLoc);
|
||||
List<INode> children = new ArrayList<INode>();
|
||||
JSXOpeningElement openingElement = this.jsx_parseOpeningElementAt(startLoc);
|
||||
JSXClosingElement closingElement = null;
|
||||
|
||||
if (!openingElement.isSelfClosing()) {
|
||||
contents:
|
||||
for (;;) {
|
||||
if (type == jsxTagStart) {
|
||||
startLoc = this.startLoc;
|
||||
this.next();
|
||||
if (this.eat(slash)) {
|
||||
closingElement = this.jsx_parseClosingElementAt(startLoc);
|
||||
break contents;
|
||||
}
|
||||
children.add(this.jsx_parseElementAt(startLoc));
|
||||
} else if (type == jsxText) {
|
||||
children.add(this.parseExprAtom(null));
|
||||
} else if (type == braceL) {
|
||||
children.add(this.jsx_parseExpressionContainer());
|
||||
} else {
|
||||
this.unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
String closingQualName = getQualifiedJSXName(openingElement.getName());
|
||||
if (!Objects.equals(getQualifiedJSXName(closingElement.getName()), closingQualName)) {
|
||||
// prettify for error message
|
||||
if (closingQualName == null)
|
||||
closingQualName = "";
|
||||
this.raise(
|
||||
closingElement,
|
||||
"Expected corresponding JSX closing tag for <" + closingQualName + ">");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.type == relational && "<".equals(this.value)) {
|
||||
this.raise(this.start, "Adjacent JSX elements must be wrapped in an enclosing tag");
|
||||
}
|
||||
return this.finishNode(new JSXElement(loc, openingElement, children, closingElement));
|
||||
}
|
||||
|
||||
/** Parses entire JSX element from current position. */
|
||||
private JSXElement jsx_parseElement() {
|
||||
Position startLoc = this.startLoc;
|
||||
this.next();
|
||||
return this.jsx_parseElementAt(startLoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Expression parseExprAtom(DestructuringErrors refDestructuringErrors) {
|
||||
if (this.type == jsxText) {
|
||||
return this.parseLiteral(this.type, this.value);
|
||||
} else if (this.type == jsxTagStart) {
|
||||
return this.jsx_parseElement();
|
||||
} else {
|
||||
return super.parseExprAtom(refDestructuringErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Token readToken(int code) {
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
263
javascript/extractor/src/com/semmle/jcorn/jsx/XHTMLEntities.java
Normal file
263
javascript/extractor/src/com/semmle/jcorn/jsx/XHTMLEntities.java
Normal file
@@ -0,0 +1,263 @@
|
||||
package com.semmle.jcorn.jsx;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class XHTMLEntities {
|
||||
public static final Map<String, Character> ENTITIES = new LinkedHashMap<>();
|
||||
static {
|
||||
ENTITIES.put("quot", '\u0022');
|
||||
ENTITIES.put("amp", '&');
|
||||
ENTITIES.put("apos", '\'');
|
||||
ENTITIES.put("lt", '<');
|
||||
ENTITIES.put("gt", '>');
|
||||
ENTITIES.put("nbsp", '\u00A0');
|
||||
ENTITIES.put("iexcl", '\u00A1');
|
||||
ENTITIES.put("cent", '\u00A2');
|
||||
ENTITIES.put("pound", '\u00A3');
|
||||
ENTITIES.put("curren", '\u00A4');
|
||||
ENTITIES.put("yen", '\u00A5');
|
||||
ENTITIES.put("brvbar", '\u00A6');
|
||||
ENTITIES.put("sect", '\u00A7');
|
||||
ENTITIES.put("uml", '\u00A8');
|
||||
ENTITIES.put("copy", '\u00A9');
|
||||
ENTITIES.put("ordf", '\u00AA');
|
||||
ENTITIES.put("laquo", '\u00AB');
|
||||
ENTITIES.put("not", '\u00AC');
|
||||
ENTITIES.put("shy", '\u00AD');
|
||||
ENTITIES.put("reg", '\u00AE');
|
||||
ENTITIES.put("macr", '\u00AF');
|
||||
ENTITIES.put("deg", '\u00B0');
|
||||
ENTITIES.put("plusmn", '\u00B1');
|
||||
ENTITIES.put("sup2", '\u00B2');
|
||||
ENTITIES.put("sup3", '\u00B3');
|
||||
ENTITIES.put("acute", '\u00B4');
|
||||
ENTITIES.put("micro", '\u00B5');
|
||||
ENTITIES.put("para", '\u00B6');
|
||||
ENTITIES.put("middot", '\u00B7');
|
||||
ENTITIES.put("cedil", '\u00B8');
|
||||
ENTITIES.put("sup1", '\u00B9');
|
||||
ENTITIES.put("ordm", '\u00BA');
|
||||
ENTITIES.put("raquo", '\u00BB');
|
||||
ENTITIES.put("frac14", '\u00BC');
|
||||
ENTITIES.put("frac12", '\u00BD');
|
||||
ENTITIES.put("frac34", '\u00BE');
|
||||
ENTITIES.put("iquest", '\u00BF');
|
||||
ENTITIES.put("Agrave", '\u00C0');
|
||||
ENTITIES.put("Aacute", '\u00C1');
|
||||
ENTITIES.put("Acirc", '\u00C2');
|
||||
ENTITIES.put("Atilde", '\u00C3');
|
||||
ENTITIES.put("Auml", '\u00C4');
|
||||
ENTITIES.put("Aring", '\u00C5');
|
||||
ENTITIES.put("AElig", '\u00C6');
|
||||
ENTITIES.put("Ccedil", '\u00C7');
|
||||
ENTITIES.put("Egrave", '\u00C8');
|
||||
ENTITIES.put("Eacute", '\u00C9');
|
||||
ENTITIES.put("Ecirc", '\u00CA');
|
||||
ENTITIES.put("Euml", '\u00CB');
|
||||
ENTITIES.put("Igrave", '\u00CC');
|
||||
ENTITIES.put("Iacute", '\u00CD');
|
||||
ENTITIES.put("Icirc", '\u00CE');
|
||||
ENTITIES.put("Iuml", '\u00CF');
|
||||
ENTITIES.put("ETH", '\u00D0');
|
||||
ENTITIES.put("Ntilde", '\u00D1');
|
||||
ENTITIES.put("Ograve", '\u00D2');
|
||||
ENTITIES.put("Oacute", '\u00D3');
|
||||
ENTITIES.put("Ocirc", '\u00D4');
|
||||
ENTITIES.put("Otilde", '\u00D5');
|
||||
ENTITIES.put("Ouml", '\u00D6');
|
||||
ENTITIES.put("times", '\u00D7');
|
||||
ENTITIES.put("Oslash", '\u00D8');
|
||||
ENTITIES.put("Ugrave", '\u00D9');
|
||||
ENTITIES.put("Uacute", '\u00DA');
|
||||
ENTITIES.put("Ucirc", '\u00DB');
|
||||
ENTITIES.put("Uuml", '\u00DC');
|
||||
ENTITIES.put("Yacute", '\u00DD');
|
||||
ENTITIES.put("THORN", '\u00DE');
|
||||
ENTITIES.put("szlig", '\u00DF');
|
||||
ENTITIES.put("agrave", '\u00E0');
|
||||
ENTITIES.put("aacute", '\u00E1');
|
||||
ENTITIES.put("acirc", '\u00E2');
|
||||
ENTITIES.put("atilde", '\u00E3');
|
||||
ENTITIES.put("auml", '\u00E4');
|
||||
ENTITIES.put("aring", '\u00E5');
|
||||
ENTITIES.put("aelig", '\u00E6');
|
||||
ENTITIES.put("ccedil", '\u00E7');
|
||||
ENTITIES.put("egrave", '\u00E8');
|
||||
ENTITIES.put("eacute", '\u00E9');
|
||||
ENTITIES.put("ecirc", '\u00EA');
|
||||
ENTITIES.put("euml", '\u00EB');
|
||||
ENTITIES.put("igrave", '\u00EC');
|
||||
ENTITIES.put("iacute", '\u00ED');
|
||||
ENTITIES.put("icirc", '\u00EE');
|
||||
ENTITIES.put("iuml", '\u00EF');
|
||||
ENTITIES.put("eth", '\u00F0');
|
||||
ENTITIES.put("ntilde", '\u00F1');
|
||||
ENTITIES.put("ograve", '\u00F2');
|
||||
ENTITIES.put("oacute", '\u00F3');
|
||||
ENTITIES.put("ocirc", '\u00F4');
|
||||
ENTITIES.put("otilde", '\u00F5');
|
||||
ENTITIES.put("ouml", '\u00F6');
|
||||
ENTITIES.put("divide", '\u00F7');
|
||||
ENTITIES.put("oslash", '\u00F8');
|
||||
ENTITIES.put("ugrave", '\u00F9');
|
||||
ENTITIES.put("uacute", '\u00FA');
|
||||
ENTITIES.put("ucirc", '\u00FB');
|
||||
ENTITIES.put("uuml", '\u00FC');
|
||||
ENTITIES.put("yacute", '\u00FD');
|
||||
ENTITIES.put("thorn", '\u00FE');
|
||||
ENTITIES.put("yuml", '\u00FF');
|
||||
ENTITIES.put("OElig", '\u0152');
|
||||
ENTITIES.put("oelig", '\u0153');
|
||||
ENTITIES.put("Scaron", '\u0160');
|
||||
ENTITIES.put("scaron", '\u0161');
|
||||
ENTITIES.put("Yuml", '\u0178');
|
||||
ENTITIES.put("fnof", '\u0192');
|
||||
ENTITIES.put("circ", '\u02C6');
|
||||
ENTITIES.put("tilde", '\u02DC');
|
||||
ENTITIES.put("Alpha", '\u0391');
|
||||
ENTITIES.put("Beta", '\u0392');
|
||||
ENTITIES.put("Gamma", '\u0393');
|
||||
ENTITIES.put("Delta", '\u0394');
|
||||
ENTITIES.put("Epsilon", '\u0395');
|
||||
ENTITIES.put("Zeta", '\u0396');
|
||||
ENTITIES.put("Eta", '\u0397');
|
||||
ENTITIES.put("Theta", '\u0398');
|
||||
ENTITIES.put("Iota", '\u0399');
|
||||
ENTITIES.put("Kappa", '\u039A');
|
||||
ENTITIES.put("Lambda", '\u039B');
|
||||
ENTITIES.put("Mu", '\u039C');
|
||||
ENTITIES.put("Nu", '\u039D');
|
||||
ENTITIES.put("Xi", '\u039E');
|
||||
ENTITIES.put("Omicron", '\u039F');
|
||||
ENTITIES.put("Pi", '\u03A0');
|
||||
ENTITIES.put("Rho", '\u03A1');
|
||||
ENTITIES.put("Sigma", '\u03A3');
|
||||
ENTITIES.put("Tau", '\u03A4');
|
||||
ENTITIES.put("Upsilon", '\u03A5');
|
||||
ENTITIES.put("Phi", '\u03A6');
|
||||
ENTITIES.put("Chi", '\u03A7');
|
||||
ENTITIES.put("Psi", '\u03A8');
|
||||
ENTITIES.put("Omega", '\u03A9');
|
||||
ENTITIES.put("alpha", '\u03B1');
|
||||
ENTITIES.put("beta", '\u03B2');
|
||||
ENTITIES.put("gamma", '\u03B3');
|
||||
ENTITIES.put("delta", '\u03B4');
|
||||
ENTITIES.put("epsilon", '\u03B5');
|
||||
ENTITIES.put("zeta", '\u03B6');
|
||||
ENTITIES.put("eta", '\u03B7');
|
||||
ENTITIES.put("theta", '\u03B8');
|
||||
ENTITIES.put("iota", '\u03B9');
|
||||
ENTITIES.put("kappa", '\u03BA');
|
||||
ENTITIES.put("lambda", '\u03BB');
|
||||
ENTITIES.put("mu", '\u03BC');
|
||||
ENTITIES.put("nu", '\u03BD');
|
||||
ENTITIES.put("xi", '\u03BE');
|
||||
ENTITIES.put("omicron", '\u03BF');
|
||||
ENTITIES.put("pi", '\u03C0');
|
||||
ENTITIES.put("rho", '\u03C1');
|
||||
ENTITIES.put("sigmaf", '\u03C2');
|
||||
ENTITIES.put("sigma", '\u03C3');
|
||||
ENTITIES.put("tau", '\u03C4');
|
||||
ENTITIES.put("upsilon", '\u03C5');
|
||||
ENTITIES.put("phi", '\u03C6');
|
||||
ENTITIES.put("chi", '\u03C7');
|
||||
ENTITIES.put("psi", '\u03C8');
|
||||
ENTITIES.put("omega", '\u03C9');
|
||||
ENTITIES.put("thetasym", '\u03D1');
|
||||
ENTITIES.put("upsih", '\u03D2');
|
||||
ENTITIES.put("piv", '\u03D6');
|
||||
ENTITIES.put("ensp", '\u2002');
|
||||
ENTITIES.put("emsp", '\u2003');
|
||||
ENTITIES.put("thinsp", '\u2009');
|
||||
ENTITIES.put("zwnj", '\u200C');
|
||||
ENTITIES.put("zwj", '\u200D');
|
||||
ENTITIES.put("lrm", '\u200E');
|
||||
ENTITIES.put("rlm", '\u200F');
|
||||
ENTITIES.put("ndash", '\u2013');
|
||||
ENTITIES.put("mdash", '\u2014');
|
||||
ENTITIES.put("lsquo", '\u2018');
|
||||
ENTITIES.put("rsquo", '\u2019');
|
||||
ENTITIES.put("sbquo", '\u201A');
|
||||
ENTITIES.put("ldquo", '\u201C');
|
||||
ENTITIES.put("rdquo", '\u201D');
|
||||
ENTITIES.put("bdquo", '\u201E');
|
||||
ENTITIES.put("dagger", '\u2020');
|
||||
ENTITIES.put("Dagger", '\u2021');
|
||||
ENTITIES.put("bull", '\u2022');
|
||||
ENTITIES.put("hellip", '\u2026');
|
||||
ENTITIES.put("permil", '\u2030');
|
||||
ENTITIES.put("prime", '\u2032');
|
||||
ENTITIES.put("Prime", '\u2033');
|
||||
ENTITIES.put("lsaquo", '\u2039');
|
||||
ENTITIES.put("rsaquo", '\u203A');
|
||||
ENTITIES.put("oline", '\u203E');
|
||||
ENTITIES.put("frasl", '\u2044');
|
||||
ENTITIES.put("euro", '\u20AC');
|
||||
ENTITIES.put("image", '\u2111');
|
||||
ENTITIES.put("weierp", '\u2118');
|
||||
ENTITIES.put("real", '\u211C');
|
||||
ENTITIES.put("trade", '\u2122');
|
||||
ENTITIES.put("alefsym", '\u2135');
|
||||
ENTITIES.put("larr", '\u2190');
|
||||
ENTITIES.put("uarr", '\u2191');
|
||||
ENTITIES.put("rarr", '\u2192');
|
||||
ENTITIES.put("darr", '\u2193');
|
||||
ENTITIES.put("harr", '\u2194');
|
||||
ENTITIES.put("crarr", '\u21B5');
|
||||
ENTITIES.put("lArr", '\u21D0');
|
||||
ENTITIES.put("uArr", '\u21D1');
|
||||
ENTITIES.put("rArr", '\u21D2');
|
||||
ENTITIES.put("dArr", '\u21D3');
|
||||
ENTITIES.put("hArr", '\u21D4');
|
||||
ENTITIES.put("forall", '\u2200');
|
||||
ENTITIES.put("part", '\u2202');
|
||||
ENTITIES.put("exist", '\u2203');
|
||||
ENTITIES.put("empty", '\u2205');
|
||||
ENTITIES.put("nabla", '\u2207');
|
||||
ENTITIES.put("isin", '\u2208');
|
||||
ENTITIES.put("notin", '\u2209');
|
||||
ENTITIES.put("ni", '\u220B');
|
||||
ENTITIES.put("prod", '\u220F');
|
||||
ENTITIES.put("sum", '\u2211');
|
||||
ENTITIES.put("minus", '\u2212');
|
||||
ENTITIES.put("lowast", '\u2217');
|
||||
ENTITIES.put("radic", '\u221A');
|
||||
ENTITIES.put("prop", '\u221D');
|
||||
ENTITIES.put("infin", '\u221E');
|
||||
ENTITIES.put("ang", '\u2220');
|
||||
ENTITIES.put("and", '\u2227');
|
||||
ENTITIES.put("or", '\u2228');
|
||||
ENTITIES.put("cap", '\u2229');
|
||||
ENTITIES.put("cup", '\u222A');
|
||||
ENTITIES.put("'int'", '\u222B');
|
||||
ENTITIES.put("there4", '\u2234');
|
||||
ENTITIES.put("sim", '\u223C');
|
||||
ENTITIES.put("cong", '\u2245');
|
||||
ENTITIES.put("asymp", '\u2248');
|
||||
ENTITIES.put("ne", '\u2260');
|
||||
ENTITIES.put("equiv", '\u2261');
|
||||
ENTITIES.put("le", '\u2264');
|
||||
ENTITIES.put("ge", '\u2265');
|
||||
ENTITIES.put("sub", '\u2282');
|
||||
ENTITIES.put("sup", '\u2283');
|
||||
ENTITIES.put("nsub", '\u2284');
|
||||
ENTITIES.put("sube", '\u2286');
|
||||
ENTITIES.put("supe", '\u2287');
|
||||
ENTITIES.put("oplus", '\u2295');
|
||||
ENTITIES.put("otimes", '\u2297');
|
||||
ENTITIES.put("perp", '\u22A5');
|
||||
ENTITIES.put("sdot", '\u22C5');
|
||||
ENTITIES.put("lceil", '\u2308');
|
||||
ENTITIES.put("rceil", '\u2309');
|
||||
ENTITIES.put("lfloor", '\u230A');
|
||||
ENTITIES.put("rfloor", '\u230B');
|
||||
ENTITIES.put("lang", '\u2329');
|
||||
ENTITIES.put("rang", '\u232A');
|
||||
ENTITIES.put("loz", '\u25CA');
|
||||
ENTITIES.put("spades", '\u2660');
|
||||
ENTITIES.put("clubs", '\u2663');
|
||||
ENTITIES.put("hearts", '\u2665');
|
||||
ENTITIES.put("diams", '\u2666');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An expression involving an operator and two operands; may be an
|
||||
* {@link AssignmentExpression}, a {@link BinaryExpression} or a {@link LogicalExpression}.
|
||||
*/
|
||||
public abstract class ABinaryExpression extends Expression {
|
||||
private final String operator;
|
||||
private final Expression left, right;
|
||||
|
||||
public ABinaryExpression(SourceLocation loc, String type, String operator, Expression left, Expression right) {
|
||||
super(type, loc);
|
||||
this.operator = operator;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public Expression getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public Expression getRight() {
|
||||
return right;
|
||||
}
|
||||
}
|
||||
81
javascript/extractor/src/com/semmle/js/ast/AClass.java
Normal file
81
javascript/extractor/src/com/semmle/js/ast/AClass.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.INodeWithSymbol;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
/**
|
||||
* Common backing class for {@linkplain ClassDeclaration} and {@linkplain ClassExpression}.
|
||||
*/
|
||||
public class AClass implements INodeWithSymbol {
|
||||
private final Identifier id;
|
||||
private final List<TypeParameter> typeParameters;
|
||||
private final Expression superClass;
|
||||
private final List<ITypeExpression> superInterfaces;
|
||||
private final ClassBody body;
|
||||
private final List<Decorator> decorators;
|
||||
private int typeSymbol = -1;
|
||||
|
||||
public AClass(Identifier id, List<TypeParameter> typeParameters, Expression superClass, List<ITypeExpression> superInterfaces,
|
||||
ClassBody body) {
|
||||
this.id = id;
|
||||
this.typeParameters = typeParameters;
|
||||
this.superClass = superClass;
|
||||
this.superInterfaces = superInterfaces;
|
||||
this.body = body;
|
||||
this.decorators = new ArrayList<Decorator>();
|
||||
}
|
||||
|
||||
public Identifier getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean hasId() {
|
||||
return id != null;
|
||||
}
|
||||
|
||||
public List<TypeParameter> getTypeParameters() {
|
||||
return typeParameters;
|
||||
}
|
||||
|
||||
public boolean hasTypeParameters() {
|
||||
return !typeParameters.isEmpty();
|
||||
}
|
||||
|
||||
public Expression getSuperClass() {
|
||||
return superClass;
|
||||
}
|
||||
|
||||
public boolean hasSuperClass() {
|
||||
return superClass != null;
|
||||
}
|
||||
|
||||
public List<ITypeExpression> getSuperInterfaces() {
|
||||
return superInterfaces;
|
||||
}
|
||||
|
||||
public ClassBody getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void addDecorators(List<Decorator> decorators) {
|
||||
this.decorators.addAll(decorators);
|
||||
}
|
||||
|
||||
public List<Decorator> getDecorators() {
|
||||
return decorators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSymbol() {
|
||||
return typeSymbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbol(int symbol) {
|
||||
this.typeSymbol = symbol;
|
||||
}
|
||||
}
|
||||
144
javascript/extractor/src/com/semmle/js/ast/AFunction.java
Normal file
144
javascript/extractor/src/com/semmle/js/ast/AFunction.java
Normal file
@@ -0,0 +1,144 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.DecoratorList;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
public class AFunction<B> {
|
||||
private final Identifier id;
|
||||
private final List<IPattern> params, allParams;
|
||||
private final List<Expression> rawParams, defaults;
|
||||
private final IPattern rest;
|
||||
private final B body;
|
||||
private final boolean generator, async;
|
||||
private final List<TypeParameter> typeParameters;
|
||||
private final ITypeExpression returnType;
|
||||
private final List<ITypeExpression> parameterTypes;
|
||||
private final ITypeExpression thisParameterType;
|
||||
private final List<DecoratorList> parameterDecorators;
|
||||
|
||||
public AFunction(Identifier id, List<Expression> params, B body, boolean generator, boolean async,
|
||||
List<TypeParameter> typeParameters, List<ITypeExpression> parameterTypes, List<DecoratorList> parameterDecorators,
|
||||
ITypeExpression returnType, ITypeExpression thisParameterType) {
|
||||
this.id = id;
|
||||
this.params = new ArrayList<IPattern>(params.size());
|
||||
this.defaults = new ArrayList<Expression>(params.size());
|
||||
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;
|
||||
for (Expression param : params) {
|
||||
if (param instanceof RestElement) {
|
||||
rest = (IPattern)((RestElement) param).getArgument();
|
||||
} else if (param instanceof AssignmentPattern) {
|
||||
AssignmentPattern ap = (AssignmentPattern) param;
|
||||
this.params.add((IPattern)ap.getLeft());
|
||||
this.defaults.add(ap.getRight());
|
||||
} else {
|
||||
// workaround for parser bug, which currently (erroneously) accepts
|
||||
// async arrow functions with parens around their parameters
|
||||
param = param.stripParens();
|
||||
this.params.add((IPattern) param);
|
||||
this.defaults.add(null);
|
||||
}
|
||||
}
|
||||
this.rest = rest;
|
||||
|
||||
this.allParams = new ArrayList<IPattern>(this.params);
|
||||
if (rest != null)
|
||||
this.allParams.add(rest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this function have a name?
|
||||
*/
|
||||
public boolean hasId() {
|
||||
return id != null;
|
||||
}
|
||||
|
||||
public Identifier getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<IPattern> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public boolean hasDefault(int i) {
|
||||
return i < defaults.size();
|
||||
}
|
||||
|
||||
public Expression getDefault(int i) {
|
||||
if (i >= defaults.size())
|
||||
return null;
|
||||
return defaults.get(i);
|
||||
}
|
||||
|
||||
public boolean hasRest() {
|
||||
return rest != null;
|
||||
}
|
||||
|
||||
public IPattern getRest() {
|
||||
return rest;
|
||||
}
|
||||
|
||||
public B getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public boolean isGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
public boolean isAsync() {
|
||||
return async;
|
||||
}
|
||||
|
||||
public List<IPattern> getAllParams() {
|
||||
return allParams;
|
||||
}
|
||||
|
||||
public List<Expression> getRawParams() {
|
||||
return rawParams;
|
||||
}
|
||||
|
||||
public ITypeExpression getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
public boolean hasParameterType(int i) {
|
||||
return getParameterType(i) != null;
|
||||
}
|
||||
|
||||
public ITypeExpression getParameterType(int i) {
|
||||
if (i >= parameterTypes.size())
|
||||
return null;
|
||||
return parameterTypes.get(i);
|
||||
}
|
||||
|
||||
public List<ITypeExpression> getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
public List<TypeParameter> getTypeParameters() {
|
||||
return typeParameters;
|
||||
}
|
||||
|
||||
public ITypeExpression getThisParameterType() {
|
||||
return thisParameterType;
|
||||
}
|
||||
|
||||
public List<DecoratorList> getParameterDecorators() {
|
||||
return parameterDecorators;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.DecoratorList;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
/**
|
||||
* A function expression, which may be either an {@link ArrowFunctionExpression} or
|
||||
* a normal {@link FunctionExpression}.
|
||||
*/
|
||||
public abstract class AFunctionExpression extends Expression implements IFunction {
|
||||
private final AFunction<? extends Node> fn;
|
||||
private int symbol = -1;
|
||||
|
||||
public AFunctionExpression(String type, SourceLocation loc, Identifier id,
|
||||
List<Expression> params, Node body, 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) {
|
||||
super(type, loc);
|
||||
this.fn = fn;
|
||||
}
|
||||
|
||||
@Override public Identifier getId() { return fn.getId(); }
|
||||
@Override public List<IPattern> getParams() { return fn.getParams(); }
|
||||
@Override public boolean hasDefault(int i) { return fn.hasDefault(i); }
|
||||
@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
|
||||
public boolean hasDeclareKeyword() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbol(int symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
}
|
||||
853
javascript/extractor/src/com/semmle/js/ast/AST2JSON.java
Normal file
853
javascript/extractor/src/com/semmle/js/ast/AST2JSON.java
Normal file
@@ -0,0 +1,853 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.semmle.js.ast.AClass;
|
||||
import com.semmle.js.ast.ArrayExpression;
|
||||
import com.semmle.js.ast.ArrayPattern;
|
||||
import com.semmle.js.ast.AssignmentExpression;
|
||||
import com.semmle.js.ast.AssignmentPattern;
|
||||
import com.semmle.js.ast.BinaryExpression;
|
||||
import com.semmle.js.ast.BlockStatement;
|
||||
import com.semmle.js.ast.BreakStatement;
|
||||
import com.semmle.js.ast.CallExpression;
|
||||
import com.semmle.js.ast.CatchClause;
|
||||
import com.semmle.js.ast.ClassBody;
|
||||
import com.semmle.js.ast.ClassDeclaration;
|
||||
import com.semmle.js.ast.ClassExpression;
|
||||
import com.semmle.js.ast.ComprehensionBlock;
|
||||
import com.semmle.js.ast.ComprehensionExpression;
|
||||
import com.semmle.js.ast.ConditionalExpression;
|
||||
import com.semmle.js.ast.ContinueStatement;
|
||||
import com.semmle.js.ast.DebuggerStatement;
|
||||
import com.semmle.js.ast.DefaultVisitor;
|
||||
import com.semmle.js.ast.DoWhileStatement;
|
||||
import com.semmle.js.ast.EmptyStatement;
|
||||
import com.semmle.js.ast.EnhancedForStatement;
|
||||
import com.semmle.js.ast.ExportAllDeclaration;
|
||||
import com.semmle.js.ast.ExportDefaultDeclaration;
|
||||
import com.semmle.js.ast.ExportNamedDeclaration;
|
||||
import com.semmle.js.ast.ExportSpecifier;
|
||||
import com.semmle.js.ast.Expression;
|
||||
import com.semmle.js.ast.ExpressionStatement;
|
||||
import com.semmle.js.ast.ForStatement;
|
||||
import com.semmle.js.ast.IFunction;
|
||||
import com.semmle.js.ast.INode;
|
||||
import com.semmle.js.ast.Identifier;
|
||||
import com.semmle.js.ast.IfStatement;
|
||||
import com.semmle.js.ast.ImportDeclaration;
|
||||
import com.semmle.js.ast.ImportNamespaceSpecifier;
|
||||
import com.semmle.js.ast.ImportSpecifier;
|
||||
import com.semmle.js.ast.LabeledStatement;
|
||||
import com.semmle.js.ast.LetExpression;
|
||||
import com.semmle.js.ast.LetStatement;
|
||||
import com.semmle.js.ast.Literal;
|
||||
import com.semmle.js.ast.LogicalExpression;
|
||||
import com.semmle.js.ast.MemberExpression;
|
||||
import com.semmle.js.ast.MetaProperty;
|
||||
import com.semmle.js.ast.MemberDefinition;
|
||||
import com.semmle.js.ast.NewExpression;
|
||||
import com.semmle.js.ast.Node;
|
||||
import com.semmle.js.ast.ObjectExpression;
|
||||
import com.semmle.js.ast.ObjectPattern;
|
||||
import com.semmle.js.ast.ParenthesizedExpression;
|
||||
import com.semmle.js.ast.Position;
|
||||
import com.semmle.js.ast.Program;
|
||||
import com.semmle.js.ast.Property;
|
||||
import com.semmle.js.ast.ReturnStatement;
|
||||
import com.semmle.js.ast.SequenceExpression;
|
||||
import com.semmle.js.ast.SourceLocation;
|
||||
import com.semmle.js.ast.SpreadElement;
|
||||
import com.semmle.js.ast.Super;
|
||||
import com.semmle.js.ast.SwitchCase;
|
||||
import com.semmle.js.ast.SwitchStatement;
|
||||
import com.semmle.js.ast.TaggedTemplateExpression;
|
||||
import com.semmle.js.ast.TemplateElement;
|
||||
import com.semmle.js.ast.TemplateLiteral;
|
||||
import com.semmle.js.ast.ThisExpression;
|
||||
import com.semmle.js.ast.ThrowStatement;
|
||||
import com.semmle.js.ast.TryStatement;
|
||||
import com.semmle.js.ast.UnaryExpression;
|
||||
import com.semmle.js.ast.UpdateExpression;
|
||||
import com.semmle.js.ast.VariableDeclaration;
|
||||
import com.semmle.js.ast.VariableDeclarator;
|
||||
import com.semmle.js.ast.WhileStatement;
|
||||
import com.semmle.js.ast.WithStatement;
|
||||
import com.semmle.js.ast.YieldExpression;
|
||||
import com.semmle.js.ast.jsx.JSXAttribute;
|
||||
import com.semmle.js.ast.jsx.JSXClosingElement;
|
||||
import com.semmle.js.ast.jsx.JSXElement;
|
||||
import com.semmle.js.ast.jsx.JSXEmptyExpression;
|
||||
import com.semmle.js.ast.jsx.JSXExpressionContainer;
|
||||
import com.semmle.js.ast.jsx.JSXIdentifier;
|
||||
import com.semmle.js.ast.jsx.JSXMemberExpression;
|
||||
import com.semmle.js.ast.jsx.JSXNamespacedName;
|
||||
import com.semmle.js.ast.jsx.JSXOpeningElement;
|
||||
import com.semmle.js.ast.jsx.JSXSpreadAttribute;
|
||||
import com.semmle.ts.ast.ExportWholeDeclaration;
|
||||
import com.semmle.ts.ast.ExternalModuleReference;
|
||||
import com.semmle.ts.ast.ImportWholeDeclaration;
|
||||
import com.semmle.ts.ast.InterfaceDeclaration;
|
||||
import com.semmle.ts.ast.NamespaceDeclaration;
|
||||
import com.semmle.util.data.StringUtil;
|
||||
|
||||
/**
|
||||
* Convert ASTs to their JSON representation.
|
||||
*/
|
||||
public class AST2JSON extends DefaultVisitor<Void, JsonElement> {
|
||||
public static JsonElement convert(INode nd) {
|
||||
return new AST2JSON().visit(nd);
|
||||
}
|
||||
|
||||
private JsonElement visit(INode nd) {
|
||||
if (nd == null)
|
||||
return JsonNull.INSTANCE;
|
||||
return nd.accept(this, null);
|
||||
}
|
||||
|
||||
private JsonArray visit(List<? extends INode> nds) {
|
||||
JsonArray result = new JsonArray();
|
||||
nds.stream().forEach((nd) -> {
|
||||
result.add(visit(nd));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private JsonElement visitPrimitive(Object o) {
|
||||
if (o == null)
|
||||
return JsonNull.INSTANCE;
|
||||
if (o instanceof Boolean)
|
||||
return new JsonPrimitive((Boolean) o);
|
||||
if (o instanceof Number)
|
||||
return new JsonPrimitive((Number) o);
|
||||
return new JsonPrimitive(String.valueOf(o));
|
||||
}
|
||||
|
||||
private JsonObject mkNode(INode nd) {
|
||||
String type = nd.getType();
|
||||
return mkNode(nd, type);
|
||||
}
|
||||
|
||||
private JsonObject mkNode(INode nd, String type) {
|
||||
JsonObject result = new JsonObject();
|
||||
result.add("type", new JsonPrimitive(type));
|
||||
if (nd.getLoc() != null)
|
||||
result.add("loc", visit(nd.getLoc()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private JsonObject visit(SourceLocation loc) {
|
||||
JsonObject result = new JsonObject();
|
||||
result.add("start", visit(loc.getStart()));
|
||||
result.add("end", visit(loc.getEnd()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private JsonObject visit(Position pos) {
|
||||
JsonObject result = new JsonObject();
|
||||
result.add("line", visitPrimitive(pos.getLine()));
|
||||
result.add("column", visitPrimitive(pos.getColumn()));
|
||||
result.add("offset", visitPrimitive(pos.getOffset()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ArrayExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("elements", visit(nd.getElements()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(AssignmentExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("operator", visitPrimitive(nd.getOperator()));
|
||||
result.add("left", visit(nd.getLeft()));
|
||||
result.add("right", visit(nd.getRight()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(AssignmentPattern nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("left", visit(nd.getLeft()));
|
||||
result.add("right", visit(nd.getRight()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(BinaryExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("left", visit(nd.getLeft()));
|
||||
result.add("operator", visitPrimitive(nd.getOperator()));
|
||||
result.add("right", visit(nd.getRight()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(BlockStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(BreakStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("label", visit(nd.getLabel()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ContinueStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("label", visit(nd.getLabel()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(CallExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("callee", visit(nd.getCallee()));
|
||||
result.add("arguments", visit(nd.getArguments()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(CatchClause nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("param", visit(nd.getParam()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ClassBody nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ClassDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
visit(nd.getClassDef(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ClassExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
visit(nd.getClassDef(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void visit(AClass classDef, JsonObject result) {
|
||||
result.add("id", visit(classDef.getId()));
|
||||
result.add("superClass", visit(classDef.getSuperClass()));
|
||||
result.add("body", visit(classDef.getBody()));
|
||||
if (!classDef.getDecorators().isEmpty())
|
||||
result.add("decorators", visit(classDef.getDecorators()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ComprehensionBlock nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("left", visit(nd.getLeft()));
|
||||
result.add("right", visit(nd.getRight()));
|
||||
result.add("each", visitPrimitive(nd.isOf()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ComprehensionExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("body", visit(nd.getBody()));
|
||||
result.add("blocks", visit(nd.getBlocks()));
|
||||
result.add("filter", visit(nd.getFilter()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ConditionalExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("test", visit(nd.getTest()));
|
||||
result.add("consequent", visit(nd.getConsequent()));
|
||||
result.add("alternate", visit(nd.getAlternate()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(DoWhileStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("body", visit(nd.getBody()));
|
||||
result.add("test", visit(nd.getTest()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(EmptyStatement nd, Void c) {
|
||||
return this.mkNode(nd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ExportNamedDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("declaration", visit(nd.getDeclaration()));
|
||||
result.add("specifiers", visit(nd.getSpecifiers()));
|
||||
result.add("source", visit(nd.getSource()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ExportSpecifier nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
if (nd.getLocal() != null)
|
||||
result.add("local", visit(nd.getLocal()));
|
||||
result.add("exported", visit(nd.getExported()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ExpressionStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("expression", visit(nd.getExpression()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(EnhancedForStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("left", visit(nd.getLeft()));
|
||||
result.add("right", visit(nd.getRight()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ForStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("init", visit(nd.getInit()));
|
||||
result.add("test", visit(nd.getTest()));
|
||||
result.add("update", visit(nd.getUpdate()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(IFunction nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("id", visit(nd.getId()));
|
||||
result.add("generator", new JsonPrimitive(nd.isGenerator()));
|
||||
result.add("expression", new JsonPrimitive(nd.getBody() instanceof Expression));
|
||||
result.add("async", new JsonPrimitive(nd.isAsync()));
|
||||
result.add("params", visit(nd.getRawParameters()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(Identifier nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("name", new JsonPrimitive(nd.getName()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(IfStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("test", visit(nd.getTest()));
|
||||
result.add("consequent", visit(nd.getConsequent()));
|
||||
result.add("alternate", visit(nd.getAlternate()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ImportDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("specifiers", visit(nd.getSpecifiers()));
|
||||
result.add("source", visit(nd.getSource()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ImportSpecifier nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("imported", visit(nd.getImported()));
|
||||
result.add("local", visit(nd.getLocal()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ImportNamespaceSpecifier nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("local", visit(nd.getLocal()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(LabeledStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("body", visit(nd.getBody()));
|
||||
result.add("label", visit(nd.getLabel()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(Literal nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
if (nd.isRegExp())
|
||||
result.add("value", new JsonObject());
|
||||
else
|
||||
result.add("value", visitPrimitive(nd.getValue()));
|
||||
result.add("raw", new JsonPrimitive(nd.getRaw()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(LogicalExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("left", visit(nd.getLeft()));
|
||||
result.add("operator", visitPrimitive(nd.getOperator()));
|
||||
result.add("right", visit(nd.getRight()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(MemberExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("object", visit(nd.getObject()));
|
||||
result.add("property", visit(nd.getProperty()));
|
||||
result.add("computed", new JsonPrimitive(nd.isComputed()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(MemberDefinition<?> nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("computed", visitPrimitive(nd.isComputed()));
|
||||
result.add("key", visit(nd.getKey()));
|
||||
result.add("static", visitPrimitive(nd.isStatic()));
|
||||
result.add("value", visit(nd.getValue()));
|
||||
if (!nd.getDecorators().isEmpty())
|
||||
result.add("decorators", visit(nd.getDecorators()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(MethodDefinition nd, Void c) {
|
||||
JsonObject result = (JsonObject) super.visit(nd, c);
|
||||
result.add("kind", visitPrimitive(StringUtil.lc(nd.getKind().toString())));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(NewExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("callee", visit(nd.getCallee()));
|
||||
result.add("arguments", visit(nd.getArguments()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject visit(Node nd, Void c) {
|
||||
throw new UnsupportedOperationException(nd.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ObjectExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("properties", visit(nd.getProperties()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ObjectPattern nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("properties", visit(nd.getRawProperties()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ParenthesizedExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("expression", visit(nd.getExpression()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(Program nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("body", visit(nd.getBody()));
|
||||
result.add("sourceType", visitPrimitive(nd.getSourceType()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(Property nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("method", new JsonPrimitive(nd.isMethod()));
|
||||
result.add("shorthand", new JsonPrimitive(nd.isShorthand()));
|
||||
result.add("computed", new JsonPrimitive(nd.isComputed()));
|
||||
result.add("key", visit(nd.getKey()));
|
||||
result.add("kind", new JsonPrimitive(StringUtil.lc(nd.getKind().name())));
|
||||
result.add("value", visit(nd.getRawValue()));
|
||||
if (!nd.getDecorators().isEmpty())
|
||||
result.add("decorators", visit(nd.getDecorators()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(RestElement nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ReturnStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(SequenceExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("expressions", visit(nd.getExpressions()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(SwitchCase nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("consequent", visit(nd.getConsequent()));
|
||||
result.add("test", visit(nd.getTest()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(SwitchStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("discriminant", visit(nd.getDiscriminant()));
|
||||
result.add("cases", visit(nd.getCases()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ThisExpression nd, Void c) {
|
||||
return this.mkNode(nd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ThrowStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(TryStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("block", visit(nd.getBlock()));
|
||||
result.add("handler", visit(nd.getHandler()));
|
||||
result.add("finalizer", visit(nd.getFinalizer()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(UnaryExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("operator", visitPrimitive(nd.getOperator()));
|
||||
result.add("prefix", new JsonPrimitive(nd.isPrefix()));
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(UpdateExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("operator", visitPrimitive(nd.getOperator()));
|
||||
result.add("prefix", new JsonPrimitive(nd.isPrefix()));
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(VariableDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("declarations", visit(nd.getDeclarations()));
|
||||
result.add("kind", new JsonPrimitive(nd.getKind()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(VariableDeclarator nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("id", visit(nd.getId()));
|
||||
result.add("init", visit(nd.getInit()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(WhileStatement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("test", visit(nd.getTest()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ArrayPattern nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("elements", visit(nd.getRawElements()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(WithStatement nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("object", visit(nd.getObject()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(SpreadElement nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(YieldExpression nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
result.add("delegate", visitPrimitive(nd.isDelegating()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(DebuggerStatement nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(TemplateElement nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
JsonObject value = new JsonObject();
|
||||
value.add("cooked", visitPrimitive(nd.getCooked()));
|
||||
value.add("raw", visitPrimitive(nd.getRaw()));
|
||||
result.add("value", value);
|
||||
result.add("tail", visitPrimitive(nd.isTail()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(TemplateLiteral nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("quasis", visit(nd.getQuasis()));
|
||||
result.add("expressions", visit(nd.getExpressions()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(TaggedTemplateExpression nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("tag", visit(nd.getTag()));
|
||||
result.add("quasi", visit(nd.getQuasi()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(LetStatement nd, Void q) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("head", visit(nd.getHead()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(LetExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("head", visit(nd.getHead()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(Super nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(MetaProperty nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("meta", visit(nd.getMeta()));
|
||||
result.add("property", visit(nd.getProperty()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ExportAllDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("source", visit(nd.getSource()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ExportDefaultDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("declaration", visit(nd.getDeclaration()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXIdentifier nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd, "JSXIdentifier");
|
||||
result.add("name", visitPrimitive(nd.getName()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXMemberExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("object", visit(nd.getObject()));
|
||||
result.add("property", visit(nd.getName()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXNamespacedName nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("namespace", visit(nd.getNamespace()));
|
||||
result.add("name", visit(nd.getName()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXEmptyExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXExpressionContainer nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("expression", visit(nd.getExpression()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXOpeningElement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("name", visit(nd.getName()));
|
||||
result.add("attributes", visit(nd.getAttributes()));
|
||||
result.add("selfClosing", visitPrimitive(nd.isSelfClosing()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXClosingElement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("name", visit(nd.getName()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXAttribute nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("name", visit(nd.getName()));
|
||||
result.add("value", visit(nd.getValue()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXSpreadAttribute nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(JSXElement nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("openingElement", visit(nd.getOpeningElement()));
|
||||
result.add("children", visit(nd.getChildren()));
|
||||
result.add("closingElement", visit(nd.getClosingElement()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(AwaitExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("argument", visit(nd.getArgument()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(Decorator nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("expression", visit(nd.getExpression()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(BindExpression nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("object", visit(nd.getObject()));
|
||||
result.add("callee", visit(nd.getCallee()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(NamespaceDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("name", visit(nd.getName()));
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ImportWholeDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("name", visit(nd.getLhs()));
|
||||
result.add("moduleReference", visit(nd.getRhs()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ExportWholeDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("expression", visit(nd.getRhs()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(ExternalModuleReference nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("expression", visit(nd.getExpression()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(DynamicImport nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("source", visit(nd.getSource()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement visit(InterfaceDeclaration nd, Void c) {
|
||||
JsonObject result = this.mkNode(nd);
|
||||
result.add("body", visit(nd.getBody()));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An array expression such as <code>[x, , "hello"]</code>.
|
||||
*/
|
||||
public class ArrayExpression extends Expression {
|
||||
private final List<Expression> elements;
|
||||
|
||||
public ArrayExpression(SourceLocation loc, List<Expression> elements) {
|
||||
super("ArrayExpression", loc);
|
||||
this.elements = elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The elements of the array; omitted elements are represented by {@literal null}.
|
||||
*/
|
||||
public List<Expression> getElements() {
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
78
javascript/extractor/src/com/semmle/js/ast/ArrayPattern.java
Normal file
78
javascript/extractor/src/com/semmle/js/ast/ArrayPattern.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An array pattern as in <code>var [x, y] = z;</code>.
|
||||
*/
|
||||
public class ArrayPattern extends Expression implements DestructuringPattern {
|
||||
private final List<Expression> elements, rawElements;
|
||||
private final List<Expression> defaults;
|
||||
private final Expression restPattern;
|
||||
|
||||
public ArrayPattern(SourceLocation loc, List<Expression> elements) {
|
||||
super("ArrayPattern", loc);
|
||||
this.rawElements = elements;
|
||||
this.elements = new ArrayList<Expression>(elements.size());
|
||||
this.defaults = new ArrayList<Expression>(elements.size());
|
||||
Expression rest = null;
|
||||
for (Expression element : elements) {
|
||||
if (element instanceof RestElement) {
|
||||
rest = ((RestElement)element).getArgument();
|
||||
} else {
|
||||
if (element instanceof AssignmentPattern) {
|
||||
AssignmentPattern assgn = (AssignmentPattern) element;
|
||||
this.defaults.add(assgn.getRight());
|
||||
this.elements.add(assgn.getLeft());
|
||||
} else {
|
||||
this.defaults.add(null);
|
||||
this.elements.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.restPattern = rest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The element patterns of the array pattern; omitted element patterns are
|
||||
* represented by {@literal null}.
|
||||
*/
|
||||
public List<Expression> getElements() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default expressions for the element patterns of the array pattern.
|
||||
*/
|
||||
public List<Expression> getDefaults() {
|
||||
return defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rest pattern of this array pattern, if any.
|
||||
*/
|
||||
public Expression getRest() {
|
||||
return restPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this array pattern have a rest pattern?
|
||||
*/
|
||||
public boolean hasRest() {
|
||||
return restPattern != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The raw element patterns of the array pattern; patterns with defaults
|
||||
* are represented as {@link AssignmentPattern}s.
|
||||
*/
|
||||
public List<Expression> getRawElements() {
|
||||
return rawElements;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
/**
|
||||
* An arrow function expression such as <code>(x) => x*x</code>.
|
||||
*/
|
||||
public class ArrowFunctionExpression extends AFunctionExpression {
|
||||
public ArrowFunctionExpression(SourceLocation loc,
|
||||
List<Expression> params, Node body, Boolean generator, Boolean async) {
|
||||
super("ArrowFunctionExpression", loc, null, params, body, generator, async, Collections.emptyList(), Collections.emptyList(),
|
||||
Collections.emptyList(), null, null);
|
||||
}
|
||||
|
||||
public ArrowFunctionExpression(SourceLocation loc,
|
||||
List<Expression> params, Node body, 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
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An assignment expression such as <code>x = 23</code> or <code>y += 19</code>.
|
||||
*/
|
||||
public class AssignmentExpression extends ABinaryExpression {
|
||||
public AssignmentExpression(SourceLocation loc, String operator, Expression left, Expression right) {
|
||||
super(loc, "AssignmentExpression", operator, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
|
||||
/**
|
||||
* An assignment pattern occurring in an lvalue position.
|
||||
*
|
||||
* Assignment patterns specify default values for function parameters, for-in/for-of loop variables and
|
||||
* in destructuring assignments. We normalise them away during AST construction, attaching information
|
||||
* about the default value directly to the parameter or variable in question. Hence, assignment patterns
|
||||
* are not expected to appear in the AST the extractor works on.
|
||||
*/
|
||||
public class AssignmentPattern extends ABinaryExpression implements IPattern {
|
||||
public AssignmentPattern(SourceLocation loc, String operator, Expression left, Expression right) {
|
||||
super(loc, "AssignmentPattern", operator, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
public class AwaitExpression extends Expression {
|
||||
private Expression argument;
|
||||
|
||||
public AwaitExpression(SourceLocation loc, Expression argument) {
|
||||
super("AwaitExpression", loc);
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
public Expression getArgument() {
|
||||
return argument;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A binary expression such as <code>x + y</code>.
|
||||
*/
|
||||
public class BinaryExpression extends ABinaryExpression {
|
||||
public BinaryExpression(SourceLocation loc, String operator, Expression left, Expression right) {
|
||||
super(loc, "BinaryExpression", operator, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
public class BindExpression extends Expression {
|
||||
private final Expression object, callee;
|
||||
|
||||
public BindExpression(SourceLocation loc, Expression object, Expression callee) {
|
||||
super("BindExpression", loc);
|
||||
this.object = object;
|
||||
this.callee = callee;
|
||||
}
|
||||
|
||||
public boolean hasObject() {
|
||||
return object != null;
|
||||
}
|
||||
|
||||
public Expression getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public Expression getCallee() {
|
||||
return callee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A block statement such as <code>{ console.log("Hi"); }</code>.
|
||||
*/
|
||||
public class BlockStatement extends Statement {
|
||||
private final List<Statement> body;
|
||||
|
||||
public BlockStatement(SourceLocation loc, List<Statement> body) {
|
||||
super("BlockStatement", loc);
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The statements in the block.
|
||||
*/
|
||||
public List<Statement> getBody() {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A break statement either with a label (<code>break outer;</code>) or without (<code>break;</code>).
|
||||
*/
|
||||
public class BreakStatement extends JumpStatement {
|
||||
public BreakStatement(SourceLocation loc, Identifier label) {
|
||||
super("BreakStatement", loc, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
|
||||
/**
|
||||
* A function call expression such as <code>f(1, 1)</code>.
|
||||
*/
|
||||
public class CallExpression extends InvokeExpression {
|
||||
public CallExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments) {
|
||||
super("CallExpression", loc, callee, typeArguments, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
50
javascript/extractor/src/com/semmle/js/ast/CatchClause.java
Normal file
50
javascript/extractor/src/com/semmle/js/ast/CatchClause.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A catch clause with or without a guarding expression.
|
||||
*/
|
||||
public class CatchClause extends Statement {
|
||||
private final IPattern param;
|
||||
private final Expression guard;
|
||||
private final BlockStatement body;
|
||||
|
||||
public CatchClause(SourceLocation loc, IPattern param, Expression guard, BlockStatement body) {
|
||||
super("CatchClause", loc);
|
||||
this.param = param;
|
||||
this.guard = guard;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameter of the catch clause.
|
||||
*/
|
||||
public IPattern getParam() {
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this catch clause have a guarding expression?
|
||||
*/
|
||||
public boolean hasGuard() {
|
||||
return guard != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The guarding expression of the catch clause; may be null.
|
||||
*/
|
||||
public Expression getGuard() {
|
||||
return guard;
|
||||
}
|
||||
|
||||
/**
|
||||
* The body of the catch clause.
|
||||
*/
|
||||
public BlockStatement getBody() {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
36
javascript/extractor/src/com/semmle/js/ast/ClassBody.java
Normal file
36
javascript/extractor/src/com/semmle/js/ast/ClassBody.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The body of a {@linkplain ClassDeclaration} or {@linkplain ClassExpression}.
|
||||
*/
|
||||
public class ClassBody extends Node {
|
||||
private final List<MemberDefinition<?>> body;
|
||||
|
||||
public ClassBody(SourceLocation loc, List<MemberDefinition<?>> body) {
|
||||
super("ClassBody", loc);
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public List<MemberDefinition<?>> getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void addMember(MemberDefinition<?> md) {
|
||||
body.add(md);
|
||||
}
|
||||
|
||||
public MethodDefinition getConstructor() {
|
||||
for (MemberDefinition<?> md : body)
|
||||
if (md.isConstructor())
|
||||
return (MethodDefinition) md;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
/**
|
||||
* A class declaration such as
|
||||
*
|
||||
* <pre>
|
||||
* class ColouredPoint extends Point {
|
||||
* constructor(x, y, colour) {
|
||||
* super(x, y);
|
||||
* this.colour = colour;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class ClassDeclaration extends Statement {
|
||||
private final AClass klass;
|
||||
private final boolean hasDeclareKeyword;
|
||||
private final boolean hasAbstractKeyword;
|
||||
|
||||
public ClassDeclaration(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,
|
||||
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) {
|
||||
super("ClassDeclaration", loc);
|
||||
this.klass = klass;
|
||||
this.hasDeclareKeyword = hasDeclareKeyword;
|
||||
this.hasAbstractKeyword = hasAbstractKeyword;
|
||||
}
|
||||
|
||||
public AClass getClassDef() {
|
||||
return klass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
public void addDecorators(List<Decorator> decorators) {
|
||||
klass.addDecorators(decorators);
|
||||
}
|
||||
|
||||
public List<Decorator> getDecorators() {
|
||||
return klass.getDecorators();
|
||||
}
|
||||
|
||||
public boolean hasDeclareKeyword() {
|
||||
return hasDeclareKeyword;
|
||||
}
|
||||
|
||||
public boolean hasAbstractKeyword() {
|
||||
return hasAbstractKeyword;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
/**
|
||||
* A class expression as in
|
||||
*
|
||||
* <pre>
|
||||
* let ColouredPoint = class extends Point {
|
||||
* constructor(x, y, colour) {
|
||||
* super(x, y);
|
||||
* this.colour = colour;
|
||||
* }
|
||||
* };
|
||||
* </pre>
|
||||
*/
|
||||
public class ClassExpression extends Expression {
|
||||
private final AClass klass;
|
||||
|
||||
public ClassExpression(SourceLocation loc, Identifier id, Expression superClass, ClassBody body) {
|
||||
this(loc, id, Collections.emptyList(), superClass, Collections.emptyList(), body);
|
||||
}
|
||||
|
||||
public ClassExpression(SourceLocation loc, 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) {
|
||||
super("ClassExpression", loc);
|
||||
this.klass = klass;
|
||||
}
|
||||
|
||||
public AClass getClassDef() {
|
||||
return klass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
public void addDecorators(List<Decorator> decorators) {
|
||||
klass.addDecorators(decorators);
|
||||
}
|
||||
|
||||
public Iterable<Decorator> getDecorators() {
|
||||
return klass.getDecorators();
|
||||
}
|
||||
}
|
||||
78
javascript/extractor/src/com/semmle/js/ast/Comment.java
Normal file
78
javascript/extractor/src/com/semmle/js/ast/Comment.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import static com.semmle.js.ast.Comment.Kind.BLOCK;
|
||||
import static com.semmle.js.ast.Comment.Kind.HTML_END;
|
||||
import static com.semmle.js.ast.Comment.Kind.HTML_START;
|
||||
import static com.semmle.js.ast.Comment.Kind.LINE;
|
||||
|
||||
/**
|
||||
* A source code comment.
|
||||
*
|
||||
* This is not part of the SpiderMonkey AST format.
|
||||
*/
|
||||
public class Comment extends SourceElement {
|
||||
/**
|
||||
* The kinds of comments recognized by the parser.
|
||||
*/
|
||||
public static enum Kind {
|
||||
/**
|
||||
* A C++-style line comment starting with two slashes.
|
||||
*/
|
||||
LINE,
|
||||
|
||||
/**
|
||||
* A C-style block comment starting with slash-star and ending with star-slash.
|
||||
*/
|
||||
BLOCK,
|
||||
|
||||
/**
|
||||
* The start of an HTML comment (<code><!--</code>).
|
||||
*/
|
||||
HTML_START,
|
||||
|
||||
/**
|
||||
* The end of an HTML comment (<code>--></code>).
|
||||
*/
|
||||
HTML_END
|
||||
};
|
||||
|
||||
private final String text;
|
||||
private final Kind kind;
|
||||
|
||||
public Comment(SourceLocation loc, String text) {
|
||||
super(loc);
|
||||
this.text = text;
|
||||
String raw = getLoc().getSource();
|
||||
if (raw.startsWith("//"))
|
||||
this.kind = LINE;
|
||||
else if (raw.startsWith("/*"))
|
||||
this.kind = BLOCK;
|
||||
else if (raw.startsWith("<!--"))
|
||||
this.kind = HTML_START;
|
||||
else
|
||||
this.kind = HTML_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* What kind of comment is this?
|
||||
*/
|
||||
public Kind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a JSDoc documentation comment?
|
||||
*/
|
||||
public boolean isDocComment() {
|
||||
return kind == BLOCK && text.startsWith("*");
|
||||
}
|
||||
|
||||
/**
|
||||
* The text of the comment, not including its delimiters.
|
||||
*
|
||||
* For documentation comments, the leading asterisk is included.
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A block in a comprehension expression.
|
||||
*/
|
||||
public class ComprehensionBlock extends Expression {
|
||||
private final IPattern left;
|
||||
private final Expression right;
|
||||
private final boolean of;
|
||||
|
||||
public ComprehensionBlock(SourceLocation loc, IPattern left, Expression right, Boolean of) {
|
||||
super("ComprehensionBlock", loc);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.of = of != Boolean.FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The iterator variable of this comprehension block.
|
||||
*/
|
||||
public IPattern getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
/**
|
||||
* The expression this comprehension block iterates over.
|
||||
*/
|
||||
public Expression getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a <code>for-of</code> comprehension block?
|
||||
*/
|
||||
public boolean isOf() {
|
||||
return of;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A comprehension expression.
|
||||
*/
|
||||
public class ComprehensionExpression extends Expression {
|
||||
private final Expression body;
|
||||
private final List<ComprehensionBlock> blocks;
|
||||
private final Expression filter;
|
||||
private final boolean generator;
|
||||
|
||||
public ComprehensionExpression(SourceLocation loc, Expression body, List<ComprehensionBlock> blocks, Expression filter, Boolean generator) {
|
||||
super("ComprehensionExpression", loc);
|
||||
this.body = body;
|
||||
this.blocks = blocks;
|
||||
this.filter = filter;
|
||||
this.generator = generator == Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The body expression of this comprehension.
|
||||
*/
|
||||
public Expression getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* The comprehension blocks of this comprehension.
|
||||
*/
|
||||
public List<ComprehensionBlock> getBlocks() {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this comprehension expression have a filter expression?
|
||||
*/
|
||||
public boolean hasFilter() {
|
||||
return filter != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The filter expression of this comprehension; may be null.
|
||||
*/
|
||||
public Expression getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a generator expression?
|
||||
*/
|
||||
public boolean isGenerator() {
|
||||
return generator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A conditional expression such as <code>i >= 0 ? a[i] : null</code>.
|
||||
*/
|
||||
public class ConditionalExpression extends Expression {
|
||||
private final Expression test;
|
||||
private final Expression consequent, alternate;
|
||||
|
||||
public ConditionalExpression(SourceLocation loc, Expression test, Expression consequent, Expression alternate) {
|
||||
super("ConditionalExpression", loc);
|
||||
this.test = test;
|
||||
this.consequent = consequent;
|
||||
this.alternate = alternate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The test expression of this conditional expression.
|
||||
*/
|
||||
public Expression getTest() {
|
||||
return test;
|
||||
}
|
||||
|
||||
/**
|
||||
* The then-branch of this conditional expression.
|
||||
*/
|
||||
public Expression getConsequent() {
|
||||
return consequent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The else-branch of this conditional expression.
|
||||
*/
|
||||
public Expression getAlternate() {
|
||||
return alternate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A continue statement either with a label (<code>continue outer;</code>) or without (<code>continue;</code>).
|
||||
*/
|
||||
public class ContinueStatement extends JumpStatement {
|
||||
public ContinueStatement(SourceLocation loc, Identifier label) {
|
||||
super("ContinueStatement", loc, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A debugger statement <code>debugger;</code>.
|
||||
*/
|
||||
public class DebuggerStatement extends Statement {
|
||||
public DebuggerStatement(SourceLocation loc) {
|
||||
super("DebuggerStatement", loc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
128
javascript/extractor/src/com/semmle/js/ast/DeclarationFlags.java
Normal file
128
javascript/extractor/src/com/semmle/js/ast/DeclarationFlags.java
Normal file
@@ -0,0 +1,128 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Defines bitmasks where each bit corresponds to a flag on
|
||||
* {@linkplain MemberDefinition} or {@linkplain VariableDeclarator}.
|
||||
*/
|
||||
public class DeclarationFlags {
|
||||
public static final int computed = 1 << 0;
|
||||
public static final int abstract_ = 1 << 1;
|
||||
public static final int static_ = 1 << 2;
|
||||
public static final int readonly = 1 << 3;
|
||||
public static final int public_ = 1 << 4;
|
||||
public static final int private_ = 1 << 5;
|
||||
public static final int protected_ = 1 << 6;
|
||||
public static final int optional = 1 << 7;
|
||||
public static final int definiteAssignmentAssertion = 1 << 8;
|
||||
|
||||
public static final int none = 0;
|
||||
public static final int numberOfFlags = 9;
|
||||
|
||||
public static final List<String> names = Arrays.asList("computed", "abstract", "static", "readonly", "public", "private", "protected",
|
||||
"optional", "definiteAssignmentAssertion");
|
||||
|
||||
public static final List<String> relationNames = Arrays.asList("isComputed", "isAbstractMember", "isStatic", "hasReadonlyKeyword",
|
||||
"hasPublicKeyword", "hasPrivateKeyword", "hasProtectedKeyword", "isOptionalMember", "hasDefiniteAssignmentAssertion");
|
||||
|
||||
public static boolean isComputed(int flags) {
|
||||
return (flags & computed) != 0;
|
||||
}
|
||||
|
||||
public static boolean isAbstract(int flags) {
|
||||
return (flags & abstract_) != 0;
|
||||
}
|
||||
|
||||
public static boolean isStatic(int flags) {
|
||||
return (flags & static_) != 0;
|
||||
}
|
||||
|
||||
public static boolean isReadonly(int flags) {
|
||||
return (flags & readonly) != 0;
|
||||
}
|
||||
|
||||
public static boolean isPublic(int flags) {
|
||||
return (flags & public_) != 0;
|
||||
}
|
||||
|
||||
public static boolean isPrivate(int flags) {
|
||||
return (flags & private_) != 0;
|
||||
}
|
||||
|
||||
public static boolean isProtected(int flags) {
|
||||
return (flags & protected_) != 0;
|
||||
}
|
||||
|
||||
public static boolean isOptional(int flags) {
|
||||
return (flags & optional) != 0;
|
||||
}
|
||||
|
||||
public static boolean hasDefiniteAssignmentAssertion(int flags) {
|
||||
return (flags & definiteAssignmentAssertion) != 0;
|
||||
}
|
||||
|
||||
/** Returns a mask with the computed bit set to the value of <tt>enable</tt>. */
|
||||
public static int getComputed(boolean enable) {
|
||||
return enable ? computed : 0;
|
||||
}
|
||||
|
||||
/** Returns a mask with the abstract bit set to the value of <tt>enable</tt>. */
|
||||
public static int getAbstract(boolean enable) {
|
||||
return enable ? abstract_ : 0;
|
||||
}
|
||||
|
||||
/** Returns a mask with the static bit set to the value of <tt>enable</tt>. */
|
||||
public static int getStatic(boolean enable) {
|
||||
return enable ? static_ : 0;
|
||||
}
|
||||
|
||||
/** Returns a mask with the public bit set to the value of <tt>enable</tt>. */
|
||||
public static int getPublic(boolean enable) {
|
||||
return enable ? public_ : 0;
|
||||
}
|
||||
|
||||
/** Returns a mask with the readonly bit set to the value of <tt>enable</tt>. */
|
||||
public static int getReadonly(boolean enable) {
|
||||
return enable ? readonly : 0;
|
||||
}
|
||||
|
||||
/** Returns a mask with the private bit set to the value of <tt>enable</tt>. */
|
||||
public static int getPrivate(boolean enable) {
|
||||
return enable ? private_ : 0;
|
||||
}
|
||||
|
||||
/** Returns a mask with the protected bit set to the value of <tt>enable</tt>. */
|
||||
public static int getProtected(boolean enable) {
|
||||
return enable ? protected_ : 0;
|
||||
}
|
||||
|
||||
/** Returns a mask with the optional bit set to the value of <tt>enable</tt>. */
|
||||
public static int getOptional(boolean enable) {
|
||||
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) {
|
||||
return enable ? definiteAssignmentAssertion : 0;
|
||||
}
|
||||
|
||||
/** Returns true if the <tt>n</tt>th bit is set in <tt>flags</tt>. */
|
||||
public static boolean hasNthFlag(int flags, int n) {
|
||||
return (flags & (1 << n)) != 0;
|
||||
}
|
||||
|
||||
public static String getFlagNames(int flags) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (int i = 0; i < numberOfFlags; ++i) {
|
||||
if (hasNthFlag(flags, i)) {
|
||||
if (b.length() > 0) {
|
||||
b.append(", ");
|
||||
}
|
||||
b.append(names.get(i));
|
||||
}
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
19
javascript/extractor/src/com/semmle/js/ast/Decorator.java
Normal file
19
javascript/extractor/src/com/semmle/js/ast/Decorator.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
public class Decorator extends Expression {
|
||||
private final Expression expression;
|
||||
|
||||
public Decorator(SourceLocation loc, Expression expression) {
|
||||
super("Decorator", loc);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
737
javascript/extractor/src/com/semmle/js/ast/DefaultVisitor.java
Normal file
737
javascript/extractor/src/com/semmle/js/ast/DefaultVisitor.java
Normal file
@@ -0,0 +1,737 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import com.semmle.js.ast.jsx.IJSXAttribute;
|
||||
import com.semmle.js.ast.jsx.IJSXExpression;
|
||||
import com.semmle.js.ast.jsx.IJSXName;
|
||||
import com.semmle.js.ast.jsx.JSXAttribute;
|
||||
import com.semmle.js.ast.jsx.JSXBoundaryElement;
|
||||
import com.semmle.js.ast.jsx.JSXClosingElement;
|
||||
import com.semmle.js.ast.jsx.JSXElement;
|
||||
import com.semmle.js.ast.jsx.JSXEmptyExpression;
|
||||
import com.semmle.js.ast.jsx.JSXExpressionContainer;
|
||||
import com.semmle.js.ast.jsx.JSXIdentifier;
|
||||
import com.semmle.js.ast.jsx.JSXMemberExpression;
|
||||
import com.semmle.js.ast.jsx.JSXNamespacedName;
|
||||
import com.semmle.js.ast.jsx.JSXOpeningElement;
|
||||
import com.semmle.js.ast.jsx.JSXSpreadAttribute;
|
||||
import com.semmle.ts.ast.ArrayTypeExpr;
|
||||
import com.semmle.ts.ast.ConditionalTypeExpr;
|
||||
import com.semmle.ts.ast.DecoratorList;
|
||||
import com.semmle.ts.ast.EnumDeclaration;
|
||||
import com.semmle.ts.ast.EnumMember;
|
||||
import com.semmle.ts.ast.ExportAsNamespaceDeclaration;
|
||||
import com.semmle.ts.ast.ExportWholeDeclaration;
|
||||
import com.semmle.ts.ast.ExpressionWithTypeArguments;
|
||||
import com.semmle.ts.ast.ExternalModuleDeclaration;
|
||||
import com.semmle.ts.ast.ExternalModuleReference;
|
||||
import com.semmle.ts.ast.FunctionTypeExpr;
|
||||
import com.semmle.ts.ast.GenericTypeExpr;
|
||||
import com.semmle.ts.ast.GlobalAugmentationDeclaration;
|
||||
import com.semmle.ts.ast.ImportTypeExpr;
|
||||
import com.semmle.ts.ast.ImportWholeDeclaration;
|
||||
import com.semmle.ts.ast.IndexedAccessTypeExpr;
|
||||
import com.semmle.ts.ast.InferTypeExpr;
|
||||
import com.semmle.ts.ast.InterfaceDeclaration;
|
||||
import com.semmle.ts.ast.InterfaceTypeExpr;
|
||||
import com.semmle.ts.ast.IntersectionTypeExpr;
|
||||
import com.semmle.ts.ast.IsTypeExpr;
|
||||
import com.semmle.ts.ast.KeyofTypeExpr;
|
||||
import com.semmle.ts.ast.KeywordTypeExpr;
|
||||
import com.semmle.ts.ast.MappedTypeExpr;
|
||||
import com.semmle.ts.ast.NamespaceDeclaration;
|
||||
import com.semmle.ts.ast.NonNullAssertion;
|
||||
import com.semmle.ts.ast.OptionalTypeExpr;
|
||||
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
||||
import com.semmle.ts.ast.RestTypeExpr;
|
||||
import com.semmle.ts.ast.TupleTypeExpr;
|
||||
import com.semmle.ts.ast.TypeAliasDeclaration;
|
||||
import com.semmle.ts.ast.TypeAssertion;
|
||||
import com.semmle.ts.ast.TypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
import com.semmle.ts.ast.TypeofTypeExpr;
|
||||
import com.semmle.ts.ast.UnionTypeExpr;
|
||||
import com.semmle.util.exception.CatastrophicError;
|
||||
|
||||
/**
|
||||
* A convenience implementation of {@link Visitor} that provides default implementations
|
||||
* of all visitor methods, and catch-all methods for treating similar classes of AST nodes.
|
||||
*/
|
||||
public class DefaultVisitor<C, R> implements Visitor<C, R> {
|
||||
public R visit(Node nd, C c) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public R visit(Expression nd, C c) {
|
||||
return visit((Node)nd, c);
|
||||
}
|
||||
|
||||
public R visit(Statement nd, C c) {
|
||||
return visit((Node)nd, c);
|
||||
}
|
||||
|
||||
/** Default visitor for type expressions that are not also expressions. */
|
||||
public R visit(TypeExpression nd, C c) {
|
||||
return visit((Node) nd, c);
|
||||
}
|
||||
|
||||
public R visit(EnhancedForStatement nd, C c) {
|
||||
return visit((Loop)nd, c);
|
||||
}
|
||||
|
||||
public R visit(InvokeExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
public R visit(Loop nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
public R visit(IFunction nd, C c) {
|
||||
if (nd instanceof Statement)
|
||||
return visit((Statement)nd, c);
|
||||
else
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(AssignmentExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(AssignmentPattern nd, C q) {
|
||||
throw new CatastrophicError("Assignment patterns should not appear in the AST.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(BinaryExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(BlockStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(CallExpression nd, C c) {
|
||||
return visit((InvokeExpression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ComprehensionBlock nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ComprehensionExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExpressionStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(FunctionDeclaration nd, C c) {
|
||||
return visit((IFunction)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(Identifier nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(Literal nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(LogicalExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(MemberExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(Program nd, C c) {
|
||||
return visit((Node)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(RestElement nd, C q) {
|
||||
throw new CatastrophicError("Rest elements should not appear in the AST.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(UnaryExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(UpdateExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(VariableDeclaration nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(VariableDeclarator nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(SwitchStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(SwitchCase nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ForStatement nd, C c) {
|
||||
return visit((Loop)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ForInStatement nd, C c) {
|
||||
return visit((EnhancedForStatement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ForOfStatement nd, C c) {
|
||||
return visit((EnhancedForStatement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(Property nd, C c) {
|
||||
return visit((Node)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ArrayPattern nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(IfStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(LabeledStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ObjectPattern nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(WithStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(DoWhileStatement nd, C c) {
|
||||
return visit((Loop)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(WhileStatement nd, C c) {
|
||||
return visit((Loop)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(CatchClause nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TryStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(NewExpression nd, C c) {
|
||||
return visit((InvokeExpression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ReturnStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ThrowStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(SpreadElement nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(YieldExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ParenthesizedExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(EmptyStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
public R visit(JumpStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(BreakStatement nd, C c) {
|
||||
return visit((JumpStatement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ContinueStatement nd, C c) {
|
||||
return visit((JumpStatement)nd, c);
|
||||
}
|
||||
|
||||
public R visit(AFunctionExpression nd, C c) {
|
||||
return visit((IFunction)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(FunctionExpression nd, C c) {
|
||||
return visit((AFunctionExpression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ArrowFunctionExpression nd, C c) {
|
||||
return visit((AFunctionExpression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(DebuggerStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ArrayExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ObjectExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ThisExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ConditionalExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(SequenceExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TemplateElement nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TemplateLiteral nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TaggedTemplateExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(LetStatement nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(LetExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ClassDeclaration nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ClassExpression nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ClassBody nd, C c) {
|
||||
return visit((Node)nd, c);
|
||||
}
|
||||
|
||||
public R visit(MemberDefinition<?> nd, C c) {
|
||||
return visit((Node)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(MethodDefinition nd, C c) {
|
||||
return visit((MemberDefinition<FunctionExpression>) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(FieldDefinition nd, C c) {
|
||||
return visit((MemberDefinition<Expression>) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(Super nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(MetaProperty nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
public R visit(ExportDeclaration nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExportAllDeclaration nd, C c) {
|
||||
return visit((ExportDeclaration)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExportDefaultDeclaration nd, C c) {
|
||||
return visit((ExportDeclaration)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExportNamedDeclaration nd, C c) {
|
||||
return visit((ExportDeclaration)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExportSpecifier nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExportDefaultSpecifier nd, C c) {
|
||||
return visit((ExportSpecifier)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExportNamespaceSpecifier nd, C c) {
|
||||
return visit((ExportSpecifier)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ImportDeclaration nd, C c) {
|
||||
return visit((Statement)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ImportDefaultSpecifier nd, C c) {
|
||||
return visit((ImportSpecifier)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ImportNamespaceSpecifier nd, C c) {
|
||||
return visit((ImportSpecifier)nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ImportSpecifier nd, C c) {
|
||||
return visit((Expression)nd, c);
|
||||
}
|
||||
|
||||
public R visit(IJSXAttribute nd, C c) {
|
||||
return visit((Node) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXAttribute nd, C c) {
|
||||
return visit((IJSXAttribute) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXSpreadAttribute nd, C c) {
|
||||
return visit((IJSXAttribute) nd, c);
|
||||
}
|
||||
|
||||
public R visit(IJSXName nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXIdentifier nd, C c) {
|
||||
return visit((IJSXName) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXMemberExpression nd, C c) {
|
||||
return visit((IJSXName) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXNamespacedName nd, C c) {
|
||||
return visit((IJSXName) nd, c);
|
||||
}
|
||||
|
||||
public R visit(IJSXExpression nd, C c) {
|
||||
return visit((Node) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXEmptyExpression nd, C c) {
|
||||
return visit((IJSXExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXExpressionContainer nd, C c) {
|
||||
return visit((IJSXExpression) nd, c);
|
||||
}
|
||||
|
||||
public R visit(JSXBoundaryElement nd, C c) {
|
||||
return visit((Node) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXOpeningElement nd, C c) {
|
||||
return visit((JSXBoundaryElement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXClosingElement nd, C c) {
|
||||
return visit((JSXBoundaryElement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(JSXElement nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(AwaitExpression nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(Decorator nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(BindExpression nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(NamespaceDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ImportWholeDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExportWholeDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExternalModuleReference nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(DynamicImport nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(InterfaceDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(KeywordTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ArrayTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(UnionTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(IndexedAccessTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(IntersectionTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ParenthesizedTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TupleTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(KeyofTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(GenericTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TypeofTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(IsTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(InterfaceTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExpressionWithTypeArguments nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TypeParameter nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(FunctionTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TypeAssertion nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(MappedTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(TypeAliasDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(EnumDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(EnumMember nd, C c) {
|
||||
return visit((Node) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(DecoratorList nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExternalModuleDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ExportAsNamespaceDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(GlobalAugmentationDeclaration nd, C c) {
|
||||
return visit((Statement) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(NonNullAssertion nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ConditionalTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(InferTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(ImportTypeExpr nd, C c) {
|
||||
return visit((Expression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(OptionalTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R visit(RestTypeExpr nd, C c) {
|
||||
return visit((TypeExpression) nd, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An array or object pattern.
|
||||
*/
|
||||
public interface DestructuringPattern extends IPattern {
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A do-while statement of the form <code>do { ... } while(...);</code>.
|
||||
*/
|
||||
public class DoWhileStatement extends Loop {
|
||||
private final Expression test;
|
||||
|
||||
public DoWhileStatement(SourceLocation loc, Expression test, Statement body) {
|
||||
super("DoWhileStatement", loc, body);
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The test expression of this loop.
|
||||
*/
|
||||
public Expression getTest() {
|
||||
return test;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getContinueTarget() {
|
||||
return test;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
public class DynamicImport extends Expression {
|
||||
private final Expression source;
|
||||
|
||||
public DynamicImport(SourceLocation loc, Expression source) {
|
||||
super("DynamicImport", loc);
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public Expression getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An empty statement <code>;</code>.
|
||||
*/
|
||||
public class EmptyStatement extends Statement {
|
||||
public EmptyStatement(SourceLocation loc) {
|
||||
super("EmptyStatement", loc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An enhanced for statement, that is, either a {@link ForInStatement} or a {@link ForOfStatement}.
|
||||
*/
|
||||
public abstract class EnhancedForStatement extends Loop {
|
||||
private final Node left;
|
||||
private final Expression defaultValue;
|
||||
private final Expression right;
|
||||
|
||||
public EnhancedForStatement(String type, SourceLocation loc, Node left,
|
||||
Expression right, Statement body) {
|
||||
super(type, loc, body);
|
||||
if (left instanceof AssignmentPattern) {
|
||||
AssignmentPattern ap = (AssignmentPattern) left;
|
||||
this.left = ap.getLeft();
|
||||
this.defaultValue = ap.getRight();
|
||||
} else {
|
||||
this.left = left;
|
||||
this.defaultValue = null;
|
||||
}
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
/**
|
||||
* The iterator variable of this statement; may be either a {@link VariableDeclaration} statement,
|
||||
* or an lvalue {@link Expression}.
|
||||
*/
|
||||
public Node getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the iterator variable of this statement have a default value?
|
||||
*/
|
||||
public boolean hasDefaultValue() {
|
||||
return defaultValue != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value of the iterator variable of this statement.
|
||||
*/
|
||||
public Expression getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* The expression this loop iterates over.
|
||||
*/
|
||||
public Expression getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getContinueTarget() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A re-export declaration of the form
|
||||
*
|
||||
* <pre>
|
||||
* export * from 'foo';
|
||||
* </pre>
|
||||
*/
|
||||
public class ExportAllDeclaration extends ExportDeclaration {
|
||||
private final Literal source;
|
||||
|
||||
public ExportAllDeclaration(SourceLocation loc, Literal source) {
|
||||
super("ExportAllDeclaration", loc);
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public Literal getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
public abstract class ExportDeclaration extends Statement {
|
||||
|
||||
public ExportDeclaration(String type, SourceLocation loc) {
|
||||
super(type, loc);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A default export declaration of the form
|
||||
*
|
||||
* <pre>
|
||||
* export default function f() { return 23; };
|
||||
* </pre>
|
||||
*
|
||||
* or
|
||||
*
|
||||
* <pre>
|
||||
* export default 42;
|
||||
* </pre>
|
||||
*/
|
||||
public class ExportDefaultDeclaration extends ExportDeclaration {
|
||||
/**
|
||||
* Either an {@linkplain Expression} or a {@linkplain FunctionDeclaration} or
|
||||
* a {@linkplain ClassDeclaration}.
|
||||
*/
|
||||
private final Node declaration;
|
||||
|
||||
public ExportDefaultDeclaration(SourceLocation loc, Node declaration) {
|
||||
super("ExportDefaultDeclaration", loc);
|
||||
this.declaration = declaration;
|
||||
}
|
||||
|
||||
public Node getDeclaration() {
|
||||
return declaration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A default export specifier, such as <code>f</code> in
|
||||
* <code>export f from 'foo';</code>.
|
||||
*/
|
||||
public class ExportDefaultSpecifier extends ExportSpecifier {
|
||||
public ExportDefaultSpecifier(SourceLocation loc, Identifier exported) {
|
||||
super("ExportDefaultSpecifier", loc, null, exported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A named export declaration, which can be of one of the following forms:
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>export var x = 23;</code></li>
|
||||
* <li><code>export { x, y } from 'foo';</code></li>
|
||||
* <li><code>export { x, y };</code></li>
|
||||
* </ul>
|
||||
*/
|
||||
public class ExportNamedDeclaration extends ExportDeclaration {
|
||||
private final Statement declaration;
|
||||
private final List<ExportSpecifier> specifiers;
|
||||
private final Literal source;
|
||||
|
||||
public ExportNamedDeclaration(SourceLocation loc, Statement declaration, List<ExportSpecifier> specifiers, Literal source) {
|
||||
super("ExportNamedDeclaration", loc);
|
||||
this.declaration = declaration;
|
||||
this.specifiers = specifiers;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public Statement getDeclaration() {
|
||||
return declaration;
|
||||
}
|
||||
|
||||
public boolean hasDeclaration() {
|
||||
return declaration != null;
|
||||
}
|
||||
|
||||
public List<ExportSpecifier> getSpecifiers() {
|
||||
return specifiers;
|
||||
}
|
||||
|
||||
public Literal getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public boolean hasSource() {
|
||||
return source != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A namespace export specifier such as <code>* as foo</code> in
|
||||
* <code>export * as foo from 'foo';</code>.
|
||||
*/
|
||||
public class ExportNamespaceSpecifier extends ExportSpecifier {
|
||||
public ExportNamespaceSpecifier(SourceLocation loc, Identifier exported) {
|
||||
super("ExportNamespaceSpecifier", loc, null, exported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An export specifier in an {@linkplain ExportNamedDeclaration}; may either be a plain
|
||||
* identifier <code>x</code>, or a rename export <code>x as y</code>.
|
||||
*/
|
||||
public class ExportSpecifier extends Expression {
|
||||
private final Identifier local, exported;
|
||||
|
||||
public ExportSpecifier(SourceLocation loc, Identifier local, Identifier exported) {
|
||||
this("ExportSpecifier", loc, local, exported);
|
||||
}
|
||||
|
||||
public ExportSpecifier(String type, SourceLocation loc, Identifier local, Identifier exported) {
|
||||
super(type, loc);
|
||||
this.local = local;
|
||||
this.exported = exported == local ? new NodeCopier().copy(exported) : exported;
|
||||
}
|
||||
|
||||
public Identifier getLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public Identifier getExported() {
|
||||
return exported;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
31
javascript/extractor/src/com/semmle/js/ast/Expression.java
Normal file
31
javascript/extractor/src/com/semmle/js/ast/Expression.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import com.semmle.ts.ast.ITypedAstNode;
|
||||
|
||||
/**
|
||||
* Common superclass of all expressions.
|
||||
*/
|
||||
public abstract class Expression extends Node implements ITypedAstNode {
|
||||
private int staticTypeId = -1;
|
||||
|
||||
public Expression(String type, SourceLocation loc) {
|
||||
super(type, loc);
|
||||
}
|
||||
|
||||
/**
|
||||
* This expression, but with any surrounding parentheses stripped off.
|
||||
*/
|
||||
public Expression stripParens() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStaticTypeId() {
|
||||
return staticTypeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStaticTypeId(int staticTypeId) {
|
||||
this.staticTypeId = staticTypeId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An expression statement such as <code>alert("Hi!");</code>.
|
||||
*/
|
||||
public class ExpressionStatement extends Statement {
|
||||
private final Expression expression;
|
||||
|
||||
public ExpressionStatement(SourceLocation loc, Expression expression) {
|
||||
super("ExpressionStatement", loc);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The expression wrapped by this expression statement.
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
|
||||
public class FieldDefinition extends MemberDefinition<Expression> {
|
||||
private final ITypeExpression typeAnnotation;
|
||||
private final int fieldParameterIndex;
|
||||
|
||||
private static final int notFieldParameter = -1;
|
||||
|
||||
public FieldDefinition(SourceLocation loc, int flags, Expression key, Expression value) {
|
||||
this(loc, flags, key, value, null);
|
||||
}
|
||||
|
||||
public FieldDefinition(SourceLocation loc, 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,
|
||||
int fieldParameterIndex) {
|
||||
super("FieldDefinition", loc, flags, key, value);
|
||||
this.typeAnnotation = typeAnnotation;
|
||||
this.fieldParameterIndex = fieldParameterIndex;
|
||||
}
|
||||
|
||||
public ITypeExpression getTypeAnnotation() {
|
||||
return typeAnnotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConcrete() {
|
||||
return !isAbstract();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParameterField() {
|
||||
return fieldParameterIndex != notFieldParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a field parameter, returns the index of the parameter that
|
||||
* generated it, or -1 if this is not a field parameter.
|
||||
*/
|
||||
public int getFieldParameterIndex() {
|
||||
return fieldParameterIndex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A for-in statement such as
|
||||
*
|
||||
* <pre>
|
||||
* for (var p in src)
|
||||
* dest[p] = src[p];
|
||||
* </pre>
|
||||
*
|
||||
* This also includes legacy for-each statements.
|
||||
*/
|
||||
public class ForInStatement extends EnhancedForStatement {
|
||||
private final boolean each;
|
||||
|
||||
public ForInStatement(SourceLocation loc, Node left, Expression right, Statement body, Boolean each) {
|
||||
super("ForInStatement", loc, left, right, body);
|
||||
this.each = each == Boolean.TRUE;
|
||||
}
|
||||
|
||||
public boolean isEach() {
|
||||
return each;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A for-of statement such as
|
||||
*
|
||||
* <pre>
|
||||
* for (var elt of array)
|
||||
* sum += elt;
|
||||
* </pre>
|
||||
*/
|
||||
public class ForOfStatement extends EnhancedForStatement {
|
||||
private boolean isAwait;
|
||||
|
||||
public ForOfStatement(SourceLocation loc, Node left, Expression right, Statement body) {
|
||||
super("ForOfStatement", loc, left, right, body);
|
||||
}
|
||||
|
||||
public void setAwait(boolean isAwait) {
|
||||
this.isAwait = isAwait;
|
||||
}
|
||||
|
||||
public boolean isAwait() {
|
||||
return isAwait;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
79
javascript/extractor/src/com/semmle/js/ast/ForStatement.java
Normal file
79
javascript/extractor/src/com/semmle/js/ast/ForStatement.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A for statement such as
|
||||
*
|
||||
* <pre>
|
||||
* for (var i=10; i>0; i--)
|
||||
* console.log(i);
|
||||
* console.log("Boom!");
|
||||
* </pre>
|
||||
*/
|
||||
public class ForStatement extends Loop {
|
||||
private final Node init;
|
||||
private final Expression test, update;
|
||||
|
||||
public ForStatement(SourceLocation loc, Node init, Expression test, Expression update, Statement body) {
|
||||
super("ForStatement", loc, body);
|
||||
this.init = init;
|
||||
this.test = test;
|
||||
this.update = update;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this for statement have an initialization part?
|
||||
*/
|
||||
public boolean hasInit() {
|
||||
return init != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initialization part of this for statement; may be a {@link VariableDeclaration}
|
||||
* statement, an {@link Expression}, or {@literal null}.
|
||||
*/
|
||||
public Node getInit() {
|
||||
return init;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this for statement have a test?
|
||||
*/
|
||||
public boolean hasTest() {
|
||||
return test != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The test expression of this for statement; may be null.
|
||||
*/
|
||||
public Expression getTest() {
|
||||
return test;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this for statement have an update expression?
|
||||
*/
|
||||
public boolean hasUpdate() {
|
||||
return update != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The update expression of this for statement; may be null.
|
||||
*/
|
||||
public Expression getUpdate() {
|
||||
return update;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getContinueTarget() {
|
||||
if (update != null)
|
||||
return update;
|
||||
if (test != null)
|
||||
return test;
|
||||
return body;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.DecoratorList;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
/**
|
||||
* A function declaration such as
|
||||
*
|
||||
* <pre>
|
||||
* function add(x, y) {
|
||||
* return x+y;
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class FunctionDeclaration extends Statement implements IFunction {
|
||||
private final AFunction<BlockStatement> fn;
|
||||
private final boolean hasDeclareKeyword;
|
||||
private int symbol = -1;
|
||||
|
||||
public FunctionDeclaration(SourceLocation loc, Identifier id, List<Expression> params, BlockStatement body, boolean generator,
|
||||
boolean async) {
|
||||
this(loc, new AFunction<BlockStatement>(id, params, body, generator, async, Collections.emptyList(), Collections.emptyList(),
|
||||
Collections.emptyList(), null, null),
|
||||
false);
|
||||
}
|
||||
|
||||
public FunctionDeclaration(SourceLocation loc, Identifier id,
|
||||
List<Expression> params, BlockStatement body, boolean generator, boolean async, boolean hasDeclareKeyword,
|
||||
List<TypeParameter> typeParameters, List<ITypeExpression> parameterTypes, ITypeExpression returnType,
|
||||
ITypeExpression thisParameterType) {
|
||||
this(loc, new AFunction<BlockStatement>(id, params, body, generator, async, typeParameters, parameterTypes, Collections.emptyList(),
|
||||
returnType, thisParameterType), hasDeclareKeyword);
|
||||
}
|
||||
|
||||
private FunctionDeclaration(SourceLocation loc, AFunction<BlockStatement> fn, boolean hasDeclareKeyword) {
|
||||
super("FunctionDeclaration", loc);
|
||||
this.fn = fn;
|
||||
this.hasDeclareKeyword = hasDeclareKeyword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
public FunctionExpression asFunctionExpression() {
|
||||
return new FunctionExpression(getLoc(), fn);
|
||||
}
|
||||
|
||||
@Override public Identifier getId() { return fn.getId(); }
|
||||
@Override public List<IPattern> getParams() { return fn.getParams(); }
|
||||
@Override public boolean hasDefault(int i) { return fn.hasDefault(i); }
|
||||
@Override public Expression getDefault(int i) { return fn.getDefault(i); }
|
||||
@Override public IPattern getRest() { return fn.getRest(); }
|
||||
@Override public BlockStatement 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.DecoratorList;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
/**
|
||||
* A plain function expression.
|
||||
*/
|
||||
public class FunctionExpression extends AFunctionExpression {
|
||||
public FunctionExpression(SourceLocation loc, Identifier id,
|
||||
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,
|
||||
List<Expression> params, Node body, 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) {
|
||||
super("FunctionExpression", loc, fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
94
javascript/extractor/src/com/semmle/js/ast/IFunction.java
Normal file
94
javascript/extractor/src/com/semmle/js/ast/IFunction.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.DecoratorList;
|
||||
import com.semmle.ts.ast.INodeWithSymbol;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
|
||||
/**
|
||||
* A function declaration or expression.
|
||||
*/
|
||||
public interface IFunction extends IStatementContainer, INodeWithSymbol {
|
||||
/**
|
||||
* The function name; may be null for function expressions.
|
||||
*/
|
||||
public Identifier getId();
|
||||
|
||||
/**
|
||||
* The parameters of the function, not including the rest parameter.
|
||||
*/
|
||||
public List<IPattern> getParams();
|
||||
|
||||
/**
|
||||
* The parameters of the function, including the rest parameter.
|
||||
*/
|
||||
public List<IPattern> getAllParams();
|
||||
|
||||
/**
|
||||
* Does the i'th parameter have a default expression?
|
||||
*/
|
||||
public boolean hasDefault(int i);
|
||||
|
||||
/**
|
||||
* The default expression for the i'th parameter; may be null.
|
||||
*/
|
||||
public Expression getDefault(int i);
|
||||
|
||||
/**
|
||||
* The rest parameter of this function; may be null.
|
||||
*/
|
||||
public IPattern getRest();
|
||||
|
||||
/**
|
||||
* The body of the function; usually a {@link BlockStatement}, but may
|
||||
* be an {@link Expression} for function expressions.
|
||||
*/
|
||||
public Node getBody();
|
||||
|
||||
/**
|
||||
* Does this function have a rest parameter?
|
||||
*/
|
||||
public boolean hasRest();
|
||||
|
||||
/**
|
||||
* Is this function a generator function?
|
||||
*/
|
||||
public boolean isGenerator();
|
||||
|
||||
/**
|
||||
* The raw parameters of this function; parameters with defaults are
|
||||
* represented as {@link AssignmentPattern}s and the rest parameter
|
||||
* (if any) as a {@link RestElement}.
|
||||
*/
|
||||
public List<Expression> getRawParameters();
|
||||
|
||||
/**
|
||||
* Is this function an asynchronous function?
|
||||
*/
|
||||
public boolean isAsync();
|
||||
|
||||
/**
|
||||
* The return type of the function, if any.
|
||||
*/
|
||||
public ITypeExpression getReturnType();
|
||||
|
||||
/**
|
||||
* Does the i'th parameter have a type annotation?
|
||||
*/
|
||||
public boolean hasParameterType(int i);
|
||||
|
||||
/**
|
||||
* The type annotation for the i'th parameter; may be null.
|
||||
*/
|
||||
public ITypeExpression getParameterType(int i);
|
||||
|
||||
public List<TypeParameter> getTypeParameters();
|
||||
|
||||
public ITypeExpression getThisParameterType();
|
||||
|
||||
public List<DecoratorList> getParameterDecorators();
|
||||
|
||||
public boolean hasDeclareKeyword();
|
||||
}
|
||||
16
javascript/extractor/src/com/semmle/js/ast/INode.java
Normal file
16
javascript/extractor/src/com/semmle/js/ast/INode.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* The common interface implemented by all AST node types.
|
||||
*/
|
||||
public interface INode extends ISourceElement {
|
||||
/**
|
||||
* Accept a visitor object.
|
||||
*/
|
||||
public <C, R> R accept(Visitor<C, R> v, C c);
|
||||
|
||||
/**
|
||||
* Return the node's type tag.
|
||||
*/
|
||||
public String getType();
|
||||
}
|
||||
8
javascript/extractor/src/com/semmle/js/ast/IPattern.java
Normal file
8
javascript/extractor/src/com/semmle/js/ast/IPattern.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A marker interface encompassing variables ({@link Identifier}) and complex patterns
|
||||
* used in destructuring assignments ({@link ArrayPattern}, {@link ObjectPattern}).
|
||||
*/
|
||||
public interface IPattern extends INode {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A source code element potentially associated with a location.
|
||||
*/
|
||||
public interface ISourceElement {
|
||||
/**
|
||||
* Get the source location of this element; may be null.
|
||||
*/
|
||||
public SourceLocation getLoc();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A statement container, that is, either a {@link Program} or a {@link IFunction}.
|
||||
*/
|
||||
public interface IStatementContainer extends INode {
|
||||
}
|
||||
45
javascript/extractor/src/com/semmle/js/ast/Identifier.java
Normal file
45
javascript/extractor/src/com/semmle/js/ast/Identifier.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import com.semmle.ts.ast.INodeWithSymbol;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
|
||||
/**
|
||||
* An identifier.
|
||||
*
|
||||
* 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
|
||||
* (like <code>f</code> in <code>e.f</code>), statement labels (like <code>l</code> in
|
||||
* <code>l: while(true);</code>), or statement label references (like <code>l</code> in
|
||||
* <code>break l;</code>).
|
||||
*/
|
||||
public class Identifier extends Expression implements IPattern, ITypeExpression, INodeWithSymbol {
|
||||
private final String name;
|
||||
private int symbol = -1;
|
||||
|
||||
public Identifier(SourceLocation loc, String name) {
|
||||
super("Identifier", loc);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of this identifier.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbol(int symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
}
|
||||
49
javascript/extractor/src/com/semmle/js/ast/IfStatement.java
Normal file
49
javascript/extractor/src/com/semmle/js/ast/IfStatement.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An if statement.
|
||||
*/
|
||||
public class IfStatement extends Statement {
|
||||
private final Expression test;
|
||||
private final Statement consequent, alternate;
|
||||
|
||||
public IfStatement(SourceLocation loc, Expression test, Statement consequent, Statement alternate) {
|
||||
super("IfStatement", loc);
|
||||
this.test = test;
|
||||
this.consequent = consequent;
|
||||
this.alternate = alternate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The test expression of this if statement.
|
||||
*/
|
||||
public Expression getTest() {
|
||||
return test;
|
||||
}
|
||||
|
||||
/**
|
||||
* The then-branch of this if statement.
|
||||
*/
|
||||
public Statement getConsequent() {
|
||||
return consequent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The else-branch of this if statement; may be null.
|
||||
*/
|
||||
public Statement getAlternate() {
|
||||
return alternate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this if statement have an else branch?
|
||||
*/
|
||||
public boolean hasAlternate() {
|
||||
return alternate != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An import declaration, which can be of one of the following forms:
|
||||
*
|
||||
* <pre>
|
||||
* import v from "m";
|
||||
* import * as ns from "m";
|
||||
* import {x, y, w as z} from "m";
|
||||
* import v, * as ns from "m";
|
||||
* import v, {x, y, w as z} from "m";
|
||||
* import "m";
|
||||
* </pre>
|
||||
*/
|
||||
public class ImportDeclaration extends Statement {
|
||||
/** List of import specifiers detailing how declarations are imported; may be empty. */
|
||||
private final List<ImportSpecifier> specifiers;
|
||||
|
||||
/** The module from which declarations are imported. */
|
||||
private final Literal source;
|
||||
|
||||
public ImportDeclaration(SourceLocation loc, List<ImportSpecifier> specifiers, Literal source) {
|
||||
super("ImportDeclaration", loc);
|
||||
this.specifiers = specifiers;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public Literal getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public List<ImportSpecifier> getSpecifiers() {
|
||||
return specifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A default import specifier, such as <code>f</code> in
|
||||
* <code>import f, { x, y } from 'foo';</code>.
|
||||
*
|
||||
* Default import specifiers do not have an explicit imported name
|
||||
* (the imported name is, implicitly, <code>default</code>).
|
||||
*/
|
||||
public class ImportDefaultSpecifier extends ImportSpecifier {
|
||||
public ImportDefaultSpecifier(SourceLocation loc, Identifier local) {
|
||||
super("ImportDefaultSpecifier", loc, null, local);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A namespace import specifier such as <code>* as foo</code> in
|
||||
* <code>import * as foo from 'foo';</code>.
|
||||
*
|
||||
* Namespace import specifiers do not have an imported name.
|
||||
*/
|
||||
public class ImportNamespaceSpecifier extends ImportSpecifier {
|
||||
public ImportNamespaceSpecifier(SourceLocation loc, Identifier local) {
|
||||
super("ImportNamespaceSpecifier", loc, null, local);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* An import specifier such as <code>x</code> and <code>y as z</code> in
|
||||
* <code>import { x, y as z } from 'foo';</code>.
|
||||
*
|
||||
* An import specifier has a local name and an imported name; for instance,
|
||||
* <code>y as z</code> has local name <code>z</code> and imported name <code>y</code>,
|
||||
* while <code>x</code> has both local and imported name <code>x</code>.
|
||||
*/
|
||||
public class ImportSpecifier extends Expression {
|
||||
private final Identifier imported, local;
|
||||
|
||||
public ImportSpecifier(SourceLocation loc, Identifier imported, Identifier local) {
|
||||
this("ImportSpecifier", loc, imported, local);
|
||||
}
|
||||
|
||||
public ImportSpecifier(String type, SourceLocation loc, Identifier imported, Identifier local) {
|
||||
super(type, loc);
|
||||
this.imported = imported;
|
||||
this.local = local == imported ? new NodeCopier().copy(local) : local;
|
||||
}
|
||||
|
||||
public Identifier getImported() {
|
||||
return imported;
|
||||
}
|
||||
|
||||
public Identifier getLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.INodeWithSymbol;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
|
||||
/**
|
||||
* An invocation, that is, either a {@link CallExpression} or a {@link NewExpression}.
|
||||
*/
|
||||
public abstract class InvokeExpression extends Expression implements INodeWithSymbol {
|
||||
private final Expression callee;
|
||||
private final List<ITypeExpression> typeArguments;
|
||||
private final List<Expression> arguments;
|
||||
private int resolvedSignatureId = -1;
|
||||
private int overloadIndex = -1;
|
||||
private int symbol = -1;
|
||||
|
||||
public InvokeExpression(String type, SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments,
|
||||
List<Expression> arguments) {
|
||||
super(type, loc);
|
||||
this.callee = callee;
|
||||
this.typeArguments = typeArguments;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* The callee expression of this invocation.
|
||||
*/
|
||||
public Expression getCallee() {
|
||||
return callee;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type arguments of this invocation.
|
||||
*/
|
||||
public List<ITypeExpression> getTypeArguments() {
|
||||
return typeArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* The argument expressions of this invocation.
|
||||
*/
|
||||
public List<Expression> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public int getResolvedSignatureId() {
|
||||
return resolvedSignatureId;
|
||||
}
|
||||
|
||||
public void setResolvedSignatureId(int resolvedSignatureId) {
|
||||
this.resolvedSignatureId = resolvedSignatureId;
|
||||
}
|
||||
|
||||
public int getOverloadIndex() {
|
||||
return overloadIndex;
|
||||
}
|
||||
|
||||
public void setOverloadIndex(int overloadIndex) {
|
||||
this.overloadIndex = overloadIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbol(int symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A jump statement, that is, either a {@link BreakStatement} or a {@link ContinueStatement}.
|
||||
*/
|
||||
public abstract class JumpStatement extends Statement {
|
||||
private final Identifier label;
|
||||
|
||||
public JumpStatement(String type, SourceLocation loc, Identifier label) {
|
||||
super(type, loc);
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this jump have an explicit target label?
|
||||
*/
|
||||
public boolean hasLabel() {
|
||||
return label != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target label of this jump; may be null.
|
||||
*/
|
||||
public Identifier getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A labeled statement.
|
||||
*/
|
||||
public class LabeledStatement extends Statement {
|
||||
private final Identifier label;
|
||||
private final Statement body;
|
||||
|
||||
public LabeledStatement(SourceLocation loc, Identifier label, Statement body) {
|
||||
super("LabeledStatement", loc);
|
||||
this.label = label;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The label of the labeled statement.
|
||||
*/
|
||||
public Identifier getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* The statement wrapped by this labeled statement.
|
||||
*/
|
||||
public Statement getBody() {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An old-style let expression of the form <code>let (vardecls) expr</code>.
|
||||
*/
|
||||
public class LetExpression extends Expression {
|
||||
private final List<VariableDeclarator> head;
|
||||
private final Expression body;
|
||||
|
||||
public LetExpression(SourceLocation loc, List<VariableDeclarator> head, Expression body) {
|
||||
super("LetExpression", loc);
|
||||
this.head = head;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
public List<VariableDeclarator> getHead() {
|
||||
return head;
|
||||
}
|
||||
|
||||
public Expression getBody() {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
30
javascript/extractor/src/com/semmle/js/ast/LetStatement.java
Normal file
30
javascript/extractor/src/com/semmle/js/ast/LetStatement.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An old-style let statement of the form <code>let(vardecls) stmt</code>.
|
||||
*/
|
||||
public class LetStatement extends Statement {
|
||||
private final List<VariableDeclarator> head;
|
||||
private final Statement body;
|
||||
|
||||
public LetStatement(SourceLocation loc, List<VariableDeclarator> head, Statement body) {
|
||||
super("LetStatement", loc);
|
||||
this.head = head;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
public List<VariableDeclarator> getHead() {
|
||||
return head;
|
||||
}
|
||||
|
||||
public Statement getBody() {
|
||||
return body;
|
||||
}
|
||||
}
|
||||
96
javascript/extractor/src/com/semmle/js/ast/Literal.java
Normal file
96
javascript/extractor/src/com/semmle/js/ast/Literal.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import com.semmle.jcorn.TokenType;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
|
||||
/**
|
||||
* A literal constant.
|
||||
* <p>
|
||||
* A <tt>null</tt> literal may occur as a TypeScript type annotation - other
|
||||
* literals are always expressions.
|
||||
*/
|
||||
public class Literal extends Expression implements ITypeExpression {
|
||||
private final TokenType tokenType;
|
||||
private final Object value;
|
||||
private final String raw;
|
||||
|
||||
public Literal(SourceLocation loc, TokenType tokenType, Object value) {
|
||||
super("Literal", loc);
|
||||
|
||||
// for numbers, check whether they can be represented as integers
|
||||
if (value instanceof Double) {
|
||||
Double dvalue = (Double)value;
|
||||
if (dvalue >= Long.MIN_VALUE && dvalue <= Long.MAX_VALUE && (dvalue%1) == 0)
|
||||
value = dvalue.longValue();
|
||||
} else if (value instanceof CharSequence) {
|
||||
value = value.toString();
|
||||
}
|
||||
|
||||
this.tokenType = tokenType;
|
||||
this.value = value;
|
||||
this.raw = getLoc().getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the token corresponding to this literal.
|
||||
*/
|
||||
public TokenType getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The source text of this literal.
|
||||
*/
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a regular expression literal?
|
||||
*/
|
||||
public boolean isRegExp() {
|
||||
return tokenType == TokenType.regexp;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of this literal expressed as a string.
|
||||
*/
|
||||
public String getStringValue() {
|
||||
// regular expressions may have a null value; use the raw value instead
|
||||
if (isRegExp())
|
||||
return raw;
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the value of this literal falsy?
|
||||
*/
|
||||
public boolean isFalsy() {
|
||||
if (isRegExp())
|
||||
return false;
|
||||
return value == null ||
|
||||
value instanceof Number && ((Number)value).intValue() == 0 ||
|
||||
value == Boolean.FALSE ||
|
||||
value instanceof String && ((String)value).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the value of this literal truthy?
|
||||
*/
|
||||
public boolean isTruthy() {
|
||||
return !isFalsy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A short-circuiting binary expression, i.e., either <code>&&</code> or <code>||</code>.
|
||||
*/
|
||||
public class LogicalExpression extends ABinaryExpression {
|
||||
public LogicalExpression(SourceLocation loc, String operator, Expression left, Expression right) {
|
||||
super(loc, "LogicalExpression", operator, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
26
javascript/extractor/src/com/semmle/js/ast/Loop.java
Normal file
26
javascript/extractor/src/com/semmle/js/ast/Loop.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A loop statement, that is, a {@link WhileStatement}, a {@link DoWhileStatement}, a {@link ForStatement},
|
||||
* or a {@link EnhancedForStatement}.
|
||||
*/
|
||||
public abstract class Loop extends Statement {
|
||||
protected final Statement body;
|
||||
|
||||
public Loop(String type, SourceLocation loc, Statement body) {
|
||||
super(type, loc);
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
/**
|
||||
* The loop body.
|
||||
*/
|
||||
public final Statement getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* The child node of this loop where execution resumes after a <code>continue</code> statement.
|
||||
*/
|
||||
public abstract Node getContinueTarget();
|
||||
}
|
||||
131
javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java
Normal file
131
javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A member definition in a {@linkplain ClassBody}.
|
||||
*
|
||||
* A member definition has a name and an optional initial value, whose type is
|
||||
* given by the type parameter {@code V}.
|
||||
*/
|
||||
public abstract class MemberDefinition<V extends Expression> extends Node {
|
||||
/**
|
||||
* A bitmask of flags defined in {@linkplain DeclarationFlags}.
|
||||
*/
|
||||
private final int flags;
|
||||
|
||||
/**
|
||||
* The name of the member.
|
||||
*
|
||||
* If {@link #isComputed} is false, this must be an {@link Identifier}, otherwise
|
||||
* it can be an arbitrary expression.
|
||||
*/
|
||||
private final Expression key;
|
||||
|
||||
/** The initial value of the member. */
|
||||
private final V value;
|
||||
|
||||
/** The decorators applied to this member, if any. */
|
||||
private final List<Decorator> decorators;
|
||||
|
||||
public MemberDefinition(String type, SourceLocation loc, int flags, Expression key, V value) {
|
||||
super(type, loc);
|
||||
this.flags = flags;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.decorators = new ArrayList<Decorator>();
|
||||
}
|
||||
|
||||
/** Returns the flags, as defined by {@linkplain DeclarationFlags}. */
|
||||
public int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/** Returns true if this has the <tt>static</tt> modifier. */
|
||||
public boolean isStatic() {
|
||||
return DeclarationFlags.isStatic(flags);
|
||||
}
|
||||
|
||||
/** Returns true if the member name is computed. */
|
||||
public boolean isComputed() {
|
||||
return DeclarationFlags.isComputed(flags);
|
||||
}
|
||||
|
||||
/** Returns true if this is an abstract member. */
|
||||
public boolean isAbstract() {
|
||||
return DeclarationFlags.isAbstract(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if has the <tt>public</tt> modifier (not true for implicitly
|
||||
* public members).
|
||||
*/
|
||||
public boolean hasPublicKeyword() {
|
||||
return DeclarationFlags.isPublic(flags);
|
||||
}
|
||||
|
||||
/** Returns true if this is a private member. */
|
||||
public boolean hasPrivateKeyword() {
|
||||
return DeclarationFlags.isPrivate(flags);
|
||||
}
|
||||
|
||||
/** Returns true if this is a protected member. */
|
||||
public boolean hasProtectedKeyword() {
|
||||
return DeclarationFlags.isProtected(flags);
|
||||
}
|
||||
|
||||
/** Returns true if this is a readonly member. */
|
||||
public boolean hasReadonlyKeyword() {
|
||||
return DeclarationFlags.isReadonly(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression denoting the name of the member, or {@code null} if
|
||||
* this is a call/construct signature.
|
||||
*/
|
||||
public Expression getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** The name of the method, if it can be determined. */
|
||||
public String getName() {
|
||||
if (!isComputed() && key instanceof Identifier)
|
||||
return ((Identifier)key).getName();
|
||||
if (key instanceof Literal)
|
||||
return ((Literal)key).getStringValue();
|
||||
return null;
|
||||
}
|
||||
|
||||
/** True if this is a constructor; does not hold for construct signatures. */
|
||||
public boolean isConstructor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** True if this is a non-abstract field or a method with a body. */
|
||||
public abstract boolean isConcrete();
|
||||
|
||||
public boolean isCallSignature() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isIndexSignature() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addDecorators(List<Decorator> decorators) {
|
||||
this.decorators.addAll(decorators);
|
||||
}
|
||||
|
||||
public List<Decorator> getDecorators() {
|
||||
return this.decorators;
|
||||
}
|
||||
|
||||
public boolean isParameterField() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import com.semmle.ts.ast.INodeWithSymbol;
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
|
||||
/**
|
||||
* A member expression, either computed (<code>e[f]</code>) or static (<code>e.f</code>).
|
||||
*/
|
||||
public class MemberExpression extends Expression implements ITypeExpression, INodeWithSymbol {
|
||||
private final Expression object, property;
|
||||
private final boolean computed;
|
||||
private int symbol = -1;
|
||||
|
||||
public MemberExpression(SourceLocation loc, Expression object, Expression property, Boolean computed) {
|
||||
super("MemberExpression", loc);
|
||||
this.object = object;
|
||||
this.property = property;
|
||||
this.computed = computed == Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The base expression of this member expression.
|
||||
*/
|
||||
public Expression getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* The property expression of this member expression; for static member expressions this is always
|
||||
* an {@link Identifier}.
|
||||
*/
|
||||
public Expression getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a computed member expression?
|
||||
*/
|
||||
public boolean isComputed() {
|
||||
return computed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbol(int symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
}
|
||||
32
javascript/extractor/src/com/semmle/js/ast/MetaProperty.java
Normal file
32
javascript/extractor/src/com/semmle/js/ast/MetaProperty.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A meta property access (cf. ECMAScript 2015 Language Specification, Chapter 12.3.8).
|
||||
*
|
||||
* <p>
|
||||
* Currently the only recognised meta properties are <code>new.target</code> and
|
||||
* <code>function.sent</code>.
|
||||
* </p>
|
||||
*/
|
||||
public class MetaProperty extends Expression {
|
||||
private final Identifier meta, property;
|
||||
|
||||
public MetaProperty(SourceLocation loc, Identifier meta, Identifier property) {
|
||||
super("MetaProperty", loc);
|
||||
this.meta = meta;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public Identifier getMeta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
public Identifier getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MethodDefinition extends MemberDefinition<FunctionExpression> {
|
||||
public enum Kind {
|
||||
CONSTRUCTOR, METHOD, GET, SET, FUNCTION_CALL_SIGNATURE, CONSTRUCTOR_CALL_SIGNATURE, INDEX_SIGNATURE
|
||||
};
|
||||
|
||||
private final Kind kind;
|
||||
private final List<FieldDefinition> parameterFields;
|
||||
|
||||
public MethodDefinition(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,
|
||||
List<FieldDefinition> parameterFields) {
|
||||
super("MethodDefinition", loc, flags, key, value);
|
||||
this.kind = kind;
|
||||
this.parameterFields = parameterFields;
|
||||
}
|
||||
|
||||
|
||||
public Kind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCallSignature() {
|
||||
return kind == Kind.FUNCTION_CALL_SIGNATURE || kind == Kind.CONSTRUCTOR_CALL_SIGNATURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIndexSignature() {
|
||||
return kind == Kind.INDEX_SIGNATURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstructor() {
|
||||
return !isStatic() && !isComputed() && "constructor".equals(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConcrete() {
|
||||
return getValue().getBody() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C, R> R accept(Visitor<C, R> v, C c) {
|
||||
return v.visit(this, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter fields synthesized for initializing constructor
|
||||
* parameters, if this is a 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.
|
||||
*/
|
||||
public List<FieldDefinition> getParameterFields() {
|
||||
return parameterFields;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.ITypeExpression;
|
||||
|
||||
/**
|
||||
* A <code>new</code> expression.
|
||||
*/
|
||||
public class NewExpression extends InvokeExpression {
|
||||
public NewExpression(SourceLocation loc, Expression callee, List<ITypeExpression> typeArguments, List<Expression> arguments) {
|
||||
super("NewExpression", loc, callee, typeArguments, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
}
|
||||
17
javascript/extractor/src/com/semmle/js/ast/Node.java
Normal file
17
javascript/extractor/src/com/semmle/js/ast/Node.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* Common superclass of all AST node types.
|
||||
*/
|
||||
public abstract class Node extends SourceElement implements INode {
|
||||
private final String type;
|
||||
|
||||
public Node(String type, SourceLocation loc) {
|
||||
super(loc);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public final String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
707
javascript/extractor/src/com/semmle/js/ast/NodeCopier.java
Normal file
707
javascript/extractor/src/com/semmle/js/ast/NodeCopier.java
Normal file
@@ -0,0 +1,707 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.js.ast.jsx.JSXAttribute;
|
||||
import com.semmle.js.ast.jsx.JSXClosingElement;
|
||||
import com.semmle.js.ast.jsx.JSXElement;
|
||||
import com.semmle.js.ast.jsx.JSXEmptyExpression;
|
||||
import com.semmle.js.ast.jsx.JSXExpressionContainer;
|
||||
import com.semmle.js.ast.jsx.JSXIdentifier;
|
||||
import com.semmle.js.ast.jsx.JSXMemberExpression;
|
||||
import com.semmle.js.ast.jsx.JSXNamespacedName;
|
||||
import com.semmle.js.ast.jsx.JSXOpeningElement;
|
||||
import com.semmle.js.ast.jsx.JSXSpreadAttribute;
|
||||
import com.semmle.ts.ast.ArrayTypeExpr;
|
||||
import com.semmle.ts.ast.ConditionalTypeExpr;
|
||||
import com.semmle.ts.ast.DecoratorList;
|
||||
import com.semmle.ts.ast.EnumDeclaration;
|
||||
import com.semmle.ts.ast.EnumMember;
|
||||
import com.semmle.ts.ast.ExportAsNamespaceDeclaration;
|
||||
import com.semmle.ts.ast.ExportWholeDeclaration;
|
||||
import com.semmle.ts.ast.ExpressionWithTypeArguments;
|
||||
import com.semmle.ts.ast.ExternalModuleDeclaration;
|
||||
import com.semmle.ts.ast.ExternalModuleReference;
|
||||
import com.semmle.ts.ast.FunctionTypeExpr;
|
||||
import com.semmle.ts.ast.GenericTypeExpr;
|
||||
import com.semmle.ts.ast.GlobalAugmentationDeclaration;
|
||||
import com.semmle.ts.ast.ImportTypeExpr;
|
||||
import com.semmle.ts.ast.ImportWholeDeclaration;
|
||||
import com.semmle.ts.ast.IndexedAccessTypeExpr;
|
||||
import com.semmle.ts.ast.InferTypeExpr;
|
||||
import com.semmle.ts.ast.InterfaceDeclaration;
|
||||
import com.semmle.ts.ast.InterfaceTypeExpr;
|
||||
import com.semmle.ts.ast.IntersectionTypeExpr;
|
||||
import com.semmle.ts.ast.IsTypeExpr;
|
||||
import com.semmle.ts.ast.KeyofTypeExpr;
|
||||
import com.semmle.ts.ast.KeywordTypeExpr;
|
||||
import com.semmle.ts.ast.MappedTypeExpr;
|
||||
import com.semmle.ts.ast.NamespaceDeclaration;
|
||||
import com.semmle.ts.ast.NonNullAssertion;
|
||||
import com.semmle.ts.ast.OptionalTypeExpr;
|
||||
import com.semmle.ts.ast.ParenthesizedTypeExpr;
|
||||
import com.semmle.ts.ast.RestTypeExpr;
|
||||
import com.semmle.ts.ast.TupleTypeExpr;
|
||||
import com.semmle.ts.ast.TypeAliasDeclaration;
|
||||
import com.semmle.ts.ast.TypeAssertion;
|
||||
import com.semmle.ts.ast.TypeParameter;
|
||||
import com.semmle.ts.ast.TypeofTypeExpr;
|
||||
import com.semmle.ts.ast.UnionTypeExpr;
|
||||
|
||||
/**
|
||||
* Deep cloning of AST nodes.
|
||||
*/
|
||||
public class NodeCopier implements Visitor<Void, INode> {
|
||||
private Position visit(Position pos) {
|
||||
return new Position(pos.getLine(), pos.getColumn(), pos.getOffset());
|
||||
}
|
||||
|
||||
private SourceLocation visit(SourceLocation loc) {
|
||||
return new SourceLocation(loc.getSource(), visit(loc.getStart()), visit(loc.getEnd()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends INode> T copy(T t) {
|
||||
if (t == null)
|
||||
return null;
|
||||
return (T) t.accept(this, null);
|
||||
}
|
||||
|
||||
private <T extends INode> List<T> copy(List<T> ts) {
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (T t : ts)
|
||||
result.add(copy(t));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssignmentExpression visit(AssignmentExpression nd, Void q) {
|
||||
return new AssignmentExpression(visit(nd.getLoc()), nd.getOperator(), copy(nd.getLeft()), copy(nd.getRight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssignmentPattern visit(AssignmentPattern nd, Void q) {
|
||||
return new AssignmentPattern(visit(nd.getLoc()), nd.getOperator(), copy(nd.getLeft()), copy(nd.getRight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryExpression visit(BinaryExpression nd, Void q) {
|
||||
return new BinaryExpression(visit(nd.getLoc()), nd.getOperator(), copy(nd.getLeft()), copy(nd.getRight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockStatement visit(BlockStatement nd, Void q) {
|
||||
return new BlockStatement(visit(nd.getLoc()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallExpression visit(CallExpression nd, Void q) {
|
||||
return new CallExpression(visit(nd.getLoc()), copy(nd.getCallee()), copy(nd.getTypeArguments()), copy(nd.getArguments()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComprehensionBlock visit(ComprehensionBlock nd, Void q) {
|
||||
return new ComprehensionBlock(visit(nd.getLoc()), copy(nd.getLeft()), copy(nd.getRight()), nd.isOf());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComprehensionExpression visit(ComprehensionExpression nd, Void q) {
|
||||
return new ComprehensionExpression(visit(nd.getLoc()), copy(nd.getBody()), copy(nd.getBlocks()), copy(nd.getFilter()), nd.isGenerator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionStatement visit(ExpressionStatement nd, Void q) {
|
||||
return new ExpressionStatement(visit(nd.getLoc()), copy(nd.getExpression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionDeclaration visit(FunctionDeclaration nd, Void q) {
|
||||
return new FunctionDeclaration(visit(nd.getLoc()), copy(nd.getId()),
|
||||
copy(nd.getRawParameters()), copy(nd.getBody()), nd.isGenerator(), nd.isAsync(),
|
||||
nd.hasDeclareKeyword(), copy(nd.getTypeParameters()), copy(nd.getParameterTypes()), copy(nd.getReturnType()),
|
||||
copy(nd.getThisParameterType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier visit(Identifier nd, Void q) {
|
||||
return new Identifier(visit(nd.getLoc()), nd.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Literal visit(Literal nd, Void q) {
|
||||
return new Literal(visit(nd.getLoc()), nd.getTokenType(), nd.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogicalExpression visit(LogicalExpression nd, Void q) {
|
||||
return new LogicalExpression(visit(nd.getLoc()), nd.getOperator(), copy(nd.getLeft()), copy(nd.getRight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberExpression visit(MemberExpression nd, Void q) {
|
||||
return new MemberExpression(visit(nd.getLoc()), copy(nd.getObject()), copy(nd.getProperty()), nd.isComputed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program visit(Program nd, Void q) {
|
||||
return new Program(visit(nd.getLoc()), copy(nd.getBody()), nd.getSourceType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnaryExpression visit(UnaryExpression nd, Void q) {
|
||||
return new UnaryExpression(visit(nd.getLoc()), nd.getOperator(), copy(nd.getArgument()), nd.isPrefix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateExpression visit(UpdateExpression nd, Void q) {
|
||||
return new UpdateExpression(visit(nd.getLoc()), nd.getOperator(), copy(nd.getArgument()), nd.isPrefix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableDeclaration visit(VariableDeclaration nd, Void q) {
|
||||
return new VariableDeclaration(visit(nd.getLoc()), nd.getKind(), copy(nd.getDeclarations()),
|
||||
nd.hasDeclareKeyword());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableDeclarator visit(VariableDeclarator nd, Void q) {
|
||||
return new VariableDeclarator(visit(nd.getLoc()), copy(nd.getId()), copy(nd.getInit()), copy(nd.getTypeAnnotation()),
|
||||
nd.getFlags());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SwitchStatement visit(SwitchStatement nd, Void q) {
|
||||
return new SwitchStatement(visit(nd.getLoc()), copy(nd.getDiscriminant()), copy(nd.getCases()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SwitchCase visit(SwitchCase nd, Void q) {
|
||||
return new SwitchCase(visit(nd.getLoc()), copy(nd.getTest()), copy(nd.getConsequent()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForStatement visit(ForStatement nd, Void q) {
|
||||
return new ForStatement(visit(nd.getLoc()), copy(nd.getInit()), copy(nd.getTest()), copy(nd.getUpdate()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForInStatement visit(ForInStatement nd, Void q) {
|
||||
return new ForInStatement(visit(nd.getLoc()), copy(nd.getLeft()), copy(nd.getRight()), copy(nd.getBody()), nd.isEach());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForOfStatement visit(ForOfStatement nd, Void q) {
|
||||
return new ForOfStatement(visit(nd.getLoc()), copy(nd.getLeft()), copy(nd.getRight()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property visit(Property nd, Void q) {
|
||||
return new Property(visit(nd.getLoc()), copy(nd.getKey()), copy(nd.getRawValue()), nd.getKind().name(), nd.isComputed(), nd.isMethod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayPattern visit(ArrayPattern nd, Void q) {
|
||||
return new ArrayPattern(visit(nd.getLoc()), copy(nd.getElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPattern visit(ObjectPattern nd, Void q) {
|
||||
return new ObjectPattern(visit(nd.getLoc()), copy(nd.getRawProperties()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IfStatement visit(IfStatement nd, Void q) {
|
||||
return new IfStatement(visit(nd.getLoc()), copy(nd.getTest()), copy(nd.getConsequent()), copy(nd.getAlternate()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LabeledStatement visit(LabeledStatement nd, Void q) {
|
||||
return new LabeledStatement(visit(nd.getLoc()), copy(nd.getLabel()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WithStatement visit(WithStatement nd, Void q) {
|
||||
return new WithStatement(visit(nd.getLoc()), copy(nd.getObject()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoWhileStatement visit(DoWhileStatement nd, Void q) {
|
||||
return new DoWhileStatement(visit(nd.getLoc()), copy(nd.getTest()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WhileStatement visit(WhileStatement nd, Void q) {
|
||||
return new WhileStatement(visit(nd.getLoc()), copy(nd.getTest()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CatchClause visit(CatchClause nd, Void q) {
|
||||
return new CatchClause(visit(nd.getLoc()), copy(nd.getParam()), copy(nd.getGuard()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TryStatement visit(TryStatement nd, Void q) {
|
||||
return new TryStatement(visit(nd.getLoc()), copy(nd.getBlock()), copy(nd.getHandler()), copy(nd.getGuardedHandlers()), copy(nd.getFinalizer()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewExpression visit(NewExpression nd, Void q) {
|
||||
return new NewExpression(visit(nd.getLoc()), copy(nd.getCallee()), copy(nd.getTypeArguments()), copy(nd.getArguments()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnStatement visit(ReturnStatement nd, Void q) {
|
||||
return new ReturnStatement(visit(nd.getLoc()), copy(nd.getArgument()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThrowStatement visit(ThrowStatement nd, Void q) {
|
||||
return new ThrowStatement(visit(nd.getLoc()), copy(nd.getArgument()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpreadElement visit(SpreadElement nd, Void q) {
|
||||
return new SpreadElement(visit(nd.getLoc()), copy(nd.getArgument()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestElement visit(RestElement nd, Void q) {
|
||||
return new RestElement(visit(nd.getLoc()), copy(nd.getArgument()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public YieldExpression visit(YieldExpression nd, Void q) {
|
||||
return new YieldExpression(visit(nd.getLoc()), copy(nd.getArgument()), nd.isDelegating());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParenthesizedExpression visit(ParenthesizedExpression nd, Void q) {
|
||||
return new ParenthesizedExpression(visit(nd.getLoc()), copy(nd.getExpression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmptyStatement visit(EmptyStatement nd, Void q) {
|
||||
return new EmptyStatement(visit(nd.getLoc()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BreakStatement visit(BreakStatement nd, Void q) {
|
||||
return new BreakStatement(visit(nd.getLoc()), copy(nd.getLabel()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContinueStatement visit(ContinueStatement nd, Void q) {
|
||||
return new ContinueStatement(visit(nd.getLoc()), copy(nd.getLabel()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionExpression visit(FunctionExpression nd, Void q) {
|
||||
return new FunctionExpression(visit(nd.getLoc()), copy(nd.getId()),
|
||||
copy(nd.getRawParameters()), copy(nd.getBody()), nd.isGenerator(), nd.isAsync(),
|
||||
copy(nd.getTypeParameters()), copy(nd.getParameterTypes()), copy(nd.getParameterDecorators()), copy(nd.getReturnType()),
|
||||
copy(nd.getThisParameterType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebuggerStatement visit(DebuggerStatement nd, Void q) {
|
||||
return new DebuggerStatement(visit(nd.getLoc()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayExpression visit(ArrayExpression nd, Void q) {
|
||||
return new ArrayExpression(visit(nd.getLoc()), copy(nd.getElements()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectExpression visit(ObjectExpression nd, Void q) {
|
||||
return new ObjectExpression(visit(nd.getLoc()), copy(nd.getProperties()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThisExpression visit(ThisExpression nd, Void q) {
|
||||
return new ThisExpression(visit(nd.getLoc()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionalExpression visit(ConditionalExpression nd, Void q) {
|
||||
return new ConditionalExpression(visit(nd.getLoc()), copy(nd.getTest()), copy(nd.getConsequent()), copy(nd.getAlternate()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequenceExpression visit(SequenceExpression nd, Void q) {
|
||||
return new SequenceExpression(visit(nd.getLoc()), copy(nd.getExpressions()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateElement visit(TemplateElement nd, Void q) {
|
||||
return new TemplateElement(visit(nd.getLoc()), nd.getCooked(), nd.getRaw(), nd.isTail());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateLiteral visit(TemplateLiteral nd, Void q) {
|
||||
return new TemplateLiteral(visit(nd.getLoc()), copy(nd.getExpressions()), copy(nd.getQuasis()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaggedTemplateExpression visit(TaggedTemplateExpression nd, Void q) {
|
||||
return new TaggedTemplateExpression(visit(nd.getLoc()), copy(nd.getTag()), copy(nd.getQuasi()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrowFunctionExpression visit(ArrowFunctionExpression nd, Void q) {
|
||||
return new ArrowFunctionExpression(visit(nd.getLoc()), copy(nd.getRawParameters()), copy(nd.getBody()), nd.isGenerator(),
|
||||
nd.isAsync(), copy(nd.getTypeParameters()), copy(nd.getParameterTypes()), copy(nd.getReturnType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LetStatement visit(LetStatement nd, Void q) {
|
||||
return new LetStatement(visit(nd.getLoc()), copy(nd.getHead()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LetExpression visit(LetExpression nd, Void c) {
|
||||
return new LetExpression(visit(nd.getLoc()), copy(nd.getHead()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDeclaration visit(ClassDeclaration nd, Void c) {
|
||||
return new ClassDeclaration(visit(nd.getLoc()), visit(nd.getClassDef()), nd.hasDeclareKeyword(), nd.hasAbstractKeyword());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassExpression visit(ClassExpression nd, Void c) {
|
||||
return new ClassExpression(visit(nd.getLoc()), visit(nd.getClassDef()));
|
||||
}
|
||||
|
||||
private AClass visit(AClass nd) {
|
||||
return new AClass(copy(nd.getId()), copy(nd.getTypeParameters()), copy(nd.getSuperClass()), copy(nd.getSuperInterfaces()),
|
||||
copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassBody visit(ClassBody nd, Void c) {
|
||||
return new ClassBody(visit(nd.getLoc()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodDefinition visit(MethodDefinition nd, Void c) {
|
||||
return new MethodDefinition(visit(nd.getLoc()), nd.getFlags(), nd.getKind(),
|
||||
copy(nd.getKey()), copy(nd.getValue()), copy(nd.getParameterFields()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldDefinition visit(FieldDefinition nd, Void c) {
|
||||
return new FieldDefinition(visit(nd.getLoc()), nd.getFlags(), copy(nd.getKey()),
|
||||
copy(nd.getValue()), copy(nd.getTypeAnnotation()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Super visit(Super nd, Void c) {
|
||||
return new Super(visit(nd.getLoc()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaProperty visit(MetaProperty nd, Void c) {
|
||||
return new MetaProperty(visit(nd.getLoc()), copy(nd.getMeta()), copy(nd.getProperty()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExportAllDeclaration visit(ExportAllDeclaration nd, Void c) {
|
||||
return new ExportAllDeclaration(visit(nd.getLoc()), copy(nd.getSource()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExportDefaultDeclaration visit(ExportDefaultDeclaration nd, Void c) {
|
||||
return new ExportDefaultDeclaration(visit(nd.getLoc()), copy(nd.getDeclaration()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExportNamedDeclaration visit(ExportNamedDeclaration nd, Void c) {
|
||||
return new ExportNamedDeclaration(visit(nd.getLoc()), copy(nd.getDeclaration()), copy(nd.getSpecifiers()), copy(nd.getSource()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExportDefaultSpecifier visit(ExportDefaultSpecifier nd, Void c) {
|
||||
return new ExportDefaultSpecifier(visit(nd.getLoc()), copy(nd.getExported()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExportNamespaceSpecifier visit(ExportNamespaceSpecifier nd, Void c) {
|
||||
return new ExportNamespaceSpecifier(visit(nd.getLoc()), copy(nd.getExported()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExportSpecifier visit(ExportSpecifier nd, Void c) {
|
||||
return new ExportSpecifier(visit(nd.getLoc()), copy(nd.getLocal()), copy(nd.getExported()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportDeclaration visit(ImportDeclaration nd, Void c) {
|
||||
return new ImportDeclaration(visit(nd.getLoc()), copy(nd.getSpecifiers()), copy(nd.getSource()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportDefaultSpecifier visit(ImportDefaultSpecifier nd, Void c) {
|
||||
return new ImportDefaultSpecifier(visit(nd.getLoc()), copy(nd.getLocal()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportNamespaceSpecifier visit(ImportNamespaceSpecifier nd, Void c) {
|
||||
return new ImportNamespaceSpecifier(visit(nd.getLoc()), copy(nd.getLocal()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportSpecifier visit(ImportSpecifier nd, Void c) {
|
||||
return new ImportSpecifier(visit(nd.getLoc()), copy(nd.getImported()), copy(nd.getLocal()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXIdentifier nd, Void c) {
|
||||
return new JSXIdentifier(visit(nd.getLoc()), nd.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXMemberExpression nd, Void c) {
|
||||
return new JSXMemberExpression(visit(nd.getLoc()), copy(nd.getObject()), copy(nd.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXNamespacedName nd, Void c) {
|
||||
return new JSXNamespacedName(visit(nd.getLoc()), copy(nd.getNamespace()), copy(nd.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXEmptyExpression nd, Void c) {
|
||||
return new JSXEmptyExpression(visit(nd.getLoc()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXExpressionContainer nd, Void c) {
|
||||
return new JSXExpressionContainer(visit(nd.getLoc()), copy(nd.getExpression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXOpeningElement nd, Void c) {
|
||||
return new JSXOpeningElement(visit(nd.getLoc()), copy(nd.getName()), copy(nd.getAttributes()), nd.isSelfClosing());
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXClosingElement nd, Void c) {
|
||||
return new JSXClosingElement(visit(nd.getLoc()), copy(nd.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXAttribute nd, Void c) {
|
||||
return new JSXAttribute(visit(nd.getLoc()), copy(nd.getName()), copy(nd.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXSpreadAttribute nd, Void c) {
|
||||
return new JSXSpreadAttribute(visit(nd.getLoc()), copy(nd.getArgument()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(JSXElement nd, Void c) {
|
||||
return new JSXElement(visit(nd.getLoc()), copy(nd.getOpeningElement()), copy(nd.getChildren()), copy(nd.getClosingElement()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(AwaitExpression nd, Void c) {
|
||||
return new AwaitExpression(visit(nd.getLoc()), copy(nd.getArgument()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(Decorator nd, Void c) {
|
||||
return new Decorator(visit(nd.getLoc()), copy(nd.getExpression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(BindExpression nd, Void c) {
|
||||
return new BindExpression(visit(nd.getLoc()), copy(nd.getObject()), copy(nd.getCallee()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(NamespaceDeclaration nd, Void c) {
|
||||
return new NamespaceDeclaration(visit(nd.getLoc()), copy(nd.getName()), copy(nd.getBody()), nd.isInstantiated(),
|
||||
nd.hasDeclareKeyword());
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ImportWholeDeclaration nd, Void c) {
|
||||
return new ImportWholeDeclaration(visit(nd.getLoc()), copy(nd.getLhs()), copy(nd.getRhs()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ExportWholeDeclaration nd, Void c) {
|
||||
return new ExportWholeDeclaration(visit(nd.getLoc()), copy(nd.getRhs()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ExternalModuleReference nd, Void c) {
|
||||
return new ExternalModuleReference(visit(nd.getLoc()), copy(nd.getExpression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(DynamicImport nd, Void c) {
|
||||
return new DynamicImport(visit(nd.getLoc()), copy(nd.getSource()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(InterfaceDeclaration nd, Void c) {
|
||||
return new InterfaceDeclaration(visit(nd.getLoc()), copy(nd.getName()), copy(nd.getTypeParameters()), copy(nd.getSuperInterfaces()),
|
||||
copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(KeywordTypeExpr nd, Void c) {
|
||||
return new KeywordTypeExpr(visit(nd.getLoc()), nd.getKeyword());
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ArrayTypeExpr nd, Void c) {
|
||||
return new ArrayTypeExpr(visit(nd.getLoc()), copy(nd.getElementType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(UnionTypeExpr nd, Void c) {
|
||||
return new UnionTypeExpr(visit(nd.getLoc()), copy(nd.getElementTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(IndexedAccessTypeExpr nd, Void c) {
|
||||
return new IndexedAccessTypeExpr(visit(nd.getLoc()), copy(nd.getObjectType()), copy(nd.getIndexType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(IntersectionTypeExpr nd, Void c) {
|
||||
return new IntersectionTypeExpr(visit(nd.getLoc()), copy(nd.getElementTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ParenthesizedTypeExpr nd, Void c) {
|
||||
return new ParenthesizedTypeExpr(visit(nd.getLoc()), copy(nd.getElementType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(TupleTypeExpr nd, Void c) {
|
||||
return new TupleTypeExpr(visit(nd.getLoc()), copy(nd.getElementTypes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(KeyofTypeExpr nd, Void c) {
|
||||
return new KeyofTypeExpr(visit(nd.getLoc()), copy(nd.getElementType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(GenericTypeExpr nd, Void c) {
|
||||
return new GenericTypeExpr(visit(nd.getLoc()), copy(nd.getTypeName()), copy(nd.getTypeArguments()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(TypeofTypeExpr nd, Void c) {
|
||||
return new TypeofTypeExpr(visit(nd.getLoc()), copy(nd.getExpression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(IsTypeExpr nd, Void c) {
|
||||
return new IsTypeExpr(visit(nd.getLoc()), copy(nd.getLeft()), copy(nd.getRight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(InterfaceTypeExpr nd, Void c) {
|
||||
return new InterfaceTypeExpr(visit(nd.getLoc()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ExpressionWithTypeArguments nd, Void c) {
|
||||
return new ExpressionWithTypeArguments(visit(nd.getLoc()), copy(nd.getExpression()), copy(nd.getTypeArguments()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(TypeParameter nd, Void c) {
|
||||
return new TypeParameter(visit(nd.getLoc()), copy(nd.getId()), copy(nd.getBound()), copy(nd.getDefault()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(FunctionTypeExpr nd, Void c) {
|
||||
return new FunctionTypeExpr(visit(nd.getLoc()), copy(nd.getFunction()), nd.isConstructor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(TypeAssertion nd, Void c) {
|
||||
return new TypeAssertion(visit(nd.getLoc()), copy(nd.getExpression()), copy(nd.getTypeAnnotation()), nd.isAsExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(MappedTypeExpr nd, Void c) {
|
||||
return new MappedTypeExpr(visit(nd.getLoc()), copy(nd.getTypeParameter()), copy(nd.getElementType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(TypeAliasDeclaration nd, Void c) {
|
||||
return new TypeAliasDeclaration(visit(nd.getLoc()), copy(nd.getId()), copy(nd.getTypeParameters()), copy(nd.getDefinition()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(EnumDeclaration nd, Void c) {
|
||||
return new EnumDeclaration(visit(nd.getLoc()), nd.isConst(), nd.hasDeclareKeyword(), copy(nd.getDecorators()), copy(nd.getId()),
|
||||
copy(nd.getMembers()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(EnumMember nd, Void c) {
|
||||
return new EnumMember(visit(nd.getLoc()), copy(nd.getId()), copy(nd.getInitializer()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(DecoratorList nd, Void c) {
|
||||
return new DecoratorList(visit(nd.getLoc()), copy(nd.getDecorators()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ExternalModuleDeclaration nd, Void c) {
|
||||
return new ExternalModuleDeclaration(visit(nd.getLoc()), copy(nd.getName()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ExportAsNamespaceDeclaration nd, Void c) {
|
||||
return new ExportAsNamespaceDeclaration(visit(nd.getLoc()), copy(nd.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(GlobalAugmentationDeclaration nd, Void c) {
|
||||
return new GlobalAugmentationDeclaration(visit(nd.getLoc()), copy(nd.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(NonNullAssertion nd, Void c) {
|
||||
return new NonNullAssertion(visit(nd.getLoc()), copy(nd.getExpression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ConditionalTypeExpr nd, Void q) {
|
||||
return new ConditionalTypeExpr(visit(nd.getLoc()), copy(nd.getCheckType()),
|
||||
copy(nd.getExtendsType()), copy(nd.getTrueType()), copy(nd.getFalseType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(InferTypeExpr nd, Void c) {
|
||||
return new InferTypeExpr(visit(nd.getLoc()), copy(nd.getTypeParameter()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(ImportTypeExpr nd, Void c) {
|
||||
return new ImportTypeExpr(visit(nd.getLoc()), copy(nd.getPath()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(OptionalTypeExpr nd, Void c) {
|
||||
return new OptionalTypeExpr(visit(nd.getLoc()), copy(nd.getElementType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public INode visit(RestTypeExpr nd, Void c) {
|
||||
return new RestTypeExpr(visit(nd.getLoc()), copy(nd.getArrayType()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An object literal.
|
||||
*/
|
||||
public class ObjectExpression extends Expression {
|
||||
private final List<Property> properties;
|
||||
|
||||
public ObjectExpression(SourceLocation loc, List<Property> properties) {
|
||||
super("ObjectExpression", loc);
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The properties in this literal.
|
||||
*/
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An object pattern.
|
||||
*/
|
||||
public class ObjectPattern extends Expression implements DestructuringPattern {
|
||||
private final List<Property> rawProperties, properties;
|
||||
private final Expression restPattern;
|
||||
|
||||
public ObjectPattern(SourceLocation loc, List<Property> properties) {
|
||||
super("ObjectPattern", loc);
|
||||
this.rawProperties = properties;
|
||||
this.properties = new ArrayList<Property>(properties.size());
|
||||
Expression rest = null;
|
||||
for (Property prop : properties) {
|
||||
Expression val = prop.getValue();
|
||||
if (val instanceof RestElement) {
|
||||
rest = ((RestElement)val).getArgument();
|
||||
} else {
|
||||
this.properties.add(prop);
|
||||
}
|
||||
}
|
||||
this.restPattern = rest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The property patterns in this literal.
|
||||
*/
|
||||
public List<Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this object pattern have a rest pattern?
|
||||
*/
|
||||
public boolean hasRest() {
|
||||
return restPattern != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rest pattern of this literal, if any.
|
||||
*/
|
||||
public Expression getRest() {
|
||||
return restPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* The raw property patterns in this literal; the rest
|
||||
* pattern (if any) is represented as a {@link RestElement}.
|
||||
*/
|
||||
public List<Property> getRawProperties() {
|
||||
return rawProperties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A parenthesized expression.
|
||||
*/
|
||||
public class ParenthesizedExpression extends Expression {
|
||||
private final Expression expression;
|
||||
|
||||
public ParenthesizedExpression(SourceLocation loc, Expression expression) {
|
||||
super("ParenthesizedExpression", loc);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The expression between parentheses.
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression stripParens() {
|
||||
return expression.stripParens();
|
||||
}
|
||||
}
|
||||
81
javascript/extractor/src/com/semmle/js/ast/Position.java
Normal file
81
javascript/extractor/src/com/semmle/js/ast/Position.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A source position identifying a single character.
|
||||
*/
|
||||
public class Position implements Comparable<Position> {
|
||||
private final int line, column, offset;
|
||||
|
||||
public Position(int line, int column, int offset) {
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* The line number (1-based) of this position.
|
||||
*/
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* The column number (1-based) of this position.
|
||||
*/
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* The offset (0-based) of this position from the start
|
||||
* of the file, that is, the number of characters that
|
||||
* precede it.
|
||||
*/
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Position that) {
|
||||
if (this.line < that.line)
|
||||
return -1;
|
||||
if (this.line == that.line)
|
||||
if (this.column < that.column)
|
||||
return -1;
|
||||
else if (this.column == that.column)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + column;
|
||||
result = prime * result + line;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Position other = (Position) obj;
|
||||
if (column != other.column)
|
||||
return false;
|
||||
if (line != other.line)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return line + ":" + column;
|
||||
}
|
||||
}
|
||||
44
javascript/extractor/src/com/semmle/js/ast/Program.java
Normal file
44
javascript/extractor/src/com/semmle/js/ast/Program.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.ts.ast.INodeWithSymbol;
|
||||
|
||||
/**
|
||||
* A top-level program entity forming the root of an AST.
|
||||
*/
|
||||
public class Program extends Node implements IStatementContainer, INodeWithSymbol {
|
||||
private final List<Statement> body;
|
||||
private final String sourceType;
|
||||
private int symbolId = -1;
|
||||
|
||||
public Program(SourceLocation loc, List<Statement> body, String sourceType) {
|
||||
super("Program", loc);
|
||||
this.body = body;
|
||||
this.sourceType = sourceType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The statements in this program.
|
||||
*/
|
||||
public List<Statement> getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public String getSourceType() {
|
||||
return sourceType;
|
||||
}
|
||||
|
||||
public int getSymbol() {
|
||||
return this.symbolId;
|
||||
}
|
||||
|
||||
public void setSymbol(int symbolId) {
|
||||
this.symbolId = symbolId;
|
||||
}
|
||||
}
|
||||
137
javascript/extractor/src/com/semmle/js/ast/Property.java
Normal file
137
javascript/extractor/src/com/semmle/js/ast/Property.java
Normal file
@@ -0,0 +1,137 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.semmle.util.data.StringUtil;
|
||||
|
||||
/**
|
||||
* A property in an object literal or an object pattern.
|
||||
*
|
||||
* This includes both regular properties as well as accessor properties, method properties,
|
||||
* properties with computed names, and spread/rest properties.
|
||||
*/
|
||||
public class Property extends Node {
|
||||
public static enum Kind {
|
||||
/** Either a normal property or a spread/rest property. */
|
||||
INIT(false),
|
||||
|
||||
/** Getter property. */
|
||||
GET(true),
|
||||
|
||||
/** Setter property. */
|
||||
SET(true);
|
||||
|
||||
public final boolean isAccessor;
|
||||
|
||||
private Kind(boolean isAccessor) {
|
||||
this.isAccessor = isAccessor;
|
||||
}
|
||||
};
|
||||
|
||||
private final Expression key;
|
||||
private final Expression value, rawValue;
|
||||
private final Expression defaultValue; // only applies to property patterns
|
||||
private final Kind kind;
|
||||
private final boolean computed, method;
|
||||
private final List<Decorator> decorators;
|
||||
|
||||
public Property(SourceLocation loc, Expression key, Expression rawValue, String kind, Boolean computed, Boolean method) {
|
||||
super("Property", loc);
|
||||
this.key = key;
|
||||
if (rawValue instanceof AssignmentPattern) {
|
||||
AssignmentPattern ap = (AssignmentPattern) rawValue;
|
||||
if (ap.getLeft() == key)
|
||||
rawValue = ap = new AssignmentPattern(ap.getLoc(), ap.getOperator(), new NodeCopier().copy(key), ap.getRight());
|
||||
this.value = ap.getLeft();
|
||||
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
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The key of this property; usually a {@link Literal} or an {@link Identifier}, but may
|
||||
* be an arbitrary expression for properties with computed names. For spread/rest properties
|
||||
* this method returns {@code null}.
|
||||
*/
|
||||
public Expression getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value expression of this property.
|
||||
*/
|
||||
public Expression getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value of this property pattern.
|
||||
*/
|
||||
public Expression getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a property pattern with a default value?
|
||||
*/
|
||||
public boolean hasDefaultValue() {
|
||||
return defaultValue != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The kind of this property.
|
||||
*/
|
||||
public Kind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the name of this property computed?
|
||||
*/
|
||||
public boolean isComputed() {
|
||||
return computed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this property declared using method syntax?
|
||||
*/
|
||||
public boolean isMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this property declared using shorthand syntax?
|
||||
*/
|
||||
public boolean isShorthand() {
|
||||
return key != null && key.getLoc().equals(value.getLoc());
|
||||
}
|
||||
|
||||
/**
|
||||
* The raw value expression of this property; if this property is a property
|
||||
* pattern with a default value, this method returns an {@link AssignmentPattern}.
|
||||
*/
|
||||
public Expression getRawValue() {
|
||||
return rawValue;
|
||||
}
|
||||
|
||||
public void addDecorators(List<Decorator> decorators) {
|
||||
this.decorators.addAll(decorators);
|
||||
}
|
||||
|
||||
public List<Decorator> getDecorators() {
|
||||
return this.decorators;
|
||||
}
|
||||
}
|
||||
29
javascript/extractor/src/com/semmle/js/ast/RestElement.java
Normal file
29
javascript/extractor/src/com/semmle/js/ast/RestElement.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* pattern; they are rewritten away by the constructors of {@linkplain AFunction} and
|
||||
* {@link ArrayPattern}, and don't appear in the AST the extractor works on.
|
||||
*/
|
||||
public class RestElement extends Expression implements IPattern {
|
||||
private final Expression argument;
|
||||
|
||||
public RestElement(SourceLocation loc, Expression argument) {
|
||||
super("RestElement", loc);
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The argument expression of this spread element.
|
||||
*/
|
||||
public Expression getArgument() {
|
||||
return argument;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A return statement.
|
||||
*/
|
||||
public class ReturnStatement extends Statement {
|
||||
private final Expression argument;
|
||||
|
||||
public ReturnStatement(SourceLocation loc, Expression argument) {
|
||||
super("ReturnStatement", loc);
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this return statement have an argument expression?
|
||||
*/
|
||||
public boolean hasArgument() {
|
||||
return argument != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The argument expression of this return statement; may be null.
|
||||
*/
|
||||
public Expression getArgument() {
|
||||
return argument;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A comma expression containing two or more expressions evaluated in sequence.
|
||||
*/
|
||||
public class SequenceExpression extends Expression {
|
||||
private final List<Expression> expressions;
|
||||
|
||||
public SequenceExpression(SourceLocation loc, List<Expression> expressions) {
|
||||
super("SequenceExpression", loc);
|
||||
this.expressions = expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
|
||||
return v.visit(this, q);
|
||||
}
|
||||
|
||||
/**
|
||||
* The expressions in this sequence.
|
||||
*/
|
||||
public List<Expression> getExpressions() {
|
||||
return expressions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* Common superclass of all source elements.
|
||||
*/
|
||||
public class SourceElement implements ISourceElement {
|
||||
private final SourceLocation loc;
|
||||
|
||||
public SourceElement(SourceLocation loc) {
|
||||
this.loc = loc;
|
||||
}
|
||||
|
||||
public boolean hasLoc() {
|
||||
return loc != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SourceLocation getLoc() {
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.semmle.js.ast;
|
||||
|
||||
/**
|
||||
* A source location representing a range of characters.
|
||||
*/
|
||||
public class SourceLocation {
|
||||
private String source;
|
||||
private Position start, end;
|
||||
|
||||
public SourceLocation(String source, Position start, Position end) {
|
||||
this.source = source;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public SourceLocation(Position start) {
|
||||
this(null, start, null);
|
||||
}
|
||||
|
||||
public SourceLocation(String source, Position start) {
|
||||
this(source, start, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* The source code contained in this location.
|
||||
*/
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source code contain in this location.
|
||||
*/
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* The start position of the location.
|
||||
*/
|
||||
public Position getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start position of this location.
|
||||
*/
|
||||
public void setStart(Position start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
/**
|
||||
* The end position of the location.
|
||||
*/
|
||||
public Position getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the end position of this location.
|
||||
*/
|
||||
public void setEnd(Position end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((end == null) ? 0 : end.hashCode());
|
||||
result = prime * result + ((start == null) ? 0 : start.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
SourceLocation other = (SourceLocation) obj;
|
||||
if (end == null) {
|
||||
if (other.end != null)
|
||||
return false;
|
||||
} else if (!end.equals(other.end))
|
||||
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
Reference in New Issue
Block a user