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

com.dragome.compiler.Project 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;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;

import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;

import com.dragome.compiler.ast.ArrayCreation;
import com.dragome.compiler.ast.FieldAccess;
import com.dragome.compiler.ast.MethodBinding;
import com.dragome.compiler.ast.MethodDeclaration;
import com.dragome.compiler.ast.MethodInvocation;
import com.dragome.compiler.ast.TypeDeclaration;
import com.dragome.compiler.parser.Pass1;
import com.dragome.compiler.type.Signature;
import com.dragome.compiler.type.TypeResolver;
import com.dragome.compiler.type.TypeVisitor;
import com.dragome.compiler.units.ClassUnit;
import com.dragome.compiler.units.ConstructorUnit;
import com.dragome.compiler.units.FieldUnit;
import com.dragome.compiler.units.MemberUnit;
import com.dragome.compiler.units.MethodUnit;
import com.dragome.compiler.units.ProcedureUnit;
import com.dragome.compiler.utils.Log;
import com.dragome.compiler.utils.Utils;

public class Project implements Serializable
{

	static final long serialVersionUID= 0;

	public static Project singleton;

	private Map classesByName;

	private ClassUnit javaLangObject;

	private boolean compressed;

	private boolean generateLineNumbers;

	private Map signatures;

	private transient Stack ids;

	private transient int currentId;

	private transient int currentIndex;

	public transient int currentGeneratedMethods;

	private List clinits= new ArrayList();

	private List genericSignatures= new ArrayList();

	transient private int badMethods= 0;

	public List writtenSignatures= new ArrayList();

	private Set typeDeclarationsWithAnnotations= new HashSet();

	public List getWrittenSignatures()
	{
		if (writtenSignatures == null)
			writtenSignatures= new ArrayList();

		return writtenSignatures;
	}

	public void writeClinits(Writer writer) throws IOException
	{
		//	for (String clinit : clinits)
		//	{
		//	    writer.write("new " + clinit.substring(0, clinit.indexOf(".")) + "();\n");
		//	}
		writer.write("new java_lang_String();\n");

		for (String clinit : clinits)
		{
			if (clinit.contains("java_lang_Class._clinit_"))
				writer.write(clinit + "\n");
		}

		for (String clinit : clinits)
		{
			writer.write(clinit + "\n");
		}
	}

	public List getClinits()
	{
		return clinits;
	}

	public void setClinits(List clinits)
	{
		this.clinits= clinits;
	}

	public static Project getSingleton()
	{
		if (singleton == null)
			throw new NullPointerException();
		return singleton;
	}

	public static Project createSingleton(File cacheFile)
	{

		if (cacheFile != null && cacheFile.exists())
		{
			Log.getLogger().debug("Using cache " + cacheFile);
			try
			{
				read(cacheFile);
			}
			catch (Exception e)
			{
				Log.getLogger().warn("Could not read cache:\n" + e.getMessage());
			}
		}

		if (singleton == null || singleton.compressed != DragomeJsCompiler.compiler.isCompression() || singleton.generateLineNumbers != DragomeJsCompiler.compiler.isGenerateLineNumbers())
		{
			singleton= new Project();
			singleton.clear();
		}

		return singleton;
	}

	private static void read(File file) throws Exception
	{
		FileInputStream fis= new FileInputStream(file);
		ObjectInputStream ois= new ObjectInputStream(fis);
		singleton= (Project) ois.readObject();
		ois.close();
	}

	public static void write() throws IOException
	{
		File file= DragomeJsCompiler.compiler.getCacheFile();
		if (file.exists() && !file.canWrite())
		{
			throw new IOException("Cannot write " + file);
		}
		FileOutputStream fos= new FileOutputStream(file);
		ObjectOutputStream oos= new ObjectOutputStream(fos);
		oos.writeObject(singleton);
		oos.close();
	}

	public Signature getArraySignature(Type type)
	{
		String signatureString= type.getSignature();

		if (!signatureString.startsWith("L") || !signatureString.endsWith(";"))
		{
			throw new RuntimeException("Not a class signature: " + signatureString);
		}
		signatureString= signatureString.substring(1, signatureString.length() - 1);
		return getSignature(signatureString);
	}

	public Signature getSignature(String signatureString)
	{
		if (signatureString.endsWith(";"))
		{

		}
		signatureString= signatureString.replaceAll("/", ".");

		Signature signature= signatures.get(signatureString);
		if (signature == null)
		{
			signature= new Signature(signatureString, getUniqueId());
			signatures.put(signatureString, signature);
		}

		return signature;
	}

	public Signature getSignature(String className, String relativeSignature)
	{
		return getSignature(className + '#' + relativeSignature);
	}

	public Signature getSignature(FieldAccess fa)
	{
		return getSignature(fa.getType().getClassName(), fa.getName());
	}

	private int getUniqueId()
	{
		if (ids == null)
		{
			ids= new Stack();
			for (Signature signature : signatures.values())
			{
				ids.add(signature.getId());
			}
			Collections.sort(ids);
		}

		while (currentIndex < ids.size() && ids.get(currentIndex) == currentId)
		{
			currentId+= 1;
			currentIndex+= 1;
		}

		currentId++;
		return currentId - 1;
	}

	private void clear()
	{
		classesByName= new LinkedHashMap();
		javaLangObject= null;

		signatures= new LinkedHashMap();
		ids= null;
		currentId= 0;
		currentIndex= 0;
		compressed= DragomeJsCompiler.compiler.isCompression();
		generateLineNumbers= DragomeJsCompiler.compiler.isGenerateLineNumbers();
		badMethods= 0;
		writtenSignatures= new ArrayList();
	}

	public void remove(ClassUnit clazz)
	{
		classesByName.remove(clazz);
	}

	public void visitSuperTypes(ClassUnit clazz, TypeVisitor visitor)
	{
		visitor.visit(clazz);
		ClassUnit superClass= clazz.getSuperUnit();
		if (superClass != null)
		{
			visitSuperTypes(superClass, visitor);
		}

		for (ClassUnit interfaceUnit : clazz.getInterfaces())
		{
			visitor.visit(interfaceUnit);
			visitSuperTypes(interfaceUnit, visitor);
		}
	}

	public ClassUnit getJavaLangObject()
	{
		return javaLangObject;
	}

	public ClassUnit getClassUnit(String className)
	{
		ClassUnit clazz= classesByName.get(className);
		if (clazz != null)
			return clazz;

		throw new RuntimeException("No such unit: " + className);
	}

	public ClassUnit getClassUnit(ReferenceType type)
	{
		String signature;
		if (type instanceof ArrayType)
		{
			ArrayType aType= (ArrayType) type;
			signature= Utils.getSignature(aType.getBasicType());
			for (int i= 0; i < aType.getDimensions(); i++)
			{
				signature+= "[]";
			}
		}
		else
		{
			signature= Utils.getSignature(type);
		}

		return getClassUnit(signature);
	}

	public ClassUnit getOrCreateClassUnit(String className)
	{
		ClassUnit classUnit= classesByName.get(className);
		if (classUnit != null)
			return classUnit;

		Signature signature= Project.singleton.getSignature(className);
		classUnit= new ClassUnit(this, signature);
		classesByName.put(className, classUnit);

		if (className.equals("java.lang.Object"))
		{
			javaLangObject= classUnit;
		}

		return classUnit;
	}

	private MemberUnit getMemberUnitOrNull(String className, Signature signature)
	{
		ClassUnit classUnit= getOrCreateClassUnit(className);
		if (classUnit == null)
			return null;
		return classUnit.getDeclaredMember(signature.toString());
	}

	private MemberUnit getMemberUnit(String className, Signature signature)
	{
		MemberUnit unit= getMemberUnitOrNull(className, signature);
		if (unit == null)
		{
			throw new RuntimeException("No such unit: " + className + "#" + signature);
		}

		return unit;
	}

	public ProcedureUnit getProcedureUnit(MethodBinding methodBinding)
	{
		Signature signature= Project.singleton.getSignature(methodBinding.getRelativeSignature());
		String className= methodBinding.getDeclaringClass().getClassName();
		return (ProcedureUnit) getMemberUnit(className, signature);
	}

	public ProcedureUnit getOrCreateProcedureUnit(MethodBinding methodBinding)
	{
		Signature signature= Project.singleton.getSignature(methodBinding.getRelativeSignature());
		String className= methodBinding.getDeclaringClass().getClassName();
		return (ProcedureUnit) getOrCreateMemberUnit(className, signature, Pass1.extractMethodNameSignature(methodBinding));
	}

	private MemberUnit getOrCreateMemberUnit(String className, Signature signature, String nameAndSignature)
	{
		MemberUnit member= getMemberUnitOrNull(className, signature);

		if (member == null)
		{
			ClassUnit clazz= getClassUnit(className);
			if (signature.isMethod())
			{
				member= new MethodUnit(signature, clazz, nameAndSignature);
			}
			else if (signature.isConstructor())
			{
				member= new ConstructorUnit(signature, clazz);
			}
			else
			{
				member= new FieldUnit(signature, clazz);
			}

		}

		return member;
	}

	public FieldUnit getOrCreateFieldUnit(ObjectType type, String name)
	{
		return (FieldUnit) getOrCreateMemberUnit(type.getClassName(), Project.singleton.getSignature(name), "");
	}

	public void addReference(MethodDeclaration decl, FieldAccess fa)
	{
		ProcedureUnit source= getOrCreateProcedureUnit(decl.getMethodBinding());
		source.addTarget(Project.singleton.getSignature(fa));
	}

	public void addReference(MethodDeclaration decl, MethodInvocation invocation)
	{
		ProcedureUnit source= getOrCreateProcedureUnit(decl.getMethodBinding());
		source.addTarget(Project.singleton.getSignature(invocation.getMethodBinding().toString()));
	}

	public void addReference(MethodDeclaration decl, ArrayCreation ac)
	{
		ProcedureUnit source= getOrCreateProcedureUnit(decl.getMethodBinding());
		Signature signature= Project.getSingleton().getArraySignature(ac.getTypeBinding());
		for (int i= 0; i < ac.getDimensions().size(); i++)
		{

			source.addTarget(Project.singleton.getSignature(signature.toString().substring(i) + "#length"));
		}
	}

	public Collection getClasses()
	{
		return new ArrayList(classesByName.values());
	}

	public void resolve(ClassUnit clazz)
	{
		if (clazz.isResolved())
			return;

		if (clazz.getName().startsWith("["))
		{

			clazz.setSuperUnit(getJavaLangObject());

			clazz.setResolved(true);

			new FieldUnit(getSignature("length"), clazz);

			TypeDeclaration typeDecl= new TypeDeclaration(new ObjectType(clazz.getName()), 0, new HashMap());//revisar annotations
			typeDecl.setSuperType(Type.OBJECT);
			typeDecl.visit(DragomeJsCompiler.compiler.generator);
		}
		else
		{
			TypeResolver resolver= new TypeResolver(this, DragomeJsCompiler.compiler.generator);
			visitSuperTypes(clazz, resolver);
		}
	}

	public void writeSignatures(Writer writer)
	{
		try
		{
			for (String genericSignature : genericSignatures)
			{
				String[] split= genericSignature.split("\\|");
				if (getWrittenSignatures().contains(split[0] + "|" + split[1]))
					writer.write("addSignatureTo(" + split[0] + ",\"" + split[1] + "\", \"" + split[2] + "\");\n");
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

	public void addGenericSignature(String genericSignature)
	{
		this.genericSignatures.add(genericSignature);
	}

	public int incrementBadMethods(int i)
	{
		return badMethods+= i;
	}

	public int getBadMethods()
	{
		return badMethods;
	}

	public void addTypeAnnotations(TypeDeclaration typeDecl)
	{
		for (Iterator iterator= getTypeDeclarationsWithAnnotations().iterator(); iterator.hasNext();)
		{
			String declaredAnnotation= (String) iterator.next();
			if (declaredAnnotation.startsWith(typeDecl.getClassName()))
				iterator.remove();
		}

		if (!typeDecl.getAnnotations().isEmpty())
		{
			for (Entry entry : typeDecl.getAnnotations().entrySet())
			{
				getTypeDeclarationsWithAnnotations().add(typeDecl.getClassName() + "#" + entry.getKey() + "#" + entry.getValue());

			}
		}
	}

	public Set getTypeDeclarationsWithAnnotations()
	{
		return typeDeclarationsWithAnnotations;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy