Reworked BNF for symbol references and program counter. Enhanced syntax highlighting. Continued work on referencing (not yet working). Fixed renaming of Labels and Symbols. Added M68kRenameInputValidator for correct renaming of symbols and labels (allow local labels with dot or dollar). Added UsagesProvider (not sure if working). Added PairedBraceMatcher.

This commit is contained in:
2021-07-18 15:05:59 +02:00
parent 349372f6b3
commit 25c755d729
55 changed files with 531 additions and 61 deletions
@@ -126,7 +126,13 @@ statement ::= (Assignment
private statement_recover ::= !(EOL)
Assignment ::= SYMBOLDEF COLON? (OP_ASSIGN|EQU) expr
SymbolDefinition ::= SYMBOLDEF {
implements = "de.platon42.intellij.plugins.m68k.psi.M68kNamedElement"
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kSymbolDefinitionMixin"
methods = [getName setName getNameIdentifier]
}
Assignment ::= SymbolDefinition COLON? (OP_ASSIGN|EQU) expr
private LabelInsts ::= LabelWithInstruction | LabelOnly | InstructionOnly
@@ -173,6 +179,9 @@ private PreprocessorOperand ::= expr
private PlainOperands ::= STRINGLIT (SEPARATOR STRINGLIT)*
SymbolReference ::= SYMBOL // TODO This should probably be a ILazyParseableElementType, no idea how to implement that yet
ProgramCounterReference ::= CURRENT_PC_SYMBOL
DataRegister ::= DREG {
name = "data register"
extends = Register
@@ -280,7 +289,7 @@ binary_logical_or_expr ::= expr OP_LOGICAL_OR expr
//macrobrace_expr ::= OP_CMP_LT expr OP_CMP_GT
paren_expr ::= ROUND_L expr ROUND_R //{pin=1 recoverWhile=statement_recover}
ref_expr ::= SYMBOL|CURRENT_PC_SYMBOL
ref_expr ::= SymbolReference|ProgramCounterReference
literal_expr ::= BINARY|DECIMAL|HEXADECIMAL|OCTAL|STRINGLIT {
implements = "com.intellij.psi.PsiLiteralValue"
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kLiteralExprMixin"
@@ -8,15 +8,20 @@ import de.platon42.intellij.plugins.m68k.M68kFileType.Companion.INSTANCE
object M68kElementFactory {
fun createGlobalLabel(project: Project, label: String): M68kGlobalLabel {
val file = createFile(project, label)
val file = createFile(project, "$label\n")
return PsiTreeUtil.findChildOfType(file, M68kGlobalLabel::class.java)!!
}
fun createLocalLabel(project: Project, label: String): M68kLocalLabel {
val file = createFile(project, label)
val file = createFile(project, "$label\n")
return PsiTreeUtil.findChildOfType(file, M68kLocalLabel::class.java)!!
}
fun createSymbolDefinition(project: Project, label: String): M68kSymbolDefinition {
val file = createFile(project, "$label=0\n")
return PsiTreeUtil.findChildOfType(file, M68kSymbolDefinition::class.java)!!
}
fun createFile(project: Project, content: String): M68kFile {
return PsiFileFactory.getInstance(project).createFileFromText("dummy.m68k", INSTANCE, content) as M68kFile
}
@@ -4,9 +4,11 @@ import com.intellij.psi.PsiElement
import com.intellij.util.IncorrectOperationException
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createLocalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kElementFactory.createSymbolDefinition
object M68kPsiImplUtil {
// Global Label
@JvmStatic
fun getName(element: M68kGlobalLabel): String? = element.firstChild.text
@@ -23,6 +25,7 @@ object M68kPsiImplUtil {
@JvmStatic
fun getNameIdentifier(element: M68kGlobalLabel): PsiElement = element.firstChild
// Local Label
@JvmStatic
fun getName(element: M68kLocalLabel): String? = element.firstChild.text
@@ -39,4 +42,24 @@ object M68kPsiImplUtil {
@JvmStatic
fun getNameIdentifier(element: M68kLocalLabel): PsiElement = element.firstChild
// Symbol Definition
@JvmStatic
fun getName(element: M68kSymbolDefinition): String? = element.firstChild.text
@JvmStatic
fun setName(element: M68kSymbolDefinition, name: String): PsiElement {
val nameNode = element.node.findChildByType(M68kTypes.SYMBOLDEF)
if (nameNode != null) {
val newSymbolDefinition = createSymbolDefinition(element.project, name)
element.node.replaceChild(nameNode, newSymbolDefinition.firstChild.node)
}
return element
}
@JvmStatic
fun getNameIdentifier(element: M68kSymbolDefinition): PsiElement = element.firstChild
}
@@ -0,0 +1,31 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns
import com.intellij.patterns.StandardPatterns
import com.intellij.psi.PsiElement
import com.intellij.refactoring.rename.RenameInputValidator
import com.intellij.util.ProcessingContext
import java.util.regex.Pattern
class M68kRenameInputValidator : RenameInputValidator {
override fun getPattern(): ElementPattern<out PsiElement?> = StandardPatterns.or(
PlatformPatterns.psiElement(M68kGlobalLabel::class.java),
PlatformPatterns.psiElement(M68kLocalLabel::class.java),
PlatformPatterns.psiElement(M68kSymbolDefinition::class.java)
)
override fun isInputValid(newName: String, element: PsiElement, context: ProcessingContext): Boolean {
return when (element) {
is M68kGlobalLabel, is M68kSymbolDefinition -> SYMBOL_PATTERN.matcher(newName).matches()
is M68kLocalLabel -> LOCAL_LABEL_PATTERN.matcher(newName).matches()
else -> false
}
}
companion object {
private val SYMBOL_PATTERN = Pattern.compile("(\\p{Alpha}|_)(\\p{Alnum}|_)*")
private val LOCAL_LABEL_PATTERN = Pattern.compile("(\\.(\\p{Alpha}|_)(\\p{Alnum}|_)*)|((\\p{Alpha}|_)(\\p{Alnum}|_)*\\$)")
}
}
@@ -0,0 +1,8 @@
package de.platon42.intellij.plugins.m68k.psi
import com.intellij.extapi.psi.ASTWrapperPsiElement
import com.intellij.lang.ASTNode
abstract class M68kSymbolDefinitionMixin(node: ASTNode) : ASTWrapperPsiElement(node), M68kSymbolDefinition {
}
@@ -0,0 +1,28 @@
package de.platon42.intellij.plugins.m68k.refs
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.*
import com.intellij.util.ProcessingContext
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
import de.platon42.intellij.plugins.m68k.psi.M68kRefExpr
class M68kReferenceContributor : PsiReferenceContributor() {
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kRefExpr::class.java), object : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
return emptyArray()
}
})
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kGlobalLabel::class.java), object : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
return emptyArray()
}
})
registrar.registerReferenceProvider(PlatformPatterns.psiElement(M68kLocalLabel::class.java), object : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
return emptyArray()
}
})
}
}
@@ -0,0 +1,60 @@
package de.platon42.intellij.plugins.m68k.scanner;
import com.intellij.lang.cacheBuilder.DefaultWordsScanner;
import com.intellij.lang.cacheBuilder.WordsScanner;
import com.intellij.lang.findUsages.FindUsagesProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.tree.TokenSet;
import de.platon42.intellij.plugins.m68k.lexer.M68kLexer;
import de.platon42.intellij.plugins.m68k.lexer.M68kLexerPrefs;
import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel;
import de.platon42.intellij.plugins.m68k.psi.M68kTypes;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class M68kFindUsagesProvider implements FindUsagesProvider {
@Nullable
@Override
public WordsScanner getWordsScanner() {
return new DefaultWordsScanner(new M68kLexer(new M68kLexerPrefs()), // FIXME Oh no! More Prefs!
TokenSet.create(M68kTypes.SYMBOLDEF, M68kTypes.GLOBAL_LABEL_DEF, M68kTypes.LOCAL_LABEL_DEF, M68kTypes.SYMBOL),
TokenSet.create(M68kTypes.COMMENT),
TokenSet.create(M68kTypes.STRINGLIT),
TokenSet.EMPTY);
}
@Override
public boolean canFindUsagesFor(@NotNull PsiElement psiElement) {
return psiElement instanceof PsiNamedElement;
}
@Override
public @Nullable @NonNls String getHelpId(@NotNull PsiElement psiElement) {
return null;
}
@Override
public @Nls @NotNull String getType(@NotNull PsiElement element) {
if (element instanceof M68kGlobalLabel) {
return "global label";
}
return "";
}
@Override
public @Nls @NotNull String getDescriptiveName(@NotNull PsiElement element) {
if (element instanceof M68kGlobalLabel) {
return ((M68kGlobalLabel) element).getName();
}
return "";
}
@Override
public @Nls @NotNull String getNodeText(@NotNull PsiElement element, boolean useFullName) {
return getDescriptiveName(element);
}
}
@@ -22,11 +22,12 @@ import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.MNEMONIC
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.NUMBER
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.OTHER_PREPROCESSOR
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.PROGRAM_COUNTER
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.SEPARATOR
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.SPECIAL_REG
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.STRING
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.SYMBOL
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.SYMBOLDEF
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.SYMBOLREF
import org.jetbrains.annotations.NonNls
import javax.swing.Icon
@@ -55,6 +56,7 @@ demo_init ; global label
tst.w d1
beq.s .skip
PUSHM d0-d7/a0-a6 ; this is a macro call
lea hello(pc),a1
lea pd_ModViewTable(a4,d1.w),a0
moveq.l #0,d0
move.w #PIC_HEIGHT-1,d7
@@ -65,6 +67,7 @@ demo_init ; global label
hello: dc.b 'Hello World!',10,0
even
dc.w *-hello ; length of string
"""
}
@@ -91,7 +94,7 @@ hello: dc.b 'Hello World!',10,0
AttributesDescriptor("Comma (separator)", SEPARATOR),
AttributesDescriptor("Colon", COLON),
AttributesDescriptor("Symbol definition", SYMBOLDEF),
AttributesDescriptor("Symbol reference", SYMBOL),
AttributesDescriptor("Symbol reference", SYMBOLREF),
AttributesDescriptor("Assembly mnemonic", MNEMONIC),
AttributesDescriptor("Macro invocation", MACRO_CALL),
AttributesDescriptor("Byte/short data width", DATA_WIDTH_BS),
@@ -103,6 +106,7 @@ hello: dc.b 'Hello World!',10,0
AttributesDescriptor("Numbers", NUMBER),
AttributesDescriptor("Address registers", AREG),
AttributesDescriptor("Data registers", DREG),
AttributesDescriptor("Program counter", PROGRAM_COUNTER),
AttributesDescriptor("Special registers", SPECIAL_REG),
AttributesDescriptor("Comments", COMMENT),
AttributesDescriptor("Bad characters", BAD_CHARACTER)
@@ -0,0 +1,22 @@
package de.platon42.intellij.plugins.m68k.syntax
import com.intellij.lang.BracePair
import com.intellij.lang.PairedBraceMatcher
import com.intellij.psi.PsiFile
import com.intellij.psi.tree.IElementType
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kPairedBraceMatcher : PairedBraceMatcher {
companion object {
val bracePairs = arrayOf(
BracePair(M68kTypes.ROUND_L, M68kTypes.ROUND_R, false)
)
}
override fun getPairs(): Array<BracePair> = bracePairs
override fun isPairedBracesAllowedBeforeType(lbraceType: IElementType, contextType: IElementType?) = true
override fun getCodeConstructStart(file: PsiFile, openingBraceOffset: Int) = openingBraceOffset
}
@@ -26,10 +26,11 @@ class M68kSyntaxHighlighter(val project: Project?) : SyntaxHighlighterBase() {
return when (tokenType) {
M68kTypes.SEPARATOR -> arrayOf(SEPARATOR)
M68kTypes.COLON -> arrayOf(COLON)
M68kTypes.GLOBAL_LABEL_DEF, M68kTypes.GLOBAL_LABEL -> arrayOf(GLOBAL_LABEL)
M68kTypes.LOCAL_LABEL_DEF, M68kTypes.LOCAL_LABEL -> arrayOf(LOCAL_LABEL)
M68kTypes.GLOBAL_LABEL_DEF -> arrayOf(GLOBAL_LABEL)
M68kTypes.LOCAL_LABEL_DEF -> arrayOf(LOCAL_LABEL)
M68kTypes.SYMBOLDEF -> arrayOf(SYMBOLDEF)
M68kTypes.SYMBOL -> arrayOf(SYMBOL)
M68kTypes.SYMBOL -> arrayOf(SYMBOLREF)
M68kTypes.CURRENT_PC_SYMBOL, M68kTypes.PC -> arrayOf(PROGRAM_COUNTER)
M68kTypes.MNEMONIC -> arrayOf(MNEMONIC)
M68kTypes.MACRO_INVOKATION -> arrayOf(MACRO_CALL)
M68kTypes.DATA_DIRECTIVE -> arrayOf(DATA_PREPROCESSOR)
@@ -37,9 +38,9 @@ class M68kSyntaxHighlighter(val project: Project?) : SyntaxHighlighterBase() {
M68kTypes.OPSIZE_BS -> arrayOf(DATA_WIDTH_BS)
M68kTypes.OPSIZE_W -> arrayOf(DATA_WIDTH_W)
M68kTypes.OPSIZE_L -> arrayOf(DATA_WIDTH_L)
M68kTypes.ADDRESS_REGISTER, M68kTypes.AREG -> arrayOf(AREG)
M68kTypes.DATA_REGISTER, M68kTypes.DREG -> arrayOf(DREG)
M68kTypes.SPECIAL_REGISTER, M68kTypes.REG_USP, M68kTypes.REG_SR, M68kTypes.REG_CCR -> arrayOf(SPECIAL_REG)
M68kTypes.AREG -> arrayOf(AREG)
M68kTypes.DREG -> arrayOf(DREG)
M68kTypes.REG_USP, M68kTypes.REG_SR, M68kTypes.REG_CCR, M68kTypes.REG_VBR -> arrayOf(SPECIAL_REG)
M68kTypes.COMMENT -> arrayOf(COMMENT)
M68kTypes.DECIMAL, M68kTypes.HEXADECIMAL, M68kTypes.OCTAL -> arrayOf(NUMBER)
M68kTypes.STRINGLIT -> arrayOf(STRING)
@@ -54,7 +55,8 @@ class M68kSyntaxHighlighter(val project: Project?) : SyntaxHighlighterBase() {
val SEPARATOR = TextAttributesKey.createTextAttributesKey("M68K_SEPARATOR", DefaultLanguageHighlighterColors.COMMA)
val COLON = TextAttributesKey.createTextAttributesKey("M68K_COLON", DefaultLanguageHighlighterColors.DOT)
val SYMBOLDEF = TextAttributesKey.createTextAttributesKey("M68K_SYMBOLDEF", DefaultLanguageHighlighterColors.STATIC_FIELD)
val SYMBOL = TextAttributesKey.createTextAttributesKey("M68K_SYMBOL", DefaultLanguageHighlighterColors.IDENTIFIER)
val SYMBOLREF = TextAttributesKey.createTextAttributesKey("M68K_SYMBOLREF", DefaultLanguageHighlighterColors.IDENTIFIER)
val PROGRAM_COUNTER = TextAttributesKey.createTextAttributesKey("M68K_PROGRAM_COUNTER", DefaultLanguageHighlighterColors.IDENTIFIER)
val MNEMONIC = TextAttributesKey.createTextAttributesKey("M68K_MNEMONIC", DefaultLanguageHighlighterColors.FUNCTION_CALL)
val MACRO_CALL = TextAttributesKey.createTextAttributesKey("M68K_MACRO_CALL", DefaultLanguageHighlighterColors.STATIC_METHOD)
val DATA_WIDTH_BS = TextAttributesKey.createTextAttributesKey("M68K_DATA_WIDTH_BS", DefaultLanguageHighlighterColors.DOT)