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); }
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; }
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); }
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; }
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; }
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; }
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); }