Esempio 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;
 }
  /** 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);
  }
Esempio 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;
  }
Esempio n. 4
0
  private void parseDirective(String token) {
    int index = token.indexOf(Constants.DIRECTIVE_EQUALS);
    String directiveName = token.substring(0, index).trim();
    if (directiveName.length() == 0) return;

    String value = token.substring(index + Constants.DIRECTIVE_EQUALS.length()).trim();

    if (directiveName.equals(Constants.MANDATORY_DIRECTIVE)) parseMandatory(value);

    directives.put(directiveName, value);
  }
Esempio n. 5
0
  private void parseAttribute(String token) {
    int index = token.indexOf(Constants.ATTRIBUTE_EQUALS);
    String attributeName = token.substring(0, index).trim();
    if (attributeName.length() == 0) return;

    Object value = token.substring(index + Constants.ATTRIBUTE_EQUALS.length()).trim();

    if (attributeName.equals(Constants.VERSION_ATTRIBUTE))
      version = Version.parseVersion((String) value);
    attributes.put(attributeName, value);
  }
  // 得到的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;
  }
Esempio n. 7
0
 PageInfo getPageInfo(ScriptContext context, String path) throws IOException {
   PageInfo info = null;
   if (pageInfoCache != null) info = this.pageInfoCache.get(path);
   if (info == null) {
     String file = prefix + path + suffix;
     String actualPath = FileHelper.findRecursive(file);
     String source = FileHelper.read(actualPath);
     Object object = context.evaluate(source, path);
     info = new PageInfo((BaseFunction) object, actualPath);
     if (pageInfoCache != null) pageInfoCache.put(path, info);
   }
   return info;
 }
Esempio n. 8
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;
 }
Esempio n. 9
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;
  }
  static {

    // This list contains all the 3 characters or less built-in global
    // symbols available in a browser. Please add to this list if you
    // see anything missing.
    builtin.add("NaN");
    builtin.add("top");

    ones = new ArrayList<String>();
    for (char c = 'a'; c <= 'z'; c++) ones.add(Character.toString(c));
    for (char c = 'A'; c <= 'Z'; c++) ones.add(Character.toString(c));

    twos = new ArrayList<String>();
    for (int i = 0; i < ones.size(); i++) {
      String one = ones.get(i);
      for (char c = 'a'; c <= 'z'; c++) twos.add(one + Character.toString(c));
      for (char c = 'A'; c <= 'Z'; c++) twos.add(one + Character.toString(c));
      for (char c = '0'; c <= '9'; c++) twos.add(one + Character.toString(c));
    }

    // Remove two-letter JavaScript reserved words and built-in globals...
    twos.remove("as");
    twos.remove("is");
    twos.remove("do");
    twos.remove("if");
    twos.remove("in");
    twos.removeAll(builtin);

    threes = new ArrayList<String>();
    for (int i = 0; i < twos.size(); i++) {
      String two = twos.get(i);
      for (char c = 'a'; c <= 'z'; c++) threes.add(two + Character.toString(c));
      for (char c = 'A'; c <= 'Z'; c++) threes.add(two + Character.toString(c));
      for (char c = '0'; c <= '9'; c++) threes.add(two + Character.toString(c));
    }

    // Remove three-letter JavaScript reserved words and built-in globals...
    threes.remove("for");
    threes.remove("int");
    threes.remove("new");
    threes.remove("try");
    threes.remove("use");
    threes.remove("var");
    threes.removeAll(builtin);

    // That's up to ((26+26)*(1+(26+26+10)))*(1+(26+26+10))-8
    // (206,380 symbols per scope)

    // The following list comes from
    // org/mozilla/javascript/Decompiler.java...
    // 注意:此处并为认为地设定键与值的acsii码相等,比如Token.ASSIGN是89,而'='为61
    literals.put(new Integer(Token.GET), "get ");
    literals.put(new Integer(Token.SET), "set ");
    literals.put(new Integer(Token.TRUE), "true");
    literals.put(new Integer(Token.FALSE), "false");
    literals.put(new Integer(Token.NULL), "null");
    literals.put(new Integer(Token.THIS), "this");
    literals.put(new Integer(Token.FUNCTION), "function");
    literals.put(new Integer(Token.COMMA), ",");
    literals.put(new Integer(Token.LC), "{");
    literals.put(new Integer(Token.RC), "}");
    literals.put(new Integer(Token.LP), "(");
    literals.put(new Integer(Token.RP), ")");
    literals.put(new Integer(Token.LB), "[");
    literals.put(new Integer(Token.RB), "]");
    literals.put(new Integer(Token.DOT), ".");
    literals.put(new Integer(Token.NEW), "new ");
    literals.put(new Integer(Token.DELPROP), "delete ");
    literals.put(new Integer(Token.IF), "if");
    literals.put(new Integer(Token.ELSE), "else");
    literals.put(new Integer(Token.FOR), "for");
    literals.put(new Integer(Token.IN), " in ");
    literals.put(new Integer(Token.WITH), "with");
    literals.put(new Integer(Token.WHILE), "while");
    literals.put(new Integer(Token.DO), "do");
    literals.put(new Integer(Token.TRY), "try");
    literals.put(new Integer(Token.CATCH), "catch");
    literals.put(new Integer(Token.FINALLY), "finally");
    literals.put(new Integer(Token.THROW), "throw");
    literals.put(new Integer(Token.SWITCH), "switch");
    literals.put(new Integer(Token.BREAK), "break");
    literals.put(new Integer(Token.CONTINUE), "continue");
    literals.put(new Integer(Token.CASE), "case");
    literals.put(new Integer(Token.DEFAULT), "default");
    literals.put(new Integer(Token.RETURN), "return");
    literals.put(new Integer(Token.VAR), "var ");
    literals.put(new Integer(Token.SEMI), ";");
    literals.put(new Integer(Token.ASSIGN), "=");
    literals.put(new Integer(Token.ASSIGN_ADD), "+=");
    literals.put(new Integer(Token.ASSIGN_SUB), "-=");
    literals.put(new Integer(Token.ASSIGN_MUL), "*=");
    literals.put(new Integer(Token.ASSIGN_DIV), "/=");
    literals.put(new Integer(Token.ASSIGN_MOD), "%=");
    literals.put(new Integer(Token.ASSIGN_BITOR), "|=");
    literals.put(new Integer(Token.ASSIGN_BITXOR), "^=");
    literals.put(new Integer(Token.ASSIGN_BITAND), "&=");
    literals.put(new Integer(Token.ASSIGN_LSH), "<<=");
    literals.put(new Integer(Token.ASSIGN_RSH), ">>=");
    literals.put(new Integer(Token.ASSIGN_URSH), ">>>=");
    literals.put(new Integer(Token.HOOK), "?");
    literals.put(new Integer(Token.OBJECTLIT), ":");
    literals.put(new Integer(Token.COLON), ":");
    literals.put(new Integer(Token.OR), "||");
    literals.put(new Integer(Token.AND), "&&");
    literals.put(new Integer(Token.BITOR), "|");
    literals.put(new Integer(Token.BITXOR), "^");
    literals.put(new Integer(Token.BITAND), "&");
    literals.put(new Integer(Token.SHEQ), "===");
    literals.put(new Integer(Token.SHNE), "!==");
    literals.put(new Integer(Token.EQ), "==");
    literals.put(new Integer(Token.NE), "!=");
    literals.put(new Integer(Token.LE), "<=");
    literals.put(new Integer(Token.LT), "<");
    literals.put(new Integer(Token.GE), ">=");
    literals.put(new Integer(Token.GT), ">");
    literals.put(new Integer(Token.INSTANCEOF), " instanceof ");
    literals.put(new Integer(Token.LSH), "<<");
    literals.put(new Integer(Token.RSH), ">>");
    literals.put(new Integer(Token.URSH), ">>>");
    literals.put(new Integer(Token.TYPEOF), "typeof");
    literals.put(new Integer(Token.VOID), "void ");
    literals.put(new Integer(Token.CONST), "const ");
    literals.put(new Integer(Token.NOT), "!");
    literals.put(new Integer(Token.BITNOT), "~");
    literals.put(new Integer(Token.POS), "+");
    literals.put(new Integer(Token.NEG), "-");
    literals.put(new Integer(Token.INC), "++");
    literals.put(new Integer(Token.DEC), "--");
    literals.put(new Integer(Token.ADD), "+");
    literals.put(new Integer(Token.SUB), "-");
    literals.put(new Integer(Token.MUL), "*");
    literals.put(new Integer(Token.DIV), "/");
    literals.put(new Integer(Token.MOD), "%");
    literals.put(new Integer(Token.COLONCOLON), "::");
    literals.put(new Integer(Token.DOTDOT), "..");
    literals.put(new Integer(Token.DOTQUERY), ".(");
    literals.put(new Integer(Token.XMLATTR), "@");
    literals.put(new Integer(Token.LET), "let ");
    literals.put(new Integer(Token.YIELD), "yield ");

    // See
    // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Reserved_Words

    // JavaScript 1.5 reserved words
    reserved.add("break");
    reserved.add("case");
    reserved.add("catch");
    reserved.add("continue");
    reserved.add("default");
    reserved.add("delete");
    reserved.add("do");
    reserved.add("else");
    reserved.add("finally");
    reserved.add("for");
    reserved.add("function");
    reserved.add("if");
    reserved.add("in");
    reserved.add("instanceof");
    reserved.add("new");
    reserved.add("return");
    reserved.add("switch");
    reserved.add("this");
    reserved.add("throw");
    reserved.add("try");
    reserved.add("typeof");
    reserved.add("var");
    reserved.add("void");
    reserved.add("while");
    reserved.add("with");
    // Words reserved for future use
    reserved.add("abstract");
    reserved.add("boolean");
    reserved.add("byte");
    reserved.add("char");
    reserved.add("class");
    reserved.add("const");
    reserved.add("debugger");
    reserved.add("double");
    reserved.add("enum");
    reserved.add("export");
    reserved.add("extends");
    reserved.add("final");
    reserved.add("float");
    reserved.add("goto");
    reserved.add("implements");
    reserved.add("import");
    reserved.add("int");
    reserved.add("interface");
    reserved.add("long");
    reserved.add("native");
    reserved.add("package");
    reserved.add("private");
    reserved.add("protected");
    reserved.add("public");
    reserved.add("short");
    reserved.add("static");
    reserved.add("super");
    reserved.add("synchronized");
    reserved.add("throws");
    reserved.add("transient");
    reserved.add("volatile");
    // These are not reserved, but should be taken into account
    // in isValidIdentifier (See jslint source code)
    reserved.add("arguments");
    reserved.add("eval");
    reserved.add("true");
    reserved.add("false");
    reserved.add("Infinity");
    reserved.add("NaN");
    reserved.add("null");
    reserved.add("undefined");
  }
  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;
  }
 /** Clears all breakpoints. */
 public void clearAllBreakpoints() {
   for (SourceInfo si : urlToSourceInfo.values()) {
     si.removeAllBreakpoints();
   }
 }
 /** Returns the SourceInfo object for the given URL. */
 public SourceInfo sourceInfo(String url) {
   return urlToSourceInfo.get(url);
 }
 /** Returns the FunctionSource object for the function with the given name. */
 public FunctionSource functionSourceByName(String functionName) {
   return functionNames.get(functionName);
 }
 /** Returns an array of all function names. */
 public String[] functionNames() {
   synchronized (urlToSourceInfo) {
     return functionNames.keySet().toArray(new String[functionNames.size()]);
   }
 }
 /** Returns the FunctionSource object for the given function or script. */
 private FunctionSource functionSource(DebuggableScript fnOrScript) {
   return functionToSource.get(fnOrScript);
 }