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:
Aditya Sharad
2018-11-09 18:49:35 +00:00
1273 changed files with 138514 additions and 2413 deletions

View File

@@ -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;
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -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;
}
}

View 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;
}
}

View File

@@ -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;
}
}

View 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;
}
}

View File

@@ -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) =&gt; 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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;
}
}

View 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);
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View 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>&lt;!--</code>).
*/
HTML_START,
/**
* The end of an HTML comment (<code>--&gt;</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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,42 @@
package com.semmle.js.ast;
/**
* A conditional expression such as <code>i &gt;= 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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();
}
}

View 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;
}
}

View 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);
}
}

View File

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

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

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

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,79 @@
package com.semmle.js.ast;
/**
* A for statement such as
*
* <pre>
* for (var i=10; i&gt;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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View 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();
}

View 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();
}

View 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 {
}

View File

@@ -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();
}

View File

@@ -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 {
}

View 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;
}
}

View 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View 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;
}
}

View 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();
}
}

View File

@@ -0,0 +1,15 @@
package com.semmle.js.ast;
/**
* A short-circuiting binary expression, i.e., either <code>&amp;&amp;</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);
}
}

View 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();
}

View 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;
}
}

View File

@@ -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;
}
}

View 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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View 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;
}
}

View 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()));
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,25 @@
package com.semmle.js.ast;
/**
* A spread element <code>...xs</code> in rvalue position.
*/
public class SpreadElement extends Expression {
private final Expression argument;
public SpreadElement(SourceLocation loc, Expression argument) {
super("SpreadElement", 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;
}
}

View File

@@ -0,0 +1,10 @@
package com.semmle.js.ast;
/**
* Common superclass of all statements.
*/
public abstract class Statement extends Node {
public Statement(String type, SourceLocation loc) {
super(type, loc);
}
}

View File

@@ -0,0 +1,16 @@
package com.semmle.js.ast;
/**
* A <code>super</code> expression, appearing either as the callee of a super constructor
* call or as the receiver of a super method call.
*/
public class Super extends Expression {
public Super(SourceLocation loc) {
super("Super", loc);
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
}

View File

@@ -0,0 +1,50 @@
package com.semmle.js.ast;
import java.util.List;
/**
* A case in a switch statement; may be a default case.
*/
public class SwitchCase extends Statement {
private final Expression test;
private final List<Statement> consequent;
public SwitchCase(SourceLocation loc, Expression test, List<Statement> consequent) {
super("SwitchCase", loc);
this.test = test;
this.consequent = consequent;
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* Does this case have a test expression?
*/
public boolean hasTest() {
return test != null;
}
/**
* The test expression of this case; is null for default cases.
*/
public Expression getTest() {
return test;
}
/**
* The statements belonging to this case.
*/
public List<Statement> getConsequent() {
return consequent;
}
/**
* Is this a default case?
*/
public boolean isDefault() {
return !hasTest();
}
}

View File

@@ -0,0 +1,36 @@
package com.semmle.js.ast;
import java.util.List;
/**
* A switch statement.
*/
public class SwitchStatement extends Statement {
private final Expression discriminant;
private final List<SwitchCase> cases;
public SwitchStatement(SourceLocation loc, Expression discriminant, List<SwitchCase> cases) {
super("SwitchStatement", loc);
this.discriminant = discriminant;
this.cases = cases;
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* The expression whose value is examined.
*/
public Expression getDiscriminant() {
return discriminant;
}
/**
* The cases in this switch statement.
*/
public List<SwitchCase> getCases() {
return cases;
}
}

View File

@@ -0,0 +1,34 @@
package com.semmle.js.ast;
/**
* A tagged template expression.
*/
public class TaggedTemplateExpression extends Expression {
private final Expression tag;
private final TemplateLiteral quasi;
public TaggedTemplateExpression(SourceLocation loc, Expression tag, TemplateLiteral quasi) {
super("TaggedTemplateExpression", loc);
this.tag = tag;
this.quasi = quasi;
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* The tagging expression.
*/
public Expression getTag() {
return tag;
}
/**
* The tagged template literal.
*/
public TemplateLiteral getQuasi() {
return quasi;
}
}

View File

@@ -0,0 +1,43 @@
package com.semmle.js.ast;
/**
* An element in a template literal.
*/
public class TemplateElement extends Expression {
private final Object cooked;
private final String raw;
private final boolean tail;
public TemplateElement(SourceLocation loc, Object cooked, String raw, Boolean tail) {
super("TemplateElement", loc);
this.cooked = cooked;
this.raw = raw;
this.tail = tail == Boolean.TRUE;
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* The "cooked" value of the template element.
*/
public Object getCooked() {
return cooked;
}
/**
* The raw value of the template element.
*/
public String getRaw() {
return raw;
}
/**
* Is this the tail element?
*/
public boolean isTail() {
return tail;
}
}

View File

@@ -0,0 +1,82 @@
package com.semmle.js.ast;
import java.util.ArrayList;
import java.util.List;
/**
* A template literal such as <code>`Hello, ${name}!`</code>.
*
* <p>
* In SpiderMonkey parlance, a template literal is composed of <i>quasis</i> (the constant parts of
* the template literal) and <i>expressions</i> (the variable parts). In the example,
* <code>"Hello, "</code> and <code>"!"</code> are the quasis, and <code>name</code> is the single
* expression.
* </p>
*/
public class TemplateLiteral extends Expression {
private final List<Expression> expressions;
private final List<TemplateElement> quasis;
private final List<Expression> children;
public TemplateLiteral(SourceLocation loc, List<Expression> expressions, List<TemplateElement> quasis) {
super("TemplateLiteral", loc);
this.expressions = expressions;
this.quasis = quasis;
this.children = mergeChildren(expressions, quasis);
}
/*
* Merge quasis and expressions into a single array in textual order.
* Also filter out the empty constant strings that the parser likes to generate.
*/
private List<Expression> mergeChildren(List<Expression> expressions, List<TemplateElement> quasis) {
List<Expression> children = new ArrayList<Expression>();
int j = 0, n = quasis.size();
for (int i=0, m=expressions.size(); i<m; ++i) {
Expression expr = expressions.get(i);
for (; j<n; ++j) {
TemplateElement quasi = quasis.get(j);
if (quasi.getLoc().getStart().compareTo(expr.getLoc().getStart()) > 0)
break;
if (!quasi.getRaw().isEmpty())
children.add(quasi);
}
children.add(expr);
}
for (; j<n; ++j) {
TemplateElement quasi = quasis.get(j);
if (!quasi.getRaw().isEmpty())
children.add(quasi);
}
return children;
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* The expressions in this template.
*/
public List<Expression> getExpressions() {
return expressions;
}
/**
* The template elements in this template.
*/
public List<TemplateElement> getQuasis() {
return quasis;
}
/**
* All expressions and template elements in this template, in lexical order.
*/
public List<Expression> getChildren() {
return children;
}
}

View File

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

View File

@@ -0,0 +1,25 @@
package com.semmle.js.ast;
/**
* A <code>throw</code> statement.
*/
public class ThrowStatement extends Statement {
private final Expression argument;
public ThrowStatement(SourceLocation loc, Expression argument) {
super("ThrowStatement", loc);
this.argument = argument;
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* The thrown expression.
*/
public Expression getArgument() {
return argument;
}
}

View File

@@ -0,0 +1,75 @@
package com.semmle.js.ast;
import static com.semmle.js.ast.Token.Type.EOF;
import static com.semmle.js.ast.Token.Type.FALSE;
import static com.semmle.js.ast.Token.Type.KEYWORD;
import static com.semmle.js.ast.Token.Type.NAME;
import static com.semmle.js.ast.Token.Type.NULL;
import static com.semmle.js.ast.Token.Type.NUM;
import static com.semmle.js.ast.Token.Type.PUNCTUATOR;
import static com.semmle.js.ast.Token.Type.REGEXP;
import static com.semmle.js.ast.Token.Type.STRING;
import static com.semmle.js.ast.Token.Type.TRUE;
/**
* A source code token.
*
* This is not part of the SpiderMonkey AST format.
*/
public class Token extends SourceElement {
/**
* The supported token types.
*/
public static enum Type { EOF, NULL, TRUE, FALSE, NUM, STRING, REGEXP, NAME, KEYWORD, PUNCTUATOR };
private final Type type;
private final String value;
public Token(SourceLocation loc, String typename, Object keyword) {
this(loc, getType(typename, keyword));
}
public Token(SourceLocation loc, Type type) {
super(loc);
this.value = loc.getSource();
this.type = type;
}
private static Type getType(String typename, Object keyword) {
if ("eof".equals(typename)) {
return EOF;
} else if ("num".equals(typename)) {
return NUM;
} else if("name".equals(typename) || "jsxName".equals(typename)) {
return NAME;
} else if("string".equals(typename) || "template".equals(typename) || "jsxText".equals(typename)) {
return STRING;
} else if("regexp".equals(typename)) {
return REGEXP;
} else if ("true".equals(keyword)) {
return TRUE;
} else if ("false".equals(keyword)) {
return FALSE;
} else if ("null".equals(keyword)) {
return NULL;
} else if (keyword instanceof String) {
return KEYWORD;
} else {
return PUNCTUATOR;
}
}
/**
* The type of this token.
*/
public Type getType() {
return type;
}
/**
* The source text of this token.
*/
public String getValue() {
return value;
}
}

View File

@@ -0,0 +1,83 @@
package com.semmle.js.ast;
import java.util.ArrayList;
import java.util.List;
/**
* A try statement.
*/
public class TryStatement extends Statement {
private final BlockStatement block;
private final CatchClause handler;
private final List<CatchClause> guardedHandlers, allHandlers;
private final BlockStatement finalizer;
public TryStatement(SourceLocation loc, BlockStatement block,
CatchClause handler, List<CatchClause> guardedHandlers,
BlockStatement finalizer) {
super("TryStatement", loc);
this.block = block;
this.handler = handler;
this.guardedHandlers = guardedHandlers;
this.finalizer = finalizer;
this.allHandlers = new ArrayList<CatchClause>();
if (guardedHandlers != null)
this.allHandlers.addAll(guardedHandlers);
if (handler != null)
this.allHandlers.add(handler);
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* The body of this try statement.
*/
public BlockStatement getBlock() {
return block;
}
/**
* The (single unguarded) catch clause of this try statement; may be null.
*/
public CatchClause getHandler() {
return handler;
}
/**
* The guarded catch clauses of this try statement.
*/
public List<CatchClause> getGuardedHandlers() {
return guardedHandlers;
}
/**
* The finally block of this try statement; may be null.
*/
public BlockStatement getFinalizer() {
return finalizer;
}
/**
* All catch clauses (both guarded and unguarded) of this try statement in lexical order.
*/
public List<CatchClause> getAllHandlers() {
return allHandlers;
}
/**
* Does this try statement have a finally block?
*/
public boolean hasFinalizer() {
return finalizer != null;
}
/**
* Does this try statement have an unguarded catch block?
*/
public boolean hasHandler() {
return handler != null;
}
}

View File

@@ -0,0 +1,46 @@
package com.semmle.js.ast;
/**
* A unary expression such as <code>!x</code> or <code>void(0)</code>.
*
* Note that increment and decrement expressions are represented by {@link UpdateExpression}.
*/
public class UnaryExpression extends Expression {
private final String operator;
private final Expression argument;
private final boolean prefix;
public UnaryExpression(SourceLocation loc, String operator, Expression argument, Boolean prefix) {
super("UnaryExpression", loc);
this.operator = operator;
this.argument = argument;
this.prefix = prefix == Boolean.TRUE;
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* The operator of this unary expression.
*/
public String getOperator() {
return operator;
}
/**
* The argument of this unary expression.
*/
public Expression getArgument() {
return argument;
}
/**
* Is the operator of this unary expression a prefix operator?
*/
public boolean isPrefix() {
return prefix;
}
}

View File

@@ -0,0 +1,44 @@
package com.semmle.js.ast;
/**
* An increment or decrement expression.
*/
public class UpdateExpression extends Expression {
private final String operator;
private final Expression argument;
private final boolean prefix;
public UpdateExpression(SourceLocation loc, String operator, Expression argument, Boolean prefix) {
super("UpdateExpression", loc);
this.operator = operator;
this.argument = argument;
this.prefix = prefix == Boolean.TRUE;
}
@Override
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
return v.visit(this, q);
}
/**
* The operator of this expression.
*/
public String getOperator() {
return operator;
}
/**
* The argument of this expression.
*/
public Expression getArgument() {
return argument;
}
/**
* Is this a prefix increment or decrement expression?
*/
public boolean isPrefix() {
return prefix;
}
}

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