diff --git a/README.md b/README.md
index aec1116..989f04c 100644
--- a/README.md
+++ b/README.md
@@ -112,6 +112,7 @@ If the current statement has no valid syntax, the instruction details of all mat
## Known issues
- `Find Usages` always shows _"Unclassified"_ though it shouldn't (?)
+- Typing in the `END` keyword will sometimes mess up the parsing for the next tokens.
- Macro invocations are not yet evaluated, thus no referencing to symbols defined via macros (e.g. `STRUCT`).
- Scoping for global symbols and labels is currently the whole project.
- No support for register replacement (e.g. registers replaced by `EQUR` or `EQURL` will cause syntax errors)
@@ -142,19 +143,22 @@ make it work with JUnit 5. Feel free to use the code (in package ```de.platon42.
## Feedback
-I guess there are currently about 100 users of this plugin and while I wrote this mainly for myself, I'm only doing this in my spare time. Feedback
-and [rating](https://plugins.jetbrains.com/plugin/17268-mc68000-assembly-language-support/reviews)
-are appreciated. They really are, because they do keep me motivated to continue development.
+I guess there are currently over 500 users of this plugin and while I wrote this mainly for myself, I'm only doing this in my spare time.
+
+Feedback and [rating](https://plugins.jetbrains.com/plugin/17268-mc68000-assembly-language-support/reviews)
+are appreciated. It really is keeping me motivated to continue development.
## Changelog
-### V0.7 (unreleased)
+### V0.7 (26-Sep-21)
- Bugfix: `btst` with pc-relative and weird immediate mode was missing (courtesy of Yann).
- Bugfix: `movem` with pc-relative mode was missing for weird immediate mode (courtesy of Yann).
- Bugfix: Special registers for address mode matching only worked with lower case register names (courtesy of Yann).
- Enhancement: Assembler syntax with implicit immediate 1 for shifts and rotations no longer cause syntax errors (courtesy of Yann).
- Enhancement: Documentation for instruction with special register shows specific register expected.
+- New: Added documentation provider info for global labels. Shows directives and comments above.
+- Bugfix: Fixed BNF for labels with preprocessor statements.
### V0.6 (09-Aug-21)
diff --git a/build.gradle b/build.gradle
index 79be03f..b9b3ab3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,9 +1,9 @@
plugins {
id 'java'
- id 'org.jetbrains.intellij' version '1.1.5'
+ id 'org.jetbrains.intellij' version '1.1.6'
id 'org.jetbrains.kotlin.jvm' version '1.5.21'
id 'jacoco'
- id 'com.github.kt3k.coveralls' version '2.11.0'
+ id 'com.github.kt3k.coveralls' version '2.12.0'
}
group = 'de.platon42'
@@ -22,9 +22,9 @@ repositories {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
- testImplementation "org.assertj:assertj-core:3.20.2"
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.0-M1'
- testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.0-M1'
+ testImplementation "org.assertj:assertj-core:3.21.0"
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
testImplementation "org.jetbrains.kotlin:kotlin-test"
testImplementation "org.jetbrains.kotlin:kotlin-reflect"
// testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
@@ -57,35 +57,16 @@ runPluginVerifier {
patchPluginXml {
setChangeNotes("""
-
V0.7 (unreleased)
+ I still got zero feedback and zero ratings :-(
+ V0.7 (26-Sep-21)
- Bugfix: 'btst' with pc-relative and weird immediate mode was missing (courtesy of Yann).
- Bugfix: 'movem' with pc-relative mode was missing for weird immediate mode (courtesy of Yann).
- Bugfix: Special registers for address mode matching only worked with lower case register names (courtesy of Yann).
- Enhancement: Assembler syntax with implicit immediate 1 for shifts and rotations no longer cause syntax errors (courtesy of Yann).
- Enhancement: Documentation for instruction with special register shows specific register expected.
-
- V0.6 (09-Aug-21)
-
- - Enhancement: 'opt' and several other directives ('printt', 'fail' etc.) no longer causes a syntax error when unquoted.
-
- Enhancement: 'include', 'incdir' and 'incbin' and 'output' with '<pathname>' quotes no longer cause syntax error.
-
- New: Files in 'include' directives can be referenced and renamed/refactored.
-
- New: Code completion for local label definitions, suggesting undefined labels already referenced.
-
- New: Added inspection suppression possibility and quickfix.
-
- New: Added inspection for unresolved symbols, macros and labels.
-
- Enhancement: 'END' directive stops parsing.
-
- V0.5 (06-Aug-21)
-
- - Bugfix: movem ISA was wrong regarding movem.w <ea>,<registerlist> (sign extends registers).
-
- Cosmetics: Changed Register Flow Documentation wording from 'reads' to 'uses' and from 'modifies' to 'changes'.
-
- Bugfix: Minor fix for 'andi/eori/ori to ccr' which were not byte sized in ISA.
-
- Bugfix: Added alternate condition code tests HS (=CC) and LO (=CS).
-
- Performance: Optimized mnemonic lookup.
-
- Enhancement: Reworked Instruction Documentation provider, now shows condition codes.
-
- Bugfix: In ISA exg is no longer treated as setting a definitive value.
-
- New: Added inspection to find dead writes to registers!
-
- New: Added inspection to warn about unexpected condition code unaffecting instructions before conditional instructions.
+
- New: Added documentation provider info for global labels. Shows directives and comments above.
+
- Bugfix: Fixed BNF for labels with preprocessor statements.
Full changelog available at Github project site.
""")
diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java b/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java
index db53253..4b6341c 100644
--- a/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java
+++ b/src/main/gen/de/platon42/intellij/plugins/m68k/parser/M68kParser.java
@@ -562,9 +562,13 @@ public class M68kParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
- // Instruction
+ // Instruction|PreprocessorDirective
static boolean InstructionOnly(PsiBuilder b, int l) {
- return Instruction(b, l + 1);
+ if (!recursion_guard_(b, l, "InstructionOnly")) return false;
+ boolean r;
+ r = Instruction(b, l + 1);
+ if (!r) r = PreprocessorDirective(b, l + 1);
+ return r;
}
/* ********************************************************** */
@@ -596,18 +600,27 @@ public class M68kParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
- // Label Instruction
+ // Label (Instruction|PreprocessorDirective)
static boolean LabelWithInstruction(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "LabelWithInstruction")) return false;
if (!nextTokenIs(b, "", GLOBAL_LABEL_DEF, LOCAL_LABEL_DEF)) return false;
boolean r;
Marker m = enter_section_(b);
r = Label(b, l + 1);
- r = r && Instruction(b, l + 1);
+ r = r && LabelWithInstruction_1(b, l + 1);
exit_section_(b, m, null, r);
return r;
}
+ // Instruction|PreprocessorDirective
+ private static boolean LabelWithInstruction_1(PsiBuilder b, int l) {
+ if (!recursion_guard_(b, l, "LabelWithInstruction_1")) return false;
+ boolean r;
+ r = Instruction(b, l + 1);
+ if (!r) r = PreprocessorDirective(b, l + 1);
+ return r;
+ }
+
/* ********************************************************** */
// LOCAL_LABEL_DEF COLON?
public static boolean LocalLabel(PsiBuilder b, int l) {
@@ -817,28 +830,21 @@ public class M68kParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
- // Label? PreprocessorKeyword PreprocessorOperands?
+ // PreprocessorKeyword PreprocessorOperands?
public static boolean PreprocessorDirective(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "PreprocessorDirective")) return false;
+ if (!nextTokenIs(b, "", DATA_DIRECTIVE, OTHER_DIRECTIVE)) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, PREPROCESSOR_DIRECTIVE, "");
- r = PreprocessorDirective_0(b, l + 1);
- r = r && PreprocessorKeyword(b, l + 1);
- r = r && PreprocessorDirective_2(b, l + 1);
+ r = PreprocessorKeyword(b, l + 1);
+ r = r && PreprocessorDirective_1(b, l + 1);
exit_section_(b, l, m, r, false, null);
return r;
}
- // Label?
- private static boolean PreprocessorDirective_0(PsiBuilder b, int l) {
- if (!recursion_guard_(b, l, "PreprocessorDirective_0")) return false;
- Label(b, l + 1);
- return true;
- }
-
// PreprocessorOperands?
- private static boolean PreprocessorDirective_2(PsiBuilder b, int l) {
- if (!recursion_guard_(b, l, "PreprocessorDirective_2")) return false;
+ private static boolean PreprocessorDirective_1(PsiBuilder b, int l) {
+ if (!recursion_guard_(b, l, "PreprocessorDirective_1")) return false;
PreprocessorOperands(b, l + 1);
return true;
}
@@ -1220,14 +1226,12 @@ public class M68kParser implements PsiParser, LightPsiParser {
/* ********************************************************** */
// Assignment
- // | PreprocessorDirective
// | LabelInsts
public static boolean statement(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "statement")) return false;
boolean r;
Marker m = enter_section_(b, l, _NONE_, STATEMENT, "");
r = Assignment(b, l + 1);
- if (!r) r = PreprocessorDirective(b, l + 1);
if (!r) r = LabelInsts(b, l + 1);
exit_section_(b, l, m, r, false, M68kParser::statement_recover);
return r;
diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kPreprocessorDirective.java b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kPreprocessorDirective.java
index 56d6d31..7706a82 100644
--- a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kPreprocessorDirective.java
+++ b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/M68kPreprocessorDirective.java
@@ -2,18 +2,11 @@
package de.platon42.intellij.plugins.m68k.psi;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface M68kPreprocessorDirective extends M68kPsiElement {
- @Nullable
- M68kGlobalLabel getGlobalLabel();
-
- @Nullable
- M68kLocalLabel getLocalLabel();
-
@NotNull
M68kPreprocessorKeyword getPreprocessorKeyword();
diff --git a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kPreprocessorDirectiveImpl.java b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kPreprocessorDirectiveImpl.java
index fba03a7..92b4ed4 100644
--- a/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kPreprocessorDirectiveImpl.java
+++ b/src/main/gen/de/platon42/intellij/plugins/m68k/psi/impl/M68kPreprocessorDirectiveImpl.java
@@ -6,7 +6,6 @@ import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import de.platon42.intellij.plugins.m68k.psi.*;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -26,18 +25,6 @@ public class M68kPreprocessorDirectiveImpl extends M68kPreprocessorDirectiveMixi
else super.accept(visitor);
}
- @Override
- @Nullable
- public M68kGlobalLabel getGlobalLabel() {
- return PsiTreeUtil.getChildOfType(this, M68kGlobalLabel.class);
- }
-
- @Override
- @Nullable
- public M68kLocalLabel getLocalLabel() {
- return PsiTreeUtil.getChildOfType(this, M68kLocalLabel.class);
- }
-
@Override
@NotNull
public M68kPreprocessorKeyword getPreprocessorKeyword() {
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kGlobalLabelDocumentationProvider.kt b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kGlobalLabelDocumentationProvider.kt
new file mode 100644
index 0000000..bc94919
--- /dev/null
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kGlobalLabelDocumentationProvider.kt
@@ -0,0 +1,47 @@
+package de.platon42.intellij.plugins.m68k.documentation
+
+import com.intellij.lang.documentation.AbstractDocumentationProvider
+import com.intellij.lang.documentation.DocumentationMarkup
+import com.intellij.openapi.util.text.StringUtil
+import com.intellij.psi.PsiComment
+import com.intellij.psi.PsiElement
+import com.intellij.psi.util.PsiTreeUtil
+import com.intellij.util.SmartList
+import de.platon42.intellij.plugins.m68k.psi.M68kGlobalLabel
+import de.platon42.intellij.plugins.m68k.psi.M68kStatement
+
+class M68kGlobalLabelDocumentationProvider : AbstractDocumentationProvider() {
+
+ override fun getQuickNavigateInfo(element: PsiElement, originalElement: PsiElement?): String? {
+ return generateDoc(element, originalElement)
+ }
+
+ override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? {
+ return if (element is M68kGlobalLabel) {
+ // TODO find out how we can generate inner links for more symbol references inside the expression (DocumentationManagerUtil)
+ val statement = element.parent as M68kStatement
+ var preprocessorDirective = statement.preprocessorDirective
+ if ((preprocessorDirective == null) && (statement.asmInstruction == null) && (statement.macroCall == null)) {
+ val nextLineStatement = PsiTreeUtil.skipWhitespacesAndCommentsForward(PsiTreeUtil.skipWhitespacesAndCommentsForward(statement))
+ as? M68kStatement
+ preprocessorDirective = nextLineStatement?.preprocessorDirective
+ }
+ val content = if (preprocessorDirective != null)
+ DocumentationMarkup.CONTENT_START + StringUtil.escapeXmlEntities(preprocessorDirective.text) + DocumentationMarkup.CONTENT_END
+ else ""
+ val comments = SmartList()
+ var prevToken: PsiElement? = statement
+ do {
+ prevToken = PsiTreeUtil.skipWhitespacesBackward(prevToken)
+ if (prevToken !is PsiComment) break
+ comments.add(prevToken.text)
+ } while (true)
+ val commentpart =
+ if (comments.isNotEmpty()) comments.asReversed().joinToString("
", DocumentationMarkup.GRAYED_START, DocumentationMarkup.GRAYED_END) else ""
+
+ commentpart +
+ DocumentationMarkup.DEFINITION_START + StringUtil.escapeXmlEntities(element.name!!) + DocumentationMarkup.DEFINITION_END +
+ content
+ } else null
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kSymbolDefinitionDocumentationProvider.kt b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kSymbolDefinitionDocumentationProvider.kt
index e03df8b..a38f473 100644
--- a/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kSymbolDefinitionDocumentationProvider.kt
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/documentation/M68kSymbolDefinitionDocumentationProvider.kt
@@ -16,7 +16,7 @@ class M68kSymbolDefinitionDocumentationProvider : AbstractDocumentationProvider(
override fun generateDoc(element: PsiElement, originalElement: PsiElement?): String? {
return if (element is M68kSymbolDefinition) {
// TODO find out how we can generate inner links for more symbol references inside the expression (DocumentationManagerUtil)
- val value = (element.getParent() as M68kAssignment).expr.text
+ val value = (element.parent as M68kAssignment).expr.text
DocumentationMarkup.DEFINITION_START + StringUtil.escapeXmlEntities(element.name!!) + DocumentationMarkup.DEFINITION_END +
DocumentationMarkup.CONTENT_START + StringUtil.escapeXmlEntities(value) + DocumentationMarkup.CONTENT_END
} else null
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf b/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf
index e07cf14..ae1b77c 100644
--- a/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/m68k.bnf
@@ -121,7 +121,6 @@ M68kFile ::= line*
private line ::= !<> (MacroDefinition | statement) (<>|EOL)
statement ::= (Assignment
- | PreprocessorDirective
| LabelInsts)
{pin = 1 recoverWhile = statement_recover}
@@ -140,8 +139,8 @@ Assignment ::= SymbolDefinition COLON? (OP_ASSIGN|EQU) expr
private LabelInsts ::= LabelWithInstruction | LabelOnly | InstructionOnly
private LabelOnly ::= Label
-private LabelWithInstruction ::= Label Instruction
-private InstructionOnly ::= Instruction
+private LabelWithInstruction ::= Label (Instruction|PreprocessorDirective)
+private InstructionOnly ::= (Instruction|PreprocessorDirective)
LocalLabel ::= LOCAL_LABEL_DEF COLON? {
name = "local label"
@@ -175,7 +174,7 @@ AsmOp ::= MNEMONIC OperandSize? {
PreprocessorKeyword ::= (DATA_DIRECTIVE | OTHER_DIRECTIVE)
-PreprocessorDirective ::= Label? PreprocessorKeyword PreprocessorOperands? {
+PreprocessorDirective ::= PreprocessorKeyword PreprocessorOperands? {
mixin = "de.platon42.intellij.plugins.m68k.psi.M68kPreprocessorDirectiveMixin"
}
diff --git a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt b/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt
index 2d7165c..eaa91a7 100644
--- a/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt
+++ b/src/main/java/de/platon42/intellij/plugins/m68k/psi/M68kPsiImplUtil.kt
@@ -29,7 +29,7 @@ object M68kPsiImplUtil {
// Local Label
@JvmStatic
- fun getName(element: M68kLocalLabel): String = element.firstChild?.text ?: ""
+ fun getName(element: M68kLocalLabel): String? = element.firstChild?.text
@JvmStatic
fun setName(element: M68kLocalLabel, name: String): PsiElement {
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index a4e1cc8..dc874d9 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -39,6 +39,8 @@
implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kPreprocessorDirectiveElementManipulator"/>
+
me
+ """
+ )
+ assertThat(generateDocumentation(myFixture))
+ .isEqualTo("; inputs: d0 = number
; output: d0 = squareinclude "fancysquarecode.asm"
")
+ }
+
+ @Test
+ internal fun check_documentation_for_a_label_definition_next_line(@MyFixture myFixture: CodeInsightTestFixture) {
+ myFixture.configureByText(
+ "documentme.asm", """
+; output: d0 = square
+squareme:
+; oh man
+ include "fancysquarecode.asm"
+ """
+ )
+ assertThat(generateDocumentation(myFixture))
+ .isEqualTo("; output: d0 = squareinclude "fancysquarecode.asm"
")
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/parser/directives/dc_b_with_strings_and_global_label.txt b/src/test/resources/parser/directives/dc_b_with_strings_and_global_label.txt
index 8a8d13a..9d42208 100644
--- a/src/test/resources/parser/directives/dc_b_with_strings_and_global_label.txt
+++ b/src/test/resources/parser/directives/dc_b_with_strings_and_global_label.txt
@@ -1,10 +1,10 @@
Assembly File: a.asm
M68kStatementImpl(STATEMENT)
+ M68kGlobalLabelImpl(GLOBAL_LABEL)
+ PsiElement(M68kTokenType.GLOBAL_LABEL_DEF)('foo')
+ PsiElement(M68kTokenType.COLON)(':')
+ PsiWhiteSpace(' ')
M68kPreprocessorDirectiveImpl(PREPROCESSOR_DIRECTIVE)
- M68kGlobalLabelImpl(GLOBAL_LABEL)
- PsiElement(M68kTokenType.GLOBAL_LABEL_DEF)('foo')
- PsiElement(M68kTokenType.COLON)(':')
- PsiWhiteSpace(' ')
M68kPreprocessorKeywordImpl(PREPROCESSOR_KEYWORD)
PsiElement(M68kTokenType.DATA_DIRECTIVE)('dc.b')
PsiWhiteSpace(' ')
diff --git a/src/test/resources/parser/directives/include_file_unquoted.txt b/src/test/resources/parser/directives/include_file_unquoted.txt
index 440b525..a3a12fc 100644
--- a/src/test/resources/parser/directives/include_file_unquoted.txt
+++ b/src/test/resources/parser/directives/include_file_unquoted.txt
@@ -1,9 +1,9 @@
Assembly File: a.asm
M68kStatementImpl(STATEMENT)
+ M68kGlobalLabelImpl(GLOBAL_LABEL)
+ PsiElement(M68kTokenType.GLOBAL_LABEL_DEF)('howto')
+ PsiElement(M68kTokenType.COLON)(':')
M68kPreprocessorDirectiveImpl(PREPROCESSOR_DIRECTIVE)
- M68kGlobalLabelImpl(GLOBAL_LABEL)
- PsiElement(M68kTokenType.GLOBAL_LABEL_DEF)('howto')
- PsiElement(M68kTokenType.COLON)(':')
M68kPreprocessorKeywordImpl(PREPROCESSOR_KEYWORD)
PsiElement(M68kTokenType.OTHER_DIRECTIVE)('incbin')
PsiWhiteSpace(' ')