1.1 --- a/python.editor/src/org/netbeans/modules/python/editor/PythonParser.java Wed Aug 12 23:27:34 2015 -0500
1.2 +++ b/python.editor/src/org/netbeans/modules/python/editor/PythonParser.java Fri Aug 14 20:21:17 2015 +0200
1.3 @@ -327,6 +327,12 @@
1.4 tokens.discardOffChannelTokens(true);
1.5 PythonTokenSource indentedSource = new PythonTokenSource(tokens, fileName);
1.6 CommonTokenStream indentedTokens = new CommonTokenStream(indentedSource);
1.7 + // Import line ending with a dot raise a NullPointerException in
1.8 + // org.python.antlr.GrammarActions.makeDottedText called from parser.file_input
1.9 + // sanitizeImportTokens will remove the dot token from the list of tokens in
1.10 + // indentedTokens to avoid the bug and add an error at this file.
1.11 + // See https://netbeans.org/bugzilla/show_bug.cgi?id=252356
1.12 + sanitizeImportTokens(indentedTokens, errors, file);
1.13 org.python.antlr.PythonParser parser;
1.14 if (charset != null) {
1.15 parser = new org.python.antlr.PythonParser(indentedTokens, charset);
1.16 @@ -391,6 +397,51 @@
1.17 }
1.18 }
1.19
1.20 + private void sanitizeImportTokens(CommonTokenStream indentedTokens, List errors, FileObject file) {
1.21 + List tokens = indentedTokens.getTokens();
1.22 + List<CommonToken> tokensToRemove = new ArrayList<>();
1.23 + int i = 0;
1.24 + while (i < tokens.size()) {
1.25 + CommonToken importToken = (CommonToken)tokens.get(i);
1.26 + if ("import".equals(importToken.getText()) || "from".equals(importToken.getText())) {
1.27 + // sanitizeDotTokens return the index of the token that starts the next line
1.28 + i = sanitizeDotTokens(tokens, tokensToRemove, importToken, i + 1, errors, file);
1.29 + } else {
1.30 + i++;
1.31 + }
1.32 + }
1.33 +
1.34 + for (CommonToken token : tokensToRemove) {
1.35 + tokens.remove(token);
1.36 + }
1.37 + }
1.38 +
1.39 + private int sanitizeDotTokens(List tokens, List tokensToRemove, CommonToken importToken,
1.40 + int startIndex, List errors, FileObject file) {
1.41 + for (int j = startIndex; j < tokens.size() - 1; j++) {
1.42 + CommonToken dotToken = (CommonToken)tokens.get(j);
1.43 + CommonToken nextToken = (CommonToken)tokens.get(j + 1);
1.44 + if (".".equals(dotToken.getText())) {
1.45 + if (nextToken.getText().startsWith("\n")) {
1.46 + tokensToRemove.add(dotToken);
1.47 + String rawTokenText;
1.48 + if (nextToken.getText().startsWith("\n")) {
1.49 + rawTokenText = "\\n";
1.50 + } else {
1.51 + rawTokenText = " ";
1.52 + }
1.53 + errors.add(
1.54 + new DefaultError(null, "Mismatch input '.' expecting NAME\nMissing NAME at '" + rawTokenText + "'",
1.55 + null, file, importToken.getStartIndex(), dotToken.getStopIndex(), Severity.ERROR));
1.56 + }
1.57 + } else if ("\n".equals(nextToken.getText())) { // End of line, must continue looping from external loop
1.58 + return j + 1;
1.59 + }
1.60 + }
1.61 +
1.62 + return startIndex;
1.63 + }
1.64 +
1.65 private static String asString(CharSequence sequence) {
1.66 if (sequence instanceof String) {
1.67 return (String)sequence;