com.dragome.compiler.generators.DragomeJavaScriptGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dragome-bytecode-js-compiler Show documentation
Show all versions of dragome-bytecode-js-compiler Show documentation
Dragome SDK module: bytecode to javascript compiler
/*******************************************************************************
* Copyright (c) 2011-2014 Fernando Petrola
*
* This file is part of Dragome SDK.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
******************************************************************************/
package com.dragome.compiler.generators;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
import com.dragome.commons.compiler.annotations.DragomeCompilerSettings;
import com.dragome.commons.compiler.annotations.MethodAlias;
import com.dragome.compiler.DragomeJsCompiler;
import com.dragome.compiler.Project;
import com.dragome.compiler.ast.ASTNode;
import com.dragome.compiler.ast.ArrayAccess;
import com.dragome.compiler.ast.ArrayCreation;
import com.dragome.compiler.ast.ArrayInitializer;
import com.dragome.compiler.ast.Assignment;
import com.dragome.compiler.ast.Block;
import com.dragome.compiler.ast.BooleanLiteral;
import com.dragome.compiler.ast.BreakStatement;
import com.dragome.compiler.ast.CastExpression;
import com.dragome.compiler.ast.CatchClause;
import com.dragome.compiler.ast.ClassInstanceCreation;
import com.dragome.compiler.ast.ClassLiteral;
import com.dragome.compiler.ast.ConditionalExpression;
import com.dragome.compiler.ast.ContinueStatement;
import com.dragome.compiler.ast.DoStatement;
import com.dragome.compiler.ast.Expression;
import com.dragome.compiler.ast.FieldAccess;
import com.dragome.compiler.ast.FieldRead;
import com.dragome.compiler.ast.IfStatement;
import com.dragome.compiler.ast.InfixExpression;
import com.dragome.compiler.ast.InstanceofExpression;
import com.dragome.compiler.ast.MethodBinding;
import com.dragome.compiler.ast.MethodDeclaration;
import com.dragome.compiler.ast.MethodInvocation;
import com.dragome.compiler.ast.Name;
import com.dragome.compiler.ast.NullLiteral;
import com.dragome.compiler.ast.NumberLiteral;
import com.dragome.compiler.ast.PostfixExpression;
import com.dragome.compiler.ast.PrefixExpression;
import com.dragome.compiler.ast.PrimitiveCast;
import com.dragome.compiler.ast.ReturnStatement;
import com.dragome.compiler.ast.StringLiteral;
import com.dragome.compiler.ast.SwitchCase;
import com.dragome.compiler.ast.SwitchStatement;
import com.dragome.compiler.ast.SynchronizedBlock;
import com.dragome.compiler.ast.ThisExpression;
import com.dragome.compiler.ast.ThrowStatement;
import com.dragome.compiler.ast.TryStatement;
import com.dragome.compiler.ast.TypeDeclaration;
import com.dragome.compiler.ast.VariableBinding;
import com.dragome.compiler.ast.VariableDeclaration;
import com.dragome.compiler.ast.WhileStatement;
import com.dragome.compiler.parser.Pass1;
import com.dragome.compiler.type.Signature;
import com.dragome.compiler.units.ClassUnit;
import com.dragome.compiler.units.FieldUnit;
import com.dragome.compiler.units.ProcedureUnit;
import com.dragome.compiler.utils.Log;
import com.dragome.compiler.utils.Utils;
public class DragomeJavaScriptGenerator extends Generator
{
public static final String DRAGOME_PACKAGE= "dragome";
private static int parametersSignaturesCounter;
public static Map parametersSignatures= new LinkedHashMap();
private ASTNode currentNode;
private MethodDeclaration currentMethodDeclaration;
private Project project;
private ByteArrayOutputStream baStream= new ByteArrayOutputStream();
// private List superMethods= new ArrayList();
public DragomeJavaScriptGenerator(Project theProject)
{
super();
project= theProject;
setOutputStream(new PrintStream(baStream));
}
private String reset()
{
flush();
String s= baStream.toString();
baStream.reset();
return s;
}
private void consume(Object object)
{
object= object == null ? object : object;
}
public void visit(TypeDeclaration theTypeDecl)
{
Map annotations= theTypeDecl.getAnnotations();
ClassUnit classUnit= project.getClassUnit(theTypeDecl.getType());
lastChar= '\0';
currentNode= null;
depth= 0;
typeDecl= theTypeDecl;
boolean isInterface= Modifier.isInterface(typeDecl.getAccess());
String type= isInterface ? "Interface" : "Class";
print("qx." + type + ".define(\"");
print(normalizeExpression(theTypeDecl.getClassName()));
println("\", ");
println("{");
depth++;
if (classUnit.getSuperUnit() != null)
{
String superUnitName= normalizeExpression(classUnit.getSuperUnit().getName());
print("extend: " + superUnitName);
println(",");
}
else
{
if (!classUnit.getName().equals("java.lang.Object"))
{
print("extend: java_lang_Object");
}
else
{
print("extend: qx.core.Object");
}
println(",");
}
if (!classUnit.getName().equals("java.lang.Object"))
println("construct: function(){},");
classUnit.setData(reset());
List fields= theTypeDecl.getFields();
for (int i= 0; i < fields.size(); i++)
{
VariableDeclaration decl= (VariableDeclaration) fields.get(i);
if (decl.getLocation() == VariableDeclaration.NON_LOCAL)
{
// if (Modifier.isStatic(decl.getModifiers()))
// continue;
// indent();
decl.visit(this);
//println(",");
}
}
depth--;
// String superType= null;
//
// if (theTypeDecl.getSuperType() != null && !Modifier.isInterface(theTypeDecl.getAccess()))
// {
// superType= Project.getSingleton().getSignature(theTypeDecl.getSuperType().getClassName()).getCommentedId();
// }
// for (int i= 0; i < fields.size(); i++)
// {
// VariableDeclaration decl= (VariableDeclaration) fields.get(i);
//
// if (!Modifier.isStatic(decl.getModifiers()))
// continue;
// indent();
// decl.visit(this);
// println(";");
// }
depth++;
MethodDeclaration[] methods= theTypeDecl.getMethods();
List processedMethods= new ArrayList();
for (int i= 0; i < methods.length; i++)
{
MethodDeclaration method= methods[i];
currentMethodDeclaration= method;
try
{
String normalizeExpression= normalizeExpression(Project.getSingleton().getSignature(method.getMethodBinding().toString()).relative());
if (!processedMethods.contains(normalizeExpression))
{
processedMethods.add(normalizeExpression);
method.visit(this);
}
else
System.out.println("duplicado!");
// System.out.println("llego!");
}
catch (RuntimeException ex)
{
throw Utils.generateException(ex, method, currentNode);
}
}
processedMethods.clear();
depth--;
reset();
depth++;
//addSuperMethodsDefinition();
depth--;
classUnit.setData(classUnit.getData() + reset());
}
// private void addSuperMethodsDefinition()
// {
// for (MethodInvocation methodInvocation : superMethods)
// {
// indent();
// String declaringClass= normalizeExpression(methodInvocation.getMethodBinding().getDeclaringClass().getClassName());
// String signature= normalizeExpression(getSignatureOfInvocation(methodInvocation));
//
// print("this.");
// print(declaringClass);
// print("_");
// print(signature);
// print("= ");
// print("this.");
// print(signature);
// println(";");
// }
//
// superMethods.clear();
// }
public void visit(MethodDeclaration method)
{
String local_alias= method.getAnnotationsValues().get(MethodAlias.class.getName() + "#" + "local_alias");
boolean hasLocalAlias= local_alias != null;
String className= normalizeExpression(method.getMethodBinding().getDeclaringClass().getClassName());
String annotationKey= DragomeCompilerSettings.class.getName() + "#" + "value";
String compiler= DragomeJsCompiler.compiler.compilerType.name();
String methodCompilerType= method.getAnnotationsValues().get(annotationKey);
String classCompilerType= typeDecl.getAnnotations().get(annotationKey);
if (methodCompilerType != null)
compiler= methodCompilerType;
else if (classCompilerType != null)
compiler= classCompilerType;
// String className2= method.getMethodBinding().getDeclaringClass().getClassName();
// !className2.startsWith("java.lang") && (method.getAnnotationsValues().get("alias") == null || className2.contains("JSONTokener")
if ("Strict".equalsIgnoreCase(compiler))
{
ClassUnit classUnit= project.getClassUnit(method.getMethodBinding().getDeclaringClass().getClassName());
classUnit.addNotReversibleMethod(Pass1.extractMethodNameSignature(method.getMethodBinding()));
}
MethodBinding methodBinding= method.getMethodBinding();
ProcedureUnit unit= project.getProcedureUnit(methodBinding);
boolean isNative= Modifier.isNative(method.getAccess());
// if (method.getBody() == null && isNative)
// {
// if (isNative || Modifier.isAbstract(method.getAccess()) || Modifier.isInterface(typeDecl.getAccess()))
// {
// return;
// }
// throw new RuntimeException("Method " + method + " with access " + method.getAccess() + " may not have empty body");
// }
// if (!dragomeJsCompiler.compiler.isCompression())
// {
// println("/* " + unit.getAbsoluteSignature() + " */");
// }
String closingString;
Signature signature= Project.getSingleton().getSignature(methodBinding.toString()).relative();
String signatureReplaced= normalizeExpression(signature);
if (typeDecl.getClassName().equals("java.lang.String") && method.isInstanceConstructor())
{
Block body= method.getBody();
body.removeChild(body.getFirstChild());
MethodInvocation consume= (MethodInvocation) body.getLastChild();
body.removeChild(consume);
ReturnStatement r= new ReturnStatement(0, 0);
r.setExpression((Expression) consume.getArguments().get(0));
body.appendChild(r);
print("_dragomeJs.StringInit" + signatureReplaced + " = function(");
closingString= "};\n";
}
else
{
if (Modifier.isStatic(method.getAccess()))
{
print(ClassUnit.STATIC_MEMBER);
// print(className + ".");
}
else
{
// if (typeDecl.getClassName().equals("java.lang.String"))
// print("String.prototype." + signatureReplaced + "=");
// print("this.");
}
print(signatureReplaced);
print(": ");
String alias= method.getAnnotationsValues().get(MethodAlias.class.getName() + "#" + "alias");
if (alias != null)
print(alias + "= ");
if (hasLocalAlias)
print(className + "_$_" + local_alias + "= ");
print("function (");
closingString= "}";
}
printParams(method);
println(")");
println("{");
depth= 1;
Collection localVariables= method.getLocalVariables();
if (localVariables.size() > 0)
print("var ");
int i= 0;
for (VariableDeclaration decl : localVariables)
{
decl.visit(this);
if (++i < localVariables.size())
print(",");
}
if (localVariables.size() > 0)
println(";");
depth= 0;
if (method.getBody() != null)
visit_(method.getBody());
else if (isNative)
println("return dragomeJs.resolveNativeMethod(this, \"" + signatureReplaced + "\").apply(this, arguments);");
if (method.isInstanceConstructor())
print("return this;\n");
print(closingString);
if (hasLocalAlias)
{
print(", \n");
print(local_alias + ": " + className + "_$_" + local_alias);
}
unit.setData(reset());
Log.getLogger().debug("Generating JavaScript for " + unit);
}
private void printParams(MethodDeclaration method)
{
Iterator iterator= method.getParameters().iterator();
while (iterator.hasNext())
{
VariableDeclaration decl= iterator.next();
// if (hasToEscapeVariable(decl.getName()))
// print("_");
decl.visit(this);
print(iterator.hasNext() ? ", " : "");
}
}
public static String normalizeExpression(Object object)
{
if (object instanceof Signature)
{
Signature signature= (Signature) object;
String string= signature.toString();
string= string.replaceAll("\\[\\]", "_ARRAYTYPE");
String result= string.replaceAll("\\(\\)", "\\$");
result= result.replaceAll("\\)", "\\$").replaceAll("\\(", "___").replaceAll("\\.", "_").replaceAll(",", "__").replaceAll("<", "").replaceAll(">", "").replaceAll("\\[", "_").replaceAll("\\]", "_").replaceAll(";", "\\$");
if (signature.isMethod() || signature.isConstructor())
{
result= "$" + result;
if (signature.isConstructor())
{
result= result.replaceAll("___$", "");
result= result.replace("$init", "$init_");
return "$" + result;
}
else
{
result= result.replaceAll("___$", "");
if (result.contains("clinit"))
result= "$" + result + "_";
if ("$$clinit$void_".equals(result))
result= "$$clinit_";
return result;
}
}
return result;
}
else
{
String string= object.toString();
string= string.replaceAll("\\[\\]", "_ARRAYTYPE");
//string= modifyMethodName(string);
return string.replaceAll("\\(", "_").replaceAll("\\)", "_").replaceAll("\\.", "_").replaceAll(",", "__").replaceAll("<", "_").replaceAll(">", "_").replaceAll("\\[", "_").replaceAll("\\]", "_").replaceAll(";", "\\$");
}
}
public static String modifyMethodName(String string)
{
if (string.contains("("))
{
int indexOf= string.indexOf("(");
String parametersPart= string.substring(indexOf);
Integer counter= parametersSignatures.get(parametersPart);
if (counter == null)
parametersSignatures.put(parametersPart, counter= ++parametersSignaturesCounter);
string= string.substring(0, indexOf) + "_" + counter;
}
return string;
}
public void visit(DoStatement doStmt)
{
println("do {");
visit_(doStmt.getBlock());
indent("} while (");
doStmt.getExpression().visit(this);
print(")");
}
public void visit(WhileStatement whileStmt)
{
print("while (");
whileStmt.getExpression().visit(this);
println(") {");
visit_(whileStmt.getBlock());
indent("}");
}
public void visit(IfStatement ifStmt)
{
print("if (");
ifStmt.getExpression().visit(this);
println(") {");
visit_(ifStmt.getIfBlock());
indent("}");
if (ifStmt.getElseBlock() != null)
{
println(" else {");
visit_(ifStmt.getElseBlock());
indent("}");
}
}
public void visit(TryStatement tryStmt)
{
println("try {");
visit_(tryStmt.getTryBlock());
indent("} ");
Block clauses= tryStmt.getCatchStatements();
CatchClause clause= (CatchClause) clauses.getFirstChild();
String ex= null;
if (clause != null)
{
ex= clause.getException().getName();
}
// if (clauses.getChildCount() == 1)
// {
// print("catch(" + ex + ") ");
// clause.visit(this);
// }
if (clauses.getChildCount() > 0)
{
println("catch(" + ex + ") {");
depth++;
indent();
while (clause != null)
{
if (clause.getException().getType() != null)
print("if (dragomeJs.isInstanceof(" + ex + ", " + normalizeExpression(Utils.getSignature(clause.getException().getType())) + ")) ");
else
print("if (true)");
clause.visit(this);
clause= (CatchClause) clause.getNextSibling();
if (clause == null)
break;
print(" else ");
}
print(" else throw dragomeJs.nullSaveException(" + ex + "); ");
println("");
depth--;
indent("}");
}
Block finallyBlock= tryStmt.getFinallyBlock();
if (finallyBlock != null)
{
println(" finally {");
visit_(finallyBlock);
indent("}");
}
}
public void visit(CatchClause clause)
{
visit((Block) clause);
}
public void visit_(Block block)
{
depth++;
ASTNode node= block.getFirstChild();
while (node != null)
{
currentNode= node;
if (DragomeJsCompiler.compiler.isGenerateLineNumbers())
{
int lineNumber= currentMethodDeclaration.getLineNumberCursor().getAndMarkLineNumber(node);
if (lineNumber != -1)
{
print("//ln=" + lineNumber + ";\n");
}
}
indent();
if (node instanceof Block && ((Block) node).isLabeled())
{
print(((Block) node).getLabel() + ": ");
}
node.visit(this);
if (lastChar == '}')
{
println("");
}
else if (lastChar == ';')
{
getOutputStream().println("");
}
else
{
println(";");
}
node= node.getNextSibling();
}
depth--;
}
public void visit(Block block)
{
println("{");
visit_(block);
indent("}");
}
public void visit(SynchronizedBlock block)
{
println("{ // Synchronized.");
visit_(block);
indent("}");
}
public void visit(PrefixExpression binOp)
{
print(binOp.getOperator().toString() + "(");
binOp.getOperand().visit(this);
print(")");
}
public void visit(PostfixExpression binOp)
{
binOp.getOperand().visit(this);
print(binOp.getOperator().toString());
}
private void bracket(ASTNode node, InfixExpression.Operator op)
{
boolean b= false; //node instanceof InfixExpression && ((InfixExpression) node).getOperator() == op;
if (b || node instanceof NumberLiteral || node instanceof NullLiteral || node instanceof FieldAccess || node instanceof VariableBinding)
{
node.visit(this);
}
else
{
print("(");
node.visit(this);
print(")");
}
}
public void visit(InfixExpression binOp)
{
InfixExpression.Operator op= binOp.getOperator();
Expression left= binOp.getLeftOperand();
Expression right= binOp.getRightOperand();
boolean isTruncate= false;
Type type= binOp.getTypeBinding();
if (op == InfixExpression.Operator.DIVIDE && (type.equals(Type.LONG) || type.equals(Type.INT)))
{
isTruncate= true;
print("dragomeJs.trunc(");
}
bracket(left, op);
// boolean leftIsObject= ObjectType.class.isAssignableFrom(left.getTypeBinding().getClass());
// boolean rightIsObject= ObjectType.class.isAssignableFrom(right.getTypeBinding().getClass());
// boolean isEqualOrNotEqual= op.toString().equals("==") || op.toString().equals("!=");
//
// if ((leftIsObject && rightIsObject) && isEqualOrNotEqual)
// print(" " + op + "= ");
// else
print(" " + op + " ");
bracket(right, op);
if (isTruncate)
{
print(")");
}
}
public void visit(ConditionalExpression ce)
{
ce.getConditionExpression().visit(this);
print("?");
ce.getThenExpression().visit(this);
print(":");
ce.getElseExpression().visit(this);
}
public void visit(InstanceofExpression node)
{
print("dragomeJs.isInstanceof (");
node.getLeftOperand().visit(this);
print(", ");
Signature signature= Project.getSingleton().getArraySignature(node.getRightOperand());
print(normalizeExpression(signature.toString()));
print(")");
// print ("true");
}
public void visit(SwitchStatement switchStmt)
{
print("switch (");
switchStmt.getExpression().visit(this);
println(") {");
ASTNode node= switchStmt.getFirstChild();
while (node != null)
{
SwitchCase sc= (SwitchCase) node;
sc.visit(this);
node= node.getNextSibling();
}
indentln("}");
}
public void visit(SwitchCase switchCase)
{
Iterator iter= switchCase.getExpressions().iterator();
if (iter.hasNext())
{
while (iter.hasNext())
{
NumberLiteral expression= iter.next();
indent("case ");
expression.visit(this);
println(":");
}
}
else
{
indentln("default:");
}
visit_(switchCase);
}
public void visit(ASTNode stmt)
{
print(stmt.toString());
}
public void visit(ReturnStatement r)
{
print("return");
if (r.getExpression() != null)
{
print(" ");
r.getExpression().visit(this);
}
}
public void visit(Assignment a)
{
Expression rhs= a.getRightHandSide();
if (rhs instanceof ClassInstanceCreation)
{
ClassInstanceCreation cic= (ClassInstanceCreation) rhs;
if (cic.getTypeBinding().toString().equals("java.lang.String"))
{
return;
}
}
a.getLeftHandSide().visit(this);
print(" " + a.getOperator() + " ");
if (VariableBinding.isBoolean(a.getLeftHandSide()))
{
if (NumberLiteral.isZero(rhs))
{
print("false");
}
if (NumberLiteral.isOne(rhs))
{
print("true");
}
else
{
rhs.visit(this);
}
}
else
{
rhs.visit(this);
}
}
public void visit(NumberLiteral literal)
{
print("" + literal.getValue());
}
public void visit(StringLiteral literal)
{
print(Utils.escape(literal.getValue()));
}
public void visit(ClassLiteral literal)
{
MethodBinding binding= MethodBinding.lookup("java.lang.Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
MethodInvocation mi= new MethodInvocation(currentMethodDeclaration, binding);
mi.addArgument(new StringLiteral(literal.getSignature().toString()));
visit(mi);
}
public void visit(NullLiteral literal)
{
consume(literal);
print("null");
}
private void generateList(List arguments)
{
for (int i= 0; i < arguments.size(); i++)
{
print(i == 0 ? "" : ", ");
((ASTNode) arguments.get(i)).visit(this);
}
}
private boolean isW3C(MethodInvocation invocation)
{
MethodBinding methodBinding= invocation.getMethodBinding();
String name= methodBinding.getName();
int argCount= invocation.getArguments().size();
boolean isSetter= name.startsWith("set") && argCount == 1;
boolean isGetter= name.startsWith("get") && argCount == 0;
if (!isSetter && !isGetter)
return false;
if (methodBinding.equals("org.w3c.dom5.NamedNodeMap"))
{
if (name.equals("setNamedItemNS") || name.equals("setNamedItem"))
return false;
}
if (methodBinding.equals("org.w3c.dom5.Element"))
{
if (name.equals("setAttributeNode") || name.equals("setAttributeNodeNS"))
return false;
}
if (name.equals("getContentDocument"))
return false;
if (name.equals("getButton"))
return false;
return true;
}
private void generateScriptCode(MethodInvocation invocation)
{
MethodBinding methodBinding= invocation.getMethodBinding();
String name= methodBinding.getName();
List args= invocation.getArguments();
String firstArg= null;
boolean isVariable= false;
if (!(args.get(0) instanceof StringLiteral))
{
if (args.get(0) instanceof VariableBinding)
{
VariableBinding variableBinding= (VariableBinding) args.get(0);
firstArg= variableBinding.getName();
isVariable= true;
}
else if (args.get(0) instanceof MethodInvocation)
{
}
else
throw new RuntimeException("First argument to " + methodBinding + " must be a string literal");
}
else
firstArg= ((StringLiteral) args.get(0)).getValue();
if (name.equals("put") || name.equals("putMethodReference"))
{
if (isVariable)
{
print("eval(\"var \"+");
print(firstArg + "+\"=");
((ASTNode) args.get(1)).visit(this);
print("\")");
}
else
{
if (firstArg.indexOf('.') == -1)
{
print("var ");
}
print(firstArg + "=");
((ASTNode) args.get(1)).visit(this);
}
}
else if (name.startsWith("eval"))
{
String evalScript= firstArg;
if (firstArg == null && args.get(0) instanceof MethodInvocation)
{
MethodInvocation methodInvocation= (MethodInvocation) args.get(0);
print("eval(");
methodInvocation.visit(this);
print(")");
}
else
{
if (isVariable)
evalScript= "eval(" + firstArg + ")";
if (name.startsWith("evalCasting"))
{
ASTNode nextSibling= invocation.getFirstChild().getNextSibling();
if (nextSibling instanceof ClassLiteral)
{
Signature signature= ((ClassLiteral) nextSibling).getSignature();
print("dragomeJs.castTo(" + evalScript + ", \"" + signature + "\")");
}
else
{
VariableBinding variableBinding= (VariableBinding) nextSibling;
print("dragomeJs.castTo2(" + evalScript + ", " + variableBinding.getName() + ")");
}
}
else
print(evalScript);
}
}
else
throw new IllegalArgumentException("Cannot handle method " + name);
}
private void generateArguments(MethodInvocation invocation)
{
Signature signature= getSignatureOfInvocation(invocation);
print(normalizeExpression(signature));
print("(");
generateList(invocation.getArguments());
print(")");
}
private static Signature getSignatureOfInvocation(MethodInvocation invocation)
{
MethodBinding methodBinding= invocation.getMethodBinding();
Signature signature= Project.getSingleton().getSignature(methodBinding.getDeclaringClass().getClassName());
signature= Project.getSingleton().getSignature(methodBinding.getRelativeSignature());
return signature;
}
public void visit(MethodInvocation invocation)
{
MethodBinding methodBinding= invocation.getMethodBinding();
String name= methodBinding.getName();
String className= methodBinding.getDeclaringClass().getClassName();
if (className.equals("com.dragome.commons.javascript.ScriptHelper"))
{
generateScriptCode(invocation);
return;
}
if (className.equals("javax.script.ScriptEngine") && (name.equals("put") || name.equals("eval")))
{
generateScriptCode(invocation);
return;
}
ASTNode expression= invocation.getExpression();
// expression.visit(this);
// } else {
// //throw new UnsupportedOperationException("Invocation of " +
// methodBinding + " not supported");
// }
// //return;
// }
if (className.equals("java.lang.String") && methodBinding.isConstructor())
{
if (expression instanceof VariableBinding)
{
expression.visit(this);
print(" = ");
}
else
{
assert expression instanceof ClassInstanceCreation;
}
Signature signature= Project.getSingleton().getSignature(methodBinding.toString()).relative();
String signatureReplaced= normalizeExpression(signature);
print("dragomeJs.StringInit" + signatureReplaced + "(");
// print("dragomeJs.StringInit" + signature.getId() + "(");
generateList(invocation.getArguments());
print(")");
return;
}
if (invocation.isSuper(typeDecl.getClassName()))
{
// print(prefix);
// print(INVOKESUPER);
// print("(");
String string= "arguments.callee.self.superclass.prototype.{methodName}.call(this";
if (methodBinding.getDeclaringClass().referencesInterface())
{
String invokeClassName= normalizeExpression(methodBinding.getDeclaringClass());
string= invokeClassName + ".$$members.{methodName}.call(this";
}
if (Modifier.isStatic(invocation.methodDecl.getAccess()))
string= "this.superclass.prototype.{methodName}.call(arguments[0]";
Signature signature= getSignatureOfInvocation(invocation);
String methodName= normalizeExpression(signature);
string= string.replace("{methodName}", methodName);
if (invocation.getArguments().isEmpty())
{
print(string);
print(")");
}
else
{
print(string);
print(", ");
generateList(invocation.getArguments());
print(")");
}
// print("this.");
// String declaringClass= normalizeExpression(methodBinding.getDeclaringClass().getClassName());
// print(declaringClass);
// print("_");
// // generateArguments(invocation);
// generateList(invocation.getArguments());
// print(")");
// superMethods.add(invocation);
// if (expression == null)
// {
// print("null");
// }
// else
// {
// expression.visit(this);
// }
// print(", ");
}
else if (invocation.isSpecial)
{
// print(getSignatureReference(Signature.getSignature(className)));
// print(", ");
if (methodBinding.isConstructor() && expression instanceof ThisExpression && !"java.lang.String".equals(className))
{
String normalizeExpression= normalizeExpression(className);
print(normalizeExpression);
print(".prototype.");
Signature signature= getSignatureOfInvocation(invocation);
print(normalizeExpression(signature));
print(".call(this");
if (!invocation.getArguments().isEmpty())
print(",");
generateList(invocation.getArguments());
print(")");
}
else
{
expression.visit(this);
print(".");
generateArguments(invocation);
}
}
else if (expression == null)
{
boolean isStatic= true;//Modifier.isStatic(invocation.methodDecl.getAccess());
Signature signature= Project.getSingleton().getSignature(methodBinding.getDeclaringClass().getClassName());
// if (isStatic)
// print("_getClassForStatic(");
print(normalizeExpression(signature));
// if (isStatic)
// {
// print(", \"");
// Signature signature2= getSignatureOfInvocation(invocation);
// print(normalizeExpression(signature2));
// print("\")");
// }
print(".");
generateArguments(invocation);
}
else
{
boolean ready= false;
if (expression instanceof CastExpression)
{
CastExpression castExpression= (CastExpression) expression;
if (castExpression.getExpression() instanceof MethodInvocation)
{
MethodInvocation methodInvocation= (MethodInvocation) castExpression.getExpression();
MethodBinding methodBinding2= methodInvocation.getMethodBinding();
if (methodBinding2.toString().startsWith("com.dragome.commons.javascript.ScriptHelper#putMethodReference"))
{
Signature signature= getSignatureOfInvocation(invocation);
String normalizeExpression= normalizeExpression(signature);
String varName= ((StringLiteral) methodInvocation.getArguments().get(0)).getValue();
Object classContainer= methodInvocation.getArguments().get(1);
String ownerClass= "";
if (classContainer instanceof ClassLiteral)
{
ownerClass= "\"" + ((ClassLiteral) classContainer).getSignature().toString() + "\"";
}
else if (classContainer instanceof VariableBinding)
{
VariableBinding variableBinding= (VariableBinding) classContainer;
ownerClass= variableBinding.getName() + ".$getName$java_lang_String()";
}
print("var " + varName + "= dragomeJs.resolveMethod (" + ownerClass + ", \"" + normalizeExpression + "\")");
ready= true;
}
}
}
if (!ready)
{
expression.visit(this);
print(".");
generateArguments(invocation);
}
}
}
public void visit(ClassInstanceCreation cic)
{
// print(prefix);
// print(NEWINSTANCE);
// print("(");
print("new ");
Object className= Project.getSingleton().getSignature(((ObjectType) cic.getTypeBinding()).getClassName());
print(normalizeExpression(className));
// print(Project.getSingleton().getSignature(((ObjectType) cic.getTypeBinding()).getClassName()).getCommentedId());
print("(");
if (cic.getMethodBinding() != null)
{
// We never get here!
print(", ");
generateArguments(cic);
}
print(")");
}
public void visit(ArrayInitializer ai)
{
print("[");
for (int i= 0; i < ai.getExpressions().size(); i++)
{
print(i == 0 ? "" : ", ");
((ASTNode) ai.getExpressions().get(i)).visit(this);
}
print("]");
}
public void visit(ArrayCreation ac)
{
if (ac.getDimensions().size() <= 0)
{
throw new RuntimeException("Expected array dimension > 0, but was" + ac.getDimensions().size());
}
if (ac.getInitializer() != null)
{
ac.getInitializer().visit(this);
}
else
{
print("dragomeJs.newArray('");
Signature signature= Project.getSingleton().getArraySignature(ac.getTypeBinding());
print(signature.toString());
print("', [");
for (int i= 0; i < ac.getDimensions().size(); i++)
{
print(i == 0 ? "" : ", ");
ac.getDimensions().get(i).visit(this);
}
print("])");
}
}
public void visit(ArrayAccess aa)
{
aa.getArray().visit(this);
print("[");
aa.getIndex().visit(this);
print("]");
}
private String normalizeAccess(FieldAccess fr)
{
String prefix= "$$$";
if (fr.getFirstChild() instanceof FieldRead)
{
FieldRead fieldRead= (FieldRead) fr.getFirstChild();
// if (variableBinding.getTypeBinding() instanceof ArrayType)
// prefix="";
}
if ("length".equals(fr.getName()))
{
// if (!fr.getTypeBinding().equals(Type.UNKNOWN))
// System.out.println("sdgsdg");
prefix= "";
}
String name= prefix + fr.getName();
if (!fr.getName().matches("\\w*"))
{
// Name contains non-word characters, for example generated by
// AspectJ.
return "[\"" + name + "\"]";
}
return "." + name;
}
public void visit(VariableDeclaration decl)
{
String name= escapeVariable(decl.getName());
if (decl.getLocation() == VariableDeclaration.LOCAL_PARAMETER)
{
print(name);
return;
}
if (decl.getLocation() == VariableDeclaration.NON_LOCAL)
{
FieldUnit fieldUnit= project.getOrCreateFieldUnit(typeDecl.getType(), name);
if (Modifier.isStatic(decl.getModifiers()))
{
// print(normalizeExpression(typeDecl.toString()));
print(ClassUnit.STATIC_MEMBER);
}
else
{
// print("this");
}
print("$$$");
// print(normalizeAccess(name));
print(name);
initializeField(decl, ":");
fieldUnit.setData(reset());
return;
}
else
{
if (decl.getLocation() != VariableDeclaration.LOCAL)
throw new RuntimeException("Declaration must be local");
print(name);
}
initializeField(decl, "=");
}
private void initializeField(VariableDeclaration decl, String assignmentOperator)
{
if (!decl.isInitialized())
return;
print(" " + assignmentOperator + " ");
switch (decl.getType().getType())
{
case Constants.T_INT:
case Constants.T_SHORT:
case Constants.T_BYTE:
case Constants.T_LONG:
case Constants.T_DOUBLE:
case Constants.T_FLOAT:
case Constants.T_CHAR:
print("0");
break;
case Constants.T_BOOLEAN:
print("false");
break;
default:
print("null");
break;
}
}
public void visit(VariableBinding reference)
{
// if (!reference.isField()) {
// print("l");
// }
// if (reference.getVariableDeclaration().getLocation() == VariableDeclaration.LOCAL_PARAMETER)
print(escapeVariable(reference.getName()));
}
private boolean hasToEscapeVariable(String name)
{
return "function".equals(name) || "default".equals(name) || "var".equals(name) || "enum".equals(name) || "this".equals(name);
}
private String escapeVariable(String name)
{
if (hasToEscapeVariable(name))
return "_" + name;
else
return name;
}
public void visit(ThisExpression reference)
{
consume(reference);
print("this");
}
public void visit(FieldAccess fr)
{
ASTNode expression= fr.getExpression();
if (expression == null)
{
// Static access.
String normalizeExpression= normalizeExpression(Project.getSingleton().getSignature(fr.getType().getClassName()));
boolean sameType= currentMethodDeclaration.getMethodBinding().getDeclaringClass().equals(fr.getType());
if (true || "".equals(currentMethodDeclaration.getMethodBinding().getName()) && !sameType)
{
String clinitExpression= normalizeExpression(new Signature("()void", 0));
print("" + normalizeExpression + "." + clinitExpression + "()");
}
else
print(normalizeExpression);
}
else if (expression instanceof ThisExpression)
{
expression.visit(this);
}
else
{
//print(prefix + "cn(");
expression.visit(this);
//print(")");
}
print(normalizeAccess(fr));
}
public void visit(BreakStatement stmt)
{
print("break");
if (stmt.getLabel() != null)
{
print(" " + stmt.getLabel());
}
}
public void visit(ContinueStatement stmt)
{
print("continue");
if (stmt.getLabel() != null)
{
print(" " + stmt.getLabel());
}
}
public void visit(CastExpression cast)
{
if (cast.getTypeBinding() != Type.VOID && DragomeJsCompiler.compiler.compilerConfiguration.isCheckingCast())
{
print("dragomeJs.checkCast(");
cast.getExpression().visit(this);
String string= cast.getTypeBinding().toString();
String normalizeExpression= normalizeExpression(string);
if (string.startsWith("[L"))
normalizeExpression= "'" + string + "'";
print("," + normalizeExpression + ")");
}
else
{
// TODO: Is it correct to remove casts to void (i.e. pop)?
// print("void ");
cast.getExpression().visit(this);
}
}
public void visit(BooleanLiteral be)
{
print(Boolean.toString(be.getValue()));
}
public void visit(ThrowStatement node)
{
print("throw dragomeJs.nullSaveException(");
node.getExpression().visit(this);
print(")");
}
public void visit(Name node)
{
if (false && node.getIdentifier().equals("javascript.Global"))
{
print("self");
}
else
{
print(node.getIdentifier());
}
}
public void visit(PrimitiveCast node)
{
// TODO: Review cast to long.
Type type= node.getTypeBinding();
if (type.equals(Type.LONG))
{
print("dragomeJs.trunc(");
node.getExpression().visit(this);
print(")");
}
else if (type.equals(Type.INT))
{
print("dragomeJs.narrow(");
node.getExpression().visit(this);
print(", 0xffffffff)");
}
else if (type.equals(Type.SHORT))
{
print("dragomeJs.narrow(");
node.getExpression().visit(this);
print(", 0xffff)");
}
else if (type.equals(Type.BYTE))
{
print("dragomeJs.narrow(");
node.getExpression().visit(this);
print(", 0xff)");
}
else
node.getExpression().visit(this);
}
}