Correctly handle JSNI references to compile-time constants.
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1513 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index 36c45c8..70c616c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -309,7 +309,7 @@
//
// Create the tree from JDT
- GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram);
+ GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram, jsProgram);
// GenerateJavaAST can uncover semantic JSNI errors; report & abort
//
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index e56caf1..fe37ed8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -15,11 +15,10 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.HasSourceInfo;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.SourceInfo;
-import com.google.gwt.dev.jjs.ast.CanBeStatic;
import com.google.gwt.dev.jjs.ast.HasEnclosingType;
-import com.google.gwt.dev.jjs.ast.HasName;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JAssertStatement;
@@ -87,9 +86,11 @@
import com.google.gwt.dev.js.ast.JsContext;
import com.google.gwt.dev.js.ast.JsExpression;
import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsInvocation;
+import com.google.gwt.dev.js.ast.JsModVisitor;
import com.google.gwt.dev.js.ast.JsNameRef;
+import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsSourceInfo;
-import com.google.gwt.dev.js.ast.JsVisitor;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.CompilationResult;
@@ -214,6 +215,158 @@
*/
private static class JavaASTGenerationVisitor {
+ private class JsniRefResolver extends JsModVisitor {
+ private final AbstractMethodDeclaration methodDecl;
+ private final JsniMethodBody nativeMethodBody;
+
+ private JsniRefResolver(AbstractMethodDeclaration methodDecl,
+ JsniMethodBody nativeMethodBody) {
+ this.methodDecl = methodDecl;
+ this.nativeMethodBody = nativeMethodBody;
+ }
+
+ @Override
+ public void endVisit(JsNameRef x, JsContext<JsExpression> ctx) {
+ String ident = x.getIdent();
+ if (ident.charAt(0) == '@') {
+ processNameRef(x, ctx);
+ }
+ }
+
+ private HasEnclosingType parseJsniRef(SourceInfo info, String ident) {
+ String[] parts = ident.substring(1).split("::");
+ assert (parts.length == 2);
+ String className = parts[0];
+ JReferenceType type = program.getFromTypeMap(className);
+ if (type == null) {
+ reportJsniError(info, methodDecl,
+ "Unresolvable native reference to type '" + className + "'");
+ return null;
+ }
+ String rhs = parts[1];
+ int parenPos = rhs.indexOf('(');
+ if (parenPos < 0) {
+ // look for a field
+ for (int i = 0; i < type.fields.size(); ++i) {
+ JField field = type.fields.get(i);
+ if (field.getName().equals(rhs)) {
+ return field;
+ }
+ }
+
+ reportJsniError(info, methodDecl,
+ "Unresolvable native reference to field '" + rhs + "' in type '"
+ + className + "'");
+ } else {
+ // look for a method
+ String methodName = rhs.substring(0, parenPos);
+ String almostMatches = null;
+ for (int i = 0; i < type.methods.size(); ++i) {
+ JMethod method = type.methods.get(i);
+ if (method.getName().equals(methodName)) {
+ String jsniSig = getJsniSig(method);
+ if (jsniSig.equals(rhs)) {
+ return method;
+ } else if (almostMatches == null) {
+ almostMatches = "'" + jsniSig + "'";
+ } else {
+ almostMatches += ", '" + jsniSig + "'";
+ }
+ }
+ }
+
+ if (almostMatches == null) {
+ reportJsniError(info, methodDecl,
+ "Unresolvable native reference to method '" + methodName
+ + "' in type '" + className + "'");
+ } else {
+ reportJsniError(info, methodDecl,
+ "Unresolvable native reference to method '" + methodName
+ + "' in type '" + className + "' (did you mean "
+ + almostMatches + "?)");
+ }
+ }
+ return null;
+ }
+
+ private void processField(JsNameRef nameRef, SourceInfo info,
+ JField field, JsContext<JsExpression> ctx) {
+ if (field.isStatic() && nameRef.getQualifier() != null) {
+ reportJsniError(info, methodDecl,
+ "Cannot make a qualified reference to the static field "
+ + field.getName());
+ } else if (!field.isStatic() && nameRef.getQualifier() == null) {
+ reportJsniError(info, methodDecl,
+ "Cannot make an unqualified reference to the instance field "
+ + field.getName());
+ }
+
+ /*
+ * We must replace any compile-time constants with the constant value of
+ * the field.
+ */
+ JLiteral initializer = field.constInitializer;
+ if (field.isStatic() && field.isFinal() && initializer != null) {
+ JType type = initializer.getType();
+ if (type instanceof JPrimitiveType
+ || type == program.getTypeJavaLangString()) {
+ GenerateJavaScriptLiterals generator = new GenerateJavaScriptLiterals(
+ jsProgram);
+ generator.accept(initializer);
+ JsExpression result = generator.peek();
+ assert (result != null);
+ ctx.replaceMe(result);
+ return;
+ }
+ }
+
+ // Normal: create a jsniRef.
+ JsniFieldRef fieldRef = new JsniFieldRef(program, info, field,
+ currentClass);
+ nativeMethodBody.jsniFieldRefs.add(fieldRef);
+ }
+
+ private void processMethod(JsNameRef nameRef, SourceInfo info,
+ JMethod method) {
+ if (method.isStatic() && nameRef.getQualifier() != null) {
+ reportJsniError(info, methodDecl,
+ "Cannot make a qualified reference to the static method "
+ + method.getName());
+ } else if (!method.isStatic() && nameRef.getQualifier() == null) {
+ reportJsniError(info, methodDecl,
+ "Cannot make an unqualified reference to the instance method "
+ + method.getName());
+ }
+
+ JsniMethodRef methodRef = new JsniMethodRef(program, info, method);
+ nativeMethodBody.jsniMethodRefs.add(methodRef);
+ }
+
+ private void processNameRef(JsNameRef nameRef, JsContext<JsExpression> ctx) {
+ SourceInfo info = nativeMethodBody.getSourceInfo();
+ // TODO: make this tighter when we have real source info
+ // JSourceInfo info = translateInfo(nameRef.getInfo());
+ String ident = nameRef.getIdent();
+ HasEnclosingType node = program.jsniMap.get(ident);
+ if (node == null) {
+ node = parseJsniRef(info, ident);
+ if (node == null) {
+ return; // already reported error
+ }
+ program.jsniMap.put(ident, node);
+ }
+
+ if (node instanceof JField) {
+ processField(nameRef, info, (JField) node, ctx);
+ } else if (node instanceof JMethod) {
+ processMethod(nameRef, info, (JMethod) node);
+ } else {
+ throw new InternalCompilerException((HasSourceInfo) node,
+ "JSNI reference to something other than a field or method?", null);
+ }
+ }
+ }
+
private static String getJsniSig(JMethod method) {
StringBuffer sb = new StringBuffer();
sb.append(method.getName());
@@ -253,15 +406,19 @@
private int[] currentSeparatorPositions;
+ private final JsProgram jsProgram;
+
private final Map<JMethod, Map<String, JLabel>> labelMap = new IdentityHashMap<JMethod, Map<String, JLabel>>();
private final JProgram program;
private final TypeMap typeMap;
- public JavaASTGenerationVisitor(TypeMap typeMap) {
+ public JavaASTGenerationVisitor(TypeMap typeMap, JProgram program,
+ JsProgram jsProgram) {
this.typeMap = typeMap;
- program = this.typeMap.getProgram();
+ this.program = program;
+ this.jsProgram = jsProgram;
}
public void processEnumType(JEnumType type) {
@@ -1403,60 +1560,7 @@
}
// resolve jsni refs
- final List<JsNameRef> nameRefs = new ArrayList<JsNameRef>();
- new JsVisitor() {
- // @Override
- public void endVisit(JsNameRef x, JsContext<JsExpression> ctx) {
- String ident = x.getIdent();
- if (ident.charAt(0) == '@') {
- nameRefs.add(x);
- }
- }
- }.accept(func);
-
- for (int i = 0; i < nameRefs.size(); ++i) {
- JsNameRef nameRef = nameRefs.get(i);
- SourceInfo info = nativeMethodBody.getSourceInfo();
- // TODO: make this tighter when we have real source info
- // JSourceInfo info = translateInfo(nameRef.getInfo());
- String ident = nameRef.getIdent();
- HasEnclosingType node = program.jsniMap.get(ident);
- if (node == null) {
- node = parseJsniRef(info, x, ident);
- if (node == null) {
- continue; // already reported error
- }
- program.jsniMap.put(ident, node);
- }
- CanBeStatic canBeStatic = (CanBeStatic) node;
- HasName hasName = (HasName) node;
- boolean isField = node instanceof JField;
- assert (isField || node instanceof JMethod);
- if (canBeStatic.isStatic() && nameRef.getQualifier() != null) {
- reportJsniError(info, x,
- "Cannot make a qualified reference to the static "
- + (isField ? "field " : "method ") + hasName.getName());
- } else if (!canBeStatic.isStatic() && nameRef.getQualifier() == null) {
- reportJsniError(info, x,
- "Cannot make an unqualified reference to the instance "
- + (isField ? "field " : "method ") + hasName.getName());
- }
-
- if (isField) {
- /*
- * TODO FIXME HACK: We should be replacing compile-time constant refs
- * from JSNI with the literal value of the field.
- */
- JField field = (JField) node;
- JsniFieldRef fieldRef = new JsniFieldRef(program, info, field,
- currentClass);
- nativeMethodBody.jsniFieldRefs.add(fieldRef);
- } else {
- JMethod method = (JMethod) node;
- JsniMethodRef methodRef = new JsniMethodRef(program, info, method);
- nativeMethodBody.jsniMethodRefs.add(methodRef);
- }
- }
+ new JsniRefResolver(x, nativeMethodBody).accept(func);
}
JStatement processStatement(AssertStatement x) {
@@ -2213,60 +2317,6 @@
currentFileName);
}
- private HasEnclosingType parseJsniRef(SourceInfo info,
- AbstractMethodDeclaration x, String ident) {
- String[] parts = ident.substring(1).split("::");
- assert (parts.length == 2);
- String className = parts[0];
- JReferenceType type = program.getFromTypeMap(className);
- if (type == null) {
- reportJsniError(info, x, "Unresolvable native reference to type '"
- + className + "'");
- return null;
- }
- String rhs = parts[1];
- int parenPos = rhs.indexOf('(');
- if (parenPos < 0) {
- // look for a field
- for (int i = 0; i < type.fields.size(); ++i) {
- JField field = type.fields.get(i);
- if (field.getName().equals(rhs)) {
- return field;
- }
- }
-
- reportJsniError(info, x, "Unresolvable native reference to field '"
- + rhs + "' in type '" + className + "'");
- } else {
- // look for a method
- String methodName = rhs.substring(0, parenPos);
- String almostMatches = null;
- for (int i = 0; i < type.methods.size(); ++i) {
- JMethod method = type.methods.get(i);
- if (method.getName().equals(methodName)) {
- String jsniSig = getJsniSig(method);
- if (jsniSig.equals(rhs)) {
- return method;
- } else if (almostMatches == null) {
- almostMatches = "'" + jsniSig + "'";
- } else {
- almostMatches += ", '" + jsniSig + "'";
- }
- }
- }
-
- if (almostMatches == null) {
- reportJsniError(info, x, "Unresolvable native reference to method '"
- + methodName + "' in type '" + className + "'");
- } else {
- reportJsniError(info, x, "Unresolvable native reference to method '"
- + methodName + "' in type '" + className + "' (did you mean "
- + almostMatches + "?)");
- }
- }
- return null;
- }
-
/**
* Sometimes a variable reference can be to a local or parameter in an an
* enclosing method. This is a tricky situation to detect. There's no
@@ -2546,8 +2596,9 @@
* a JProgram structure.
*/
public static void exec(TypeDeclaration[] types, TypeMap typeMap,
- JProgram jprogram) {
- JavaASTGenerationVisitor v = new JavaASTGenerationVisitor(typeMap);
+ JProgram jprogram, JsProgram jsProgram) {
+ JavaASTGenerationVisitor v = new JavaASTGenerationVisitor(typeMap,
+ jprogram, jsProgram);
for (int i = 0; i < types.length; ++i) {
v.processType(types[i]);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index e45e74e..923d174 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -26,38 +26,31 @@
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
import com.google.gwt.dev.jjs.ast.JBlock;
-import com.google.gwt.dev.jjs.ast.JBooleanLiteral;
import com.google.gwt.dev.jjs.ast.JBreakStatement;
import com.google.gwt.dev.jjs.ast.JCaseStatement;
import com.google.gwt.dev.jjs.ast.JCastOperation;
-import com.google.gwt.dev.jjs.ast.JCharLiteral;
import com.google.gwt.dev.jjs.ast.JClassLiteral;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConditional;
import com.google.gwt.dev.jjs.ast.JContinueStatement;
import com.google.gwt.dev.jjs.ast.JDoStatement;
-import com.google.gwt.dev.jjs.ast.JDoubleLiteral;
import com.google.gwt.dev.jjs.ast.JExpressionStatement;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JFieldRef;
-import com.google.gwt.dev.jjs.ast.JFloatLiteral;
import com.google.gwt.dev.jjs.ast.JForStatement;
import com.google.gwt.dev.jjs.ast.JIfStatement;
import com.google.gwt.dev.jjs.ast.JInstanceOf;
-import com.google.gwt.dev.jjs.ast.JIntLiteral;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JLabel;
import com.google.gwt.dev.jjs.ast.JLabeledStatement;
import com.google.gwt.dev.jjs.ast.JLocal;
import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JLocalRef;
-import com.google.gwt.dev.jjs.ast.JLongLiteral;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JNewArray;
import com.google.gwt.dev.jjs.ast.JNewInstance;
-import com.google.gwt.dev.jjs.ast.JNullLiteral;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JParameterRef;
import com.google.gwt.dev.jjs.ast.JPostfixOperation;
@@ -66,7 +59,6 @@
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JReturnStatement;
import com.google.gwt.dev.jjs.ast.JStatement;
-import com.google.gwt.dev.jjs.ast.JStringLiteral;
import com.google.gwt.dev.jjs.ast.JSwitchStatement;
import com.google.gwt.dev.jjs.ast.JThisRef;
import com.google.gwt.dev.jjs.ast.JThrowStatement;
@@ -125,12 +117,10 @@
import com.google.gwt.dev.js.ast.JsUnaryOperation;
import com.google.gwt.dev.js.ast.JsUnaryOperator;
import com.google.gwt.dev.js.ast.JsVars;
-import com.google.gwt.dev.js.ast.JsVisitable;
import com.google.gwt.dev.js.ast.JsWhile;
import com.google.gwt.dev.js.ast.JsVars.JsVar;
import java.math.BigInteger;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -364,7 +354,7 @@
}
}
- private class GenerateJavaScriptVisitor extends JVisitor {
+ private class GenerateJavaScriptVisitor extends GenerateJavaScriptLiterals {
private final Set<JClassType> alreadyRan = new HashSet<JClassType>();
@@ -372,8 +362,6 @@
private final JsName globalTemp = topScope.declareName("_");
- private final Stack<JsVisitable> nodeStack = new Stack<JsVisitable>();
-
private final JsName prototype = objectScope.declareName("prototype");
{
@@ -381,6 +369,10 @@
prototype.setObfuscatable(false);
}
+ public GenerateJavaScriptVisitor() {
+ super(jsProgram);
+ }
+
@Override
public void endVisit(JAbsentArrayDimension x, Context ctx) {
throw new InternalCompilerException("Should not get here.");
@@ -438,12 +430,6 @@
}
@Override
- public void endVisit(JBooleanLiteral x, Context ctx) {
- push(x.getValue() ? jsProgram.getTrueLiteral()
- : jsProgram.getFalseLiteral());
- }
-
- @Override
public void endVisit(JBreakStatement x, Context ctx) {
JsNameRef labelRef = null;
if (x.getLabel() != null) {
@@ -470,11 +456,6 @@
}
@Override
- public void endVisit(JCharLiteral x, Context ctx) {
- push(jsProgram.getIntegralLiteral(BigInteger.valueOf(x.getValue())));
- }
-
- @Override
public void endVisit(JClassLiteral x, Context ctx) {
JsExpression classObjectAllocation = pop(); // classObjectAllocation
@@ -570,11 +551,6 @@
}
@Override
- public void endVisit(JDoubleLiteral x, Context ctx) {
- push(jsProgram.getDecimalLiteral(String.valueOf(x.getValue())));
- }
-
- @Override
public void endVisit(JExpressionStatement x, Context ctx) {
JsExpression expr = (JsExpression) pop(); // expr
push(expr.makeStmt());
@@ -651,11 +627,6 @@
}
@Override
- public void endVisit(JFloatLiteral x, Context ctx) {
- push(jsProgram.getDecimalLiteral(String.valueOf(x.getValue())));
- }
-
- @Override
public void endVisit(JForStatement x, Context ctx) {
JsFor jsFor = new JsFor();
@@ -742,11 +713,6 @@
}
@Override
- public void endVisit(JIntLiteral x, Context ctx) {
- push(jsProgram.getIntegralLiteral(BigInteger.valueOf(x.getValue())));
- }
-
- @Override
public void endVisit(JLabel x, Context ctx) {
push(new JsLabel(names.get(x)));
}
@@ -792,11 +758,6 @@
}
@Override
- public void endVisit(JLongLiteral x, Context ctx) {
- push(jsProgram.getIntegralLiteral(BigInteger.valueOf(x.getValue())));
- }
-
- @Override
public void endVisit(JMethod x, Context ctx) {
if (x.isAbstract()) {
push(null);
@@ -930,11 +891,6 @@
}
@Override
- public void endVisit(JNullLiteral x, Context ctx) {
- push(jsProgram.getNullLiteral());
- }
-
- @Override
public void endVisit(JParameter x, Context ctx) {
push(new JsParameter(names.get(x)));
}
@@ -1070,11 +1026,6 @@
}
@Override
- public void endVisit(JStringLiteral x, Context ctx) {
- push(jsProgram.getStringLiteral(x.getValue()));
- }
-
- @Override
public void endVisit(JThisRef x, Context ctx) {
push(new JsThisRef());
}
@@ -1449,41 +1400,6 @@
jsInvocation.setQualifier(names.get(clinitMethod).makeRef());
return jsInvocation;
}
-
- private <T extends JsVisitable> T pop() {
- return (T) nodeStack.pop();
- }
-
- private <T extends JsVisitable> List<T> popList(int count) {
- List<T> list = new ArrayList<T>();
- while (count > 0) {
- T item = this.<T> pop();
- if (item != null) {
- list.add(item);
- }
- --count;
- }
- Collections.reverse(list);
- return list;
- }
-
- private <T extends JsVisitable<T>> void popList(List<T> collection,
- int count) {
- List<T> list = new ArrayList<T>();
- while (count > 0) {
- T item = this.<T> pop();
- if (item != null) {
- list.add(item);
- }
- --count;
- }
- Collections.reverse(list);
- collection.addAll(list);
- }
-
- private <T extends JsVisitable> void push(T node) {
- nodeStack.push(node);
- }
}
private static class JavaToJsOperatorMap {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java
new file mode 100644
index 0000000..a8cda95
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JBooleanLiteral;
+import com.google.gwt.dev.jjs.ast.JCharLiteral;
+import com.google.gwt.dev.jjs.ast.JDoubleLiteral;
+import com.google.gwt.dev.jjs.ast.JFloatLiteral;
+import com.google.gwt.dev.jjs.ast.JIntLiteral;
+import com.google.gwt.dev.jjs.ast.JLongLiteral;
+import com.google.gwt.dev.jjs.ast.JNullLiteral;
+import com.google.gwt.dev.jjs.ast.JStringLiteral;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsVisitable;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Translates Java literals into JavaScript literals.
+ */
+public class GenerateJavaScriptLiterals extends JVisitor {
+
+ private final JsProgram program;
+ private final Stack<JsVisitable<?>> nodeStack = new Stack<JsVisitable<?>>();
+
+ public GenerateJavaScriptLiterals(JsProgram program) {
+ this.program = program;
+ }
+
+ @Override
+ public final void endVisit(JBooleanLiteral x, Context ctx) {
+ push(x.getValue() ? program.getTrueLiteral() : program.getFalseLiteral());
+ }
+
+ @Override
+ public final void endVisit(JCharLiteral x, Context ctx) {
+ push(program.getIntegralLiteral(BigInteger.valueOf(x.getValue())));
+ }
+
+ @Override
+ public final void endVisit(JDoubleLiteral x, Context ctx) {
+ push(program.getDecimalLiteral(String.valueOf(x.getValue())));
+ }
+
+ @Override
+ public final void endVisit(JFloatLiteral x, Context ctx) {
+ push(program.getDecimalLiteral(String.valueOf(x.getValue())));
+ }
+
+ @Override
+ public final void endVisit(JIntLiteral x, Context ctx) {
+ push(program.getIntegralLiteral(BigInteger.valueOf(x.getValue())));
+ }
+
+ @Override
+ public final void endVisit(JLongLiteral x, Context ctx) {
+ push(program.getIntegralLiteral(BigInteger.valueOf(x.getValue())));
+ }
+
+ @Override
+ public final void endVisit(JNullLiteral x, Context ctx) {
+ push(program.getNullLiteral());
+ }
+
+ @Override
+ public final void endVisit(JStringLiteral x, Context ctx) {
+ push(program.getStringLiteral(x.getValue()));
+ }
+
+ public final <T extends JsVisitable> T peek() {
+ return (T) nodeStack.peek();
+ }
+
+ protected final <T extends JsVisitable> T pop() {
+ return (T) nodeStack.pop();
+ }
+
+ protected final <T extends JsVisitable> List<T> popList(int count) {
+ List<T> list = new ArrayList<T>();
+ while (count > 0) {
+ T item = this.<T> pop();
+ if (item != null) {
+ list.add(item);
+ }
+ --count;
+ }
+ Collections.reverse(list);
+ return list;
+ }
+
+ protected final <T extends JsVisitable> void popList(List<T> collection,
+ int count) {
+ List<T> list = new ArrayList<T>();
+ while (count > 0) {
+ T item = this.<T> pop();
+ if (item != null) {
+ list.add(item);
+ }
+ --count;
+ }
+ Collections.reverse(list);
+ collection.addAll(list);
+ }
+
+ protected final <T extends JsVisitable> void push(T node) {
+ nodeStack.push(node);
+ }
+}
\ No newline at end of file