Compare commits

..

12 Commits
v0.8 ... main

49 changed files with 1151 additions and 140 deletions

View File

@ -1,4 +1,4 @@
# MC68000 Assembly Language Plugin [![Build Status](https://travis-ci.com/chrisly42/mc68000-asm-plugin.svg?branch=main)](https://travis-ci.com/chrisly42/mc68000-asm-plugin) [![Coverage Status](https://coveralls.io/repos/github/chrisly42/mc68000-asm-plugin/badge.svg?branch=main&kill_cache=1)](https://coveralls.io/github/chrisly42/mc68000-asm-plugin?branch=main) # MC68000 Assembly Language Plugin
_MC68000 Assembly Language Plugin_ is plugin for Jetbrains IDEs (CLion, IntelliJ, etc.). _MC68000 Assembly Language Plugin_ is plugin for Jetbrains IDEs (CLion, IntelliJ, etc.).
@ -133,6 +133,7 @@ If the current statement has no valid syntax, the instruction details of all mat
- Switching the spaces option usually needs the caches to be invalidated. Find Usages word scanner always uses default settings, as it is not configurable per - Switching the spaces option usually needs the caches to be invalidated. Find Usages word scanner always uses default settings, as it is not configurable per
project :-/ project :-/
- Unit Test coverage is not as good as it could be (ahem). - Unit Test coverage is not as good as it could be (ahem).
- Code flow sometimes outputs "uhm?"
- Missing but planned features: - Missing but planned features:
- Macro evaluation on invocation - Macro evaluation on invocation
- Folding - Folding
@ -149,9 +150,10 @@ to highlight the same address and data registers while editing (see new `View ->
## Development notice ## Development notice
This plugin has been written in Kotlin 1.5 using Grammar-Kit. This plugin has been written in Kotlin 1.9 using Grammar-Kit.
It is probably the only plugin (besides [Cajon](https://github.com/chrisly42/cajon-plugin) from the same author) that uses JUnit 5 Jupiter for unit testing so It is probably the only plugin (besides [Cajon](https://git.platon42.de/chrisly42/cajon-plugin) from the same author) that uses JUnit 5 Jupiter for unit testing
so
far (or at least the only one I'm aware of ;) ). The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing, and it took me quite a while to far (or at least the only one I'm aware of ;) ). The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing, and it took me quite a while to
make it work with JUnit 5. Feel free to use the code (in package ```de.platon42.intellij.jupiter```) for your projects (with attribution). make it work with JUnit 5. Feel free to use the code (in package ```de.platon42.intellij.jupiter```) for your projects (with attribution).
@ -164,6 +166,26 @@ are appreciated. It really is keeping me motivated to continue development.
## Changelog ## Changelog
### V0.10 (20-Feb-24)
- Decided to release some features that have been sitting on my harddrive for almost two years, but never got released,
because I was unable to get that damn formatter working in a way that was acceptable (the API and the docs are easily one
the worst abominations I've come across).
- Maintenance. Updated all dependencies to the latest versions.
- New: Added semantic highlighting. Currently available for data and address registers and local labels.
- Bugfix: addq/subq for address register stated it would affect the condition codes, which it in fact doesn't.
- New: Added simple custom navigation bar.
- New: Added folding support for functions and macro definitions.
- New: Added assembler directives to code completion (only lower-case except for other directives like IF
and MACRO, which are only suggested for upper-case).
### V0.9 (16-Aug-22)
- Maintenance. Updated all dependencies to the latest versions.
- Bugfix: Fixed condition code for `asr/lsr/lsl`, which is has a different behaviour for V flag than `asl`.
- Bugfix: Fixed 'Unknown op size' exception when uppercase sizes were used.
- Bugfix: Refactoring was broken for newer IDE versions, at least for me, this now works again by unknown magic.
### V0.8 (15-Oct-21) ### V0.8 (15-Oct-21)
- New: Support for MC68020+ addressing modes! However, MC68020+ specific instructions have not been added yet. - New: Support for MC68020+ addressing modes! However, MC68020+ specific instructions have not been added yet.

View File

@ -1,15 +1,14 @@
plugins { plugins {
id 'java' id 'java'
id 'org.jetbrains.intellij' version '1.1.6' id 'org.jetbrains.intellij' version '1.17.1'
id 'org.jetbrains.kotlin.jvm' version '1.5.21' id 'org.jetbrains.kotlin.jvm' version '1.9.22'
id 'jacoco' id 'jacoco'
id 'com.github.kt3k.coveralls' version '2.12.0'
} }
group = 'de.platon42' group = 'de.platon42'
version = '0.8' version = '0.10'
sourceCompatibility = "1.8" sourceCompatibility = 17
targetCompatibility = "1.8" targetCompatibility = 17
repositories { repositories {
mavenCentral() mavenCentral()
@ -22,53 +21,44 @@ repositories {
dependencies { dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
testImplementation "org.assertj:assertj-core:3.21.0" testImplementation 'org.assertj:assertj-core:3.25.3'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
testImplementation "org.jetbrains.kotlin:kotlin-test" testImplementation "org.jetbrains.kotlin:kotlin-test"
testImplementation "org.jetbrains.kotlin:kotlin-reflect" testImplementation "org.jetbrains.kotlin:kotlin-reflect"
testImplementation 'org.junit.platform:junit-platform-launcher:1.10.2'
// testImplementation "org.jetbrains.kotlin:kotlin-test-junit" // testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
} }
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += "-Xjvm-default=all"
}
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
intellij { intellij {
setVersion("2021.2.2") // LATEST-EAP-SNAPSHOT setVersion("2022.3") // LATEST-EAP-SNAPSHOT
setUpdateSinceUntilBuild(false) setUpdateSinceUntilBuild(false)
// setPlugins(["com.intellij.java"]) // setPlugins(["com.intellij.java"])
} }
runPluginVerifier { runPluginVerifier {
ideVersions = ["IC-203.6682.168", "IC-212.5457.46", // 2020.3 - 2021.2.3 ideVersions = ["IC-203.6682.168", "IC-233.14015.106", // 2020.3 - 2023.3
"CL-203.5981.166", "CL-203.8084.11", // 2020.3 "CL-203.8084.11", "CL-233.14015.92"] // 2020.3 - 2023.3
"CL-211.6693.114", "CL-211.7628.27", // 2021.1
"CL-212.4746.93", "CL-212.5284.51"] // 2021.2 - 2021.2.2
downloadDir = System.getProperty("user.home") + "/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/verifier" downloadDir = System.getProperty("user.home") + "/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/verifier"
} }
patchPluginXml { patchPluginXml {
setChangeNotes(""" setChangeNotes("""
<p>I still got zero feedback and zero <a href="https://plugins.jetbrains.com/plugin/17268-mc68000-assembly-language-support/reviews">ratings</a> :-(</p> <h4>V0.10 (20-Feb-24)</h4>
<h4>V0.8 (15-Oct-21)</h4>
<ul> <ul>
<li>New: Support for MC68020+ addressing modes! However, MC68020+ specific instructions have not been added yet. <li>Decided to release some features that have been sitting on my harddrive for almost two years, but never got released,
<li>New: Full support for MC68010 ISA ('movec', 'moves' and new special registers 'SFC' and 'DFC'). because I was unable to get that damn formatter working in a way that was acceptable (the API and the docs are easily one
<li>Enhancement: Label documentation now also works for local labels and includes end-of-line comment for label, too. the worst abominations I've come across).
<li>Enhancement: Symbol definition documentation now also includes comments in the same way as the label documentation does. <li>Maintenance. Updated all dependencies to the latest versions.
<li>New: Macro definition / invocation documentation provider that even tries to expand macros. <li>New: Added semantic highlighting. Currently available for data and address registers and local labels.
<li>New: Added Language settings page with one option so far (-spaces option). <li>Bugfix: addq/subq for address register stated it would affect the condition codes, which it in fact doesn't.
<li>New: Added some more settings for maximum parsed lines inside a macro and maximum displayed lines of code for documentation. <li>New: Added simple custom navigation bar.
<li>New: Added folding support for functions and macro definitions.
<li>New: Added assembler directives to code completion (only lower-case except for other directives like IF
and MACRO, which are only suggested for upper-case).
</ul> </ul>
<p>Full changelog available at <a href="https://github.com/chrisly42/mc68000-asm-plugin#changelog">Github project site</a>.</p> <p>Full changelog available at <a href="https://git.platon42.de/chrisly42/mc68000-asm-plugin#changelog">Gitea project site</a>.</p>
""") """)
} }
@ -79,10 +69,13 @@ test {
testLogging { testLogging {
events "passed", "skipped", "failed" events "passed", "skipped", "failed"
} }
runIde {
jvmArgs '--add-exports', 'java.base/jdk.internal.vm=ALL-UNNAMED'
}
} }
jacoco { jacoco {
toolVersion = '0.8.7' toolVersion = '0.8.8'
} }
jacocoTestReport { jacocoTestReport {

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

17
plans.txt Normal file
View File

@ -0,0 +1,17 @@
Formatting:
- dc.w statements: Pressing return will automatically add dc.w in next line (plus tabs)
Showing of used registers in selection
Actions:
- Replace constant by symbol (with suggestion)
- Converting of hex values into decimal values and vice versa
- convert new style to old style
- convert old style to new style
- simplify explicit mnemonics (e.g. movea)
Marker:
- go to source register setter
- go to target register setter
- Can we add "find declaration to go for registers"

View File

@ -649,22 +649,12 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// AsmInstruction | MacroCall // AsmInstruction | MacroCall | PreprocessorDirective
static boolean Instruction(PsiBuilder b, int l) { static boolean Instruction(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "Instruction")) return false; if (!recursion_guard_(b, l, "Instruction")) return false;
if (!nextTokenIs(b, "", MACRO_INVOCATION, MNEMONIC)) return false;
boolean r; boolean r;
r = AsmInstruction(b, l + 1); r = AsmInstruction(b, l + 1);
if (!r) r = MacroCall(b, l + 1); if (!r) r = MacroCall(b, l + 1);
return r;
}
/* ********************************************************** */
// Instruction|PreprocessorDirective
static boolean InstructionOnly(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "InstructionOnly")) return false;
boolean r;
r = Instruction(b, l + 1);
if (!r) r = PreprocessorDirective(b, l + 1); if (!r) r = PreprocessorDirective(b, l + 1);
return r; return r;
} }
@ -681,13 +671,13 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// LabelWithInstruction | LabelOnly | InstructionOnly // LabelWithInstruction | LabelOnly | Instruction
static boolean LabelInsts(PsiBuilder b, int l) { static boolean LabelInsts(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "LabelInsts")) return false; if (!recursion_guard_(b, l, "LabelInsts")) return false;
boolean r; boolean r;
r = LabelWithInstruction(b, l + 1); r = LabelWithInstruction(b, l + 1);
if (!r) r = LabelOnly(b, l + 1); if (!r) r = LabelOnly(b, l + 1);
if (!r) r = InstructionOnly(b, l + 1); if (!r) r = Instruction(b, l + 1);
return r; return r;
} }
@ -698,27 +688,18 @@ public class M68kParser implements PsiParser, LightPsiParser {
} }
/* ********************************************************** */ /* ********************************************************** */
// Label (Instruction|PreprocessorDirective) // Label Instruction
static boolean LabelWithInstruction(PsiBuilder b, int l) { static boolean LabelWithInstruction(PsiBuilder b, int l) {
if (!recursion_guard_(b, l, "LabelWithInstruction")) return false; if (!recursion_guard_(b, l, "LabelWithInstruction")) return false;
if (!nextTokenIs(b, "", GLOBAL_LABEL_DEF, LOCAL_LABEL_DEF)) return false; if (!nextTokenIs(b, "", GLOBAL_LABEL_DEF, LOCAL_LABEL_DEF)) return false;
boolean r; boolean r;
Marker m = enter_section_(b); Marker m = enter_section_(b);
r = Label(b, l + 1); r = Label(b, l + 1);
r = r && LabelWithInstruction_1(b, l + 1); r = r && Instruction(b, l + 1);
exit_section_(b, m, null, r); exit_section_(b, m, null, r);
return 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? // LOCAL_LABEL_DEF COLON?
public static boolean LocalLabel(PsiBuilder b, int l) { public static boolean LocalLabel(PsiBuilder b, int l) {

View File

@ -10,7 +10,7 @@ class M68kFileElementType private constructor() : ILightStubFileElementType<PsiF
@JvmField @JvmField
val INSTANCE = M68kFileElementType() val INSTANCE = M68kFileElementType()
const val STUB_VERSION = 7 const val STUB_VERSION = 8
const val STUB_EXTERNAL_ID_PREFIX = "MC68000." const val STUB_EXTERNAL_ID_PREFIX = "MC68000."
const val EXTERNAL_ID = STUB_EXTERNAL_ID_PREFIX + "FILE" const val EXTERNAL_ID = STUB_EXTERNAL_ID_PREFIX + "FILE"
} }

View File

@ -19,7 +19,9 @@ object AssemblerDirectives {
"align", "even", "odd", "cnop", "long", "dphrase", "phrase", "qphrase", "align", "even", "odd", "cnop", "long", "dphrase", "phrase", "qphrase",
"cargs", "comm", "comment", "cargs", "comm", "comment",
"rsset", "clrfo", "clrso", "setfo", "setso" "rsset", "clrfo", "clrso", "setfo", "setso",
"rsreset", "rs.b", "rs.w", "rs.l"
) )
val plainDirectives: Set<String> = setOf( val plainDirectives: Set<String> = setOf(

View File

@ -0,0 +1,27 @@
package de.platon42.intellij.plugins.m68k.asm
import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.PlatformPatterns
import com.intellij.util.ProcessingContext
import de.platon42.intellij.plugins.m68k.M68kIcons
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kDirectiveCompletionContributor : CompletionContributor() {
companion object {
val DIRECTIVES =
listOf(AssemblerDirectives.dataDirectives, AssemblerDirectives.plainDirectives, AssemblerDirectives.otherDirectives.map(String::uppercase))
.flatten()
.toSortedSet()
.map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(M68kIcons.MNEMONIC), 1.5) }
}
init {
extend(CompletionType.BASIC, PlatformPatterns.psiElement(M68kTypes.MACRO_INVOCATION), object : CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
resultSet.addAllElements(DIRECTIVES)
}
})
}
}

View File

@ -294,7 +294,7 @@ object M68kIsa {
AllowedAdrMode( AllowedAdrMode(
setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, modInfo = RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("C****") setOf(AddressMode.IMMEDIATE_DATA), ALL_EXCEPT_AREG_IMMEDIATE_AND_PC_REL, modInfo = RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("C****")
), ),
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), AREG_ONLY, size = OP_SIZE_WL, modInfo = RWM_MODIFY_OP2_L, affectedCc = cc("C****")) AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), AREG_ONLY, size = OP_SIZE_WL, modInfo = RWM_MODIFY_OP2_L)
) )
private val ADDX_SUBX_MODES = listOf( private val ADDX_SUBX_MODES = listOf(
@ -307,7 +307,7 @@ object M68kIsa {
) )
) )
private val ASD_LSD_MODES = listOf( private val ASL_MODES = listOf(
AllowedAdrMode(DREG_ONLY, DREG_ONLY, modInfo = RWM_READ_OP1_OPSIZE or RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("*****")), AllowedAdrMode(DREG_ONLY, DREG_ONLY, modInfo = RWM_READ_OP1_OPSIZE or RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("*****")),
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), DREG_ONLY, modInfo = RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("*****")), AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), DREG_ONLY, modInfo = RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("*****")),
AllowedAdrMode(INDIRECT_MODES, null, size = OP_SIZE_W, modInfo = RWM_MODIFY_OP1_OPSIZE, affectedCc = cc("*****")), AllowedAdrMode(INDIRECT_MODES, null, size = OP_SIZE_W, modInfo = RWM_MODIFY_OP1_OPSIZE, affectedCc = cc("*****")),
@ -315,6 +315,14 @@ object M68kIsa {
AllowedAdrMode(DREG_ONLY, null, modInfo = RWM_MODIFY_OP1_OPSIZE, affectedCc = cc("*****")) AllowedAdrMode(DREG_ONLY, null, modInfo = RWM_MODIFY_OP1_OPSIZE, affectedCc = cc("*****"))
) )
private val ASR_LSD_MODES = listOf(
AllowedAdrMode(DREG_ONLY, DREG_ONLY, modInfo = RWM_READ_OP1_OPSIZE or RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("***0*")),
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), DREG_ONLY, modInfo = RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("***0*")),
AllowedAdrMode(INDIRECT_MODES, null, size = OP_SIZE_W, modInfo = RWM_MODIFY_OP1_OPSIZE, affectedCc = cc("***0*")),
// not an official address mode, but supported by assembler (implicit #1)
AllowedAdrMode(DREG_ONLY, null, modInfo = RWM_MODIFY_OP1_OPSIZE, affectedCc = cc("***0*"))
)
private val ROD_MODES = listOf( private val ROD_MODES = listOf(
AllowedAdrMode(DREG_ONLY, DREG_ONLY, modInfo = RWM_READ_OP1_OPSIZE or RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("-**0*")), AllowedAdrMode(DREG_ONLY, DREG_ONLY, modInfo = RWM_READ_OP1_OPSIZE or RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("-**0*")),
AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), DREG_ONLY, modInfo = RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("-**0*")), AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), DREG_ONLY, modInfo = RWM_MODIFY_OP2_OPSIZE, affectedCc = cc("-**0*")),
@ -761,10 +769,10 @@ object M68kIsa {
), ),
// Shift and Rotate Instructions // Shift and Rotate Instructions
IsaData("asl", "Arithmetic Shift Left", modes = ASD_LSD_MODES), IsaData("asl", "Arithmetic Shift Left", modes = ASL_MODES),
IsaData("asr", "Arithmetic Shift Right", modes = ASD_LSD_MODES), IsaData("asr", "Arithmetic Shift Right", modes = ASR_LSD_MODES),
IsaData("lsl", "Logical Shift Left", modes = ASD_LSD_MODES), IsaData("lsl", "Logical Shift Left", modes = ASR_LSD_MODES),
IsaData("lsr", "Logical Shift Right", modes = ASD_LSD_MODES), IsaData("lsr", "Logical Shift Right", modes = ASR_LSD_MODES),
IsaData("rol", "Rotate Left", modes = ROD_MODES), IsaData("rol", "Rotate Left", modes = ROD_MODES),
IsaData("ror", "Rotate Right", modes = ROD_MODES), IsaData("ror", "Rotate Right", modes = ROD_MODES),
IsaData("roxl", "Rotate with Extend Left", modes = ROXD_MODES), IsaData("roxl", "Rotate with Extend Left", modes = ROXD_MODES),
@ -1066,12 +1074,14 @@ object M68kIsa {
), ),
IsaData("reset", "Reset External Devices", machine = ALL_MACHINES, isPrivileged = true, hasOps = false, modes = NO_OPS_UNSIZED), IsaData("reset", "Reset External Devices", machine = ALL_MACHINES, isPrivileged = true, hasOps = false, modes = NO_OPS_UNSIZED),
IsaData( IsaData(
"rte", "Return from Exception", "rte", "Return from Exception",
machine = ALL_MACHINES, isPrivileged = true, hasOps = false, machine = ALL_MACHINES, isPrivileged = true, hasOps = false,
modes = listOf(AllowedAdrMode(size = OP_UNSIZED, modInfo = RWM_MODIFY_STACK)), modes = listOf(AllowedAdrMode(size = OP_UNSIZED, modInfo = RWM_MODIFY_STACK)),
changesControlFlow = true changesControlFlow = true
), ),
IsaData( IsaData(
"stop", "Stop", "stop", "Stop",
machine = ALL_MACHINES, isPrivileged = true, machine = ALL_MACHINES, isPrivileged = true,
@ -1087,6 +1097,7 @@ object M68kIsa {
), ),
IsaData("illegal", "Take Illegal Instruction Trap", machine = ALL_MACHINES, hasOps = false, modes = NO_OPS_UNSIZED, changesControlFlow = true), IsaData("illegal", "Take Illegal Instruction Trap", machine = ALL_MACHINES, hasOps = false, modes = NO_OPS_UNSIZED, changesControlFlow = true),
IsaData( IsaData(
"trap", "trap",
"Trap", "Trap",
@ -1195,8 +1206,7 @@ object M68kIsa {
null null
} }
private private val mnemonicLookupMap = isaData.asSequence()
val mnemonicLookupMap = isaData.asSequence()
.flatMap { .flatMap {
(if (it.conditionCodes.isEmpty()) it.altMnemonics.plus(it.mnemonic) else it.altMnemonics.plus(it.conditionCodes (if (it.conditionCodes.isEmpty()) it.altMnemonics.plus(it.mnemonic) else it.altMnemonics.plus(it.conditionCodes
.map { cc -> .map { cc ->

View File

@ -0,0 +1,67 @@
package de.platon42.intellij.plugins.m68k.folding
import com.intellij.lang.ASTNode
import com.intellij.lang.folding.FoldingBuilderEx
import com.intellij.lang.folding.FoldingDescriptor
import com.intellij.openapi.editor.Document
import com.intellij.openapi.project.DumbAware
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.suggested.endOffset
import com.intellij.refactoring.suggested.startOffset
import de.platon42.intellij.plugins.m68k.psi.M68kFile
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kStatement
import de.platon42.intellij.plugins.m68k.psi.utils.M68kPsiWalkUtil.getBeginningOfRelatedComment
import de.platon42.intellij.plugins.m68k.psi.utils.M68kPsiWalkUtil.isSignificantLine
class M68kFoldingBuilder : FoldingBuilderEx(), DumbAware {
override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array<FoldingDescriptor> {
if (root !is M68kFile) return FoldingDescriptor.EMPTY
val descriptors = ArrayList<FoldingDescriptor>()
var lineElement = root.firstChild
var foldingOpen = false
var foldingStart: PsiElement? = null
var foldingName: String? = null
var lastStatement = lineElement as? M68kStatement
while (lineElement != null) {
if (lineElement is M68kMacroDefinition) {
val fd = FoldingDescriptor(lineElement, lineElement.startOffset, lineElement.endOffset, null, "[[[ MACRO " + lineElement.name!! + " ]]]")
descriptors.add(fd)
}
if (lineElement is M68kStatement) {
val label = lineElement.globalLabel
if (label != null) {
foldingOpen = true
foldingStart = getBeginningOfRelatedComment(lineElement)
foldingName = "[[[ ${label.name} ]]]"
}
lastStatement = lineElement
}
lineElement = PsiTreeUtil.skipWhitespacesAndCommentsForward(lineElement)
if (foldingOpen) {
val stopIt = (lineElement == null) || isSignificantLine(lineElement)
if (stopIt) {
val fd = FoldingDescriptor(
foldingStart!!.parent!!,
foldingStart.startOffsetInParent, lastStatement!!.textRangeInParent.endOffset,
null, foldingName!!
)
descriptors.add(fd)
foldingOpen = false
}
}
}
return descriptors.toArray(FoldingDescriptor.EMPTY)
}
override fun getPlaceholderText(node: ASTNode): String? {
return "..."
}
override fun isCollapsedByDefault(node: ASTNode): Boolean {
return false
}
}

View File

@ -0,0 +1,23 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Alignment
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.formatting.Wrap
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmAssignmentBlock(
node: ASTNode, wrap: Wrap?, alignment: Alignment?,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, wrap, alignment) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return Spacing.getReadOnlySpacing()
}
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,62 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Alignment
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.formatting.Wrap
import com.intellij.lang.ASTNode
import com.intellij.psi.TokenType
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kAsmBlock(
node: ASTNode, wrap: Wrap?, alignment: Alignment?,
val column: Int,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, wrap, alignment) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child1 is M68kAsmBlock && child2 is M68kAsmBlock) {
val columnDiff = child2.column - child1.column
if (columnDiff > 0) {
var minSpaces = columnDiff * codeStyleSettings.indentOptions.INDENT_SIZE - child1.node.textLength
while (minSpaces < 1) {
minSpaces += codeStyleSettings.indentOptions.INDENT_SIZE
}
return Spacing.createSpacing(minSpaces, minSpaces, 0, false, 0)
}
}
return null
}
override fun isLeaf() = (node.firstChildNode == null)
override fun buildChildren(): List<Block> {
val subBlocks = ArrayList<Block>()
if (myNode.elementType == M68kTypes.ASM_OP) {
return subBlocks
}
var child = myNode.firstChildNode
var newColumn = column
while (child != null) {
if (child.elementType != TokenType.WHITE_SPACE) {
subBlocks.add(
M68kAsmBlock(
child,
null,
null,
newColumn,
codeStyleSettings
)
)
if (child.elementType == M68kTypes.ASM_OP) {
newColumn += 2
}
}
child = child.treeNext
}
return subBlocks
}
}

View File

@ -0,0 +1,7 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CustomCodeStyleSettings
class M68kAsmCodeStyleSettings(container: CodeStyleSettings) : CustomCodeStyleSettings("MC68000AsmCodeStyleSettings", container) {
}

View File

@ -0,0 +1,31 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.application.options.CodeStyleAbstractConfigurable
import com.intellij.application.options.CodeStyleAbstractPanel
import com.intellij.application.options.TabbedLanguageCodeStylePanel
import com.intellij.psi.codeStyle.CodeStyleConfigurable
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CodeStyleSettingsProvider
import com.intellij.psi.codeStyle.CustomCodeStyleSettings
import de.platon42.intellij.plugins.m68k.MC68000Language
class M68kAsmCodeStyleSettingsProvider : CodeStyleSettingsProvider() {
override fun createCustomSettings(settings: CodeStyleSettings): CustomCodeStyleSettings {
return M68kAsmCodeStyleSettings(settings)
}
override fun createConfigurable(settings: CodeStyleSettings, modelSettings: CodeStyleSettings): CodeStyleConfigurable {
return object : CodeStyleAbstractConfigurable(settings, modelSettings, configurableDisplayName) {
override fun createPanel(settings: CodeStyleSettings): CodeStyleAbstractPanel {
return M68kAsmCodeStyleMainPanel(currentSettings, settings)
}
}
}
override fun getConfigurableDisplayName() = "M68k"
private class M68kAsmCodeStyleMainPanel(currentSettings: CodeStyleSettings, settings: CodeStyleSettings) :
TabbedLanguageCodeStylePanel(MC68000Language.INSTANCE, currentSettings, settings)
}

View File

@ -0,0 +1,21 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmCommentBlock(
node: ASTNode,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, null, null) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return Spacing.getReadOnlySpacing()
}
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,14 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.lang.ASTNode
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmEolBlock(node: ASTNode) : AbstractBlock(node, null, null) {
override fun getSpacing(child1: Block?, child2: Block) = null
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,19 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.FormattingContext
import com.intellij.formatting.FormattingModel
import com.intellij.formatting.FormattingModelBuilder
import com.intellij.formatting.FormattingModelProvider
class M68kAsmFormattingModelBuilder : FormattingModelBuilder {
override fun createModel(formattingContext: FormattingContext): FormattingModel {
val codeStyleSettings = formattingContext.codeStyleSettings
return FormattingModelProvider.createFormattingModelForPsiFile(
formattingContext.containingFile,
M68kAsmRootBlock(formattingContext.node, codeStyleSettings),
codeStyleSettings
)
}
}

View File

@ -0,0 +1,23 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Alignment
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.formatting.Wrap
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmLabelBlock(
node: ASTNode, wrap: Wrap?, alignment: Alignment?,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, wrap, alignment) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return Spacing.getReadOnlySpacing()
}
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,21 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.formatting.Spacing
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
class M68kAsmMacroDefBlock(
node: ASTNode,
private val codeStyleSettings: CodeStyleSettings
) : AbstractBlock(node, null, null) {
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return Spacing.getReadOnlySpacing()
}
override fun isLeaf() = true
override fun buildChildren() = emptyList<Block>()
}

View File

@ -0,0 +1,70 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.formatting.Indent
import com.intellij.formatting.Spacing
import com.intellij.lang.ASTNode
import com.intellij.psi.PsiComment
import com.intellij.psi.TokenType
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kStatement
import de.platon42.intellij.plugins.m68k.psi.M68kTypes
class M68kAsmRootBlock(node: ASTNode, private val codeStyleSettings: CodeStyleSettings) : AbstractBlock(node, null, null) {
override fun getIndent(): Indent? {
return Indent.getAbsoluteNoneIndent()
}
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child2 is M68kAsmEolBlock) {
return Spacing.createSpacing(0, 0, 0, false, 0)
//return null
}
if (child2 is M68kAsmMacroDefBlock) {
return child2.getSpacing(child1, child2)
}
if (child2 is M68kAsmCommentBlock) {
if (child1 is M68kAsmStatementBlock) {
val indentSize = codeStyleSettings.indentOptions.INDENT_SIZE
val oddIdent = indentSize - (child1.node.textLength % indentSize)
return Spacing.createSpacing(oddIdent, Integer.MAX_VALUE, 0, false, 0)
} else {
return Spacing.getReadOnlySpacing()
}
}
if (child2.subBlocks.isNotEmpty()) {
return child2.getSpacing(child1, child2.subBlocks.first())
}
return null
}
override fun isLeaf(): Boolean {
return false
}
override fun buildChildren(): List<Block> {
val subBlocks = ArrayList<Block>()
var child = myNode.firstChildNode
while (child != null) {
if (child.elementType == M68kTypes.EOL) {
subBlocks.add(M68kAsmEolBlock(child))
} else if (child.elementType != TokenType.WHITE_SPACE) {
if (child.psi is M68kStatement) {
subBlocks.add(M68kAsmStatementBlock(child, codeStyleSettings))
} else if (child.psi is M68kMacroDefinition) {
subBlocks.add(M68kAsmMacroDefBlock(child, codeStyleSettings))
} else if (child.psi is PsiComment) {
subBlocks.add(M68kAsmCommentBlock(child, codeStyleSettings))
} else {
subBlocks.add(M68kAsmBlock(child, null, null, 0, codeStyleSettings))
}
}
child = child.treeNext
}
return subBlocks
}
}

View File

@ -0,0 +1,74 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.formatting.Block
import com.intellij.formatting.Indent
import com.intellij.formatting.Spacing
import com.intellij.lang.ASTNode
import com.intellij.psi.TokenType
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.common.AbstractBlock
import de.platon42.intellij.plugins.m68k.psi.*
class M68kAsmStatementBlock(node: ASTNode, private val codeStyleSettings: CodeStyleSettings) :
AbstractBlock(node, null, null) {
override fun getIndent(): Indent? {
val statement = myNode.psi as M68kStatement
if (((statement.asmInstruction != null) || (statement.asmInstruction != null) || (statement.preprocessorDirective != null)
|| (statement.macroCall != null))
&& ((statement.localLabel == null) && (statement.globalLabel == null))
) {
return null
} else {
return Indent.getAbsoluteNoneIndent()
}
}
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child2 is M68kAsmBlock) {
val indentSize = codeStyleSettings.indentOptions.INDENT_SIZE * child2.column
if (child1 is M68kAsmEolBlock || child1 is M68kAsmCommentBlock) {
return Spacing.createSpacing(indentSize, indentSize, 0, true, 0)
}
if (child1 is M68kAsmLabelBlock) {
val spacesLeft = indentSize - child1.node.textLength
if (spacesLeft <= 0) {
return Spacing.createSpacing(0, 0, 1, true, 0)
} else {
return Spacing.createSpacing(spacesLeft, spacesLeft, 0, true, 0)
}
}
return Spacing.createSpacing(indentSize, indentSize, 0, true, 0)
}
if (child2 is M68kAsmLabelBlock || child2 is M68kAsmAssignmentBlock) {
return Spacing.createSpacing(0, 0, 0, true, 0)
}
return null
}
override fun isLeaf() = false
override fun buildChildren(): List<Block> {
val subBlocks = ArrayList<Block>()
var child = myNode.firstChildNode
while (child != null) {
if (child.elementType != TokenType.WHITE_SPACE) {
val element = child.psi
when (element) {
is M68kAssignment -> subBlocks.add(M68kAsmAssignmentBlock(child, null, null, codeStyleSettings))
is M68kAsmInstruction, is M68kPreprocessorDirective, is M68kMacroCall ->
subBlocks.add(M68kAsmBlock(child, null, null, 2, codeStyleSettings))
is M68kGlobalLabel, is M68kLocalLabel ->
subBlocks.add(M68kAsmLabelBlock(child, null, null, codeStyleSettings))
else -> subBlocks.add(M68kAsmBlock(child, null, null, 1, codeStyleSettings))
}
}
child = child.treeNext
}
return subBlocks
}
}

View File

@ -0,0 +1,41 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider
import de.platon42.intellij.plugins.m68k.MC68000Language
class M68kLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvider() {
override fun getLanguage() = MC68000Language.INSTANCE
override fun getCodeSample(settingsType: SettingsType) = """; This is an example assembly language program
PIC_HEIGHT = 256
include "../includes/hardware/custom.i"
BLTHOGON MACRO ; macro definition
move.w #DMAF_SETCLR|DMAF_BLITHOG,dmacon(a5) ; hog!
ENDM
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
.loop move.l d0,(a0)+ ; local label
dbra d7,.loop
POPM
.skip rts
irq: move.l a0,-(sp)
move usp,a0
move.l a0,${'$'}400.w
move.l (sp)+,a0
rte
hello: dc.b 'Hello World!',10,0
even
dc.w *-hello ; length of string
"""
}

View File

@ -29,7 +29,7 @@ class M68kUnresolvedReferenceInspection : AbstractBaseM68kLocalInspectionTool()
} }
override fun visitSymbolReference(symbolReference: M68kSymbolReference) { override fun visitSymbolReference(symbolReference: M68kSymbolReference) {
val references = symbolReference.references ?: return val references = symbolReference.references
if (references.isEmpty()) return if (references.isEmpty()) return
val resolve = references.mapNotNull { it as? PsiPolyVariantReference } val resolve = references.mapNotNull { it as? PsiPolyVariantReference }
.firstNotNullOfOrNull { it.multiResolve(false).ifEmpty { null } } .firstNotNullOfOrNull { it.multiResolve(false).ifEmpty { null } }

View File

@ -136,11 +136,10 @@ SymbolDefinition ::= SYMBOLDEF {
Assignment ::= SymbolDefinition COLON? (OP_ASSIGN|EQU) expr Assignment ::= SymbolDefinition COLON? (OP_ASSIGN|EQU) expr
private LabelInsts ::= LabelWithInstruction | LabelOnly | InstructionOnly private LabelInsts ::= LabelWithInstruction | LabelOnly | Instruction
private LabelOnly ::= Label private LabelOnly ::= Label
private LabelWithInstruction ::= Label (Instruction|PreprocessorDirective) private LabelWithInstruction ::= Label Instruction
private InstructionOnly ::= (Instruction|PreprocessorDirective)
LocalLabel ::= LOCAL_LABEL_DEF COLON? { LocalLabel ::= LOCAL_LABEL_DEF COLON? {
name = "local label" name = "local label"
@ -199,7 +198,7 @@ MacroCall ::= MACRO_INVOCATION PlainOperands? {
} }
AsmInstruction ::= AsmOp AsmOperands? AsmInstruction ::= AsmOp AsmOperands?
private Instruction ::= AsmInstruction | MacroCall private Instruction ::= AsmInstruction | MacroCall | PreprocessorDirective
//external Instruction ::= parseMacroCallOrAsmInstruction //external Instruction ::= parseMacroCallOrAsmInstruction
private AsmOperands ::= AddressingMode (SEPARATOR AddressingMode)? private AsmOperands ::= AddressingMode (SEPARATOR AddressingMode)?

View File

@ -0,0 +1,75 @@
package de.platon42.intellij.plugins.m68k.navigation
import com.intellij.ide.navigationToolbar.AbstractNavBarModelExtension
import com.intellij.ide.ui.UISettings
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import de.platon42.intellij.plugins.m68k.M68kIcons
import de.platon42.intellij.plugins.m68k.MC68000Language
import de.platon42.intellij.plugins.m68k.psi.*
import de.platon42.intellij.plugins.m68k.psi.utils.M68kPsiWalkUtil.findStatementForElement
import org.jetbrains.annotations.Nullable
import javax.swing.Icon
class M68kStructureAwareNavbar : AbstractNavBarModelExtension() {
override fun getLeafElement(dataContext: DataContext): PsiElement? {
if (UISettings.getInstance().showMembersInNavigationBar) {
val psiFile = CommonDataKeys.PSI_FILE.getData(dataContext)
val editor = CommonDataKeys.EDITOR.getData(dataContext)
if (psiFile == null || !psiFile.isValid || editor == null) return null
val psiElement = psiFile.findElementAt(editor.caretModel.offset)
if (isAcceptableLanguage(psiElement)) {
try {
var statement = findStatementForElement(psiElement!!) ?: return null
do {
if (statement.localLabel != null) return statement.localLabel
if (statement.globalLabel != null) return statement.globalLabel
statement = PsiTreeUtil.getPrevSiblingOfType(statement, M68kStatement::class.java) ?: return null
} while (true)
} catch (ignored: IndexNotReadyException) {
}
}
}
return null
}
private fun isAcceptableLanguage(psiElement: @Nullable PsiElement?) = psiElement?.language == MC68000Language.INSTANCE
override fun getPresentableText(obj: Any?): String? {
return when (obj) {
is M68kFile -> obj.name
is M68kGlobalLabel -> obj.name
is M68kLocalLabel -> obj.name
is M68kSymbolDefinition -> obj.name
is M68kMacroDefinition -> obj.macroNameDefinition.text
else -> null
}
}
override fun getParent(psiElement: PsiElement): PsiElement? {
if (!isAcceptableLanguage(psiElement)) return null
var statement = findStatementForElement(psiElement) ?: return null
if (statement.localLabel != null) {
do {
if (statement.globalLabel != null) return statement.globalLabel
statement = PsiTreeUtil.getPrevSiblingOfType(statement, M68kStatement::class.java) ?: return null
} while (true)
}
return psiElement.containingFile
}
override fun getIcon(obj: Any?): Icon? {
return when (obj) {
is M68kFile -> M68kIcons.FILE
is M68kGlobalLabel -> M68kIcons.GLOBAL_LABEL
is M68kLocalLabel -> M68kIcons.LOCAL_LABEL
is M68kSymbolDefinition -> M68kIcons.SYMBOL_DEF
is M68kMacroDefinition -> M68kIcons.MACRO_DEF
else -> null
}
}
}

View File

@ -105,7 +105,7 @@ object M68kPsiImplUtil {
// OperandSize // OperandSize
@JvmStatic @JvmStatic
fun getSize(element: M68kOperandSize): Int = fun getSize(element: M68kOperandSize): Int =
when (element.text) { when (element.text?.lowercase()) {
null -> OP_UNSIZED null -> OP_UNSIZED
".w" -> OP_SIZE_W ".w" -> OP_SIZE_W
".l" -> OP_SIZE_L ".l" -> OP_SIZE_L

View File

@ -2,10 +2,13 @@ package de.platon42.intellij.plugins.m68k.psi.utils
import com.intellij.psi.PsiComment import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.SmartList import com.intellij.util.SmartList
import com.intellij.util.containers.addIfNotNull import com.intellij.util.containers.addIfNotNull
import de.platon42.intellij.plugins.m68k.psi.M68kFile
import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition import de.platon42.intellij.plugins.m68k.psi.M68kMacroDefinition
import de.platon42.intellij.plugins.m68k.psi.M68kStatement
object M68kPsiWalkUtil { object M68kPsiWalkUtil {
@ -28,4 +31,37 @@ object M68kPsiWalkUtil {
return comments.reversed() return comments.reversed()
} }
fun getBeginningOfRelatedComment(lineElement: PsiElement): PsiElement {
// go back to catch comments that are not more than one empty line away
var relStart = lineElement
var prevLine = relStart.prevSibling ?: return lineElement
var eolCount = 2
do {
if (prevLine is PsiComment) {
relStart = prevLine
eolCount = 1
} else if (prevLine is PsiWhiteSpace) {
if (--eolCount < 0) break
} else {
break
}
prevLine = prevLine.prevSibling ?: break
} while (true)
return relStart
}
fun isSignificantLine(element: PsiElement) = when (element) {
is M68kStatement -> (element.assignment != null) || (element.globalLabel != null)
is M68kMacroDefinition -> true
else -> false
}
fun findStatementForElement(psiElement: PsiElement): M68kStatement? {
if (psiElement is M68kStatement) return psiElement
if (psiElement.parent is M68kFile) {
return PsiTreeUtil.getPrevSiblingOfType(psiElement, M68kStatement::class.java)
}
return PsiTreeUtil.getParentOfType(psiElement, M68kStatement::class.java);
}
} }

View File

@ -32,7 +32,7 @@ class M68kLocalLabelDefCompletionContributor : CompletionContributor() {
} }
referencedLocalLabels.removeAll(definedLocalLabels) referencedLocalLabels.removeAll(definedLocalLabels)
resultSet.addAllElements( resultSet.addAllElements(
if (parameters.originalPosition?.text == ".") { if (parameters.originalPosition?.text?.startsWith(".") == true) {
referencedLocalLabels.map { LookupElementBuilder.create(it.removePrefix(".")) } referencedLocalLabels.map { LookupElementBuilder.create(it.removePrefix(".")) }
} else { } else {
referencedLocalLabels.map(LookupElementBuilder::create) referencedLocalLabels.map(LookupElementBuilder::create)

View File

@ -1,11 +1,13 @@
package de.platon42.intellij.plugins.m68k.syntax package de.platon42.intellij.plugins.m68k.syntax
import com.intellij.codeHighlighting.RainbowHighlighter
import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.fileTypes.SyntaxHighlighter import com.intellij.openapi.fileTypes.SyntaxHighlighter
import com.intellij.openapi.options.colors.AttributesDescriptor import com.intellij.openapi.options.colors.AttributesDescriptor
import com.intellij.openapi.options.colors.ColorDescriptor import com.intellij.openapi.options.colors.ColorDescriptor
import com.intellij.openapi.options.colors.ColorSettingsPage import com.intellij.openapi.options.colors.RainbowColorSettingsPage
import de.platon42.intellij.plugins.m68k.M68kIcons.FILE import de.platon42.intellij.plugins.m68k.M68kIcons.FILE
import de.platon42.intellij.plugins.m68k.MC68000Language
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.AREG import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.AREG
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.BAD_CHARACTER import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.BAD_CHARACTER
import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.COLON import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.COLON
@ -34,7 +36,9 @@ import de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighter.Companion.
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import javax.swing.Icon import javax.swing.Icon
class M68kColorSettingsPage : ColorSettingsPage { class M68kColorSettingsPage : RainbowColorSettingsPage {
override fun getLanguage() = MC68000Language.INSTANCE
override fun getIcon(): Icon { override fun getIcon(): Icon {
return FILE return FILE
@ -49,6 +53,8 @@ class M68kColorSettingsPage : ColorSettingsPage {
return """; This is an example assembly language program return """; This is an example assembly language program
PIC_HEIGHT = 256 PIC_HEIGHT = 256
* Semantic highlighting is available for registers and local labels
include "../includes/hardware/custom.i" include "../includes/hardware/custom.i"
BLTHOGON MACRO ; macro definition BLTHOGON MACRO ; macro definition
@ -80,23 +86,21 @@ hello: dc.b 'Hello World!',10,0
""" """
} }
override fun getAdditionalHighlightingTagToDescriptorMap(): Map<String, TextAttributesKey>? { override fun getAdditionalHighlightingTagToDescriptorMap(): Map<String, TextAttributesKey> {
return null return RainbowHighlighter.createRainbowHLM()
} }
override fun getAttributeDescriptors(): Array<AttributesDescriptor> { override fun isRainbowType(type: TextAttributesKey) = RAINBOW_TYPES.contains(type)
return DESCRIPTORS
}
override fun getColorDescriptors(): Array<ColorDescriptor> { override fun getAttributeDescriptors() = DESCRIPTORS
return ColorDescriptor.EMPTY_ARRAY
}
override fun getDisplayName(): String { override fun getColorDescriptors() = ColorDescriptor.EMPTY_ARRAY
return "M68k Assembly"
} override fun getDisplayName() = "M68k Assembly"
companion object { companion object {
private val RAINBOW_TYPES = setOf(AREG, DREG, LOCAL_LABEL)
private val DESCRIPTORS = arrayOf( private val DESCRIPTORS = arrayOf(
AttributesDescriptor("Global labels", GLOBAL_LABEL), AttributesDescriptor("Global labels", GLOBAL_LABEL),
AttributesDescriptor("Local labels", LOCAL_LABEL), AttributesDescriptor("Local labels", LOCAL_LABEL),

View File

@ -0,0 +1,28 @@
package de.platon42.intellij.plugins.m68k.syntax
import com.intellij.codeInsight.daemon.RainbowVisitor
import com.intellij.codeInsight.daemon.impl.HighlightVisitor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import de.platon42.intellij.plugins.m68k.psi.M68kAddressRegister
import de.platon42.intellij.plugins.m68k.psi.M68kDataRegister
import de.platon42.intellij.plugins.m68k.psi.M68kFile
import de.platon42.intellij.plugins.m68k.psi.M68kLocalLabel
class M68kRainbowVisitor : RainbowVisitor() {
override fun suitableForFile(file: PsiFile): Boolean = file is M68kFile
override fun visit(element: PsiElement) {
when (element) {
is M68kAddressRegister -> addInfo(getInfo(element.containingFile, element, element.text, M68kSyntaxHighlighter.AREG))
is M68kDataRegister -> addInfo(getInfo(element.containingFile, element, element.text, M68kSyntaxHighlighter.DREG))
// is M68kGlobalLabel -> addInfo(getInfo(element.containingFile, element, element.text, M68kSyntaxHighlighter.GLOBAL_LABEL))
is M68kLocalLabel -> addInfo(getInfo(element.containingFile, element, element.text, M68kSyntaxHighlighter.LOCAL_LABEL))
// is M68kMacroCall -> addInfo(getInfo(element.containingFile, element.firstChild, element.macroName, M68kSyntaxHighlighter.MACRO_CALL))
}
}
override fun clone(): HighlightVisitor = M68kRainbowVisitor()
}

View File

@ -1,14 +1,14 @@
<idea-plugin> <idea-plugin>
<id>de.platon42.m68k</id> <id>de.platon42.m68k</id>
<name>MC68000 Assembly Language Support</name> <name>MC68000 Assembly Language Support</name>
<vendor email="chrisly@platon42.de" url="https://github.com/chrisly42/mc68000-asm-plugin">Chris 'platon42' Hodges <vendor email="chrisly@platon42.de" url="https://git.platon42.de/chrisly42/mc68000-asm-plugin">Chris 'platon42' Hodges
</vendor> </vendor>
<description><![CDATA[ <description><![CDATA[
MC68000 Assembly Language Plugin adds language support for Motorola 68000 (M68k) assembly language files (asm). MC68000 Assembly Language Plugin adds language support for Motorola 68000 (M68k) assembly language files (asm).
It provides syntax highlighting and refactoring possibilities among other things. It provides syntax highlighting and refactoring possibilities among other things.
<p> <p>
<a href="https://github.com/chrisly42/mc68000-asm-plugin/blob/main/README.md">Full documentation here...</a> <a href="https://git.platon42.de/chrisly42/mc68000-asm-plugin/blob/main/README.md">Full documentation here...</a>
]]></description> ]]></description>
<idea-version since-build="203.5981.166"/> <idea-version since-build="203.5981.166"/>
@ -21,8 +21,17 @@
implementationClass="de.platon42.intellij.plugins.m68k.parser.M68kParserDefinition"/> implementationClass="de.platon42.intellij.plugins.m68k.parser.M68kParserDefinition"/>
<lang.syntaxHighlighterFactory language="MC68000" <lang.syntaxHighlighterFactory language="MC68000"
implementationClass="de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighterFactory"/> implementationClass="de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighterFactory"/>
<lang.foldingBuilder language="MC68000"
implementationClass="de.platon42.intellij.plugins.m68k.folding.M68kFoldingBuilder"/>
<!--lang.formatter language="MC68000"
implementationClass="de.platon42.intellij.plugins.m68k.formatter.M68kAsmFormattingModelBuilder"/-->
<codeStyleSettingsProvider implementation="de.platon42.intellij.plugins.m68k.formatter.M68kAsmCodeStyleSettingsProvider"/>
<langCodeStyleSettingsProvider implementation="de.platon42.intellij.plugins.m68k.formatter.M68kLanguageCodeStyleSettingsProvider"/>
<navbar implementation="de.platon42.intellij.plugins.m68k.navigation.M68kStructureAwareNavbar"/>
<highlightVisitor implementation="de.platon42.intellij.plugins.m68k.syntax.M68kRainbowVisitor"/>
<colorSettingsPage implementation="de.platon42.intellij.plugins.m68k.syntax.M68kColorSettingsPage"/> <colorSettingsPage implementation="de.platon42.intellij.plugins.m68k.syntax.M68kColorSettingsPage"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.asm.M68kMnemonicCompletionContributor"/> <completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.asm.M68kMnemonicCompletionContributor"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.asm.M68kDirectiveCompletionContributor"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kGlobalLabelSymbolCompletionContributor"/> <completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kGlobalLabelSymbolCompletionContributor"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kLocalLabelDefCompletionContributor"/> <completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kLocalLabelDefCompletionContributor"/>
<completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kMacroCallCompletionContributor"/> <completion.contributor language="MC68000" implementationClass="de.platon42.intellij.plugins.m68k.refs.M68kMacroCallCompletionContributor"/>

View File

@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.extension.*; import org.junit.jupiter.api.extension.*;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.runner.Description;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -34,8 +35,11 @@ public class LightCodeInsightExtension implements ParameterResolver, AfterTestEx
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
LightCodeInsightFixtureTestCaseWrapper testCase = getWrapper(extensionContext); LightCodeInsightFixtureTestCaseWrapper testCase = getWrapper(extensionContext);
Parameter parameter = parameterContext.getParameter(); Parameter parameter = parameterContext.getParameter();
if (parameter.isAnnotationPresent(MyFixture.class)) return testCase.getMyFixture(); if (parameter.isAnnotationPresent(MyFixture.class)) {
else if (parameter.isAnnotationPresent(MyTestCase.class)) return testCase; return testCase.getMyFixture();
} else if (parameter.isAnnotationPresent(MyTestCase.class)) {
return testCase;
}
return null; return null;
} }
@ -68,14 +72,15 @@ public class LightCodeInsightExtension implements ParameterResolver, AfterTestEx
@Override @Override
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable { public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
Throwable[] throwables = new Throwable[1]; Throwable[] throwables = new Throwable[1];
Description testDescription = Description.createTestDescription(extensionContext.getRequiredTestClass(), getWrapper(extensionContext).getName());
Runnable runnable = () -> { Runnable runnable = () -> {
try { try {
TestLoggerFactory.onTestStarted(); TestLoggerFactory.onTestStarted();
invocation.proceed(); invocation.proceed();
TestLoggerFactory.onTestFinished(true); TestLoggerFactory.onTestFinished(true, testDescription);
} catch (Throwable e) { } catch (Throwable e) {
TestLoggerFactory.onTestFinished(false); TestLoggerFactory.onTestFinished(false, testDescription);
throwables[0] = e; throwables[0] = e;
} }
}; };

View File

@ -6,14 +6,13 @@ import com.intellij.mock.MockProjectEx;
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Disposer;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.testFramework.EdtTestUtilKt;
import com.intellij.testFramework.ParsingTestCase; import com.intellij.testFramework.ParsingTestCase;
import com.intellij.testFramework.TestLoggerFactory; import com.intellij.testFramework.TestLoggerFactory;
import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.extension.*; import org.junit.jupiter.api.extension.*;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace; import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.runner.Description;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
@ -81,37 +80,22 @@ public class ParsingTestExtension implements ParameterResolver, AfterTestExecuti
@Override @Override
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable { public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
Throwable[] throwables = new Throwable[1]; Throwable[] throwables = new Throwable[1];
Description testDescription = Description.createTestDescription(extensionContext.getRequiredTestClass(), getWrapper(extensionContext).getName());
Runnable runnable = () -> {
try { try {
TestLoggerFactory.onTestStarted(); TestLoggerFactory.onTestStarted();
invocation.proceed(); invocation.proceed();
TestLoggerFactory.onTestFinished(true); TestLoggerFactory.onTestFinished(true, testDescription);
} catch (Throwable e) { } catch (Throwable e) {
TestLoggerFactory.onTestFinished(false); TestLoggerFactory.onTestFinished(false, testDescription);
throwables[0] = e; throwables[0] = e;
} }
};
invokeTestRunnable(runnable);
if (throwables[0] != null) { if (throwables[0] != null) {
throw throwables[0]; throw throwables[0];
} }
} }
private static void invokeTestRunnable(@NotNull Runnable runnable) {
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
if (policy != null && !policy.runInDispatchThread()) {
runnable.run();
} else {
EdtTestUtilKt.runInEdtAndWait(() -> {
runnable.run();
return null;
});
}
}
public interface IParsingTestCase { public interface IParsingTestCase {
MockProjectEx getProject(); MockProjectEx getProject();

View File

@ -0,0 +1,63 @@
package de.platon42.intellij.plugins.m68k.asm
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import de.platon42.intellij.jupiter.LightCodeInsightExtension
import de.platon42.intellij.jupiter.MyFixture
import de.platon42.intellij.plugins.m68k.AbstractM68kTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
@ExtendWith(LightCodeInsightExtension::class)
internal class M68kDirectiveCompletionContributorTest : AbstractM68kTest() {
@Test
internal fun completion_shows_plain_directive(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByText(
"completeme.asm", """
inc<caret>
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder("include", "incbin", "incdir")
}
@Test
internal fun completion_shows_other_directive(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByText(
"completeme.asm", """
IF<caret>
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder(
"IF",
"IFB",
"IFC",
"IFD",
"IFEQ",
"IFGE",
"IFGT",
"IFLE",
"IFLT",
"IFMACROD",
"IFMACROND",
"IFNB",
"IFNC",
"IFND",
"IFNE",
"ENDIF"
)
}
@Test
internal fun completion_shows_data_directives(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByText(
"completeme.asm", """
dc<caret>
"""
)
myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder("dc", "dc.b", "dc.w", "dc.l", "dcb", "dcb.b", "dcb.w", "dcb.l", "data_c")
}
}

View File

@ -30,7 +30,7 @@ label: <caret>
""" """
) )
myFixture.completeBasic() myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).hasSameElementsAs(M68kIsa.mnemonics) assertThat(myFixture.lookupElementStrings).containsAnyElementsOf(M68kIsa.mnemonics)
} }
@Test @Test
@ -41,6 +41,6 @@ label: <caret>
""" """
) )
myFixture.completeBasic() myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).hasSameElementsAs(M68kIsa.mnemonics) assertThat(myFixture.lookupElementStrings).containsAnyElementsOf(M68kIsa.mnemonics)
} }
} }

View File

@ -12,6 +12,7 @@ import org.junit.jupiter.api.extension.ExtendWith
abstract class AbstractDocumentationProviderTest : AbstractM68kTest() { abstract class AbstractDocumentationProviderTest : AbstractM68kTest() {
fun generateDocumentation(myFixture: CodeInsightTestFixture): String? { fun generateDocumentation(myFixture: CodeInsightTestFixture): String? {
// FIXME migrate to DocumentationTarget
val docElement = DocumentationManager.getInstance(myFixture.project).findTargetElement(myFixture.editor, myFixture.file) val docElement = DocumentationManager.getInstance(myFixture.project).findTargetElement(myFixture.editor, myFixture.file)
val provider = DocumentationManager.getProviderFromElement(docElement) val provider = DocumentationManager.getProviderFromElement(docElement)

View File

@ -0,0 +1,19 @@
package de.platon42.intellij.plugins.m68k.folding
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import de.platon42.intellij.jupiter.LightCodeInsightExtension
import de.platon42.intellij.jupiter.MyFixture
import de.platon42.intellij.jupiter.TestDataPath
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
@TestDataPath("src/test/resources/folding")
@ExtendWith(LightCodeInsightExtension::class)
internal class M68kFoldingBuilderTest {
@Test
internal fun check_documentation_for_a_symbol_definition(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.testFolding(myFixture.testDataPath + "/folding.asm")
}
}

View File

@ -0,0 +1,52 @@
package de.platon42.intellij.plugins.m68k.formatter
import com.intellij.application.options.CodeStyle
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import com.intellij.util.containers.ContainerUtil
import de.platon42.intellij.jupiter.LightCodeInsightExtension
import de.platon42.intellij.jupiter.MyFixture
import de.platon42.intellij.jupiter.TestDataPath
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
@TestDataPath("src/test/resources/formatting")
@ExtendWith(LightCodeInsightExtension::class)
internal class M68kAsmFormatterTest {
@Test
@Disabled
internal fun check_if_formatting_works_as_expected(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByFile("basic_before.asm")
val settings = CodeStyle.getLanguageSettings(myFixture.file)
settings.indentOptions?.INDENT_SIZE = 6
settings.indentOptions?.CONTINUATION_INDENT_SIZE = 9
WriteCommandAction.runWriteCommandAction(myFixture.project)
{
CodeStyleManager.getInstance(myFixture.project).reformatText(
myFixture.file,
ContainerUtil.newArrayList(myFixture.file.textRange)
)
}
myFixture.checkResultByFile("basic_after.asm")
}
@Test
internal fun check_formatting_for_mnemonics(@MyFixture myFixture: CodeInsightTestFixture) {
myFixture.configureByFile("mnemonics_before.asm")
val settings = CodeStyle.getLanguageSettings(myFixture.file)
settings.indentOptions?.INDENT_SIZE = 8
WriteCommandAction.runWriteCommandAction(myFixture.project)
{
CodeStyleManager.getInstance(myFixture.project).reformatText(
myFixture.file,
ContainerUtil.newArrayList(myFixture.file.textRange)
)
}
myFixture.checkResultByFile("mnemonics_after.asm")
}
}

View File

@ -63,7 +63,7 @@ internal class M68kInspectionSuppressorTest : AbstractInspectionTest() {
val quickFixPair = highlightInfos[0].quickFixActionRanges[0] val quickFixPair = highlightInfos[0].quickFixActionRanges[0]
val intentionActionDescriptor = quickFixPair.first val intentionActionDescriptor = quickFixPair.first
val element = myFixture.file.findElementAt(quickFixPair.second.startOffset)!! val element = myFixture.file.findElementAt(quickFixPair.second.startOffset)!!
val suppressQuickFix = intentionActionDescriptor.getOptions(element, myFixture.editor)!! val suppressQuickFix = intentionActionDescriptor.getOptions(element, myFixture.editor)
.first { it.text == suppressAction } .first { it.text == suppressAction }
myFixture.launchAction(suppressQuickFix) myFixture.launchAction(suppressQuickFix)
} }

View File

@ -14,7 +14,7 @@ internal class AddressingModesTest : AbstractParsingTest() {
@Test @Test
internal fun register_direct(@MyTestCase testCase: ParsingTestExtension.IParsingTestCase) { internal fun register_direct(@MyTestCase testCase: ParsingTestExtension.IParsingTestCase) {
testGoodSyntax(testCase, " move.l d0,a7\n") testGoodSyntax(testCase, " MOVE.L d0,a7\n")
} }
@Test @Test

View File

@ -27,6 +27,6 @@ noppy MACRO
""" """
) )
myFixture.completeBasic() myFixture.completeBasic()
assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder("nop", "not", "noppy") assertThat(myFixture.lookupElementStrings).containsExactlyInAnyOrder("nop", "not", "noppy", "cnop")
} }
} }

View File

@ -103,7 +103,7 @@ internal class M68kReferenceContributorTest : AbstractM68kTest() {
assertThat(otherfile.text).isEqualTo("; oh no!") assertThat(otherfile.text).isEqualTo("; oh no!")
myFixture.renameElementAtCaret("foobar.asm") myFixture.renameElementAtCaret("foobar.asm")
val files = FilenameIndex.getFilesByName(myFixture.project, "foobar.asm", GlobalSearchScope.allScope(myFixture.project)) val files = FilenameIndex.getVirtualFilesByName("foobar.asm", GlobalSearchScope.allScope(myFixture.project))
assertThat(files).hasSize(1) assertThat(files).hasSize(1)
assertThat(file.text).isEqualToIgnoringWhitespace("include \"foobar.asm\"") assertThat(file.text).isEqualToIgnoringWhitespace("include \"foobar.asm\"")
@ -123,7 +123,7 @@ internal class M68kReferenceContributorTest : AbstractM68kTest() {
assertThat(otherfile.text).isEqualTo("; oh no!") assertThat(otherfile.text).isEqualTo("; oh no!")
myFixture.renameElementAtCaret("foobar.asm") myFixture.renameElementAtCaret("foobar.asm")
val files = FilenameIndex.getFilesByName(myFixture.project, "foobar.asm", GlobalSearchScope.allScope(myFixture.project)) val files = FilenameIndex.getVirtualFilesByName("foobar.asm", GlobalSearchScope.allScope(myFixture.project))
assertThat(files).hasSize(1) assertThat(files).hasSize(1)
assertThat(file.text).isEqualToIgnoringWhitespace("include \"foobar/foobar.asm\"") assertThat(file.text).isEqualToIgnoringWhitespace("include \"foobar/foobar.asm\"")

View File

@ -0,0 +1,46 @@
; this is a test
FOO = 1
<fold text='[[[ demo_main ]]]'>; this is the main demo routine
demo_main:
moveq.l #0,d0
rts
; data area starts here
.data dc.w 10,0
even</fold>
; this is an unrelated comment
<fold text='[[[ intro_part1 ]]]'>; this is another folding area
; could be anything.
intro_part1
dc.w $47fe
illegal
rts</fold>
; this comment is two lines away
<fold text='[[[ intro_part2 ]]]'>intro_part2:
moveq.l #0,d1
rts</fold>
; standard macros
<fold text='[[[ MACRO BLTWAIT ]]]'>BLTWAIT MACRO
.bw\@
btst #DMAB_BLTDONE-8,dmaconr(a5)
bne.s .bw\@
ENDM</fold>
********************** foobar
<fold text='[[[ some_more_data ]]]'>some_more_data:
dc.w $123
dc.w $345
dc.w $333
dc.w $222</fold>
CUBE_SIZE = 100

View File

@ -0,0 +1,51 @@
; this is a test
FOO = 1
; this is the main demo routine
demo_main:
moveq.l #0,d0 ; end of line comment
rts ; some more comments
; data area starts here
.data dc.w 10,0
even
this_is_a_very_long_label: moveq.l #0,d0 ; and an end of line comment, too
; this is another folding area
; could be anything.
intro_part1
; What is this doing here?
dc.w $47fe
illegal
rts
; this comment is two lines away
intro_part2:
moveq.l #0,d1
rts
; standard macros
BLTWAIT MACRO
.bw\@
btst #DMAB_BLTDONE-8,dmaconr(a5)
bne.s .bw\@
ENDM
MACRO BLTHOGOFF
moveq.l #0,d0
ENDM
********************** foobar
some_more_data:
dc.w $123
dc.w $345
dc.w $333
dc.w $222
CUBE_SIZE = 100

View File

@ -0,0 +1,51 @@
; this is a test
FOO = 1
; this is the main demo routine
demo_main:
moveq.l #0,d0 ; end of line comment
rts ; some more comments
; data area starts here
.data dc.w 10,0
even
this_is_a_very_long_label: moveq.l #0,d0 ; and an end of line comment, too
; this is another folding area
; could be anything.
intro_part1
; What is this doing here?
dc.w $47fe
illegal
rts
; this comment is two lines away
intro_part2:
moveq.l #0,d1
rts
; standard macros
BLTWAIT MACRO
.bw\@
btst #DMAB_BLTDONE-8,dmaconr(a5)
bne.s .bw\@
ENDM
MACRO BLTHOGOFF
moveq.l #0,d0
ENDM
********************** foobar
some_more_data:
dc.w $123
dc.w $345
dc.w $333
dc.w $222
CUBE_SIZE = 100

View File

@ -0,0 +1,32 @@
FOO = 1234
BAR = 1235
COUNTER SET COUNTER+1
FISH MACRO
.fish\@ rts
ENDM
MACRO SOUP
moveq.l #0,d0
ENDM
; with space
; standalone comment
moveq.l #10,d1 ; end of line comment
FISH
add.l #10,d1
SOUP
subq.b #2,d2 ; end of line comment
bra.s .foo
nop
.foo move.l d2,d1
rts
.verylonglabel:
stop #$2000
.narf
moveq.l #2,d0
globallabel:
moveq.l #0,d0

View File

@ -0,0 +1,31 @@
FOO = 1234
BAR = 1235
COUNTER SET COUNTER+1
FISH MACRO
.fish\@ rts
ENDM
MACRO SOUP
moveq.l #0,d0
ENDM
; with space
; standalone comment
moveq.l #10,d1; end of line comment
FISH
add.l #10,d1
SOUP
subq.b #2,d2 ; end of line comment
bra.s .foo
nop
.foo move.l d2,d1
rts
.verylonglabel: stop #$2000
.narf
moveq.l #2,d0
globallabel: moveq.l #0,d0

View File

@ -3,9 +3,9 @@ Assembly File: a.asm
M68kStatementImpl(STATEMENT) M68kStatementImpl(STATEMENT)
M68kAsmInstructionImpl(ASM_INSTRUCTION) M68kAsmInstructionImpl(ASM_INSTRUCTION)
M68kAsmOpImpl(ASM_OP) M68kAsmOpImpl(ASM_OP)
PsiElement(M68kTokenType.MNEMONIC)('move') PsiElement(M68kTokenType.MNEMONIC)('MOVE')
M68kOperandSizeImpl(OPERAND_SIZE) M68kOperandSizeImpl(OPERAND_SIZE)
PsiElement(M68kTokenType.OPSIZE_L)('.l') PsiElement(M68kTokenType.OPSIZE_L)('.L')
PsiWhiteSpace(' ') PsiWhiteSpace(' ')
M68kDataRegisterDirectAddressingModeImpl(DATA_REGISTER_DIRECT_ADDRESSING_MODE) M68kDataRegisterDirectAddressingModeImpl(DATA_REGISTER_DIRECT_ADDRESSING_MODE)
M68kDataRegisterImpl(DATA_REGISTER) M68kDataRegisterImpl(DATA_REGISTER)