QuasiQuote injection, not sure if implemented correctly

This commit is contained in:
ice1000 2019-11-03 10:53:31 -05:00
parent dd951e98d0
commit c48dfeea40
17 changed files with 179 additions and 16 deletions

View File

@ -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) {

View File

@ -29,6 +29,9 @@ public interface HaskellCidecl extends HaskellCompositeElement {
@NotNull
List<HaskellQName> getQNameList();
@NotNull
List<HaskellQuasiQuote> getQuasiQuoteList();
@NotNull
List<HaskellReservedId> getReservedIdList();

View File

@ -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<HaskellQName> getQNameList();
@NotNull
List<HaskellQuasiQuote> getQuasiQuoteList();
@NotNull
List<HaskellReservedId> getReservedIdList();

View File

@ -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 {
}

View File

@ -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<HaskellQName> getQNameList();
@NotNull
List<HaskellQuasiQuote> getQuasiQuoteList();
@NotNull
List<HaskellReservedId> getReservedIdList();

View File

@ -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) {

View File

@ -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);
}

View File

@ -67,6 +67,12 @@ public class HaskellCideclImpl extends HaskellCompositeElementImpl implements Ha
return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQName.class);
}
@Override
@NotNull
public List<HaskellQuasiQuote> getQuasiQuoteList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQuasiQuote.class);
}
@Override
@NotNull
public List<HaskellReservedId> getReservedIdList() {

View File

@ -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<HaskellQuasiQuote> getQuasiQuoteList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQuasiQuote.class);
}
@Override
@NotNull
public List<HaskellReservedId> getReservedIdList() {

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.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);
}
}

View File

@ -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<HaskellQuasiQuote> getQuasiQuoteList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, HaskellQuasiQuote.class);
}
@Override
@NotNull
public List<HaskellReservedId> getReservedIdList() {

View File

@ -307,6 +307,8 @@
implementationClass="intellij.haskell.alex.lang.psi.impl.AlexElementManipulator"/>
<lang.elementManipulator forClass="intellij.haskell.psi.impl.HaskellStringLiteralElementImpl"
implementationClass="intellij.haskell.psi.impl.HaskellStringLiteralManipulator"/>
<lang.elementManipulator forClass="intellij.haskell.psi.impl.HaskellQuasiQuoteElementImpl"
implementationClass="intellij.haskell.psi.impl.HaskellQuasiQuoteManipulator"/>
<lang.namesValidator language="Haskell" implementationClass="intellij.haskell.refactor.HaskellNamesValidator"/>
<languageInjector implementation="intellij.haskell.alex.lang.psi.AlexHaskellInjector"/>

View File

@ -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

View File

@ -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 {
}

View File

@ -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)
}
}

View File

@ -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('|'))
}
}

View File

@ -26,7 +26,7 @@ public class HaskellStringEscaper extends LiteralTextEscaper<HaskellStringLitera
public int getOffsetInHost(int offsetInDecoded, @NotNull final TextRange rangeInsideHost) {
int result = offsetInDecoded < outSourceOffsets.length ? outSourceOffsets[offsetInDecoded] : -1;
if (result == -1) return -1;
return (result <= rangeInsideHost.getLength() ? result : rangeInsideHost.getLength()) + rangeInsideHost.getStartOffset();
return Math.min(result, rangeInsideHost.getLength()) + rangeInsideHost.getStartOffset();
}
@Override