Compare commits
	
		
			12 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6233cefd20 | |||
| a3f979b48b | |||
| 84eb1eab69 | |||
| aed9ed686d | |||
| e3efc545a8 | |||
| df2a220473 | |||
| 130f6a106d | |||
| def6fe306f | |||
| cd0bcd22ff | |||
| f87bc7fea9 | |||
| 64b7042208 | |||
| b785b716bb | 
							
								
								
									
										36
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								README.md
									
									
									
									
									
								
							@ -1,4 +1,4 @@
 | 
				
			|||||||
# MC68000 Assembly Language Plugin [](https://app.travis-ci.com/chrisly42/mc68000-asm-plugin)
 | 
					# 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.).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -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
 | 
					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.
 | 
					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
 | 
					### Documentation provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### M68kSymbolDefinition
 | 
					#### 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
 | 
					- 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 +161,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 +177,23 @@ are appreciated. It really is keeping me motivated to continue development.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Changelog
 | 
					## 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)
 | 
					### V0.9 (16-Aug-22)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Maintenance. Updated all dependencies to the latest versions.
 | 
					- Maintenance. Updated all dependencies to the latest versions.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										62
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								build.gradle
									
									
									
									
									
								
							@ -1,15 +1,14 @@
 | 
				
			|||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
    id 'java'
 | 
					    id 'java'
 | 
				
			||||||
    id 'org.jetbrains.intellij' version '1.8.0'
 | 
					    id 'org.jetbrains.intellij' version '1.17.1'
 | 
				
			||||||
    id 'org.jetbrains.kotlin.jvm' version '1.7.10'
 | 
					    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.9'
 | 
					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.23.1'
 | 
					    testImplementation 'org.assertj:assertj-core:3.26.3'
 | 
				
			||||||
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
 | 
					    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.1'
 | 
				
			||||||
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
 | 
					    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.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.9.0'
 | 
					    testImplementation 'org.junit.platform:junit-platform-launcher:1.11.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("2022.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-222.3345.118", // 2020.3 - 2022.2
 | 
					    ideVersions = ["IC-203.6682.168", "IC-233.14015.106", // 2020.3 - 2023.3
 | 
				
			||||||
                   "CL-203.8084.11", // 2020.3
 | 
					                   "CL-203.8084.11", "CL-233.14015.92"] // 2020.3 - 2023.3
 | 
				
			||||||
                   "CL-211.7628.27", // 2021.1
 | 
					
 | 
				
			||||||
                   "CL-212.5712.21", // 2021.2
 | 
					 | 
				
			||||||
                   "CL-213.7172.20", // 2021.3.4
 | 
					 | 
				
			||||||
                   "CL-221.5080.224", // 2022.1
 | 
					 | 
				
			||||||
                   "CL-222.3345.126"] // 2022.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("""
 | 
				
			||||||
  <h4>V0.9 (16-Aug-22)</h4>
 | 
					  <h4>V0.10 (20-Feb-24)</h4>
 | 
				
			||||||
    <ul>
 | 
					    <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>Maintenance. Updated all dependencies to the latest versions.
 | 
				
			||||||
    <li>Bugfix: Fixed condition code for asr/lsr/lsl, which is has a different behaviour for V flag than asl.
 | 
					    <li>New: Added semantic highlighting. Currently available for data and address registers and local labels.
 | 
				
			||||||
    <li>Bugfix: Fixed 'Unknown op size' exception when uppercase sizes were used.
 | 
					    <li>Bugfix: addq/subq for address register stated it would affect the condition codes, which it in fact doesn't.
 | 
				
			||||||
    <li>Bugfix: Refactoring was broken for newer IDE versions, at least for me, this now works again by unknown magic.
 | 
					    <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>
 | 
				
			||||||
""")
 | 
					""")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -84,10 +74,6 @@ test {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks.coveralls {
 | 
					 | 
				
			||||||
    dependsOn jacocoTestReport
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jacoco {
 | 
					jacoco {
 | 
				
			||||||
    toolVersion = '0.8.8'
 | 
					    toolVersion = '0.8.8'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@ -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.5.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
									
								
							
							
						
						
									
										17
									
								
								plans.txt
									
									
									
									
									
										Normal 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"
 | 
				
			||||||
@ -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) {
 | 
				
			||||||
 | 
				
			|||||||
@ -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"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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(
 | 
				
			||||||
 | 
				
			|||||||
@ -88,13 +88,13 @@ fun getCcInfo(cc: Int): Map<String, Pair<String, String>> {
 | 
				
			|||||||
        CC_V_OR -> "*" to CC_OR_STR
 | 
					        CC_V_OR -> "*" to CC_OR_STR
 | 
				
			||||||
        else -> "*" to "$CC_RES_STR (usually for overflows)"
 | 
					        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
 | 
					        0 -> "-" to CC_NOT_AFFECTED_STR
 | 
				
			||||||
        CC_V_SET -> "1" to CC_ALWAYS_SET_STR
 | 
					        CC_C_SET -> "1" to CC_ALWAYS_SET_STR
 | 
				
			||||||
        CC_V_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
 | 
					        CC_C_CLEAR -> "0" to CC_ALWAYS_CLEAR_STR
 | 
				
			||||||
        CC_V_UNDEF -> "U" to CC_UNDEFINED_STR
 | 
					        CC_C_UNDEF -> "U" to CC_UNDEFINED_STR
 | 
				
			||||||
        CC_V_AND -> "*" to CC_AND_STR
 | 
					        CC_C_AND -> "*" to CC_AND_STR
 | 
				
			||||||
        CC_V_OR -> "*" to CC_OR_STR
 | 
					        CC_C_OR -> "*" to CC_OR_STR
 | 
				
			||||||
        else -> "*" to "$CC_RES_STR (usually carry/borrow)"
 | 
					        else -> "*" to "$CC_RES_STR (usually carry/borrow)"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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(
 | 
				
			||||||
@ -1085,7 +1085,7 @@ object M68kIsa {
 | 
				
			|||||||
        IsaData(
 | 
					        IsaData(
 | 
				
			||||||
            "stop", "Stop",
 | 
					            "stop", "Stop",
 | 
				
			||||||
            machine = ALL_MACHINES, isPrivileged = true,
 | 
					            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(
 | 
					        *autoExpandForOtherCpus(
 | 
				
			||||||
@ -1208,10 +1208,10 @@ object M68kIsa {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private val mnemonicLookupMap = isaData.asSequence()
 | 
					    private 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(
 | 
				
			||||||
                .map { cc ->
 | 
					                it.conditionCodes
 | 
				
			||||||
                    it.mnemonic.replace("CC", cc)
 | 
					                    .map { cc -> it.mnemonic.replace("CC", cc) }))
 | 
				
			||||||
                })).map { mnemonic -> mnemonic to it }
 | 
					                .map { mnemonic -> mnemonic to it }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        .groupBy({ it.first }) { it.second }
 | 
					        .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> {
 | 
					    fun findMatchingOpMode(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, opSize: Int?, specialReg: String?): List<IsaData> {
 | 
				
			||||||
        return candidates.filter {
 | 
					        return candidates.filter {
 | 
				
			||||||
            it.modes.any { am ->
 | 
					            it.modes.any { am -> isAddressModeMatching(am, op1, op2, specialReg) && ((opSize == null) || ((opSize and am.size) == opSize)) }
 | 
				
			||||||
                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> {
 | 
					    fun findMatchingAddressMode(modes: List<AllowedAdrMode>, op1: AddressMode?, op2: AddressMode?, opSize: Int?, specialReg: String?): List<AllowedAdrMode> {
 | 
				
			||||||
        return modes.filter { am ->
 | 
					        return modes.filter { am -> isAddressModeMatching(am, op1, op2, specialReg) && ((opSize == null) || ((opSize and am.size) == opSize)) }
 | 
				
			||||||
            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> {
 | 
					    fun findMatchingOpModeIgnoringSize(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, specialReg: String?): List<IsaData> {
 | 
				
			||||||
        return candidates.filter {
 | 
					        return candidates.filter { it.modes.any { am -> isAddressModeMatching(am, op1, op2, specialReg) } }
 | 
				
			||||||
            it.modes.any { am -> isAddressModeMatching(am, op1, op2, specialReg) }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun findSupportedOpSizes(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, specialReg: String?): Int {
 | 
					    fun findSupportedOpSizes(candidates: List<IsaData>, op1: AddressMode?, op2: AddressMode?, specialReg: String?): Int {
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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>()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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
 | 
					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)?
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -12,22 +12,26 @@ import de.platon42.intellij.plugins.m68k.psi.utils.M68kLookupUtil
 | 
				
			|||||||
class M68kGlobalLabelSymbolCompletionContributor : CompletionContributor() {
 | 
					class M68kGlobalLabelSymbolCompletionContributor : CompletionContributor() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        val REGISTER_SUGGESTIONS: List<LookupElement> =
 | 
					        val REGS = listOf(
 | 
				
			||||||
            listOf(
 | 
					 | 
				
			||||||
            "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
 | 
					            "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
 | 
				
			||||||
            "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
 | 
					            "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
 | 
				
			||||||
            "pc"
 | 
					            "pc"
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
                .map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(M68kIcons.REGISTER).withBoldness(true), 2.0) }
 | 
					        val REGSET = REGS.toSet()
 | 
				
			||||||
 | 
					        val REGISTER_SUGGESTIONS: List<LookupElement> =
 | 
				
			||||||
 | 
					            REGS.map { PrioritizedLookupElement.withPriority(LookupElementBuilder.create(it).withIcon(M68kIcons.REGISTER).withBoldness(true), 2.0) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        extend(CompletionType.BASIC, PlatformPatterns.psiElement(M68kTypes.SYMBOL), object : CompletionProvider<CompletionParameters>() {
 | 
					        extend(CompletionType.BASIC, PlatformPatterns.psiElement(M68kTypes.SYMBOL), object : CompletionProvider<CompletionParameters>() {
 | 
				
			||||||
            override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
 | 
					            override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
 | 
				
			||||||
                resultSet.addAllElements(REGISTER_SUGGESTIONS)
 | 
					                resultSet.addAllElements(REGISTER_SUGGESTIONS)
 | 
				
			||||||
 | 
					                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.findAllGlobalLabels(parameters.originalFile.project).map(LookupElementBuilder::createWithIcon))
 | 
				
			||||||
                    resultSet.addAllElements(M68kLookupUtil.findAllSymbolDefinitions(parameters.originalFile.project).map(LookupElementBuilder::createWithIcon))
 | 
					                    resultSet.addAllElements(M68kLookupUtil.findAllSymbolDefinitions(parameters.originalFile.project).map(LookupElementBuilder::createWithIcon))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -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)
 | 
				
			||||||
 | 
				
			|||||||
@ -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),
 | 
				
			||||||
 | 
				
			|||||||
@ -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()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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"/>
 | 
				
			||||||
@ -68,6 +77,9 @@
 | 
				
			|||||||
        <localInspection implementationClass="de.platon42.intellij.plugins.m68k.inspections.M68kUnresolvedReferenceInspection"
 | 
					        <localInspection implementationClass="de.platon42.intellij.plugins.m68k.inspections.M68kUnresolvedReferenceInspection"
 | 
				
			||||||
                         displayName="Unresolved label/symbol/macro reference" groupName="M68k"
 | 
					                         displayName="Unresolved label/symbol/macro reference" groupName="M68k"
 | 
				
			||||||
                         enabledByDefault="true" level="WARNING"/>
 | 
					                         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"/>
 | 
					        <projectService serviceImplementation="de.platon42.intellij.plugins.m68k.settings.M68kProjectSettings"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -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")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								src/test/resources/folding/folding.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/test/resources/folding/folding.asm
									
									
									
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/test/resources/formatting/basic_after.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/test/resources/formatting/basic_after.asm
									
									
									
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/test/resources/formatting/basic_before.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/test/resources/formatting/basic_before.asm
									
									
									
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/test/resources/formatting/mnemonics_after.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/test/resources/formatting/mnemonics_after.asm
									
									
									
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										31
									
								
								src/test/resources/formatting/mnemonics_before.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/test/resources/formatting/mnemonics_before.asm
									
									
									
									
									
										Normal 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
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user