Fix parser in case OPTIONS_GHC pragma contains field/option that starts with --. Fix issue #382.

This commit is contained in:
Rik van der Kleij 2019-02-11 21:02:07 +01:00
parent 7a39d41717
commit 88ee8d19ca
11 changed files with 1528 additions and 1305 deletions

View File

@ -139,6 +139,8 @@ public class HaskellParser implements PsiParser, LightPsiParser {
r = newconstr_fielddecl(b, 0);
} else if (t == HS_NEWTYPE_DECLARATION) {
r = newtype_declaration(b, 0);
} else if (t == HS_OPTIONS_GHC_PRAGMA) {
r = options_ghc_pragma(b, 0);
} else if (t == HS_OTHER_PRAGMA) {
r = other_pragma(b, 0);
} else if (t == HS_OVERLAP_PRAGMA) {
@ -1497,7 +1499,7 @@ public class HaskellParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// COMMENT | NCOMMENT | HADDOCK | NHADDOCK | NOT_TERMINATED_COMMENT
// COMMENT | NCOMMENT | HADDOCK | NHADDOCK | NOT_TERMINATED_COMMENT | NOT_TERMINATED_OPTIONS_GHC
public static boolean comments(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "comments")) return false;
boolean r;
@ -1507,6 +1509,7 @@ public class HaskellParser implements PsiParser, LightPsiParser {
if (!r) r = consumeToken(b, HS_HADDOCK);
if (!r) r = consumeToken(b, HS_NHADDOCK);
if (!r) r = consumeToken(b, HS_NOT_TERMINATED_COMMENT);
if (!r) r = consumeToken(b, HS_NOT_TERMINATED_OPTIONS_GHC);
exit_section_(b, l, m, r, false, null);
return r;
}
@ -2940,7 +2943,7 @@ public class HaskellParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// (file_header_pragma onl)*
// ((file_header_pragma | options_ghc_pragma) onl)*
public static boolean file_header(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "file_header")) return false;
Marker m = enter_section_(b, l, _NONE_, HS_FILE_HEADER, "<file header>");
@ -2953,38 +2956,35 @@ public class HaskellParser implements PsiParser, LightPsiParser {
return true;
}
// file_header_pragma onl
// (file_header_pragma | options_ghc_pragma) onl
private static boolean file_header_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "file_header_0")) return false;
boolean r;
Marker m = enter_section_(b);
r = file_header_pragma(b, l + 1);
r = file_header_0_0(b, l + 1);
r = r && onl(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
// file_header_pragma | options_ghc_pragma
private static boolean file_header_0_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "file_header_0_0")) return false;
boolean r;
r = file_header_pragma(b, l + 1);
if (!r) r = options_ghc_pragma(b, l + 1);
return r;
}
/* ********************************************************** */
// pragma NEWLINE | pragma
// pragma
public static boolean file_header_pragma(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "file_header_pragma")) return false;
if (!nextTokenIs(b, HS_PRAGMA_START)) return false;
boolean r;
Marker m = enter_section_(b);
r = file_header_pragma_0(b, l + 1);
if (!r) r = pragma(b, l + 1);
exit_section_(b, m, HS_FILE_HEADER_PRAGMA, r);
return r;
}
// pragma NEWLINE
private static boolean file_header_pragma_0(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "file_header_pragma_0")) return false;
boolean r;
Marker m = enter_section_(b);
r = pragma(b, l + 1);
r = r && consumeToken(b, HS_NEWLINE);
exit_section_(b, m, null, r);
exit_section_(b, m, HS_FILE_HEADER_PRAGMA, r);
return r;
}
@ -4831,6 +4831,18 @@ public class HaskellParser implements PsiParser, LightPsiParser {
return r;
}
/* ********************************************************** */
// OPTIONS_GHC
public static boolean options_ghc_pragma(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "options_ghc_pragma")) return false;
if (!nextTokenIs(b, HS_OPTIONS_GHC)) return false;
boolean r;
Marker m = enter_section_(b);
r = consumeToken(b, HS_OPTIONS_GHC);
exit_section_(b, m, HS_OPTIONS_GHC_PRAGMA, r);
return r;
}
/* ********************************************************** */
// pragma
public static boolean other_pragma(PsiBuilder b, int l) {

View File

@ -1,13 +1,16 @@
// This is a generated file. Not intended for manual editing.
package intellij.haskell.psi;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.psi.PsiElement;
public interface HaskellFileHeader extends HaskellCompositeElement {
@NotNull
List<HaskellFileHeaderPragma> getFileHeaderPragmaList();
@NotNull
List<HaskellFileHeaderPragma> getFileHeaderPragmaList();
@NotNull
List<HaskellOptionsGhcPragma> getOptionsGhcPragmaList();
}

View File

@ -0,0 +1,6 @@
// This is a generated file. Not intended for manual editing.
package intellij.haskell.psi;
public interface HaskellOptionsGhcPragma extends HaskellCompositeElement {
}

View File

@ -66,6 +66,7 @@ public interface HaskellTypes {
IElementType HS_NEWCONSTR = new HaskellCompositeElementType("HS_NEWCONSTR");
IElementType HS_NEWCONSTR_FIELDDECL = new HaskellCompositeElementType("HS_NEWCONSTR_FIELDDECL");
IElementType HS_NEWTYPE_DECLARATION = new HaskellCompositeElementType("HS_NEWTYPE_DECLARATION");
IElementType HS_OPTIONS_GHC_PRAGMA = new HaskellCompositeElementType("HS_OPTIONS_GHC_PRAGMA");
IElementType HS_OTHER_PRAGMA = new HaskellCompositeElementType("HS_OTHER_PRAGMA");
IElementType HS_OVERLAP_PRAGMA = new HaskellCompositeElementType("HS_OVERLAP_PRAGMA");
IElementType HS_QUALIFIER = new HaskellCompositeElementType("HS_QUALIFIER");
@ -151,8 +152,10 @@ public interface HaskellTypes {
IElementType HS_NEWTYPE = new HaskellTokenType("NEWTYPE");
IElementType HS_NHADDOCK = new HaskellTokenType("NHADDOCK");
IElementType HS_NOT_TERMINATED_COMMENT = new HaskellTokenType("NOT_TERMINATED_COMMENT");
IElementType HS_NOT_TERMINATED_OPTIONS_GHC = new HaskellTokenType("NOT_TERMINATED_OPTIONS_GHC");
IElementType HS_OCTAL = new HaskellTokenType("OCTAL");
IElementType HS_OF = new HaskellTokenType("OF");
IElementType HS_OPTIONS_GHC = new HaskellTokenType("OPTIONS_GHC");
IElementType HS_PRAGMA_END = new HaskellTokenType("PRAGMA_END");
IElementType HS_PRAGMA_START = new HaskellTokenType("PRAGMA_START");
IElementType HS_QUASIQUOTE = new HaskellTokenType("QUASIQUOTE");
@ -293,6 +296,8 @@ public interface HaskellTypes {
return new HaskellNewconstrFielddeclImpl(node);
} else if (type == HS_NEWTYPE_DECLARATION) {
return new HaskellNewtypeDeclarationImpl(node);
} else if (type == HS_OPTIONS_GHC_PRAGMA) {
return new HaskellOptionsGhcPragmaImpl(node);
} else if (type == HS_OTHER_PRAGMA) {
return new HaskellOtherPragmaImpl(node);
} else if (type == HS_OVERLAP_PRAGMA) {

View File

@ -239,6 +239,10 @@ public class HaskellVisitor extends PsiElementVisitor {
visitDataConstructorDeclarationElement(o);
}
public void visitOptionsGhcPragma(@NotNull HaskellOptionsGhcPragma o) {
visitCompositeElement(o);
}
public void visitOtherPragma(@NotNull HaskellOtherPragma o) {
visitCompositeElement(o);
}

View File

@ -1,34 +1,42 @@
// This is a generated file. Not intended for manual editing.
package intellij.haskell.psi.impl;
import java.util.List;
import org.jetbrains.annotations.*;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static intellij.haskell.psi.HaskellTypes.*;
import intellij.haskell.psi.*;
import intellij.haskell.psi.HaskellFileHeader;
import intellij.haskell.psi.HaskellFileHeaderPragma;
import intellij.haskell.psi.HaskellOptionsGhcPragma;
import intellij.haskell.psi.HaskellVisitor;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class HaskellFileHeaderImpl extends HaskellCompositeElementImpl implements HaskellFileHeader {
public HaskellFileHeaderImpl(ASTNode node) {
super(node);
}
public HaskellFileHeaderImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull HaskellVisitor visitor) {
visitor.visitFileHeader(this);
}
public void accept(@NotNull HaskellVisitor visitor) {
visitor.visitFileHeader(this);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof HaskellVisitor) accept((HaskellVisitor)visitor);
else super.accept(visitor);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof HaskellVisitor) accept((HaskellVisitor) visitor);
else super.accept(visitor);
}
@Override
@NotNull
public List<HaskellFileHeaderPragma> getFileHeaderPragmaList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellFileHeaderPragma.class);
}
@Override
@NotNull
public List<HaskellFileHeaderPragma> getFileHeaderPragmaList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellFileHeaderPragma.class);
}
@Override
@NotNull
public List<HaskellOptionsGhcPragma> getOptionsGhcPragmaList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellOptionsGhcPragma.class);
}
}

View File

@ -0,0 +1,25 @@
// This is a generated file. Not intended for manual editing.
package intellij.haskell.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import intellij.haskell.psi.HaskellOptionsGhcPragma;
import intellij.haskell.psi.HaskellVisitor;
import org.jetbrains.annotations.NotNull;
public class HaskellOptionsGhcPragmaImpl extends HaskellCompositeElementImpl implements HaskellOptionsGhcPragma {
public HaskellOptionsGhcPragmaImpl(ASTNode node) {
super(node);
}
public void accept(@NotNull HaskellVisitor visitor) {
visitor.visitOptionsGhcPragma(this);
}
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof HaskellVisitor) accept((HaskellVisitor) visitor);
else super.accept(visitor);
}
}

View File

@ -22,6 +22,9 @@ import static intellij.haskell.psi.HaskellTypes.*;
private int commentStart;
private int commentDepth;
private int optionsGhcStart;
private int optionsGhcDepth;
private int haddockStart;
private int haddockDepth;
@ -29,7 +32,7 @@ import static intellij.haskell.psi.HaskellTypes.*;
private int qqDepth;
%}
%xstate NCOMMENT, NHADDOCK, QQ
%xstate NCOMMENT, NHADDOCK, QQ, OPTIONS_GHC
newline = \r|\n|\r\n
unispace = \x05
@ -199,6 +202,31 @@ nhaddock_start = {left_brace}{dash}{white_char}?{vertical_bar}
}
<OPTIONS_GHC> {
<<EOF>> {
int state = yystate();
yybegin(YYINITIAL);
zzStartRead = optionsGhcStart;
return HS_NOT_TERMINATED_OPTIONS_GHC;
}
{pragma_end} {
int state = yystate();
yybegin(YYINITIAL);
zzStartRead = optionsGhcStart;
return HS_OPTIONS_GHC;
}
.|{white_char}|{newline} {}
}
{pragma_start} {white_char}* "OPTIONS_GHC" {
yybegin(OPTIONS_GHC);
optionsGhcDepth = 0;
optionsGhcStart = getTokenStart();
}
<QQ> {
{left_bracket} ({var_id}|{con_id}|{dot})* {vertical_bar} {
qqDepth++;

File diff suppressed because it is too large Load Diff

View File

@ -55,13 +55,13 @@
program ::= onl shebang_line? onl file_header onl module_body
shebang_line ::= "#!" general_id+
file_header ::= (file_header_pragma onl)*
options_ghc_pragma ::= OPTIONS_GHC
file_header ::= ((file_header_pragma | options_ghc_pragma) onl)*
private pragma ::= PRAGMA_START (onl CON_ID? onl general_pragma_content? onl PRAGMA_END)+ {pin=1}
file_header_pragma ::= pragma NEWLINE | pragma
file_header_pragma ::= pragma
other_pragma ::= pragma
// TODO Add all GHC options
general_pragma_content ::= (CON_ID | VAR_ID | CONSYM_ID | VARSYM_ID |
LEFT_PAREN | RIGHT_PAREN | FLOAT | UNDERSCORE |
SEMICOLON | LEFT_BRACKET | RIGHT_BRACKET | literal | LEFT_BRACE | RIGHT_BRACE |
@ -153,7 +153,7 @@ private onls ::= (&<<containsSpaces>> NEWLINE | DIRECTIVE NEWLINE
private nls ::= (&<<containsSpaces>> NEWLINE)+ // multiple new lines and spaces
private oonls ::= (&<<containsSpaces>> NEWLINE)? // optional one (new line and spaces)
comments ::= COMMENT | NCOMMENT | HADDOCK | NHADDOCK | NOT_TERMINATED_COMMENT // rule is necessary to refer to various comment types in code
comments ::= COMMENT | NCOMMENT | HADDOCK | NHADDOCK | NOT_TERMINATED_COMMENT | NOT_TERMINATED_OPTIONS_GHC // rule is necessary to refer to various comment types in code
modid ::= (conid DOT)* conid {pin=1 stubClass = "intellij.haskell.psi.stubs.HaskellModidStub"}

View File

@ -16,10 +16,12 @@ class HaskellHighlightingAnnotator extends Annotator {
.setTextAttributes(HaskellSyntaxHighlighter.Keyword)
case psi: HaskellFileHeaderPragma => psi.getGeneralPragmaContentList.forEach((t: HaskellGeneralPragmaContent) =>
holder.createInfoAnnotation(t, null).setTextAttributes(HaskellSyntaxHighlighter.PragmaContent))
case psi: HaskellOptionsGhcPragma =>
holder.createInfoAnnotation(psi, null).setTextAttributes(HaskellSyntaxHighlighter.PragmaContent)
case psi: HaskellTypeSignature => holder.createInfoAnnotation(psi.getFirstChild, null)
.setTextAttributes(HaskellSyntaxHighlighter.FunctionName)
.setTextAttributes(HaskellSyntaxHighlighter.FunctionName)
case psi: HaskellStringLiteralElementImpl => holder.createInfoAnnotation(psi, null)
.setTextAttributes(HaskellSyntaxHighlighter.String)
.setTextAttributes(HaskellSyntaxHighlighter.String)
case _ =>
}
}