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

com.dragome.compiler.parser.Parser 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
 ******************************************************************************/

// Copyright 2011 The j2js Authors. All Rights Reserved.
//
// This file is part of j2js.
//
// j2js is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// j2js is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with j2js. If not, see .

package com.dragome.compiler.parser;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.bcel.classfile.AnnotationEntry;
import org.apache.bcel.classfile.Annotations;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.AttributeReader;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.DescendingVisitor;
import org.apache.bcel.classfile.ElementValuePair;
import org.apache.bcel.classfile.EmptyVisitor;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
import org.apache.commons.io.IOUtils;

import com.dragome.commons.compiler.annotations.CompilerType;
import com.dragome.compiler.DragomeJsCompiler;
import com.dragome.compiler.Project;
import com.dragome.compiler.annotations.AnnotationReader;
import com.dragome.compiler.ast.ASTNode;
import com.dragome.compiler.ast.Block;
import com.dragome.compiler.ast.MethodBinding;
import com.dragome.compiler.ast.MethodDeclaration;
import com.dragome.compiler.ast.ReturnStatement;
import com.dragome.compiler.ast.ThrowStatement;
import com.dragome.compiler.ast.TypeDeclaration;
import com.dragome.compiler.ast.VariableDeclaration;
import com.dragome.compiler.exceptions.UnhandledCompilerProblemException;
import com.dragome.compiler.generators.DragomeJavaScriptGenerator;
import com.dragome.compiler.invokedynamic.InvokeDynamicBackporter;
import com.dragome.compiler.type.Signature;
import com.dragome.compiler.units.ClassUnit;
import com.dragome.compiler.utils.FileObject;
import com.dragome.compiler.utils.Log;
import com.dragome.compiler.utils.Utils;

public class Parser
{

	public static String getResourcePath(String name)
	{
		name= name.replace('.', '/') + ".class";
		java.net.URL url= Parser.class.getClassLoader().getResource(name);
		if (url == null)
			throw new RuntimeException("Resource not found: " + name);
		return url.getPath();
	}

	private JavaClass jc;

	private ClassUnit fileUnit;

	InvokeDynamicBackporter lambdaUsageBackporter= new InvokeDynamicBackporter();

	public Parser(ClassUnit theFileUnit)
	{
		fileUnit= theFileUnit;
		fileUnit.annotations= null;

		AttributeReader r= new AnnotationReader(fileUnit);
		Attribute.addAttributeReader("RuntimeVisibleAnnotations", r);

		try
		{
			InputStream openInputStream= fileUnit.getClassFile().openInputStream();

			String filename= fileUnit.getName();
			byte[] originalByteArray= IOUtils.toByteArray(openInputStream);
			byte[] transformedArray= originalByteArray;

			transformedArray= lambdaUsageBackporter.transform(filename, transformedArray);

			if (DragomeJsCompiler.compiler.bytecodeTransformer != null)
				if (DragomeJsCompiler.compiler.bytecodeTransformer.requiresTransformation(filename))
					transformedArray= DragomeJsCompiler.compiler.bytecodeTransformer.transform(filename, transformedArray);

			fileUnit.setBytecodeArrayI(transformedArray);

			ClassParser cp= new ClassParser(new ByteArrayInputStream(transformedArray), filename);
			jc= cp.parse();

		}
		catch (IOException e)
		{
			throw new RuntimeException(e);
		}
	}
	public TypeDeclaration parse()
	{
		DescendingVisitor classWalker= new DescendingVisitor(jc, new EmptyVisitor()
		{
			public void visitConstantClass(ConstantClass obj)
			{
				ConstantPool cp= jc.getConstantPool();
				String bytes= obj.getBytes(cp);
				fileUnit.addDependency(bytes.replace("/", "."));
			}
		});
		classWalker.visit();

		org.apache.bcel.classfile.Method[] bcelMethods= jc.getMethods();

		ObjectType type= new ObjectType(jc.getClassName());
		Map annotationsValues= getAnnotationsValues(jc.getAttributes());
		TypeDeclaration typeDecl= new TypeDeclaration(type, jc.getAccessFlags(), annotationsValues);
		Project.singleton.addTypeAnnotations(typeDecl);

		fileUnit.isInterface= Modifier.isInterface(typeDecl.getAccess());
		fileUnit.isAbstract= Modifier.isAbstract(typeDecl.getAccess());

		fileUnit.setAnnotations(annotationsValues);

		if (!type.getClassName().equals("java.lang.Object"))
		{

			ObjectType superType= new ObjectType(jc.getSuperclassName());
			typeDecl.setSuperType(superType);
			ClassUnit superUnit= Project.getSingleton().getOrCreateClassUnit(superType.getClassName());
			fileUnit.setSuperUnit(superUnit);

			String[] interfaceNames= jc.getInterfaceNames();
			for (int i= 0; i < interfaceNames.length; i++)
			{
				ObjectType interfaceType= new ObjectType(interfaceNames[i]);
				ClassUnit interfaceUnit= Project.getSingleton().getOrCreateClassUnit(interfaceType.getClassName());
				fileUnit.addInterface(interfaceUnit);
			}
		}

		Field[] fields= jc.getFields();
		for (int i= 0; i < fields.length; i++)
		{
			Field field= fields[i];
			VariableDeclaration variableDecl= new VariableDeclaration(VariableDeclaration.NON_LOCAL);
			variableDecl.setName(field.getName());
			variableDecl.setModifiers(field.getModifiers());
			variableDecl.setType(field.getType());

			typeDecl.addField(variableDecl);
		}

		for (int i= 0; i < bcelMethods.length; i++)
		{
			Method method= bcelMethods[i];

			Attribute[] attributes= method.getAttributes();

			Map methodAnnotationsValues= getAnnotationsValues(attributes);

			MethodBinding binding= MethodBinding.lookup(jc.getClassName(), method.getName(), method.getSignature());

			String genericSignature= method.getGenericSignature();
			if (genericSignature != null && !genericSignature.equals(method.getSignature()))
			{
				Signature signature= Project.getSingleton().getSignature(binding.toString()).relative();
				String normalizedSignature= DragomeJavaScriptGenerator.normalizeExpression(signature);
				String normalizedClassname= DragomeJavaScriptGenerator.normalizeExpression(type.getClassName());
				Project.getSingleton().addGenericSignature(normalizedClassname + "|" + normalizedSignature + "|" + genericSignature);
				//		System.out.println(genericSignature);
			}

			if (DragomeJsCompiler.compiler.getSingleEntryPoint() != null)
			{
				Signature signature= Project.getSingleton().getSignature(binding.toString());
				String singleSignature= DragomeJsCompiler.compiler.getSingleEntryPoint();
				if (!signature.toString().equals(singleSignature))
					continue;
			}

			MethodDeclaration methodDecl= new MethodDeclaration(binding, method.getAccessFlags(), method.getCode(), methodAnnotationsValues);
			typeDecl.addMethod(methodDecl);

			parseMethod(typeDecl, methodDecl, method);
		}

		return typeDecl;
	}

	private Map getAnnotationsValues(Attribute[] attributes)
	{
		Map result= new LinkedHashMap();
		for (Attribute attribute : attributes)
		{
			if (attribute instanceof Annotations)
			{
				Annotations annotations= (Annotations) attribute;
				AnnotationEntry[] entries= annotations.getAnnotationEntries();
				List newEntries= new ArrayList();
				for (AnnotationEntry entry : entries)
				{
					if (entry.getElementValuePairs().length == 0)
						result.put(Type.getType(entry.getAnnotationType()) + "# ", " ");

					for (int i= 0; i < entry.getElementValuePairs().length; i++)
					{
						ElementValuePair elementValuePair= entry.getElementValuePairs()[i];
						result.put(Type.getType(entry.getAnnotationType()) + "#" + elementValuePair.getNameString(), elementValuePair.getValue().toString());
					}
				}
			}
		}
		return result;
	}

	public void parseMethod(TypeDeclaration typeDecl, MethodDeclaration methodDecl, Method method)
	{
		Type[] types= method.getArgumentTypes();

		int offset;
		if (Modifier.isStatic(methodDecl.getAccess()))
		{
			offset= 0;
		}
		else
		{

			offset= 1;
		}
		for (int i= 0; i < types.length; i++)
		{
			VariableDeclaration variableDecl= new VariableDeclaration(VariableDeclaration.LOCAL_PARAMETER);
			variableDecl.setName(VariableDeclaration.getLocalVariableName(method, offset, 0));
			variableDecl.setType(types[i]);
			methodDecl.addParameter(variableDecl);
			offset+= types[i].getSize();
		}

		if (methodDecl.getCode() == null)
			return;

		Log.getLogger().debug("Parsing " + methodDecl.toString());
		Pass1 pass1= new Pass1(jc);

		try
		{
			pass1.parse(method, methodDecl);
		}
		catch (Throwable ex)
		{
			if (ex instanceof UnhandledCompilerProblemException)
			{
				Pass1.setClassNotReversible(methodDecl);
			}
			else
			{
				ASTNode node= null;
				if (ex instanceof ParseException)
				{
					node= ((ParseException) ex).getAstNode();
				}
				else
				{
					node= Pass1.getCurrentNode();
				}

				if (DragomeJsCompiler.compiler.isFailOnError())
				{
					throw Utils.generateException(ex, methodDecl, node);
				}
				else
				{
					fileUnit.addNotReversibleMethod(Pass1.extractMethodNameSignature(methodDecl.getMethodBinding()));
					//String msg= Utils.generateExceptionMessage(methodDecl, node);
					//DragomeJsCompiler.errorCount++;
					//		    Log.getLogger().error(msg + "\n" + Utils.stackTraceToString(ex));
				}

			}
			Block body= new Block();
			ThrowStatement throwStmt= new ThrowStatement();
			/*
			MethodBinding binding= MethodBinding.lookup("java.lang.RuntimeException", "", "(java/lang/String)V;");
			ClassInstanceCreation cic= new ClassInstanceCreation(methodDecl, binding);
			cic.addArgument(new StringLiteral("Unresolved decompilation problem"));
			throwStmt.setExpression(cic);
			body.appendChild(throwStmt);*/
			methodDecl.setBody(body);

		}

		if (DragomeJsCompiler.compiler.optimize && methodDecl.getBody().getLastChild() instanceof ReturnStatement)
		{
			ReturnStatement ret= (ReturnStatement) methodDecl.getBody().getLastChild();
			if (ret.getExpression() == null)
			{
				methodDecl.getBody().removeChild(ret);
			}
		}

		//		Pass1.dump(methodDecl.getBody(), "Body of " + methodDecl.toString());

		return;
	}

	public ConstantPool getConstantPool()
	{
		return jc.getConstantPool();
	}

	public String toString()
	{
		return jc.getClassName();
	}

	public static void main(String[] args) throws Exception
	{
		String className= args[0];
		DragomeJsCompiler.compiler= new DragomeJsCompiler(CompilerType.Standard);

		Project.createSingleton(null);
		ClassUnit classUnit= new ClassUnit(Project.singleton, Project.singleton.getSignature(className));
		classUnit.setClassFile(new FileObject(new File(args[1])));
		Parser parser= new Parser(classUnit);
		TypeDeclaration typeDecl= parser.parse();
		DragomeJavaScriptGenerator dragomeJavaScriptGenerator= new DragomeJavaScriptGenerator(Project.singleton);
		dragomeJavaScriptGenerator.setOutputStream(new PrintStream(new FileOutputStream(new File("/tmp/webapp.js"))));
		dragomeJavaScriptGenerator.visit(typeDecl);

		FileInputStream fis= new FileInputStream(new File("/tmp/webapp.js"));
		String md5= org.apache.commons.codec.digest.DigestUtils.md5Hex(fis);
		System.out.println(md5);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy