public String toString() { StringBuffer sb = new StringBuffer(); sb.append(getClass().getName()); sb.append('@'); sb.append(Integer.toHexString(System.identityHashCode(this))); sb.append(" (context="); sb.append(_context); sb.append(", static_permitions="); sb.append(_statisPermissions); sb.append(')'); return sb.toString(); }
// 得到的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; }
protected int[] resize( int thumbWidth, int thumbHeight, int imageWidth, int imageHeight, String srcPath, String dstPath, boolean scaleComputed) { if (!scaleComputed) { int[] dims = computeResizedDimensions(thumbWidth, thumbHeight, imageWidth, imageHeight); thumbWidth = dims[0]; thumbHeight = dims[1]; } String[] paths = escapePaths(srcPath, dstPath); srcPath = paths[0]; dstPath = paths[1]; String cmd = core.app.getProperty("imagemagick"); boolean success = false; if (cmd == null) { RenderedOp resizedImage = this.resizeJAI( thumbWidth, thumbHeight, FileLoadDescriptor.create(srcPath, null, null, null), false); // Don't like the pre-calculated scaling. Recalculate it. String type = dstPath.substring(dstPath.lastIndexOf(".") + 1); success = writeImage(dstPath, type, resizedImage); } else { if (!cmd.endsWith("convert")) { if (!cmd.endsWith(File.separator)) { cmd += File.separator; } cmd += "convert"; } StringBuffer command = new StringBuffer(cmd); command.append(" -geometry "); command.append(thumbWidth).append("x").append(thumbHeight); command.append(" ").append(srcPath); command.append(" ").append(dstPath); success = exec(command.toString()); } if (success) { return new int[] {thumbWidth, thumbHeight}; } return null; }
/** Returns the source URL for the given script or function. */ private String getNormalizedUrl(DebuggableScript fnOrScript) { String url = fnOrScript.getSourceName(); if (url == null) { url = "<stdin>"; } else { // Not to produce window for eval from different lines, // strip line numbers, i.e. replace all #[0-9]+\(eval\) by // (eval) // Option: similar teatment for Function? char evalSeparator = '#'; StringBuffer sb = null; int urlLength = url.length(); int cursor = 0; for (; ; ) { int searchStart = url.indexOf(evalSeparator, cursor); if (searchStart < 0) { break; } String replace = null; int i = searchStart + 1; while (i != urlLength) { int c = url.charAt(i); if (!('0' <= c && c <= '9')) { break; } ++i; } if (i != searchStart + 1) { // i points after #[0-9]+ if ("(eval)".regionMatches(0, url, i, 6)) { cursor = i + 6; replace = "(eval)"; } } if (replace == null) { break; } if (sb == null) { sb = new StringBuffer(); sb.append(url.substring(0, searchStart)); } sb.append(replace); } if (sb != null) { if (cursor != urlLength) { sb.append(url.substring(cursor)); } url = sb.toString(); } } return url; }
@Override String toXMLString() { // See ECMA 10.2.1 StringBuffer sb = new StringBuffer(); for (int i = 0; i < length(); i++) { if (getProcessor().isPrettyPrinting() && i != 0) { sb.append('\n'); } sb.append(getXmlFromAnnotation(i).toXMLString()); } return sb.toString(); }
protected int[] crop( int width, int height, int offsetx, int offsety, String srcPath, String dstPath) { String[] paths = escapePaths(srcPath, dstPath); srcPath = paths[0]; dstPath = paths[1]; boolean success = false; String cmd = core.app.getProperty("imagemagick"); if (cmd == null) { ParameterBlock args = new ParameterBlock(); args.addSource(FileLoadDescriptor.create(srcPath, null, null, null)); args.add((float) offsetx); args.add((float) offsety); args.add((float) width); args.add((float) height); RenderedOp croppedImage = JAI.create("crop", args); String type = dstPath.substring(dstPath.lastIndexOf(".") + 1); success = writeImage(dstPath, type, croppedImage); } else { if (!cmd.endsWith("convert")) { if (!cmd.endsWith(File.separator)) { cmd += File.separator; } cmd += "convert"; } StringBuffer command = new StringBuffer(cmd); command.append(" -crop "); command .append(width) .append("x") .append(height) .append("+") .append(offsetx) .append("+") .append(offsety) .append("!"); command.append(" ").append(srcPath); command.append(" ").append(dstPath); success = exec(command.toString()); } if (success) { return new int[] {width, height}; } return null; }
private static int printSourceNumber(String source, int offset, StringBuffer sb) { double number = 0.0; char type = source.charAt(offset); ++offset; if (type == 'S') { if (sb != null) { number = source.charAt(offset); } ++offset; } else if (type == 'J' || type == 'D') { if (sb != null) { long lbits; lbits = (long) source.charAt(offset) << 48; lbits |= (long) source.charAt(offset + 1) << 32; lbits |= (long) source.charAt(offset + 2) << 16; lbits |= (long) source.charAt(offset + 3); if (type == 'J') { number = lbits; } else { number = Double.longBitsToDouble(lbits); } } offset += 4; } else { // Bad source throw new RuntimeException(); } if (sb != null) { sb.append(ScriptRuntime.numberToString(number, 10)); } return offset; }
/** * Adds another Image object as a thumbnail (child) of this Image object, which can be retrieved * using <code> getThumbnail(accessname) </code>. * * @param {Image} child The Image object to add as a child of this Image object * @param {String} [accessname] The accessname by which the child Image object may be retrieved by * calling getThumbnail(accessname). If this argument is left unspecified, defaults to a * String "[width]x[height]". So if the width is 200 and the height is 100, the default * accessname will be 200x100 * @returns {Boolean} Whether the operation was a success or not. If there is already an Image * object with the same name as accessname located as a child of this Image object, then it * will fail and return <code> false </code> */ public boolean jsFunction_addThumbnail(Object child, Object accessname) { if (child instanceof ImageObject) { ImageObject th = (ImageObject) child; StringBuffer sb = new StringBuffer(); if (accessname != null && accessname != Scriptable.NOT_FOUND) { sb.append((String) accessname); } else { sb.append(th.getDimension(WIDTH)).append("x").append(th.getDimension(HEIGHT)); } th.node.setString(FileObject.ACCESSNAME, sb.toString()); return super.jsFunction_add(th); } return false; }
private String getDebugString(int max) { assert max > 0; StringBuffer result = new StringBuffer(); int start = Math.max(offset - max, 0); int end = Math.min(offset + max, tokens.size()); for (int i = start; i < end; i++) { JavaScriptToken token = tokens.get(i); if (i == offset - 1) { result.append(" ---> "); } result.append(token.getValue()); if (i == offset - 1) { result.append(" <--- "); } } return result.toString(); }
protected String[] escapePaths(String srcPath, String dstPath) { srcPath = srcPath.trim(); dstPath = dstPath.trim(); String os = System.getProperty("os.name").toLowerCase(); if (os != null && os.indexOf("windows") > -1) { srcPath = "\"" + srcPath + "\""; dstPath = "\"" + dstPath + "\""; } else { int lastidx = -1, curridx; StringBuffer buff = new StringBuffer(srcPath); while ((curridx = buff.indexOf(" ", lastidx)) > 0) { buff.insert(curridx, "\\"); lastidx = curridx + 2; } srcPath = buff.toString(); buff = new StringBuffer(dstPath); lastidx = -1; while ((curridx = buff.indexOf(" ", lastidx)) > 0) { buff.insert(curridx, "\\"); lastidx = curridx + 2; } dstPath = buff.toString(); } return new String[] {srcPath, dstPath}; }
// Add necessary escaping that was removed in Rhino's tokenizer(词法分析器). private static String escapeString(String s, char quotechar) { assert quotechar == '"' || quotechar == '\''; // 如果启用了断言,则表达式为假时,程序抛出AssertionError(这是一个错误,不是异常,所以不能被捕获) if (s == null) { return null; } StringBuffer sb = new StringBuffer(); for (int i = 0, L = s.length(); i < L; i++) { int c = s.charAt(i); if (c == quotechar) { sb.append("\\"); } sb.append((char) c); } return sb.toString(); }
@Override public String toString() { // ECMA357 10.1.2 if (hasSimpleContent()) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < length(); i++) { XML next = getXmlFromAnnotation(i); if (next.isComment() || next.isProcessingInstruction()) { // do nothing } else { sb.append(next.toString()); } } return sb.toString(); } else { return toXMLString(); } }
private static int printSourceString(String source, int offset, StringBuffer sb) { int length = source.charAt(offset); ++offset; if ((0x8000 & length) != 0) { length = ((0x7FFF & length) << 16) | source.charAt(offset); ++offset; } if (sb != null) { String str = source.substring(offset, offset + length); sb.append(str); } return offset + length; }
public String printMungeMapping() { StringBuffer sb = new StringBuffer(); globalScope.getFullMapping(sb, ""); return sb.toString(); }
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; }