protected void saveTo(OutputStreamWriter writer, FastStringBuffer tempBuf, File pathToSave) throws IOException { synchronized (lock) { if (DEBUG_ADDITIONAL_INFO) { System.out.println( "Saving info " + this.getClass().getName() + " to file (size = " + getAllTokens().size() + ") " + pathToSave); } Map<String, Integer> dictionary = new HashMap<String, Integer>(); tempBuf.append("-- START TREE 1\n"); TreeIO.dumpTreeToBuffer(this.topLevelInitialsToInfo, tempBuf, dictionary); tempBuf.append("-- START TREE 2\n"); TreeIO.dumpTreeToBuffer(this.innerInitialsToInfo, tempBuf, dictionary); FastStringBuffer buf2 = new FastStringBuffer(50 * (dictionary.size() + 4)); TreeIO.dumpDictToBuffer(dictionary, buf2); // Write the dictionary before the actual trees. writer.write(buf2.getInternalCharsArray(), 0, buf2.length()); buf2 = null; // Note: tried LZFFileInputStream from https://github.com/ning/compress // and Snappy from https://github.com/dain/snappy checking to see if by writing less we'd // get a better time but it got a bit slower (gzip was slowest, then snappy and the faster was // LZFFileInputStream) writer.write(tempBuf.getInternalCharsArray(), 0, tempBuf.length()); } }
/** * We just want to trim whitespaces, not newlines! * * @param locBuf the buffer to be trimmed * @return the same buffer passed as a parameter */ private FastStringBuffer trim(FastStringBuffer locBuf) { while (locBuf.length() > 0 && (locBuf.firstChar() == ' ' || locBuf.firstChar() == '\t')) { locBuf.deleteCharAt(0); } rtrim(locBuf); return locBuf; }
/** Check if we are still in the number */ @Override public boolean isWordPart(char c) { // ok, we have to test for scientific notation e.g.: 10.9e10 if ((c == 'x' || c == 'X') && buffer.length() == 1 && buffer.charAt(0) == '0') { // it is an hexadecimal buffer.append(c); isInHexa = true; return true; } else { buffer.append(c); } if (isInHexa) { return Character.isDigit(c) || c == 'a' || c == 'A' || c == 'b' || c == 'B' || c == 'c' || c == 'C' || c == 'd' || c == 'D' || c == 'e' || c == 'E' || c == 'f' || c == 'F'; } else { return Character.isDigit(c) || c == 'e' || c == '.'; } }
public void run(IAction action) { FastStringBuffer buf = new FastStringBuffer(); try { PyEdit pyEdit = getPyEdit(); PySelection pySelection = new PySelection(pyEdit); IPythonNature nature = pyEdit.getPythonNature(); File editorFile = pyEdit.getEditorFile(); if (editorFile != null) { if (nature != null) { String mod = nature.resolveModule(editorFile); if (mod != null) { buf.append(mod); } else { // Support for external files (not in PYTHONPATH). buf.append(FullRepIterable.getFirstPart(editorFile.getName())); } } else { buf.append(FullRepIterable.getFirstPart(editorFile.getName())); } } List<stmtType> path = FastParser.parseToKnowGloballyAccessiblePath( pySelection.getDoc(), pySelection.getStartLineIndex()); for (stmtType stmtType : path) { if (buf.length() > 0) { buf.append('.'); } buf.append(NodeUtils.getRepresentationString(stmtType)); } } catch (MisconfigurationException e1) { Log.log(e1); return; } Transfer[] dataTypes = new Transfer[] {TextTransfer.getInstance()}; Object[] data = new Object[] {buf.toString()}; Clipboard clipboard = new Clipboard(EditorUtils.getShell().getDisplay()); try { clipboard.setContents(data, dataTypes); } catch (SWTError e) { if (e.code != DND.ERROR_CANNOT_SET_CLIPBOARD) { throw e; } MessageDialog.openError( EditorUtils.getShell(), "Error copying to clipboard.", e.getMessage()); } finally { clipboard.dispose(); } }
public static String getRunningName(IPath[] paths) { FastStringBuffer buf = new FastStringBuffer(20 * paths.length); for (IPath p : paths) { if (buf.length() > 0) { buf.append(" - "); } buf.append(p.lastSegment()); } return buf.toString(); }
/** * @param lastMayBeMethod if true, it gets the path and accepts a method (if it is the last in the * stack) if false, null is returned if a method is found. * @param tempStack is a temporary stack object (which may be cleared) * @return a tuple, where the first element is the path where the entry is located (may return * null). and the second element is a boolean that indicates if the last was actually a method * or not. */ private Tuple<String, Boolean> getPathToRoot( ASTEntry entry, boolean lastMayBeMethod, boolean acceptAny, FastStack<SimpleNode> tempStack) { if (entry.parent == null) { return null; } // just to be sure that it's empty tempStack.clear(); boolean lastIsMethod = false; // if the last 'may be a method', in this case, we have to remember that it will actually be the // first one // to be analyzed. // let's get the stack while (entry.parent != null) { if (entry.parent.node instanceof ClassDef) { tempStack.push(entry.parent.node); } else if (entry.parent.node instanceof FunctionDef) { if (!acceptAny) { if (lastIsMethod) { // already found a method return null; } if (!lastMayBeMethod) { return null; } // ok, the last one may be a method... (in this search, it MUST be the first one...) if (tempStack.size() != 0) { return null; } } // ok, there was a class, so, let's go and set it tempStack.push(entry.parent.node); lastIsMethod = true; } else { return null; } entry = entry.parent; } // now that we have the stack, let's make it into a path... FastStringBuffer buf = new FastStringBuffer(); while (tempStack.size() > 0) { if (buf.length() > 0) { buf.append("."); } buf.append(NodeUtils.getRepresentationString(tempStack.pop())); } return new Tuple<String, Boolean>(buf.toString(), lastIsMethod); }
public List<IInfo> addAstInfo(ModulesKey key, boolean generateDelta) throws Exception { boolean isZipModule = key instanceof ModulesKeyForZip; ModulesKeyForZip modulesKeyForZip = null; if (isZipModule) { modulesKeyForZip = (ModulesKeyForZip) key; } Object doc; if (isZipModule) { doc = FileUtilsFileBuffer.getCustomReturnFromZip( modulesKeyForZip.file, modulesKeyForZip.zipModulePath, null); } else { doc = FileUtilsFileBuffer.getCustomReturnFromFile(key.file, true, null); } char[] charArray; int len; if (doc instanceof IDocument) { IDocument document = (IDocument) doc; charArray = document.get().toCharArray(); len = charArray.length; } else if (doc instanceof FastStringBuffer) { FastStringBuffer fastStringBuffer = (FastStringBuffer) doc; // In this case, we can actually get the internal array without doing any copies (and just // specifying the len). charArray = fastStringBuffer.getInternalCharsArray(); len = fastStringBuffer.length(); } else if (doc instanceof String) { String str = (String) doc; charArray = str.toCharArray(); len = charArray.length; } else if (doc instanceof char[]) { charArray = (char[]) doc; len = charArray.length; } else { throw new RuntimeException("Don't know how to handle: " + doc + " -- " + doc.getClass()); } SimpleNode node = FastDefinitionsParser.parse(charArray, key.file.getName(), len); if (node == null) { return null; } return addAstInfo(node, key, generateDelta); }
/** Inserts a string at a given position in the buffer. */ public FastStringBuffer insert(int offset, FastStringBuffer str) { int len = str.length(); int newCount = count + len; if (newCount > value.length) { int newCapacity = (value.length + 1) * 2; if (newCount > newCapacity) { newCapacity = newCount; } char newValue[] = new char[newCapacity]; System.arraycopy(value, 0, newValue, 0, count); value = newValue; } System.arraycopy(value, offset, value, offset + len, count - offset); System.arraycopy(str.value, 0, value, offset, str.count); count = newCount; return this; }
public static Map<Integer, String> loadDictFrom( FastBufferedReader reader, FastStringBuffer buf, ObjectsPoolMap objectsPoolMap) throws IOException { int size = StringUtils.parsePositiveInt(reader.readLine()); HashMap<Integer, String> map = new HashMap<Integer, String>(size + 5); FastStringBuffer line; int val = 0; while (true) { line = reader.readLine(); if (line == null) { return map; } else if (line.startsWith("-- ")) { if (line.startsWith("-- END DICTIONARY")) { return map; } throw new RuntimeException("Unexpected line: " + line); } else { int length = line.length(); // line is str=int for (int i = 0; i < length; i++) { char c = line.charAt(i); if (c == '=') { val = StringUtils.parsePositiveInt(buf); buf.clear(); } else { buf.appendResizeOnExc(c); } } String bufStr = buf.toString(); String interned = objectsPoolMap.get(bufStr); if (interned == null) { interned = bufStr; objectsPoolMap.put(bufStr, bufStr); } map.put(val, interned); buf.clear(); } } }
/** * Adds spaces after the '#' according to the configured settings. The first char of the buffer * passed (which is also the output) should always start with a '#'. */ public static void formatComment(FormatStd std, FastStringBuffer bufWithComment) { if (std.spacesInStartComment > 0) { Assert.isTrue(bufWithComment.charAt(0) == '#'); int len = bufWithComment.length(); char firstCharFound = '\n'; String bufAsString = bufWithComment.toString(); // handle cases where the code-formatting should not take place if (FileUtils.isPythonShebangLine(bufAsString)) { return; } int spacesFound = 0; String remainingStringContent = ""; for (int j = 1; j < len; j++) { // start at 1 because 0 should always be '#' if ((firstCharFound = bufWithComment.charAt(j)) != ' ') { remainingStringContent = bufAsString.substring(j).trim(); break; } spacesFound += 1; } if (firstCharFound != '\r' && firstCharFound != '\n') { // Only add spaces if it wasn't an empty line. // handle cases where the code-formatting should not take place for (String s : BLOCK_COMMENT_SKIPS) { if (remainingStringContent.endsWith(s) || remainingStringContent.startsWith(s)) { return; } } int diff = std.spacesInStartComment - spacesFound; if (diff > 0) { bufWithComment.insertN(1, ' ', diff); } } } }
protected void save(File persistingLocation) { try { FileOutputStream stream = new FileOutputStream(persistingLocation); OutputStreamWriter writer = new OutputStreamWriter(stream); try { FastStringBuffer tempBuf = new FastStringBuffer(); tempBuf.append("-- VERSION_"); tempBuf.append(AbstractAdditionalTokensInfo.version); tempBuf.append('\n'); writer.write(tempBuf.getInternalCharsArray(), 0, tempBuf.length()); tempBuf.clear(); saveTo(writer, tempBuf, persistingLocation); } finally { try { writer.close(); } finally { stream.close(); } } } catch (Exception e) { Log.log(e); } }
public static PyPublicTreeMap<String, Set<IInfo>> loadTreeFrom( final FastBufferedReader reader, final Map<Integer, String> dictionary, FastStringBuffer buf, ObjectsPoolMap objectsPoolMap, IPythonNature nature) throws IOException { PyPublicTreeMap<String, Set<IInfo>> tree = new PyPublicTreeMap<String, Set<IInfo>>(); final int size = StringUtils.parsePositiveInt(reader.readLine()); try { final Entry[] entries = new Entry[size]; // each line is something as: cub|CubeColourDialog!13&999@CUBIC!263@cube!202&999@ // note: the path (2nd int in record) is optional for (int iEntry = 0; iEntry < size; iEntry++) { buf.clear(); FastStringBuffer line = reader.readLine(); if (line == null || line.startsWith("-- ")) { throw new RuntimeException("Unexpected line: " + line); } char[] internalCharsArray = line.getInternalCharsArray(); int length = line.length(); String key = null; String infoName = null; String path = null; int i = 0; OUT: for (; i < length; i++) { char c = internalCharsArray[i]; switch (c) { case '|': key = ObjectsInternPool.internLocal(objectsPoolMap, buf.toString()); buf.clear(); i++; break OUT; default: buf.appendResizeOnExc(c); } } int hashSize = 0; OUT2: for (; i < length; i++) { char c = internalCharsArray[i]; switch (c) { case '|': hashSize = StringUtils.parsePositiveInt(buf); buf.clear(); i++; break OUT2; default: buf.appendResizeOnExc(c); } } HashSet<IInfo> set = new HashSet<IInfo>(hashSize); for (; i < length; i++) { char c = internalCharsArray[i]; switch (c) { case '!': infoName = ObjectsInternPool.internLocal(objectsPoolMap, buf.toString()); buf.clear(); break; case '&': path = dictionary.get(StringUtils.parsePositiveInt(buf)); buf.clear(); break; case '@': int dictKey = StringUtils.parsePositiveInt(buf); byte type = (byte) dictKey; type &= 0x07; // leave only the 3 least significant bits there (this is the type -- value // from 0 - 8). dictKey = (dictKey >> 3); // the entry in the dict doesn't have the least significant bits there. buf.clear(); String moduleDeclared = dictionary.get(dictKey); if (moduleDeclared == null) { throw new AssertionError("Unable to find key: " + dictKey); } if (infoName == null) { throw new AssertionError("Info name may not be null. Line: " + line); } switch (type) { case IInfo.CLASS_WITH_IMPORT_TYPE: set.add(new ClassInfo(infoName, moduleDeclared, path, false, nature)); break; case IInfo.METHOD_WITH_IMPORT_TYPE: set.add(new FuncInfo(infoName, moduleDeclared, path, false, nature)); break; case IInfo.ATTRIBUTE_WITH_IMPORT_TYPE: set.add(new AttrInfo(infoName, moduleDeclared, path, false, nature)); break; case IInfo.NAME_WITH_IMPORT_TYPE: set.add(new NameInfo(infoName, moduleDeclared, path, false, nature)); break; case IInfo.MOD_IMPORT_TYPE: set.add(new ModInfo(infoName, false, nature)); break; default: Log.log("Unexpected type: " + type); } break; default: buf.appendResizeOnExc(c); } } entries[iEntry] = new MapEntry(key, set); } tree.buildFromSorted( size, new Iterator() { private int iNext; @Override public boolean hasNext() { return iNext > size; } @Override public Object next() { Object o = entries[iNext]; iNext++; return o; } @Override public void remove() {} }, null, null); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return tree; }
/** * @param operation * @return * @throws IOException */ private FastStringBuffer read(IProgressMonitor monitor) throws IOException { synchronized (ioLock) { if (finishedForGood) { throw new RuntimeException( "Shells are already finished for good, so, it is an invalid state to try to read from it."); } if (inStart) { throw new RuntimeException( "The shell is still not completely started, so, it is an invalid state to try to read from it."); } if (!isConnected) { throw new RuntimeException( "The shell is still not connected, so, it is an invalid state to try to read from it."); } if (isInRead) { throw new RuntimeException( "The shell is already in read mode, so, it is an invalid state to try to read from it."); } if (isInWrite) { throw new RuntimeException( "The shell is already in write mode, so, it is an invalid state to try to read from it."); } isInRead = true; try { FastStringBuffer str = new FastStringBuffer(AbstractShell.BUFFER_SIZE); byte[] b = new byte[AbstractShell.BUFFER_SIZE]; while (true) { int len = this.socket.getInputStream().read(b); if (len == 0) { break; } String s = new String(b, 0, len); str.append(s); if (str.indexOf("END@@") != -1) { break; } else { sleepALittle(10); } } str.replaceFirst("@@COMPLETIONS", ""); // remove END@@ try { if (str.indexOf("END@@") != -1) { str.setCount(str.indexOf("END@@")); return str; } else { throw new RuntimeException("Couldn't find END@@ on received string."); } } catch (RuntimeException e) { if (str.length() > 500) { str.setCount(499) .append("...(continued)..."); // if the string gets too big, it can crash Eclipse... } Log.log(IStatus.ERROR, ("ERROR WITH STRING:" + str), e); return new FastStringBuffer(); } } finally { isInRead = false; } } }
/** * Handles having an operator * * @param std the coding standard to be used * @param cs the contents of the string * @param buf the buffer where the contents should be added * @param parsingUtils helper to get the contents * @param i current index * @param c current char * @return the new index after handling the operator */ private int handleOperator( FormatStd std, char[] cs, FastStringBuffer buf, ParsingUtils parsingUtils, int i, char c) { // let's discover if it's an unary operator (~ + -) boolean isUnaryWithContents = true; boolean isUnary = false; boolean changeWhitespacesBefore = true; if (c == '~' || c == '+' || c == '-') { // could be an unary operator... String trimmedLastWord = buf.getLastWord().trim(); isUnary = trimmedLastWord.length() == 0 || PySelection.ALL_KEYWORD_TOKENS.contains(trimmedLastWord); if (!isUnary) { for (char itChar : buf.reverseIterator()) { if (itChar == ' ' || itChar == '\t') { continue; } switch (itChar) { case '[': case '{': case '=': changeWhitespacesBefore = false; case '(': case ':': isUnaryWithContents = false; case '>': case '<': case '-': case '+': case '~': case '*': case '/': case '%': case '!': case '&': case '^': case '|': case ',': isUnary = true; } break; } } else { isUnaryWithContents = buf.length() > 0; } } if (!isUnary) { // We don't want to change whitespaces before in a binary operator that is in a new line. for (char ch : buf.reverseIterator()) { if (!Character.isWhitespace(ch)) { break; } if (ch == '\r' || ch == '\n') { changeWhitespacesBefore = false; break; } } } if (changeWhitespacesBefore) { while (buf.length() > 0 && (buf.lastChar() == ' ' || buf.lastChar() == ' ')) { buf.deleteLast(); } } boolean surroundWithSpaces = std.operatorsWithSpace; if (changeWhitespacesBefore) { // add spaces before if (isUnaryWithContents && surroundWithSpaces) { buf.append(' '); } } char localC = c; char prev = '\0'; boolean backOne = true; while (isOperatorPart(localC, prev)) { buf.append(localC); prev = localC; i++; if (i == cs.length) { break; } localC = cs[i]; if (localC == '=') { // when we get to an assign, we have found a full stmt (with assign) -- e.g.: a \\= a += a // == buf.append(localC); backOne = false; break; } } if (backOne) { i--; } // add space after only if it's not unary if (!isUnary && surroundWithSpaces) { buf.append(' '); } i = parsingUtils.eatWhitespaces(null, i + 1); return i; }
public void saveToFile(File workspaceMetadataFile) { if (workspaceMetadataFile.exists() && !workspaceMetadataFile.isDirectory()) { try { FileUtils.deleteFile(workspaceMetadataFile); } catch (IOException e) { throw new RuntimeException(e); } } if (!workspaceMetadataFile.exists()) { workspaceMetadataFile.mkdirs(); } File modulesKeysFile = new File(workspaceMetadataFile, "modulesKeys"); File pythonpatHelperFile = new File(workspaceMetadataFile, "pythonpath"); FastStringBuffer buf; HashMap<String, Integer> commonTokens = new HashMap<String, Integer>(); synchronized (modulesKeysLock) { buf = new FastStringBuffer(this.modulesKeys.size() * 50); buf.append(MODULES_MANAGER_V2); for (Iterator<ModulesKey> iter = this.modulesKeys.keySet().iterator(); iter.hasNext(); ) { ModulesKey next = iter.next(); buf.append(next.name); if (next.file != null) { buf.append("|"); if (next instanceof ModulesKeyForZip) { ModulesKeyForZip modulesKeyForZip = (ModulesKeyForZip) next; if (modulesKeyForZip.zipModulePath != null) { String fileStr = next.file.toString(); Integer t = commonTokens.get(fileStr); if (t == null) { t = commonTokens.size(); commonTokens.put(fileStr, t); } buf.append(t); buf.append("|"); buf.append(modulesKeyForZip.zipModulePath); buf.append("|"); buf.append(modulesKeyForZip.isFile ? '1' : '0'); } } else { buf.append(next.file.toString()); } } buf.append('\n'); } } if (commonTokens.size() > 0) { FastStringBuffer header = new FastStringBuffer(buf.length() + (commonTokens.size() * 50)); header.append(MODULES_MANAGER_V2); header.append("--COMMON--\n"); for (Map.Entry<String, Integer> entries : commonTokens.entrySet()) { header.append(entries.getValue()); header.append('='); header.append(entries.getKey()); header.append('\n'); } header.append("--END-COMMON--\n"); header.append(buf); buf = header; } FileUtils.writeStrToFile(buf.toString(), modulesKeysFile); this.pythonPathHelper.saveToFile(pythonpatHelperFile); }
public BackwardCharIterator(FastStringBuffer fastStringBuffer) { this.fastStringBuffer = fastStringBuffer; i = fastStringBuffer.length(); }
/** * Formats the contents for when a parenthesis is found (so, go until the closing parens and * format it accordingly) * * @param throwSyntaxError * @throws SyntaxErrorException */ private int formatForPar( final ParsingUtils parsingUtils, final char[] cs, final int i, final FormatStd std, final FastStringBuffer buf, final int parensLevel, final String delimiter, boolean throwSyntaxError) throws SyntaxErrorException { char c = ' '; FastStringBuffer locBuf = new FastStringBuffer(); int j = i + 1; int start = j; int end = start; while (j < cs.length && (c = cs[j]) != ')') { j++; if (c == '\'' || c == '"') { // ignore comments or multiline comments... j = parsingUtils.eatLiterals(null, j - 1, std.trimMultilineLiterals) + 1; end = j; } else if (c == '#') { j = parsingUtils.eatComments(null, j - 1) + 1; end = j; } else if (c == '(') { // open another par. if (end > start) { locBuf.append(cs, start, end - start); start = end; } j = formatForPar( parsingUtils, cs, j - 1, std, locBuf, parensLevel + 1, delimiter, throwSyntaxError) + 1; start = j; } else { end = j; } } if (end > start) { locBuf.append(cs, start, end - start); start = end; } if (c == ')') { // Now, when a closing parens is found, let's see the contents of the line where that parens // was found // and if it's only whitespaces, add all those whitespaces (to handle the following case: // a(a, // b // ) <-- we don't want to change this one. char c1; FastStringBuffer buf1 = new FastStringBuffer(); if (locBuf.indexOf('\n') != -1 || locBuf.indexOf('\r') != -1) { for (int k = locBuf.length(); k > 0 && (c1 = locBuf.charAt(k - 1)) != '\n' && c1 != '\r'; k--) { buf1.insert(0, c1); } } String formatStr = formatStr(trim(locBuf).toString(), std, parensLevel, delimiter, throwSyntaxError); FastStringBuffer formatStrBuf = trim(new FastStringBuffer(formatStr, 10)); String closing = ")"; if (buf1.length() > 0 && PySelection.containsOnlyWhitespaces(buf1.toString())) { formatStrBuf.append(buf1); } else if (std.parametersWithSpace) { closing = " )"; } if (std.parametersWithSpace) { if (formatStrBuf.length() == 0) { buf.append("()"); } else { buf.append("( "); buf.append(formatStrBuf); buf.append(closing); } } else { buf.append('('); buf.append(formatStrBuf); buf.append(closing); } return j; } else { if (throwSyntaxError) { throw new SyntaxErrorException("No closing ')' found."); } // we found no closing parens but we finished looking already, so, let's just add anything // without // more formatting... buf.append('('); buf.append(locBuf); return j; } }
/** * We just want to trim whitespaces, not newlines! * * @param locBuf the buffer to be trimmed * @return the same buffer passed as a parameter */ private FastStringBuffer rtrim(FastStringBuffer locBuf) { while (locBuf.length() > 0 && (locBuf.lastChar() == ' ' || locBuf.lastChar() == '\t')) { locBuf.deleteLast(); } return locBuf; }
/** * This method formats a string given some standard. * * @param str the string to be formatted * @param std the standard to be used * @param parensLevel the level of the parenthesis available. * @return a new (formatted) string * @throws SyntaxErrorException */ private String formatStr( String str, FormatStd std, int parensLevel, String delimiter, boolean throwSyntaxError) throws SyntaxErrorException { char[] cs = str.toCharArray(); FastStringBuffer buf = new FastStringBuffer(); // Temporary buffer for some operations. Must always be cleared before it's used. FastStringBuffer tempBuf = new FastStringBuffer(); ParsingUtils parsingUtils = ParsingUtils.create(cs, throwSyntaxError); char lastChar = '\0'; for (int i = 0; i < cs.length; i++) { char c = cs[i]; switch (c) { case '\'': case '"': // ignore literals and multi-line literals, including comments... i = parsingUtils.eatLiterals(buf, i, std.trimMultilineLiterals); break; case '#': i = handleComment(std, cs, buf, tempBuf, parsingUtils, i); break; case ',': i = formatForComma(std, cs, buf, i, tempBuf); break; case '(': i = formatForPar( parsingUtils, cs, i, std, buf, parensLevel + 1, delimiter, throwSyntaxError); break; // Things to treat: // +, -, *, /, % // ** // << >> // <, >, !=, <>, <=, >=, //=, *=, /=, // & ^ ~ | case '*': // for *, we also need to treat when it's used in varargs, kwargs and list expansion boolean isOperator = false; for (int j = buf.length() - 1; j >= 0; j--) { char localC = buf.charAt(j); if (Character.isWhitespace(localC)) { continue; } if (localC == '(' || localC == ',') { // it's not an operator, but vararg. kwarg or list expansion } if (Character.isJavaIdentifierPart(localC)) { // ok, there's a chance that it can be an operator, but we still have to check // the chance that it's a wild import tempBuf.clear(); while (Character.isJavaIdentifierPart(localC)) { tempBuf.append(localC); j--; if (j < 0) { break; // break while } localC = buf.charAt(j); } String reversed = tempBuf.reverse().toString(); if (!reversed.equals("import") && !reversed.equals("lambda")) { isOperator = true; } } if (localC == '\'' || localC == ')' || localC == ']') { isOperator = true; } // If it got here (i.e.: not whitespace), get out of the for loop. break; } if (!isOperator) { buf.append('*'); break; // break switch } // Otherwise, FALLTHROUGH case '+': case '-': if (c == '-' || c == '+') { // could also be * // handle exponentials correctly: e.g.: 1e-6 cannot have a space tempBuf.clear(); boolean started = false; for (int j = buf.length() - 1; ; j--) { if (j < 0) { break; } char localC = buf.charAt(j); if (localC == ' ' || localC == '\t') { if (!started) { continue; } else { break; } } started = true; if (Character.isJavaIdentifierPart(localC) || localC == '.') { tempBuf.append(localC); } else { break; // break for } } boolean isExponential = true; String partialNumber = tempBuf.reverse().toString(); int partialLen = partialNumber.length(); if (partialLen < 2 || !Character.isDigit(partialNumber.charAt(0))) { // at least 2 chars: the number and the 'e' isExponential = false; } else { // first char checked... now, if the last is an 'e', we must leave it together no // matter what if (partialNumber.charAt(partialLen - 1) != 'e' && partialNumber.charAt(partialLen - 1) != 'E') { isExponential = false; } } if (isExponential) { buf.rightTrim(); buf.append(c); // skip the next whitespaces from the buffer int initial = i; do { i++; } while (i < cs.length && (c = cs[i]) == ' ' || c == '\t'); if (i > initial) { i--; // backup 1 because we walked 1 too much. } break; // break switch } // Otherwise, FALLTHROUGH } case '/': case '%': case '<': case '>': case '!': case '&': case '^': case '~': case '|': i = handleOperator(std, cs, buf, parsingUtils, i, c); c = cs[i]; break; // check for = and == (other cases that have an = as the operator should already be // treated) case '=': if (i < cs.length - 1 && cs[i + 1] == '=') { // if == handle as if a regular operator i = handleOperator(std, cs, buf, parsingUtils, i, c); c = cs[i]; break; } while (buf.length() > 0 && buf.lastChar() == ' ') { buf.deleteLast(); } boolean surroundWithSpaces = std.operatorsWithSpace; if (parensLevel > 0) { surroundWithSpaces = std.assignWithSpaceInsideParens; } // add space before if (surroundWithSpaces) { buf.append(' '); } // add the operator and the '=' buf.append('='); // add space after if (surroundWithSpaces) { buf.append(' '); } i = parsingUtils.eatWhitespaces(null, i + 1); break; default: if (c == '\r' || c == '\n') { if (lastChar == ',' && std.spaceAfterComma && buf.lastChar() == ' ') { buf.deleteLast(); } if (std.trimLines) { buf.rightTrim(); } } buf.append(c); } lastChar = c; } if (parensLevel == 0 && std.trimLines) { buf.rightTrim(); } return buf.toString(); }