Package com.google.caja.parser.js

Examples of com.google.caja.parser.js.Expression


      ObjectConstructor dataObj = new ObjectConstructor(unk);

      String regex = data.regex;
      if (regex != null) {
        int poolIndex = regexPoolMap.get(regex)[0];
        Expression re = poolIndex < 0
            ? makeRegexp(commonSubstringMap, regex)
            : (Expression) QuasiBuilder.substV(
                "c[@i]", "i", new IntegerLiteral(unk, poolIndex));
        dataObj.appendChild(new ValueProperty(regexObjKey, re));
      }
View Full Code Here


    String pattern = regex.substring(1, regex.length() - 2);
    makeRegexpOnto(substrings, pattern, 0, parts);
    if (parts.size() == 1 && parts.get(0) instanceof StringLiteral) {
      return new RegexpLiteral(unk, regex);
    } else {
      Expression e = parts.get(0);
      for (int i = 1, n = parts.size(); i < n; ++i) {
        e = Operation.createInfix(Operator.ADDITION, e, parts.get(i));
      }
      return (Expression) QuasiBuilder.substV(
          "RegExp(@pattern, 'i')", "pattern", e);
View Full Code Here

            reason="lets us rename globals",
            matches="/* Expression */ @e",
            substitutes="@e")
        public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          if (node instanceof Expression && scope == null) {
            Expression e = (Expression) node;
            Block bl = new Block(
                e.getFilePosition(),
                Collections.singletonList(new ExpressionStmt(e)));
            scope = Scope.fromProgram(bl, AlphaRenamingRewriter.this);
            contexts.put(scope, rootContext);
            return expand(e, scope);
          }
          return NONE;
        }
      },

      new Rule() {
        @Override
        @RuleDescription(
            name="fns",
            synopsis=("introduces function scope and assigns rewritten names"
                      + " for function names, formals, and locals"),
            reason="",
            matches="function @name?(@params*) { @body* }",
            substitutes="function @name?(@params*) { @headDecls?; @body* }")
        public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          FunctionConstructor fc;
          if (node instanceof FunctionConstructor) {
            fc = (FunctionConstructor) node;
          } else if (node instanceof FunctionDeclaration) {
            fc = ((FunctionDeclaration) node).getInitializer();
          } else {
            return NONE;
          }
          Map<String, ParseTreeNode> bindings = match(fc);
          if (bindings != null) {
            boolean isDeclaration = fc != node;
            NameContext<String, ?> context = contexts.get(scope);
            NameContext<String, ?> newContext = context.makeChildContext();
            Scope newScope = Scope.fromFunctionConstructor(scope, fc);
            List<Declaration> headDecls = Lists.newArrayList();

            if (newScope.hasFreeThis()) {
              NameContext.VarInfo<String, ?> vi;
              try {
                vi = newContext.declare("this", FilePosition.UNKNOWN);
              } catch (NameContext.RedeclarationException ex) {
                throw new SomethingWidgyHappenedError(
                    "Local variable unexpectedly not set", ex);
              }
              headDecls.add((Declaration) QuasiBuilder.substV(
                  "var @newName = this",
                  "newName", new Identifier(FilePosition.UNKNOWN, vi.newName)));
            }
            if (newScope.hasFreeArguments()) {
              NameContext.VarInfo<String, ?> vi;
              try {
                vi = newContext.declare("arguments", FilePosition.UNKNOWN);
              } catch (NameContext.RedeclarationException ex) {
                throw new SomethingWidgyHappenedError(
                    "Local variable unexpectedly not set", ex);
              }
              headDecls.add((Declaration) QuasiBuilder.substV(
                  "var @newName = arguments",
                  "newName", new Identifier(FilePosition.UNKNOWN, vi.newName)));
            }

            for (String local : newScope.getLocals()) {
              try {
                newContext.declare(
                    local, newScope.getLocationOfDeclaration(local));
              } catch (NameContext.RedeclarationException ex) {
                // Might occur if a var named arguments is defined.
              }
            }
            contexts.put(newScope, newContext);

            Identifier name = fc.getIdentifier();
            Identifier rewrittenName;
            if (name.getName() == null) {
              rewrittenName = name;
            } else if (!isSynthetic(name)) {
              rewrittenName = new Identifier(
                  name.getFilePosition(),
                  (isDeclaration ? context : newContext)
                  .lookup(name.getName()).newName);
            } else {
              rewrittenName = name;
            }

            List<FormalParam> newFormals = Lists.newArrayList();
            for (FormalParam p : fc.getParams()) {
              if (!isSynthetic(p.getIdentifier())) {
                NameContext.VarInfo<String, ?> v
                    = newContext.lookup(p.getIdentifierName());
                if (v == null) {
                  // Occurs when an invalid parameter appears,
                  // e.g., function (arguments) { ... }
                  try {
                    v = newContext.declare(
                        p.getIdentifierName(), p.getFilePosition());
                  } catch (NameContext.RedeclarationException ex) {
                    // If it was previously declared then v wouldn't be null.
                    throw new SomethingWidgyHappenedError(ex);
                  }
                }
                FormalParam newP = new FormalParam(new Identifier(
                    p.getFilePosition(), v.newName));
                newFormals.add(newP);
              } else {
                newFormals.add(p);
              }
            }

            // For a declaration, a name is normally introduced in both the
            // scope containing the declaration, and the function body scope.
            // We produce a declaration with the outer name, but in the inner
            // scope the function name should refer to the function itself.
            // The only exception is that if there is a local declaration
            // inside the local scope that masks the function name, then we
            // should not clobber it.
            // Examples:
            //     (function f() {
            //       var f = 0;
            //       return f;
            //     })() === 0
            // and
            //     (function f() {
            //       function f() { return 0; }
            //       return f();
            //     })() === 0
            //
            // Because the var f or inner function f masks the outer function f,
            // the name "f" should not be considered to refer to the function
            // within its body. The condition
            //     newScope.isFunction(name.getName())
            //     && !newScope.isDeclaredFunction(name.getName())
            // checks that the name still refers to the outer function, not a
            // variable or a different function that is declared within the
            // body.
            // The second clause is required because isDeclaredFunction implies
            // isDeclaredFunction but we need to distinguish the two cases.
            // For a declaration, a name is normally introduced in both the
            // scope containing the declaration, and the function body scope.
            // We produce a declaration with the outer name, but in the inner
            // scope the function name should refer to the function itself.
            // The only exception is that if there is a local declaration
            // inside the local scope that masks the function name, then we
            // should not clobber it.
            // Examples:
            //     (function f() {
            //       var f = 0;
            //       return f;
            //     })() === 0
            // and
            //     (function f() {
            //       function f() { return 0; }
            //       return f();
            //     })() === 0
            //
            // Because the var f or inner function f masks the outer function f,
            // the name "f" should not be considered to refer to the function
            // within its body. The condition
            //     newScope.isFunction(name.getName())
            //     && !newScope.isDeclaredFunction(name.getName())
            // checks that the name still refers to the outer function, not a
            // variable or a different function that is declared within the
            // body.
            // The second clause is required because isDeclaredFunction implies
            // isFunction but we need to distinguish the two cases.
            if (isDeclaration && !isSynthetic(name)
                && newScope.isFunction(name.getName())
                && !newScope.isDeclaredFunction(name.getName())) {
              headDecls.add((Declaration) QuasiBuilder.substV(
                  "var @innerName = @outerName;",
                  "outerName", new Reference(rewrittenName),
                  "innerName", new Identifier(
                      name.getFilePosition(),
                      newContext.lookup(name.getName()).newName)));
              // TODO(mikesamuel): skip if the self name is never used.
            }

            FunctionConstructor out = (FunctionConstructor) substV(
                "name", rewrittenName,
                "headDecls", optionalDeclarations(headDecls),
                "params", new ParseTreeNodeContainer(newFormals),
                "body", expandAll(bindings.get("body"), newScope));
            return isDeclaration ? new FunctionDeclaration(out) : out;
          }
          return NONE;
        }
      },

      new Rule() {
        @Override
        @RuleDescription(
            name="block",
            synopsis="block scoping",
            reason="",
            matches="{ @body* }",
            substitutes="{ @body* }")
        public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          if (node instanceof Block) {
            Block bl = (Block) node;
            List<Statement> stmts = Lists.newArrayList();
            Scope newScope = Scope.fromPlainBlock(scope);
            NameContext<String, ?> newContext = contexts.get(scope)
                .makeChildContext();
            contexts.put(newScope, newContext);
            for (String local : newScope.getLocals()) {
              try {
                newContext.declare(
                    local, newScope.getLocationOfDeclaration(local));
              } catch (NameContext.RedeclarationException ex) {
                throw new SomethingWidgyHappenedError(
                    "Local variable unexpectedly not set", ex);
              }
            }
            for (Statement s : bl.children()) {
              stmts.add((Statement) expand(s, newScope));
            }
            stmts.addAll(0, newScope.getStartStatements());
            return new Block(bl.getFilePosition(), stmts);
          }
          return NONE;
        }
      },

      new Rule() {
        @Override
        @RuleDescription(
            name="catch",
            synopsis="catch block scoping",
            reason="",
            matches="catch (@e) { @body* }",
            substitutes="catch (@e) { @body* }")
        public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          if (node instanceof CatchStmt) {
            CatchStmt cs = (CatchStmt) node;
            Scope newScope = Scope.fromCatchStmt(scope, cs);
            NameContext<String, ?> context = contexts.get(scope);
            NameContext<String, ?> newContext = context.makeChildContext();
            contexts.put(newScope, newContext);
            try {
              newContext.declare(cs.getException().getIdentifierName(),
                                 cs.getException().getFilePosition());
            } catch (NameContext.RedeclarationException ex) {
              ex.toMessageQueue(mq);
            }
            return expandAll(cs, newScope);
          }
          return NONE;
        }
      },

      //////////////
      // Renaming //
      //////////////

      new Rule() {
        @Override
        @RuleDescription(
            name="memberAccess",
            synopsis="",
            reason="so that we do not mistakenly rename property names",
            matches="@o.@r",
            substitutes="@o.@r")
        public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          Map<String, ParseTreeNode> bindings = match(node);
          if (bindings != null) {
            return substV("o", expand(bindings.get("o"), scope),
                          "r", bindings.get("r"));
          }
          return NONE;
        }
      },
      new Rule() {
        @Override
        @RuleDescription(
            name="thisReference",
            synopsis="Disallow this in the global scope.",
            reason="The declaration cannot be rewritten.",
            matches="this",
            substitutes="this")
            public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          if (match(node) != null) {
            if (scope.isOuter()) {
              mq.addMessage(
                  RewriterMessageType.THIS_IN_GLOBAL_CONTEXT,
                  node.getFilePosition());
              return new NullLiteral(node.getFilePosition());
            }
          }
          return NONE;
        }
      },
      new Rule() {
        @Override
        @RuleDescription(
            name="argumentsReference",
            synopsis="Disallow arguments in the global scope.",
            reason="The declaration cannot be rewritten.",
            matches="arguments",
            substitutes="arguments")
            public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          if (match(node) != null) {
            if (scope.isOuter()) {
              mq.addMessage(
                  RewriterMessageType.ARGUMENTS_IN_GLOBAL_CONTEXT,
                  node.getFilePosition());
              return new NullLiteral(node.getFilePosition());
            }
          }
          return NONE;
        }
      },
      new Rule() {
        @Override
        @RuleDescription(
            name="rename",
            synopsis="",
            reason="",
            matches="/* Reference */ @r",
            substitutes="@r")
        public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          if (node instanceof Reference) {
            Reference r = (Reference) node;
            if (!isSynthetic(r)) {
              FilePosition pos = r.getFilePosition();
              String rname = r.getIdentifierName();
              NameContext<String, ?> context = contexts.get(scope);
              NameContext.VarInfo<String, ?> vi = context.lookup(rname);
              if (vi != null) {
                return new Reference(new Identifier(pos, vi.newName));
              } else {
                mq.addMessage(
                    RewriterMessageType.FREE_VARIABLE, pos,
                    MessagePart.Factory.valueOf(rname));
                return new NullLiteral(pos);
              }
            }
          }
          return NONE;
        }
      },
      new Rule() {
        @Override
        @RuleDescription(
            name="decl",
            synopsis="rewrite declaration identifiers",
            reason="",
            matches="var @i = @v?",
            substitutes="var @ri = @v?;")
        public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
          Map<String, ParseTreeNode> bindings = match(node);
          if (bindings != null) {
            Identifier i = (Identifier) bindings.get("i");
            Expression v = (Expression) bindings.get("v");
            Identifier ri;
            if (!isSynthetic(i)) {
              NameContext<String, ?> context = contexts.get(scope);
              NameContext.VarInfo<String, ?> var = context.lookup(i.getName());
              if (var == null) {  // A variable like arguments
View Full Code Here

  private static void optimize(ParseTreeNode node, ScopeTree t) {
    if (node instanceof Operation) {
      Operation op = (Operation) node;
      if (op.getOperator() == Operator.SQUARE_BRACKET) {
        Expression index = op.children().get(1);
        Set<String> expanding = new HashSet<String>();
        if (isVisiblePropertyExpr(index, t, expanding)) {
          Operation numIndex = Operation.create(
              index.getFilePosition(), Operator.TO_NUMBER, index);
          numIndex.setFilePosition(index.getFilePosition());
          op.replaceChild(numIndex, index);
        }
      }
    }
    for (ParseTreeNode child : node.children()) {
View Full Code Here

        // a function call or thrown exception, assume it's not numeric.
        if (d instanceof FormalParam) { return false; }
        if (use.parent.parent.node instanceof CatchStmt) { return false; }
        // Otherwise the initializer had better not be a non-numeric value.
        if (d.getInitializer() != null) {
          Expression init = d.getInitializer();
          if (!isVisiblePropertyExpr(init, scopeTree, identifiersExpanding)) {
            return false;
          }
        } else if (isKeyReceiver(use)) {
          return false;
View Full Code Here

    if (e instanceof NumberLiteral) { return true; }
    if (e instanceof Operation) {
      Operation op = (Operation) e;
      switch (op.getOperator()) {
        case COMMA:
          Expression last = op.children().get(1);
          return isVisiblePropertyExpr(last, scopeTree, identifiersExpanding);
        // || and && pass through one of their operands unchanged.
        // The addition operator works as follows:
        // 11.6.1 Additive Operator
        //   ...
View Full Code Here

          && substitutes.get(subsSize) instanceof StringLiteral) {
        if (getValue().createSubstitutes(substitutes, bindings)) {
          int subsSizeValue = substitutes.size();
          if (subsSizeValue == subsSizeKey + 1) {
            StringLiteral key = (StringLiteral) substitutes.get(subsSize);
            Expression value = (Expression) substitutes.get(subsSize + 1);
            substitutes.subList(subsSize, substitutes.size()).clear();
            substitutes.add(new ValueProperty(key, value));
            return true;
          }
        }
View Full Code Here

  private static QuasiNode buildObjectConstructorNode(ObjectConstructor obj) {
    List<QuasiNode> propQuasis = Lists.newArrayList();
    for (ObjProperty prop : obj.children()) {
      StringLiteral key = prop.getPropertyNameNode();
      if (prop instanceof ValueProperty) {
        Expression value = ((ValueProperty) prop).getValueExpr();
        String keyIdent = quasiIdent(key);
        if (value instanceof Reference) {
          String valueStr = ((Reference) value).getIdentifierName();
          if (keyIdent != null && keyIdent.endsWith("*")
              && valueStr.startsWith("@") && valueStr.endsWith("*")) {
View Full Code Here

  protected Expression commas(Expression... operands) {
    if (operands.length == 0) {
      return Operation.undefined(FilePosition.UNKNOWN);
    }
    Expression result = operands[0];
    for (int i = 1; i < operands.length; i++) {
      result = comma(result, operands[i]);
    }
    return result;
  }
View Full Code Here

  }

  private ReadAssignOperands sideEffectingReadAssignOperand(
      Expression uncajoledObject, Expression uncajoledKey, Scope scope) {
    Reference object;  // The object that contains the field to assign.
    Expression key;  // Identifies the field to assign.
    List<Expression> temporaries = Lists.newArrayList();

    // Don't cajole the operands.  We return a simple assignment operator that
    // can then itself be cajoled, so that a rewriter can use context to treat
    // the LHS differently from the RHS.

    // a[b] += 2
    //   =>
    // var x___ = a;
    // var x0___ = b;

    // If the right is simple then we can assume it does not modify the
    // left, but otherwise the left has to be put into a temporary so that
    // it's evaluated before the right can muck with it.
    boolean isKeySimple = (uncajoledKey instanceof Literal
                           || isLocalReference(uncajoledKey, scope));

    // If the left is simple and the right does not need a temporary variable
    // then don't introduce one.
    if (isKeySimple && (isLocalReference(uncajoledObject, scope)
                        || isImportsReference(uncajoledObject))) {
      object = (Reference) uncajoledObject;
    } else {
      Reference tmpVar = scope.declareStartOfScopeTemp();
      temporaries.add((Expression) QuasiBuilder.substV(
          "@tmpVar = @left;",
          "tmpVar", tmpVar,
          "left", rewriter.expand(uncajoledObject, scope)));
      object = tmpVar;
    }

    // Don't bother to generate a temporary for a simple value like 'foo'
    if (isKeySimple) {
      key = uncajoledKey;
    } else {
      ParseTreeNode rightExpanded = rewriter.expand(uncajoledKey, scope);
      Reference tmpVar = scope.declareStartOfScopeTemp();
      key = tmpVar;
      if (QuasiBuilder.match("@s&(-1>>>1)", rightExpanded)) {
        // TODO(metaweta): Figure out a way to leave key alone and
        // protect propertyAccess from rewriting instead.
        key = (Expression) QuasiBuilder.substV("@key&(-1>>>1)", "key", key);
      }
      temporaries.add((Expression) QuasiBuilder.substV(
          "@tmpVar = @right;",
          "tmpVar", tmpVar,
          "right", rightExpanded));
    }

    Operation propertyAccess = null;
    if (key instanceof StringLiteral) {
      // Make sure that cases like
      //   arr.length -= 1
      // optimize arr.length in the right-hand-side usage.
      // See the array length case in testSetReadModifyWriteLocalVar.
      String keyText = ((StringLiteral) key).getUnquotedValue();
      if (ParserBase.isJavascriptIdentifier(keyText)
          && Keyword.fromString(keyText) == null) {
        Reference ident = new Reference(
            new Identifier(key.getFilePosition(), keyText));
        propertyAccess = Operation.create(
            FilePosition.span(object.getFilePosition(), key.getFilePosition()),
            Operator.MEMBER_ACCESS, object, ident);
      }
    }
    if (propertyAccess == null) {
      propertyAccess = Operation.create(
          FilePosition.span(object.getFilePosition(), key.getFilePosition()),
          Operator.SQUARE_BRACKET, object, key);
    }
    return new ReadAssignOperands(
        temporaries, propertyAccess,
        (Expression) rewriter.expand(propertyAccess, scope));
View Full Code Here

TOP

Related Classes of com.google.caja.parser.js.Expression

Copyright © 2018 www.massapicom. 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.