mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 05:10:55 +00:00
idea: brace matching and function resolution
This commit is contained in:
@ -0,0 +1,35 @@
|
||||
package gay.pizza.pork.idea
|
||||
|
||||
import com.intellij.lang.BracePair
|
||||
import com.intellij.lang.PairedBraceMatcher
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import gay.pizza.pork.parser.TokenType
|
||||
|
||||
class PorkBraceMatcher : PairedBraceMatcher {
|
||||
override fun getPairs(): Array<BracePair> = arrayOf(
|
||||
BracePair(
|
||||
PorkElementTypes.elementTypeFor(TokenType.LeftCurly),
|
||||
PorkElementTypes.elementTypeFor(TokenType.RightCurly),
|
||||
true
|
||||
),
|
||||
BracePair(
|
||||
PorkElementTypes.elementTypeFor(TokenType.LeftParentheses),
|
||||
PorkElementTypes.elementTypeFor(TokenType.RightParentheses),
|
||||
false
|
||||
),
|
||||
BracePair(
|
||||
PorkElementTypes.elementTypeFor(TokenType.LeftBracket),
|
||||
PorkElementTypes.elementTypeFor(TokenType.RightBracket),
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
override fun isPairedBracesAllowedBeforeType(lbraceType: IElementType, contextType: IElementType?): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getCodeConstructStart(file: PsiFile?, openingBraceOffset: Int): Int {
|
||||
return openingBraceOffset
|
||||
}
|
||||
}
|
@ -2,4 +2,5 @@ package gay.pizza.pork.idea
|
||||
|
||||
import com.intellij.lang.Language
|
||||
|
||||
@Suppress("JavaIoSerializableObjectMustHaveReadResolve")
|
||||
object PorkLanguage : Language("Pork")
|
||||
|
@ -61,10 +61,12 @@ class PorkLexer : LexerBase() {
|
||||
internalTokenEnd = currentToken.sourceIndex.index + currentToken.text.length
|
||||
} catch (e: ProcessCanceledException) {
|
||||
throw e
|
||||
} catch (e: Throwable) {
|
||||
} catch (e: BadCharacterError) {
|
||||
currentTokenType = PsiTokenType.BAD_CHARACTER
|
||||
internalTokenEnd = bufferEnd
|
||||
} catch (e: UnterminatedTokenError) {
|
||||
currentTokenType = PsiTokenType.BAD_CHARACTER
|
||||
internalTokenEnd = bufferEnd
|
||||
log.warn(Tokenizer::class.java.name, e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,17 +3,20 @@ package gay.pizza.pork.idea
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.lang.PsiBuilder
|
||||
import com.intellij.lang.PsiParser
|
||||
import com.intellij.psi.impl.PsiElementBase
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import gay.pizza.pork.parser.Parser
|
||||
|
||||
class PorkParser : PsiParser {
|
||||
override fun parse(root: IElementType, builder: PsiBuilder): ASTNode {
|
||||
val marker = builder.mark()
|
||||
val psiBuilderMarkAttribution = PsiBuilderMarkAttribution(builder)
|
||||
val source = PsiBuilderTokenSource(builder)
|
||||
val parser = Parser(source, psiBuilderMarkAttribution)
|
||||
try {
|
||||
parser.parseCompilationUnit()
|
||||
} catch (_: ExitParser) {}
|
||||
marker.done(root)
|
||||
return builder.treeBuilt
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,34 @@
|
||||
package gay.pizza.pork.idea.psi
|
||||
|
||||
import gay.pizza.pork.ast.Node
|
||||
import gay.pizza.pork.idea.PorkNodeKey
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.util.childrenOfType
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.idea.PorkElementTypes
|
||||
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||
import gay.pizza.pork.idea.psi.gen.PorkNamedElement
|
||||
import gay.pizza.pork.idea.psi.gen.SymbolElement
|
||||
|
||||
val PorkElement.porkNode: Node?
|
||||
get() = node.getUserData(PorkNodeKey)
|
||||
object PorkElementHelpers {
|
||||
private val symbolElementType = PorkElementTypes.elementTypeFor(NodeType.Symbol)
|
||||
|
||||
val PorkElement.porkNodeChecked: Node
|
||||
get() = porkNode!!
|
||||
fun nameOfNamedElement(element: PorkNamedElement): String? {
|
||||
val child = element.node.findChildByType(symbolElementType)
|
||||
return child?.text
|
||||
}
|
||||
|
||||
fun setNameOfNamedElement(element: PorkNamedElement, name: String): PsiElement = element
|
||||
|
||||
fun nameIdentifierOfNamedElement(element: PorkNamedElement): PsiElement? {
|
||||
val child = element.node.findChildByType(symbolElementType)
|
||||
return child?.psi
|
||||
}
|
||||
|
||||
fun referenceOfElement(element: PorkElement, type: NodeType): PsiReference? {
|
||||
val textRangeOfSymbolInElement = element.childrenOfType<SymbolElement>().firstOrNull()?.textRangeInParent ?: return null
|
||||
if (type == NodeType.FunctionDefinition) {
|
||||
return PorkFunctionReference(element, textRangeOfSymbolInElement)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package gay.pizza.pork.idea.psi
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import gay.pizza.pork.idea.psi.gen.FunctionDefinitionElement
|
||||
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||
|
||||
class PorkFunctionReference(element: PorkElement, textRange: TextRange) : PorkReference(element, textRange) {
|
||||
override fun resolve(): PorkElement? {
|
||||
val functionName = canonicalText
|
||||
for (file in getRelevantFiles()) {
|
||||
val thisFileFunctionDefinitions = PsiTreeUtil.collectElementsOfType(file, FunctionDefinitionElement::class.java)
|
||||
val thisFileFoundFunctionDefinition = thisFileFunctionDefinitions.firstOrNull {
|
||||
it.name == functionName
|
||||
}
|
||||
if (thisFileFoundFunctionDefinition != null) {
|
||||
return thisFileFoundFunctionDefinition
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package gay.pizza.pork.idea.psi
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.PsiReferenceBase
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.childrenOfType
|
||||
import gay.pizza.pork.idea.psi.gen.ImportDeclarationElement
|
||||
import gay.pizza.pork.idea.psi.gen.PorkElement
|
||||
import gay.pizza.pork.idea.psi.gen.SymbolElement
|
||||
|
||||
abstract class PorkReference(element: PorkElement, textRange: TextRange) : PsiReferenceBase<PsiElement>(element, textRange) {
|
||||
fun getRelevantFiles(): List<PsiFile> {
|
||||
val containingFile = element.containingFile
|
||||
val importDeclarationElements = PsiTreeUtil.collectElementsOfType(containingFile, ImportDeclarationElement::class.java)
|
||||
val files = mutableListOf<PsiFile>(containingFile)
|
||||
for (importDeclaration in importDeclarationElements) {
|
||||
val symbolElements = importDeclaration.childrenOfType<SymbolElement>()
|
||||
val importType = importDeclaration.childrenOfType<SymbolElement>().first().text
|
||||
if (importType != "local") {
|
||||
continue
|
||||
}
|
||||
|
||||
val basicImportPath = symbolElements.drop(1).joinToString("/") { it.text.trim() }
|
||||
val actualImportPath = "../${basicImportPath}.pork"
|
||||
val virtualFile = containingFile.virtualFile.findFileByRelativePath(actualImportPath) ?: continue
|
||||
val psiFile = PsiManager.getInstance(element.project).findFile(virtualFile) ?: continue
|
||||
files.add(psiFile)
|
||||
}
|
||||
return files
|
||||
}
|
||||
}
|
@ -1,6 +1,12 @@
|
||||
// GENERATED CODE FROM PORK AST CODEGEN
|
||||
package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class FunctionCallElement(node: ASTNode) : PorkElement(node)
|
||||
class FunctionCallElement(node: ASTNode) : PorkElement(node) {
|
||||
override fun getReference(): PsiReference? =
|
||||
PorkElementHelpers.referenceOfElement(this, NodeType.FunctionDefinition)
|
||||
}
|
||||
|
@ -3,13 +3,15 @@ package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.idea.PorkElementTypes
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class FunctionDefinitionElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
node.findChildByType(PorkElementTypes.elementTypeFor(NodeType.FunctionDefinition))?.text
|
||||
PorkElementHelpers.nameOfNamedElement(this)
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
this
|
||||
PorkElementHelpers.setNameOfNamedElement(this, name)
|
||||
|
||||
override fun getNameIdentifier(): PsiElement? =
|
||||
PorkElementHelpers.nameIdentifierOfNamedElement(this)
|
||||
}
|
||||
|
@ -3,13 +3,15 @@ package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.idea.PorkElementTypes
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class LetAssignmentElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
node.findChildByType(PorkElementTypes.elementTypeFor(NodeType.LetAssignment))?.text
|
||||
PorkElementHelpers.nameOfNamedElement(this)
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
this
|
||||
PorkElementHelpers.setNameOfNamedElement(this, name)
|
||||
|
||||
override fun getNameIdentifier(): PsiElement? =
|
||||
PorkElementHelpers.nameIdentifierOfNamedElement(this)
|
||||
}
|
||||
|
@ -3,13 +3,15 @@ package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.idea.PorkElementTypes
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class LetDefinitionElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
node.findChildByType(PorkElementTypes.elementTypeFor(NodeType.LetDefinition))?.text
|
||||
PorkElementHelpers.nameOfNamedElement(this)
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
this
|
||||
PorkElementHelpers.setNameOfNamedElement(this, name)
|
||||
|
||||
override fun getNameIdentifier(): PsiElement? =
|
||||
PorkElementHelpers.nameIdentifierOfNamedElement(this)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
|
||||
abstract class PorkNamedElement(node: ASTNode) : PorkElement(node), PsiNamedElement
|
||||
abstract class PorkNamedElement(node: ASTNode) : PorkElement(node), PsiNamedElement, PsiNameIdentifierOwner
|
||||
|
@ -3,13 +3,15 @@ package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.idea.PorkElementTypes
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class SetAssignmentElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
node.findChildByType(PorkElementTypes.elementTypeFor(NodeType.SetAssignment))?.text
|
||||
PorkElementHelpers.nameOfNamedElement(this)
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
this
|
||||
PorkElementHelpers.setNameOfNamedElement(this, name)
|
||||
|
||||
override fun getNameIdentifier(): PsiElement? =
|
||||
PorkElementHelpers.nameIdentifierOfNamedElement(this)
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
// GENERATED CODE FROM PORK AST CODEGEN
|
||||
package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.idea.PorkElementTypes
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class SymbolReferenceElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
node.findChildByType(PorkElementTypes.elementTypeFor(NodeType.SymbolReference))?.text
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
this
|
||||
class SymbolReferenceElement(node: ASTNode) : PorkElement(node) {
|
||||
override fun getReference(): PsiReference? =
|
||||
PorkElementHelpers.referenceOfElement(this, NodeType.Node)
|
||||
}
|
||||
|
@ -3,13 +3,15 @@ package gay.pizza.pork.idea.psi.gen
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.lang.ASTNode
|
||||
import gay.pizza.pork.ast.NodeType
|
||||
import gay.pizza.pork.idea.PorkElementTypes
|
||||
import gay.pizza.pork.idea.psi.PorkElementHelpers
|
||||
|
||||
class VarAssignmentElement(node: ASTNode) : PorkNamedElement(node) {
|
||||
override fun getName(): String? =
|
||||
node.findChildByType(PorkElementTypes.elementTypeFor(NodeType.VarAssignment))?.text
|
||||
PorkElementHelpers.nameOfNamedElement(this)
|
||||
|
||||
override fun setName(name: String): PsiElement =
|
||||
this
|
||||
PorkElementHelpers.setNameOfNamedElement(this, name)
|
||||
|
||||
override fun getNameIdentifier(): PsiElement? =
|
||||
PorkElementHelpers.nameIdentifierOfNamedElement(this)
|
||||
}
|
||||
|
@ -17,6 +17,9 @@
|
||||
<lang.commenter
|
||||
language="Pork"
|
||||
implementationClass="gay.pizza.pork.idea.PorkCommenter"/>
|
||||
<lang.braceMatcher
|
||||
language="Pork"
|
||||
implementationClass="gay.pizza.pork.idea.PorkBraceMatcher"/>
|
||||
<psi.declarationProvider implementation="gay.pizza.pork.idea.PorkSymbolDeclarationProvider"/>
|
||||
</extensions>
|
||||
|
||||
|
Reference in New Issue
Block a user