public void process(Node externs, Node root) {
    Node initCode = null;
    if (initCodeSource.length() != 0) {
      Node initCodeRoot = compiler.parseSyntheticCode(templateFilename + ":init", initCodeSource);
      if (initCodeRoot != null && initCodeRoot.getFirstChild() != null) {
        initCode = initCodeRoot.removeChildren();
      } else {
        return; // parse failure
      }
    }

    NodeTraversal.traverse(compiler, root, new RemoveCallback(declarationsToRemove));
    NodeTraversal.traverse(compiler, root, new InstrumentCallback());

    if (appNameSetter.length() != 0) {
      Node call =
          new Node(
              Token.CALL, Node.newString(Token.NAME, appNameSetter), Node.newString(appNameStr));
      Node expr = new Node(Token.EXPR_RESULT, call);

      Node addingRoot = compiler.getNodeForCodeInsertion(null);
      addingRoot.addChildrenToFront(expr);
      compiler.reportCodeChange();
    }

    if (initCode != null) {
      Node addingRoot = compiler.getNodeForCodeInsertion(null);
      addingRoot.addChildrenToFront(initCode);
      compiler.reportCodeChange();
    }
  }
  @Override
  public void process(Node externs, Node root) {
    Node initCode = null;
    if (!initCodeSource.isEmpty()) {
      Node initCodeRoot = compiler.parseSyntheticCode("template:init", initCodeSource);
      if (initCodeRoot != null && initCodeRoot.getFirstChild() != null) {
        initCode = initCodeRoot.removeChildren();
      } else {
        return; // parse failure
      }
    }

    NodeTraversal.traverseEs6(compiler, root, new RemoveCallback(declarationsToRemove));
    NodeTraversal.traverseEs6(compiler, root, new InstrumentCallback());

    if (!appNameSetter.isEmpty()) {
      Node call = IR.call(IR.name(appNameSetter), IR.string(appNameStr));
      call.putBooleanProp(Node.FREE_CALL, true);
      Node expr = IR.exprResult(call);

      Node addingRoot = compiler.getNodeForCodeInsertion(null);
      addingRoot.addChildrenToFront(expr.useSourceInfoIfMissingFromForTree(addingRoot));
      compiler.reportCodeChange();
    }

    if (initCode != null) {
      Node addingRoot = compiler.getNodeForCodeInsertion(null);
      addingRoot.addChildrenToFront(initCode);
      compiler.reportCodeChange();
    }
  }
 /** Applies optimizations to all previously marked nodes. */
 public void applyChanges() {
   for (Node n : toRemove) {
     n.getParent().removeChild(n);
     compiler.reportCodeChange();
   }
   for (Node n : toReplaceWithZero) {
     n.getParent().replaceChild(n, Node.newNumber(0).copyInformationFrom(n));
     compiler.reportCodeChange();
   }
 }
  /** Processes trailing default and rest parameters. */
  private void visitParamList(Node paramList, Node function) {
    Node insertSpot = null;
    Node block = function.getLastChild();
    for (int i = 0; i < paramList.getChildCount(); i++) {
      Node param = paramList.getChildAtIndex(i);
      if (param.isDefaultValue()) {
        Node nameOrPattern = param.removeFirstChild();
        Node defaultValue = param.removeFirstChild();
        Node newParam =
            nameOrPattern.isName()
                ? nameOrPattern
                : IR.name(DESTRUCTURING_TEMP_VAR + (destructuringVarCounter++));

        Node lhs = nameOrPattern.cloneTree();
        Node rhs = defaultValueHook(newParam.cloneTree(), defaultValue);
        Node newStatement =
            nameOrPattern.isName() ? IR.exprResult(IR.assign(lhs, rhs)) : IR.var(lhs, rhs);
        newStatement.useSourceInfoIfMissingFromForTree(param);
        block.addChildAfter(newStatement, insertSpot);
        insertSpot = newStatement;

        paramList.replaceChild(param, newParam);
        newParam.setOptionalArg(true);

        compiler.reportCodeChange();
      } else if (param.isRest()) { // rest parameter
        param.setType(Token.NAME);
        param.setVarArgs(true);
        // Transpile to: param = [].slice.call(arguments, i);
        Node newArr =
            IR.exprResult(
                IR.assign(
                    IR.name(param.getString()),
                    IR.call(
                        IR.getprop(
                            IR.getprop(IR.arraylit(), IR.string("slice")), IR.string("call")),
                        IR.name("arguments"),
                        IR.number(i))));
        block.addChildAfter(newArr.useSourceInfoIfMissingFromForTree(param), insertSpot);
        compiler.reportCodeChange();
      } else if (param.isDestructuringPattern()) {
        String tempVarName = DESTRUCTURING_TEMP_VAR + (destructuringVarCounter++);
        paramList.replaceChild(param, IR.name(tempVarName));
        Node newDecl = IR.var(param, IR.name(tempVarName));
        block.addChildAfter(newDecl, insertSpot);
        insertSpot = newDecl;
      }
    }
    // For now, we are running transpilation before type-checking, so we'll
    // need to make sure changes don't invalidate the JSDoc annotations.
    // Therefore we keep the parameter list the same length and only initialize
    // the values if they are set to undefined.
  }
Exemplo n.º 5
0
  private void addExportMethod(
      Map<String, GenerateNodeContext> exports, String export, GenerateNodeContext context) {
    CodingConvention convention = compiler.getCodingConvention();

    // Emit the proper CALL expression.
    // This is an optimization to avoid exporting everything as a symbol
    // because exporting a property is significantly simpler/faster.
    // Only export the property if the parent is being exported or
    // if the parent is "prototype" and the grandparent is being exported.
    String parent = null;
    String grandparent = null;

    Node node = context.getNode().getFirstChild();
    if (node.isGetProp()) {
      Node parentNode = node.getFirstChild();
      parent = parentNode.getQualifiedName();
      if (parentNode.isGetProp()
          && parentNode.getLastChild().getString().equals(PROTOTYPE_PROPERTY)) {
        grandparent = parentNode.getFirstChild().getQualifiedName();
      }
    }

    boolean useExportSymbol = true;
    if (grandparent != null && exports.containsKey(grandparent)) {
      // grandparent is only set for properties exported off a prototype obj.
      useExportSymbol = false;
    } else if (parent != null && exports.containsKey(parent)) {
      useExportSymbol = false;
    }

    Node call;
    if (useExportSymbol) {
      // exportSymbol(publicPath, object);
      call =
          IR.call(
              NodeUtil.newQualifiedNameNode(
                  convention, exportSymbolFunction, context.getNode(), export),
              IR.string(export),
              NodeUtil.newQualifiedNameNode(convention, export, context.getNode(), export));
    } else {
      // exportProperty(object, publicName, symbol);
      String property = getPropertyName(node);
      call =
          IR.call(
              NodeUtil.newQualifiedNameNode(
                  convention, exportPropertyFunction, context.getNode(), exportPropertyFunction),
              NodeUtil.newQualifiedNameNode(
                  convention, parent, context.getNode(), exportPropertyFunction),
              IR.string(property),
              NodeUtil.newQualifiedNameNode(
                  convention, export, context.getNode(), exportPropertyFunction));
    }

    Node expression = IR.exprResult(call);
    annotate(expression);

    addStatement(context, expression);

    compiler.reportCodeChange();
  }
  /**
   * Removes unreferenced arguments from a function declaration and when possible the function's
   * callSites.
   *
   * @param fnScope The scope inside the function
   */
  private void removeUnreferencedFunctionArgs(Scope fnScope) {
    // TODO(johnlenz): Update type registry for function signature changes.

    Node function = fnScope.getRootNode();

    Preconditions.checkState(function.getType() == Token.FUNCTION);
    if (NodeUtil.isGetOrSetKey(function.getParent())) {
      // The parameters object literal setters can not be removed.
      return;
    }

    Node argList = getFunctionArgList(function);
    boolean modifyCallers = modifyCallSites && callSiteOptimizer.canModifyCallers(function);
    if (!modifyCallers) {
      // Strip unreferenced args off the end of the function declaration.
      Node lastArg;
      while ((lastArg = argList.getLastChild()) != null) {
        Var var = fnScope.getVar(lastArg.getString());
        if (!referenced.contains(var)) {
          Preconditions.checkNotNull(var == null);
          argList.removeChild(lastArg);
          compiler.reportCodeChange();
        } else {
          break;
        }
      }
    } else {
      callSiteOptimizer.optimize(fnScope, referenced);
    }
  }
  /**
   * Replaces a GETPROP a.b.c with a NAME a$b$c.
   *
   * @param alias A flattened prefix name (e.g. "a$b")
   * @param n The GETPROP node corresponding to the original name (e.g. "a.b")
   * @param parent {@code n}'s parent
   * @param originalName String version of the property name.
   */
  private void flattenNameRef(String alias, Node n, Node parent, String originalName) {
    Preconditions.checkArgument(
        n.isGetProp(), "Expected GETPROP, found %s. Node: %s", Token.name(n.getType()), n);

    // BEFORE:
    //   getprop
    //     getprop
    //       name a
    //       string b
    //     string c
    // AFTER:
    //   name a$b$c
    Node ref = NodeUtil.newName(compiler, alias, n, originalName);
    NodeUtil.copyNameAnnotations(n.getLastChild(), ref);
    if (parent.isCall() && n == parent.getFirstChild()) {
      // The node was a call target, we are deliberately flatten these as
      // we node the "this" isn't provided by the namespace. Mark it as such:
      parent.putBooleanProp(Node.FREE_CALL, true);
    }

    TypeI type = n.getTypeI();
    if (type != null) {
      ref.setTypeI(type);
    }

    parent.replaceChild(n, ref);
    compiler.reportCodeChange();
  }
  /**
   * Adds an interface for the given ClassDefinition to externs. This allows generated setter
   * functions for read-only properties to avoid renaming altogether.
   *
   * @see https://www.polymer-project.org/0.8/docs/devguide/properties.html#read-only
   */
  private void addInterfaceExterns(
      final ClassDefinition cls, List<MemberDefinition> readOnlyProps) {
    Node block = IR.block();

    String interfaceName = getInterfaceName(cls);
    Node fnNode = IR.function(IR.name(""), IR.paramList(), IR.block());
    Node varNode = IR.var(NodeUtil.newQName(compiler, interfaceName), fnNode);

    JSDocInfoBuilder info = new JSDocInfoBuilder(true);
    info.recordInterface();
    varNode.setJSDocInfo(info.build());
    block.addChildToBack(varNode);

    appendPropertiesToBlock(cls, block, interfaceName + ".prototype.");
    for (MemberDefinition prop : readOnlyProps) {
      // Add all _set* functions to avoid renaming.
      String propName = prop.name.getString();
      String setterName = "_set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
      Node setterExprNode =
          IR.exprResult(NodeUtil.newQName(compiler, interfaceName + ".prototype." + setterName));

      JSDocInfoBuilder setterInfo = new JSDocInfoBuilder(true);
      JSTypeExpression propType = getTypeFromProperty(prop);
      setterInfo.recordParameter(propName, propType);
      setterExprNode.getFirstChild().setJSDocInfo(setterInfo.build());

      block.addChildToBack(setterExprNode);
    }

    Node parent = polymerElementExterns.getParent();
    Node stmts = block.removeChildren();
    parent.addChildrenToBack(stmts);

    compiler.reportCodeChange();
  }
  private void visitForOf(Node node, Node parent) {
    Node variable = node.removeFirstChild();
    Node iterable = node.removeFirstChild();
    Node body = node.removeFirstChild();

    Node iterName = IR.name(ITER_BASE + compiler.getUniqueNameIdSupplier().get());
    Node getNext = IR.call(IR.getprop(iterName.cloneTree(), IR.string("next")));
    String variableName =
        variable.isName()
            ? variable.getQualifiedName()
            : variable.getFirstChild().getQualifiedName(); // var or let
    Node iterResult = IR.name(ITER_RESULT + variableName);

    Node makeIter =
        IR.call(NodeUtil.newQualifiedNameNode(compiler.getCodingConvention(), MAKE_ITER), iterable);

    Node init = IR.var(iterName.cloneTree(), makeIter);
    Node initIterResult = iterResult.cloneTree();
    initIterResult.addChildToFront(getNext.cloneTree());
    init.addChildToBack(initIterResult);

    Node cond = IR.not(IR.getprop(iterResult.cloneTree(), IR.string("done")));
    Node incr = IR.assign(iterResult.cloneTree(), getNext.cloneTree());
    body.addChildToFront(
        IR.var(IR.name(variableName), IR.getprop(iterResult.cloneTree(), IR.string("value"))));

    Node newFor = IR.forNode(init, cond, incr, body);
    newFor.useSourceInfoIfMissingFromForTree(node);
    parent.replaceChild(node, newFor);
    compiler.reportCodeChange();
  }
  /**
   * Duplicates the PolymerElement externs with a different element base class if needed. For
   * example, if the base class is HTMLInputElement, then a class PolymerInputElement will be added.
   * If the element does not extend a native HTML element, this method is a no-op.
   */
  private void appendPolymerElementExterns(final ClassDefinition cls) {
    if (!nativeExternsAdded.add(cls.nativeBaseElement)) {
      return;
    }

    Node block = IR.block();

    Node baseExterns = polymerElementExterns.cloneTree();
    String polymerElementType = getPolymerElementType(cls);
    baseExterns.getFirstChild().setString(polymerElementType);

    String elementType = tagNameMap.get(cls.nativeBaseElement);
    JSTypeExpression elementBaseType =
        new JSTypeExpression(new Node(Token.BANG, IR.string(elementType)), VIRTUAL_FILE);
    JSDocInfoBuilder baseDocs = JSDocInfoBuilder.copyFrom(baseExterns.getJSDocInfo());
    baseDocs.changeBaseType(elementBaseType);
    baseExterns.setJSDocInfo(baseDocs.build());
    block.addChildToBack(baseExterns);

    for (Node baseProp : polymerElementProps) {
      Node newProp = baseProp.cloneTree();
      Node newPropRootName =
          NodeUtil.getRootOfQualifiedName(newProp.getFirstChild().getFirstChild());
      newPropRootName.setString(polymerElementType);
      block.addChildToBack(newProp);
    }

    Node parent = polymerElementExterns.getParent();
    Node stmts = block.removeChildren();
    parent.addChildrenAfter(stmts, polymerElementExterns);

    compiler.reportCodeChange();
  }
  /** @param marker The marker to add synthetic blocks for. */
  private void addBlocks(Marker marker) {
    // Add block around the template section so that it looks like this:
    //  BLOCK (synthetic)
    //    START
    //      BLOCK (synthetic)
    //        BODY
    //    END
    // This prevents the start or end markers from mingling with the code
    // in the block body.

    Node originalParent = marker.endMarker.getParent();
    Node outerBlock = IR.block();
    outerBlock.setIsSyntheticBlock(true);
    originalParent.addChildBefore(outerBlock, marker.startMarker);

    Node innerBlock = IR.block();
    innerBlock.setIsSyntheticBlock(true);
    // Move everything after the start Node up to the end Node into the inner
    // block.
    moveSiblingExclusive(originalParent, innerBlock, marker.startMarker, marker.endMarker);

    // Add the start node.
    outerBlock.addChildToBack(originalParent.removeChildAfter(outerBlock));
    // Add the inner block
    outerBlock.addChildToBack(innerBlock);
    // and finally the end node.
    outerBlock.addChildToBack(originalParent.removeChildAfter(outerBlock));

    compiler.reportCodeChange();
  }
Exemplo n.º 12
0
 private void addExtern(String export) {
   Node propstmt =
       IR.exprResult(IR.getprop(qualifiedNameNode("Object.prototype"), IR.string(export)));
   NodeUtil.setDebugInformation(propstmt, getSynthesizedExternsRoot(), export);
   getSynthesizedExternsRoot().addChildToBack(propstmt);
   compiler.reportCodeChange();
 }
 /**
  * Adds global variable "stubs" for any properties of a global name that are only set in a local
  * scope or read but never set.
  *
  * @param n An object representing a global name (e.g. "a", "a.b.c")
  * @param alias The flattened name of the object whose properties we are adding stubs for (e.g.
  *     "a$b$c")
  * @param parent The node to which new global variables should be added as children
  * @param addAfter The child of after which new variables should be added
  * @return The number of variables added
  */
 private int addStubsForUndeclaredProperties(Name n, String alias, Node parent, Node addAfter) {
   Preconditions.checkState(n.canCollapseUnannotatedChildNames());
   Preconditions.checkArgument(NodeUtil.isStatementBlock(parent));
   Preconditions.checkNotNull(addAfter);
   if (n.props == null) {
     return 0;
   }
   int numStubs = 0;
   for (Name p : n.props) {
     if (p.needsToBeStubbed()) {
       String propAlias = appendPropForAlias(alias, p.getBaseName());
       Node nameNode = IR.name(propAlias);
       Node newVar = IR.var(nameNode).useSourceInfoIfMissingFromForTree(addAfter);
       parent.addChildAfter(newVar, addAfter);
       addAfter = newVar;
       numStubs++;
       compiler.reportCodeChange();
       // Determine if this is a constant var by checking the first
       // reference to it. Don't check the declaration, as it might be null.
       if (p.getRefs().get(0).node.getLastChild().getBooleanProp(Node.IS_CONSTANT_NAME)) {
         nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
       }
     }
   }
   return numStubs;
 }
Exemplo n.º 14
0
  @Override
  public void process(Node externs, Node root) {
    assignmentLog = new StringBuilder();

    // Do variable reference counting.
    NodeTraversal.traverse(compiler, externs, new ProcessVars(true));
    NodeTraversal.traverse(compiler, root, new ProcessVars(false));

    // Make sure that new names don't overlap with extern names.
    reservedNames.addAll(externNames);

    // Rename vars, sorted by frequency of occurrence to minimize code size.
    SortedSet<Assignment> varsByFrequency = new TreeSet<Assignment>(FREQUENCY_COMPARATOR);
    varsByFrequency.addAll(assignments.values());

    if (shouldShadow) {
      new ShadowVariables(compiler, assignments, varsByFrequency, pseudoNameMap)
          .process(externs, root);
    }

    // First try to reuse names from an earlier compilation.
    if (prevUsedRenameMap != null) {
      reusePreviouslyUsedVariableMap();
    }

    // Assign names, sorted by descending frequency to minimize code size.
    assignNames(varsByFrequency);

    boolean changed = false;

    // Rename the globals!
    for (Node n : globalNameNodes) {
      String newName = getNewGlobalName(n);
      // Note: if newName is null, then oldName is an extern.
      if (newName != null) {
        n.setString(newName);
        changed = true;
      }
    }

    // Rename the locals!
    int count = 0;
    for (Node n : localNameNodes) {
      String newName = getNewLocalName(n);
      if (newName != null) {
        n.setString(newName);
        changed = true;
      }
      count++;
    }

    if (changed) {
      compiler.reportCodeChange();
    }

    // Lastly, write the name assignments to the debug log.
    compiler.addToDebugLog("JS var assignments:\n" + assignmentLog);
    assignmentLog = null;
  }
 /** Converts extended object literal {a} to {a:a}. */
 private void visitStringKey(Node n) {
   if (!n.hasChildren()) {
     Node name = IR.name(n.getString());
     name.useSourceInfoIfMissingFrom(n);
     n.addChildToBack(name);
     compiler.reportCodeChange();
   }
 }
Exemplo n.º 16
0
 /** Converts extended object literal {a} to {a:a}. */
 private void visitStringKey(Node n) {
   if (!n.hasChildren()) {
     Node name = IR.name(n.getString());
     name.copyInformationFrom(n);
     n.addChildToBack(name);
     compiler.reportCodeChange();
   }
 }
Exemplo n.º 17
0
 @Override
 public void visit(NodeTraversal t, Node n, Node parent) {
   switch (n.getType()) {
     case Token.THIS:
       parent.replaceChild(n, Node.newString(Token.NAME, "$$_self"));
       thisChanged = true;
       compiler.reportCodeChange();
   }
 }
 @Override
 public void hotSwapScript(Node scriptRoot, Node originalRoot) {
   Traverser traverser = new Traverser();
   NodeTraversal.traverseEs6(compiler, scriptRoot, traverser);
   if (traverser.changed) {
     compiler.needsEs6Runtime = true;
     compiler.reportCodeChange();
   }
 }
Exemplo n.º 19
0
 /**
  * Processes array literals or calls containing spreads. Eg.: [1, 2, ...x, 4, 5] => [1,
  * 2].concat(x, [4, 5]); Eg.: f(...arr) => f.apply(null, arr) Eg.: new F(...args) => new
  * Function.prototype.bind.apply(F, [].concat(args))
  */
 private void visitArrayLitOrCallWithSpread(Node node, Node parent) {
   Preconditions.checkArgument(node.isCall() || node.isArrayLit() || node.isNew());
   List<Node> groups = new ArrayList<>();
   Node currGroup = null;
   Node callee = node.isArrayLit() ? null : node.removeFirstChild();
   Node currElement = node.removeFirstChild();
   while (currElement != null) {
     if (currElement.isSpread()) {
       if (currGroup != null) {
         groups.add(currGroup);
         currGroup = null;
       }
       groups.add(currElement.removeFirstChild());
     } else {
       if (currGroup == null) {
         currGroup = IR.arraylit();
       }
       currGroup.addChildToBack(currElement);
     }
     currElement = node.removeFirstChild();
   }
   if (currGroup != null) {
     groups.add(currGroup);
   }
   Node result = null;
   Node joinedGroups =
       IR.call(
           IR.getprop(IR.arraylit(), IR.string("concat")),
           groups.toArray(new Node[groups.size()]));
   if (node.isArrayLit()) {
     result = joinedGroups;
   } else if (node.isCall()) {
     if (NodeUtil.mayHaveSideEffects(callee) && callee.isGetProp()) {
       Node statement = node;
       while (!NodeUtil.isStatement(statement)) {
         statement = statement.getParent();
       }
       Node freshVar = IR.name(FRESH_SPREAD_VAR + freshSpreadVarCounter++);
       Node n = IR.var(freshVar.cloneTree());
       n.useSourceInfoIfMissingFromForTree(statement);
       statement.getParent().addChildBefore(n, statement);
       callee.addChildToFront(IR.assign(freshVar.cloneTree(), callee.removeFirstChild()));
       result = IR.call(IR.getprop(callee, IR.string("apply")), freshVar, joinedGroups);
     } else {
       Node context = callee.isGetProp() ? callee.getFirstChild().cloneTree() : IR.nullNode();
       result = IR.call(IR.getprop(callee, IR.string("apply")), context, joinedGroups);
     }
   } else {
     Node bindApply =
         NodeUtil.newQualifiedNameNode(
             compiler.getCodingConvention(), "Function.prototype.bind.apply");
     result = IR.newNode(bindApply, callee, joinedGroups);
   }
   result.useSourceInfoIfMissingFromForTree(node);
   parent.replaceChild(node, result);
   compiler.reportCodeChange();
 }
  private void visitObjectWithComputedProperty(Node obj, Node parent) {
    Preconditions.checkArgument(obj.isObjectLit());
    List<Node> props = new ArrayList<>();
    Node currElement = obj.getFirstChild();

    while (currElement != null) {
      if (currElement.getBooleanProp(Node.COMPUTED_PROP_GETTER)
          || currElement.getBooleanProp(Node.COMPUTED_PROP_SETTER)) {
        cannotConvertYet(currElement, "computed getter/setter");
        return;
      } else if (currElement.isGetterDef() || currElement.isSetterDef()) {
        currElement = currElement.getNext();
      } else {
        Node nextNode = currElement.getNext();
        obj.removeChild(currElement);
        props.add(currElement);
        currElement = nextNode;
      }
    }

    String objName = FRESH_COMP_PROP_VAR + compiler.getUniqueNameIdSupplier().get();

    props = Lists.reverse(props);
    Node result = IR.name(objName);
    for (Node propdef : props) {
      if (propdef.isComputedProp()) {
        Node propertyExpression = propdef.removeFirstChild();
        Node value = propdef.removeFirstChild();
        result =
            IR.comma(IR.assign(IR.getelem(IR.name(objName), propertyExpression), value), result);
      } else {
        if (!propdef.hasChildren()) {
          Node name = IR.name(propdef.getString()).useSourceInfoIfMissingFrom(propdef);
          propdef.addChildToBack(name);
        }
        Node val = propdef.removeFirstChild();
        propdef.setType(Token.STRING);
        int type = propdef.isQuotedString() ? Token.GETELEM : Token.GETPROP;
        Node access = new Node(type, IR.name(objName), propdef);
        result = IR.comma(IR.assign(access, val), result);
      }
    }

    Node statement = obj;
    while (!NodeUtil.isStatement(statement)) {
      statement = statement.getParent();
    }

    result.useSourceInfoIfMissingFromForTree(obj);
    parent.replaceChild(obj, result);

    Node var = IR.var(IR.name(objName), obj);
    var.useSourceInfoIfMissingFromForTree(statement);
    statement.getParent().addChildBefore(var, statement);
    compiler.reportCodeChange();
  }
Exemplo n.º 21
0
 /** Update all of the nodes with a reference to the corresponding alias node. */
 public void doAlias(AbstractCompiler compiler) {
   if (isAliased) {
     for (Map.Entry<Node, Node> entry : nodes.entrySet()) {
       Node n = entry.getKey();
       Node parent = entry.getValue();
       aliasNode(n, parent);
       compiler.reportCodeChange();
     }
   }
 }
  /** Flattens a stub declaration. This is mostly a hack to support legacy users. */
  private void flattenSimpleStubDeclaration(Name name, String alias) {
    Ref ref = Iterables.getOnlyElement(name.getRefs());
    Node nameNode = NodeUtil.newName(compiler, alias, ref.node, name.getFullName());
    Node varNode = IR.var(nameNode).useSourceInfoIfMissingFrom(nameNode);

    Preconditions.checkState(ref.node.getParent().isExprResult());
    Node parent = ref.node.getParent();
    Node grandparent = parent.getParent();
    grandparent.replaceChild(parent, varNode);
    compiler.reportCodeChange();
  }
Exemplo n.º 23
0
  @Override
  public void visit(NodeTraversal t, Node n, Node parent) {
    // System.out.println(n);
    switch (n.getType()) {
      case Token.FUNCTION:
        Node functionNameNode = n.getFirstChild();
        String currFunctionName = functionNameNode.getString();

        if (!anonymizedFnNodes.contains(n)) {
          if (currFunctionName.length() == 0) {
            Set<String> closures = findClosures(n);

            // System.out.println("closures" + closures);

            n.detachFromParent(); // detach anonymous function from.

            // change all references to 'this' in method to $$_self
            boolean thisChanged = changeThisTo$$_self(n);

            // clone the parameters of modified $$$anonym(originalParams..., closures..) so that
            // we can use it for parameters of function call below

            Node clonedorigParamNode = n.getChildAtIndex(1).cloneTree();
            clonedorigParamNode.setType(Token.LP);

            // parent
            // give 'n' a name and attach to end
            // e.g. function $$anonym(originalParams..., closures..)
            String anonymName = "$$anonym" + anonymCount++;
            Node funcNameNode = Node.newString(Token.NAME, anonymName);
            n.replaceChild(n.getFirstChild(), funcNameNode);

            Node parametersNode = n.getChildAtIndex(1);
            addParamsToMethod(closures, parametersNode, thisChanged, "$$_self");

            root.getFirstChild().addChildrenToBack(n);

            // replace original anonymous call to new anonymous function that closes over
            // params and then makes a call to our named function
            Node newAnonymNode =
                createAnonymWithParamCall(closures, anonymName, clonedorigParamNode, thisChanged);
            parent.addChildrenToBack(newAnonymNode);

            // add to list of anonymized nodes so that we can ignore it on second pass
            anonymizedFnNodes.add(newAnonymNode);

            compiler.reportCodeChange();
          } else { // named function just find closures and add as parameter
            // TODO
          }
        }
    }
  }
Exemplo n.º 24
0
 private void addExtern() {
   Node name = IR.name(PROTECTOR_FN);
   name.putBooleanProp(Node.IS_CONSTANT_NAME, true);
   Node var = IR.var(name);
   // Add "@noalias" so we can strip the method when AliasExternals is enabled.
   JSDocInfoBuilder builder = new JSDocInfoBuilder(false);
   builder.recordNoAlias();
   var.setJSDocInfo(builder.build(var));
   CompilerInput input = compiler.getSynthesizedExternsInput();
   input.getAstRoot(compiler).addChildrenToBack(var);
   compiler.reportCodeChange();
 }
Exemplo n.º 25
0
  /**
   * Inject alias nodes into the global scope. e.g. var
   * $$ALIAS_NULL=null,$$ALIAS_TRUE=true,$$ALIAS_FALSE=false;.
   */
  private void addAliasNodes(Node codeRoot) {
    boolean codeChanged = false;

    for (AliasSpecification spec : aliasSpecifications) {
      if (spec.maybeInsertAliasDeclarationIntoParseTree(codeRoot)) {
        codeChanged = true;
      }
    }

    if (codeChanged) {
      compiler.reportCodeChange();
    }
  }
Exemplo n.º 26
0
 /** Processes trailing default and rest parameters. */
 private void visitParamList(Node paramList, Node function) {
   Node insertSpot = null;
   Node block = function.getLastChild();
   for (int i = 0; i < paramList.getChildCount(); i++) {
     Node param = paramList.getChildAtIndex(i);
     if (param.hasChildren()) { // default parameter
       param.setOptionalArg(true);
       Node defaultValue = param.removeFirstChild();
       // Transpile to: param === undefined && (param = defaultValue);
       Node name = IR.name(param.getString());
       Node undefined = IR.name("undefined");
       Node stm =
           IR.exprResult(
               IR.and(IR.sheq(name, undefined), IR.assign(name.cloneNode(), defaultValue)));
       block.addChildAfter(stm.useSourceInfoIfMissingFromForTree(param), insertSpot);
       insertSpot = stm;
       compiler.reportCodeChange();
     } else if (param.isRest()) { // rest parameter
       param.setType(Token.NAME);
       param.setVarArgs(true);
       // Transpile to: param = [].slice.call(arguments, i);
       Node newArr =
           IR.exprResult(
               IR.assign(
                   IR.name(param.getString()),
                   IR.call(
                       IR.getprop(
                           IR.getprop(IR.arraylit(), IR.string("slice")), IR.string("call")),
                       IR.name("arguments"),
                       IR.number(i))));
       block.addChildAfter(newArr.useSourceInfoIfMissingFromForTree(param), insertSpot);
       compiler.reportCodeChange();
     }
   }
   // For now, we are running transpilation before type-checking, so we'll
   // need to make sure changes don't invalidate the JSDoc annotations.
   // Therefore we keep the parameter list the same length and only initialize
   // the values if they are set to undefined.
 }
  /**
   * Attempt to inline an global alias of a global name. This requires that the name is well
   * defined: assigned unconditionally, assigned exactly once. It is assumed that, the name for
   * which it is an alias must already meet these same requirements.
   *
   * @param alias The alias to inline
   * @return Whether the alias was inlined.
   */
  private boolean inlineGlobalAliasIfPossible(Name name, Ref alias, GlobalNamespace namespace) {
    // Ensure that the alias is assigned to global name at that the
    // declaration.
    Node aliasParent = alias.node.getParent();
    if (aliasParent.isAssign() && NodeUtil.isExecutedExactlyOnce(aliasParent)
        // We special-case for constructors here, to inline constructor aliases
        // more aggressively in global scope.
        // We do this because constructor properties are always collapsed,
        // so we want to inline the aliases also to avoid breakages.
        || aliasParent.isName() && name.isConstructor()) {
      Node lvalue = aliasParent.isName() ? aliasParent : aliasParent.getFirstChild();
      if (!lvalue.isQualifiedName()) {
        return false;
      }
      name = namespace.getSlot(lvalue.getQualifiedName());
      if (name != null && name.isInlinableGlobalAlias()) {
        Set<AstChange> newNodes = new LinkedHashSet<>();

        List<Ref> refs = new ArrayList<>(name.getRefs());
        for (Ref ref : refs) {
          switch (ref.type) {
            case SET_FROM_GLOBAL:
              continue;
            case DIRECT_GET:
            case ALIASING_GET:
              Node newNode = alias.node.cloneTree();
              Node node = ref.node;
              node.getParent().replaceChild(node, newNode);
              newNodes.add(new AstChange(ref.module, ref.scope, newNode));
              name.removeRef(ref);
              break;
            default:
              throw new IllegalStateException();
          }
        }

        rewriteAliasProps(name, alias.node, 0, newNodes);

        // just set the original alias to null.
        aliasParent.replaceChild(alias.node, IR.nullNode());
        compiler.reportCodeChange();

        // Inlining the variable may have introduced new references
        // to descendants of {@code name}. So those need to be collected now.
        namespace.scanNewNodes(newNodes);

        return true;
      }
    }
    return false;
  }
 private void varify() {
   if (!blockScopedDeclarations.isEmpty()) {
     for (Node n : blockScopedDeclarations) {
       if (n.isConst()) {
         JSDocInfoBuilder builder = JSDocInfoBuilder.maybeCopyFrom(n.getJSDocInfo());
         builder.recordConstancy();
         JSDocInfo info = builder.build();
         n.setJSDocInfo(info);
       }
       n.setType(Token.VAR);
     }
     compiler.reportCodeChange();
   }
 }
  private void visitForOf(Node node, Node parent) {
    Node variable = node.removeFirstChild();
    Node iterable = node.removeFirstChild();
    Node body = node.removeFirstChild();

    Node iterName = IR.name(ITER_BASE + compiler.getUniqueNameIdSupplier().get());
    Node getNext = IR.call(IR.getprop(iterName.cloneTree(), IR.string("next")));
    String variableName;
    int declType;
    if (variable.isName()) {
      declType = Token.NAME;
      variableName = variable.getQualifiedName();
    } else {
      Preconditions.checkState(
          NodeUtil.isNameDeclaration(variable), "Expected var, let, or const. Got %s", variable);
      declType = variable.getType();
      variableName = variable.getFirstChild().getQualifiedName();
    }
    Node iterResult = IR.name(ITER_RESULT + variableName);

    Node makeIter = IR.call(NodeUtil.newQName(compiler, MAKE_ITER), iterable);
    compiler.needsEs6Runtime = true;

    Node init = IR.var(iterName.cloneTree(), makeIter);
    Node initIterResult = iterResult.cloneTree();
    initIterResult.addChildToFront(getNext.cloneTree());
    init.addChildToBack(initIterResult);

    Node cond = IR.not(IR.getprop(iterResult.cloneTree(), IR.string("done")));
    Node incr = IR.assign(iterResult.cloneTree(), getNext.cloneTree());

    Node declarationOrAssign;
    if (declType == Token.NAME) {
      declarationOrAssign =
          IR.exprResult(
              IR.assign(
                  IR.name(variableName), IR.getprop(iterResult.cloneTree(), IR.string("value"))));
    } else {
      declarationOrAssign = new Node(declType, IR.name(variableName));
      declarationOrAssign
          .getFirstChild()
          .addChildToBack(IR.getprop(iterResult.cloneTree(), IR.string("value")));
    }
    body.addChildToFront(declarationOrAssign);

    Node newFor = IR.forNode(init, cond, incr, body);
    newFor.useSourceInfoIfMissingFromForTree(node);
    parent.replaceChild(node, newFor);
    compiler.reportCodeChange();
  }
Exemplo n.º 30
0
 /**
  * Protect side-effect free nodes by making them parameters to a extern function call. This call
  * will be removed after all the optimizations passes have run.
  */
 private void protectSideEffects() {
   if (!problemNodes.isEmpty()) {
     addExtern();
     for (Node n : problemNodes) {
       Node name = IR.name(PROTECTOR_FN).srcref(n);
       name.putBooleanProp(Node.IS_CONSTANT_NAME, true);
       Node replacement = IR.call(name).srcref(n);
       replacement.putBooleanProp(Node.FREE_CALL, true);
       n.getParent().replaceChild(n, replacement);
       replacement.addChildToBack(n);
     }
     compiler.reportCodeChange();
   }
 }