1313 lines
36 KiB
Java
1313 lines
36 KiB
Java
|
/******************************************************************************
|
||
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
||
|
* All rights reserved. This program and the accompanying materials
|
||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||
|
* which accompanies this distribution, and is available at
|
||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||
|
*
|
||
|
* Contributors:
|
||
|
* IBM Corporation - initial API and implementation
|
||
|
*****************************************************************************/
|
||
|
package com.ibm.wala.cast.js.translator;
|
||
|
|
||
|
import org.mozilla.javascript.CompilerEnvirons;
|
||
|
import org.mozilla.javascript.FunctionNode;
|
||
|
import org.mozilla.javascript.Node;
|
||
|
import org.mozilla.javascript.Parser;
|
||
|
import org.mozilla.javascript.ScriptOrFnNode;
|
||
|
import org.mozilla.javascript.Token;
|
||
|
import org.mozilla.javascript.tools.ToolErrorReporter;
|
||
|
|
||
|
import com.ibm.wala.util.debug.Assertions;
|
||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||
|
import com.ibm.wala.util.debug.Trace;
|
||
|
|
||
|
import com.ibm.wala.cast.tree.*;
|
||
|
import com.ibm.wala.cast.tree.impl.*;
|
||
|
import com.ibm.wala.classLoader.*;
|
||
|
|
||
|
import java.io.*;
|
||
|
import java.net.*;
|
||
|
import java.util.*;
|
||
|
|
||
|
public class RhinoToAstTranslator {
|
||
|
|
||
|
private final boolean DEBUG = true;
|
||
|
|
||
|
private interface WalkContext {
|
||
|
|
||
|
String script();
|
||
|
|
||
|
ScriptOrFnNode top();
|
||
|
|
||
|
void addScopedEntity(CAstNode construct, CAstEntity e);
|
||
|
|
||
|
Map getScopedEntities();
|
||
|
|
||
|
boolean expressionContext();
|
||
|
|
||
|
CAstControlFlowRecorder cfg();
|
||
|
|
||
|
CAstSourcePositionRecorder pos();
|
||
|
|
||
|
CAstNode getCatchTarget();
|
||
|
|
||
|
CAstNode setBase(Node node);
|
||
|
|
||
|
boolean foundBase(Node node);
|
||
|
|
||
|
void copyBase(Node from, Node to);
|
||
|
|
||
|
String getCatchVar();
|
||
|
|
||
|
void setCatchVar(String name);
|
||
|
|
||
|
String getForInVar(String loopVarName, Node initExpr);
|
||
|
|
||
|
String getForInInitVar();
|
||
|
|
||
|
String getForInLoopVar();
|
||
|
|
||
|
void addInitializer(CAstNode n);
|
||
|
}
|
||
|
|
||
|
private static class RootContext implements WalkContext {
|
||
|
|
||
|
public String script() { return null; }
|
||
|
|
||
|
public ScriptOrFnNode top() { return null; }
|
||
|
|
||
|
public void addScopedEntity(CAstNode construct, CAstEntity e) { }
|
||
|
|
||
|
public Map getScopedEntities() { return null; }
|
||
|
|
||
|
public boolean expressionContext() { return false; }
|
||
|
|
||
|
public CAstControlFlowRecorder cfg() { return null; }
|
||
|
|
||
|
public CAstSourcePositionRecorder pos() { return null; }
|
||
|
|
||
|
public CAstNode getCatchTarget() { return null; }
|
||
|
|
||
|
public CAstNode setBase(Node node) { return null; }
|
||
|
|
||
|
public boolean foundBase(Node node) { return false; }
|
||
|
|
||
|
public void copyBase(Node from, Node to) { }
|
||
|
|
||
|
public String getCatchVar() { return null; }
|
||
|
|
||
|
public void setCatchVar(String name) { }
|
||
|
|
||
|
public String getForInVar(String loopVarName, Node initExpr) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public String getForInInitVar() { return null; }
|
||
|
|
||
|
public String getForInLoopVar() { return null; }
|
||
|
|
||
|
public void addInitializer(CAstNode n) { }
|
||
|
}
|
||
|
|
||
|
private static abstract class DelegatingContext implements WalkContext {
|
||
|
private final WalkContext parent;
|
||
|
|
||
|
DelegatingContext(WalkContext parent) {
|
||
|
this.parent = parent;
|
||
|
}
|
||
|
|
||
|
public String script() { return parent.script(); }
|
||
|
|
||
|
public ScriptOrFnNode top() { return parent.top(); }
|
||
|
|
||
|
public void addScopedEntity(CAstNode construct, CAstEntity e) {
|
||
|
parent.addScopedEntity(construct, e);
|
||
|
}
|
||
|
|
||
|
public Map getScopedEntities() { return parent.getScopedEntities(); }
|
||
|
|
||
|
public boolean expressionContext() { return parent.expressionContext(); }
|
||
|
|
||
|
public CAstControlFlowRecorder cfg() { return parent.cfg(); }
|
||
|
|
||
|
public CAstSourcePositionRecorder pos() { return parent.pos(); }
|
||
|
|
||
|
public CAstNode getCatchTarget() { return parent.getCatchTarget(); }
|
||
|
|
||
|
public CAstNode setBase(Node node) { return parent.setBase(node); }
|
||
|
|
||
|
public boolean foundBase(Node node) { return parent.foundBase(node); }
|
||
|
|
||
|
public void copyBase(Node from, Node to) { parent.copyBase(from, to); }
|
||
|
|
||
|
public String getCatchVar() { return parent.getCatchVar(); }
|
||
|
|
||
|
public void setCatchVar(String name) { parent.setCatchVar(name); }
|
||
|
|
||
|
public String getForInVar(String loopVarName, Node initExpr) {
|
||
|
return parent.getForInVar(loopVarName, initExpr);
|
||
|
}
|
||
|
|
||
|
public String getForInInitVar() { return parent.getForInInitVar(); }
|
||
|
|
||
|
public String getForInLoopVar() { return parent.getForInLoopVar(); }
|
||
|
|
||
|
public void addInitializer(CAstNode n) { parent.addInitializer(n); }
|
||
|
}
|
||
|
|
||
|
private static class FunctionContext extends DelegatingContext {
|
||
|
private final ScriptOrFnNode topNode;
|
||
|
private final Map scopedEntities = new HashMap();
|
||
|
private final List initializers = new ArrayList();
|
||
|
private final CAstControlFlowRecorder cfg = new CAstControlFlowRecorder();
|
||
|
private final CAstSourcePositionRecorder pos =
|
||
|
new CAstSourcePositionRecorder();
|
||
|
|
||
|
FunctionContext(WalkContext parent, ScriptOrFnNode s) {
|
||
|
super(parent);
|
||
|
this.topNode = s;
|
||
|
}
|
||
|
|
||
|
public ScriptOrFnNode top() { return topNode; }
|
||
|
|
||
|
public void addScopedEntity(CAstNode construct, CAstEntity e) {
|
||
|
if (! scopedEntities.containsKey(construct))
|
||
|
scopedEntities.put(construct, new HashSet());
|
||
|
|
||
|
((Set)scopedEntities.get(construct)).add(e);
|
||
|
}
|
||
|
|
||
|
public Map getScopedEntities() { return scopedEntities; }
|
||
|
|
||
|
public boolean expressionContext() { return false; }
|
||
|
|
||
|
public CAstControlFlowRecorder cfg() { return cfg; }
|
||
|
|
||
|
public CAstSourcePositionRecorder pos() { return pos; }
|
||
|
|
||
|
public String getForInVar(String loopVarName, Node initExpr) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public String getForInInitVar() { return null; }
|
||
|
|
||
|
public String getForInLoopVar() { return null; }
|
||
|
|
||
|
public void addInitializer(CAstNode n) {
|
||
|
initializers.add(n);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
private static class ScriptContext extends FunctionContext {
|
||
|
private final String script;
|
||
|
|
||
|
ScriptContext(WalkContext parent, ScriptOrFnNode s, String script) {
|
||
|
super(parent, s);
|
||
|
this.script = script;
|
||
|
}
|
||
|
|
||
|
public String script() { return script; }
|
||
|
}
|
||
|
|
||
|
private static class ExpressionContext extends DelegatingContext {
|
||
|
|
||
|
ExpressionContext(WalkContext parent) {
|
||
|
super(parent);
|
||
|
}
|
||
|
|
||
|
public boolean expressionContext() { return true; }
|
||
|
|
||
|
}
|
||
|
|
||
|
private static class CatchBlockContext extends DelegatingContext {
|
||
|
private String catchVarName;
|
||
|
|
||
|
CatchBlockContext(WalkContext parent) {
|
||
|
super(parent);
|
||
|
}
|
||
|
|
||
|
public String getCatchVar() { return catchVarName; }
|
||
|
|
||
|
public void setCatchVar(String name) { catchVarName = name; }
|
||
|
}
|
||
|
|
||
|
private static class TryBlockContext extends DelegatingContext {
|
||
|
private final CAstNode catchNode;
|
||
|
|
||
|
TryBlockContext(WalkContext parent, CAstNode catchNode) {
|
||
|
super(parent);
|
||
|
this.catchNode = catchNode;
|
||
|
}
|
||
|
|
||
|
public CAstNode getCatchTarget() { return catchNode; }
|
||
|
|
||
|
}
|
||
|
|
||
|
private static class BaseCollectingContext extends DelegatingContext {
|
||
|
private final Set baseFor = new HashSet();
|
||
|
private final CAstNode baseVar;
|
||
|
private boolean foundBase = false;
|
||
|
|
||
|
BaseCollectingContext(WalkContext parent, Node initialBaseFor, CAstNode baseVar) {
|
||
|
super(parent);
|
||
|
baseFor.add( initialBaseFor );
|
||
|
this.baseVar = baseVar;
|
||
|
}
|
||
|
|
||
|
public CAstNode setBase(Node node) {
|
||
|
if (baseFor.contains( node )) {
|
||
|
foundBase = true;
|
||
|
return baseVar;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public boolean foundBase(Node node) {
|
||
|
return foundBase;
|
||
|
}
|
||
|
|
||
|
public void copyBase(Node from, Node to) {
|
||
|
if (baseFor.contains(from)) baseFor.add(to);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class LoopContext extends DelegatingContext {
|
||
|
private static int counter = 0;
|
||
|
|
||
|
private String loopVarName;
|
||
|
private String forInVar = null;
|
||
|
private Node forInInitExpr = null;
|
||
|
|
||
|
private LoopContext(WalkContext parent) {
|
||
|
super(parent);
|
||
|
}
|
||
|
|
||
|
public String getForInVar(String loopVarName, Node initExpr) {
|
||
|
this.loopVarName = loopVarName;
|
||
|
this.forInVar = "_forin_tmp" + counter++;
|
||
|
this.forInInitExpr = initExpr;
|
||
|
return forInVar;
|
||
|
}
|
||
|
|
||
|
public String getForInInitVar() {
|
||
|
Assertions._assert(forInVar != null);
|
||
|
return forInVar;
|
||
|
}
|
||
|
|
||
|
public String getForInLoopVar() {
|
||
|
Assertions._assert(loopVarName != null);
|
||
|
return loopVarName;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
private CAstNode translateOpcode(int nodeType) {
|
||
|
switch (nodeType) {
|
||
|
case Token.ADD: return CAstOperator.OP_ADD;
|
||
|
case Token.DIV: return CAstOperator.OP_DIV;
|
||
|
case Token.LSH: return CAstOperator.OP_LSH;
|
||
|
case Token.MOD: return CAstOperator.OP_MOD;
|
||
|
case Token.MUL: return CAstOperator.OP_MUL;
|
||
|
case Token.RSH: return CAstOperator.OP_RSH;
|
||
|
case Token.SUB: return CAstOperator.OP_SUB;
|
||
|
case Token.URSH: return CAstOperator.OP_URSH;
|
||
|
case Token.BITAND: return CAstOperator.OP_BIT_AND;
|
||
|
|
||
|
case Token.EQ: return CAstOperator.OP_EQ;
|
||
|
case Token.SHEQ: return CAstOperator.OP_EQ; // FIXME
|
||
|
case Token.IFEQ: return CAstOperator.OP_EQ;
|
||
|
case Token.GE: return CAstOperator.OP_GE;
|
||
|
case Token.GT: return CAstOperator.OP_GT;
|
||
|
case Token.LE: return CAstOperator.OP_LE;
|
||
|
case Token.LT: return CAstOperator.OP_LT;
|
||
|
case Token.NE: return CAstOperator.OP_NE;
|
||
|
case Token.SHNE: return CAstOperator.OP_NE; // FIXME
|
||
|
case Token.IFNE: return CAstOperator.OP_NE;
|
||
|
|
||
|
case Token.BITNOT: return CAstOperator.OP_BITNOT;
|
||
|
case Token.NOT: return CAstOperator.OP_NOT;
|
||
|
|
||
|
default:
|
||
|
Assertions.UNREACHABLE();
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private CAstNode makeBuiltinNew(WalkContext context, String typeName) {
|
||
|
return Ast.makeNode(CAstNode.NEW, Ast.makeConstant( typeName ));
|
||
|
}
|
||
|
|
||
|
private CAstNode handleNew(WalkContext context, String globalName, Node arguments) {
|
||
|
return handleNew(context, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(globalName)), arguments);
|
||
|
}
|
||
|
|
||
|
private CAstNode handleNew(WalkContext context, CAstNode value, Node arguments) {
|
||
|
return makeCtorCall(value, arguments, context);
|
||
|
}
|
||
|
|
||
|
private boolean isPrologueScript(WalkContext context) {
|
||
|
return TranslatorBase.bootstrapFileNames.contains( context.script() );
|
||
|
}
|
||
|
|
||
|
private boolean isPrimitiveCall(WalkContext context, Node n) {
|
||
|
return
|
||
|
isPrologueScript( context )
|
||
|
&&
|
||
|
n.getType() == Token.CALL
|
||
|
&&
|
||
|
n.getFirstChild().getType() == Token.NAME
|
||
|
&&
|
||
|
n.getFirstChild().getString().equals("primitive");
|
||
|
}
|
||
|
|
||
|
private boolean isPrimitiveCreation(WalkContext context, Node n) {
|
||
|
return
|
||
|
isPrologueScript( context )
|
||
|
&&
|
||
|
n.getType() == Token.NEW
|
||
|
&&
|
||
|
n.getFirstChild().getType() == Token.NAME
|
||
|
&&
|
||
|
n.getFirstChild().getString().equals("Primitives");
|
||
|
}
|
||
|
|
||
|
private CAstNode makeCall(CAstNode fun, CAstNode thisptr, Node firstChild, WalkContext context) {
|
||
|
return makeCall(fun, thisptr, firstChild, context, "do");
|
||
|
}
|
||
|
|
||
|
private CAstNode makeCtorCall(CAstNode thisptr, Node firstChild, WalkContext context) {
|
||
|
return makeCall(thisptr, null, firstChild, context, "ctor");
|
||
|
}
|
||
|
|
||
|
private CAstNode makeCall(CAstNode fun, CAstNode thisptr, Node firstChild, WalkContext context, String callee) {
|
||
|
int children = 0;
|
||
|
for (Node c = firstChild; c != null; c = c.getNext(), children++ );
|
||
|
|
||
|
int nargs = (thisptr==null)? children+2: children+3;
|
||
|
int i = 0;
|
||
|
CAstNode arguments[] = new CAstNode[ nargs ];
|
||
|
arguments[i++] = fun;
|
||
|
arguments[i++] = Ast.makeConstant( callee );
|
||
|
if (thisptr!=null) arguments[i++] = thisptr;
|
||
|
for(Node arg = firstChild; arg!=null; arg = arg.getNext() )
|
||
|
arguments[i++] = walkNodes( arg, context );
|
||
|
|
||
|
CAstNode call = Ast.makeNode(CAstNode.CALL, arguments);
|
||
|
|
||
|
context.cfg().map(call, call);
|
||
|
if (context.getCatchTarget() != null) {
|
||
|
context.cfg().add(call, context.getCatchTarget(), null);
|
||
|
}
|
||
|
|
||
|
return call;
|
||
|
}
|
||
|
|
||
|
private CAstEntity walkEntity(final ScriptOrFnNode n, WalkContext context) {
|
||
|
final FunctionContext child =
|
||
|
(n instanceof FunctionNode)?
|
||
|
new FunctionContext(context, (FunctionNode)n):
|
||
|
new ScriptContext(context, n, n.getSourceName());
|
||
|
|
||
|
CAstNode[] stmts = gatherChildren(n, child);
|
||
|
|
||
|
// add initializers, if any
|
||
|
if (! child.initializers.isEmpty()) {
|
||
|
CAstNode[] newStmts = new CAstNode[ stmts.length + 1];
|
||
|
|
||
|
newStmts[0] =
|
||
|
Ast.makeNode(CAstNode.BLOCK_STMT,
|
||
|
(CAstNode[])child.
|
||
|
initializers.
|
||
|
toArray( new CAstNode[ child.initializers.size() ] ));
|
||
|
|
||
|
for(int i = 0; i < stmts.length; i++)
|
||
|
newStmts[i+1] = stmts[i];
|
||
|
|
||
|
stmts = newStmts;
|
||
|
}
|
||
|
|
||
|
// function initialization code
|
||
|
if (n instanceof FunctionNode) {
|
||
|
CAstNode[] newStmts = new CAstNode[ stmts.length + 1];
|
||
|
newStmts[0] = Ast.makeNode(CAstNode.DECL_STMT,
|
||
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant("arguments")),
|
||
|
Ast.makeConstant(true),
|
||
|
Ast.makeConstant(false),
|
||
|
makeBuiltinNew(child, "Object"));
|
||
|
|
||
|
for(int i = 0; i < stmts.length; i++)
|
||
|
newStmts[i+1] = stmts[i];
|
||
|
|
||
|
stmts = newStmts;
|
||
|
}
|
||
|
|
||
|
final CAstNode ast = Ast.makeNode(CAstNode.BLOCK_STMT, stmts);
|
||
|
final CAstControlFlowMap map = child.cfg();
|
||
|
final CAstSourcePositionMap pos = child.pos();
|
||
|
|
||
|
final Map subs = new HashMap();
|
||
|
for(Iterator keys = child.getScopedEntities().keySet().iterator();
|
||
|
keys.hasNext(); )
|
||
|
{
|
||
|
Object k = keys.next();
|
||
|
Object v = child.getScopedEntities().get(k);
|
||
|
if (v instanceof Collection)
|
||
|
subs.put(k, v);
|
||
|
else
|
||
|
subs.put(k, Collections.singleton(v));
|
||
|
}
|
||
|
|
||
|
return new CAstEntity() {
|
||
|
private final String[] arguments;
|
||
|
private final String name;
|
||
|
|
||
|
// constructor of inner class
|
||
|
{
|
||
|
if (n instanceof FunctionNode) {
|
||
|
String x = ((FunctionNode)n).getFunctionName();
|
||
|
if (x == null || "".equals(x)) {
|
||
|
name = scriptName + "_anonymous_" + anonymousCounter++;
|
||
|
} else {
|
||
|
name = x;
|
||
|
}
|
||
|
} else {
|
||
|
name = n.getSourceName();
|
||
|
}
|
||
|
|
||
|
if (n instanceof FunctionNode) {
|
||
|
FunctionNode f = (FunctionNode)n;
|
||
|
int i = 0;
|
||
|
arguments = new String[ f.getParamCount() + 2 ];
|
||
|
arguments[i++] = name;
|
||
|
arguments[i++] = "this";
|
||
|
for(int j = 0; j < f.getParamCount(); j++) {
|
||
|
arguments[i++] = f.getParamOrVarName(j);
|
||
|
}
|
||
|
} else {
|
||
|
arguments = new String[0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public String toString() {
|
||
|
return "<JS function " + getName() + ">";
|
||
|
}
|
||
|
|
||
|
public String getName() {
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
public String getSignature() {
|
||
|
Assertions.UNREACHABLE();
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public int getKind() {
|
||
|
if (n instanceof FunctionNode)
|
||
|
return CAstEntity.FUNCTION_ENTITY;
|
||
|
else
|
||
|
return CAstEntity.SCRIPT_ENTITY;
|
||
|
}
|
||
|
|
||
|
public String[] getArgumentNames() {
|
||
|
return arguments;
|
||
|
}
|
||
|
|
||
|
public CAstNode[] getArgumentDefaults() {
|
||
|
return new CAstNode[0];
|
||
|
}
|
||
|
|
||
|
public int getArgumentCount() {
|
||
|
return arguments.length;
|
||
|
}
|
||
|
|
||
|
public Map getAllScopedEntities() {
|
||
|
return Collections.unmodifiableMap(subs);
|
||
|
}
|
||
|
|
||
|
public Iterator getScopedEntities(CAstNode construct) {
|
||
|
if (subs.containsKey(construct))
|
||
|
return ((Set)subs.get(construct)).iterator();
|
||
|
else
|
||
|
return EmptyIterator.instance();
|
||
|
}
|
||
|
|
||
|
public CAstNode getAST() {
|
||
|
return ast;
|
||
|
}
|
||
|
|
||
|
public CAstControlFlowMap getControlFlow() {
|
||
|
return map;
|
||
|
}
|
||
|
|
||
|
public CAstSourcePositionMap getSourceMap() {
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
public CAstSourcePositionMap.Position getPosition() {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public CAstNodeTypeMap getNodeTypeMap() {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public Collection getQualifiers() {
|
||
|
Assertions.UNREACHABLE("JuliansUnnamedCAstEntity$2.getQualifiers()");
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public CAstType getType() {
|
||
|
Assertions.UNREACHABLE("JuliansUnnamedCAstEntity$2.getType()");
|
||
|
return null;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
private CAstNode[] gatherSiblings(Node n, WalkContext context) {
|
||
|
int cnt = 0;
|
||
|
for(Node c = n; c != null; cnt++, c=c.getNext());
|
||
|
|
||
|
CAstNode[] result = new CAstNode[ cnt ];
|
||
|
for(int i = 0; i < result.length; i++, n=n.getNext()) {
|
||
|
result[i] = walkNodes(n, context);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
private CAstNode[] gatherChildren(Node n, WalkContext context, int skip) {
|
||
|
Node c = n.getFirstChild();
|
||
|
while (skip-- > 0) c=c.getNext();
|
||
|
return gatherSiblings(c, context);
|
||
|
}
|
||
|
|
||
|
private CAstNode[] gatherChildren(Node n, WalkContext context) {
|
||
|
return gatherSiblings(n.getFirstChild(), context);
|
||
|
}
|
||
|
|
||
|
private CAstNode walkNodes(final Node n, WalkContext context) {
|
||
|
return
|
||
|
noteSourcePosition(context,
|
||
|
walkNodesInternal(n, context),
|
||
|
n);
|
||
|
}
|
||
|
|
||
|
private CAstSourcePositionMap.Position makePosition(Node n) {
|
||
|
URL url;
|
||
|
if (sourceModule instanceof SourceFileModule) {
|
||
|
try {
|
||
|
url = new URL("file://"+((SourceFileModule)sourceModule).getFile());
|
||
|
} catch (MalformedURLException e){
|
||
|
Assertions.UNREACHABLE();
|
||
|
return null;
|
||
|
}
|
||
|
} else {
|
||
|
url = ((SourceURLModule)sourceModule).getURL();
|
||
|
}
|
||
|
|
||
|
return new LineNumberPosition(url, url, n.getLineno());
|
||
|
}
|
||
|
|
||
|
private CAstNode
|
||
|
noteSourcePosition(WalkContext context, CAstNode n, Node p)
|
||
|
{
|
||
|
if (p.getLineno() != -1 && context.pos().getPosition(n) == null) {
|
||
|
context.pos().setPosition(n, makePosition(p));
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
private CAstNode walkNodesInternal(final Node n, WalkContext context) {
|
||
|
int NT = n.getType();
|
||
|
switch (NT) {
|
||
|
|
||
|
case Token.FUNCTION: {
|
||
|
int fnIndex = n.getExistingIntProp(Node.FUNCTION_PROP);
|
||
|
FunctionNode fn = context.top().getFunctionNode(fnIndex);
|
||
|
|
||
|
CAstEntity fne = walkEntity(fn, context);
|
||
|
|
||
|
if (context.expressionContext()) {
|
||
|
CAstNode fun =
|
||
|
Ast.makeNode(CAstNode.FUNCTION_EXPR, Ast.makeConstant( fne ));
|
||
|
|
||
|
context.addScopedEntity(fun, fne);
|
||
|
|
||
|
return fun;
|
||
|
|
||
|
} else {
|
||
|
context.addInitializer(
|
||
|
Ast.makeNode(CAstNode.FUNCTION_STMT, Ast.makeConstant( fne )));
|
||
|
|
||
|
context.addScopedEntity(null, fne);
|
||
|
|
||
|
return Ast.makeNode(CAstNode.EMPTY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.CATCH_SCOPE: {
|
||
|
Node catchVarNode = n.getFirstChild();
|
||
|
String catchVarName = catchVarNode.getString();
|
||
|
Assertions._assert(catchVarName != null);
|
||
|
context.setCatchVar(catchVarName);
|
||
|
return Ast.makeNode(CAstNode.EMPTY);
|
||
|
}
|
||
|
|
||
|
case Token.LOCAL_BLOCK: {
|
||
|
return Ast.makeNode(CAstNode.BLOCK_EXPR, gatherChildren(n, context));
|
||
|
}
|
||
|
|
||
|
case Token.TRY: {
|
||
|
Node catchNode = ((Node.Jump)n).target;
|
||
|
Node finallyNode = ((Node.Jump)n).getFinally();
|
||
|
|
||
|
ArrayList tryList = new ArrayList();
|
||
|
ArrayList catchList = new ArrayList();
|
||
|
ArrayList finallyList = new ArrayList();
|
||
|
|
||
|
Node lastChildNode = null;
|
||
|
for(Node c = n.getFirstChild(); c != null; c=c.getNext()) {
|
||
|
lastChildNode = c;
|
||
|
}
|
||
|
|
||
|
ArrayList current = tryList;
|
||
|
Node c;
|
||
|
for(c = n.getFirstChild(); c.getNext() != null; c=c.getNext()) {
|
||
|
if (c == catchNode) {
|
||
|
current = catchList;
|
||
|
} else if (c == finallyNode) {
|
||
|
current = finallyList;
|
||
|
}
|
||
|
|
||
|
if (c.getType() == Token.GOTO &&
|
||
|
// ((Node.Jump)c).target == lastChildNode &&
|
||
|
( c.getNext() == catchNode || c.getNext() == finallyNode ))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
current.add( c );
|
||
|
}
|
||
|
|
||
|
CAstNode finallyBlock = null;
|
||
|
if (finallyNode != null) {
|
||
|
int i = 0;
|
||
|
CAstNode[] finallyAsts = new CAstNode[ finallyList.size() ];
|
||
|
for(Iterator fns = finallyList.iterator(); fns.hasNext(); ) {
|
||
|
finallyAsts[i++] = walkNodes((Node)fns.next(), context);
|
||
|
}
|
||
|
finallyBlock = Ast.makeNode(CAstNode.BLOCK_STMT, finallyAsts);
|
||
|
}
|
||
|
|
||
|
if (catchNode != null) {
|
||
|
|
||
|
int i = 0;
|
||
|
WalkContext catchChild = new CatchBlockContext(context);
|
||
|
CAstNode[] catchAsts = new CAstNode[ catchList.size() ];
|
||
|
for(Iterator cns = catchList.iterator(); cns.hasNext(); ) {
|
||
|
catchAsts[i++] = walkNodes((Node)cns.next(), catchChild);
|
||
|
}
|
||
|
CAstNode catchBlock = Ast.makeNode(CAstNode.CATCH,
|
||
|
Ast.makeConstant(catchChild.getCatchVar()),
|
||
|
Ast.makeNode(CAstNode.BLOCK_STMT, catchAsts));
|
||
|
context.cfg().map(catchBlock, catchBlock);
|
||
|
|
||
|
i = 0;
|
||
|
WalkContext tryChild = new TryBlockContext(context, catchBlock);
|
||
|
CAstNode[] tryAsts = new CAstNode[ tryList.size() ];
|
||
|
for(Iterator tns = tryList.iterator(); tns.hasNext(); ) {
|
||
|
tryAsts[i++] = walkNodes((Node)tns.next(), tryChild);
|
||
|
}
|
||
|
CAstNode tryBlock = Ast.makeNode(CAstNode.BLOCK_STMT, tryAsts);
|
||
|
|
||
|
if (finallyBlock != null) {
|
||
|
return Ast.makeNode(CAstNode.BLOCK_STMT,
|
||
|
Ast.makeNode(CAstNode.UNWIND,
|
||
|
Ast.makeNode(CAstNode.TRY, tryBlock, catchBlock),
|
||
|
finallyBlock),
|
||
|
walkNodes(c,context));
|
||
|
} else {
|
||
|
return Ast.makeNode(CAstNode.BLOCK_STMT,
|
||
|
Ast.makeNode(CAstNode.TRY, tryBlock, catchBlock),
|
||
|
walkNodes(c,context));
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
int i = 0;
|
||
|
CAstNode[] tryAsts = new CAstNode[ tryList.size() ];
|
||
|
for(Iterator tns = tryList.iterator(); tns.hasNext(); ) {
|
||
|
tryAsts[i++] = walkNodes((Node)tns.next(), context);
|
||
|
}
|
||
|
CAstNode tryBlock = Ast.makeNode(CAstNode.BLOCK_STMT, tryAsts);
|
||
|
|
||
|
return Ast.makeNode(CAstNode.BLOCK_STMT,
|
||
|
Ast.makeNode(CAstNode.UNWIND,
|
||
|
Ast.makeNode(CAstNode.BLOCK_STMT, tryBlock),
|
||
|
Ast.makeNode(CAstNode.BLOCK_STMT, finallyBlock)),
|
||
|
walkNodes(c,context));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.JSR: {
|
||
|
return Ast.makeNode(CAstNode.EMPTY);
|
||
|
/*
|
||
|
Node jsrTarget = ((Node.Jump)n).target;
|
||
|
Node finallyNode = jsrTarget.getNext();
|
||
|
return walkNodes(finallyNode, context);
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
case Token.COMMA: {
|
||
|
int count = 0;
|
||
|
for (Node c = n.getFirstChild(); c!=null; count++,c=c.getNext());
|
||
|
|
||
|
CAstNode[] cs = new CAstNode[ count ];
|
||
|
int i = 0;
|
||
|
for (Node c = n.getFirstChild(); c != null; i++, c=c.getNext()) {
|
||
|
if (c.getNext() == null) {
|
||
|
context.copyBase(n, c);
|
||
|
}
|
||
|
cs[i] = walkNodes(c, context);
|
||
|
}
|
||
|
|
||
|
return Ast.makeNode(CAstNode.BLOCK_EXPR, cs);
|
||
|
}
|
||
|
|
||
|
case Token.ENTERWITH:
|
||
|
case Token.LEAVEWITH: {
|
||
|
return Ast.makeNode(CAstNode.EMPTY);
|
||
|
}
|
||
|
|
||
|
case Token.LOOP: {
|
||
|
LoopContext child = new LoopContext(context);
|
||
|
CAstNode[] nodes = gatherChildren(n, child);
|
||
|
|
||
|
if (child.forInInitExpr != null) {
|
||
|
String nm = child.forInVar;
|
||
|
return Ast.makeNode(CAstNode.BLOCK_STMT,
|
||
|
Ast.makeNode(CAstNode.DECL_STMT,
|
||
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(nm)),
|
||
|
Ast.makeConstant(true),
|
||
|
Ast.makeConstant(false),
|
||
|
walkNodes(child.forInInitExpr, context)),
|
||
|
nodes);
|
||
|
} else {
|
||
|
return Ast.makeNode(CAstNode.BLOCK_STMT, nodes);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.WITH:
|
||
|
case Token.FINALLY:
|
||
|
case Token.BLOCK:
|
||
|
case Token.LABEL: {
|
||
|
Node c1 = n.getFirstChild();
|
||
|
if (c1 != null && c1.getType() == Token.SWITCH) {
|
||
|
Node switchValue = c1.getFirstChild();
|
||
|
|
||
|
CAstNode defaultLabel =
|
||
|
Ast.makeNode(CAstNode.LABEL_STMT,
|
||
|
Ast.makeNode(CAstNode.EMPTY));
|
||
|
context.cfg().map(defaultLabel, defaultLabel);
|
||
|
|
||
|
for(Node kase = switchValue.getNext();
|
||
|
kase != null;
|
||
|
kase = kase.getNext())
|
||
|
{
|
||
|
Assertions._assert(kase.getType() == Token.CASE);
|
||
|
Node caseLbl = kase.getFirstChild();
|
||
|
Node target = ((Node.Jump)kase).target;
|
||
|
context.cfg().add(c1, target, walkNodes(caseLbl, context));
|
||
|
}
|
||
|
|
||
|
context.cfg().add(c1, defaultLabel, CAstControlFlowMap.SWITCH_DEFAULT);
|
||
|
|
||
|
CAstNode switchAst =
|
||
|
Ast.makeNode(CAstNode.SWITCH,
|
||
|
walkNodes(switchValue, context),
|
||
|
Ast.makeNode(CAstNode.BLOCK_STMT,
|
||
|
defaultLabel,
|
||
|
gatherChildren(n, context, 1)));
|
||
|
|
||
|
noteSourcePosition(context, switchAst, c1);
|
||
|
context.cfg().map(c1, switchAst);
|
||
|
return switchAst;
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
return
|
||
|
Ast.makeNode(CAstNode.BLOCK_STMT, gatherChildren(n, context));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.EXPR_VOID:
|
||
|
case Token.EXPR_RESULT:
|
||
|
case Token.POS: {
|
||
|
WalkContext child = new ExpressionContext( context );
|
||
|
Node expr = n.getFirstChild();
|
||
|
|
||
|
if (NT==Token.EXPR_RESULT) {
|
||
|
child.copyBase(n, expr);
|
||
|
}
|
||
|
|
||
|
return walkNodes(expr, child);
|
||
|
}
|
||
|
|
||
|
case Token.CALL: {
|
||
|
if (! isPrimitiveCall(context, n)) {
|
||
|
CAstNode base = Ast.makeNode(CAstNode.VAR, Ast.makeConstant("base"));
|
||
|
Node callee = n.getFirstChild();
|
||
|
WalkContext child = new BaseCollectingContext(context, callee, base);
|
||
|
CAstNode fun = walkNodes( callee, child );
|
||
|
|
||
|
if (child.foundBase(callee))
|
||
|
return Ast.makeNode(CAstNode.LOCAL_SCOPE,
|
||
|
Ast.makeNode(CAstNode.BLOCK_EXPR,
|
||
|
Ast.makeNode(CAstNode.DECL_STMT,
|
||
|
base,
|
||
|
Ast.makeConstant(false),
|
||
|
Ast.makeConstant(false),
|
||
|
Ast.makeConstant(null)),
|
||
|
makeCall(fun, base, callee.getNext(), context)));
|
||
|
else
|
||
|
return makeCall(fun, Ast.makeConstant(null), callee.getNext(), context);
|
||
|
} else {
|
||
|
return Ast.makeNode(CAstNode.PRIMITIVE, gatherChildren(n, context, 1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.NAME: {
|
||
|
return Ast.makeNode(CAstNode.VAR, Ast.makeConstant( n.getString() ));
|
||
|
}
|
||
|
|
||
|
case Token.THIS: {
|
||
|
return Ast.makeNode(CAstNode.VAR, Ast.makeConstant( "this" ));
|
||
|
}
|
||
|
|
||
|
case Token.THISFN: {
|
||
|
return Ast.makeNode(CAstNode.VAR, Ast.makeConstant( ((FunctionNode)context.top()).getFunctionName() ));
|
||
|
}
|
||
|
|
||
|
case Token.STRING: {
|
||
|
return Ast.makeConstant( n.getString() );
|
||
|
}
|
||
|
|
||
|
case Token.NUMBER: {
|
||
|
return Ast.makeConstant( n.getDouble() );
|
||
|
}
|
||
|
|
||
|
case Token.FALSE: {
|
||
|
return Ast.makeConstant( false );
|
||
|
}
|
||
|
|
||
|
case Token.TRUE: {
|
||
|
return Ast.makeConstant( true );
|
||
|
}
|
||
|
|
||
|
case Token.NULL: {
|
||
|
return Ast.makeConstant( null );
|
||
|
}
|
||
|
|
||
|
case Token.ADD:
|
||
|
case Token.DIV:
|
||
|
case Token.LSH:
|
||
|
case Token.MOD:
|
||
|
case Token.MUL:
|
||
|
case Token.RSH:
|
||
|
case Token.SUB:
|
||
|
case Token.URSH:
|
||
|
case Token.BITAND:
|
||
|
case Token.EQ:
|
||
|
case Token.SHEQ:
|
||
|
case Token.GE:
|
||
|
case Token.GT:
|
||
|
case Token.LE:
|
||
|
case Token.LT:
|
||
|
case Token.SHNE:
|
||
|
case Token.NE: {
|
||
|
Node l = n.getFirstChild();
|
||
|
Node r = l.getNext();
|
||
|
return Ast.makeNode(CAstNode.BINARY_EXPR,
|
||
|
translateOpcode(NT),
|
||
|
walkNodes(l, context),
|
||
|
walkNodes(r, context));
|
||
|
}
|
||
|
|
||
|
case Token.NEG: {
|
||
|
return Ast.makeNode(CAstNode.BINARY_EXPR,
|
||
|
translateOpcode(Token.SUB),
|
||
|
Ast.makeConstant(0),
|
||
|
walkNodes(n.getFirstChild(), context));
|
||
|
}
|
||
|
|
||
|
case Token.BITNOT:
|
||
|
case Token.NOT: {
|
||
|
return Ast.makeNode(CAstNode.UNARY_EXPR,
|
||
|
translateOpcode(NT),
|
||
|
walkNodes(n.getFirstChild(), context));
|
||
|
}
|
||
|
|
||
|
case Token.VAR: {
|
||
|
Node nm = n.getFirstChild();
|
||
|
|
||
|
context.addInitializer(
|
||
|
Ast.makeNode(CAstNode.DECL_STMT,
|
||
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant( nm.getString() )),
|
||
|
Ast.makeConstant(false),
|
||
|
Ast.makeConstant(false),
|
||
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant("undefined"))));
|
||
|
|
||
|
|
||
|
if (nm.getFirstChild() != null) {
|
||
|
WalkContext child = new ExpressionContext( context );
|
||
|
|
||
|
return
|
||
|
Ast.makeNode(CAstNode.ASSIGN,
|
||
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant( nm.getString() )),
|
||
|
walkNodes( nm.getFirstChild(), child ));
|
||
|
|
||
|
} else {
|
||
|
if (n.getNext().getType() == Token.ENUM_INIT_KEYS) {
|
||
|
context.getForInVar(nm.getString(), n.getNext().getFirstChild());
|
||
|
}
|
||
|
|
||
|
return Ast.makeNode(CAstNode.EMPTY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.REGEXP: {
|
||
|
int regexIdx = n.getIntProp(Node.REGEXP_PROP, -1);
|
||
|
|
||
|
Assertions._assert(regexIdx != -1, "while converting: " + context.top().toStringTree(context.top()) + "\nlooking at bad regex:\n " + n.toStringTree(context.top()));
|
||
|
|
||
|
String flags = context.top().getRegexpFlags(regexIdx);
|
||
|
Node flagsNode = Node.newString( flags );
|
||
|
|
||
|
String str = context.top().getRegexpString(regexIdx);
|
||
|
Node strNode = Node.newString( str );
|
||
|
|
||
|
strNode.addChildToFront( flagsNode );
|
||
|
|
||
|
return handleNew(context, "RegExp", strNode);
|
||
|
}
|
||
|
|
||
|
case Token.ENUM_INIT_KEYS: {
|
||
|
return Ast.makeNode(CAstNode.EMPTY);
|
||
|
}
|
||
|
|
||
|
case Token.ENUM_ID: {
|
||
|
return
|
||
|
Ast.makeNode(CAstNode.EACH_ELEMENT_GET,
|
||
|
Ast.makeNode(CAstNode.VAR,
|
||
|
Ast.makeConstant(context.getForInInitVar())));
|
||
|
}
|
||
|
|
||
|
case Token.ENUM_NEXT: {
|
||
|
return
|
||
|
Ast.makeNode(CAstNode.EACH_ELEMENT_HAS_NEXT,
|
||
|
Ast.makeNode(CAstNode.VAR,
|
||
|
Ast.makeConstant(context.getForInInitVar())));
|
||
|
}
|
||
|
|
||
|
case Token.RETURN: {
|
||
|
Node val = n.getFirstChild();
|
||
|
if (val != null) {
|
||
|
WalkContext child = new ExpressionContext( context );
|
||
|
return Ast.makeNode(CAstNode.RETURN, walkNodes(val, child));
|
||
|
} else {
|
||
|
return Ast.makeNode(CAstNode.RETURN);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.SETNAME: {
|
||
|
Node nm = n.getFirstChild();
|
||
|
return Ast.makeNode(CAstNode.ASSIGN,
|
||
|
walkNodes(nm, context),
|
||
|
walkNodes(nm.getNext(), context));
|
||
|
}
|
||
|
|
||
|
case Token.BINDNAME: {
|
||
|
return Ast.makeNode(CAstNode.VAR, Ast.makeConstant( n.getString() ));
|
||
|
}
|
||
|
|
||
|
case Token.IFNE:
|
||
|
case Token.IFEQ: {
|
||
|
context.cfg().add(n, ((Node.Jump)n).target, Boolean.TRUE);
|
||
|
WalkContext child = new ExpressionContext( context );
|
||
|
CAstNode gotoAst = Ast.makeNode(CAstNode.IFGOTO,
|
||
|
translateOpcode(NT),
|
||
|
walkNodes( n.getFirstChild(), child ),
|
||
|
Ast.makeConstant( 1 ));
|
||
|
|
||
|
context.cfg().map(n, gotoAst);
|
||
|
return gotoAst;
|
||
|
}
|
||
|
|
||
|
case Token.GOTO: {
|
||
|
context.cfg().add(n, ((Node.Jump)n).target, null);
|
||
|
CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO,
|
||
|
Ast.makeConstant(((Node.Jump)n).target.labelId()));
|
||
|
|
||
|
context.cfg().map(n, gotoAst);
|
||
|
return gotoAst;
|
||
|
}
|
||
|
|
||
|
case Token.BREAK: {
|
||
|
context.cfg().add(n, ((Node.Jump)n).getJumpStatement().target, null);
|
||
|
CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO,
|
||
|
Ast.makeConstant(((Node.Jump)n).getJumpStatement().target.labelId()));
|
||
|
|
||
|
context.cfg().map(n, gotoAst);
|
||
|
return gotoAst;
|
||
|
}
|
||
|
|
||
|
case Token.CONTINUE: {
|
||
|
context.cfg().add(n, ((Node.Jump)n).getJumpStatement().getContinue(), null);
|
||
|
CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO,
|
||
|
Ast.makeConstant(((Node.Jump)n).getJumpStatement().getContinue().labelId()));
|
||
|
|
||
|
context.cfg().map(n, gotoAst);
|
||
|
return gotoAst;
|
||
|
}
|
||
|
|
||
|
case Token.TARGET: {
|
||
|
CAstNode result = Ast.makeNode(CAstNode.LABEL_STMT,
|
||
|
Ast.makeConstant( n.labelId() ),
|
||
|
Ast.makeNode(CAstNode.EMPTY));
|
||
|
|
||
|
context.cfg().map(n, result);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
case Token.OR: {
|
||
|
Node l = n.getFirstChild();
|
||
|
Node r = l.getNext();
|
||
|
return Ast.makeNode(CAstNode.IF_EXPR,
|
||
|
walkNodes(l, context),
|
||
|
Ast.makeConstant( true ),
|
||
|
walkNodes(r, context));
|
||
|
}
|
||
|
|
||
|
case Token.AND: {
|
||
|
Node l = n.getFirstChild();
|
||
|
Node r = l.getNext();
|
||
|
return Ast.makeNode(CAstNode.IF_EXPR,
|
||
|
walkNodes(l, context),
|
||
|
walkNodes(r, context),
|
||
|
Ast.makeConstant( false ));
|
||
|
}
|
||
|
|
||
|
case Token.HOOK: {
|
||
|
Node cond = n.getFirstChild();
|
||
|
Node thenBranch = cond.getNext();
|
||
|
Node elseBranch = thenBranch.getNext();
|
||
|
return Ast.makeNode(CAstNode.IF_EXPR,
|
||
|
walkNodes(cond, context),
|
||
|
walkNodes(thenBranch, context),
|
||
|
walkNodes(elseBranch, context));
|
||
|
|
||
|
}
|
||
|
|
||
|
case Token.INC:
|
||
|
case Token.DEC: {
|
||
|
int flags = n.getIntProp( Node.INCRDECR_PROP, -1 );
|
||
|
CAstNode op = ((flags&Node.DECR_FLAG)!=0)? CAstOperator.OP_SUB: CAstOperator.OP_ADD;
|
||
|
|
||
|
Node l = n.getFirstChild();
|
||
|
CAstNode last = walkNodes(l, context);
|
||
|
|
||
|
return Ast.makeNode((((flags&Node.POST_FLAG)!=0)?CAstNode.ASSIGN_POST_OP:CAstNode.ASSIGN_PRE_OP), last, Ast.makeConstant(1), op);
|
||
|
}
|
||
|
|
||
|
case Token.NEW: {
|
||
|
if (isPrimitiveCreation(context, n)) {
|
||
|
return makeBuiltinNew(context, n.getFirstChild().getString());
|
||
|
} else {
|
||
|
Node receiver = n.getFirstChild();
|
||
|
return handleNew(context, walkNodes(receiver, context), receiver.getNext());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.ARRAYLIT: {
|
||
|
int count = 0;
|
||
|
for(Node x = n.getFirstChild(); x != null; count++, x=x.getNext());
|
||
|
|
||
|
int i = 0;
|
||
|
CAstNode[] args = new CAstNode[ 2*count+1 ];
|
||
|
args[i++] =
|
||
|
(isPrologueScript(context))?
|
||
|
makeBuiltinNew(context, "Array"):
|
||
|
handleNew(context, "Array", null);
|
||
|
|
||
|
int[] skips = (int[])n.getProp( Node.SKIP_INDEXES_PROP );
|
||
|
int skip = 0;
|
||
|
int idx = 0;
|
||
|
Node elt = n.getFirstChild();
|
||
|
while (elt != null) {
|
||
|
if (skips != null && skip < skips.length && skips[skip] == idx) {
|
||
|
skip++;
|
||
|
idx++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
args[i++] = Ast.makeConstant(idx++);
|
||
|
args[i++] = walkNodes( elt, context );
|
||
|
|
||
|
elt = elt.getNext();
|
||
|
}
|
||
|
|
||
|
return Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
|
||
|
}
|
||
|
|
||
|
case Token.OBJECTLIT: {
|
||
|
Object[] propertyList = (Object[])n.getProp( Node.OBJECT_IDS_PROP );
|
||
|
CAstNode[] args = new CAstNode[ propertyList.length*2 + 1 ];
|
||
|
int i = 0;
|
||
|
args[i++] =
|
||
|
((isPrologueScript(context))?
|
||
|
makeBuiltinNew(context, "Object"):
|
||
|
handleNew(context, "Object", null));
|
||
|
|
||
|
Node val = n.getFirstChild();
|
||
|
int nameIdx = 0;
|
||
|
for( ; nameIdx < propertyList.length; nameIdx++, val=val.getNext()) {
|
||
|
args[i++] = Ast.makeConstant( propertyList[ nameIdx ] );
|
||
|
args[i++] = walkNodes( val, context );
|
||
|
}
|
||
|
|
||
|
return Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
|
||
|
}
|
||
|
|
||
|
case Token.GETPROP:
|
||
|
case Token.GETELEM: {
|
||
|
Node receiver = n.getFirstChild();
|
||
|
Node element = receiver.getNext();
|
||
|
|
||
|
CAstNode rcvr = walkNodes(receiver, context);
|
||
|
CAstNode baseVar = context.setBase(n);
|
||
|
|
||
|
CAstNode elt = walkNodes(element, context);
|
||
|
|
||
|
if (baseVar != null) {
|
||
|
return Ast.makeNode(CAstNode.BLOCK_EXPR,
|
||
|
Ast.makeNode(CAstNode.ASSIGN, baseVar, rcvr),
|
||
|
Ast.makeNode(CAstNode.OBJECT_REF, baseVar, elt));
|
||
|
} else {
|
||
|
return Ast.makeNode(CAstNode.OBJECT_REF, rcvr, elt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.SETPROP:
|
||
|
case Token.SETELEM: {
|
||
|
Node receiver = n.getFirstChild();
|
||
|
Node elt = receiver.getNext();
|
||
|
Node val = elt.getNext();
|
||
|
|
||
|
CAstNode rcvr = walkNodes(receiver, context);
|
||
|
|
||
|
return Ast.makeNode(CAstNode.ASSIGN,
|
||
|
Ast.makeNode(CAstNode.OBJECT_REF, rcvr, walkNodes(elt, context)),
|
||
|
walkNodes(val, context));
|
||
|
}
|
||
|
|
||
|
case Token.DELPROP: {
|
||
|
Node receiver = n.getFirstChild();
|
||
|
Node element = receiver.getNext();
|
||
|
|
||
|
CAstNode rcvr = walkNodes(receiver, context);
|
||
|
CAstNode baseVar = context.setBase(n);
|
||
|
|
||
|
CAstNode elt = walkNodes(element, context);
|
||
|
|
||
|
if (baseVar != null) {
|
||
|
return Ast.makeNode(CAstNode.BLOCK_EXPR,
|
||
|
Ast.makeNode(CAstNode.ASSIGN, baseVar, rcvr),
|
||
|
Ast.makeNode(CAstNode.ASSIGN,
|
||
|
Ast.makeNode(CAstNode.OBJECT_REF, baseVar, elt),
|
||
|
Ast.makeConstant(null)));
|
||
|
} else {
|
||
|
return Ast.makeNode(CAstNode.ASSIGN,
|
||
|
Ast.makeNode(CAstNode.OBJECT_REF, rcvr, elt),
|
||
|
Ast.makeConstant(null));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case Token.TYPEOFNAME: {
|
||
|
return Ast.makeNode(CAstNode.TYPE_OF,
|
||
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(n.getString())));
|
||
|
}
|
||
|
|
||
|
case Token.TYPEOF: {
|
||
|
return Ast.makeNode(CAstNode.TYPE_OF,
|
||
|
walkNodes(n.getFirstChild(), context));
|
||
|
}
|
||
|
|
||
|
case Token.SETPROP_OP:
|
||
|
case Token.SETELEM_OP: {
|
||
|
Node receiver = n.getFirstChild();
|
||
|
Node elt = receiver.getNext();
|
||
|
Node op = elt.getNext();
|
||
|
|
||
|
CAstNode rcvr = walkNodes(receiver, context);
|
||
|
|
||
|
return Ast.makeNode(CAstNode.ASSIGN_POST_OP,
|
||
|
Ast.makeNode(CAstNode.OBJECT_REF, rcvr, walkNodes(elt, context)),
|
||
|
walkNodes(op.getFirstChild().getNext(), context),
|
||
|
translateOpcode(op.getType()));
|
||
|
}
|
||
|
|
||
|
case Token.THROW: {
|
||
|
CAstNode catchNode = context.getCatchTarget();
|
||
|
if (catchNode != null)
|
||
|
context.cfg().add(n, context.getCatchTarget(), null);
|
||
|
else
|
||
|
context.cfg().add(n, CAstControlFlowMap.EXCEPTION_TO_EXIT, null);
|
||
|
|
||
|
CAstNode throwAst = Ast.makeNode(CAstNode.THROW,
|
||
|
walkNodes(n.getFirstChild(), context));
|
||
|
|
||
|
context.cfg().map(n, throwAst);
|
||
|
return throwAst;
|
||
|
}
|
||
|
|
||
|
case Token.EMPTY: {
|
||
|
return Ast.makeConstant( null );
|
||
|
}
|
||
|
|
||
|
default: {
|
||
|
System.err.println("while converting: " + context.top().toStringTree(context.top()) + "\nlooking at unhandled:\n " + n.toStringTree(context.top()) + "\n(of type " + NT + ") (of class " + n.getClass() +")");
|
||
|
|
||
|
Assertions.UNREACHABLE();
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public CAstEntity translate()
|
||
|
throws java.io.IOException
|
||
|
{
|
||
|
ToolErrorReporter reporter = new ToolErrorReporter(true);
|
||
|
CompilerEnvirons compilerEnv = new CompilerEnvirons();
|
||
|
compilerEnv.setErrorReporter(reporter);
|
||
|
|
||
|
if (DEBUG) Trace.println("translating " + scriptName + " with Rhino");
|
||
|
|
||
|
Parser P = new Parser(compilerEnv, compilerEnv.getErrorReporter());
|
||
|
|
||
|
return walkEntity( P.parse(new InputStreamReader(sourceModule.getInputStream()), scriptName, 1), new RootContext());
|
||
|
}
|
||
|
|
||
|
private final CAst Ast;
|
||
|
private final String scriptName;
|
||
|
private final ModuleEntry sourceModule;
|
||
|
private int anonymousCounter = 0;
|
||
|
|
||
|
public RhinoToAstTranslator(CAst Ast, ModuleEntry M, String scriptName) {
|
||
|
this.Ast = Ast;
|
||
|
this.scriptName = scriptName;
|
||
|
this.sourceModule = M;
|
||
|
}
|
||
|
}
|