Package org.stjs.generator.writer.expression

Source Code of org.stjs.generator.writer.expression.NewClassWriter

package org.stjs.generator.writer.expression;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.Element;

import org.stjs.generator.GenerationContext;
import org.stjs.generator.javac.TreeUtils;
import org.stjs.generator.javac.TreeWrapper;
import org.stjs.generator.javascript.NameValue;
import org.stjs.generator.writer.WriterContributor;
import org.stjs.generator.writer.WriterVisitor;

import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;

public class NewClassWriter<JS> implements WriterContributor<NewClassTree, JS> {
  public static BlockTree getDoubleBracesBlock(NewClassTree tree) {
    if (tree.getClassBody() == null) {
      return null;
    }
    for (Tree member : tree.getClassBody().getMembers()) {
      if (member instanceof BlockTree) {
        // XXX I should be sure it's not the one generated by the compiler
        BlockTree block = (BlockTree) member;
        if (!block.isStatic()) {
          return block;
        }
      }
    }
    return null;
  }

  private String getPropertyName(ExpressionTree var) {
    if (var instanceof IdentifierTree) {
      return ((IdentifierTree) var).getName().toString();
    }
    if (var instanceof MemberSelectTree) {
      return ((MemberSelectTree) var).getIdentifier().toString();
    }
    // TODO exception!?
    return null;
  }

  /**
   * special construction for object initialization new Object(){{x = 1; y = 2; }};
   */
  private JS getObjectInitializer(WriterVisitor<JS> visitor, TreeWrapper<NewClassTree, JS> tw) {
    NewClassTree tree = tw.getTree();
    BlockTree initBlock = getDoubleBracesBlock(tree);
    if (initBlock == null && !tw.child(tree.getIdentifier()).isSyntheticType()) {
      return null;
    }

    List<NameValue<JS>> props = new ArrayList<NameValue<JS>>();
    if (initBlock != null) {
      for (StatementTree stmt : initBlock.getStatements()) {
        // check the right type of statements x=y is done in NewClassObjectInitCheck
        AssignmentTree assign = (AssignmentTree) ((ExpressionStatementTree) stmt).getExpression();
        props.add(NameValue.of(getPropertyName(assign.getVariable()), visitor.scan(assign.getExpression(), tw.getContext())));
      }
    }
    return tw.getContext().js().object(props);
  }

  /**
   * check by {@link org.stjs.generator.check.expression.NewClassInlineFunctionCheck} generate the code for inline
   * functions:
   *
   * <pre>
   * new FunctionInterface(){
   *     public void $invoke(args){
   *    }
   * }
   * </pre>
   *
   * is transformed in
   *
   * <pre>
   * function(args){
   * }
   * </pre>
   */
  private JS getInlineFunctionDeclaration(WriterVisitor<JS> visitor, TreeWrapper<NewClassTree, JS> tw) {
    // special construction for inline function definition
    if (!tw.child(tw.getTree().getIdentifier()).isJavaScriptFunction()) {
      return null;
    }

    // the check verifies the existence of a single method (first is the generated
    // constructor)
    Tree method = tw.getTree().getClassBody().getMembers().get(1);
    return visitor.scan(method, tw.getContext());
  }

  private JS getAnonymousClassDeclaration(WriterVisitor<JS> visitor, NewClassTree tree, GenerationContext<JS> context) {
    if (tree.getClassBody() == null) {
      return null;
    }

    JS typeDeclaration = visitor.scan(tree.getClassBody(), context);

    return context.js().newExpression(context.js().paren(typeDeclaration), arguments(visitor, tree, context));
  }

  private List<JS> arguments(WriterVisitor<JS> visitor, NewClassTree tree, GenerationContext<JS> context) {
    List<JS> arguments = new ArrayList<JS>();
    for (Tree arg : tree.getArguments()) {
      arguments.add(visitor.scan(arg, context));
    }
    return arguments;
  }

  private JS getRegularNewExpression(WriterVisitor<JS> visitor, NewClassTree tree, GenerationContext<JS> context) {
    Element type = TreeUtils.elementFromUse(tree.getIdentifier());
    JS typeName = context.js().name(context.getNames().getTypeName(context, type));
    return context.js().newExpression(typeName, arguments(visitor, tree, context));
  }

  @Override
  public JS visit(WriterVisitor<JS> visitor, NewClassTree tree, GenerationContext<JS> context) {
    TreeWrapper<NewClassTree, JS> tw = context.getCurrentWrapper();
    JS js = getInlineFunctionDeclaration(visitor, tw);
    if (js != null) {
      return js;
    }

    js = getObjectInitializer(visitor, tw);
    if (js != null) {
      return js;
    }

    js = getAnonymousClassDeclaration(visitor, tree, context);
    if (js != null) {
      return js;
    }

    return getRegularNewExpression(visitor, tree, context);

    // if (clazz instanceof ClassWrapper && ClassUtils.isSyntheticType(clazz)) {
    // // this is a call to an mock type
    // printer.print("{}");
    // return;
    // }

  }

}
TOP

Related Classes of org.stjs.generator.writer.expression.NewClassWriter

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.