Package com.google.caja.parser.js

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


                      + " 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;
View Full Code Here


          reason="Synthetic functions allow generated code to avoid introducing"
              + " unnecessary scopes.",
          matches="/* synthetic */ function @i?(@actuals*) { @body* }",
          substitutes="<expanded>")
      public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
        FunctionConstructor ctor = node instanceof FunctionDeclaration
            ? ((FunctionDeclaration) node).getInitializer()
            : (FunctionConstructor) node;
        if (isSynthetic(ctor)) {
          Scope newScope = Scope.fromFunctionConstructor(scope, ctor);
          ParseTreeNode result = expandAll(node, newScope);
View Full Code Here

    for (JobEnvelope env : jobs.getJobsByType(ContentType.JS)) {
      Job job = env.job;
      if (job.getRoot() instanceof CajoledModule) {
        jobs.getJobs().remove(env);
        ObjectConstructor cs = ((CajoledModule) job.getRoot()).getModuleBody();
        FunctionConstructor instantiate = (FunctionConstructor)
            ((ValueProperty) cs.propertyWithName("instantiate")).getValueExpr();
        jobs.getJobs().add(
            JobEnvelope.of(Job.jsJob(instantiate.getBody(), null)));
      }
    }
    return true;
  }
View Full Code Here

TOP

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

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.