Package com.dragome.compiler.parser

Source Code of com.dragome.compiler.parser.Parser

/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>.

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<String, String> 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<String, String> 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<String, String> getAnnotationsValues(Attribute[] attributes)
  {
    Map<String, String> result= new LinkedHashMap<String, String>();
    for (Attribute attribute : attributes)
    {
      if (attribute instanceof Annotations)
      {
        Annotations annotations= (Annotations) attribute;
        AnnotationEntry[] entries= annotations.getAnnotationEntries();
        List<AnnotationEntry> newEntries= new ArrayList<AnnotationEntry>();
        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", "<init>", "(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);
  }

}
TOP

Related Classes of com.dragome.compiler.parser.Parser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.