Ejemplo n.º 1
0
 private static String getPath(Map<String, Object> map, String part) {
   Object obj = "/".equals(part) ? null : map.get(part);
   if (obj == null) {
     obj = map.get("/");
     if (obj != null) {
       return (String) obj;
     }
     obj = map.get("*");
     String path = (String) obj;
     if (path != null && path.endsWith("*")) {
       return path.substring(0, path.length() - 1) + part;
     } else {
       return path;
     }
   }
   if (obj instanceof String) {
     return (String) obj;
   }
   map = (Map<String, Object>) obj;
   obj = map.get("/");
   if (obj != null) {
     return (String) obj;
   }
   obj = map.get("*");
   return (String) obj;
 }
Ejemplo n.º 2
0
  /** Registers the given script as a top-level script in the debugger. */
  private void registerTopScript(DebuggableScript topScript, String source) {
    if (!topScript.isTopLevel()) {
      throw new IllegalArgumentException();
    }
    String url = getNormalizedUrl(topScript);
    DebuggableScript[] functions = getAllFunctions(topScript);
    final SourceInfo sourceInfo = new SourceInfo(source, functions, url);

    synchronized (urlToSourceInfo) {
      SourceInfo old = urlToSourceInfo.get(url);
      if (old != null) {
        sourceInfo.copyBreakpointsFrom(old);
      }
      urlToSourceInfo.put(url, sourceInfo);
      for (int i = 0; i != sourceInfo.functionSourcesTop(); ++i) {
        FunctionSource fsource = sourceInfo.functionSource(i);
        String name = fsource.name();
        if (name.length() != 0) {
          functionNames.put(name, fsource);
        }
      }
    }

    synchronized (functionToSource) {
      for (int i = 0; i != functions.length; ++i) {
        FunctionSource fsource = sourceInfo.functionSource(i);
        functionToSource.put(functions[i], fsource);
      }
    }

    callback.updateSourceText(sourceInfo);
  }
Ejemplo n.º 3
0
  public static ScriptableObject require(
      Context cx, Scriptable thisObj, Object[] args, Function funObj)
      throws ScriptException, IOException {
    String functionName = "require";
    int argsCount = args.length;
    if (argsCount != 1) {
      HostObjectUtil.invalidNumberOfArgs(
          CommonManager.HOST_OBJECT_NAME, functionName, argsCount, false);
    }
    if (!(args[0] instanceof String)) {
      HostObjectUtil.invalidArgsError(
          CommonManager.HOST_OBJECT_NAME, functionName, "1", "string", args[0], false);
    }

    String moduleId = (String) args[0];
    int dotIndex = moduleId.lastIndexOf(".");
    if (moduleId.length() == dotIndex + 1) {
      String msg = "Invalid file path for require method : " + moduleId;
      log.error(msg);
      throw new ScriptException(msg);
    }

    JaggeryContext jaggeryContext = CommonManager.getJaggeryContext();
    Map<String, ScriptableObject> requiredModules =
        (Map<String, ScriptableObject>)
            jaggeryContext.getProperty(Constants.JAGGERY_REQUIRED_MODULES);
    ScriptableObject object = requiredModules.get(moduleId);
    if (object != null) {
      return object;
    }

    if (dotIndex == -1) {
      object = CommonManager.require(cx, thisObj, args, funObj);
      initModule(cx, jaggeryContext, moduleId, object);
    } else {
      object = (ScriptableObject) cx.newObject(thisObj);
      object.setPrototype(thisObj);
      object.setParentScope(null);
      String ext = moduleId.substring(dotIndex + 1);
      if (ext.equalsIgnoreCase("json")) {
        object = executeScript(jaggeryContext, object, moduleId, true, true, false);
      } else if (ext.equalsIgnoreCase("js")) {
        object = executeScript(jaggeryContext, object, moduleId, false, true, false);
      } else if (ext.equalsIgnoreCase("jag")) {
        object = executeScript(jaggeryContext, object, moduleId, false, false, false);
      } else {
        String msg = "Unsupported file type for require() method : ." + ext;
        log.error(msg);
        throw new ScriptException(msg);
      }
    }
    requiredModules.put(moduleId, object);
    return object;
  }
  // 得到的tokens包含源代码的由词法分析器分析出的所有单词,但不包含注释
  private static ArrayList<JavaScriptToken> parse(
      Reader in, ErrorReporter reporter) // 返回tokens(保存的是源文件中出现的javascript关键字和NAME,REGEXP,STRING等类型)
      throws IOException, EvaluatorException {

    CompilerEnvirons env = new CompilerEnvirons(); // 创建编译环境对象
    env.setLanguageVersion(Context.VERSION_1_7); // 设置语言版本
    Parser parser = new Parser(env, reporter); // 创建解释器对象
    parser.parse(in, null, 1); // 解释输入流
    String source = parser.getEncodedSource(); // 获得已编码的源码(词法分析阶段通常是把从源程序中识别出的各个单词的词文
    // 转换为某种内部表示
    int offset = 0;
    int length = source.length();
    ArrayList<JavaScriptToken> tokens = new ArrayList<JavaScriptToken>();
    StringBuffer sb = new StringBuffer();

    while (offset < length) {
      int tt = source.charAt(offset++); // 获取特定位置上的字符,并转化为ASCII编码
      switch (tt) {
        case Token.CONDCOMMENT: // 条件注释
        case Token.KEEPCOMMENT: // 注释
        case Token.NAME: //
        case Token.REGEXP: // 正则表达式类型
        case Token.STRING: // String类型,js程序中双引号或单引号括起来的字符串
          sb.setLength(0);
          offset = printSourceString(source, offset, sb);
          tokens.add(new JavaScriptToken(tt, sb.toString()));
          break;

        case Token.NUMBER: // Number类型
          sb.setLength(0);
          offset = printSourceNumber(source, offset, sb);
          tokens.add(new JavaScriptToken(tt, sb.toString()));
          break;

        default:
          String literal = literals.get(new Integer(tt));
          if (literal != null) { // 若不为空,说明哈希表literals中含有键new
            // Integer(tt)所对应的值
            tokens.add(new JavaScriptToken(tt, literal)); // 将此关键字保存到数组列表tokens中
          }
          break;
      }
    }

    /*
     * //begin Iterator<JavaScriptToken> iterator = tokens.iterator();
     * JavaScriptToken token; while(iterator.hasNext()) { token =
     * iterator.next();
     * System.out.println(token.getType()+"\t"+token.getValue()); } //end
     */
    return tokens;
  }
Ejemplo n.º 5
0
 private static String resolveScriptPath(List<String> parts, Map<String, Object> map) {
   String part = parts.remove(0);
   if (parts.isEmpty()) {
     return getPath(map, part);
   }
   Object obj = map.get(part);
   if (obj == null) {
     return getPath(map, "/");
   }
   if (obj instanceof Map) {
     return resolveScriptPath(parts, (Map<String, Object>) obj);
   }
   return null;
 }
Ejemplo n.º 6
0
  private static ScriptableObject executeScript(
      JaggeryContext jaggeryContext,
      ScriptableObject scope,
      String fileURL,
      final boolean isJSON,
      boolean isBuilt,
      boolean isIncludeOnce)
      throws ScriptException {
    Stack<String> includesCallstack = CommonManager.getCallstack(jaggeryContext);
    Map<String, Boolean> includedScripts = CommonManager.getIncludes(jaggeryContext);
    ServletContext context = (ServletContext) jaggeryContext.getProperty(Constants.SERVLET_CONTEXT);
    String parent = includesCallstack.lastElement();

    String keys[] = WebAppManager.getKeys(context.getContextPath(), parent, fileURL);
    fileURL = getNormalizedScriptPath(keys);
    if (includesCallstack.search(fileURL) != -1) {
      return scope;
    }
    if (isIncludeOnce && includedScripts.get(fileURL) != null) {
      return scope;
    }

    ScriptReader source;
    RhinoEngine engine = jaggeryContext.getEngine();
    if (isBuilt) {
      source =
          new ScriptReader(context.getResourceAsStream(fileURL)) {
            @Override
            protected void build() throws IOException {
              try {
                if (isJSON) {
                  sourceReader =
                      new StringReader("(" + HostObjectUtil.streamToString(sourceIn) + ")");
                } else {
                  sourceReader = new StringReader(HostObjectUtil.streamToString(sourceIn));
                }
              } catch (ScriptException e) {
                throw new IOException(e);
              }
            }
          };
    } else {
      source = new ScriptReader(context.getResourceAsStream(fileURL));
    }

    ScriptCachingContext sctx =
        new ScriptCachingContext(jaggeryContext.getTenantId(), keys[0], keys[1], keys[2]);
    sctx.setSecurityDomain(new JaggerySecurityDomain(fileURL, context));
    long lastModified = WebAppManager.getScriptLastModified(context, fileURL);
    sctx.setSourceModifiedTime(lastModified);

    includedScripts.put(fileURL, true);
    includesCallstack.push(fileURL);
    if (isJSON) {
      scope = (ScriptableObject) engine.eval(source, scope, sctx);
    } else {
      engine.exec(source, scope, sctx);
    }
    includesCallstack.pop();
    return scope;
  }
  public StringBuffer printSymbolTree(int linebreakpos, boolean preserveAllSemiColons)
      throws IOException {

    offset = 0;
    braceNesting = 0;
    scopes.clear();

    String symbol;
    JavaScriptToken token;
    // begin
    if (tokens.size() == 0) {
      StringBuffer result = new StringBuffer();
      return result;
    }
    // end
    JavaScriptToken lastToken = getToken(0);
    ScriptOrFnScope currentScope;
    JavaScriptIdentifier identifier;

    int length = tokens.size(); // 文本的长度
    StringBuffer result = new StringBuffer();

    int linestartpos = 0;

    enterScope(globalScope); // 将globalScope压入栈scopes中

    while (offset < length) {

      token = consumeToken();
      symbol = token.getValue();
      currentScope = getCurrentScope();
      switch (token.getType()) {
        case Token.GET:
        case Token.SET:
          lastToken = token; // 注意没有break;

        case Token.NAME:
          if (offset >= 2 && getToken(-2).getType() == Token.DOT
              || getToken(0).getType() == Token.OBJECTLIT) {

            result.append(symbol);

          } else {
            identifier = getIdentifier(symbol, currentScope);
            if (identifier != null) {
              if (identifier.getMungedValue() != null) {
                result.append(identifier.getMungedValue());
              } else {
                result.append(symbol);
              }
              if (currentScope != globalScope // 全局域中的变量可能被HTML文档使用,不需要发出警告
                  && identifier.getRefcount() == 0) {
                warn("标识符" + symbol + "已经声明但未使用 ", true);
              }
            } else {
              result.append(symbol);
            }
          }
          break;

        case Token.REGEXP:
        case Token.STRING:
          result.append(symbol);
          break;

        case Token.NUMBER:
          if (getToken(0).getType() == Token.DOT) {
            // calling methods on int requires a leading dot so JS
            // doesn't
            // treat the method as the decimal component of a float
            result.append('(');
            result.append(symbol);
            result.append(')');
          } else {
            result.append(symbol);
          }
          break;

        case Token.ADD:
        case Token.SUB:
          result.append(literals.get(new Integer(token.getType())));
          if (offset < length) {
            token = getToken(0);
            if (token.getType() == Token.INC
                || token.getType() == Token.DEC
                || token.getType() == Token.ADD
                || token.getType() == Token.DEC) {
              // Handle the case x +/- ++/-- y
              // We must keep a white space here. Otherwise, x +++ y
              // would be
              // interpreted as x ++ + y by the compiler, which is a
              // bug (due
              // to the implicit(隐式的) assignment being done on the
              // wrong variable)
              result.append(' ');
            } else if (token.getType() == Token.POS && getToken(-1).getType() == Token.ADD
                || token.getType() == Token.NEG && getToken(-1).getType() == Token.SUB) {
              // Handle the case x + + y and x - - y
              result.append(' ');
            }
          }
          break;

        case Token.FUNCTION:
          if (lastToken.getType() != Token.GET && lastToken.getType() != Token.SET) {
            result.append("function");
          }
          lastToken = token;
          token = consumeToken();
          if (token.getType() == Token.NAME) {
            result.append(' ');
            symbol = token.getValue();
            identifier = getIdentifier(symbol, currentScope);
            assert identifier != null;
            if (identifier.getMungedValue() != null) {
              result.append(identifier.getMungedValue());
            } else {
              result.append(symbol);
            }
            if (currentScope != globalScope && identifier.getRefcount() == 0) {
              warn("标识符" + symbol + "已经声明但未使用", true);
            }
            token = consumeToken();
          }
          assert token.getType() == Token.LP;
          result.append('(');
          currentScope = indexedScopes.get(new Integer(offset)); // 根据左圆括号的下一个索引映射得到函数作用域
          enterScope(currentScope);
          while ((token = consumeToken()).getType() != Token.RP) {
            assert token.getType() == Token.NAME || token.getType() == Token.COMMA;
            if (token.getType() == Token.NAME) {
              symbol = token.getValue();
              identifier = getIdentifier(symbol, currentScope);
              assert identifier != null;
              if (identifier.getMungedValue() != null) {
                result.append(identifier.getMungedValue());
              } else {
                result.append(symbol);
              }
            } else if (token.getType() == Token.COMMA) {
              result.append(',');
            }
          }
          result.append(')');
          token = consumeToken(); // 得到左花括号
          assert token.getType() == Token.LC;
          result.append("{"); // nomodify
          braceNesting++;
          token = getToken(0);
          if (token.getType() == Token.STRING && getToken(1).getType() == Token.SEMI) {
            // This is a hint. Skip it!
            consumeToken();
            consumeToken();
          }
          break;

        case Token.RETURN:
        case Token.TYPEOF:
          result.append(literals.get(new Integer(token.getType())));
          // No space needed after 'return' and 'typeof' when followed
          // by '(', '[', '{', a string or a regexp.
          if (offset < length) {
            token = getToken(0);
            if (token.getType() != Token.LP
                && token.getType() != Token.LB
                && token.getType() != Token.LC
                && token.getType() != Token.STRING
                && token.getType() != Token.REGEXP
                && token.getType() != Token.SEMI) {
              result.append(' ');
            }
          }
          break;

        case Token.CASE:
        case Token.THROW:
          result.append(literals.get(new Integer(token.getType())));
          // White-space needed after 'case' and 'throw' when not followed
          // by a string.
          if (offset < length && getToken(0).getType() != Token.STRING) {
            result.append(' ');
          }
          break;

        case Token.BREAK:
        case Token.CONTINUE:
          result.append(literals.get(new Integer(token.getType())));
          if (offset < length && getToken(0).getType() != Token.SEMI) {
            // If 'break' or 'continue' is not followed by a
            // semi-colon(分号), it must
            // be followed by a label, hence(因此) the need for a white
            // space.
            result.append(' ');
          }
          break;

        case Token.LC:
          result.append("{"); // nomodify
          braceNesting++;
          break;

        case Token.RC:
          result.append('}');
          braceNesting--;
          assert braceNesting >= currentScope.getBraceNesting();
          if (braceNesting == currentScope.getBraceNesting()) {
            leaveCurrentScope();
          }
          break;

        case Token.SEMI:
          // No need to output a semi-colon if the next character is a
          // right-curly...
          if (preserveAllSemiColons || offset < length && getToken(0).getType() != Token.RC) {
            result.append(';');
          }

          if (linebreakpos >= 0 && result.length() - linestartpos > linebreakpos) {
            // Some source control tools don't like it when files
            // containing lines longer
            // than, say 8000 characters, are checked in. The linebreak
            // option is used in
            // that case to split long lines after a specific column.
            result.append('\n');
            linestartpos = result.length();
          }
          break;

        case Token.COMMA:
          // No need to output a comma if the next character is a
          // right-curly or a right-square bracket
          if (offset < length
              && getToken(0).getType() != Token.RC
              && getToken(0).getType() != Token.RB) {
            result.append(',');
          }
          break;

        case Token.CONDCOMMENT:
        case Token.KEEPCOMMENT:
          if (result.length() > 0 && result.charAt(result.length() - 1) != '\n') {
            result.append("\n");
          }
          result.append("/*");
          if (token.getType() == Token.KEEPCOMMENT) {
            result.append("!");
          }
          result.append(symbol);
          result.append("*/\n");
          break;

          // begin--这个分支用于实现压扁控制流
          // 此分支将if(expression){...}else if(expression){...}else{...}转化为
          // switch(expression){case true:原if块;break;case false:原else块;break;}
        case Token.IF:
          if (!EditOptionPanel.checkBoxFlatten.isSelected()) {
            result.append(symbol);
            break;
          }
          FlattenIF flattenIF = new FlattenIF(offset, length, tokens, currentScope);
          String switchBlock = flattenIF.flattenIF();
          result.append(switchBlock);
          offset = flattenIF.offset;
          break;
        case Token.WHILE:
          if (!EditOptionPanel.checkBoxOpacity.isSelected()) {
            result.append(symbol);
            break;
          }
          result.append(symbol);
          OpacityPredicate opacityPredicateWhile =
              new OpacityPredicate(offset, tokens, currentScope);
          String whileBlock = opacityPredicateWhile.opacityPredicateWhile();
          result.append(whileBlock);
          offset = opacityPredicateWhile.offset;
          break;
        case Token.DO:
          if (!EditOptionPanel.checkBoxOpacity.isSelected()) {
            result.append(symbol);
            break;
          }
          result.append(symbol);
          OpacityPredicate opacityPredicateDoWhile =
              new OpacityPredicate(offset, tokens, currentScope);
          String doWhileBlock = opacityPredicateDoWhile.opacityPredicateDoWhile();
          result.append(doWhileBlock);
          offset = opacityPredicateDoWhile.offset;
          break;
          // end
        default:
          String literal = literals.get(new Integer(token.getType()));
          if (literal != null) {
            result.append(literal);
          } else {
            warn("此标志符不能被打印出来:" + symbol, true);
          }
          break;
      }
    }

    // Append a semi-colon at the end, even if unnecessary semi-colons are
    // supposed to be removed. This is especially useful when concatenating
    // several minified files (the absence of an ending semi-colon at the
    // end of one file may very likely cause a syntax error)
    /*if (!preserveAllSemiColons && result.length() > 0
    		&& getToken(-1).getType() != Token.CONDCOMMENT
    		&& getToken(-1).getType() != Token.KEEPCOMMENT) {
    	if (result.charAt(result.length() - 1) == '\n') {
    		result.setCharAt(result.length() - 1, ';');
    	} else {
    		result.append(';');
    	}
    }*/
    // 暂时用不上,注释掉

    return result;
  }
Ejemplo n.º 8
0
 /** Returns the SourceInfo object for the given URL. */
 public SourceInfo sourceInfo(String url) {
   return urlToSourceInfo.get(url);
 }
Ejemplo n.º 9
0
 /** Returns the FunctionSource object for the function with the given name. */
 public FunctionSource functionSourceByName(String functionName) {
   return functionNames.get(functionName);
 }
Ejemplo n.º 10
0
 /** Returns the FunctionSource object for the given function or script. */
 private FunctionSource functionSource(DebuggableScript fnOrScript) {
   return functionToSource.get(fnOrScript);
 }