Compare commits
6
Commits
130f6a106d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6233cefd20 | ||
|
|
a3f979b48b | ||
|
|
84eb1eab69 | ||
|
|
aed9ed686d | ||
|
|
e3efc545a8 | ||
|
|
df2a220473 |
@@ -1,4 +1,4 @@
|
||||
# MC68000 Assembly Language Plugin [](https://app.travis-ci.com/chrisly42/mc68000-asm-plugin) [](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.).
|
||||
|
||||
@@ -84,6 +84,17 @@ optimize the order of execution.
|
||||
Points out unresolved references such for global and local labels, macros or symbols. Right now, missing symbol and global label references are shown only as
|
||||
weak warnings as missing macro evaluation will not resolve symbols defined via `STRUCT` macros.
|
||||
|
||||
#### M68kAddressRegisterWordAccessInspection - Suspicious word access to address register
|
||||
|
||||
Warns on `movea.w` to address registers which is often a typo and takes ages to find and fix.
|
||||
Of course there are legal intentional uses of this instruction that sign extends the word
|
||||
to a long word, or using it as a temporary register or for index purposes.
|
||||
|
||||
Also warns on `cmpa.w` with address register as second operand (there are some clever ways
|
||||
using this, such as using `cmpa.w ax,ax` to see if a value is between $ffff8000 and $7fff).
|
||||
|
||||
Third instruction checked is `tst.w` on address registers for 68020+.
|
||||
|
||||
### Documentation provider
|
||||
|
||||
#### M68kSymbolDefinition
|
||||
@@ -133,6 +144,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
|
||||
project :-/
|
||||
- Unit Test coverage is not as good as it could be (ahem).
|
||||
- Code flow sometimes outputs "uhm?"
|
||||
- Missing but planned features:
|
||||
- Macro evaluation on invocation
|
||||
- Folding
|
||||
@@ -149,9 +161,10 @@ to highlight the same address and data registers while editing (see new `View ->
|
||||
|
||||
## 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
|
||||
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 +177,23 @@ are appreciated. It really is keeping me motivated to continue development.
|
||||
|
||||
## Changelog
|
||||
|
||||
### V0.11 (unreleased)
|
||||
|
||||
- New: Added M68kAddressRegisterWordAccessInspection to find suspicious uses of address registers.
|
||||
|
||||
### 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.
|
||||
@@ -249,4 +279,4 @@ are appreciated. It really is keeping me motivated to continue development.
|
||||
|
||||
### V0.1 (20-Jul-21)
|
||||
|
||||
- Initial public release.
|
||||
- Initial public release.
|
||||
|
||||
+20
-36
@@ -1,68 +1,56 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.jetbrains.intellij' version '1.9.0'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.7.20'
|
||||
id 'org.jetbrains.intellij' version '1.17.1'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.9.22'
|
||||
id 'jacoco'
|
||||
id 'com.github.kt3k.coveralls' version '2.12.0'
|
||||
}
|
||||
|
||||
group = 'de.platon42'
|
||||
version = '0.10'
|
||||
sourceCompatibility = "1.8"
|
||||
targetCompatibility = "1.8"
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
/*
|
||||
To run tests in IntelliJ use these VM Options for run configuration
|
||||
To run tests in IntelliJ use these VM Options for run configuration
|
||||
-ea -Didea.system.path=build/idea-sandbox/system-test -Didea.config.path=build/idea-sandbox/config-test -Didea.plugins.path=build/idea-sandbox/plugins-test
|
||||
*/
|
||||
|
||||
dependencies {
|
||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
|
||||
testImplementation 'org.assertj:assertj-core:3.23.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
|
||||
testImplementation 'org.assertj:assertj-core:3.26.3'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.1'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.2'
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-test"
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||
testImplementation 'org.junit.platform:junit-platform-launcher:1.9.0'
|
||||
testImplementation 'org.junit.platform:junit-platform-launcher:1.11.2'
|
||||
// testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
freeCompilerArgs += "-Xjvm-default=all"
|
||||
}
|
||||
}
|
||||
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
|
||||
intellij {
|
||||
setVersion("2022.2.3") // LATEST-EAP-SNAPSHOT
|
||||
setVersion("2022.3") // LATEST-EAP-SNAPSHOT
|
||||
setUpdateSinceUntilBuild(false)
|
||||
// setPlugins(["com.intellij.java"])
|
||||
}
|
||||
|
||||
runPluginVerifier {
|
||||
ideVersions = ["IC-203.6682.168", "IC-222.4345.14", // 2020.3 - 2022.2.3
|
||||
"CL-203.8084.11", // 2020.3
|
||||
"CL-211.7628.27", // 2021.1
|
||||
"CL-212.5712.21", // 2021.2
|
||||
"CL-213.7172.20", // 2021.3.4
|
||||
"CL-221.5921.22", // 2022.1.3
|
||||
"CL-222.4345.21"] // 2022.2.4
|
||||
ideVersions = ["IC-203.6682.168", "IC-233.14015.106", // 2020.3 - 2023.3
|
||||
"CL-203.8084.11", "CL-233.14015.92"] // 2020.3 - 2023.3
|
||||
|
||||
downloadDir = System.getProperty("user.home") + "/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/verifier"
|
||||
}
|
||||
|
||||
patchPluginXml {
|
||||
setChangeNotes("""
|
||||
<h4>V0.10 (undefined)</h4>
|
||||
<h4>V0.10 (20-Feb-24)</h4>
|
||||
<ul>
|
||||
<li>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).
|
||||
<li>Maintenance. Updated all dependencies to the latest versions.
|
||||
<li>New: Added semantic highlighting. Currently available for data and address registers and local labels.
|
||||
<li>Bugfix: addq/subq for address register stated it would affect the condition codes, which it in fact doesn't.
|
||||
<li>New: Added simple custom navigation bar.
|
||||
@@ -70,7 +58,7 @@ patchPluginXml {
|
||||
<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>
|
||||
<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>
|
||||
""")
|
||||
}
|
||||
|
||||
@@ -86,10 +74,6 @@ test {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.coveralls {
|
||||
dependsOn jacocoTestReport
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = '0.8.8'
|
||||
}
|
||||
@@ -103,4 +87,4 @@ jacocoTestReport {
|
||||
|
||||
publishPlugin {
|
||||
setToken(intellijPublishToken)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
kotlin.code.style=official
|
||||
kotlin.incremental=true
|
||||
intellijPublishToken=perm:dummy
|
||||
systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
|
||||
systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -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"
|
||||
@@ -649,22 +649,12 @@ public class M68kParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// AsmInstruction | MacroCall
|
||||
// AsmInstruction | MacroCall | PreprocessorDirective
|
||||
static boolean Instruction(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "Instruction")) return false;
|
||||
if (!nextTokenIs(b, "", MACRO_INVOCATION, MNEMONIC)) return false;
|
||||
boolean r;
|
||||
r = AsmInstruction(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);
|
||||
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) {
|
||||
if (!recursion_guard_(b, l, "LabelInsts")) return false;
|
||||
boolean r;
|
||||
r = LabelWithInstruction(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;
|
||||
}
|
||||
|
||||
@@ -698,27 +688,18 @@ public class M68kParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// Label (Instruction|PreprocessorDirective)
|
||||
// Label Instruction
|
||||
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 && LabelWithInstruction_1(b, l + 1);
|
||||
r = r && Instruction(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) {
|
||||
|
||||
@@ -10,7 +10,7 @@ class M68kFileElementType private constructor() : ILightStubFileElementType<PsiF
|
||||
@JvmField
|
||||
val INSTANCE = M68kFileElementType()
|
||||
|
||||
const val STUB_VERSION = 7
|
||||
const val STUB_VERSION = 8
|
||||
const val STUB_EXTERNAL_ID_PREFIX = "MC68000."
|
||||
const val EXTERNAL_ID = STUB_EXTERNAL_ID_PREFIX + "FILE"
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@ object AssemblerDirectives {
|
||||
"align", "even", "odd", "cnop", "long", "dphrase", "phrase", "qphrase",
|
||||
|
||||
"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(
|
||||
|
||||
@@ -88,13 +88,13 @@ fun getCcInfo(cc: Int): Map<String, Pair<String, String>> {
|
||||
CC_V_OR -> "*" to CC_OR_STR
|
||||
else -> "*" to "$CC_RES_STR (usually for overflows)"
|
||||
}
|
||||
xnzvcMap["C"] = when (cc and CC_V_TST) {
|
||||
xnzvcMap["C"] = when (cc and CC_C_TST) {
|
||||
0 -> "-" to CC_NOT_AFFECTED_STR
|
||||
CC_V_SET -> "1" to CC_ALWAYS_SET_STR
|
||||
CC_V_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
|
||||
CC_V_UNDEF -> "U" to CC_UNDEFINED_STR
|
||||
CC_V_AND -> "*" to CC_AND_STR
|
||||
CC_V_OR -> "*" to CC_OR_STR
|
||||
CC_C_SET -> "1" to CC_ALWAYS_SET_STR
|
||||
CC_C_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
|
||||
CC_C_UNDEF -> "U" to CC_UNDEFINED_STR
|
||||
CC_C_AND -> "*" to CC_AND_STR
|
||||
CC_C_OR -> "*" to CC_OR_STR
|
||||
else -> "*" to "$CC_RES_STR (usually carry/borrow)"
|
||||
}
|
||||
|
||||
|
||||
@@ -1085,7 +1085,7 @@ object M68kIsa {
|
||||
IsaData(
|
||||
"stop", "Stop",
|
||||
machine = ALL_MACHINES, isPrivileged = true,
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), null, OP_UNSIZED))
|
||||
modes = listOf(AllowedAdrMode(setOf(AddressMode.IMMEDIATE_DATA), null, OP_UNSIZED, affectedCc = cc("*****")))
|
||||
),
|
||||
|
||||
*autoExpandForOtherCpus(
|
||||
@@ -1208,10 +1208,10 @@ object M68kIsa {
|
||||
|
||||
private val mnemonicLookupMap = isaData.asSequence()
|
||||
.flatMap {
|
||||
(if (it.conditionCodes.isEmpty()) it.altMnemonics.plus(it.mnemonic) else it.altMnemonics.plus(it.conditionCodes
|
||||
.map { cc ->
|
||||
it.mnemonic.replace("CC", cc)
|
||||
})).map { mnemonic -> mnemonic to it }
|
||||
(if (it.conditionCodes.isEmpty()) it.altMnemonics.plus(it.mnemonic) else it.altMnemonics.plus(
|
||||
it.conditionCodes
|
||||
.map { cc -> it.mnemonic.replace("CC", cc) }))
|
||||
.map { mnemonic -> mnemonic to it }
|
||||
}
|
||||
.groupBy({ it.first }) { it.second }
|
||||
|
||||
@@ -1223,24 +1223,16 @@ object M68kIsa {
|
||||
|
||||
fun findMatchingOpMode(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, opSize: Int?, specialReg: String?): List<IsaData> {
|
||||
return candidates.filter {
|
||||
it.modes.any { am ->
|
||||
isAddressModeMatching(am, op1, op2, specialReg)
|
||||
&& ((opSize == null) || ((opSize and am.size) == opSize))
|
||||
}
|
||||
it.modes.any { am -> isAddressModeMatching(am, op1, op2, specialReg) && ((opSize == null) || ((opSize and am.size) == opSize)) }
|
||||
}
|
||||
}
|
||||
|
||||
fun findMatchingAddressMode(modes: List<AllowedAdrMode>, op1: AddressMode?, op2: AddressMode?, opSize: Int?, specialReg: String?): List<AllowedAdrMode> {
|
||||
return modes.filter { am ->
|
||||
isAddressModeMatching(am, op1, op2, specialReg)
|
||||
&& ((opSize == null) || ((opSize and am.size) == opSize))
|
||||
}
|
||||
return modes.filter { am -> isAddressModeMatching(am, op1, op2, specialReg) && ((opSize == null) || ((opSize and am.size) == opSize)) }
|
||||
}
|
||||
|
||||
fun findMatchingOpModeIgnoringSize(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, specialReg: String?): List<IsaData> {
|
||||
return candidates.filter {
|
||||
it.modes.any { am -> isAddressModeMatching(am, op1, op2, specialReg) }
|
||||
}
|
||||
return candidates.filter { it.modes.any { am -> isAddressModeMatching(am, op1, op2, specialReg) } }
|
||||
}
|
||||
|
||||
fun findSupportedOpSizes(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, specialReg: String?): Int {
|
||||
@@ -1253,6 +1245,6 @@ object M68kIsa {
|
||||
|
||||
private fun isAddressModeMatching(am: AllowedAdrMode, op1: AddressMode?, op2: AddressMode?, specialReg: String?) =
|
||||
((((op1 == null) && (am.op1 == null)) || am.op1?.contains(op1) ?: false)
|
||||
&& (((op2 == null) && (am.op2 == null)) || am.op2?.contains(op2) ?: false)
|
||||
&& ((specialReg == null) || (am.specialReg?.split('|')?.any { it.equals(specialReg, true) } ?: false)))
|
||||
}
|
||||
&& (((op2 == null) && (am.op2 == null)) || am.op2?.contains(op2) ?: false)
|
||||
&& ((specialReg == null) || (am.specialReg?.split('|')?.any { it.equals(specialReg, true) } ?: false)))
|
||||
}
|
||||
|
||||
@@ -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>()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
+31
@@ -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)
|
||||
}
|
||||
@@ -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>()
|
||||
}
|
||||
@@ -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>()
|
||||
}
|
||||
+19
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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>()
|
||||
}
|
||||
@@ -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>()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+41
@@ -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
|
||||
"""
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package de.platon42.intellij.plugins.m68k.inspections
|
||||
|
||||
import com.intellij.codeInspection.InspectionManager
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import de.platon42.intellij.plugins.m68k.asm.AddressMode
|
||||
import de.platon42.intellij.plugins.m68k.asm.M68kIsa.findMatchingInstructions
|
||||
import de.platon42.intellij.plugins.m68k.asm.OP_SIZE_W
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kAddressModeUtil
|
||||
import de.platon42.intellij.plugins.m68k.psi.M68kAsmInstruction
|
||||
import de.platon42.intellij.plugins.m68k.utils.M68kIsaUtil.findExactIsaDataAndAllowedAdrModeForInstruction
|
||||
|
||||
class M68kAddressRegisterWordAccessInspection : AbstractBaseM68kLocalInspectionTool() {
|
||||
|
||||
companion object {
|
||||
private const val DISPLAY_NAME = "Word access to address register"
|
||||
|
||||
private const val ADDR_REG_WORD_ACCESS_MSG_TEMPLATE = "Suspicious %s %s address register"
|
||||
}
|
||||
|
||||
override fun getDisplayName() = DISPLAY_NAME
|
||||
|
||||
override fun checkAsmInstruction(asmInstruction: M68kAsmInstruction, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? {
|
||||
val asmOp = asmInstruction.asmOp
|
||||
if (asmOp.opSize != OP_SIZE_W) return emptyArray()
|
||||
|
||||
val isaDataCandidates = findMatchingInstructions(asmOp.mnemonic)
|
||||
if (isaDataCandidates.isEmpty()) return emptyArray()
|
||||
val (isaData, adrMode) = findExactIsaDataAndAllowedAdrModeForInstruction(asmInstruction) ?: return emptyArray()
|
||||
|
||||
return when (isaData.mnemonic) {
|
||||
"movea" -> arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction,
|
||||
asmInstruction,
|
||||
ADDR_REG_WORD_ACCESS_MSG_TEMPLATE.format(isaData.mnemonic, "word write to"),
|
||||
ProblemHighlightType.WARNING,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
|
||||
"cmpa" -> arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction,
|
||||
asmInstruction,
|
||||
ADDR_REG_WORD_ACCESS_MSG_TEMPLATE.format(isaData.mnemonic, "comparing with word-sized"),
|
||||
ProblemHighlightType.WARNING,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
|
||||
"tst" -> if (M68kAddressModeUtil.getAddressModeForType(asmInstruction.addressingModeList.getOrNull(0)) == AddressMode.ADDRESS_REGISTER_DIRECT) {
|
||||
arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
asmInstruction,
|
||||
asmInstruction,
|
||||
ADDR_REG_WORD_ACCESS_MSG_TEMPLATE.format(isaData.mnemonic, "with word-sized"),
|
||||
ProblemHighlightType.WARNING,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
} else {
|
||||
emptyArray()
|
||||
}
|
||||
|
||||
else -> emptyArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,11 +136,10 @@ SymbolDefinition ::= SYMBOLDEF {
|
||||
|
||||
Assignment ::= SymbolDefinition COLON? (OP_ASSIGN|EQU) expr
|
||||
|
||||
private LabelInsts ::= LabelWithInstruction | LabelOnly | InstructionOnly
|
||||
private LabelInsts ::= LabelWithInstruction | LabelOnly | Instruction
|
||||
|
||||
private LabelOnly ::= Label
|
||||
private LabelWithInstruction ::= Label (Instruction|PreprocessorDirective)
|
||||
private InstructionOnly ::= (Instruction|PreprocessorDirective)
|
||||
private LabelWithInstruction ::= Label Instruction
|
||||
|
||||
LocalLabel ::= LOCAL_LABEL_DEF COLON? {
|
||||
name = "local label"
|
||||
@@ -199,7 +198,7 @@ MacroCall ::= MACRO_INVOCATION PlainOperands? {
|
||||
}
|
||||
|
||||
AsmInstruction ::= AsmOp AsmOperands?
|
||||
private Instruction ::= AsmInstruction | MacroCall
|
||||
private Instruction ::= AsmInstruction | MacroCall | PreprocessorDirective
|
||||
//external Instruction ::= parseMacroCallOrAsmInstruction
|
||||
|
||||
private AsmOperands ::= AddressingMode (SEPARATOR AddressingMode)?
|
||||
|
||||
+13
-9
@@ -12,22 +12,26 @@ import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil
|
||||
class M68kGlobalLabelSymbolCompletionContributor : CompletionContributor() {
|
||||
|
||||
companion object {
|
||||
val REGS = listOf(
|
||||
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
|
||||
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
|
||||
"pc"
|
||||
)
|
||||
val REGSET = REGS.toSet()
|
||||
val REGISTER_SUGGESTIONS: List<LookupElement> =
|
||||
listOf(
|
||||
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
|
||||
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
|
||||
"pc"
|
||||
)
|
||||
.map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(M68kIcons.REGISTER).withBoldness(true), 2.0) }
|
||||
REGS.map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(M68kIcons.REGISTER).withBoldness(true), 2.0) }
|
||||
}
|
||||
|
||||
init {
|
||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement(M68kTypes.SYMBOL), object : CompletionProvider<CompletionParameters>() {
|
||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
|
||||
resultSet.addAllElements(REGISTER_SUGGESTIONS)
|
||||
resultSet.addAllElements(M68kLookupUtil.findAllGlobalLabels(parameters.originalFile.project).map(LookupElementBuilder::createWithIcon))
|
||||
resultSet.addAllElements(M68kLookupUtil.findAllSymbolDefinitions(parameters.originalFile.project).map(LookupElementBuilder::createWithIcon))
|
||||
val prefix = resultSet.prefixMatcher.prefix.lowercase()
|
||||
if (!(prefix == "a" || prefix == "d" || REGSET.contains(prefix))) {
|
||||
resultSet.addAllElements(M68kLookupUtil.findAllGlobalLabels(parameters.originalFile.project).map(LookupElementBuilder::createWithIcon))
|
||||
resultSet.addAllElements(M68kLookupUtil.findAllSymbolDefinitions(parameters.originalFile.project).map(LookupElementBuilder::createWithIcon))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<idea-plugin>
|
||||
<id>de.platon42.m68k</id>
|
||||
<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>
|
||||
|
||||
<description><![CDATA[
|
||||
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.
|
||||
<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>
|
||||
<idea-version since-build="203.5981.166"/>
|
||||
|
||||
@@ -21,9 +21,12 @@
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.parser.M68kParserDefinition"/>
|
||||
<lang.syntaxHighlighterFactory language="MC68000"
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.syntax.M68kSyntaxHighlighterFactory"/>
|
||||
<lang.foldingBuilder
|
||||
language="MC68000"
|
||||
implementationClass="de.platon42.intellij.plugins.m68k.folding.M68kFoldingBuilder"/>
|
||||
<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"/>
|
||||
@@ -74,6 +77,9 @@
|
||||
<localInspection implementationClass="de.platon42.intellij.plugins.m68k.inspections.M68kUnresolvedReferenceInspection"
|
||||
displayName="Unresolved label/symbol/macro reference" groupName="M68k"
|
||||
enabledByDefault="true" level="WARNING"/>
|
||||
<localInspection implementationClass="de.platon42.intellij.plugins.m68k.inspections.M68kAddressRegisterWordAccessInspection"
|
||||
displayName="Suspicious word access to address register" groupName="M68k"
|
||||
enabledByDefault="true" level="WARNING"/>
|
||||
|
||||
<projectService serviceImplementation="de.platon42.intellij.plugins.m68k.settings.M68kProjectSettings"/>
|
||||
|
||||
@@ -84,4 +90,4 @@
|
||||
|
||||
<actions>
|
||||
</actions>
|
||||
</idea-plugin>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package de.platon42.intellij.plugins.m68k.inspections
|
||||
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import de.platon42.intellij.jupiter.MyFixture
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class M68kAddressRegisterWordAccessInspectionTest : AbstractInspectionTest() {
|
||||
|
||||
@Test
|
||||
internal fun shows_warning_on_movea_word_sized(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kAddressRegisterWordAccessInspection::class.java)
|
||||
myFixture.configureByText("wordaccess.asm", " move.w d0,a0")
|
||||
assertHighlightings(myFixture, 1, "Suspicious movea word write to address register")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_warning_on_cmpa_word_sized(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kAddressRegisterWordAccessInspection::class.java)
|
||||
myFixture.configureByText("wordaccess.asm", " cmp.w d0,a0")
|
||||
assertHighlightings(myFixture, 1, "Suspicious cmpa comparing with word-sized address register")
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun shows_warning_on_tst_with_word_sized_address_register(@MyFixture myFixture: CodeInsightTestFixture) {
|
||||
myFixture.enableInspections(M68kAddressRegisterWordAccessInspection::class.java)
|
||||
myFixture.configureByText("wordaccess.asm", " tst.w a0")
|
||||
assertHighlightings(myFixture, 1, "Suspicious tst with word-sized address register")
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user