All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dragome.compiler.generators.DragomeJavaScriptGenerator Maven / Gradle / Ivy

There is a newer version: 0.96-beta4
Show newest version
/*******************************************************************************
 * 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);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy