Refactor JS parser
This commit is contained in:
@@ -15,14 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.gwt.dev.js;
|
package com.google.gwt.dev.js;
|
||||||
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsBooleanLiteral;
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.HasMetadata;
|
|
||||||
import com.google.gwt.dev.js.parserExceptions.JsParserException;
|
import com.google.gwt.dev.js.parserExceptions.JsParserException;
|
||||||
import com.google.gwt.dev.js.rhino.*;
|
import com.google.gwt.dev.js.rhino.Node;
|
||||||
|
import com.google.gwt.dev.js.rhino.TokenStream;
|
||||||
import com.intellij.util.SmartList;
|
import com.intellij.util.SmartList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -40,8 +39,7 @@ public class JsAstMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static JsParserException createParserException(String msg, Node offender) {
|
private static JsParserException createParserException(String msg, Node offender) {
|
||||||
CodePosition position = new CodePosition(offender.getLineno(), 0);
|
return new JsParserException("Parser encountered internal error: " + msg, offender.getPosition());
|
||||||
return new JsParserException("Parser encountered internal error: " + msg, position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsNode map(Node node) throws JsParserException {
|
private JsNode map(Node node) throws JsParserException {
|
||||||
@@ -254,7 +252,7 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
private JsExpression mapAssignmentVariant(Node asgNode)
|
private JsExpression mapAssignmentVariant(Node asgNode)
|
||||||
throws JsParserException {
|
throws JsParserException {
|
||||||
switch (asgNode.getIntDatum()) {
|
switch (asgNode.getOperation()) {
|
||||||
case TokenStream.NOP:
|
case TokenStream.NOP:
|
||||||
return mapBinaryOperation(JsBinaryOperator.ASG, asgNode);
|
return mapBinaryOperation(JsBinaryOperator.ASG, asgNode);
|
||||||
|
|
||||||
@@ -293,7 +291,7 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
throw createParserException("Unknown assignment operator variant: "
|
throw createParserException("Unknown assignment operator variant: "
|
||||||
+ asgNode.getIntDatum(), asgNode);
|
+ asgNode.getOperation(), asgNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +432,7 @@ public class JsAstMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JsExpression mapEqualityVariant(Node eqNode) throws JsParserException {
|
private JsExpression mapEqualityVariant(Node eqNode) throws JsParserException {
|
||||||
switch (eqNode.getIntDatum()) {
|
switch (eqNode.getOperation()) {
|
||||||
case TokenStream.EQ:
|
case TokenStream.EQ:
|
||||||
return mapBinaryOperation(JsBinaryOperator.EQ, eqNode);
|
return mapBinaryOperation(JsBinaryOperator.EQ, eqNode);
|
||||||
|
|
||||||
@@ -461,18 +459,13 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
throw createParserException("Unknown equality operator variant: "
|
throw createParserException("Unknown equality operator variant: "
|
||||||
+ eqNode.getIntDatum(), eqNode);
|
+ eqNode.getOperation(), eqNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsExpression mapExpression(Node exprNode) throws JsParserException {
|
private JsExpression mapExpression(Node exprNode) throws JsParserException {
|
||||||
JsNode unknown = map(exprNode);
|
JsNode unknown = map(exprNode);
|
||||||
|
|
||||||
if (unknown instanceof HasMetadata) {
|
|
||||||
HasMetadata metadataContainer = (HasMetadata) unknown;
|
|
||||||
metadataContainer.setData("line", exprNode.getLineno());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unknown instanceof JsExpression) {
|
if (unknown instanceof JsExpression) {
|
||||||
return (JsExpression) unknown;
|
return (JsExpression) unknown;
|
||||||
}
|
}
|
||||||
@@ -611,16 +604,8 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
JsExpression toQualifier = mapExpression(from1);
|
JsExpression toQualifier = mapExpression(from1);
|
||||||
JsNameRef toNameRef;
|
JsNameRef toNameRef;
|
||||||
if (from2 != null) {
|
toNameRef = mapAsPropertyNameRef(from2);
|
||||||
toNameRef = mapAsPropertyNameRef(from2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Special properties don't have a second expression.
|
|
||||||
//
|
|
||||||
Object obj = getPropNode.getProp(Node.SPECIAL_PROP_PROP);
|
|
||||||
assert (obj instanceof String);
|
|
||||||
toNameRef = scopeContext.referenceFor((String) obj);
|
|
||||||
}
|
|
||||||
toNameRef.setQualifier(toQualifier);
|
toNameRef.setQualifier(toQualifier);
|
||||||
|
|
||||||
return toNameRef;
|
return toNameRef;
|
||||||
@@ -649,14 +634,14 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
private JsExpression mapIncDecFixity(JsUnaryOperator op, Node node)
|
private JsExpression mapIncDecFixity(JsUnaryOperator op, Node node)
|
||||||
throws JsParserException {
|
throws JsParserException {
|
||||||
switch (node.getIntDatum()) {
|
switch (node.getOperation()) {
|
||||||
case TokenStream.PRE:
|
case TokenStream.PRE:
|
||||||
return mapPrefixOperation(op, node);
|
return mapPrefixOperation(op, node);
|
||||||
case TokenStream.POST:
|
case TokenStream.POST:
|
||||||
return mapPostfixOperation(op, node);
|
return mapPostfixOperation(op, node);
|
||||||
default:
|
default:
|
||||||
throw createParserException(
|
throw createParserException(
|
||||||
"Unknown prefix/postfix variant: " + node.getIntDatum(), node);
|
"Unknown prefix/postfix variant: " + node.getOperation(), node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,7 +746,7 @@ public class JsAstMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static JsExpression mapPrimary(Node node) throws JsParserException {
|
private static JsExpression mapPrimary(Node node) throws JsParserException {
|
||||||
switch (node.getIntDatum()) {
|
switch (node.getOperation()) {
|
||||||
case TokenStream.THIS:
|
case TokenStream.THIS:
|
||||||
return new JsThisRef();
|
return new JsThisRef();
|
||||||
|
|
||||||
@@ -778,7 +763,7 @@ public class JsAstMapper {
|
|||||||
return new JsNameRef("undefined");
|
return new JsNameRef("undefined");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw createParserException("Unknown primary: " + node.getIntDatum(),
|
throw createParserException("Unknown primary: " + node.getOperation(),
|
||||||
node);
|
node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -799,7 +784,7 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
private JsExpression mapRelationalVariant(Node relNode)
|
private JsExpression mapRelationalVariant(Node relNode)
|
||||||
throws JsParserException {
|
throws JsParserException {
|
||||||
switch (relNode.getIntDatum()) {
|
switch (relNode.getOperation()) {
|
||||||
case TokenStream.LT:
|
case TokenStream.LT:
|
||||||
return mapBinaryOperation(JsBinaryOperator.LT, relNode);
|
return mapBinaryOperation(JsBinaryOperator.LT, relNode);
|
||||||
|
|
||||||
@@ -820,7 +805,7 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
throw createParserException("Unknown relational operator variant: "
|
throw createParserException("Unknown relational operator variant: "
|
||||||
+ relNode.getIntDatum(), relNode);
|
+ relNode.getOperation(), relNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -864,7 +849,7 @@ public class JsAstMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JsExpression mapShiftVariant(Node shiftNode) throws JsParserException {
|
private JsExpression mapShiftVariant(Node shiftNode) throws JsParserException {
|
||||||
switch (shiftNode.getIntDatum()) {
|
switch (shiftNode.getOperation()) {
|
||||||
case TokenStream.LSH:
|
case TokenStream.LSH:
|
||||||
return mapBinaryOperation(JsBinaryOperator.SHL, shiftNode);
|
return mapBinaryOperation(JsBinaryOperator.SHL, shiftNode);
|
||||||
|
|
||||||
@@ -876,18 +861,13 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
throw createParserException("Unknown equality operator variant: "
|
throw createParserException("Unknown equality operator variant: "
|
||||||
+ shiftNode.getIntDatum(), shiftNode);
|
+ shiftNode.getOperation(), shiftNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsStatement mapStatement(Node nodeStmt) throws JsParserException {
|
private JsStatement mapStatement(Node nodeStmt) throws JsParserException {
|
||||||
JsNode unknown = map(nodeStmt);
|
JsNode unknown = map(nodeStmt);
|
||||||
|
|
||||||
if (unknown instanceof HasMetadata) {
|
|
||||||
HasMetadata metadataContainer = (HasMetadata) unknown;
|
|
||||||
metadataContainer.setData("line", nodeStmt.getLineno());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unknown != null) {
|
if (unknown != null) {
|
||||||
if (unknown instanceof JsStatement) {
|
if (unknown instanceof JsStatement) {
|
||||||
return (JsStatement) unknown;
|
return (JsStatement) unknown;
|
||||||
@@ -1050,7 +1030,7 @@ public class JsAstMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JsExpression mapUnaryVariant(Node unOp) throws JsParserException {
|
private JsExpression mapUnaryVariant(Node unOp) throws JsParserException {
|
||||||
switch (unOp.getIntDatum()) {
|
switch (unOp.getOperation()) {
|
||||||
case TokenStream.SUB:
|
case TokenStream.SUB:
|
||||||
return mapPrefixOperation(JsUnaryOperator.NEG, unOp);
|
return mapPrefixOperation(JsUnaryOperator.NEG, unOp);
|
||||||
|
|
||||||
@@ -1077,7 +1057,7 @@ public class JsAstMapper {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
throw createParserException(
|
throw createParserException(
|
||||||
"Unknown unary operator variant: " + unOp.getIntDatum(), unOp);
|
"Unknown unary operator variant: " + unOp.getOperation(), unOp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ package com.google.gwt.dev.js.rhino;
|
|||||||
* @see Node
|
* @see Node
|
||||||
*/
|
*/
|
||||||
public class IRFactory {
|
public class IRFactory {
|
||||||
|
|
||||||
public IRFactory(TokenStream ts) {
|
public IRFactory(TokenStream ts) {
|
||||||
this.ts = ts;
|
this.ts = ts;
|
||||||
}
|
}
|
||||||
@@ -49,77 +48,70 @@ public class IRFactory {
|
|||||||
/**
|
/**
|
||||||
* Script (for associating file/url names with toplevel scripts.)
|
* Script (for associating file/url names with toplevel scripts.)
|
||||||
*/
|
*/
|
||||||
public Object createScript(Object body, String sourceName,
|
public Node createScript(Node body)
|
||||||
int baseLineno, int endLineno, Object source)
|
|
||||||
{
|
{
|
||||||
Node result = new Node(TokenStream.SCRIPT);
|
Node result = new Node(TokenStream.SCRIPT);
|
||||||
Node children = ((Node) body).getFirstChild();
|
Node children = body.getFirstChild();
|
||||||
if (children != null)
|
if (children != null)
|
||||||
result.addChildrenToBack(children);
|
result.addChildrenToBack(children);
|
||||||
|
|
||||||
result.putProp(Node.SOURCENAME_PROP, sourceName);
|
|
||||||
result.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
|
|
||||||
result.putIntProp(Node.END_LINENO_PROP, endLineno);
|
|
||||||
if (source != null)
|
|
||||||
result.putProp(Node.SOURCE_PROP, source);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leaf
|
* Leaf
|
||||||
*/
|
*/
|
||||||
public Object createLeaf(int nodeType) {
|
public Node createLeaf(int nodeType, CodePosition location) {
|
||||||
return new Node(nodeType);
|
return new Node(nodeType, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createLeaf(int nodeType, int nodeOp) {
|
public Node createLeaf(int nodeType, int nodeOp, CodePosition location) {
|
||||||
return new Node(nodeType, nodeOp);
|
return new Node(nodeType, nodeOp, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLeafType(Object leaf) {
|
public int getLeafType(Node leaf) {
|
||||||
Node n = (Node) leaf;
|
return leaf.getType();
|
||||||
return n.getType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Statement leaf nodes.
|
* Statement leaf nodes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Object createSwitch(int lineno) {
|
public Node createSwitch(CodePosition location) {
|
||||||
return new Node(TokenStream.SWITCH, lineno);
|
return new Node(TokenStream.SWITCH, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createVariables(int lineno) {
|
public Node createVariables(CodePosition location) {
|
||||||
return new Node(TokenStream.VAR, lineno);
|
return new Node(TokenStream.VAR, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createExprStatement(Object expr, int lineno) {
|
public Node createExprStatement(Object expr, CodePosition location) {
|
||||||
return new Node(TokenStream.EXPRSTMT, (Node) expr, lineno);
|
return new Node(TokenStream.EXPRSTMT, (Node) expr, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name
|
* Name
|
||||||
*/
|
*/
|
||||||
public Object createName(String name) {
|
public Node createName(String name, CodePosition location) {
|
||||||
return Node.newString(TokenStream.NAME, name);
|
return Node.newString(TokenStream.NAME, name, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String (for literals)
|
* String (for literals)
|
||||||
*/
|
*/
|
||||||
public Object createString(String string) {
|
public Node createString(String string, CodePosition location) {
|
||||||
return Node.newString(string);
|
return Node.newString(string, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number (for literals)
|
* Number (for literals)
|
||||||
*/
|
*/
|
||||||
public Object createNumber(int number) {
|
public Node createNumber(int number, CodePosition location) {
|
||||||
return Node.newNumber(number);
|
return Node.newNumber(number, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createNumber(double number) {
|
public Node createNumber(double number, CodePosition location) {
|
||||||
return Node.newNumber(number);
|
return Node.newNumber(number, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,52 +122,47 @@ public class IRFactory {
|
|||||||
* @param stmts the statements in the catch clause
|
* @param stmts the statements in the catch clause
|
||||||
* @param lineno the starting line number of the catch clause
|
* @param lineno the starting line number of the catch clause
|
||||||
*/
|
*/
|
||||||
public Object createCatch(String varName, Object catchCond, Object stmts,
|
public Node createCatch(Node varName, Node catchCond, Node stmts, CodePosition location) {
|
||||||
int lineno)
|
|
||||||
{
|
|
||||||
if (catchCond == null) {
|
if (catchCond == null) {
|
||||||
catchCond = new Node(TokenStream.PRIMARY, TokenStream.TRUE);
|
catchCond = new Node(TokenStream.PRIMARY, TokenStream.TRUE, location);
|
||||||
}
|
}
|
||||||
return new Node(TokenStream.CATCH, (Node)createName(varName),
|
return new Node(TokenStream.CATCH, varName, catchCond, stmts, location);
|
||||||
(Node)catchCond, (Node)stmts, lineno);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw
|
* Throw
|
||||||
*/
|
*/
|
||||||
public Object createThrow(Object expr, int lineno) {
|
public Node createThrow(Node expr, CodePosition location) {
|
||||||
return new Node(TokenStream.THROW, (Node)expr, lineno);
|
return new Node(TokenStream.THROW, expr, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return
|
* Return
|
||||||
*/
|
*/
|
||||||
public Object createReturn(Object expr, int lineno) {
|
public Node createReturn(Node expr, CodePosition location) {
|
||||||
return expr == null
|
return expr == null
|
||||||
? new Node(TokenStream.RETURN, lineno)
|
? new Node(TokenStream.RETURN, location)
|
||||||
: new Node(TokenStream.RETURN, (Node)expr, lineno);
|
: new Node(TokenStream.RETURN, expr, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label
|
* Label
|
||||||
*/
|
*/
|
||||||
public Object createLabel(String label, int lineno) {
|
public Node createLabel(Node label, CodePosition location) {
|
||||||
Node result = new Node(TokenStream.LABEL, lineno);
|
Node result = new Node(TokenStream.LABEL, location);
|
||||||
Node name = Node.newString(TokenStream.NAME, label);
|
result.addChildToBack(label);
|
||||||
result.addChildToBack(name);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Break (possibly labeled)
|
* Break (possibly labeled)
|
||||||
*/
|
*/
|
||||||
public Object createBreak(String label, int lineno) {
|
public Node createBreak(Node label, CodePosition location) {
|
||||||
Node result = new Node(TokenStream.BREAK, lineno);
|
Node result = new Node(TokenStream.BREAK, location);
|
||||||
if (label == null) {
|
if (label == null) {
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
Node name = Node.newString(TokenStream.NAME, label);
|
result.addChildToBack(label);
|
||||||
result.addChildToBack(name);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,13 +170,12 @@ public class IRFactory {
|
|||||||
/**
|
/**
|
||||||
* Continue (possibly labeled)
|
* Continue (possibly labeled)
|
||||||
*/
|
*/
|
||||||
public Object createContinue(String label, int lineno) {
|
public Node createContinue(Node label, CodePosition location) {
|
||||||
Node result = new Node(TokenStream.CONTINUE, lineno);
|
Node result = new Node(TokenStream.CONTINUE, location);
|
||||||
if (label == null) {
|
if (label == null) {
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
Node name = Node.newString(TokenStream.NAME, label);
|
result.addChildToBack(label);
|
||||||
result.addChildToBack(name);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,8 +183,8 @@ public class IRFactory {
|
|||||||
/**
|
/**
|
||||||
* debugger
|
* debugger
|
||||||
*/
|
*/
|
||||||
public Object createDebugger(int lineno) {
|
public Node createDebugger(CodePosition location) {
|
||||||
Node result = new Node(TokenStream.DEBUGGER, lineno);
|
Node result = new Node(TokenStream.DEBUGGER, location);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,81 +193,54 @@ public class IRFactory {
|
|||||||
* Creates the empty statement block
|
* Creates the empty statement block
|
||||||
* Must make subsequent calls to add statements to the node
|
* Must make subsequent calls to add statements to the node
|
||||||
*/
|
*/
|
||||||
public Object createBlock(int lineno) {
|
public Node createBlock(CodePosition location) {
|
||||||
return new Node(TokenStream.BLOCK, lineno);
|
return new Node(TokenStream.BLOCK, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createFunction(String name, Object args, Object statements,
|
public Node createFunction(Node name, Node args, Node statements, CodePosition location) {
|
||||||
String sourceName, int baseLineno,
|
if (name == null) {
|
||||||
int endLineno, Object source,
|
name = createName("", location);
|
||||||
boolean isExpr)
|
}
|
||||||
{
|
return new Node(TokenStream.FUNCTION, name, args, statements, location);
|
||||||
Node f = new Node(TokenStream.FUNCTION,
|
|
||||||
Node.newString(TokenStream.NAME,
|
|
||||||
name == null ? "" : name),
|
|
||||||
(Node)args, (Node)statements, baseLineno);
|
|
||||||
|
|
||||||
f.putProp(Node.SOURCENAME_PROP, sourceName);
|
|
||||||
f.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
|
|
||||||
f.putIntProp(Node.END_LINENO_PROP, endLineno);
|
|
||||||
if (source != null)
|
|
||||||
f.putProp(Node.SOURCE_PROP, source);
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a child to the back of the given node. This function
|
|
||||||
* breaks the Factory abstraction, but it removes a requirement
|
|
||||||
* from implementors of Node.
|
|
||||||
*/
|
|
||||||
public void addChildToBack(Object parent, Object child) {
|
|
||||||
((Node)parent).addChildToBack((Node)child);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* While
|
* While
|
||||||
*/
|
*/
|
||||||
public Object createWhile(Object cond, Object body, int lineno) {
|
public Node createWhile(Node cond, Node body, CodePosition location) {
|
||||||
return new Node(TokenStream.WHILE, (Node)cond, (Node)body, lineno);
|
return new Node(TokenStream.WHILE, cond, body, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DoWhile
|
* DoWhile
|
||||||
*/
|
*/
|
||||||
public Object createDoWhile(Object body, Object cond, int lineno) {
|
public Node createDoWhile(Node body, Node cond, CodePosition location) {
|
||||||
return new Node(TokenStream.DO, (Node)body, (Node)cond, lineno);
|
return new Node(TokenStream.DO, body, cond, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For
|
* For
|
||||||
*/
|
*/
|
||||||
public Object createFor(Object init, Object test, Object incr,
|
public Node createFor(Node init, Node test, Node incr, Node body, CodePosition location) {
|
||||||
Object body, int lineno)
|
return new Node(TokenStream.FOR, init, test, incr, body, location);
|
||||||
{
|
|
||||||
return new Node(TokenStream.FOR, (Node)init, (Node)test, (Node)incr,
|
|
||||||
(Node)body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For .. In
|
* For .. In
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public Object createForIn(Object lhs, Object obj, Object body, int lineno) {
|
public Node createForIn(Node lhs, Node obj, Node body, CodePosition location) {
|
||||||
return new Node(TokenStream.FOR, (Node)lhs, (Node)obj, (Node)body);
|
return new Node(TokenStream.FOR, lhs, obj, body, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try/Catch/Finally
|
* Try/Catch/Finally
|
||||||
*/
|
*/
|
||||||
public Object createTryCatchFinally(Object tryblock, Object catchblocks,
|
public Node createTryCatchFinally(Node tryblock, Node catchblocks, Node finallyblock, CodePosition location) {
|
||||||
Object finallyblock, int lineno)
|
|
||||||
{
|
|
||||||
if (finallyblock == null) {
|
if (finallyblock == null) {
|
||||||
return new Node(TokenStream.TRY, (Node)tryblock, (Node)catchblocks);
|
return new Node(TokenStream.TRY, tryblock, catchblocks, location);
|
||||||
}
|
}
|
||||||
return new Node(TokenStream.TRY, (Node)tryblock,
|
return new Node(TokenStream.TRY, tryblock, catchblocks, finallyblock, location);
|
||||||
(Node)catchblocks, (Node)finallyblock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -291,81 +250,70 @@ public class IRFactory {
|
|||||||
/**
|
/**
|
||||||
* With
|
* With
|
||||||
*/
|
*/
|
||||||
public Object createWith(Object obj, Object body, int lineno) {
|
public Node createWith(Node obj, Node body, CodePosition location) {
|
||||||
return new Node(TokenStream.WITH, (Node)obj, (Node)body, lineno);
|
return new Node(TokenStream.WITH, obj, body, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array Literal
|
* Array Literal
|
||||||
*/
|
*/
|
||||||
public Object createArrayLiteral(Object obj) {
|
public Node createArrayLiteral(Node obj) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object Literals
|
* Object Literals
|
||||||
*/
|
*/
|
||||||
public Object createObjectLiteral(Object obj) {
|
public Node createObjectLiteral(Node obj) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regular expressions
|
* Regular expressions
|
||||||
*/
|
*/
|
||||||
public Object createRegExp(String string, String flags) {
|
public Node createRegExp(String string, String flags, CodePosition location) {
|
||||||
return flags.length() == 0
|
return flags.length() == 0
|
||||||
? new Node(TokenStream.REGEXP,
|
? new Node(TokenStream.REGEXP,
|
||||||
Node.newString(string))
|
Node.newString(string, location), location)
|
||||||
: new Node(TokenStream.REGEXP,
|
: new Node(TokenStream.REGEXP,
|
||||||
Node.newString(string),
|
Node.newString(string, location),
|
||||||
Node.newString(flags));
|
Node.newString(flags, location),
|
||||||
|
location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If statement
|
* If statement
|
||||||
*/
|
*/
|
||||||
public Object createIf(Object cond, Object ifTrue, Object ifFalse,
|
public Node createIf(Node cond, Node ifTrue, Node ifFalse, CodePosition location) {
|
||||||
int lineno)
|
|
||||||
{
|
|
||||||
if (ifFalse == null)
|
if (ifFalse == null)
|
||||||
return new Node(TokenStream.IF, (Node)cond, (Node)ifTrue, lineno);
|
return new Node(TokenStream.IF, cond, ifTrue, location);
|
||||||
return new Node(TokenStream.IF, (Node)cond, (Node)ifTrue, (Node)ifFalse, lineno);
|
return new Node(TokenStream.IF, cond, ifTrue, ifFalse, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createTernary(Object cond, Object ifTrue, Object ifFalse) {
|
public Node createTernary(Node cond, Node ifTrue, Node ifFalse, CodePosition location) {
|
||||||
return new Node(TokenStream.HOOK,
|
return new Node(TokenStream.HOOK, cond, ifTrue, ifFalse, location);
|
||||||
(Node)cond, (Node)ifTrue, (Node)ifFalse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unary
|
* Unary
|
||||||
*/
|
*/
|
||||||
public Object createUnary(int nodeType, Object child) {
|
public Node createUnary(int nodeType, Node child, CodePosition location) {
|
||||||
Node childNode = (Node) child;
|
return new Node(nodeType, child, location);
|
||||||
return new Node(nodeType, childNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createUnary(int nodeType, int nodeOp, Object child) {
|
public Node createUnary(int nodeType, int nodeOp, Node child, CodePosition location) {
|
||||||
return new Node(nodeType, (Node)child, nodeOp);
|
return new Node(nodeType, child, nodeOp, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binary
|
* Binary
|
||||||
*/
|
*/
|
||||||
public Object createBinary(int nodeType, Object left, Object right) {
|
public Node createBinary(int nodeType, Node left, Node right, CodePosition location) {
|
||||||
Node temp;
|
|
||||||
switch (nodeType) {
|
switch (nodeType) {
|
||||||
|
|
||||||
case TokenStream.DOT:
|
case TokenStream.DOT:
|
||||||
nodeType = TokenStream.GETPROP;
|
nodeType = TokenStream.GETPROP;
|
||||||
Node idNode = (Node) right;
|
right.setType(TokenStream.STRING);
|
||||||
idNode.setType(TokenStream.STRING);
|
|
||||||
String id = idNode.getString();
|
|
||||||
if (id.equals("__proto__") || id.equals("__parent__")) {
|
|
||||||
Node result = new Node(nodeType, (Node) left);
|
|
||||||
result.putProp(Node.SPECIAL_PROP_PROP, id);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokenStream.LB:
|
case TokenStream.LB:
|
||||||
@@ -373,22 +321,17 @@ public class IRFactory {
|
|||||||
nodeType = TokenStream.GETELEM;
|
nodeType = TokenStream.GETELEM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return new Node(nodeType, (Node)left, (Node)right);
|
return new Node(nodeType, left, right, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createBinary(int nodeType, int nodeOp, Object left,
|
public Node createBinary(int nodeType, int nodeOp, Node left, Node right, CodePosition location) {
|
||||||
Object right)
|
|
||||||
{
|
|
||||||
if (nodeType == TokenStream.ASSIGN) {
|
if (nodeType == TokenStream.ASSIGN) {
|
||||||
return createAssignment(nodeOp, (Node) left, (Node) right,
|
return createAssignment(nodeOp, left, right, location);
|
||||||
null, false);
|
|
||||||
}
|
}
|
||||||
return new Node(nodeType, (Node) left, (Node) right, nodeOp);
|
return new Node(nodeType, left, right, nodeOp, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object createAssignment(int nodeOp, Node left, Node right,
|
public Node createAssignment(int nodeOp, Node left, Node right, CodePosition location) {
|
||||||
Class convert, boolean postfix)
|
|
||||||
{
|
|
||||||
int nodeType = left.getType();
|
int nodeType = left.getType();
|
||||||
switch (nodeType) {
|
switch (nodeType) {
|
||||||
case TokenStream.NAME:
|
case TokenStream.NAME:
|
||||||
@@ -401,7 +344,7 @@ public class IRFactory {
|
|||||||
reportError("msg.bad.lhs.assign");
|
reportError("msg.bad.lhs.assign");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Node(TokenStream.ASSIGN, left, right, nodeOp);
|
return new Node(TokenStream.ASSIGN, left, right, nodeOp, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reportError(String msgResource) {
|
private void reportError(String msgResource) {
|
||||||
|
|||||||
@@ -46,13 +46,13 @@ public class Node implements Cloneable {
|
|||||||
|
|
||||||
private static class NumberNode extends Node {
|
private static class NumberNode extends Node {
|
||||||
|
|
||||||
NumberNode(int number) {
|
NumberNode(int number, CodePosition location) {
|
||||||
super(TokenStream.NUMBER_INT);
|
super(TokenStream.NUMBER_INT, location);
|
||||||
this.number = number;
|
this.number = number;
|
||||||
}
|
}
|
||||||
|
|
||||||
NumberNode(double number) {
|
NumberNode(double number, CodePosition position) {
|
||||||
super(TokenStream.NUMBER);
|
super(TokenStream.NUMBER, position);
|
||||||
this.number = number;
|
this.number = number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,19 +61,13 @@ public class Node implements Cloneable {
|
|||||||
return this.number;
|
return this.number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return o instanceof NumberNode
|
|
||||||
&& getDouble() == ((NumberNode) o).getDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
private double number;
|
private double number;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class StringNode extends Node {
|
private static class StringNode extends Node {
|
||||||
|
|
||||||
StringNode(int type, String str) {
|
StringNode(int type, String str, CodePosition position) {
|
||||||
super(type);
|
super(type, position);
|
||||||
if (null == str) {
|
if (null == str) {
|
||||||
throw new IllegalArgumentException("StringNode: str is null");
|
throw new IllegalArgumentException("StringNode: str is null");
|
||||||
}
|
}
|
||||||
@@ -99,13 +93,6 @@ public class Node implements Cloneable {
|
|||||||
this.str = str;
|
this.str = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof StringNode)) { return false; }
|
|
||||||
return o instanceof StringNode
|
|
||||||
&& this.str.equals(((StringNode) o).str);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String str;
|
private String str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,30 +100,46 @@ public class Node implements Cloneable {
|
|||||||
type = nodeType;
|
type = nodeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, Node child) {
|
public Node(int nodeType, Node child, CodePosition position) {
|
||||||
type = nodeType;
|
type = nodeType;
|
||||||
first = last = child;
|
first = last = child;
|
||||||
child.next = null;
|
child.next = null;
|
||||||
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, Node left, Node right) {
|
public Node(int nodeType, Node child, int operation, CodePosition position) {
|
||||||
|
type = nodeType;
|
||||||
|
first = last = child;
|
||||||
|
child.next = null;
|
||||||
|
this.operation = operation;
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node(int nodeType, Node left, Node right, CodePosition position) {
|
||||||
|
this(nodeType, left, right, -1, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node(int nodeType, Node left, Node right, int operation, CodePosition position) {
|
||||||
type = nodeType;
|
type = nodeType;
|
||||||
first = left;
|
first = left;
|
||||||
last = right;
|
last = right;
|
||||||
left.next = right;
|
left.next = right;
|
||||||
right.next = null;
|
right.next = null;
|
||||||
|
this.operation = operation;
|
||||||
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, Node left, Node mid, Node right) {
|
public Node(int nodeType, Node left, Node mid, Node right, CodePosition position) {
|
||||||
type = nodeType;
|
type = nodeType;
|
||||||
first = left;
|
first = left;
|
||||||
last = right;
|
last = right;
|
||||||
left.next = mid;
|
left.next = mid;
|
||||||
mid.next = right;
|
mid.next = right;
|
||||||
right.next = null;
|
right.next = null;
|
||||||
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, Node left, Node mid, Node mid2, Node right) {
|
public Node(int nodeType, Node left, Node mid, Node mid2, Node right, CodePosition position) {
|
||||||
type = nodeType;
|
type = nodeType;
|
||||||
first = left;
|
first = left;
|
||||||
last = right;
|
last = right;
|
||||||
@@ -144,6 +147,7 @@ public class Node implements Cloneable {
|
|||||||
mid.next = mid2;
|
mid.next = mid2;
|
||||||
mid2.next = right;
|
mid2.next = right;
|
||||||
right.next = null;
|
right.next = null;
|
||||||
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, Node[] children) {
|
public Node(int nodeType, Node[] children) {
|
||||||
@@ -166,40 +170,31 @@ public class Node implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, int value) {
|
public Node(int nodeType, CodePosition position) {
|
||||||
type = nodeType;
|
type = nodeType;
|
||||||
intDatum = value;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, Node child, int value) {
|
public Node(int nodeType, int operation, CodePosition position) {
|
||||||
this(nodeType, child);
|
type = nodeType;
|
||||||
intDatum = value;
|
this.operation = operation;
|
||||||
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, Node left, Node right, int value) {
|
public static Node newNumber(int number, CodePosition position) {
|
||||||
this(nodeType, left, right);
|
return new NumberNode(number, position);
|
||||||
intDatum = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node(int nodeType, Node left, Node mid, Node right, int value) {
|
public static Node newNumber(double number, CodePosition position) {
|
||||||
this(nodeType, left, mid, right);
|
return new NumberNode(number, position);
|
||||||
intDatum = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Node newNumber(int number) {
|
public static Node newString(String str, CodePosition position) {
|
||||||
return new NumberNode(number);
|
return new StringNode(TokenStream.STRING, str, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Node newNumber(double number) {
|
public static Node newString(int type, String str, CodePosition position) {
|
||||||
return new NumberNode(number);
|
return new StringNode(type, str, position);
|
||||||
}
|
|
||||||
|
|
||||||
public static Node newString(String str) {
|
|
||||||
return new StringNode(TokenStream.STRING, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Node newString(int type, String str) {
|
|
||||||
return new StringNode(type, str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
@@ -210,10 +205,6 @@ public class Node implements Cloneable {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIntDatum() {
|
|
||||||
return this.intDatum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node getFirstChild() {
|
public Node getFirstChild() {
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
@@ -353,73 +344,12 @@ public class Node implements Cloneable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getProp(int propType) {
|
|
||||||
if (props == null)
|
|
||||||
return null;
|
|
||||||
return props.getObject(propType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putProp(int propType, Object prop) {
|
|
||||||
if (prop == null) {
|
|
||||||
removeProp(propType);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (props == null) {
|
|
||||||
props = new UintMap(2);
|
|
||||||
}
|
|
||||||
props.put(propType, prop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putIntProp(int propType, int prop) {
|
|
||||||
if (props == null)
|
|
||||||
props = new UintMap(2);
|
|
||||||
props.put(propType, prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeProp(int propType) {
|
|
||||||
if (props != null) {
|
|
||||||
props.remove(propType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOperation() {
|
public int getOperation() {
|
||||||
switch (type) {
|
return operation;
|
||||||
case TokenStream.EQOP:
|
|
||||||
case TokenStream.RELOP:
|
|
||||||
case TokenStream.UNARYOP:
|
|
||||||
case TokenStream.PRIMARY:
|
|
||||||
return intDatum;
|
|
||||||
}
|
|
||||||
Context.codeBug();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLineno() {
|
public CodePosition getPosition() {
|
||||||
if (hasLineno()) {
|
return position;
|
||||||
return intDatum;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasLineno() {
|
|
||||||
switch (type) {
|
|
||||||
case TokenStream.EXPRSTMT:
|
|
||||||
case TokenStream.BLOCK:
|
|
||||||
case TokenStream.VAR:
|
|
||||||
case TokenStream.WHILE:
|
|
||||||
case TokenStream.DO:
|
|
||||||
case TokenStream.SWITCH:
|
|
||||||
case TokenStream.CATCH:
|
|
||||||
case TokenStream.THROW:
|
|
||||||
case TokenStream.RETURN:
|
|
||||||
case TokenStream.BREAK:
|
|
||||||
case TokenStream.CONTINUE:
|
|
||||||
case TokenStream.WITH:
|
|
||||||
case TokenStream.IF:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
|
/** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
|
||||||
@@ -437,22 +367,6 @@ public class Node implements Cloneable {
|
|||||||
throw new UnsupportedOperationException(this + " is not a string node");
|
throw new UnsupportedOperationException(this + " is not a string node");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Not usefully implemented.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final int hashCode() {
|
|
||||||
assert false : "hashCode not designed";
|
|
||||||
return 42; // any arbitrary constant will do
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof Node)) { return false; }
|
|
||||||
return hasLineno()
|
|
||||||
|| this.getIntDatum() == ((Node) o).getIntDatum();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (Context.printTrees) {
|
if (Context.printTrees) {
|
||||||
@@ -480,57 +394,19 @@ public class Node implements Cloneable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (intDatum != -1) {
|
if (operation != -1) {
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
sb.append(intDatum);
|
sb.append(operation);
|
||||||
}
|
|
||||||
if (props == null)
|
|
||||||
return sb.toString();
|
|
||||||
|
|
||||||
int[] keys = props.getKeys();
|
|
||||||
for (int i = 0; i != keys.length; ++i) {
|
|
||||||
int key = keys[i];
|
|
||||||
sb.append(" [");
|
|
||||||
sb.append(propToString(key));
|
|
||||||
sb.append(": ");
|
|
||||||
switch (key) {
|
|
||||||
case FIXUPS_PROP : // can't add this as it recurses
|
|
||||||
sb.append("fixups property");
|
|
||||||
break;
|
|
||||||
case SOURCE_PROP : // can't add this as it has unprintables
|
|
||||||
sb.append("source property");
|
|
||||||
break;
|
|
||||||
case TARGETBLOCK_PROP : // can't add this as it recurses
|
|
||||||
sb.append("target block property");
|
|
||||||
break;
|
|
||||||
case LASTUSE_PROP : // can't add this as it is dull
|
|
||||||
sb.append("last use property");
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
Object obj = props.getObject(key);
|
|
||||||
if (obj != null) {
|
|
||||||
sb.append(obj.toString());
|
|
||||||
} else {
|
|
||||||
sb.append(props.getExistingInt(key));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sb.append(']');
|
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIsSyntheticBlock(boolean val) {
|
|
||||||
isSyntheticBlock = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
int type; // type of the node; TokenStream.NAME for example
|
int type; // type of the node; TokenStream.NAME for example
|
||||||
Node next; // next sibling
|
Node next; // next sibling
|
||||||
private Node first; // first element of a linked list of children
|
private Node first; // first element of a linked list of children
|
||||||
private Node last; // last element of a linked list of children
|
private Node last; // last element of a linked list of children
|
||||||
private int intDatum = -1; // encapsulated int data; depends on type
|
private CodePosition position;
|
||||||
private UintMap props;
|
private int operation;
|
||||||
private boolean isSyntheticBlock = false;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,19 +86,17 @@ public class Parser extends Observable {
|
|||||||
* will be returned. (The parse failure will result in a call to the current
|
* will be returned. (The parse failure will result in a call to the current
|
||||||
* Context's ErrorReporter.)
|
* Context's ErrorReporter.)
|
||||||
*/
|
*/
|
||||||
public Object parse(TokenStream ts) throws IOException {
|
public Node parse(TokenStream ts) throws IOException {
|
||||||
this.ok = true;
|
this.ok = true;
|
||||||
sourceTop = 0;
|
sourceTop = 0;
|
||||||
functionNumber = 0;
|
functionNumber = 0;
|
||||||
|
|
||||||
int tt; // last token from getToken();
|
int tt; // last token from getToken();
|
||||||
int baseLineno = ts.getLineno(); // line number where source starts
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* so we have something to add nodes to until we've collected all the source
|
* so we have something to add nodes to until we've collected all the source
|
||||||
*/
|
*/
|
||||||
Object tempBlock = nf.createLeaf(TokenStream.BLOCK);
|
Node tempBlock = nf.createLeaf(TokenStream.BLOCK, ts.tokenPosition);
|
||||||
((Node) tempBlock).setIsSyntheticBlock(true);
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ts.flags |= TokenStream.TSF_REGEXP;
|
ts.flags |= TokenStream.TSF_REGEXP;
|
||||||
@@ -111,7 +109,7 @@ public class Parser extends Observable {
|
|||||||
|
|
||||||
if (tt == TokenStream.FUNCTION) {
|
if (tt == TokenStream.FUNCTION) {
|
||||||
try {
|
try {
|
||||||
nf.addChildToBack(tempBlock, function(ts, false));
|
tempBlock.addChildToBack(function(ts, false));
|
||||||
}
|
}
|
||||||
catch (JavaScriptException e) {
|
catch (JavaScriptException e) {
|
||||||
this.ok = false;
|
this.ok = false;
|
||||||
@@ -120,7 +118,7 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ts.ungetToken(tt);
|
ts.ungetToken(tt);
|
||||||
nf.addChildToBack(tempBlock, statement(ts));
|
tempBlock.addChildToBack(statement(ts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,9 +127,7 @@ public class Parser extends Observable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object pn = nf.createScript(tempBlock, ts.getSourceName(), baseLineno, ts.getLineno(), null);
|
return nf.createScript(tempBlock);
|
||||||
((Node) pn).setIsSyntheticBlock(true);
|
|
||||||
return pn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -139,21 +135,21 @@ public class Parser extends Observable {
|
|||||||
* to be needed for tree generation... it'd only be useful for checking
|
* to be needed for tree generation... it'd only be useful for checking
|
||||||
* argument hiding, which I'm not doing anyway...
|
* argument hiding, which I'm not doing anyway...
|
||||||
*/
|
*/
|
||||||
private Object parseFunctionBody(TokenStream ts) throws IOException {
|
private Node parseFunctionBody(TokenStream ts) throws IOException {
|
||||||
int oldflags = ts.flags;
|
int oldflags = ts.flags;
|
||||||
ts.flags &= ~(TokenStream.TSF_RETURN_EXPR | TokenStream.TSF_RETURN_VOID);
|
ts.flags &= ~(TokenStream.TSF_RETURN_EXPR | TokenStream.TSF_RETURN_VOID);
|
||||||
ts.flags |= TokenStream.TSF_FUNCTION;
|
ts.flags |= TokenStream.TSF_FUNCTION;
|
||||||
|
|
||||||
Object pn = nf.createBlock(ts.getLineno());
|
Node pn = nf.createBlock(ts.tokenPosition);
|
||||||
try {
|
try {
|
||||||
int tt;
|
int tt;
|
||||||
while ((tt = ts.peekToken()) > TokenStream.EOF && tt != TokenStream.RC) {
|
while ((tt = ts.peekToken()) > TokenStream.EOF && tt != TokenStream.RC) {
|
||||||
if (tt == TokenStream.FUNCTION) {
|
if (tt == TokenStream.FUNCTION) {
|
||||||
ts.getToken();
|
ts.getToken();
|
||||||
nf.addChildToBack(pn, function(ts, false));
|
pn.addChildToBack(function(ts, false));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nf.addChildToBack(pn, statement(ts));
|
pn.addChildToBack(statement(ts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,31 +166,30 @@ public class Parser extends Observable {
|
|||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object function(TokenStream ts, boolean isExpr) throws IOException, JavaScriptException {
|
private Node function(TokenStream ts, boolean isExpr) throws IOException, JavaScriptException {
|
||||||
notifyObservers(new ParserEvents.OnFunctionParsingStart());
|
notifyObservers(new ParserEvents.OnFunctionParsingStart());
|
||||||
int baseLineno = ts.getLineno(); // line number where source starts
|
CodePosition basePosition = ts.tokenPosition;
|
||||||
|
|
||||||
String name;
|
Node nameNode;
|
||||||
Object memberExprNode = null;
|
Node memberExprNode = null;
|
||||||
if (ts.matchToken(TokenStream.NAME)) {
|
if (ts.matchToken(TokenStream.NAME)) {
|
||||||
name = ts.getString();
|
nameNode = nf.createName(ts.getString(), basePosition);
|
||||||
if (!ts.matchToken(TokenStream.LP)) {
|
if (!ts.matchToken(TokenStream.LP)) {
|
||||||
if (Context.getContext().hasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)) {
|
if (Context.getContext().hasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)) {
|
||||||
// Extension to ECMA: if 'function <name>' does not follow
|
// Extension to ECMA: if 'function <name>' does not follow
|
||||||
// by '(', assume <name> starts memberExpr
|
// by '(', assume <name> starts memberExpr
|
||||||
Object memberExprHead = nf.createName(name);
|
Node memberExprHead = nameNode;
|
||||||
name = null;
|
nameNode = null;
|
||||||
memberExprNode = memberExprTail(ts, false, memberExprHead);
|
memberExprNode = memberExprTail(ts, false, memberExprHead, basePosition);
|
||||||
}
|
}
|
||||||
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.parms");
|
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.parms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ts.matchToken(TokenStream.LP)) {
|
else if (ts.matchToken(TokenStream.LP)) {
|
||||||
// Anonymous function
|
// Anonymous function
|
||||||
name = null;
|
nameNode = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
name = null;
|
|
||||||
if (Context.getContext().hasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)) {
|
if (Context.getContext().hasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)) {
|
||||||
// Note that memberExpr can not start with '(' like
|
// Note that memberExpr can not start with '(' like
|
||||||
// in (1+2).toString, because 'function (' already
|
// in (1+2).toString, because 'function (' already
|
||||||
@@ -202,6 +197,7 @@ public class Parser extends Observable {
|
|||||||
memberExprNode = memberExpr(ts, false);
|
memberExprNode = memberExpr(ts, false);
|
||||||
}
|
}
|
||||||
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.parms");
|
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.parms");
|
||||||
|
nameNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
++functionNumber;
|
++functionNumber;
|
||||||
@@ -210,17 +206,18 @@ public class Parser extends Observable {
|
|||||||
// function to parent source
|
// function to parent source
|
||||||
int savedSourceTop = sourceTop;
|
int savedSourceTop = sourceTop;
|
||||||
int savedFunctionNumber = functionNumber;
|
int savedFunctionNumber = functionNumber;
|
||||||
Object args;
|
Node args;
|
||||||
Object body;
|
Node body;
|
||||||
try {
|
try {
|
||||||
functionNumber = 0;
|
functionNumber = 0;
|
||||||
args = nf.createLeaf(TokenStream.LP);
|
args = nf.createLeaf(TokenStream.LP, ts.tokenPosition);
|
||||||
|
|
||||||
if (!ts.matchToken(TokenStream.GWT)) {
|
if (!ts.matchToken(TokenStream.GWT)) {
|
||||||
do {
|
do {
|
||||||
|
CodePosition namePosition = ts.tokenPosition;
|
||||||
mustMatchToken(ts, TokenStream.NAME, "msg.no.parm");
|
mustMatchToken(ts, TokenStream.NAME, "msg.no.parm");
|
||||||
String s = ts.getString();
|
String s = ts.getString();
|
||||||
nf.addChildToBack(args, nf.createName(s));
|
args.addChildToBack(nf.createName(s, namePosition));
|
||||||
}
|
}
|
||||||
while (ts.matchToken(TokenStream.COMMA));
|
while (ts.matchToken(TokenStream.COMMA));
|
||||||
|
|
||||||
@@ -237,10 +234,9 @@ public class Parser extends Observable {
|
|||||||
functionNumber = savedFunctionNumber;
|
functionNumber = savedFunctionNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object pn = nf.createFunction(name, args, body, ts.getSourceName(),
|
Node pn = nf.createFunction(nameNode, args, body, basePosition);
|
||||||
baseLineno, ts.getLineno(), null, isExpr || memberExprNode != null);
|
|
||||||
if (memberExprNode != null) {
|
if (memberExprNode != null) {
|
||||||
pn = nf.createBinary(TokenStream.ASSIGN, TokenStream.NOP, memberExprNode, pn);
|
pn = nf.createBinary(TokenStream.ASSIGN, TokenStream.NOP, memberExprNode, pn, basePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add EOL but only if function is not part of expression, in which
|
// Add EOL but only if function is not part of expression, in which
|
||||||
@@ -253,19 +249,19 @@ public class Parser extends Observable {
|
|||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object statements(TokenStream ts) throws IOException {
|
private Node statements(TokenStream ts) throws IOException {
|
||||||
Object pn = nf.createBlock(ts.getLineno());
|
Node pn = nf.createBlock(ts.tokenPosition);
|
||||||
|
|
||||||
int tt;
|
int tt;
|
||||||
while ((tt = ts.peekToken()) > TokenStream.EOF && tt != TokenStream.RC) {
|
while ((tt = ts.peekToken()) > TokenStream.EOF && tt != TokenStream.RC) {
|
||||||
nf.addChildToBack(pn, statement(ts));
|
pn.addChildToBack(statement(ts));
|
||||||
}
|
}
|
||||||
|
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object condition(TokenStream ts) throws IOException, JavaScriptException {
|
private Node condition(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
Object pn;
|
Node pn;
|
||||||
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.cond");
|
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.cond");
|
||||||
pn = expr(ts, false);
|
pn = expr(ts, false);
|
||||||
mustMatchToken(ts, TokenStream.GWT, "msg.no.paren.after.cond");
|
mustMatchToken(ts, TokenStream.GWT, "msg.no.paren.after.cond");
|
||||||
@@ -297,7 +293,8 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// match a NAME; return null if no match.
|
// match a NAME; return null if no match.
|
||||||
private String matchLabel(TokenStream ts) throws IOException, JavaScriptException {
|
private Node matchLabel(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
int lineno = ts.getLineno();
|
int lineno = ts.getLineno();
|
||||||
|
|
||||||
String label = null;
|
String label = null;
|
||||||
@@ -312,23 +309,23 @@ public class Parser extends Observable {
|
|||||||
wellTerminated(ts, TokenStream.ERROR);
|
wellTerminated(ts, TokenStream.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return label;
|
return label != null ? nf.createString(label, position) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object statement(TokenStream ts) throws IOException {
|
private Node statement(TokenStream ts) throws IOException {
|
||||||
|
CodePosition position = ts.lastPosition;
|
||||||
try {
|
try {
|
||||||
return statementHelper(ts);
|
return statementHelper(ts);
|
||||||
}
|
}
|
||||||
catch (JavaScriptException e) {
|
catch (JavaScriptException e) {
|
||||||
// skip to end of statement
|
// skip to end of statement
|
||||||
int lineno = ts.getLineno();
|
|
||||||
int t;
|
int t;
|
||||||
do {
|
do {
|
||||||
t = ts.getToken();
|
t = ts.getToken();
|
||||||
}
|
}
|
||||||
while (t != TokenStream.SEMI && t != TokenStream.EOL
|
while (t != TokenStream.SEMI && t != TokenStream.EOL
|
||||||
&& t != TokenStream.EOF && t != TokenStream.ERROR);
|
&& t != TokenStream.EOF && t != TokenStream.ERROR);
|
||||||
return nf.createExprStatement(nf.createName("error"), lineno);
|
return nf.createExprStatement(nf.createName("error", position), position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,47 +334,47 @@ public class Parser extends Observable {
|
|||||||
* implemented.
|
* implemented.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private Object statementHelper(TokenStream ts) throws IOException, JavaScriptException {
|
private Node statementHelper(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
Object pn;
|
Node pn;
|
||||||
|
|
||||||
int tt;
|
int tt;
|
||||||
|
|
||||||
int lastExprType; // For wellTerminated
|
int lastExprType; // For wellTerminated
|
||||||
|
|
||||||
tt = ts.getToken();
|
tt = ts.getToken();
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
|
|
||||||
switch (tt) {
|
switch (tt) {
|
||||||
case TokenStream.IF: {
|
case TokenStream.IF: {
|
||||||
int lineno = ts.getLineno();
|
Node cond = condition(ts);
|
||||||
Object cond = condition(ts);
|
Node ifTrue = statement(ts);
|
||||||
Object ifTrue = statement(ts);
|
Node ifFalse = null;
|
||||||
Object ifFalse = null;
|
|
||||||
if (ts.matchToken(TokenStream.ELSE)) {
|
if (ts.matchToken(TokenStream.ELSE)) {
|
||||||
ifFalse = statement(ts);
|
ifFalse = statement(ts);
|
||||||
}
|
}
|
||||||
pn = nf.createIf(cond, ifTrue, ifFalse, lineno);
|
pn = nf.createIf(cond, ifTrue, ifFalse, position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TokenStream.SWITCH: {
|
case TokenStream.SWITCH: {
|
||||||
pn = nf.createSwitch(ts.getLineno());
|
pn = nf.createSwitch(position);
|
||||||
|
|
||||||
Object cur_case = null; // to kill warning
|
Node curCase = null; // to kill warning
|
||||||
Object case_statements;
|
Node caseStatements;
|
||||||
|
|
||||||
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.switch");
|
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.switch");
|
||||||
nf.addChildToBack(pn, expr(ts, false));
|
pn.addChildToBack(expr(ts, false));
|
||||||
mustMatchToken(ts, TokenStream.GWT, "msg.no.paren.after.switch");
|
mustMatchToken(ts, TokenStream.GWT, "msg.no.paren.after.switch");
|
||||||
mustMatchToken(ts, TokenStream.LC, "msg.no.brace.switch");
|
mustMatchToken(ts, TokenStream.LC, "msg.no.brace.switch");
|
||||||
|
|
||||||
while ((tt = ts.getToken()) != TokenStream.RC && tt != TokenStream.EOF) {
|
while ((tt = ts.getToken()) != TokenStream.RC && tt != TokenStream.EOF) {
|
||||||
switch (tt) {
|
switch (tt) {
|
||||||
case TokenStream.CASE:
|
case TokenStream.CASE:
|
||||||
cur_case = nf.createUnary(TokenStream.CASE, expr(ts, false));
|
curCase = nf.createUnary(TokenStream.CASE, expr(ts, false), ts.tokenPosition);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokenStream.DEFAULT:
|
case TokenStream.DEFAULT:
|
||||||
cur_case = nf.createLeaf(TokenStream.DEFAULT);
|
curCase = nf.createLeaf(TokenStream.DEFAULT, ts.tokenPosition);
|
||||||
// XXX check that there isn't more than one default
|
// XXX check that there isn't more than one default
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -387,60 +384,56 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
mustMatchToken(ts, TokenStream.COLON, "msg.no.colon.case");
|
mustMatchToken(ts, TokenStream.COLON, "msg.no.colon.case");
|
||||||
|
|
||||||
case_statements = nf.createLeaf(TokenStream.BLOCK);
|
caseStatements = nf.createLeaf(TokenStream.BLOCK, null);
|
||||||
((Node) case_statements).setIsSyntheticBlock(true);
|
|
||||||
|
|
||||||
while ((tt = ts.peekToken()) != TokenStream.RC && tt != TokenStream.CASE
|
while ((tt = ts.peekToken()) != TokenStream.RC && tt != TokenStream.CASE
|
||||||
&& tt != TokenStream.DEFAULT && tt != TokenStream.EOF) {
|
&& tt != TokenStream.DEFAULT && tt != TokenStream.EOF) {
|
||||||
nf.addChildToBack(case_statements, statement(ts));
|
caseStatements.addChildToBack(statement(ts));
|
||||||
}
|
}
|
||||||
// assert cur_case
|
// assert cur_case
|
||||||
nf.addChildToBack(cur_case, case_statements);
|
if (curCase != null) {
|
||||||
|
curCase.addChildToBack(caseStatements);
|
||||||
|
}
|
||||||
|
|
||||||
nf.addChildToBack(pn, cur_case);
|
pn.addChildToBack(curCase);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TokenStream.WHILE: {
|
case TokenStream.WHILE: {
|
||||||
int lineno = ts.getLineno();
|
Node cond = condition(ts);
|
||||||
Object cond = condition(ts);
|
Node body = statement(ts);
|
||||||
Object body = statement(ts);
|
|
||||||
|
|
||||||
pn = nf.createWhile(cond, body, lineno);
|
pn = nf.createWhile(cond, body, position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TokenStream.DO: {
|
case TokenStream.DO: {
|
||||||
int lineno = ts.getLineno();
|
Node body = statement(ts);
|
||||||
|
|
||||||
Object body = statement(ts);
|
|
||||||
|
|
||||||
mustMatchToken(ts, TokenStream.WHILE, "msg.no.while.do");
|
mustMatchToken(ts, TokenStream.WHILE, "msg.no.while.do");
|
||||||
Object cond = condition(ts);
|
Node cond = condition(ts);
|
||||||
|
|
||||||
pn = nf.createDoWhile(body, cond, lineno);
|
pn = nf.createDoWhile(body, cond, position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TokenStream.FOR: {
|
case TokenStream.FOR: {
|
||||||
int lineno = ts.getLineno();
|
Node init; // Node init is also foo in 'foo in Object'
|
||||||
|
Node cond; // Node cond is also object in 'foo in Object'
|
||||||
Object init; // Node init is also foo in 'foo in Object'
|
Node incr = null; // to kill warning
|
||||||
Object cond; // Node cond is also object in 'foo in Object'
|
Node body;
|
||||||
Object incr = null; // to kill warning
|
|
||||||
Object body;
|
|
||||||
|
|
||||||
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.for");
|
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.for");
|
||||||
tt = ts.peekToken();
|
tt = ts.peekToken();
|
||||||
if (tt == TokenStream.SEMI) {
|
if (tt == TokenStream.SEMI) {
|
||||||
init = nf.createLeaf(TokenStream.VOID);
|
init = nf.createLeaf(TokenStream.VOID, null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (tt == TokenStream.VAR) {
|
if (tt == TokenStream.VAR) {
|
||||||
// set init to a var list or initial
|
// set init to a var list or initial
|
||||||
ts.getToken(); // throw away the 'var' token
|
ts.getToken(); // throw away the 'var' token
|
||||||
init = variables(ts, true);
|
init = variables(ts, true, ts.tokenPosition);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
init = expr(ts, true);
|
init = expr(ts, true);
|
||||||
@@ -457,7 +450,7 @@ public class Parser extends Observable {
|
|||||||
mustMatchToken(ts, TokenStream.SEMI, "msg.no.semi.for");
|
mustMatchToken(ts, TokenStream.SEMI, "msg.no.semi.for");
|
||||||
if (ts.peekToken() == TokenStream.SEMI) {
|
if (ts.peekToken() == TokenStream.SEMI) {
|
||||||
// no loop condition
|
// no loop condition
|
||||||
cond = nf.createLeaf(TokenStream.VOID);
|
cond = nf.createLeaf(TokenStream.VOID, null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cond = expr(ts, false);
|
cond = expr(ts, false);
|
||||||
@@ -465,7 +458,7 @@ public class Parser extends Observable {
|
|||||||
|
|
||||||
mustMatchToken(ts, TokenStream.SEMI, "msg.no.semi.for.cond");
|
mustMatchToken(ts, TokenStream.SEMI, "msg.no.semi.for.cond");
|
||||||
if (ts.peekToken() == TokenStream.GWT) {
|
if (ts.peekToken() == TokenStream.GWT) {
|
||||||
incr = nf.createLeaf(TokenStream.VOID);
|
incr = nf.createLeaf(TokenStream.VOID, null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
incr = expr(ts, false);
|
incr = expr(ts, false);
|
||||||
@@ -477,24 +470,22 @@ public class Parser extends Observable {
|
|||||||
|
|
||||||
if (incr == null) {
|
if (incr == null) {
|
||||||
// cond could be null if 'in obj' got eaten by the init node.
|
// cond could be null if 'in obj' got eaten by the init node.
|
||||||
pn = nf.createForIn(init, cond, body, lineno);
|
pn = nf.createForIn(init, cond, body, position);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pn = nf.createFor(init, cond, incr, body, lineno);
|
pn = nf.createFor(init, cond, incr, body, position);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TokenStream.TRY: {
|
case TokenStream.TRY: {
|
||||||
int lineno = ts.getLineno();
|
Node tryblock;
|
||||||
|
Node catchblocks;
|
||||||
Object tryblock;
|
Node finallyblock = null;
|
||||||
Object catchblocks;
|
|
||||||
Object finallyblock = null;
|
|
||||||
|
|
||||||
tryblock = statement(ts);
|
tryblock = statement(ts);
|
||||||
|
|
||||||
catchblocks = nf.createLeaf(TokenStream.BLOCK);
|
catchblocks = nf.createLeaf(TokenStream.BLOCK, null);
|
||||||
|
|
||||||
boolean sawDefaultCatch = false;
|
boolean sawDefaultCatch = false;
|
||||||
int peek = ts.peekToken();
|
int peek = ts.peekToken();
|
||||||
@@ -503,12 +494,13 @@ public class Parser extends Observable {
|
|||||||
if (sawDefaultCatch) {
|
if (sawDefaultCatch) {
|
||||||
reportError(ts, "msg.catch.unreachable");
|
reportError(ts, "msg.catch.unreachable");
|
||||||
}
|
}
|
||||||
|
CodePosition catchPosition = ts.tokenPosition;
|
||||||
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.catch");
|
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.catch");
|
||||||
|
|
||||||
mustMatchToken(ts, TokenStream.NAME, "msg.bad.catchcond");
|
mustMatchToken(ts, TokenStream.NAME, "msg.bad.catchcond");
|
||||||
String varName = ts.getString();
|
Node varName = nf.createName(ts.getString(), ts.tokenPosition);
|
||||||
|
|
||||||
Object catchCond = null;
|
Node catchCond = null;
|
||||||
if (ts.matchToken(TokenStream.IF)) {
|
if (ts.matchToken(TokenStream.IF)) {
|
||||||
catchCond = expr(ts, false);
|
catchCond = expr(ts, false);
|
||||||
}
|
}
|
||||||
@@ -519,7 +511,7 @@ public class Parser extends Observable {
|
|||||||
mustMatchToken(ts, TokenStream.GWT, "msg.bad.catchcond");
|
mustMatchToken(ts, TokenStream.GWT, "msg.bad.catchcond");
|
||||||
mustMatchToken(ts, TokenStream.LC, "msg.no.brace.catchblock");
|
mustMatchToken(ts, TokenStream.LC, "msg.no.brace.catchblock");
|
||||||
|
|
||||||
nf.addChildToBack(catchblocks, nf.createCatch(varName, catchCond, statements(ts), ts.getLineno()));
|
catchblocks.addChildToBack(nf.createCatch(varName, catchCond, statements(ts), catchPosition));
|
||||||
|
|
||||||
mustMatchToken(ts, TokenStream.RC, "msg.no.brace.after.body");
|
mustMatchToken(ts, TokenStream.RC, "msg.no.brace.after.body");
|
||||||
}
|
}
|
||||||
@@ -532,37 +524,32 @@ public class Parser extends Observable {
|
|||||||
finallyblock = statement(ts);
|
finallyblock = statement(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
pn = nf.createTryCatchFinally(tryblock, catchblocks, finallyblock, lineno);
|
pn = nf.createTryCatchFinally(tryblock, catchblocks, finallyblock, position);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenStream.THROW: {
|
case TokenStream.THROW: {
|
||||||
int lineno = ts.getLineno();
|
int lineno = ts.getLineno();
|
||||||
pn = nf.createThrow(expr(ts, false), lineno);
|
pn = nf.createThrow(expr(ts, false), position);
|
||||||
if (lineno == ts.getLineno()) {
|
if (lineno == ts.getLineno()) {
|
||||||
wellTerminated(ts, TokenStream.ERROR);
|
wellTerminated(ts, TokenStream.ERROR);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenStream.BREAK: {
|
case TokenStream.BREAK: {
|
||||||
int lineno = ts.getLineno();
|
|
||||||
|
|
||||||
// matchLabel only matches if there is one
|
// matchLabel only matches if there is one
|
||||||
String label = matchLabel(ts);
|
Node label = matchLabel(ts);
|
||||||
pn = nf.createBreak(label, lineno);
|
pn = nf.createBreak(label, position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenStream.CONTINUE: {
|
case TokenStream.CONTINUE: {
|
||||||
int lineno = ts.getLineno();
|
|
||||||
|
|
||||||
// matchLabel only matches if there is one
|
// matchLabel only matches if there is one
|
||||||
String label = matchLabel(ts);
|
Node label = matchLabel(ts);
|
||||||
pn = nf.createContinue(label, lineno);
|
pn = nf.createContinue(label, position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenStream.DEBUGGER: {
|
case TokenStream.DEBUGGER: {
|
||||||
int lineno = ts.getLineno();
|
pn = nf.createDebugger(position);
|
||||||
pn = nf.createDebugger(lineno);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenStream.WITH: {
|
case TokenStream.WITH: {
|
||||||
@@ -572,25 +559,24 @@ public class Parser extends Observable {
|
|||||||
|
|
||||||
reportError(ts, "msg.jsni.unsupported.with");
|
reportError(ts, "msg.jsni.unsupported.with");
|
||||||
|
|
||||||
int lineno = ts.getLineno();
|
|
||||||
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.with");
|
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.with");
|
||||||
Object obj = expr(ts, false);
|
Node obj = expr(ts, false);
|
||||||
mustMatchToken(ts, TokenStream.GWT, "msg.no.paren.after.with");
|
mustMatchToken(ts, TokenStream.GWT, "msg.no.paren.after.with");
|
||||||
Object body = statement(ts);
|
Node body = statement(ts);
|
||||||
pn = nf.createWith(obj, body, lineno);
|
pn = nf.createWith(obj, body, position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenStream.VAR: {
|
case TokenStream.VAR: {
|
||||||
int lineno = ts.getLineno();
|
int lineno = ts.getLineno();
|
||||||
pn = variables(ts, false);
|
pn = variables(ts, false, position);
|
||||||
if (ts.getLineno() == lineno) {
|
if (ts.getLineno() == lineno) {
|
||||||
wellTerminated(ts, TokenStream.ERROR);
|
wellTerminated(ts, TokenStream.ERROR);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenStream.RETURN: {
|
case TokenStream.RETURN: {
|
||||||
Object retExpr = null;
|
Node retExpr = null;
|
||||||
int lineno = 0;
|
int lineno;
|
||||||
// bail if we're not in a (toplevel) function
|
// bail if we're not in a (toplevel) function
|
||||||
if ((!insideFunction) && ((ts.flags & TokenStream.TSF_FUNCTION) == 0)) {
|
if ((!insideFunction) && ((ts.flags & TokenStream.TSF_FUNCTION) == 0)) {
|
||||||
reportError(ts, "msg.bad.return");
|
reportError(ts, "msg.bad.return");
|
||||||
@@ -614,7 +600,7 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XXX ASSERT pn
|
// XXX ASSERT pn
|
||||||
pn = nf.createReturn(retExpr, lineno);
|
pn = nf.createReturn(retExpr, position);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenStream.LC:
|
case TokenStream.LC:
|
||||||
@@ -626,7 +612,7 @@ public class Parser extends Observable {
|
|||||||
// Fall thru, to have a node for error recovery to work on
|
// Fall thru, to have a node for error recovery to work on
|
||||||
case TokenStream.EOL:
|
case TokenStream.EOL:
|
||||||
case TokenStream.SEMI:
|
case TokenStream.SEMI:
|
||||||
pn = nf.createLeaf(TokenStream.VOID);
|
pn = nf.createLeaf(TokenStream.VOID, ts.tokenPosition);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@@ -653,12 +639,12 @@ public class Parser extends Observable {
|
|||||||
* follows: nf.addChildToBack(pn, statement(ts));
|
* follows: nf.addChildToBack(pn, statement(ts));
|
||||||
*/
|
*/
|
||||||
String name = ts.getString();
|
String name = ts.getString();
|
||||||
pn = nf.createLabel(name, lineno);
|
pn = nf.createLabel(nf.createString(name, position), position);
|
||||||
|
|
||||||
// bruce: added to make it easier to bind labels to the
|
// bruce: added to make it easier to bind labels to the
|
||||||
// statements they modify
|
// statements they modify
|
||||||
//
|
//
|
||||||
nf.addChildToBack(pn, statement(ts));
|
pn.addChildToBack(statement(ts));
|
||||||
|
|
||||||
// depend on decompiling lookahead to guess that that
|
// depend on decompiling lookahead to guess that that
|
||||||
// last name was a label.
|
// last name was a label.
|
||||||
@@ -671,7 +657,7 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pn = nf.createExprStatement(pn, lineno);
|
pn = nf.createExprStatement(pn, position);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check explicitly against (multi-line) function statement.
|
* Check explicitly against (multi-line) function statement.
|
||||||
@@ -693,15 +679,15 @@ public class Parser extends Observable {
|
|||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object variables(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node variables(TokenStream ts, boolean inForInit, CodePosition position) throws IOException, JavaScriptException {
|
||||||
Object pn = nf.createVariables(ts.getLineno());
|
Node pn = nf.createVariables(position);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
Object name;
|
Node name;
|
||||||
Object init;
|
Node init;
|
||||||
mustMatchToken(ts, TokenStream.NAME, "msg.bad.var");
|
mustMatchToken(ts, TokenStream.NAME, "msg.bad.var");
|
||||||
String s = ts.getString();
|
String s = ts.getString();
|
||||||
name = nf.createName(s);
|
name = nf.createName(s, ts.tokenPosition);
|
||||||
|
|
||||||
// omitted check for argument hiding
|
// omitted check for argument hiding
|
||||||
|
|
||||||
@@ -711,9 +697,9 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init = assignExpr(ts, inForInit);
|
init = assignExpr(ts, inForInit);
|
||||||
nf.addChildToBack(name, init);
|
name.addChildToBack(init);
|
||||||
}
|
}
|
||||||
nf.addChildToBack(pn, name);
|
pn.addChildToBack(name);
|
||||||
if (!ts.matchToken(TokenStream.COMMA)) {
|
if (!ts.matchToken(TokenStream.COMMA)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -721,93 +707,90 @@ public class Parser extends Observable {
|
|||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object expr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node expr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = assignExpr(ts, inForInit);
|
Node pn = assignExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.COMMA)) {
|
while (ts.matchToken(TokenStream.COMMA)) {
|
||||||
pn = nf.createBinary(TokenStream.COMMA, pn, assignExpr(ts, inForInit));
|
pn = nf.createBinary(TokenStream.COMMA, pn, assignExpr(ts, inForInit), pn.getPosition());
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object assignExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node assignExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = condExpr(ts, inForInit);
|
Node pn = condExpr(ts, inForInit);
|
||||||
|
|
||||||
if (ts.matchToken(TokenStream.ASSIGN)) {
|
if (ts.matchToken(TokenStream.ASSIGN)) {
|
||||||
// omitted: "invalid assignment left-hand side" check.
|
// omitted: "invalid assignment left-hand side" check.
|
||||||
pn = nf.createBinary(TokenStream.ASSIGN, ts.getOp(), pn, assignExpr(ts, inForInit));
|
pn = nf.createBinary(TokenStream.ASSIGN, ts.getOp(), pn, assignExpr(ts, inForInit), pn.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object condExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node condExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object ifTrue;
|
Node pn = orExpr(ts, inForInit);
|
||||||
Object ifFalse;
|
|
||||||
|
|
||||||
Object pn = orExpr(ts, inForInit);
|
|
||||||
|
|
||||||
if (ts.matchToken(TokenStream.HOOK)) {
|
if (ts.matchToken(TokenStream.HOOK)) {
|
||||||
ifTrue = assignExpr(ts, false);
|
Node ifTrue = assignExpr(ts, false);
|
||||||
mustMatchToken(ts, TokenStream.COLON, "msg.no.colon.cond");
|
mustMatchToken(ts, TokenStream.COLON, "msg.no.colon.cond");
|
||||||
ifFalse = assignExpr(ts, inForInit);
|
Node ifFalse = assignExpr(ts, inForInit);
|
||||||
return nf.createTernary(pn, ifTrue, ifFalse);
|
return nf.createTernary(pn, ifTrue, ifFalse, pn.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object orExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node orExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = andExpr(ts, inForInit);
|
Node pn = andExpr(ts, inForInit);
|
||||||
if (ts.matchToken(TokenStream.OR)) {
|
while (ts.matchToken(TokenStream.OR)) {
|
||||||
pn = nf.createBinary(TokenStream.OR, pn, orExpr(ts, inForInit));
|
pn = nf.createBinary(TokenStream.OR, pn, andExpr(ts, inForInit), pn.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object andExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node andExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = bitOrExpr(ts, inForInit);
|
Node pn = bitOrExpr(ts, inForInit);
|
||||||
if (ts.matchToken(TokenStream.AND)) {
|
while (ts.matchToken(TokenStream.AND)) {
|
||||||
pn = nf.createBinary(TokenStream.AND, pn, andExpr(ts, inForInit));
|
pn = nf.createBinary(TokenStream.AND, pn, bitOrExpr(ts, inForInit), pn.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object bitOrExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node bitOrExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = bitXorExpr(ts, inForInit);
|
Node pn = bitXorExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.BITOR)) {
|
while (ts.matchToken(TokenStream.BITOR)) {
|
||||||
pn = nf.createBinary(TokenStream.BITOR, pn, bitXorExpr(ts, inForInit));
|
pn = nf.createBinary(TokenStream.BITOR, pn, bitXorExpr(ts, inForInit), pn.getPosition());
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object bitXorExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node bitXorExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = bitAndExpr(ts, inForInit);
|
Node pn = bitAndExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.BITXOR)) {
|
while (ts.matchToken(TokenStream.BITXOR)) {
|
||||||
pn = nf.createBinary(TokenStream.BITXOR, pn, bitAndExpr(ts, inForInit));
|
pn = nf.createBinary(TokenStream.BITXOR, pn, bitAndExpr(ts, inForInit), pn.getPosition());
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object bitAndExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node bitAndExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = eqExpr(ts, inForInit);
|
Node pn = eqExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.BITAND)) {
|
while (ts.matchToken(TokenStream.BITAND)) {
|
||||||
pn = nf.createBinary(TokenStream.BITAND, pn, eqExpr(ts, inForInit));
|
pn = nf.createBinary(TokenStream.BITAND, pn, eqExpr(ts, inForInit), pn.getPosition());
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object eqExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node eqExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = relExpr(ts, inForInit);
|
Node pn = relExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.EQOP)) {
|
while (ts.matchToken(TokenStream.EQOP)) {
|
||||||
pn = nf.createBinary(TokenStream.EQOP, ts.getOp(), pn, relExpr(ts, inForInit));
|
pn = nf.createBinary(TokenStream.EQOP, ts.getOp(), pn, relExpr(ts, inForInit), pn.getPosition());
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object relExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node relExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
Object pn = shiftExpr(ts);
|
Node pn = shiftExpr(ts);
|
||||||
while (ts.matchToken(TokenStream.RELOP)) {
|
while (ts.matchToken(TokenStream.RELOP)) {
|
||||||
int op = ts.getOp();
|
int op = ts.getOp();
|
||||||
if (inForInit && op == TokenStream.IN) {
|
if (inForInit && op == TokenStream.IN) {
|
||||||
@@ -815,66 +798,67 @@ public class Parser extends Observable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pn = nf.createBinary(TokenStream.RELOP, op, pn, shiftExpr(ts));
|
pn = nf.createBinary(TokenStream.RELOP, op, pn, shiftExpr(ts), pn.getPosition());
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object shiftExpr(TokenStream ts) throws IOException, JavaScriptException {
|
private Node shiftExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
Object pn = addExpr(ts);
|
Node pn = addExpr(ts);
|
||||||
while (ts.matchToken(TokenStream.SHOP)) {
|
while (ts.matchToken(TokenStream.SHOP)) {
|
||||||
pn = nf.createBinary(TokenStream.SHOP, ts.getOp(), pn, addExpr(ts));
|
pn = nf.createBinary(TokenStream.SHOP, ts.getOp(), pn, addExpr(ts), pn.getPosition());
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object addExpr(TokenStream ts) throws IOException, JavaScriptException {
|
private Node addExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
int tt;
|
int tt;
|
||||||
Object pn = mulExpr(ts);
|
Node pn = mulExpr(ts);
|
||||||
|
|
||||||
while ((tt = ts.getToken()) == TokenStream.ADD || tt == TokenStream.SUB) {
|
while ((tt = ts.getToken()) == TokenStream.ADD || tt == TokenStream.SUB) {
|
||||||
// flushNewLines
|
// flushNewLines
|
||||||
pn = nf.createBinary(tt, pn, mulExpr(ts));
|
pn = nf.createBinary(tt, pn, mulExpr(ts), pn.getPosition());
|
||||||
}
|
}
|
||||||
ts.ungetToken(tt);
|
ts.ungetToken(tt);
|
||||||
|
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object mulExpr(TokenStream ts) throws IOException, JavaScriptException {
|
private Node mulExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
int tt;
|
int tt;
|
||||||
|
|
||||||
Object pn = unaryExpr(ts);
|
Node pn = unaryExpr(ts);
|
||||||
|
|
||||||
while ((tt = ts.peekToken()) == TokenStream.MUL || tt == TokenStream.DIV || tt == TokenStream.MOD) {
|
while ((tt = ts.peekToken()) == TokenStream.MUL || tt == TokenStream.DIV || tt == TokenStream.MOD) {
|
||||||
tt = ts.getToken();
|
tt = ts.getToken();
|
||||||
pn = nf.createBinary(tt, pn, unaryExpr(ts));
|
pn = nf.createBinary(tt, pn, unaryExpr(ts), pn.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object unaryExpr(TokenStream ts) throws IOException, JavaScriptException {
|
private Node unaryExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
int tt;
|
int tt;
|
||||||
|
|
||||||
ts.flags |= TokenStream.TSF_REGEXP;
|
ts.flags |= TokenStream.TSF_REGEXP;
|
||||||
tt = ts.getToken();
|
tt = ts.getToken();
|
||||||
ts.flags &= ~TokenStream.TSF_REGEXP;
|
ts.flags &= ~TokenStream.TSF_REGEXP;
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
|
|
||||||
switch (tt) {
|
switch (tt) {
|
||||||
case TokenStream.UNARYOP:
|
case TokenStream.UNARYOP:
|
||||||
return nf.createUnary(TokenStream.UNARYOP, ts.getOp(), unaryExpr(ts));
|
return nf.createUnary(TokenStream.UNARYOP, ts.getOp(), unaryExpr(ts), position);
|
||||||
|
|
||||||
case TokenStream.ADD:
|
case TokenStream.ADD:
|
||||||
case TokenStream.SUB:
|
case TokenStream.SUB:
|
||||||
return nf.createUnary(TokenStream.UNARYOP, tt, unaryExpr(ts));
|
return nf.createUnary(TokenStream.UNARYOP, tt, unaryExpr(ts), position);
|
||||||
|
|
||||||
case TokenStream.INC:
|
case TokenStream.INC:
|
||||||
case TokenStream.DEC:
|
case TokenStream.DEC:
|
||||||
return nf.createUnary(tt, TokenStream.PRE, memberExpr(ts, true));
|
return nf.createUnary(tt, TokenStream.PRE, memberExpr(ts, true), position);
|
||||||
|
|
||||||
case TokenStream.DELPROP:
|
case TokenStream.DELPROP:
|
||||||
return nf.createUnary(TokenStream.DELPROP, unaryExpr(ts));
|
return nf.createUnary(TokenStream.DELPROP, unaryExpr(ts), position);
|
||||||
|
|
||||||
case TokenStream.ERROR:
|
case TokenStream.ERROR:
|
||||||
break;
|
break;
|
||||||
@@ -884,7 +868,7 @@ public class Parser extends Observable {
|
|||||||
|
|
||||||
int lineno = ts.getLineno();
|
int lineno = ts.getLineno();
|
||||||
|
|
||||||
Object pn = memberExpr(ts, true);
|
Node pn = memberExpr(ts, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* don't look across a newline boundary for a postfix incop.
|
* don't look across a newline boundary for a postfix incop.
|
||||||
@@ -897,21 +881,21 @@ public class Parser extends Observable {
|
|||||||
if (((peeked = ts.peekToken()) == TokenStream.INC || peeked == TokenStream.DEC)
|
if (((peeked = ts.peekToken()) == TokenStream.INC || peeked == TokenStream.DEC)
|
||||||
&& ts.getLineno() == lineno) {
|
&& ts.getLineno() == lineno) {
|
||||||
int pf = ts.getToken();
|
int pf = ts.getToken();
|
||||||
return nf.createUnary(pf, TokenStream.POST, pn);
|
return nf.createUnary(pf, TokenStream.POST, pn, position);
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
return nf.createName("err"); // Only reached on error. Try to continue.
|
return nf.createName("err", position); // Only reached on error. Try to continue.
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object argumentList(TokenStream ts, Object listNode) throws IOException, JavaScriptException {
|
private Node argumentList(TokenStream ts, Node listNode) throws IOException, JavaScriptException {
|
||||||
boolean matched;
|
boolean matched;
|
||||||
ts.flags |= TokenStream.TSF_REGEXP;
|
ts.flags |= TokenStream.TSF_REGEXP;
|
||||||
matched = ts.matchToken(TokenStream.GWT);
|
matched = ts.matchToken(TokenStream.GWT);
|
||||||
ts.flags &= ~TokenStream.TSF_REGEXP;
|
ts.flags &= ~TokenStream.TSF_REGEXP;
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
do {
|
do {
|
||||||
nf.addChildToBack(listNode, assignExpr(ts, false));
|
listNode.addChildToBack(assignExpr(ts, false));
|
||||||
}
|
}
|
||||||
while (ts.matchToken(TokenStream.COMMA));
|
while (ts.matchToken(TokenStream.COMMA));
|
||||||
|
|
||||||
@@ -920,10 +904,11 @@ public class Parser extends Observable {
|
|||||||
return listNode;
|
return listNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object memberExpr(TokenStream ts, boolean allowCallSyntax) throws IOException, JavaScriptException {
|
private Node memberExpr(TokenStream ts, boolean allowCallSyntax) throws IOException, JavaScriptException {
|
||||||
int tt;
|
int tt;
|
||||||
|
|
||||||
Object pn;
|
Node pn;
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
|
|
||||||
/* Check for new expressions. */
|
/* Check for new expressions. */
|
||||||
ts.flags |= TokenStream.TSF_REGEXP;
|
ts.flags |= TokenStream.TSF_REGEXP;
|
||||||
@@ -934,8 +919,8 @@ public class Parser extends Observable {
|
|||||||
ts.getToken();
|
ts.getToken();
|
||||||
|
|
||||||
/* Make a NEW node to append to. */
|
/* Make a NEW node to append to. */
|
||||||
pn = nf.createLeaf(TokenStream.NEW);
|
pn = nf.createLeaf(TokenStream.NEW, position);
|
||||||
nf.addChildToBack(pn, memberExpr(ts, false));
|
pn.addChildToBack(memberExpr(ts, false));
|
||||||
|
|
||||||
if (ts.matchToken(TokenStream.LP)) {
|
if (ts.matchToken(TokenStream.LP)) {
|
||||||
/* Add the arguments to pn, if any are supplied. */
|
/* Add the arguments to pn, if any are supplied. */
|
||||||
@@ -955,19 +940,19 @@ public class Parser extends Observable {
|
|||||||
*/
|
*/
|
||||||
tt = ts.peekToken();
|
tt = ts.peekToken();
|
||||||
if (tt == TokenStream.LC) {
|
if (tt == TokenStream.LC) {
|
||||||
nf.addChildToBack(pn, primaryExpr(ts));
|
pn.addChildToBack(primaryExpr(ts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pn = primaryExpr(ts);
|
pn = primaryExpr(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
return memberExprTail(ts, allowCallSyntax, pn);
|
return memberExprTail(ts, allowCallSyntax, pn, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object memberExprTail(
|
private Node memberExprTail(
|
||||||
TokenStream ts, boolean allowCallSyntax,
|
TokenStream ts, boolean allowCallSyntax,
|
||||||
Object pn
|
Node pn, CodePosition position
|
||||||
) throws IOException, JavaScriptException {
|
) throws IOException, JavaScriptException {
|
||||||
lastExprEndLine = ts.getLineno();
|
lastExprEndLine = ts.getLineno();
|
||||||
int tt;
|
int tt;
|
||||||
@@ -976,7 +961,7 @@ public class Parser extends Observable {
|
|||||||
ts.treatKeywordAsIdentifier = true;
|
ts.treatKeywordAsIdentifier = true;
|
||||||
mustMatchToken(ts, TokenStream.NAME, "msg.no.name.after.dot");
|
mustMatchToken(ts, TokenStream.NAME, "msg.no.name.after.dot");
|
||||||
ts.treatKeywordAsIdentifier = false;
|
ts.treatKeywordAsIdentifier = false;
|
||||||
pn = nf.createBinary(TokenStream.DOT, pn, nf.createName(ts.getString()));
|
pn = nf.createBinary(TokenStream.DOT, pn, nf.createName(ts.getString(), ts.tokenPosition), position);
|
||||||
/*
|
/*
|
||||||
* pn = nf.createBinary(ts.DOT, pn, memberExpr(ts)) is the version in
|
* pn = nf.createBinary(ts.DOT, pn, memberExpr(ts)) is the version in
|
||||||
* Brendan's IR C version. Not in ECMA... does it reflect the 'new'
|
* Brendan's IR C version. Not in ECMA... does it reflect the 'new'
|
||||||
@@ -985,14 +970,14 @@ public class Parser extends Observable {
|
|||||||
lastExprEndLine = ts.getLineno();
|
lastExprEndLine = ts.getLineno();
|
||||||
}
|
}
|
||||||
else if (tt == TokenStream.LB) {
|
else if (tt == TokenStream.LB) {
|
||||||
pn = nf.createBinary(TokenStream.LB, pn, expr(ts, false));
|
pn = nf.createBinary(TokenStream.LB, pn, expr(ts, false), position);
|
||||||
|
|
||||||
mustMatchToken(ts, TokenStream.RB, "msg.no.bracket.index");
|
mustMatchToken(ts, TokenStream.RB, "msg.no.bracket.index");
|
||||||
lastExprEndLine = ts.getLineno();
|
lastExprEndLine = ts.getLineno();
|
||||||
}
|
}
|
||||||
else if (allowCallSyntax && tt == TokenStream.LP) {
|
else if (allowCallSyntax && tt == TokenStream.LP) {
|
||||||
/* make a call node */
|
/* make a call node */
|
||||||
pn = nf.createUnary(TokenStream.CALL, pn);
|
pn = nf.createUnary(TokenStream.CALL, pn, position);
|
||||||
|
|
||||||
/* Add the arguments to pn, if any are supplied. */
|
/* Add the arguments to pn, if any are supplied. */
|
||||||
pn = argumentList(ts, pn);
|
pn = argumentList(ts, pn);
|
||||||
@@ -1007,13 +992,14 @@ public class Parser extends Observable {
|
|||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object primaryExpr(TokenStream ts) throws IOException, JavaScriptException {
|
public Node primaryExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
int tt;
|
int tt;
|
||||||
|
|
||||||
Object pn;
|
Node pn;
|
||||||
|
|
||||||
ts.flags |= TokenStream.TSF_REGEXP;
|
ts.flags |= TokenStream.TSF_REGEXP;
|
||||||
tt = ts.getToken();
|
tt = ts.getToken();
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
ts.flags &= ~TokenStream.TSF_REGEXP;
|
ts.flags &= ~TokenStream.TSF_REGEXP;
|
||||||
|
|
||||||
switch (tt) {
|
switch (tt) {
|
||||||
@@ -1022,7 +1008,7 @@ public class Parser extends Observable {
|
|||||||
return function(ts, true);
|
return function(ts, true);
|
||||||
|
|
||||||
case TokenStream.LB: {
|
case TokenStream.LB: {
|
||||||
pn = nf.createLeaf(TokenStream.ARRAYLIT);
|
pn = nf.createLeaf(TokenStream.ARRAYLIT, position);
|
||||||
|
|
||||||
ts.flags |= TokenStream.TSF_REGEXP;
|
ts.flags |= TokenStream.TSF_REGEXP;
|
||||||
boolean matched = ts.matchToken(TokenStream.RB);
|
boolean matched = ts.matchToken(TokenStream.RB);
|
||||||
@@ -1039,10 +1025,10 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tt == TokenStream.COMMA) {
|
if (tt == TokenStream.COMMA) {
|
||||||
nf.addChildToBack(pn, nf.createLeaf(TokenStream.PRIMARY, TokenStream.UNDEFINED));
|
pn.addChildToBack(nf.createLeaf(TokenStream.PRIMARY, TokenStream.UNDEFINED, position));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nf.addChildToBack(pn, assignExpr(ts, false));
|
pn.addChildToBack(assignExpr(ts, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (ts.matchToken(TokenStream.COMMA));
|
while (ts.matchToken(TokenStream.COMMA));
|
||||||
@@ -1053,28 +1039,28 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TokenStream.LC: {
|
case TokenStream.LC: {
|
||||||
pn = nf.createLeaf(TokenStream.OBJLIT);
|
pn = nf.createLeaf(TokenStream.OBJLIT, position);
|
||||||
|
|
||||||
if (!ts.matchToken(TokenStream.RC)) {
|
if (!ts.matchToken(TokenStream.RC)) {
|
||||||
|
|
||||||
commaloop:
|
commaloop:
|
||||||
do {
|
do {
|
||||||
Object property;
|
Node property;
|
||||||
|
|
||||||
tt = ts.getToken();
|
tt = ts.getToken();
|
||||||
switch (tt) {
|
switch (tt) {
|
||||||
// map NAMEs to STRINGs in object literal context.
|
// map NAMEs to STRINGs in object literal context.
|
||||||
case TokenStream.NAME:
|
case TokenStream.NAME:
|
||||||
case TokenStream.STRING:
|
case TokenStream.STRING:
|
||||||
property = nf.createString(ts.getString());
|
property = nf.createString(ts.getString(), ts.tokenPosition);
|
||||||
break;
|
break;
|
||||||
case TokenStream.NUMBER_INT:
|
case TokenStream.NUMBER_INT:
|
||||||
int n = (int) ts.getNumber();
|
int n = (int) ts.getNumber();
|
||||||
property = nf.createNumber(n);
|
property = nf.createNumber(n, ts.tokenPosition);
|
||||||
break;
|
break;
|
||||||
case TokenStream.NUMBER:
|
case TokenStream.NUMBER:
|
||||||
double d = ts.getNumber();
|
double d = ts.getNumber();
|
||||||
property = nf.createNumber(d);
|
property = nf.createNumber(d, ts.tokenPosition);
|
||||||
break;
|
break;
|
||||||
case TokenStream.RC:
|
case TokenStream.RC:
|
||||||
// trailing comma is OK.
|
// trailing comma is OK.
|
||||||
@@ -1088,8 +1074,8 @@ public class Parser extends Observable {
|
|||||||
|
|
||||||
// OBJLIT is used as ':' in object literal for
|
// OBJLIT is used as ':' in object literal for
|
||||||
// decompilation to solve spacing ambiguity.
|
// decompilation to solve spacing ambiguity.
|
||||||
nf.addChildToBack(pn, property);
|
pn.addChildToBack(property);
|
||||||
nf.addChildToBack(pn, assignExpr(ts, false));
|
pn.addChildToBack(assignExpr(ts, false));
|
||||||
}
|
}
|
||||||
while (ts.matchToken(TokenStream.COMMA));
|
while (ts.matchToken(TokenStream.COMMA));
|
||||||
|
|
||||||
@@ -1112,29 +1098,29 @@ public class Parser extends Observable {
|
|||||||
|
|
||||||
case TokenStream.NAME:
|
case TokenStream.NAME:
|
||||||
String name = ts.getString();
|
String name = ts.getString();
|
||||||
return nf.createName(name);
|
return nf.createName(name, position);
|
||||||
|
|
||||||
case TokenStream.NUMBER_INT:
|
case TokenStream.NUMBER_INT:
|
||||||
int n = (int) ts.getNumber();
|
int n = (int) ts.getNumber();
|
||||||
return nf.createNumber(n);
|
return nf.createNumber(n, position);
|
||||||
|
|
||||||
case TokenStream.NUMBER:
|
case TokenStream.NUMBER:
|
||||||
double d = ts.getNumber();
|
double d = ts.getNumber();
|
||||||
return nf.createNumber(d);
|
return nf.createNumber(d, position);
|
||||||
|
|
||||||
case TokenStream.STRING:
|
case TokenStream.STRING:
|
||||||
String s = ts.getString();
|
String s = ts.getString();
|
||||||
return nf.createString(s);
|
return nf.createString(s, position);
|
||||||
|
|
||||||
case TokenStream.REGEXP: {
|
case TokenStream.REGEXP: {
|
||||||
String flags = ts.regExpFlags;
|
String flags = ts.regExpFlags;
|
||||||
ts.regExpFlags = null;
|
ts.regExpFlags = null;
|
||||||
String re = ts.getString();
|
String re = ts.getString();
|
||||||
return nf.createRegExp(re, flags);
|
return nf.createRegExp(re, flags, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
case TokenStream.PRIMARY:
|
case TokenStream.PRIMARY:
|
||||||
return nf.createLeaf(TokenStream.PRIMARY, ts.getOp());
|
return nf.createLeaf(TokenStream.PRIMARY, ts.getOp(), position);
|
||||||
|
|
||||||
case TokenStream.ERROR:
|
case TokenStream.ERROR:
|
||||||
/* the scanner or one of its subroutines reported the error. */
|
/* the scanner or one of its subroutines reported the error. */
|
||||||
|
|||||||
@@ -514,8 +514,7 @@ public class TokenStream {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
// didn't match, push back token
|
// didn't match, push back token
|
||||||
tokenno--;
|
ungetToken(token);
|
||||||
this.pushbackToken = token;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,6 +525,8 @@ public class TokenStream {
|
|||||||
throw new RuntimeException(message);
|
throw new RuntimeException(message);
|
||||||
}
|
}
|
||||||
this.pushbackToken = tt;
|
this.pushbackToken = tt;
|
||||||
|
lastPosition = secondToLastPosition;
|
||||||
|
lastTokenPosition = tokenPosition;
|
||||||
tokenno--;
|
tokenno--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,6 +534,8 @@ public class TokenStream {
|
|||||||
int result = getToken();
|
int result = getToken();
|
||||||
|
|
||||||
this.pushbackToken = result;
|
this.pushbackToken = result;
|
||||||
|
lastPosition = secondToLastPosition;
|
||||||
|
lastTokenPosition = tokenPosition;
|
||||||
tokenno--;
|
tokenno--;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -583,13 +586,14 @@ public class TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getToken() throws IOException {
|
public int getToken() throws IOException {
|
||||||
int c;
|
lastTokenPosition = tokenPosition;
|
||||||
do {
|
int c;
|
||||||
c = getTokenHelper();
|
do {
|
||||||
} while (c == RETRY_TOKEN);
|
c = getTokenHelper();
|
||||||
|
} while (c == RETRY_TOKEN);
|
||||||
|
|
||||||
updatePosition();
|
updatePosition();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getTokenHelper() throws IOException {
|
private int getTokenHelper() throws IOException {
|
||||||
@@ -613,6 +617,7 @@ public class TokenStream {
|
|||||||
}
|
}
|
||||||
} while (isJSSpace(c) || c == '\n');
|
} while (isJSSpace(c) || c == '\n');
|
||||||
|
|
||||||
|
tokenPosition = new CodePosition(in.getLineno(), Math.max(in.getOffset() - 1, 0));
|
||||||
if (c == EOF_CHAR)
|
if (c == EOF_CHAR)
|
||||||
return EOF;
|
return EOF;
|
||||||
if (c != '-' && c != '\n')
|
if (c != '-' && c != '\n')
|
||||||
@@ -694,7 +699,7 @@ public class TokenStream {
|
|||||||
}
|
}
|
||||||
in.unread();
|
in.unread();
|
||||||
|
|
||||||
String str = getStringFromBuffer();
|
String str = getStringFromBuffer();
|
||||||
if (!containsEscape && !treatKeywordAsIdentifier) {
|
if (!containsEscape && !treatKeywordAsIdentifier) {
|
||||||
// OPT we shouldn't have to make a string (object!) to
|
// OPT we shouldn't have to make a string (object!) to
|
||||||
// check if it's a keyword.
|
// check if it's a keyword.
|
||||||
@@ -1475,6 +1480,8 @@ public class TokenStream {
|
|||||||
|
|
||||||
CodePosition secondToLastPosition;
|
CodePosition secondToLastPosition;
|
||||||
CodePosition lastPosition;
|
CodePosition lastPosition;
|
||||||
|
CodePosition tokenPosition;
|
||||||
|
CodePosition lastTokenPosition;
|
||||||
|
|
||||||
private int op;
|
private int op;
|
||||||
public boolean treatKeywordAsIdentifier;
|
public boolean treatKeywordAsIdentifier;
|
||||||
|
|||||||
Reference in New Issue
Block a user