/** Check if we are still in the number */ 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 == '.'; } }
/** * 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) + 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; } }
/** * 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(); 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 comments or multiline comments... i = parsingUtils.eatLiterals(buf, i); break; case '#': i = parsingUtils.eatComments(buf, i); break; case ',': i = formatForComma(std, cs, buf, i); 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 FastStringBuffer localBufToCheckWildImport = new FastStringBuffer(); while (Character.isJavaIdentifierPart(localC)) { localBufToCheckWildImport.append(localC); j--; if (j < 0) { break; // break while } localC = buf.charAt(j); } if (!localBufToCheckWildImport.reverse().toString().equals("import")) { isOperator = true; } } if (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 FastStringBuffer localBufToCheckNumber = new FastStringBuffer(); 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 == '.') { localBufToCheckNumber.append(localC); } else { break; // break for } } boolean isExponential = true; String partialNumber = localBufToCheckNumber.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(); } rightTrimIfNeeded(std, buf); } buf.append(c); } lastChar = c; } if (parensLevel == 0) { rightTrimIfNeeded(std, buf); if (std.addNewLineAtEndOfFile) { char tempC; if (buf.length() == 0 || ((tempC = buf.lastChar()) != '\r' && tempC != '\n')) { buf.append(delimiter); } } } return buf.toString(); }