From c48dfeea401ce91b9426e4c23b31a967a3f9ead5 Mon Sep 17 00:00:00 2001 From: ice1000 Date: Sun, 3 Nov 2019 10:53:31 -0500 Subject: [PATCH] QuasiQuote injection, not sure if implemented correctly --- .../haskell/parser/HaskellParser.java | 16 +++++++-- gen/intellij/haskell/psi/HaskellCidecl.java | 3 ++ .../haskell/psi/HaskellExpression.java | 7 ++-- .../haskell/psi/HaskellQuasiQuote.java | 8 +++++ .../haskell/psi/HaskellShebangLine.java | 7 ++-- gen/intellij/haskell/psi/HaskellTypes.java | 3 ++ gen/intellij/haskell/psi/HaskellVisitor.java | 9 +++++ .../haskell/psi/impl/HaskellCideclImpl.java | 6 ++++ .../psi/impl/HaskellExpressionImpl.java | 13 +++++--- .../psi/impl/HaskellQuasiQuoteImpl.java | 25 ++++++++++++++ .../psi/impl/HaskellShebangLineImpl.java | 13 +++++--- intellij-haskell/META-INF/plugin.xml | 2 ++ src/main/scala/intellij/haskell/haskell.bnf | 6 +++- .../psi/HaskellQuasiQuoteElement.scala | 20 +++++++++++ .../impl/HaskellQuasiQuoteElementImpl.scala | 22 +++++++++++++ .../impl/HaskellQuasiQuoteManipulator.scala | 33 +++++++++++++++++++ .../psi/impl/HaskellStringEscaper.java | 2 +- 17 files changed, 179 insertions(+), 16 deletions(-) create mode 100644 gen/intellij/haskell/psi/HaskellQuasiQuote.java create mode 100644 gen/intellij/haskell/psi/impl/HaskellQuasiQuoteImpl.java create mode 100644 src/main/scala/intellij/haskell/psi/HaskellQuasiQuoteElement.scala create mode 100644 src/main/scala/intellij/haskell/psi/impl/HaskellQuasiQuoteElementImpl.scala create mode 100644 src/main/scala/intellij/haskell/psi/impl/HaskellQuasiQuoteManipulator.scala diff --git a/gen/intellij/haskell/parser/HaskellParser.java b/gen/intellij/haskell/parser/HaskellParser.java index 81771f90..43a3d82f 100644 --- a/gen/intellij/haskell/parser/HaskellParser.java +++ b/gen/intellij/haskell/parser/HaskellParser.java @@ -2706,14 +2706,14 @@ public class HaskellParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // QUASIQUOTE | q_name | symbol_reserved_op | reserved_id | LEFT_PAREN | RIGHT_PAREN | FLOAT | + // quasi_quote | q_name | symbol_reserved_op | reserved_id | LEFT_PAREN | RIGHT_PAREN | FLOAT | // SEMICOLON | LEFT_BRACKET | RIGHT_BRACKET | literal | LEFT_BRACE | RIGHT_BRACE | // COMMA | QUOTE | BACKQUOTE | fixity | // pragma | DIRECTIVE | DOUBLE_QUOTES static boolean general_id(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "general_id")) return false; boolean r; - r = consumeToken(b, HS_QUASIQUOTE); + r = quasi_quote(b, l + 1); if (!r) r = q_name(b, l + 1); if (!r) r = symbol_reserved_op(b, l + 1); if (!r) r = reserved_id(b, l + 1); @@ -4819,6 +4819,18 @@ public class HaskellParser implements PsiParser, LightPsiParser { return r; } + /* ********************************************************** */ + // QUASIQUOTE + public static boolean quasi_quote(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "quasi_quote")) return false; + if (!nextTokenIs(b, HS_QUASIQUOTE)) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, HS_QUASIQUOTE); + exit_section_(b, m, HS_QUASI_QUOTE, r); + return r; + } + /* ********************************************************** */ // CASE | CLASS | DATA | DEFAULT | DERIVING | DO | ELSE | IF | IMPORT | IN | INSTANCE | LET | MODULE | NEWTYPE | OF | THEN | TYPE | WHERE | UNDERSCORE public static boolean reserved_id(PsiBuilder b, int l) { diff --git a/gen/intellij/haskell/psi/HaskellCidecl.java b/gen/intellij/haskell/psi/HaskellCidecl.java index 8c930c30..8d929a0c 100644 --- a/gen/intellij/haskell/psi/HaskellCidecl.java +++ b/gen/intellij/haskell/psi/HaskellCidecl.java @@ -29,6 +29,9 @@ public interface HaskellCidecl extends HaskellCompositeElement { @NotNull List getQNameList(); + @NotNull + List getQuasiQuoteList(); + @NotNull List getReservedIdList(); diff --git a/gen/intellij/haskell/psi/HaskellExpression.java b/gen/intellij/haskell/psi/HaskellExpression.java index c6789ff5..6cc6c57c 100644 --- a/gen/intellij/haskell/psi/HaskellExpression.java +++ b/gen/intellij/haskell/psi/HaskellExpression.java @@ -1,9 +1,9 @@ // 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 HaskellExpression extends HaskellExpressionElement { @@ -16,6 +16,9 @@ public interface HaskellExpression extends HaskellExpressionElement { @NotNull List getQNameList(); + @NotNull + List getQuasiQuoteList(); + @NotNull List getReservedIdList(); diff --git a/gen/intellij/haskell/psi/HaskellQuasiQuote.java b/gen/intellij/haskell/psi/HaskellQuasiQuote.java new file mode 100644 index 00000000..7da869f8 --- /dev/null +++ b/gen/intellij/haskell/psi/HaskellQuasiQuote.java @@ -0,0 +1,8 @@ +// This is a generated file. Not intended for manual editing. +package intellij.haskell.psi; + +import com.intellij.psi.PsiLanguageInjectionHost; + +public interface HaskellQuasiQuote extends HaskellQuasiQuoteElement, PsiLanguageInjectionHost { + +} diff --git a/gen/intellij/haskell/psi/HaskellShebangLine.java b/gen/intellij/haskell/psi/HaskellShebangLine.java index eaf1f5e1..b5e61019 100644 --- a/gen/intellij/haskell/psi/HaskellShebangLine.java +++ b/gen/intellij/haskell/psi/HaskellShebangLine.java @@ -1,9 +1,9 @@ // 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 HaskellShebangLine extends HaskellCompositeElement { @@ -16,6 +16,9 @@ public interface HaskellShebangLine extends HaskellCompositeElement { @NotNull List getQNameList(); + @NotNull + List getQuasiQuoteList(); + @NotNull List getReservedIdList(); diff --git a/gen/intellij/haskell/psi/HaskellTypes.java b/gen/intellij/haskell/psi/HaskellTypes.java index 139ded95..5c7d52cc 100644 --- a/gen/intellij/haskell/psi/HaskellTypes.java +++ b/gen/intellij/haskell/psi/HaskellTypes.java @@ -61,6 +61,7 @@ public interface HaskellTypes { IElementType HS_NEWTYPE_DECLARATION = new HaskellCompositeElementType("HS_NEWTYPE_DECLARATION"); IElementType HS_PRAGMA = new HaskellCompositeElementType("HS_PRAGMA"); IElementType HS_QUALIFIER = new HaskellCompositeElementType("HS_QUALIFIER"); + IElementType HS_QUASI_QUOTE = new HaskellCompositeElementType("HS_QUASI_QUOTE"); IElementType HS_Q_CON = new HaskellCompositeElementType("HS_Q_CON"); IElementType HS_Q_CON_QUALIFIER = new HaskellCompositeElementType("HS_Q_CON_QUALIFIER"); IElementType HS_Q_CON_QUALIFIER_1 = new HaskellCompositeElementType("HS_Q_CON_QUALIFIER_1"); @@ -273,6 +274,8 @@ public interface HaskellTypes { return new HaskellPragmaImpl(node); } else if (type == HS_QUALIFIER) { return new HaskellQualifierImpl(node); + } else if (type == HS_QUASI_QUOTE) { + return new HaskellQuasiQuoteImpl(node); } else if (type == HS_Q_CON) { return new HaskellQConImpl(node); } else if (type == HS_Q_CON_QUALIFIER) { diff --git a/gen/intellij/haskell/psi/HaskellVisitor.java b/gen/intellij/haskell/psi/HaskellVisitor.java index 9c5bd07d..a353cf88 100644 --- a/gen/intellij/haskell/psi/HaskellVisitor.java +++ b/gen/intellij/haskell/psi/HaskellVisitor.java @@ -260,6 +260,11 @@ public class HaskellVisitor extends PsiElementVisitor { // visitNamedElement(o); } + public void visitQuasiQuote(@NotNull HaskellQuasiQuote o) { + visitQuasiQuoteElement(o); + // visitPsiLanguageInjectionHost(o); + } + public void visitReservedId(@NotNull HaskellReservedId o) { visitCompositeElement(o); } @@ -365,6 +370,10 @@ public class HaskellVisitor extends PsiElementVisitor { visitCompositeElement(o); } + public void visitQuasiQuoteElement(@NotNull HaskellQuasiQuoteElement o) { + visitCompositeElement(o); + } + public void visitStringLiteralElement(@NotNull HaskellStringLiteralElement o) { visitCompositeElement(o); } diff --git a/gen/intellij/haskell/psi/impl/HaskellCideclImpl.java b/gen/intellij/haskell/psi/impl/HaskellCideclImpl.java index c75de235..3ab9f1ba 100644 --- a/gen/intellij/haskell/psi/impl/HaskellCideclImpl.java +++ b/gen/intellij/haskell/psi/impl/HaskellCideclImpl.java @@ -67,6 +67,12 @@ public class HaskellCideclImpl extends HaskellCompositeElementImpl implements Ha return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQName.class); } + @Override + @NotNull + public List getQuasiQuoteList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQuasiQuote.class); + } + @Override @NotNull public List getReservedIdList() { diff --git a/gen/intellij/haskell/psi/impl/HaskellExpressionImpl.java b/gen/intellij/haskell/psi/impl/HaskellExpressionImpl.java index 49734575..f5467783 100644 --- a/gen/intellij/haskell/psi/impl/HaskellExpressionImpl.java +++ b/gen/intellij/haskell/psi/impl/HaskellExpressionImpl.java @@ -1,14 +1,13 @@ // 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 org.jetbrains.annotations.NotNull; + +import java.util.List; public class HaskellExpressionImpl extends HaskellExpressionElementImpl implements HaskellExpression { @@ -43,6 +42,12 @@ public class HaskellExpressionImpl extends HaskellExpressionElementImpl implemen return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQName.class); } + @Override + @NotNull + public List getQuasiQuoteList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQuasiQuote.class); + } + @Override @NotNull public List getReservedIdList() { diff --git a/gen/intellij/haskell/psi/impl/HaskellQuasiQuoteImpl.java b/gen/intellij/haskell/psi/impl/HaskellQuasiQuoteImpl.java new file mode 100644 index 00000000..824226ea --- /dev/null +++ b/gen/intellij/haskell/psi/impl/HaskellQuasiQuoteImpl.java @@ -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.HaskellQuasiQuote; +import intellij.haskell.psi.HaskellVisitor; +import org.jetbrains.annotations.NotNull; + +public class HaskellQuasiQuoteImpl extends HaskellQuasiQuoteElementImpl implements HaskellQuasiQuote { + + public HaskellQuasiQuoteImpl(ASTNode node) { + super(node); + } + + public void accept(@NotNull HaskellVisitor visitor) { + visitor.visitQuasiQuote(this); + } + + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof HaskellVisitor) accept((HaskellVisitor) visitor); + else super.accept(visitor); + } + +} diff --git a/gen/intellij/haskell/psi/impl/HaskellShebangLineImpl.java b/gen/intellij/haskell/psi/impl/HaskellShebangLineImpl.java index 77efcd69..385c7dc3 100644 --- a/gen/intellij/haskell/psi/impl/HaskellShebangLineImpl.java +++ b/gen/intellij/haskell/psi/impl/HaskellShebangLineImpl.java @@ -1,14 +1,13 @@ // 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 org.jetbrains.annotations.NotNull; + +import java.util.List; public class HaskellShebangLineImpl extends HaskellCompositeElementImpl implements HaskellShebangLine { @@ -43,6 +42,12 @@ public class HaskellShebangLineImpl extends HaskellCompositeElementImpl implemen return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQName.class); } + @Override + @NotNull + public List getQuasiQuoteList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQuasiQuote.class); + } + @Override @NotNull public List getReservedIdList() { diff --git a/intellij-haskell/META-INF/plugin.xml b/intellij-haskell/META-INF/plugin.xml index c9201cc5..55cc3c85 100644 --- a/intellij-haskell/META-INF/plugin.xml +++ b/intellij-haskell/META-INF/plugin.xml @@ -307,6 +307,8 @@ implementationClass="intellij.haskell.alex.lang.psi.impl.AlexElementManipulator"/> + diff --git a/src/main/scala/intellij/haskell/haskell.bnf b/src/main/scala/intellij/haskell/haskell.bnf index 6c9c525f..41461d80 100644 --- a/src/main/scala/intellij/haskell/haskell.bnf +++ b/src/main/scala/intellij/haskell/haskell.bnf @@ -47,6 +47,9 @@ implements("text_literal")=["intellij.haskell.psi.HaskellStringLiteralElement" "com.intellij.psi.PsiLanguageInjectionHost"] mixin("text_literal")="intellij.haskell.psi.impl.HaskellStringLiteralElementImpl" + + implements("quasi_quote")=["intellij.haskell.psi.HaskellQuasiQuoteElement" "com.intellij.psi.PsiLanguageInjectionHost"] + mixin("quasi_quote")="intellij.haskell.psi.impl.HaskellQuasiQuoteElementImpl" } program ::= onl shebang_line? onl file_header onl module_body @@ -124,6 +127,7 @@ type_family_declaration ::= TYPE_FAMILY onls type_family_type (onls (WHERE | deriving_declaration ::= DERIVING INSTANCE (scontext onls DOUBLE_RIGHT_ARROW)? onls q_name onls inst text_literal ::= STRING_LITERAL +quasi_quote ::= QUASIQUOTE private literal ::= DECIMAL | HEXADECIMAL | OCTAL | FLOAT | CHARACTER_LITERAL | text_literal @@ -237,7 +241,7 @@ cidecl ::= pragma | instance_declaration | default_declarat expression ::= line_expression (nls line_expression)* private line_expression ::= general_id+ -private general_id ::= QUASIQUOTE | q_name | symbol_reserved_op | reserved_id | LEFT_PAREN | RIGHT_PAREN | FLOAT | +private general_id ::= quasi_quote | q_name | symbol_reserved_op | reserved_id | LEFT_PAREN | RIGHT_PAREN | FLOAT | SEMICOLON | LEFT_BRACKET | RIGHT_BRACKET | literal | LEFT_BRACE | RIGHT_BRACE | COMMA | QUOTE | BACKQUOTE | fixity | pragma | DIRECTIVE | DOUBLE_QUOTES diff --git a/src/main/scala/intellij/haskell/psi/HaskellQuasiQuoteElement.scala b/src/main/scala/intellij/haskell/psi/HaskellQuasiQuoteElement.scala new file mode 100644 index 00000000..9215e343 --- /dev/null +++ b/src/main/scala/intellij/haskell/psi/HaskellQuasiQuoteElement.scala @@ -0,0 +1,20 @@ +/* + * Copyright 2014-2019 Rik van der Kleij + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package intellij.haskell.psi + +trait HaskellQuasiQuoteElement extends HaskellCompositeElement { +} diff --git a/src/main/scala/intellij/haskell/psi/impl/HaskellQuasiQuoteElementImpl.scala b/src/main/scala/intellij/haskell/psi/impl/HaskellQuasiQuoteElementImpl.scala new file mode 100644 index 00000000..afc47d90 --- /dev/null +++ b/src/main/scala/intellij/haskell/psi/impl/HaskellQuasiQuoteElementImpl.scala @@ -0,0 +1,22 @@ +package intellij.haskell.psi.impl + +import com.intellij.lang.ASTNode +import com.intellij.psi.{ElementManipulators, LiteralTextEscaper, PsiLanguageInjectionHost} +import intellij.haskell.psi.HaskellQuasiQuoteElement + +abstract class HaskellQuasiQuoteElementImpl private[impl](node: ASTNode) + extends HaskellCompositeElementImpl(node) + with HaskellQuasiQuoteElement + with PsiLanguageInjectionHost { + override def isValidHost: Boolean = { + true + } + + override def updateText(text: String): HaskellQuasiQuoteElementImpl = { + ElementManipulators.handleContentChange(this, text) + } + + override def createLiteralTextEscaper(): LiteralTextEscaper[HaskellQuasiQuoteElementImpl] = { + LiteralTextEscaper.createSimple(this) + } +} diff --git a/src/main/scala/intellij/haskell/psi/impl/HaskellQuasiQuoteManipulator.scala b/src/main/scala/intellij/haskell/psi/impl/HaskellQuasiQuoteManipulator.scala new file mode 100644 index 00000000..29e9833e --- /dev/null +++ b/src/main/scala/intellij/haskell/psi/impl/HaskellQuasiQuoteManipulator.scala @@ -0,0 +1,33 @@ +package intellij.haskell.psi.impl + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.{AbstractElementManipulator, PsiFileFactory} +import com.intellij.util.IncorrectOperationException +import intellij.haskell.HaskellLanguage +import org.jetbrains.annotations.Nullable + +/** + * @author ice1000 + */ +class HaskellQuasiQuoteManipulator extends AbstractElementManipulator[HaskellQuasiQuoteElementImpl] { + @Nullable + @throws[IncorrectOperationException] + override def handleContentChange(psi: HaskellQuasiQuoteElementImpl, + range: TextRange, + newContent: String): HaskellQuasiQuoteElementImpl = { + val oldText = psi.getText + val newText = oldText.substring(0, range.getStartOffset) + newContent + oldText.substring(range.getEndOffset) + val newElement = PsiFileFactory + .getInstance(psi.getProject) + .createFileFromText("a.hs", HaskellLanguage.Instance, newText, false, false) + .getLastChild + .getLastChild + psi.replace(newElement).asInstanceOf[HaskellQuasiQuoteElementImpl] + } + + override def getRangeInElement(element: HaskellQuasiQuoteElementImpl): TextRange = { + val text = element.getText + new TextRange(text.indexOf('|') + 1, text.lastIndexOf('|')) + } +} + diff --git a/src/main/scala/intellij/haskell/psi/impl/HaskellStringEscaper.java b/src/main/scala/intellij/haskell/psi/impl/HaskellStringEscaper.java index 5672a054..6b2bcebe 100644 --- a/src/main/scala/intellij/haskell/psi/impl/HaskellStringEscaper.java +++ b/src/main/scala/intellij/haskell/psi/impl/HaskellStringEscaper.java @@ -26,7 +26,7 @@ public class HaskellStringEscaper extends LiteralTextEscaper