blob: a78eef60fc8e5aeade3770d646ff08742cd9630f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.debugger.jpda.expr;
import java.util.Random;
/**
* Represents an pre-parsed Java expression to be later evaluated in a specific JVM context.
* The expression can have a 1.4 or 1.5 syntax.
*
*
* Uses Compiler API
* 1) Generate a method (like evaluate_<long random number>), which takes all local variables as arguments
* 2) Add that method into the current source file
* 3) Compile the current source file, like http://www.javabeat.net/javabeat/java6/articles/java_6_0_compiler_api_4.php
* 4) Traverse the parsed tree and perform the evaluation - http://java.sun.com/javase/6/docs/jdk/api/javac/tree/com/sun/source/util/JavacTask.html
* 5) Instead of (4) it would be cool to be able to do a hot-swap. But we can not add new methods. :-(
*
*
* @author Martin Entlicher
*/
public class JavaExpression {
public static final String LANGUAGE_JAVA_1_5 = "1.5.0"; // NOI18N
private static final String REPLACE_return = "return01234";
private static final String REPLACE_class = "class01234";
static final String RETURN_MACRO = "{return}";
static final String CLASS_MACRO = "{class}";
private String strExpression;
private String language;
private String replace_return;
private String replace_class;
/**
* Creates a new expression by pre-parsing the given String representation of the expression.
*
* @param expr textual representation of an expression
* @param language one of the LANGUAGE_XXX constants
* @return pre-parsed Java expression
* @throws ParseException if the expression has wrong syntax
*/
public static JavaExpression parse (String expr, String language) {
//throws ParseException {
String replace_return = REPLACE_return;
while (expr.indexOf(replace_return) >= 0) {
replace_return = "return" + new Random().nextLong(); // NOI18N
}
String replace_class = REPLACE_class;
while (expr.indexOf(replace_class) >= 0) {
replace_class = "class" + new Random().nextLong(); // NOI18N
}
String replacedExpr = replaceSpecialVar(expr, RETURN_MACRO, replace_return); // NOI18N
replacedExpr = replaceSpecialVar(replacedExpr, CLASS_MACRO, replace_class); // NOI18N
return new JavaExpression(replacedExpr, language, replace_return, replace_class);
}
private static String replaceSpecialVar(String expr, String var, String replace_var) {
int i = expr.indexOf(var);
while (i >= 0) {
boolean replace;
if (i > 0) {
char ch = expr.charAt(i - 1);
if (Character.isJavaIdentifierStart(ch) ||
Character.isJavaIdentifierPart(ch) ||
ch == '.') {
replace = false;
} else {
replace = true;
}
} else {
replace = true;
}
if (replace && i < (expr.length() - var.length())) {
char ch = expr.charAt(i + var.length());
if (Character.isJavaIdentifierPart(ch)) {
replace = false;
}
}
if (replace) {
expr = expr.substring(0, i) + replace_var + expr.substring(i + var.length());
i += replace_var.length();
} else {
i += var.length();
}
i = expr.indexOf(var, i);
}
return expr;
}
private JavaExpression(String expression, String language,
String replace_return, String replace_class) {
strExpression = expression;
this.language = language;
this.replace_return = replace_return;
this.replace_class = replace_class;
}
/**
* Creates an evaluator engine that can be used to evaluate this expression in a given
* runtime JVM context.
*
* @param context a runtime JVM context
* @return the evaluator engine
*/
public TreeEvaluator evaluator(EvaluationContext context,
CompilationInfoHolder ciHolder) {
return new TreeEvaluator(this, context, ciHolder);
}
public String getLanguage() {
return language;
}
public String getExpression() {
return strExpression;
}
String returnReplaced() {
return replace_return;
}
String classReplaced() {
return replace_class;
}
}