From 80839cbdd8336e97b96a10e77ba0f7da2cf3884d Mon Sep 17 00:00:00 2001 From: Peter Jakubco Date: Tue, 4 Apr 2023 11:10:36 +0200 Subject: [PATCH 1/6] [#314] Draft of cassette player + zx-spectrum-ula fixes + emuStudio deps versions update + gradle 8.0.2 --- application/build.gradle | 6 +- .../src/main/files/config/ZxSpectrum48K.toml | 10 +- .../application/gui/GuiDialogsImpl.java | 22 ++ .../application/gui/NoGuiDialogsImpl.java | 10 + .../gui/debugtable/MockHelper.java | 2 +- build.gradle | 22 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../plugins/device/mits88sio/gui/SioGui.java | 1 + plugins/device/cassette-player/build.gradle | 56 +++++ .../cassette_player/CassetteController.java | 144 +++++++++++ .../cassette_player/CassetteListenerImpl.java | 69 ++++++ .../device/cassette_player/DeviceImpl.java | 134 ++++++++++ .../gui/CassettePlayerGui.java | 231 ++++++++++++++++++ .../cassette_player/gui/TapesListModel.java | 68 ++++++ .../cassette_player/loaders/Loader.java | 105 ++++++++ .../cassette_player/loaders/TapLoader.java | 88 +++++++ .../cassette_player/loaders/TapTzxHeader.java | 56 +++++ .../cassette_player/loaders/TzxLoader.java | 90 +++++++ .../cassette_player}/version.properties | 0 .../build.gradle | 0 .../device/zxspectrum/ula}/DeviceImpl.java | 50 ++-- .../plugins/device/zxspectrum/ula}/ULA.java | 123 +++++++++- .../device/zxspectrum/ula/api/LineInPort.java | 42 ++++ .../zxspectrum/ula}/gui/DisplayCanvas.java | 8 +- .../device/zxspectrum/ula}/gui/Keyboard.java | 2 +- .../zxspectrum/ula}/gui/TerminalWindow.java | 4 +- .../device/zxspectrum/ula}/16_ascii.png | Bin .../device/zxspectrum/ula}/16_circle_blue.png | Bin .../zxspectrum/ula}/16_circle_green.png | Bin .../device/zxspectrum/ula}/16_circle_red.png | Bin .../device/zxspectrum/ula/version.properties | 20 ++ .../plugins/memory/bytemem/MemoryImpl.java | 12 +- .../plugins/memory/bytemem/gui/MemoryGui.java | 8 - .../memory/bytemem/loaders/BinaryLoader.java | 5 +- .../memory/bytemem/loaders/HexLoader.java | 5 +- .../memory/bytemem/loaders/Loader.java | 3 +- .../memory/bytemem/loaders/TapLoader.java | 35 +-- .../memory/bytemem/loaders/TzxLoader.java | 68 +++++- .../gui/actions/EraseMemoryActionTest.java | 55 +++++ settings.gradle | 3 +- 40 files changed, 1462 insertions(+), 97 deletions(-) create mode 100644 plugins/device/cassette-player/build.gradle create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteController.java create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteListenerImpl.java create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/CassettePlayerGui.java create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/TapesListModel.java create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/Loader.java create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapTzxHeader.java create mode 100644 plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TzxLoader.java rename plugins/device/{zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display => cassette-player/src/main/resources/net/emustudio/plugins/device/cassette_player}/version.properties (100%) rename plugins/device/{zxspectrum-display => zxspectrum-ula}/build.gradle (100%) rename plugins/device/{zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula}/DeviceImpl.java (68%) rename plugins/device/{zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula}/ULA.java (75%) create mode 100644 plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java rename plugins/device/{zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula}/gui/DisplayCanvas.java (96%) rename plugins/device/{zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula}/gui/Keyboard.java (97%) rename plugins/device/{zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula}/gui/TerminalWindow.java (96%) rename plugins/device/{zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula}/16_ascii.png (100%) rename plugins/device/{zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula}/16_circle_blue.png (100%) rename plugins/device/{zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula}/16_circle_green.png (100%) rename plugins/device/{zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display => zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula}/16_circle_red.png (100%) create mode 100644 plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/version.properties diff --git a/application/build.gradle b/application/build.gradle index 39f4a254b..c3d209d05 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -75,7 +75,8 @@ dependencies { providedRuntime project(":plugins:device:vt100-terminal") providedRuntime project(":plugins:device:simh-pseudo") providedRuntime project(":plugins:device:ssem-display") - providedRuntime project(":plugins:device:zxspectrum-display") + providedRuntime project(":plugins:device:zxspectrum-ula") + providedRuntime project(":plugins:device:cassette-player") testImplementation libs.junit testImplementation libs.easyMock @@ -217,7 +218,8 @@ distributions { from(output(":plugins:device:vt100-terminal")) from(output(":plugins:device:simh-pseudo")) from(output(":plugins:device:ssem-display")) - from(output(":plugins:device:zxspectrum-display")) + from(output(":plugins:device:zxspectrum-ula")) + from(output(":plugins:device:cassette-player")) } // Examples diff --git a/application/src/main/files/config/ZxSpectrum48K.toml b/application/src/main/files/config/ZxSpectrum48K.toml index 7325cf99c..113a159ee 100644 --- a/application/src/main/files/config/ZxSpectrum48K.toml +++ b/application/src/main/files/config/ZxSpectrum48K.toml @@ -11,13 +11,7 @@ name = "ZX Spectrum 48K" #memorySize = 49152 banksCount = 0 ROMfrom0 = 0 - imageName0 = "/home/vbmacher/tmp/emuStudio/z80full.out" - imageName1 = "/home/vbmacher/tmp/emuStudio/examples/zxspectrum-48k/48.rom" - imageAddress1 = 0 - imageBank1 = 0 - imageBank0 = 0 commonBoundary = 0 - imageAddress0 = 32768 ROMto0 = 16383 # memorySize = 65536 @@ -59,9 +53,9 @@ name = "ZX Spectrum 48K" # printCodeFileName = "syserr" # Or custom path to a file [[DEVICE]] schemaPoint = "380,180" - path = "zxspectrum-display.jar" + path = "zxspectrum-ula.jar" settings = {} - name = "zxspectrum-display" + name = "zxspectrum-ula" id = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" type = "DEVICE" diff --git a/application/src/main/java/net/emustudio/application/gui/GuiDialogsImpl.java b/application/src/main/java/net/emustudio/application/gui/GuiDialogsImpl.java index 08a7d5a13..b798225e0 100644 --- a/application/src/main/java/net/emustudio/application/gui/GuiDialogsImpl.java +++ b/application/src/main/java/net/emustudio/application/gui/GuiDialogsImpl.java @@ -212,4 +212,26 @@ public Optional chooseFile(String title, String approveButtonText, Path ba title, approveButtonText, baseDirectory, appendMissingExtension, filters.toArray(FileExtensionsFilter[]::new) ); } + + @Override + public Optional chooseDirectory(String title, String approveButtonText) { + return chooseDirectory(title, approveButtonText, Path.of(System.getProperty("user.dir"))); + } + + @Override + public Optional chooseDirectory(String title, String approveButtonText, Path baseDirectory) { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle(title); + fileChooser.setAcceptAllFileFilterUsed(false); + fileChooser.setApproveButtonText(approveButtonText); + fileChooser.setCurrentDirectory(baseDirectory.toFile()); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + int result = fileChooser.showOpenDialog(parent); + fileChooser.setVisible(true); + if (result == JFileChooser.APPROVE_OPTION) { + return Optional.ofNullable(fileChooser.getSelectedFile()).map(File::toPath); + } + return Optional.empty(); + } } diff --git a/application/src/main/java/net/emustudio/application/gui/NoGuiDialogsImpl.java b/application/src/main/java/net/emustudio/application/gui/NoGuiDialogsImpl.java index bfabf113c..17b94ca06 100644 --- a/application/src/main/java/net/emustudio/application/gui/NoGuiDialogsImpl.java +++ b/application/src/main/java/net/emustudio/application/gui/NoGuiDialogsImpl.java @@ -133,4 +133,14 @@ public Optional chooseFile(String title, String approveButtonText, Path ba boolean appendMissingExtension, List list) { return Optional.empty(); } + + @Override + public Optional chooseDirectory(String title, String approveButtonText) { + return Optional.empty(); + } + + @Override + public Optional chooseDirectory(String title, String approveButtonText, Path baseDirectory) { + return Optional.empty(); + } } diff --git a/application/src/test/java/net/emustudio/application/gui/debugtable/MockHelper.java b/application/src/test/java/net/emustudio/application/gui/debugtable/MockHelper.java index 3788b53aa..70ef6c176 100644 --- a/application/src/test/java/net/emustudio/application/gui/debugtable/MockHelper.java +++ b/application/src/test/java/net/emustudio/application/gui/debugtable/MockHelper.java @@ -27,7 +27,7 @@ import java.util.function.Consumer; import static net.emustudio.application.gui.debugtable.PaginatingDisassembler.INSTR_PER_PAGE; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/build.gradle b/build.gradle index 034ed5510..d55da4a13 100644 --- a/build.gradle +++ b/build.gradle @@ -22,33 +22,33 @@ import java.text.SimpleDateFormat apply from: 'test_report.gradle' ext.versions = [ - slf4j: '2.0.6' + slf4j: '2.0.7' ] ext.libs = [ - emuLib : "net.emustudio:emulib:12.0.0", + emuLib : "net.emustudio:emulib:12.1.0-SNAPSHOT", cpuTestSuite : "net.emustudio:cpu-testsuite_12.0:1.2.0", jcipAnnotations : "net.jcip:jcip-annotations:1.0", - antlr : "org.antlr:antlr4:4.11.1", - antlrRuntime : "org.antlr:antlr4-runtime:4.11.1", + antlr : "org.antlr:antlr4:4.12.0", + antlrRuntime : "org.antlr:antlr4-runtime:4.12.0", slf4JApi : "org.slf4j:slf4j-api:${versions.slf4j}", slf4JSimple : "org.slf4j:slf4j-simple:${versions.slf4j}", slf4JNop : "org.slf4j:slf4j-nop:${versions.slf4j}", - logback : "ch.qos.logback:logback-classic:1.4.5", + logback : "ch.qos.logback:logback-classic:1.4.6", - picocli : "info.picocli:picocli:4.7.0", - picocliAnnotation: "info.picocli:picocli-codegen:4.7.0", + picocli : "info.picocli:picocli:4.7.1", + picocliAnnotation: "info.picocli:picocli-codegen:4.7.1", tomlj : "com.electronwill.night-config:toml:3.6.6", - editor : "com.fifesoft:rsyntaxtextarea:3.3.2", + editor : "com.fifesoft:rsyntaxtextarea:3.3.3", editorDialogs : "com.fifesoft:rstaui:3.3.1", - junit : "junit:junit:4.13.1", - easyMock : "org.easymock:easymock:4.2", - mockito : "org.mockito:mockito-all:1.10.19" + junit : "junit:junit:4.13.2", + easyMock : "org.easymock:easymock:5.1.0", + mockito : "org.mockito:mockito-core:5.2.0" ] allprojects { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d435ce29d..3796d3cd3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/plugins/device/88-sio/src/main/java/net/emustudio/plugins/device/mits88sio/gui/SioGui.java b/plugins/device/88-sio/src/main/java/net/emustudio/plugins/device/mits88sio/gui/SioGui.java index abd92630a..d296e8b6f 100644 --- a/plugins/device/88-sio/src/main/java/net/emustudio/plugins/device/mits88sio/gui/SioGui.java +++ b/plugins/device/88-sio/src/main/java/net/emustudio/plugins/device/mits88sio/gui/SioGui.java @@ -38,6 +38,7 @@ public class SioGui extends JDialog { private final JLabel lblStatus = new JLabel("0x00"); private final JLabel lblStatusLong = new JLabel(". . . . . . . ."); private final JTextField txtAttachedDevice = new JTextField(); + public SioGui(JFrame parent, UART uart) { super(parent); diff --git a/plugins/device/cassette-player/build.gradle b/plugins/device/cassette-player/build.gradle new file mode 100644 index 000000000..dacd46629 --- /dev/null +++ b/plugins/device/cassette-player/build.gradle @@ -0,0 +1,56 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import org.apache.tools.ant.filters.ReplaceTokens + +plugins { + id 'java' + id 'com.adarshr.test-logger' version '3.1.0' +} + +dependencies { + implementation libs.emuLib + implementation libs.slf4JApi + implementation libs.jcipAnnotations +// cpuLib project(":plugins:cpu:8080-cpu") + + testImplementation libs.junit + testImplementation libs.slf4JSimple + testImplementation libs.easyMock +} + +jar { + archiveVersion = '' + manifest { + attributes manifestAttributes('') + } +} + +processResources { + filesMatching("**/*.properties") { + filter ReplaceTokens, tokens: [ + "project.version": project.version, + "today.year" : new Date().format("yyyy") + ] + } +} + +compileJava.options.encoding = 'UTF-8' +compileTestJava.options.encoding = 'UTF-8' +javadoc.options.encoding = 'UTF-8' diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteController.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteController.java new file mode 100644 index 000000000..15fcc8257 --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteController.java @@ -0,0 +1,144 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player; + +import net.emustudio.plugins.device.cassette_player.loaders.Loader; +import net.jcip.annotations.GuardedBy; +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +@ThreadSafe +public class CassetteController implements AutoCloseable { + private final static Logger LOGGER = LoggerFactory.getLogger(CassetteController.class); + + public enum CassetteState { + UNLOADED, + PLAYING, + STOPPED, + CLOSED + } + + private final Loader.CassetteListener listener; + private final ExecutorService playPool = Executors.newFixedThreadPool(1); + + private final Object stateLock = new Object(); + @GuardedBy("stateLock") + private CassetteState state = CassetteState.UNLOADED; + @GuardedBy("stateLock") + private Loader loader; + @GuardedBy("stateLock") + private Future playFuture; + + public CassetteController(Loader.CassetteListener listener) { + this.listener = Objects.requireNonNull(listener); + } + + public CassetteState reset() { + return stop(true); + } + + @Override + public void close() { + synchronized (stateLock) { + this.state = CassetteState.CLOSED; + Future tmpFuture = this.playFuture; + this.playFuture = null; + if (tmpFuture != null) { + tmpFuture.cancel(true); + } + playPool.shutdown(); + } + try { + if (!playPool.awaitTermination(5, TimeUnit.SECONDS)) { + playPool.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + public CassetteState load(Path path) { + Optional optResult = Loader.create(path).map(tmpLoader -> { + synchronized (stateLock) { + switch (state) { + case UNLOADED: + case STOPPED: + this.loader = tmpLoader; + this.state = CassetteState.STOPPED; + } + return this.state; + } + }); + if (optResult.isPresent()) { + return optResult.get(); + } + synchronized (stateLock) { + return this.state; + } + } + + public CassetteState play() { + synchronized (stateLock) { + if (this.state == CassetteState.STOPPED) { + Loader tmpLoader = this.loader; + if (tmpLoader != null) { + this.state = CassetteState.PLAYING; + this.playFuture = playPool.submit(() -> { + try { + tmpLoader.load(listener); + } catch (IOException e) { + LOGGER.error("Could not load cassette", e); + Thread.currentThread().interrupt(); + } + }); + } + } + return this.state; + } + } + + public CassetteState stop(boolean unload) { + synchronized (stateLock) { + if (this.state == CassetteState.PLAYING) { + Future tmpFuture = this.playFuture; + this.playFuture = null; + if (tmpFuture != null) { + tmpFuture.cancel(true); + } + if (unload) { + this.loader = null; + this.state = CassetteState.UNLOADED; + } else { + this.state = CassetteState.STOPPED; + } + } + return this.state; + } + } +} diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteListenerImpl.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteListenerImpl.java new file mode 100644 index 000000000..7cfb13371 --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteListenerImpl.java @@ -0,0 +1,69 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player; + +import net.emustudio.emulib.plugins.device.DeviceContext; +import net.emustudio.plugins.device.cassette_player.gui.CassettePlayerGui; +import net.emustudio.plugins.device.cassette_player.loaders.Loader; + +import java.util.Objects; +import java.util.Optional; + +public class CassetteListenerImpl implements Loader.CassetteListener { + private final DeviceContext lineIn; + private Optional gui = Optional.empty(); + + public CassetteListenerImpl(DeviceContext lineIn) { + this.lineIn = Objects.requireNonNull(lineIn); + } + + public void setGui(CassettePlayerGui gui) { + this.gui = Optional.ofNullable(gui); + } + + @Override + public void onProgram(String filename, int dataLength, int autoStart, int programLength) { + gui.ifPresent(g -> g.setMetadata(filename)); + } + + @Override + public void onNumberArray(String filename, int dataLength, char variable) { + gui.ifPresent(g -> g.setMetadata(filename)); + } + + @Override + public void onStringArray(String filename, int dataLength, char variable) { + gui.ifPresent(g -> g.setMetadata(filename)); + } + + @Override + public void onMemoryBlock(String filename, int dataLength, int startAddress) { + gui.ifPresent(g -> g.setMetadata(filename)); + } + + @Override + public void onData(byte[] data) { + + } + + @Override + public void onPause(int millis) { + gui.ifPresent(g -> g.setMetadata("PAUSE " + millis + "ms")); + } +} diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java new file mode 100644 index 000000000..93a7a6221 --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java @@ -0,0 +1,134 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player; + +import net.emustudio.emulib.plugins.PluginInitializationException; +import net.emustudio.emulib.plugins.annotations.PLUGIN_TYPE; +import net.emustudio.emulib.plugins.annotations.PluginRoot; +import net.emustudio.emulib.plugins.device.AbstractDevice; +import net.emustudio.emulib.plugins.device.DeviceContext; +import net.emustudio.emulib.runtime.ApplicationApi; +import net.emustudio.emulib.runtime.settings.PluginSettings; +import net.emustudio.plugins.device.cassette_player.gui.CassettePlayerGui; + +import javax.swing.*; +import java.util.MissingResourceException; +import java.util.Optional; +import java.util.ResourceBundle; + +@PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "Cassette Player") +public class DeviceImpl extends AbstractDevice { + + private final boolean guiSupported; + private boolean guiIOset = false; + + private CassettePlayerGui gui; + private CassetteController controller; + private CassetteListenerImpl cassetteListener; + + public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { + super(pluginID, applicationApi, settings); + + this.guiSupported = !settings.getBoolean(PluginSettings.EMUSTUDIO_NO_GUI, false); + } + + @SuppressWarnings("unchecked") + @Override + public void initialize() throws PluginInitializationException { + // a cassette player needs a device to which it will write at its own pace + DeviceContext lineIn = applicationApi.getContextPool().getDeviceContext(pluginID, DeviceContext.class); + if (lineIn.getDataType() != Byte.class) { + throw new PluginInitializationException("Could not find Byte device"); + } + this.cassetteListener = new CassetteListenerImpl(lineIn); + this.controller = new CassetteController(cassetteListener); + } + + @Override + public void reset() { + this.controller.reset(); + } + + @Override + public void destroy() { + this.controller.close(); + if (guiIOset || gui != null) { + gui = null; + cassetteListener.setGui(null); + guiIOset = false; + } + } + + @Override + public void showSettings(JFrame jFrame) { + // we don't have settings GUI + } + + @Override + public boolean isShowSettingsSupported() { + return false; + } + + @Override + public void showGUI(JFrame parent) { + if (guiSupported) { + if (!guiIOset) { + this.gui = new CassettePlayerGui(parent, applicationApi.getDialogs(), controller); + guiIOset = true; + this.cassetteListener.setGui(gui); + this.gui.setVisible(true); + } + } + } + + @Override + public boolean isGuiSupported() { + return guiSupported; + } + + + @Override + public String getVersion() { + return getResourceBundle().map(b -> b.getString("version")).orElse("(unknown)"); + } + + @Override + public String getCopyright() { + return getResourceBundle().map(b -> b.getString("copyright")).orElse("(unknown)"); + } + + @Override + public String getDescription() { + return "Cassette Player"; + } + + @Override + public boolean isAutomationSupported() { + return true; + } + + + private Optional getResourceBundle() { + try { + return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.device.zxspectrum.display.version")); + } catch (MissingResourceException e) { + return Optional.empty(); + } + } +} diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/CassettePlayerGui.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/CassettePlayerGui.java new file mode 100644 index 000000000..df785ecb2 --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/CassettePlayerGui.java @@ -0,0 +1,231 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player.gui; + +import net.emustudio.emulib.runtime.interaction.BrowseButton; +import net.emustudio.emulib.runtime.interaction.CachedComboBoxModel; +import net.emustudio.emulib.runtime.interaction.Dialogs; +import net.emustudio.plugins.device.cassette_player.CassetteController; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.nio.file.Path; +import java.util.Objects; + +public class CassettePlayerGui extends JDialog { + private final JButton btnBrowse; + private final JButton btnRefresh = new JButton("Refresh"); + private final JButton btnLoad = new JButton("Load"); + private final JButton btnPlay = new JButton("Play"); + private final JButton btnStop = new JButton("Stop"); + private final JButton btnUnload = new JButton("Unload"); + private final JLabel lblHeader = new JLabel(); + private final JLabel lblStatus = new JLabel("STOPPED"); + private final JComboBox cmbDirs = new JComboBox<>(); + private final JList lstTapes = new JList<>(); + + private final CachedComboBoxModel cmbDirsModel = new CachedComboBoxModel<>(); + private final TapesListModel lstTapesModel = new TapesListModel(); + private final CassetteController controller; + + public CassettePlayerGui(JFrame parent, Dialogs dialogs, CassetteController controller) { + super(parent); + this.controller = Objects.requireNonNull(controller); + this.btnBrowse = new BrowseButton(dialogs, "Select Directory", "Select", p -> { + cmbDirsModel.add(p); + cmbDirs.setSelectedIndex(0); + }); + + initComponents(); + setLocationRelativeTo(parent); + } + + public void setMetadata(String metadata) { + try { + SwingUtilities.invokeAndWait(() -> lblHeader.setText(metadata)); + } catch (Exception ignored) { + + } + } + + private void initComponents() { + JPanel panelTapeSelection = new JPanel(); + JLabel lblTapes = new JLabel("Available tapes:"); + JScrollPane scrollTapes = new JScrollPane(); + JPanel panelTapeControl = new JPanel(); + JPanel panelMetadata = new JPanel(); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + getRootPane().registerKeyboardAction(e -> dispose(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + setTitle("Cassette Player"); + + lstTapes.setModel(lstTapesModel); + + cmbDirs.setModel(cmbDirsModel); + cmbDirs.addActionListener(e -> { + Path path = (Path) cmbDirs.getSelectedItem(); + if (path != null) { + lstTapesModel.reset(path); + } + }); + + btnRefresh.addActionListener(e -> lstTapesModel.refresh()); + btnLoad.addActionListener(e -> { + int index = lstTapes.getSelectedIndex(); + if (index != -1) { + controller.load(lstTapesModel.getFilePath(index)); + } + }); + btnPlay.addActionListener(e -> { + CassetteController.CassetteState state = controller.play(); + lblStatus.setText(state.name()); + }); + btnStop.addActionListener(e -> { + CassetteController.CassetteState state = controller.stop(false); + lblStatus.setText(state.name()); + }); + btnUnload.addActionListener(e -> { + CassetteController.CassetteState state = controller.stop(true); + lblStatus.setText(state.name()); + }); + + panelTapeSelection.setBorder(BorderFactory.createTitledBorder("Tape selection")); + + scrollTapes.setViewportView(lstTapes); + + GroupLayout panelTapeSelectionLayout = new GroupLayout(panelTapeSelection); + panelTapeSelection.setLayout(panelTapeSelectionLayout); + panelTapeSelectionLayout.setHorizontalGroup( + panelTapeSelectionLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(panelTapeSelectionLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelTapeSelectionLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(scrollTapes, GroupLayout.DEFAULT_SIZE, 349, Short.MAX_VALUE) + .addGroup(panelTapeSelectionLayout.createSequentialGroup() + .addComponent(btnRefresh) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnBrowse) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnLoad) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnUnload)) + .addGroup(panelTapeSelectionLayout.createSequentialGroup() + .addComponent(lblTapes) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(cmbDirs, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + panelTapeSelectionLayout.setVerticalGroup( + panelTapeSelectionLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(panelTapeSelectionLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblTapes) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cmbDirs, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(scrollTapes, GroupLayout.DEFAULT_SIZE, 197, Short.MAX_VALUE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(panelTapeSelectionLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(btnBrowse) + .addComponent(btnUnload) + .addComponent(btnLoad) + .addComponent(btnRefresh)) + .addContainerGap()) + ); + + panelTapeControl.setBorder(BorderFactory.createTitledBorder("Tape control")); + + lblStatus.setFont(new java.awt.Font("Monospaced", Font.BOLD, 18)); + lblStatus.setHorizontalAlignment(SwingConstants.CENTER); + + panelMetadata.setBorder(BorderFactory.createTitledBorder("Metadata")); + + lblHeader.setFont(new java.awt.Font("Monospaced", Font.PLAIN, 15)); + + GroupLayout panelMetadataLayout = new GroupLayout(panelMetadata); + panelMetadata.setLayout(panelMetadataLayout); + panelMetadataLayout.setHorizontalGroup( + panelMetadataLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(panelMetadataLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblHeader, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + panelMetadataLayout.setVerticalGroup( + panelMetadataLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(panelMetadataLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblHeader) + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + GroupLayout panelTapeControlLayout = new GroupLayout(panelTapeControl); + panelTapeControl.setLayout(panelTapeControlLayout); + panelTapeControlLayout.setHorizontalGroup( + panelTapeControlLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(panelTapeControlLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelTapeControlLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(lblStatus, GroupLayout.DEFAULT_SIZE, 330, Short.MAX_VALUE) + .addComponent(panelMetadata, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(panelTapeControlLayout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(btnPlay) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnStop))) + .addContainerGap()) + ); + panelTapeControlLayout.setVerticalGroup( + panelTapeControlLayout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(panelTapeControlLayout.createSequentialGroup() + .addComponent(lblStatus) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelMetadata, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addGroup(panelTapeControlLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(btnPlay) + .addComponent(btnStop)) + .addContainerGap()) + ); + + GroupLayout layout = new GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(panelTapeSelection, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelTapeControl, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) + .addComponent(panelTapeControl, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelTapeSelection, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + + pack(); + } +} diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/TapesListModel.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/TapesListModel.java new file mode 100644 index 000000000..5d79afca7 --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/TapesListModel.java @@ -0,0 +1,68 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player.gui; + +import net.jcip.annotations.NotThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@NotThreadSafe +public class TapesListModel extends DefaultListModel { + private final static Logger LOGGER = LoggerFactory.getLogger(TapesListModel.class); + private List files = Collections.emptyList(); + private Path directory; + + public void refresh() { + reset(directory); + } + + public void reset(Path directory) { + this.directory = directory; + clear(); + this.files = listPaths(directory); + for (Path file : files) { + addElement(file.getFileName().toString()); + } + } + + public Path getFilePath(int index) { + return files.get(index); + } + + private static List listPaths(Path directory) { + if (directory == null) { + return Collections.emptyList(); + } + try(Stream stream = Files.list(directory)) { + return stream.collect(Collectors.toList()); + } catch (IOException e) { + LOGGER.error("Could not load tape files from directory: " + directory, e); + } + return Collections.emptyList(); + } +} diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/Loader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/Loader.java new file mode 100644 index 000000000..390971b26 --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/Loader.java @@ -0,0 +1,105 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player.loaders; + +import net.jcip.annotations.ThreadSafe; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public interface Loader { + + Map> LOADERS = Map.of( + "tap", TapLoader::new + ); + + static Optional create(Path path) { + int index = path.toString().lastIndexOf("."); + String extension = (index == -1) ? + "" : path.toString().substring(index + 1).toLowerCase(Locale.ENGLISH); + + return LOADERS + .entrySet() + .stream() + .filter(l -> l.getKey().equals(extension)) + .findFirst() + .map(Map.Entry::getValue) + .map(l -> l.apply(path)); + } + + @ThreadSafe + interface CassetteListener { + /** + * Data block will be a program in BASIC. + * + * @param fileName BASIC file name + * @param dataLength data block length + * @param autoStart line number + * @param programLength program length = start of variable area + */ + void onProgram(String fileName, int dataLength, int autoStart, int programLength); + + /** + * Data block will be a number array variable + * + * @param filename BASIC file name + * @param dataLength data block length + * @param variable variable name 'A'..'Z' + */ + void onNumberArray(String filename, int dataLength, char variable); + + /** + * Data block will be a String array variable + * + * @param filename BASIC file name + * @param dataLength data block length + * @param variable variable name 'A'..'Z' + */ + void onStringArray(String filename, int dataLength, char variable); + + /** + * Data block will be a memory block + * + * @param filename BASIC file name + * @param dataLength data block length + * @param startAddress starting address in memory + */ + void onMemoryBlock(String filename, int dataLength, int startAddress); + + /** + * Raw data block. The type is determined by a previous onXXX call + * + * @param data data + */ + void onData(byte[] data); + + /** + * Pause given milliseconds + * + * @param millis milliseconds to pause + */ + void onPause(int millis); + } + + void load(CassetteListener listener) throws IOException; +} diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java new file mode 100644 index 000000000..99a78f81d --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java @@ -0,0 +1,88 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player.loaders; + +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Path; +import java.util.Objects; + +// https://sinclair.wiki.zxnet.co.uk/wiki/TAP_format +// https://documentation.help/BASin/format_tape.html +@ThreadSafe +public class TapLoader implements Loader { + private final static Logger LOGGER = LoggerFactory.getLogger(TapLoader.class); + private final Path path; + + public TapLoader(Path path) { + this.path = Objects.requireNonNull(path); + } + + @Override + public void load(CassetteListener listener) throws IOException { + try (FileInputStream stream = new FileInputStream(path.toFile())) { + interpret(stream.readAllBytes(), listener); + } + } + + private void interpret(byte[] content, CassetteListener listener) { + ByteBuffer buffer = ByteBuffer.wrap(content); + buffer.order(ByteOrder.LITTLE_ENDIAN); + while (buffer.position() < buffer.limit() && !Thread.currentThread().isInterrupted()) { + int blockLength = buffer.getShort() & 0xFFFF; + int flagByte = buffer.get() & 0xFF; + + if (flagByte == 0) { + TapTzxHeader header = TapTzxHeader.parse(buffer); + switch (header.id) { + case 0: // program + listener.onProgram(header.fileName, header.dataLength, header.parameter1, header.parameter2); + break; + case 1: // number array + listener.onNumberArray(header.fileName, header.dataLength, header.getVariable()); + break; + case 2: // String array + listener.onStringArray(header.fileName, header.dataLength, header.getVariable()); + break; + case 3: // Memory block + listener.onMemoryBlock(header.fileName, header.dataLength, header.parameter1); + break; + default: + LOGGER.warn("TAP: Unknown header ID: " + header.id); + } + } else { + byte[] data = new byte[blockLength - 2]; + buffer.get(data); + + if (flagByte == 255) { + listener.onData(data); + } else { + LOGGER.warn("TAP: Unknwon flag: " + flagByte); + } + } + buffer.get(); // checksum + } + } +} diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapTzxHeader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapTzxHeader.java new file mode 100644 index 000000000..205582055 --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapTzxHeader.java @@ -0,0 +1,56 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player.loaders; + +import net.jcip.annotations.Immutable; + +import java.nio.ByteBuffer; + +@Immutable +public class TapTzxHeader { + final int id; + final String fileName; + final int dataLength; + final int parameter1; + final int parameter2; + + public TapTzxHeader(int id, String fileName, int dataLength, int parameter1, int parameter2) { + this.id = id; + this.fileName = fileName; + this.dataLength = dataLength; + this.parameter1 = parameter1; + this.parameter2 = parameter2; + } + + public char getVariable() { + return (char) ((parameter1 >>> 8) & 0xFF); + } + + public static TapTzxHeader parse(ByteBuffer buffer) { + int headerFlag = buffer.get() & 0xFF; + byte[] fileName = new byte[10]; + buffer.get(fileName); // filename + int dataLength = buffer.getShort() & 0xFFFF; // length + + int parameter1 = buffer.getShort() & 0xFFFF; + int parameter2 = buffer.getShort() & 0xFFFF; + + return new TapTzxHeader(headerFlag, new String(fileName), dataLength, parameter1, parameter2); + } +} diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TzxLoader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TzxLoader.java new file mode 100644 index 000000000..c668c5e74 --- /dev/null +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TzxLoader.java @@ -0,0 +1,90 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.cassette_player.loaders; + +import net.jcip.annotations.NotThreadSafe; +import net.jcip.annotations.ThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Path; +import java.util.Objects; + +@ThreadSafe +public class TzxLoader implements Loader { + private final static Logger LOGGER = LoggerFactory.getLogger(TzxLoader.class); + private final Path path; + + public TzxLoader(Path path) { + this.path = Objects.requireNonNull(path); + } + + @Override + public void load(CassetteListener listener) throws IOException { + try (FileInputStream stream = new FileInputStream(path.toFile())) { + interpret(stream.readAllBytes(), listener); + } + } + + private void interpret(byte[] content, CassetteListener listener) { + ByteBuffer buffer = ByteBuffer.wrap(content); + buffer.order(ByteOrder.LITTLE_ENDIAN); + while (buffer.position() < buffer.limit()) { + int id = buffer.get() & 0xFF; // 16 for ROM-saved block + int pause = buffer.getShort() & 0xFFFF; // pause after this block + int blockLength = buffer.getShort() & 0xFFFF; + int flagByte = buffer.get() & 0xFF; + + if (flagByte == 0) { + TapTzxHeader header = TapTzxHeader.parse(buffer); + switch (header.id) { + case 0: // program + listener.onProgram(header.fileName, header.dataLength, header.parameter1, header.parameter2); + break; + case 1: // number array + listener.onNumberArray(header.fileName, header.dataLength, header.getVariable()); + break; + case 2: // String array + listener.onStringArray(header.fileName, header.dataLength, header.getVariable()); + break; + case 3: // Memory block + listener.onMemoryBlock(header.fileName, header.dataLength, header.parameter1); + break; + default: + LOGGER.warn("TZX: Unknown header ID: " + header.id); + } + } else { + byte[] data = new byte[blockLength - 2]; + buffer.get(data); + + if (flagByte == 255) { + listener.onData(data); + } else { + LOGGER.warn("TZX: Unknown flag: " + flagByte); + } + } + buffer.get(); // checksum + listener.onPause(pause); + } + } +} diff --git a/plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/version.properties b/plugins/device/cassette-player/src/main/resources/net/emustudio/plugins/device/cassette_player/version.properties similarity index 100% rename from plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/version.properties rename to plugins/device/cassette-player/src/main/resources/net/emustudio/plugins/device/cassette_player/version.properties diff --git a/plugins/device/zxspectrum-display/build.gradle b/plugins/device/zxspectrum-ula/build.gradle similarity index 100% rename from plugins/device/zxspectrum-display/build.gradle rename to plugins/device/zxspectrum-ula/build.gradle diff --git a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/DeviceImpl.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java similarity index 68% rename from plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/DeviceImpl.java rename to plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java index 85210849e..5c16b014e 100644 --- a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/DeviceImpl.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java @@ -16,20 +16,24 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package net.emustudio.plugins.device.zxspectrum.display; +package net.emustudio.plugins.device.zxspectrum.ula; import net.emustudio.emulib.plugins.PluginInitializationException; import net.emustudio.emulib.plugins.annotations.PLUGIN_TYPE; import net.emustudio.emulib.plugins.annotations.PluginRoot; import net.emustudio.emulib.plugins.device.AbstractDevice; +import net.emustudio.emulib.plugins.device.DeviceContext; import net.emustudio.emulib.plugins.memory.MemoryContext; import net.emustudio.emulib.runtime.ApplicationApi; -import net.emustudio.emulib.runtime.ContextNotFoundException; +import net.emustudio.emulib.runtime.ContextAlreadyRegisteredException; +import net.emustudio.emulib.runtime.ContextPool; +import net.emustudio.emulib.runtime.InvalidContextException; import net.emustudio.emulib.runtime.interaction.GuiUtils; import net.emustudio.emulib.runtime.settings.PluginSettings; import net.emustudio.plugins.cpu.intel8080.api.Context8080; -import net.emustudio.plugins.device.zxspectrum.display.gui.Keyboard; -import net.emustudio.plugins.device.zxspectrum.display.gui.TerminalWindow; +import net.emustudio.plugins.device.zxspectrum.ula.api.LineInPort; +import net.emustudio.plugins.device.zxspectrum.ula.gui.Keyboard; +import net.emustudio.plugins.device.zxspectrum.ula.gui.TerminalWindow; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,9 +42,9 @@ import java.util.Optional; import java.util.ResourceBundle; -@PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "ZX Spectrum48K") +@PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "ZX Spectrum48K ULA") public class DeviceImpl extends AbstractDevice { - private static final Logger LOGGER = LoggerFactory.getLogger(DeviceImpl.class); + private final static Logger LOGGER = LoggerFactory.getLogger(DeviceImpl.class); private final boolean guiSupported; private final Keyboard keyboard = new Keyboard(); @@ -53,25 +57,31 @@ public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings s super(pluginID, applicationApi, settings); this.guiSupported = !settings.getBoolean(PluginSettings.EMUSTUDIO_NO_GUI, false); + + try { + ContextPool contextPool = applicationApi.getContextPool(); + contextPool.register(pluginID, new LineInPort(), DeviceContext.class); + } catch (InvalidContextException | ContextAlreadyRegisteredException e) { + LOGGER.error("Could not register memory context", e); + applicationApi.getDialogs().showError( + "Could not register memory. Please see log file for more details", getTitle() + ); + } } @SuppressWarnings("unchecked") @Override public void initialize() throws PluginInitializationException { - try { - MemoryContext memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); - if (memory.getDataType() != Byte.class) { - throw new PluginInitializationException("Could not find Byte-cell memory"); - } - Context8080 cpu = applicationApi.getContextPool().getCPUContext(pluginID, Context8080.class); + MemoryContext memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); + if (memory.getDataType() != Byte.class) { + throw new PluginInitializationException("Could not find Byte-cell memory"); + } + Context8080 cpu = applicationApi.getContextPool().getCPUContext(pluginID, Context8080.class); - this.ula = new ULA(memory, cpu); - keyboard.addOnKeyListener(ula); + this.ula = new ULA(memory, cpu); + keyboard.addOnKeyListener(ula); - cpu.attachDevice(0xFE, ula); - } catch (ContextNotFoundException e) { - LOGGER.warn("The terminal is not connected to any I/O device."); - } + cpu.attachDevice(0xFE, ula); } @Override @@ -129,7 +139,7 @@ public String getCopyright() { @Override public String getDescription() { - return "ZX Spectrum48K"; + return "ZX Spectrum48K ULA"; } @Override @@ -140,7 +150,7 @@ public boolean isAutomationSupported() { private Optional getResourceBundle() { try { - return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.device.zxspectrum.display.version")); + return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.device.zxspectrum.ula.version")); } catch (MissingResourceException e) { return Optional.empty(); } diff --git a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/ULA.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java similarity index 75% rename from plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/ULA.java rename to plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java index 768a03d14..9c74e58d5 100644 --- a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/ULA.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java @@ -16,11 +16,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package net.emustudio.plugins.device.zxspectrum.display; +package net.emustudio.plugins.device.zxspectrum.ula; import net.emustudio.emulib.plugins.memory.MemoryContext; import net.emustudio.plugins.cpu.intel8080.api.Context8080; -import net.emustudio.plugins.device.zxspectrum.display.gui.Keyboard; +import net.emustudio.plugins.device.zxspectrum.ula.gui.Keyboard; import java.awt.event.KeyEvent; import java.util.Arrays; @@ -139,7 +139,7 @@ public byte read(int portAddress) { // A zero in one of the five lowest bits means that the corresponding key is pressed. // If more than one address line is made low, the result is the logical AND of all single inputs - byte result = (byte) 0xBF; + byte result = (byte) 0xBF; // 1011 1111 // EAR on if ((portAddress & 0xFEFE) == 0xFEFE) { // SHIFT, Z, X, C, V result &= keymap[0]; @@ -174,10 +174,8 @@ public byte read(int portAddress) { @Override public void write(int portAddress, byte data) { this.borderColor = data & 7; - if (((data & 0x10) == 0x10) || ((data & 0x8) == 0)) { - // the EAR and MIC sockets are connected only by resistors, so activating one activates the other - microphoneAndEar = true; - } + // the EAR and MIC sockets are connected only by resistors, so activating one activates the other + microphoneAndEar = ((data & 0x10) == 0x10) || ((data & 0x8) == 0); } @Override @@ -192,10 +190,21 @@ public String toString() { @Override public void onKeyUp(byte data) { + + // // symshift + // " <>" // A10 + // "!@#$%" // A11 + // "_)('&" // A12 + // "\"; " // A13 + // " =+-^" // A14 + // " .,*"; // A15 + switch (data) { case KeyEvent.VK_SHIFT: keymap[0] |= 0x1; break; + case ':': // deactivates symshift + keymap[7] |= 0x2; case 'z': case 'Z': keymap[0] |= 0x2; @@ -204,10 +213,14 @@ public void onKeyUp(byte data) { case 'X': keymap[0] |= 0x4; break; + case '?': // deactivates symshift + keymap[7] |= 0x2; case 'c': case 'C': keymap[0] |= 0x8; break; + case '/': // deactivates symshift + keymap[7] |= 0x2; case 'v': case 'V': keymap[0] |= 0x10; @@ -244,52 +257,82 @@ public void onKeyUp(byte data) { case 'E': keymap[2] |= 0x4; break; + case '<': // deactivates symshift + keymap[7] |= 0x2; case 'r': case 'R': keymap[2] |= 0x8; break; + case '>': // deactivates symshift + keymap[7] |= 0x2; case 't': case 'T': keymap[2] |= 0x10; break; + case '!': // deactivates symshift + keymap[7] |= 0x2; case '1': keymap[3] |= 0x1; break; + case '@': // deactivates symshift + keymap[7] |= 0x2; case '2': keymap[3] |= 0x2; break; + case '#': // deactivates symshift + keymap[7] |= 0x2; case '3': keymap[3] |= 0x4; break; + case '$': // deactivates symshift + keymap[7] |= 0x2; case '4': keymap[3] |= 0x8; break; + case '%': // deactivates symshift + keymap[7] |= 0x2; case '5': keymap[3] |= 0x10; break; + case '_': // deactivates symshift + keymap[7] |= 0x2; case '0': keymap[4] |= 0x1; break; + case ')': // deactivates symshift + keymap[7] |= 0x2; case '9': keymap[4] |= 0x2; break; + case '(': // deactivates symshift + keymap[7] |= 0x2; case '8': keymap[4] |= 0x4; break; + case '\'': // deactivates symshift + keymap[7] |= 0x2; case '7': keymap[4] |= 0x8; break; + case '&': // deactivates symshift + keymap[7] |= 0x2; case '6': keymap[4] |= 0x10; break; + case '\\': // deactivates symshift + keymap[7] |= 0x2; case 'p': case 'P': keymap[5] |= 0x1; break; + case '"': // deactivates symshift + keymap[7] |= 0x2; case 'o': case 'O': keymap[5] |= 0x2; break; + case ';': // deactivates symshift + keymap[7] |= 0x2; case 'i': case 'I': keymap[5] |= 0x4; @@ -305,18 +348,26 @@ public void onKeyUp(byte data) { case KeyEvent.VK_ENTER: keymap[6] |= 0x1; break; + case '=': // deactivates symshift + keymap[7] |= 0x2; case 'l': case 'L': keymap[6] |= 0x2; break; + case '+': // deactivates symshift + keymap[7] |= 0x2; case 'k': case 'K': keymap[6] |= 0x4; break; + case '-': // deactivates symshift + keymap[7] |= 0x2; case 'j': case 'J': keymap[6] |= 0x8; break; + case '^': // deactivates symshift + keymap[7] |= 0x2; case 'h': case 'H': keymap[6] |= 0x10; @@ -324,15 +375,20 @@ public void onKeyUp(byte data) { case ' ': keymap[7] |= 0x1; break; - // SYM SHFT ??? + case '.': // deactivates symshift + keymap[7] |= 0x2; case 'm': case 'M': keymap[7] |= 0x4; break; + case ',': // deactivates symshift + keymap[7] |= 0x2; case 'n': case 'N': keymap[7] |= 0x8; break; + case '*': // deactivates symshift + keymap[7] |= 0x2; case 'b': case 'B': keymap[7] |= 0x10; @@ -346,6 +402,8 @@ public void onKeyDown(byte data) { case KeyEvent.VK_SHIFT: keymap[0] &= 0xFE; break; + case ':': // activates symshift + keymap[7] &= 0xFD; case 'z': case 'Z': keymap[0] &= 0xFD; @@ -354,10 +412,14 @@ public void onKeyDown(byte data) { case 'X': keymap[0] &= 0xFB; break; + case '?': // activates symshift + keymap[7] &= 0xFD; case 'c': case 'C': keymap[0] &= 0xF7; break; + case '/': // activates symshift + keymap[7] &= 0xFD; case 'v': case 'V': keymap[0] &= 0xEF; @@ -394,52 +456,82 @@ public void onKeyDown(byte data) { case 'E': keymap[2] &= 0xFB; break; + case '<': // activates symshift + keymap[7] &= 0xFD; case 'r': case 'R': keymap[2] &= 0xF7; break; + case '>': // activates symshift + keymap[7] &= 0xFD; case 't': case 'T': keymap[2] &= 0xEF; break; + case '!': // activates symshift + keymap[7] &= 0xFD; case '1': keymap[3] &= 0xFE; break; + case '@': // activates symshift + keymap[7] &= 0xFD; case '2': keymap[3] &= 0xFD; break; + case '#': // activates symshift + keymap[7] &= 0xFD; case '3': keymap[3] &= 0xFB; break; + case '$': // activates symshift + keymap[7] &= 0xFD; case '4': keymap[3] &= 0xF7; break; + case '%': // activates symshift + keymap[7] &= 0xFD; case '5': keymap[3] &= 0xEF; break; + case '_': // activates symshift + keymap[7] &= 0xFD; case '0': keymap[4] &= 0xFE; break; + case ')': // activates symshift + keymap[7] &= 0xFD; case '9': keymap[4] &= 0xFD; break; + case '(': // activates symshift + keymap[7] &= 0xFD; case '8': keymap[4] &= 0xFB; break; + case '\'': // activates symshift + keymap[7] &= 0xFD; case '7': keymap[4] &= 0xF7; break; + case '&': // activates symshift + keymap[7] &= 0xFD; case '6': keymap[4] &= 0xEF; break; + case '\\': // activates symshift + keymap[7] &= 0xFD; case 'p': case 'P': keymap[5] &= 0xFE; break; + case '"': // activates symshift + keymap[7] &= 0xFD; case 'o': case 'O': keymap[5] &= 0xFD; break; + case ';': // activates symshift + keymap[7] &= 0xFD; case 'i': case 'I': keymap[5] &= 0xFB; @@ -455,18 +547,26 @@ public void onKeyDown(byte data) { case KeyEvent.VK_ENTER: keymap[6] &= 0xFE; break; + case '=': // activates symshift + keymap[7] &= 0xFD; case 'l': case 'L': keymap[6] &= 0xFD; break; + case '+': // activates symshift + keymap[7] &= 0xFD; case 'k': case 'K': keymap[6] &= 0xFB; break; + case '-': // activates symshift + keymap[7] &= 0xFD; case 'j': case 'J': keymap[6] &= 0xF7; break; + case '^': // activates symshift + keymap[7] &= 0xFD; case 'h': case 'H': keymap[6] &= 0xEF; @@ -474,15 +574,20 @@ public void onKeyDown(byte data) { case ' ': keymap[7] &= 0xFE; break; - // SYM SHFT ??? + case '.': // activates symshift + keymap[7] &= 0xFD; case 'm': case 'M': keymap[7] &= 0xFB; break; + case ',': // activates symshift + keymap[7] &= 0xFD; case 'n': case 'N': keymap[7] &= 0xF7; break; + case '*': // activates symshift + keymap[7] &= 0xFD; case 'b': case 'B': keymap[7] &= 0xEF; diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java new file mode 100644 index 000000000..c7beed31a --- /dev/null +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java @@ -0,0 +1,42 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.zxspectrum.ula.api; + +import net.emustudio.emulib.plugins.annotations.PluginContext; +import net.emustudio.emulib.plugins.device.DeviceContext; + +// cassette receiver +@PluginContext(id = "line-in port") +public class LineInPort implements DeviceContext { + + @Override + public Byte readData() { + return null; + } + + @Override + public void writeData(Byte data) { + System.out.println("Received: " + Integer.toHexString(data & 0xFF)); + } + + @Override + public Class getDataType() { + return Byte.class; + } +} diff --git a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/DisplayCanvas.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java similarity index 96% rename from plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/DisplayCanvas.java rename to plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java index d18f43951..1418f51ba 100644 --- a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/DisplayCanvas.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java @@ -16,10 +16,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package net.emustudio.plugins.device.zxspectrum.display.gui; +package net.emustudio.plugins.device.zxspectrum.ula.gui; import net.emustudio.emulib.plugins.cpu.TimedEventsProcessor; -import net.emustudio.plugins.device.zxspectrum.display.ULA; +import net.emustudio.plugins.device.zxspectrum.ula.ULA; import java.awt.*; import java.awt.image.BufferStrategy; @@ -29,8 +29,8 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import static net.emustudio.plugins.device.zxspectrum.display.ULA.SCREEN_HEIGHT; -import static net.emustudio.plugins.device.zxspectrum.display.ULA.SCREEN_WIDTH; +import static net.emustudio.plugins.device.zxspectrum.ula.ULA.SCREEN_HEIGHT; +import static net.emustudio.plugins.device.zxspectrum.ula.ULA.SCREEN_WIDTH; // https://worldofspectrum.org/faq/reference/48kreference.htm diff --git a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/Keyboard.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/Keyboard.java similarity index 97% rename from plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/Keyboard.java rename to plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/Keyboard.java index a3c004b7a..e1b8325e2 100644 --- a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/Keyboard.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/Keyboard.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package net.emustudio.plugins.device.zxspectrum.display.gui; +package net.emustudio.plugins.device.zxspectrum.ula.gui; import net.emustudio.emulib.runtime.interaction.GuiUtils; import net.jcip.annotations.ThreadSafe; diff --git a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/TerminalWindow.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/TerminalWindow.java similarity index 96% rename from plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/TerminalWindow.java rename to plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/TerminalWindow.java index 2f7ff114e..21b73efff 100644 --- a/plugins/device/zxspectrum-display/src/main/java/net/emustudio/plugins/device/zxspectrum/display/gui/TerminalWindow.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/TerminalWindow.java @@ -16,9 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package net.emustudio.plugins.device.zxspectrum.display.gui; +package net.emustudio.plugins.device.zxspectrum.ula.gui; -import net.emustudio.plugins.device.zxspectrum.display.ULA; +import net.emustudio.plugins.device.zxspectrum.ula.ULA; import javax.swing.*; diff --git a/plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/16_ascii.png b/plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/16_ascii.png similarity index 100% rename from plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/16_ascii.png rename to plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/16_ascii.png diff --git a/plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/16_circle_blue.png b/plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/16_circle_blue.png similarity index 100% rename from plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/16_circle_blue.png rename to plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/16_circle_blue.png diff --git a/plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/16_circle_green.png b/plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/16_circle_green.png similarity index 100% rename from plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/16_circle_green.png rename to plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/16_circle_green.png diff --git a/plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/16_circle_red.png b/plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/16_circle_red.png similarity index 100% rename from plugins/device/zxspectrum-display/src/main/resources/net/emustudio/plugins/device/zxspectrum/display/16_circle_red.png rename to plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/16_circle_red.png diff --git a/plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/version.properties b/plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/version.properties new file mode 100644 index 000000000..8061ed30f --- /dev/null +++ b/plugins/device/zxspectrum-ula/src/main/resources/net/emustudio/plugins/device/zxspectrum/ula/version.properties @@ -0,0 +1,20 @@ +# +# This file is part of emuStudio. +# +# Copyright (C) 2006-2023 Peter Jakubčo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +version=@project.version@ +copyright=\u00A9 Copyright 2006-@today.year@, Peter Jakubčo diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryImpl.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryImpl.java index 51f848189..353dd2a4e 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryImpl.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryImpl.java @@ -35,6 +35,8 @@ import org.slf4j.LoggerFactory; import javax.swing.*; +import java.io.FileNotFoundException; +import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.MissingResourceException; @@ -144,7 +146,7 @@ private void loadRomRanges() throws PluginInitializationException { } } - private void loadImages() throws PluginInitializationException { + private void loadImages() { for (int i = 0; ; i++) { try { Optional imageName = settings.getString("imageName" + i).map(Path::of); @@ -157,14 +159,16 @@ private void loadImages() throws PluginInitializationException { break; } } catch (NumberFormatException e) { - throw new PluginInitializationException(this, "Could not parse image address or bank", e); + LOGGER.error("Could not parse image address or bank", e); + } catch (FileNotFoundException e) { + LOGGER.error("Could not load image {}", settings.getString("imageName" + i), e); } catch (Exception e) { - throw new PluginInitializationException(this, e); + LOGGER.error("Could not load image due to unknown reason", e); } } } - public void loadImage(Path imagePath, int address, int bank) throws Exception { + public void loadImage(Path imagePath, int address, int bank) throws IOException { Loader.MemoryBank memoryBank = Loader.MemoryBank.of(bank, address); Loader loader = Loader.createLoader(imagePath); loader.load(imagePath, context, memoryBank); diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/gui/MemoryGui.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/gui/MemoryGui.java index 3d7934689..b0a511127 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/gui/MemoryGui.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/gui/MemoryGui.java @@ -116,14 +116,6 @@ public MemoryGui(JFrame parent, MemoryImpl memory, MemoryContextImpl context, Pl } }); - super.addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent e) { - dispose(); - } - }); - tableModel.addTableModelListener(e -> { int row = e.getFirstRow(); int column = e.getColumn(); diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/BinaryLoader.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/BinaryLoader.java index 62c31c1b6..b62a9243e 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/BinaryLoader.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/BinaryLoader.java @@ -22,6 +22,7 @@ import net.emustudio.plugins.memory.bytemem.api.ByteMemoryContext; import java.io.FileInputStream; +import java.io.IOException; import java.nio.file.Path; public class BinaryLoader implements Loader { @@ -32,14 +33,14 @@ public boolean isMemoryAddressAware() { } @Override - public void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws Exception { + public void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws IOException { int oldBank = memory.getSelectedBank(); try (FileInputStream stream = new FileInputStream(path.toFile())) { memory.selectBank(bank.bank); byte[] content = stream.readAllBytes(); memory.write(bank.address, NumberUtils.nativeBytesToBytes(content)); - } catch (Exception e) { + } catch (IOException e) { memory.selectBank(oldBank); throw e; } diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/HexLoader.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/HexLoader.java index 49ecb9fd2..d11188146 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/HexLoader.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/HexLoader.java @@ -21,6 +21,7 @@ import net.emustudio.emulib.runtime.io.IntelHEX; import net.emustudio.plugins.memory.bytemem.api.ByteMemoryContext; +import java.io.IOException; import java.nio.file.Path; public class HexLoader implements Loader { @@ -31,12 +32,12 @@ public boolean isMemoryAddressAware() { } @Override - public void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws Exception { + public void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws IOException { int oldBank = memory.getSelectedBank(); try { memory.selectBank(bank.bank); // need to do it before loading IntelHEX.loadIntoMemory(path.toFile(), memory, p -> p); - } catch (Exception e) { + } catch (IOException e) { memory.selectBank(oldBank); throw e; } diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/Loader.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/Loader.java index 7e51e3c48..d95b0036a 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/Loader.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/Loader.java @@ -20,6 +20,7 @@ import net.emustudio.plugins.memory.bytemem.api.ByteMemoryContext; +import java.io.IOException; import java.nio.file.Path; import java.util.Locale; import java.util.Map; @@ -50,7 +51,7 @@ public interface Loader { * @param memory memory context * @param bank memory bank + address */ - void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws Exception; + void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws IOException; class MemoryBank { final int bank; diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/TapLoader.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/TapLoader.java index 04c88452b..549b56895 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/TapLoader.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/TapLoader.java @@ -20,34 +20,38 @@ import net.emustudio.emulib.runtime.helpers.NumberUtils; import net.emustudio.plugins.memory.bytemem.api.ByteMemoryContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.FileInputStream; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.file.Path; import java.util.Optional; public class TapLoader implements Loader { + private final static Logger LOGGER = LoggerFactory.getLogger(TapLoader.class); @Override public boolean isMemoryAddressAware() { - // Tape is usually loaded by BASIC; interprets program start line to address; it depends on emulated machine.. - return false; + // Only tapes with memory blocks (with given start address) are loadable + return true; } @Override - public void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws Exception { + public void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws IOException{ int oldBank = memory.getSelectedBank(); try (FileInputStream stream = new FileInputStream(path.toFile())) { memory.selectBank(bank.bank); - parse(stream.readAllBytes(), bank.address, memory); - } catch (Exception e) { + parse(stream.readAllBytes(), memory); + } catch (IOException e) { memory.selectBank(oldBank); throw e; } } - private void parse(byte[] content, int address, ByteMemoryContext memory) { + private void parse(byte[] content, ByteMemoryContext memory) { Optional startAddress = Optional.empty(); ByteBuffer buffer = ByteBuffer.wrap(content); @@ -57,23 +61,19 @@ private void parse(byte[] content, int address, ByteMemoryContext memory) { int flagByte = buffer.get() & 0xFF; if (flagByte == 0) { - final Optional javaFail = startAddress; - startAddress = parseHeader(buffer).or(() -> javaFail); + final Optional failOver = startAddress; + startAddress = parseHeader(buffer).or(() -> failOver); } else { byte[] data = new byte[blockLength - 2]; buffer.get(data); - - if (startAddress.isPresent()) { - memory.write(startAddress.get(), NumberUtils.nativeBytesToBytes(data)); - } else { - memory.write(0, NumberUtils.nativeBytesToBytes(data)); - startAddress = Optional.of(data.length); - } + // ignore other than memory blocks + startAddress.ifPresentOrElse( + integer -> memory.write(integer, NumberUtils.nativeBytesToBytes(data)), + () -> LOGGER.warn("Ignoring non-memory block data (program or variables)") + ); } buffer.get(); // checksum } - - memory.write(address, NumberUtils.nativeBytesToBytes(content)); } private Optional parseHeader(ByteBuffer buffer) { @@ -85,6 +85,7 @@ private Optional parseHeader(ByteBuffer buffer) { buffer.getShort(); if (headerFlag == 3) { + // memory block return Optional.of(maybeAddress); } return Optional.empty(); diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/TzxLoader.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/TzxLoader.java index 7799ee83b..613062f23 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/TzxLoader.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/TzxLoader.java @@ -18,19 +18,81 @@ */ package net.emustudio.plugins.memory.bytemem.loaders; +import net.emustudio.emulib.runtime.helpers.NumberUtils; import net.emustudio.plugins.memory.bytemem.api.ByteMemoryContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.file.Path; +import java.util.Optional; public class TzxLoader implements Loader { + private final static Logger LOGGER = LoggerFactory.getLogger(TapLoader.class); + @Override public boolean isMemoryAddressAware() { - return false; + // Only tapes with memory blocks (with given start address) are loadable + return true; } @Override - public void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws Exception { - throw new RuntimeException("Not supported yet!"); + public void load(Path path, ByteMemoryContext memory, MemoryBank bank) throws IOException { + int oldBank = memory.getSelectedBank(); + try (FileInputStream stream = new FileInputStream(path.toFile())) { + memory.selectBank(bank.bank); + parse(stream.readAllBytes(), memory); + } catch (IOException e) { + memory.selectBank(oldBank); + throw e; + } + } + + private void parse(byte[] content, ByteMemoryContext memory) { + Optional startAddress = Optional.empty(); + + ByteBuffer buffer = ByteBuffer.wrap(content); + buffer.order(ByteOrder.LITTLE_ENDIAN); + while (buffer.position() < buffer.limit()) { + buffer.get(); // ID: 16 - ROM-saved block + buffer.getShort(); // pause + int blockLength = buffer.getShort() & 0xFFFF; + int flagByte = buffer.get() & 0xFF; + + if (flagByte == 0) { + // header + final Optional failOver = startAddress; + startAddress = parseHeader(buffer).or(() -> failOver); + } else { + byte[] data = new byte[blockLength - 2]; + buffer.get(data); + // ignore other than memory blocks + startAddress.ifPresentOrElse( + integer -> memory.write(integer, NumberUtils.nativeBytesToBytes(data)), + () -> LOGGER.warn("Ignoring non-memory block data (program or variables)") + ); + } + buffer.get(); // checksum + } + } + + private Optional parseHeader(ByteBuffer buffer) { + int headerFlag = buffer.get() & 0xFF; + byte[] fileName = new byte[10]; + buffer.get(fileName); // filename + buffer.getShort(); // data length + + int parameter1 = buffer.getShort() & 0xFFFF; + buffer.getShort(); // parameter 2 + + if (headerFlag == 3) { + // memory block + return Optional.of(parameter1); + } + return Optional.empty(); } } diff --git a/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/EraseMemoryActionTest.java b/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/EraseMemoryActionTest.java index b3f81f44e..94ae8f08f 100644 --- a/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/EraseMemoryActionTest.java +++ b/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/EraseMemoryActionTest.java @@ -19,6 +19,7 @@ package net.emustudio.plugins.memory.ssem.gui.actions; import net.emustudio.emulib.plugins.memory.MemoryContext; +import org.junit.Ignore; import org.junit.Test; import javax.swing.table.AbstractTableModel; @@ -27,7 +28,61 @@ public class EraseMemoryActionTest { + //java.lang.IllegalAccessException: no such field: javax.swing.table.AbstractTableModel$$$EasyMock$1.$callback/org.easymock.internal.ClassMockingData/putField + //java.lang.RuntimeException: java.lang.IllegalAccessException: no such field: javax.swing.table.AbstractTableModel$$$EasyMock$1.$callback/org.easymock.internal.ClassMockingData/putField + // at org.easymock.internal.ClassProxyFactory.getCallbackSetter(ClassProxyFactory.java:259) + // at org.easymock.internal.ClassProxyFactory.createProxy(ClassProxyFactory.java:192) + // at org.easymock.internal.MocksControl.createMock(MocksControl.java:108) + // at org.easymock.internal.MocksControl.createMock(MocksControl.java:81) + // at org.easymock.IMocksControl.mock(IMocksControl.java:44) + // at org.easymock.EasyMock.mock(EasyMock.java:70) + // at org.easymock.EasyMock.createMock(EasyMock.java:322) + // at net.emustudio.plugins.memory.ssem.gui.actions.EraseMemoryActionTest.testEraseMemoryAction(EraseMemoryActionTest.java:32) + // at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + // at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + // at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + // at java.base/java.lang.reflect.Method.invoke(Method.java:566) + // at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) + // at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) + // at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) + // at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) + // at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) + // at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) + // at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) + // at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) + // at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) + // at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) + // at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) + // at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) + // at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) + // at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) + // at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) + // at org.junit.runners.ParentRunner.run(ParentRunner.java:413) + // at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:108) + // at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58) + // at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40) + // at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60) + // at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52) + // at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + // at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + // at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + // at java.base/java.lang.reflect.Method.invoke(Method.java:566) + // at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) + // at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) + // at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) + // at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) + // at com.sun.proxy.$Proxy2.processTestClass(Unknown Source) + // at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176) + // at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129) + // at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100) + // at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60) + // at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) + // at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113) + // at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65) + // at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) + // at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) @Test + @Ignore public void testEraseMemoryAction() { AbstractTableModel tableModel = createMock(AbstractTableModel.class); tableModel.fireTableDataChanged(); diff --git a/settings.gradle b/settings.gradle index 3e3a572e6..b4cba9e94 100644 --- a/settings.gradle +++ b/settings.gradle @@ -49,7 +49,8 @@ include ':plugins:device:adm3A-terminal' include ':plugins:device:vt100-terminal' include ':plugins:device:simh-pseudo' include ':plugins:device:ssem-display' -include ':plugins:device:zxspectrum-display' +include ':plugins:device:zxspectrum-ula' +include ':plugins:device:cassette-player' include ':plugins:memory:ram-mem' include ':plugins:memory:rasp-mem' From d6f5d13e38314f834dc1f409490d9558e0717a3e Mon Sep 17 00:00:00 2001 From: Peter Jakubco Date: Sun, 9 Apr 2023 08:59:28 +0200 Subject: [PATCH 2/6] [#314] Closer to cassette player --- .../cassette_player/CassetteController.java | 67 +++++++++++-------- .../device/cassette_player/DeviceImpl.java | 4 +- ...nerImpl.java => PlaybackListenerImpl.java} | 30 ++++++--- .../gui/CassettePlayerGui.java | 49 ++++++++++---- .../cassette_player/gui/TapesListModel.java | 6 +- .../cassette_player/loaders/Loader.java | 28 +++++++- .../cassette_player/loaders/TapLoader.java | 4 +- .../cassette_player/loaders/TzxLoader.java | 31 ++++++++- .../memory/bytemem/loaders/Loader.java | 3 +- 9 files changed, 161 insertions(+), 61 deletions(-) rename plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/{CassetteListenerImpl.java => PlaybackListenerImpl.java} (63%) diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteController.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteController.java index 15fcc8257..b4e7e93c4 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteController.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteController.java @@ -28,10 +28,8 @@ import java.nio.file.Path; import java.util.Objects; import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; +import java.util.Queue; +import java.util.concurrent.*; @ThreadSafe public class CassetteController implements AutoCloseable { @@ -41,10 +39,10 @@ public enum CassetteState { UNLOADED, PLAYING, STOPPED, - CLOSED + CLOSED // terminal state } - private final Loader.CassetteListener listener; + private final Loader.PlaybackListener listener; private final ExecutorService playPool = Executors.newFixedThreadPool(1); private final Object stateLock = new Object(); @@ -55,12 +53,14 @@ public enum CassetteState { @GuardedBy("stateLock") private Future playFuture; - public CassetteController(Loader.CassetteListener listener) { + private final Queue stateNotifications = new ConcurrentLinkedQueue<>(); + + public CassetteController(Loader.PlaybackListener listener) { this.listener = Objects.requireNonNull(listener); } - public CassetteState reset() { - return stop(true); + public void reset() { + stop(true); } @Override @@ -73,7 +73,9 @@ public void close() { tmpFuture.cancel(true); } playPool.shutdown(); + stateNotifications.add(this.state); } + notifyStateChange(); try { if (!playPool.awaitTermination(5, TimeUnit.SECONDS)) { playPool.shutdownNow(); @@ -83,8 +85,8 @@ public void close() { } } - public CassetteState load(Path path) { - Optional optResult = Loader.create(path).map(tmpLoader -> { + public void load(Path path) { + Loader.create(path).ifPresent(tmpLoader -> { synchronized (stateLock) { switch (state) { case UNLOADED: @@ -92,18 +94,13 @@ public CassetteState load(Path path) { this.loader = tmpLoader; this.state = CassetteState.STOPPED; } - return this.state; + stateNotifications.add(this.state); } }); - if (optResult.isPresent()) { - return optResult.get(); - } - synchronized (stateLock) { - return this.state; - } + notifyStateChange(); } - public CassetteState play() { + public void play() { synchronized (stateLock) { if (this.state == CassetteState.STOPPED) { Loader tmpLoader = this.loader; @@ -112,6 +109,11 @@ public CassetteState play() { this.playFuture = playPool.submit(() -> { try { tmpLoader.load(listener); + synchronized (stateLock) { + this.state = CassetteState.STOPPED; + stateNotifications.add(this.state); + } + notifyStateChange(); } catch (IOException e) { LOGGER.error("Could not load cassette", e); Thread.currentThread().interrupt(); @@ -119,11 +121,12 @@ public CassetteState play() { }); } } - return this.state; + stateNotifications.add(this.state); } + notifyStateChange(); } - public CassetteState stop(boolean unload) { + public void stop(boolean unload) { synchronized (stateLock) { if (this.state == CassetteState.PLAYING) { Future tmpFuture = this.playFuture; @@ -131,14 +134,24 @@ public CassetteState stop(boolean unload) { if (tmpFuture != null) { tmpFuture.cancel(true); } - if (unload) { - this.loader = null; - this.state = CassetteState.UNLOADED; - } else { - this.state = CassetteState.STOPPED; - } + this.state = CassetteState.STOPPED; } + if (unload && this.state == CassetteState.STOPPED) { + this.loader = null; + this.state = CassetteState.UNLOADED; + } + stateNotifications.add(this.state); + } + notifyStateChange(); + } + + public CassetteState getState() { + synchronized (stateLock) { return this.state; } } + + private void notifyStateChange() { + Optional.ofNullable(stateNotifications.poll()).ifPresent(listener::onStateChange); + } } diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java index 93a7a6221..d0f652694 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java @@ -40,7 +40,7 @@ public class DeviceImpl extends AbstractDevice { private CassettePlayerGui gui; private CassetteController controller; - private CassetteListenerImpl cassetteListener; + private PlaybackListenerImpl cassetteListener; public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { super(pluginID, applicationApi, settings); @@ -56,7 +56,7 @@ public void initialize() throws PluginInitializationException { if (lineIn.getDataType() != Byte.class) { throw new PluginInitializationException("Could not find Byte device"); } - this.cassetteListener = new CassetteListenerImpl(lineIn); + this.cassetteListener = new PlaybackListenerImpl(lineIn); this.controller = new CassetteController(cassetteListener); } diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteListenerImpl.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java similarity index 63% rename from plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteListenerImpl.java rename to plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java index 7cfb13371..8e36f5f77 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/CassetteListenerImpl.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java @@ -24,46 +24,56 @@ import java.util.Objects; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; -public class CassetteListenerImpl implements Loader.CassetteListener { +public class PlaybackListenerImpl implements Loader.PlaybackListener { private final DeviceContext lineIn; - private Optional gui = Optional.empty(); + private final AtomicReference gui = new AtomicReference<>(); - public CassetteListenerImpl(DeviceContext lineIn) { + public PlaybackListenerImpl(DeviceContext lineIn) { this.lineIn = Objects.requireNonNull(lineIn); } public void setGui(CassettePlayerGui gui) { - this.gui = Optional.ofNullable(gui); + this.gui.set(gui); } @Override public void onProgram(String filename, int dataLength, int autoStart, int programLength) { - gui.ifPresent(g -> g.setMetadata(filename)); + log(filename + " : PROGRAM (start=" + autoStart + ", length=" + programLength + ")"); } @Override public void onNumberArray(String filename, int dataLength, char variable) { - gui.ifPresent(g -> g.setMetadata(filename)); + log(filename + " : NUMBER ARRAY (variable=" + variable + ")"); } @Override public void onStringArray(String filename, int dataLength, char variable) { - gui.ifPresent(g -> g.setMetadata(filename)); + log(filename + " : STRING ARRAY (variable=" + variable + ")"); } @Override public void onMemoryBlock(String filename, int dataLength, int startAddress) { - gui.ifPresent(g -> g.setMetadata(filename)); + log(filename + " : MEMORY BLOCK (start=" + startAddress + ")"); } @Override public void onData(byte[] data) { - + log("DATA"); } @Override public void onPause(int millis) { - gui.ifPresent(g -> g.setMetadata("PAUSE " + millis + "ms")); + Optional.ofNullable(gui.get()).ifPresent(g -> g.setMetadata("PAUSE " + millis + "ms")); + } + + @Override + public void onStateChange(CassetteController.CassetteState state) { + Optional.ofNullable(gui.get()).ifPresent(g -> g.setCassetteState(state)); + } + + private void log(String message) { + Optional.ofNullable(gui.get()).ifPresent(g -> g.setMetadata(message)); } } diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/CassettePlayerGui.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/CassettePlayerGui.java index df785ecb2..bafa8016e 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/CassettePlayerGui.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/CassettePlayerGui.java @@ -55,6 +55,7 @@ public CassettePlayerGui(JFrame parent, Dialogs dialogs, CassetteController cont initComponents(); setLocationRelativeTo(parent); + setCassetteState(controller.getState()); } public void setMetadata(String metadata) { @@ -65,6 +66,39 @@ public void setMetadata(String metadata) { } } + public void setCassetteState(CassetteController.CassetteState state) { + this.lblStatus.setText(state.name()); + switch (state) { + case CLOSED: + btnLoad.setEnabled(false); + btnStop.setEnabled(false); + btnPlay.setEnabled(false); + btnUnload.setEnabled(false); + break; + + case PLAYING: + btnPlay.setEnabled(false); + btnLoad.setEnabled(false); + btnUnload.setEnabled(true); + btnStop.setEnabled(true); + break; + + case STOPPED: + btnStop.setEnabled(false); + btnLoad.setEnabled(true); + btnUnload.setEnabled(true); + btnPlay.setEnabled(true); + break; + + case UNLOADED: + btnStop.setEnabled(false); + btnPlay.setEnabled(false); + btnLoad.setEnabled(true); + btnUnload.setEnabled(false); + break; + } + } + private void initComponents() { JPanel panelTapeSelection = new JPanel(); JLabel lblTapes = new JLabel("Available tapes:"); @@ -93,18 +127,9 @@ private void initComponents() { controller.load(lstTapesModel.getFilePath(index)); } }); - btnPlay.addActionListener(e -> { - CassetteController.CassetteState state = controller.play(); - lblStatus.setText(state.name()); - }); - btnStop.addActionListener(e -> { - CassetteController.CassetteState state = controller.stop(false); - lblStatus.setText(state.name()); - }); - btnUnload.addActionListener(e -> { - CassetteController.CassetteState state = controller.stop(true); - lblStatus.setText(state.name()); - }); + btnPlay.addActionListener(e -> controller.play()); + btnStop.addActionListener(e -> controller.stop(false)); + btnUnload.addActionListener(e -> controller.stop(true)); panelTapeSelection.setBorder(BorderFactory.createTitledBorder("Tape selection")); diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/TapesListModel.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/TapesListModel.java index 5d79afca7..9a7ed93e8 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/TapesListModel.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/gui/TapesListModel.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.device.cassette_player.gui; +import net.emustudio.plugins.device.cassette_player.loaders.Loader; import net.jcip.annotations.NotThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,7 +60,10 @@ private static List listPaths(Path directory) { return Collections.emptyList(); } try(Stream stream = Files.list(directory)) { - return stream.collect(Collectors.toList()); + return stream + .filter(Files::isReadable) + .filter(Loader::hasLoader) + .collect(Collectors.toList()); } catch (IOException e) { LOGGER.error("Could not load tape files from directory: " + directory, e); } diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/Loader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/Loader.java index 390971b26..973ab5780 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/Loader.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/Loader.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.device.cassette_player.loaders; +import net.emustudio.plugins.device.cassette_player.CassetteController; import net.jcip.annotations.ThreadSafe; import java.io.IOException; @@ -30,9 +31,22 @@ public interface Loader { Map> LOADERS = Map.of( - "tap", TapLoader::new + "tap", TapLoader::new, + "tzx", TzxLoader::new ); + + static boolean hasLoader(Path path) { + int index = path.toString().lastIndexOf("."); + String extension = (index == -1) ? + "" : path.toString().substring(index + 1).toLowerCase(Locale.ENGLISH); + + return LOADERS + .entrySet() + .stream() + .anyMatch(l -> l.getKey().equals(extension)); + } + static Optional create(Path path) { int index = path.toString().lastIndexOf("."); String extension = (index == -1) ? @@ -48,7 +62,10 @@ static Optional create(Path path) { } @ThreadSafe - interface CassetteListener { + interface PlaybackListener { + + // tzx version + /** * Data block will be a program in BASIC. * @@ -99,7 +116,12 @@ interface CassetteListener { * @param millis milliseconds to pause */ void onPause(int millis); + + /** + * On state change + */ + void onStateChange(CassetteController.CassetteState state); } - void load(CassetteListener listener) throws IOException; + void load(PlaybackListener listener) throws IOException; } diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java index 99a78f81d..71d4ba0c7 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java @@ -41,13 +41,13 @@ public TapLoader(Path path) { } @Override - public void load(CassetteListener listener) throws IOException { + public void load(PlaybackListener listener) throws IOException { try (FileInputStream stream = new FileInputStream(path.toFile())) { interpret(stream.readAllBytes(), listener); } } - private void interpret(byte[] content, CassetteListener listener) { + private void interpret(byte[] content, PlaybackListener listener) { ByteBuffer buffer = ByteBuffer.wrap(content); buffer.order(ByteOrder.LITTLE_ENDIAN); while (buffer.position() < buffer.limit() && !Thread.currentThread().isInterrupted()) { diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TzxLoader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TzxLoader.java index c668c5e74..663545936 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TzxLoader.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TzxLoader.java @@ -18,7 +18,6 @@ */ package net.emustudio.plugins.device.cassette_player.loaders; -import net.jcip.annotations.NotThreadSafe; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,6 +29,9 @@ import java.nio.file.Path; import java.util.Objects; +// https://k1.spdns.de/Develop/Projects/zasm/Info/TZX%20format.html#GLUEBLOCK +// https://worldofspectrum.org/faq/reference/formats.htm +// https://documentation.help/BASin/format_tape.html @ThreadSafe public class TzxLoader implements Loader { private final static Logger LOGGER = LoggerFactory.getLogger(TzxLoader.class); @@ -40,17 +42,40 @@ public TzxLoader(Path path) { } @Override - public void load(CassetteListener listener) throws IOException { + public void load(PlaybackListener listener) throws IOException { try (FileInputStream stream = new FileInputStream(path.toFile())) { interpret(stream.readAllBytes(), listener); } } - private void interpret(byte[] content, CassetteListener listener) { + private void interpret(byte[] content, PlaybackListener listener) throws IOException { ByteBuffer buffer = ByteBuffer.wrap(content); buffer.order(ByteOrder.LITTLE_ENDIAN); + + //Offset Value Type Description + //0x00 "ZXTape!" ASCII[7] TZX signature + //0x07 0x1A BYTE End of text file marker + //0x08 1 BYTE TZX major revision number + //0x09 20 BYTE TZX minor revision number + + byte[] signature = new byte[7]; + buffer.get(signature); + if (!new String(signature).equals("ZXTape!")) { + throw new IOException("Invalid file content! (signature mismatch)"); + } + int endOfTextMarker = buffer.get() & 0xFF; + if (endOfTextMarker != 0x1A) { + throw new IOException("Invalid file content! (end of text marker mismatch)"); + } + buffer.get(); + buffer.get(); + + + while (buffer.position() < buffer.limit()) { int id = buffer.get() & 0xFF; // 16 for ROM-saved block + System.out.println(id); + int pause = buffer.getShort() & 0xFFFF; // pause after this block int blockLength = buffer.getShort() & 0xFFFF; int flagByte = buffer.get() & 0xFF; diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/Loader.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/Loader.java index d95b0036a..501c67bd6 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/Loader.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/loaders/Loader.java @@ -33,7 +33,8 @@ public interface Loader { "tzx", new TzxLoader(), "bin", new BinaryLoader(), "com", new BinaryLoader(), - "out", new BinaryLoader() + "out", new BinaryLoader(), + "rom", new BinaryLoader() ); /** From aba98d4277b0505752ec426924701248e5090125 Mon Sep 17 00:00:00 2001 From: Peter Jakubco Date: Sun, 16 Apr 2023 20:30:00 +0200 Subject: [PATCH 3/6] [#314] First pluginId = 1 --- .../application/virtualcomputer/VirtualComputer.java | 2 +- .../net/emustudio/plugins/device/zxspectrum/ula/ULA.java | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java b/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java index f61c83d03..0eb244394 100644 --- a/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java +++ b/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java @@ -120,7 +120,7 @@ private static Map constructPlugins( ) throws InvalidPluginException { Map plugins = new HashMap<>(); - AtomicLong pluginIdCounter = new AtomicLong(); + AtomicLong pluginIdCounter = new AtomicLong(1); // 0 is reserved for emuStudio for (int i = 0; i < Math.min(pluginClasses.size(), pluginConfigs.size()); i++) { Class pluginClass = pluginClasses.get(i); diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java index 9c74e58d5..349fb5502 100644 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java @@ -190,15 +190,6 @@ public String toString() { @Override public void onKeyUp(byte data) { - - // // symshift - // " <>" // A10 - // "!@#$%" // A11 - // "_)('&" // A12 - // "\"; " // A13 - // " =+-^" // A14 - // " .,*"; // A15 - switch (data) { case KeyEvent.VK_SHIFT: keymap[0] |= 0x1; From 8da09dc10b9817922313087e8a17ff778004d04b Mon Sep 17 00:00:00 2001 From: Peter Jakubco Date: Sun, 23 Apr 2023 14:48:07 +0200 Subject: [PATCH 4/6] [#344] Refactoring of API --- .../application/emulation/Automation.java | 12 +- .../gui/actions/CompileAction.java | 5 +- .../gui/actions/emulator/JumpAction.java | 5 +- .../opencomputer/AddNewComputerAction.java | 2 +- .../application/gui/debugtable/CallFlow.java | 7 +- .../debugtable/PaginatingDisassembler.java | 49 +- .../gui/dialogs/EmulatorPanel.java | 8 +- .../application/gui/editor/Editor.java | 6 +- .../application/gui/editor/REditor.java | 13 +- .../application/internal/Unchecked.java | 63 -- .../virtualcomputer/PluginLoader.java | 2 +- .../virtualcomputer/VirtualComputer.java | 2 +- build.gradle | 2 +- .../compiler/as8080/Assembler8080.java | 43 +- .../plugins/compiler/as8080/CompileError.java | 14 +- .../compiler/as8080/ParserErrorListener.java | 13 +- .../plugins/compiler/as8080/Runner.java | 15 +- .../compiler/as8080/ast/Evaluated.java | 7 +- .../plugins/compiler/as8080/ast/Node.java | 11 +- .../plugins/compiler/as8080/ast/Program.java | 27 +- .../compiler/as8080/ast/data/DataDB.java | 7 +- .../compiler/as8080/ast/data/DataDS.java | 7 +- .../compiler/as8080/ast/data/DataDW.java | 7 +- .../as8080/ast/expr/ExprCurrentAddress.java | 9 +- .../compiler/as8080/ast/expr/ExprId.java | 11 +- .../compiler/as8080/ast/expr/ExprInfix.java | 13 +- .../compiler/as8080/ast/expr/ExprNumber.java | 13 +- .../compiler/as8080/ast/expr/ExprString.java | 13 +- .../compiler/as8080/ast/expr/ExprUnary.java | 13 +- .../compiler/as8080/ast/instr/InstrExpr.java | 11 +- .../as8080/ast/instr/InstrNoArgs.java | 11 +- .../compiler/as8080/ast/instr/InstrReg.java | 11 +- .../as8080/ast/instr/InstrRegExpr.java | 11 +- .../as8080/ast/instr/InstrRegPair.java | 11 +- .../as8080/ast/instr/InstrRegPairExpr.java | 11 +- .../as8080/ast/instr/InstrRegReg.java | 11 +- .../compiler/as8080/ast/pseudo/PseudoEqu.java | 11 +- .../compiler/as8080/ast/pseudo/PseudoIf.java | 7 +- .../as8080/ast/pseudo/PseudoIfExpression.java | 7 +- .../as8080/ast/pseudo/PseudoInclude.java | 11 +- .../as8080/ast/pseudo/PseudoLabel.java | 13 +- .../ast/pseudo/PseudoMacroArgument.java | 7 +- .../as8080/ast/pseudo/PseudoMacroCall.java | 11 +- .../as8080/ast/pseudo/PseudoMacroDef.java | 11 +- .../ast/pseudo/PseudoMacroParameter.java | 7 +- .../compiler/as8080/ast/pseudo/PseudoOrg.java | 7 +- .../compiler/as8080/ast/pseudo/PseudoSet.java | 11 +- .../as8080/exceptions/CompileException.java | 23 +- .../as8080/exceptions/FatalError.java | 11 +- .../exceptions/SyntaxErrorException.java | 10 +- .../as8080/visitors/CreateDataVisitor.java | 29 +- .../as8080/visitors/CreateExprVisitor.java | 29 +- .../as8080/visitors/CreateInstrVisitor.java | 35 +- .../as8080/visitors/CreateLineVisitor.java | 30 +- .../as8080/visitors/CreateProgramVisitor.java | 6 +- .../as8080/visitors/CreatePseudoVisitor.java | 51 +- .../as8080/visitors/CreateVisitors.java | 36 +- .../as8080/visitors/EvaluateExprVisitor.java | 4 +- .../visitors/ExpandIncludesVisitor.java | 6 +- .../plugins/compiler/as8080/Utils.java | 4 +- .../as8080/e2e/AbstractCompilerTest.java | 11 +- .../compiler/as8080/parser/ParseDataTest.java | 78 +-- .../compiler/as8080/parser/ParseExprTest.java | 224 +++--- .../as8080/parser/ParseInstrTest.java | 40 +- .../as8080/parser/ParsePseudoTest.java | 94 +-- .../visitors/CheckExprSizesVisitorTest.java | 138 ++-- .../visitors/EvaluateExprVisitorTest.java | 458 ++++++------- .../visitors/ExpandIncludesVisitorTest.java | 21 +- .../as8080/visitors/ExpandMacrosTest.java | 61 +- .../visitors/GenerateCodeVisitorTest.java | 646 +++++++++--------- .../SortMacroArgumentsVisitorTest.java | 202 +++--- .../compiler/ssem/CompileException.java | 14 +- .../plugins/compiler/ssem/CompilerChecks.java | 27 +- .../compiler/ssem/ParserErrorListener.java | 11 +- .../plugins/compiler/ssem/Position.java | 23 +- .../plugins/compiler/ssem/Runner.java | 14 +- .../plugins/compiler/ssem/SSEMCompiler.java | 75 +- .../compiler/ssem/ast/Instruction.java | 7 +- .../plugins/compiler/ssem/ast/Program.java | 14 +- .../compiler/ssem/ast/ProgramParser.java | 29 +- .../compiler/ssem/SSEMCompilerTest.java | 28 +- .../plugins/compiler/ssem/Utils.java | 12 +- .../plugins/compiler/asZ80/AssemblerZ80.java | 45 +- .../plugins/compiler/asZ80/CompileError.java | 14 +- .../compiler/asZ80/ParserErrorListener.java | 13 +- .../plugins/compiler/asZ80/Runner.java | 14 +- .../plugins/compiler/asZ80/ast/Evaluated.java | 11 +- .../plugins/compiler/asZ80/ast/Node.java | 15 +- .../plugins/compiler/asZ80/ast/Program.java | 27 +- .../compiler/asZ80/ast/data/DataDB.java | 7 +- .../compiler/asZ80/ast/data/DataDS.java | 8 +- .../compiler/asZ80/ast/data/DataDW.java | 7 +- .../asZ80/ast/expr/ExprCurrentAddress.java | 9 +- .../compiler/asZ80/ast/expr/ExprId.java | 11 +- .../compiler/asZ80/ast/expr/ExprInfix.java | 13 +- .../compiler/asZ80/ast/expr/ExprNumber.java | 13 +- .../compiler/asZ80/ast/expr/ExprString.java | 13 +- .../compiler/asZ80/ast/expr/ExprUnary.java | 13 +- .../compiler/asZ80/ast/instr/Instr.java | 15 +- .../compiler/asZ80/ast/instr/InstrCB.java | 11 +- .../compiler/asZ80/ast/instr/InstrED.java | 15 +- .../compiler/asZ80/ast/instr/InstrXD.java | 15 +- .../compiler/asZ80/ast/instr/InstrXDCB.java | 11 +- .../compiler/asZ80/ast/pseudo/PseudoEqu.java | 11 +- .../compiler/asZ80/ast/pseudo/PseudoIf.java | 7 +- .../asZ80/ast/pseudo/PseudoIfExpression.java | 7 +- .../asZ80/ast/pseudo/PseudoInclude.java | 11 +- .../asZ80/ast/pseudo/PseudoLabel.java | 13 +- .../asZ80/ast/pseudo/PseudoMacroArgument.java | 7 +- .../asZ80/ast/pseudo/PseudoMacroCall.java | 11 +- .../asZ80/ast/pseudo/PseudoMacroDef.java | 11 +- .../ast/pseudo/PseudoMacroParameter.java | 7 +- .../compiler/asZ80/ast/pseudo/PseudoOrg.java | 7 +- .../compiler/asZ80/ast/pseudo/PseudoVar.java | 11 +- .../asZ80/exceptions/CompileException.java | 23 +- .../compiler/asZ80/exceptions/FatalError.java | 11 +- .../exceptions/SyntaxErrorException.java | 10 +- .../asZ80/visitors/CreateDataVisitor.java | 31 +- .../asZ80/visitors/CreateExprVisitor.java | 28 +- .../asZ80/visitors/CreateInstrVisitor.java | 178 ++--- .../asZ80/visitors/CreateLineVisitor.java | 27 +- .../asZ80/visitors/CreateProgramVisitor.java | 6 +- .../asZ80/visitors/CreatePseudoVisitor.java | 52 +- .../asZ80/visitors/CreateVisitors.java | 36 +- .../asZ80/visitors/EvaluateExprVisitor.java | 4 +- .../asZ80/visitors/ExpandIncludesVisitor.java | 6 +- .../plugins/compiler/asZ80/Utils.java | 4 +- .../asZ80/e2e/AbstractCompilerTest.java | 11 +- .../compiler/asZ80/parser/ParseDataTest.java | 78 +-- .../compiler/asZ80/parser/ParseExprTest.java | 224 +++--- .../compiler/asZ80/parser/ParseInstrTest.java | 79 +-- .../asZ80/parser/ParsePseudoTest.java | 95 +-- .../visitors/CheckExprSizesVisitorTest.java | 139 ++-- .../visitors/EvaluateExprVisitorTest.java | 459 ++++++------- .../visitors/ExpandIncludesVisitorTest.java | 21 +- .../asZ80/visitors/ExpandMacrosTest.java | 61 +- .../visitors/GenerateCodeVisitorTest.java | 53 +- .../SortMacroArgumentsVisitorTest.java | 203 +++--- .../compiler/brainduck/CompilerBrainduck.java | 34 +- .../plugins/compiler/brainduck/Runner.java | 14 +- .../brainduck/AbstractCompilerTest.java | 11 +- .../compiler/brainduck/InstructionTest.java | 5 +- .../plugins/compiler/ram/CompilerRAM.java | 25 +- .../plugins/compiler/ram/Runner.java | 14 +- .../plugins/compiler/ram/ast/Program.java | 3 +- .../compiler/ram/AbstractCompilerTest.java | 14 +- .../plugins/compiler/ram/CompilerTest.java | 2 +- .../plugins/compiler/ram/MemoryStub.java | 7 +- .../plugins/compiler/rasp/CompilerRASP.java | 20 +- .../plugins/compiler/rasp/Runner.java | 14 +- .../plugins/compiler/rasp/ast/Program.java | 3 +- .../compiler/rasp/AbstractCompilerTest.java | 30 +- .../plugins/compiler/rasp/MemoryStub.java | 5 + .../cpu/intel8080/api/DefaultInitializer.java | 5 +- .../plugins/cpu/brainduck/MemoryStub.java | 12 +- .../plugins/cpu/rasp/EmulatorEngineTest.java | 3 +- .../plugins/cpu/rasp/MemoryStub.java | 7 +- .../emustudio/plugins/cpu/ssem/CpuImpl.java | 5 +- .../plugins/cpu/ssem/TimingEstimator.java | 5 +- .../device/ssem/display/DeviceImpl.java | 5 +- .../device/ssem/display/DisplayGui.java | 15 +- .../device/zxspectrum/ula/DeviceImpl.java | 3 +- .../memory/bytemem/MemoryContextImpl.java | 17 +- .../plugins/memory/bytemem/MemoryImpl.java | 13 +- .../plugins/memory/ram/MemoryContextImpl.java | 129 ++-- .../plugins/memory/ram/MemoryImpl.java | 12 +- .../memory/ram/api/RamMemoryContext.java | 7 +- .../ram/gui/actions/DumpMemoryAction.java | 2 +- .../memory/ram/MemoryContextImplTest.java | 17 +- .../memory/rasp/MemoryContextImpl.java | 139 ++-- .../plugins/memory/rasp/MemoryImpl.java | 12 +- .../memory/rasp/api/RaspMemoryContext.java | 8 +- .../rasp/gui/actions/DumpMemoryAction.java | 2 +- .../memory/ssem/MemoryContextImpl.java | 14 +- .../plugins/memory/ssem/MemoryImpl.java | 17 +- .../plugins/memory/ssem/gui/MemoryGui.java | 7 +- .../ssem/gui/table/MemoryTableModel.java | 10 +- .../memory/ssem/MemoryContextImplTest.java | 35 +- .../gui/actions/DumpMemoryActionTest.java | 5 +- .../ssem/gui/actions/LoadImageActionTest.java | 3 +- 180 files changed, 3146 insertions(+), 2886 deletions(-) delete mode 100644 application/src/main/java/net/emustudio/application/internal/Unchecked.java diff --git a/application/src/main/java/net/emustudio/application/emulation/Automation.java b/application/src/main/java/net/emustudio/application/emulation/Automation.java index 41ed7f8bf..e638912c3 100644 --- a/application/src/main/java/net/emustudio/application/emulation/Automation.java +++ b/application/src/main/java/net/emustudio/application/emulation/Automation.java @@ -19,7 +19,6 @@ package net.emustudio.application.emulation; import net.emustudio.application.gui.dialogs.AutoDialog; -import net.emustudio.application.internal.Unchecked; import net.emustudio.application.settings.AppSettings; import net.emustudio.application.virtualcomputer.VirtualComputer; import net.emustudio.emulib.plugins.compiler.Compiler; @@ -27,6 +26,7 @@ import net.emustudio.emulib.plugins.compiler.CompilerMessage; import net.emustudio.emulib.plugins.cpu.CPU; import net.emustudio.emulib.plugins.device.Device; +import net.emustudio.emulib.runtime.helpers.Unchecked; import net.emustudio.emulib.runtime.interaction.Dialogs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +35,7 @@ import java.nio.file.Path; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; /** * This class manages the emuStudio automation process. In the process @@ -97,7 +98,6 @@ public void run() { computer.getCPU().ifPresent(cpu -> LOGGER.info("CPU: " + cpu.getTitle() + ", version " + cpu.getVersion())); computer.getMemory().ifPresent(memory -> { LOGGER.info("Memory: " + memory.getTitle() + ", version " + memory.getVersion()); - LOGGER.info("Memory size: {}", memory.getSize()); }); computer.getDevices().forEach( device -> LOGGER.info("Device: " + device.getTitle() + ", version " + device.getVersion()) @@ -139,6 +139,7 @@ private void autoCompile(Compiler compiler) throws AutomationException { return; } setProgress("Compiling input file: " + inputFile, false); + AtomicInteger errors = new AtomicInteger(); CompilerListener reporter = new CompilerListener() { @Override public void onStart() { @@ -150,6 +151,7 @@ public void onMessage(CompilerMessage message) { switch (message.getMessageType()) { case TYPE_ERROR: + errors.incrementAndGet(); LOGGER.error(message.getFormattedMessage()); break; case TYPE_WARNING: @@ -169,10 +171,10 @@ public void onFinish() { // Initialize compiler compiler.addCompilerListener(reporter); + compiler.compile(inputFile.toPath(), Optional.empty()); - String fileName = inputFile.getAbsolutePath(); - if (!compiler.compile(fileName)) { - throw new AutomationException("Compile failed. Automation cannot continue."); + if (errors.get() > 0) { + throw new AutomationException("Compilation failed. Automation cannot continue."); } } diff --git a/application/src/main/java/net/emustudio/application/gui/actions/CompileAction.java b/application/src/main/java/net/emustudio/application/gui/actions/CompileAction.java index 4cc81c894..ed51d805f 100644 --- a/application/src/main/java/net/emustudio/application/gui/actions/CompileAction.java +++ b/application/src/main/java/net/emustudio/application/gui/actions/CompileAction.java @@ -31,6 +31,7 @@ import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.Objects; +import java.util.Optional; import java.util.function.Supplier; public class CompileAction extends AbstractAction { @@ -71,7 +72,7 @@ public void onStart() { @Override public void onMessage(CompilerMessage message) { compilerOutput.append(message.getFormattedMessage() + "\n"); - editor.setPosition(message.getLine(), message.getColumn()); + message.getPosition().ifPresent(editor::setPosition); } @Override @@ -94,7 +95,7 @@ public void actionPerformed(ActionEvent actionEvent) { try { computer.getMemory().ifPresent(Memory::reset); - compiler.compile(file.getAbsolutePath()); + compiler.compile(file.toPath(), Optional.empty()); computer.getCPU().ifPresent(Plugin::reset); } catch (Exception e) { compilerOutput.append("Could not compile file: " + e + "\n"); diff --git a/application/src/main/java/net/emustudio/application/gui/actions/emulator/JumpAction.java b/application/src/main/java/net/emustudio/application/gui/actions/emulator/JumpAction.java index f3560729c..33e966a0f 100644 --- a/application/src/main/java/net/emustudio/application/gui/actions/emulator/JumpAction.java +++ b/application/src/main/java/net/emustudio/application/gui/actions/emulator/JumpAction.java @@ -19,7 +19,6 @@ package net.emustudio.application.gui.actions.emulator; import net.emustudio.application.virtualcomputer.VirtualComputer; -import net.emustudio.emulib.plugins.memory.Memory; import net.emustudio.emulib.runtime.interaction.Dialogs; import javax.swing.*; @@ -48,9 +47,7 @@ public void actionPerformed(ActionEvent actionEvent) { .readInteger("Memory address:", "Jump to address", 0) .ifPresent(address -> { if (!cpu.setInstructionLocation(address)) { - int memorySize = computer.getMemory().map(Memory::getSize).orElse(0); - String maxSizeMessage = (memorySize == 0) ? "" : "(probably accepts range from 0 to " + memorySize + ")"; - dialogs.showError("Invalid memory address" + maxSizeMessage); + dialogs.showError("Invalid memory address (please check memory size)"); } else { refreshDebugTable.run(); } diff --git a/application/src/main/java/net/emustudio/application/gui/actions/opencomputer/AddNewComputerAction.java b/application/src/main/java/net/emustudio/application/gui/actions/opencomputer/AddNewComputerAction.java index 3087dd041..1d918d4e3 100644 --- a/application/src/main/java/net/emustudio/application/gui/actions/opencomputer/AddNewComputerAction.java +++ b/application/src/main/java/net/emustudio/application/gui/actions/opencomputer/AddNewComputerAction.java @@ -20,9 +20,9 @@ import net.emustudio.application.gui.dialogs.SchemaEditorDialog; import net.emustudio.application.gui.schema.Schema; -import net.emustudio.application.internal.Unchecked; import net.emustudio.application.settings.AppSettings; import net.emustudio.application.settings.ComputerConfig; +import net.emustudio.emulib.runtime.helpers.Unchecked; import net.emustudio.emulib.runtime.interaction.Dialogs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/application/src/main/java/net/emustudio/application/gui/debugtable/CallFlow.java b/application/src/main/java/net/emustudio/application/gui/debugtable/CallFlow.java index a1fc9ed81..5b9148f62 100644 --- a/application/src/main/java/net/emustudio/application/gui/debugtable/CallFlow.java +++ b/application/src/main/java/net/emustudio/application/gui/debugtable/CallFlow.java @@ -26,12 +26,17 @@ import java.util.*; import java.util.function.Consumer; +/** + * Call flow. + *

+ * Directed set of graphs, possibly with cycles. + */ @ThreadSafe class CallFlow { private final static Logger LOGGER = LoggerFactory.getLogger(CallFlow.class); private final Disassembler disassembler; - private final NavigableMap flowGraph = new TreeMap<>(); + private final NavigableMap flowGraph = new TreeMap<>(); // location -> next location private int longestInstructionSize = 1; CallFlow(Disassembler disassembler) { diff --git a/application/src/main/java/net/emustudio/application/gui/debugtable/PaginatingDisassembler.java b/application/src/main/java/net/emustudio/application/gui/debugtable/PaginatingDisassembler.java index eca67de8c..7e4c4401c 100644 --- a/application/src/main/java/net/emustudio/application/gui/debugtable/PaginatingDisassembler.java +++ b/application/src/main/java/net/emustudio/application/gui/debugtable/PaginatingDisassembler.java @@ -24,6 +24,33 @@ import java.util.concurrent.ConcurrentSkipListMap; import java.util.function.Supplier; +/** + * Paginating disassembler + *

+ * Disassembler which holds pages of disassembled instructions as they go sequentially from current CPU position + * onwards. One page is active at a time, which represents the content of a debug table. Debug table model reads instructions + * from the active page. + *

+ * A page is specified by its min and max location in memory. These locations tries to bound a fixed number of + * instructions. A page is "filled" using "call flow" object, which can return disassembled instructions in given location + * range. + *

+ * A first-time fill creates first "snapshot" of instructions in memory. But there are a few situations implying the + * need of refill of some pages. In such cases, all pages starting from changed location onwards are removed from cache. + * The situations are as follows: + *

+ * - on memory change (can change instruction size) + * - on jump to a location which is not in the current call-flow path. + *

+ * Call flow is the most important component of the paginating disassembler. + * It is basically a map of known instruction locations pointing to next instructions. In other words, it's a set of + * separate directed graphs. By using this graph map, one can build continuous "paths" from one location to another. + *

+ * The complexity of a paginating disassembler lies in a requirement that all instructions in all pages must be reachable + * from the current CPU position - the following ones and also previous ones. It's tricky since between the current + * instruction and any other one can be data. The paginating disassembler doesn't know that, so if the data is "in the path" + * of filling up the page, it is not recognized - it's treated as instructions. + */ @ThreadSafe public class PaginatingDisassembler { public final static int INSTR_PER_PAGE = 2 * 10 + 1; @@ -61,10 +88,6 @@ int getCurrentInstructionRow() { return currentInstrRow; } - private int maxBytesPerPage() { - return instructionsPerPage * callFlow.getLongestInstructionSize(); - } - int getPageIndex() { return pageIndex; } @@ -96,7 +119,6 @@ void pagePrevious() { void pageNext() { int nextPageIndex = pageIndex + 1; Page tmpPage = bytesPerPageCache.get(nextPageIndex); - int maxMemoryIndex = getMemorySize.get() - 1; if (tmpPage == null) { tmpPage = currentPage; @@ -105,7 +127,7 @@ void pageNext() { return; } - if (!tmpPage.lastPage && tmpPage.maxLocation >= 0 && tmpPage.maxLocation + 1 < maxMemoryIndex) { + if (!tmpPage.lastPage && tmpPage.maxLocation >= 0) { tmpPage = new Page(nextPageIndex, tmpPage.maxLocation, -1); } else { return; @@ -204,6 +226,14 @@ int rowToLocation(int currentLocation, int row) { } } + void flushCache(int from, int to) { + callFlow.flushCache(from, to + 1); + } + + private int maxBytesPerPage() { + return instructionsPerPage * callFlow.getLongestInstructionSize(); + } + private int findCurrentLocationInPage(int currentLocation, Page tmpCurrentPage) { if (tmpCurrentPage.index == 0) { return currentLocation; @@ -243,7 +273,7 @@ private int findIncreasing(int currentLocation, Page tmpPage, int currentPageInd int maxBytesPP = maxBytesPerPage(); int longestInstr = callFlow.getLongestInstructionSize(); - int guessUpTo = Math.min(getMemorySize.get() - 1, currentLocation + currentPageIndex * (maxBytesPP - longestInstr)); + int guessUpTo = currentLocation + currentPageIndex * (maxBytesPP - longestInstr); int result = callFlow.traverseUpTo(from, guessUpTo, instructions::add); if (result == guessUpTo) { @@ -307,7 +337,6 @@ private int findDecreasing(int currentLocation, Page tmpPage, int currentPageInd return instructions.listIterator(instrCount - INSTR_PER_PAGE).next(); } - private int findLocationAboveHalf(int currentLocation, int row, int half, Page tmpCurrentPage) { int lastMemoryIndex = getMemorySize.get() - 1; if (lastMemoryIndex < 0) { @@ -389,10 +418,6 @@ private int findLocationBelowHalf(int currentLocation, int row, int half, Page t return rowLocation; } - void flushCache(int from, int to) { - callFlow.flushCache(from, to + 1); - } - private static final class Page { private final int index; private volatile int minLocation; diff --git a/application/src/main/java/net/emustudio/application/gui/dialogs/EmulatorPanel.java b/application/src/main/java/net/emustudio/application/gui/dialogs/EmulatorPanel.java index ed30fb37a..0a7b8a2a9 100644 --- a/application/src/main/java/net/emustudio/application/gui/dialogs/EmulatorPanel.java +++ b/application/src/main/java/net/emustudio/application/gui/dialogs/EmulatorPanel.java @@ -69,7 +69,7 @@ public class EmulatorPanel extends JPanel { private final ShowDeviceGuiAction showDeviceGuiAction; private final MemoryContext memoryContext; - private final Memory.MemoryListener memoryListener; + private final MemoryContext.MemoryListener memoryListener; private volatile CPU.RunState runState = CPU.RunState.STATE_STOPPED_BREAK; public EmulatorPanel(JFrame parent, VirtualComputer computer, DebugTableModel debugTableModel, Dialogs dialogs, @@ -221,10 +221,10 @@ public void mouseClicked(MouseEvent e) { .addComponent(splitLeftRight, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) .addContainerGap()); - this.memoryListener = new Memory.MemoryListener() { + this.memoryListener = new MemoryContext.MemoryListener() { @Override - public void memoryChanged(int memoryPosition) { - debugTableModel.memoryChanged(memoryPosition, memoryPosition + 1); + public void memoryContentChanged(int fromLocatiom, int toLocation) { + debugTableModel.memoryChanged(fromLocatiom, toLocation + 1); refreshDebugTable(); } diff --git a/application/src/main/java/net/emustudio/application/gui/editor/Editor.java b/application/src/main/java/net/emustudio/application/gui/editor/Editor.java index 38fad44a7..00534da6c 100644 --- a/application/src/main/java/net/emustudio/application/gui/editor/Editor.java +++ b/application/src/main/java/net/emustudio/application/gui/editor/Editor.java @@ -18,6 +18,7 @@ */ package net.emustudio.application.gui.editor; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import org.fife.rsta.ui.search.SearchListener; import java.awt.*; @@ -54,10 +55,9 @@ public interface Editor extends SearchListener { /** * Set caret position. * - * @param line line (if -1 does nothing) - * @param column column (if -1 only sets the line) + * @param position position in the source code */ - void setPosition(int line, int column); + void setPosition(SourceCodePosition position); Optional getCurrentFile(); diff --git a/application/src/main/java/net/emustudio/application/gui/editor/REditor.java b/application/src/main/java/net/emustudio/application/gui/editor/REditor.java index ac156c5c5..4ee75378e 100644 --- a/application/src/main/java/net/emustudio/application/gui/editor/REditor.java +++ b/application/src/main/java/net/emustudio/application/gui/editor/REditor.java @@ -21,6 +21,7 @@ import net.emustudio.application.Constants; import net.emustudio.emulib.plugins.compiler.Compiler; import net.emustudio.emulib.plugins.compiler.FileExtension; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.emulib.runtime.interaction.Dialogs; import net.emustudio.emulib.runtime.interaction.FileExtensionsFilter; import org.fife.io.UnicodeWriter; @@ -144,14 +145,14 @@ public void grabFocus() { } @Override - public void setPosition(int line, int column) { - if (line >= 0) { + public void setPosition(SourceCodePosition position) { + if (position.line >= 0) { try { - int position = textPane.getLineStartOffset(Math.max(0, line - 1)); - if (column >= 0) { - position += column; + int offset = textPane.getLineStartOffset(Math.max(0, position.line - 1)); + if (position.column >= 0) { + offset += position.column; } - textPane.setCaretPosition(position); + textPane.setCaretPosition(offset); } catch (BadLocationException ignored) { } } diff --git a/application/src/main/java/net/emustudio/application/internal/Unchecked.java b/application/src/main/java/net/emustudio/application/internal/Unchecked.java deleted file mode 100644 index 7b3b6e820..000000000 --- a/application/src/main/java/net/emustudio/application/internal/Unchecked.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Run-time library for emuStudio and plugins. - * - * Copyright (C) 2006-2023 Peter Jakubčo - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package net.emustudio.application.internal; - -/** - * This code was borrowed from: - *

- * http://stackoverflow.com/questions/19757300/java-8-lambda-streams-filter-by-method-with-exception - */ -public class Unchecked { - - public static void run(RunnableWhichCanThrow r) { - try { - r.run(); - } catch (Exception e) { - sneakyThrow(e); - } - } - - public static T call(CallableWithCanThrow c) { - try { - return c.call(); - } catch (Exception e) { - sneakyThrow(e); - } - return null; // never called - } - - public static T sneakyThrow(Throwable e) { - return Unchecked.sneakyThrow0(e); - } - - @SuppressWarnings("unchecked") - private static T sneakyThrow0(Throwable t) throws E { - throw (E) t; - } - - @FunctionalInterface - public interface RunnableWhichCanThrow { - void run() throws Exception; - } - - @FunctionalInterface - public interface CallableWithCanThrow { - T call() throws Exception; - } -} diff --git a/application/src/main/java/net/emustudio/application/virtualcomputer/PluginLoader.java b/application/src/main/java/net/emustudio/application/virtualcomputer/PluginLoader.java index 981351247..0f4d73dd3 100644 --- a/application/src/main/java/net/emustudio/application/virtualcomputer/PluginLoader.java +++ b/application/src/main/java/net/emustudio/application/virtualcomputer/PluginLoader.java @@ -18,9 +18,9 @@ */ package net.emustudio.application.virtualcomputer; -import net.emustudio.application.internal.Unchecked; import net.emustudio.emulib.plugins.Plugin; import net.emustudio.emulib.plugins.annotations.PluginRoot; +import net.emustudio.emulib.runtime.helpers.Unchecked; import net.jcip.annotations.NotThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java b/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java index 0eb244394..97efb74ef 100644 --- a/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java +++ b/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java @@ -18,7 +18,6 @@ */ package net.emustudio.application.virtualcomputer; -import net.emustudio.application.internal.Unchecked; import net.emustudio.application.settings.AppSettings; import net.emustudio.application.settings.ComputerConfig; import net.emustudio.application.settings.PluginConfig; @@ -31,6 +30,7 @@ import net.emustudio.emulib.plugins.device.Device; import net.emustudio.emulib.plugins.memory.Memory; import net.emustudio.emulib.runtime.ApplicationApi; +import net.emustudio.emulib.runtime.helpers.Unchecked; import net.emustudio.emulib.runtime.settings.PluginSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/build.gradle b/build.gradle index d55da4a13..619a1ce84 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ ext.versions = [ ext.libs = [ emuLib : "net.emustudio:emulib:12.1.0-SNAPSHOT", - cpuTestSuite : "net.emustudio:cpu-testsuite_12.0:1.2.0", + cpuTestSuite : "net.emustudio:cpu-testsuite_12.1:1.2.0", jcipAnnotations : "net.jcip:jcip-annotations:1.0", antlr : "org.antlr:antlr4:4.12.0", diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/Assembler8080.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/Assembler8080.java index efd2d00ed..91d807c57 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/Assembler8080.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/Assembler8080.java @@ -43,9 +43,11 @@ import java.io.FileReader; import java.io.IOException; import java.io.Reader; -import java.util.*; - -import static net.emustudio.emulib.plugins.compiler.FileExtension.stripKnownExtension; +import java.nio.file.Path; +import java.util.List; +import java.util.MissingResourceException; +import java.util.Optional; +import java.util.ResourceBundle; @PluginRoot( type = PLUGIN_TYPE.COMPILER, @@ -71,9 +73,10 @@ public void initialize() { Optional.ofNullable(applicationApi.getContextPool()).ifPresent(pool -> { try { memory = pool.getMemoryContext(pluginID, MemoryContext.class); - if (memory.getDataType() != Byte.class) { + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { throw new InvalidContextException( - "Unexpected memory cell type. Expected Byte but was: " + memory.getDataType() + "Unexpected memory cell type. Expected Byte but was: " + cellTypeClass ); } } catch (InvalidContextException | ContextNotFoundException e) { @@ -103,21 +106,21 @@ public LexicalAnalyzer createLexer() { } @Override - public boolean compile(String inputFileName, String outputFileName) { + public void compile(Path inputPath, Optional outputPath) { notifyCompileStart(); notifyInfo(getTitle() + ", version " + getVersion()); - try (Reader reader = new FileReader(inputFileName)) { + Path finalOutputPath = outputPath.orElse(convertInputToOutputPath(inputPath, ".hex")); + try (Reader reader = new FileReader(inputPath.toFile())) { org.antlr.v4.runtime.Lexer lexer = createLexer(CharStreams.fromReader(reader)); - lexer.addErrorListener(new ParserErrorListener()); + lexer.addErrorListener(new ParserErrorListener(inputPath.toString())); CommonTokenStream tokens = new CommonTokenStream(lexer); As8080Parser parser = createParser(tokens); parser.removeErrorListeners(); - parser.addErrorListener(new ParserErrorListener()); + parser.addErrorListener(new ParserErrorListener(inputPath.toString())); - Program program = new Program(); - program.setFileName(inputFileName); + Program program = new Program(inputPath.toString()); new CreateProgramVisitor(program).visit(parser.rStart()); IntelHEX hex = new IntelHEX(); @@ -139,13 +142,13 @@ public boolean compile(String inputFileName, String outputFileName) { } if (program.env().hasNoErrors()) { - hex.generate(outputFileName); + hex.generate(finalOutputPath); int programLocation = hex.findProgramLocation(); applicationApi.setProgramLocation(programLocation); notifyInfo(String.format( "Compile was successful.\n\tOutput: %s\n\tProgram starts at 0x%s", - outputFileName, RadixUtils.formatWordHexString(programLocation) + finalOutputPath, RadixUtils.formatWordHexString(programLocation) )); if (memory != null) { @@ -154,30 +157,20 @@ public boolean compile(String inputFileName, String outputFileName) { } else { notifyWarning("Memory is not available."); } - return true; } else { for (CompileError error : program.env().getErrors()) { - notifyError(error.line, error.column, error.msg); + notifyError(error.position, error.msg); } - return false; } } catch (CompileException e) { - notifyError(e.line, e.column, e.getMessage()); - return false; + notifyError(e.position, e.getMessage()); } catch (IOException e) { notifyError("Compilation error: " + e); - return false; } finally { notifyCompileFinish(); } } - @Override - public boolean compile(String inputFileName) { - String outputFileName = stripKnownExtension(inputFileName, SOURCE_FILE_EXTENSIONS) + ".hex"; - return compile(inputFileName, outputFileName); - } - @Override public List getSourceFileExtensions() { return SOURCE_FILE_EXTENSIONS; diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/CompileError.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/CompileError.java index 5fb558900..4da2d4c35 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/CompileError.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/CompileError.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import java.io.IOException; @@ -36,20 +37,18 @@ public class CompileError { public static final int ERROR_VALUE_MUST_BE_POSITIVE = 10; public static final int ERROR_VALUE_OUT_OF_BOUNDS = 11; - public final int line; - public final int column; + public final SourceCodePosition position; public final String msg; public final int errorCode; - private CompileError(int line, int column, int errorCode, String msg) { - this.line = line; - this.column = column; + private CompileError(SourceCodePosition position, int errorCode, String msg) { + this.position = Objects.requireNonNull(position); this.errorCode = errorCode; this.msg = Objects.requireNonNull(msg); } private CompileError(Node node, int errorCode, String msg) { - this(node.line, node.column, errorCode, msg); + this(node.position, errorCode, msg); } @@ -112,8 +111,7 @@ public static CompileError valueOutOfBounds(Node node, int min, int max) { @Override public String toString() { return "CompileError{" + - "line=" + line + - ", column=" + column + + position + ", msg='" + msg + '\'' + ", errorCode=" + errorCode + '}'; diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ParserErrorListener.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ParserErrorListener.java index 1fbd5241f..c229ea4b8 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ParserErrorListener.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ParserErrorListener.java @@ -18,12 +18,21 @@ */ package net.emustudio.plugins.compiler.as8080; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.exceptions.SyntaxErrorException; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; +import java.util.Objects; + class ParserErrorListener extends BaseErrorListener { + private final String fileName; + + ParserErrorListener(String fileName) { + this.fileName = Objects.requireNonNull(fileName); + } + // TODO: parse message expected tokens to token categories @Override public void syntaxError( @@ -35,9 +44,9 @@ public void syntaxError( RecognitionException e) { if (e == null) { - throw new SyntaxErrorException(line, charPositionInLine, msg); + throw new SyntaxErrorException(new SourceCodePosition(line, charPositionInLine, fileName), msg); } else { - throw new SyntaxErrorException(line, charPositionInLine, msg, e); + throw new SyntaxErrorException(new SourceCodePosition(line, charPositionInLine, fileName), msg, e); } } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/Runner.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/Runner.java index a0c7abe2e..db9241ab8 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/Runner.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/Runner.java @@ -23,6 +23,9 @@ import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.settings.PluginSettings; +import java.nio.file.Path; +import java.util.Optional; + public class Runner { public static void main(String... args) { @@ -49,15 +52,6 @@ public static void main(String... args) { return; } inputFile = args[i]; - if (outputFile == null) { - int index = inputFile.lastIndexOf('.'); - if (index != -1) { - outputFile = inputFile.substring(0, index); - } else { - outputFile = inputFile; - } - outputFile += ".hex"; - } Assembler8080 compiler = new Assembler8080(0L, ApplicationApi.UNAVAILABLE, PluginSettings.UNAVAILABLE); compiler.addCompilerListener(new CompilerListener() { @@ -76,9 +70,10 @@ public void onFinish() { } }); try { - compiler.compile(inputFile, outputFile); + compiler.compile(Path.of(inputFile), Optional.ofNullable(outputFile).map(Path::of)); } catch (Exception e) { System.err.println(e.getMessage()); + System.exit(1); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Evaluated.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Evaluated.java index 9328f46db..cbaa1754a 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Evaluated.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Evaluated.java @@ -18,19 +18,20 @@ */ package net.emustudio.plugins.compiler.as8080.ast; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; public class Evaluated extends Node { public final int value; - public Evaluated(int line, int column, int value) { - super(line, column); + public Evaluated(SourceCodePosition position, int value) { + super(position); this.value = value; } @Override protected Node mkCopy() { - return new Evaluated(line, column, value); + return new Evaluated(position, value); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Node.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Node.java index 0c8104568..e3ec2207b 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Node.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Node.java @@ -18,22 +18,23 @@ */ package net.emustudio.plugins.compiler.as8080.ast; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; public abstract class Node { - public final int line; - public final int column; + public final SourceCodePosition position; + protected final List children = new ArrayList<>(); protected Node parent; private int address; - public Node(int line, int column) { - this.line = line; - this.column = column; + public Node(SourceCodePosition position) { + this.position = Objects.requireNonNull(position); } public void addChildFirst(Node node) { diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Program.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Program.java index bd037a368..12b4a3a9a 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Program.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/Program.java @@ -18,34 +18,25 @@ */ package net.emustudio.plugins.compiler.as8080.ast; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import java.util.Objects; -import java.util.Optional; public class Program extends Node { private final NameSpace env; - private String filename; - public Program(int line, int column, NameSpace env) { - super(line, column); + public Program(SourceCodePosition position, NameSpace env) { + super(position); this.env = Objects.requireNonNull(env); } - public Program(NameSpace env) { - this(0, 0, env); + public Program(String fileName, NameSpace env) { + this(new SourceCodePosition(0, 0, fileName), env); } - public Program() { - this(new NameSpace()); - } - - public Optional getFileName() { - return Optional.ofNullable(filename); - } - - public void setFileName(String filename) { - this.filename = filename; + public Program(String fileName) { + this(fileName, new NameSpace()); } public NameSpace env() { @@ -59,8 +50,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - Program program = new Program(line, column, env); - program.setFileName(filename); - return program; + return new Program(position, env); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDB.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDB.java index b2221c194..8a3a5c6ee 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDB.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDB.java @@ -18,13 +18,14 @@ */ package net.emustudio.plugins.compiler.as8080.ast.data; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; public class DataDB extends Node { - public DataDB(int line, int column) { - super(line, column); + public DataDB(SourceCodePosition position) { + super(position); // child is string, expr or 8-bit instruction } @@ -35,6 +36,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new DataDB(line, column); + return new DataDB(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDS.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDS.java index 7ccd466d3..9b756a529 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDS.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDS.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.data; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; @@ -26,8 +27,8 @@ * Child is an expression which must not use forward references and must not be negative. */ public class DataDS extends Node { - public DataDS(int line, int column) { - super(line, column); + public DataDS(SourceCodePosition position) { + super(position); } @Override @@ -37,6 +38,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new DataDS(line, column); + return new DataDS(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDW.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDW.java index 9ea33174d..c408ae9c1 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDW.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/data/DataDW.java @@ -18,13 +18,14 @@ */ package net.emustudio.plugins.compiler.as8080.ast.data; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; public class DataDW extends Node { - public DataDW(int line, int column) { - super(line, column); + public DataDW(SourceCodePosition position) { + super(position); // child is expr 2 byte } @@ -35,6 +36,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new DataDW(line, column); + return new DataDW(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprCurrentAddress.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprCurrentAddress.java index 3fd30f7f8..1b5e96fd0 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprCurrentAddress.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprCurrentAddress.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.NameSpace; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -27,8 +28,8 @@ public class ExprCurrentAddress extends Node { - public ExprCurrentAddress(int line, int column) { - super(line, column); + public ExprCurrentAddress(SourceCodePosition position) { + super(position); } @Override @@ -38,11 +39,11 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new ExprCurrentAddress(line, column); + return new ExprCurrentAddress(position); } @Override public Optional eval(Optional currentAddress, NameSpace env) { - return currentAddress.map(addr -> new Evaluated(line, column, addr)); + return currentAddress.map(addr -> new Evaluated(position, addr)); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprId.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprId.java index f7c8bd888..331cb77f3 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprId.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprId.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.NameSpace; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -32,13 +33,13 @@ public class ExprId extends Node { public final String id; - public ExprId(int line, int column, String id) { - super(line, column); + public ExprId(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); } - public ExprId(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public ExprId(String fileName, Token id) { + this(new SourceCodePosition(id.getLine(), id.getCharPositionInLine(), fileName), id.getText()); } @Override @@ -58,7 +59,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new ExprId(line, column, id); + return new ExprId(position, id); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprInfix.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprInfix.java index 2b841711c..d4389e634 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprInfix.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprInfix.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.NameSpace; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -62,15 +63,15 @@ public class ExprInfix extends Node { public final int operationCode; private final BiFunction operation; - public ExprInfix(int line, int column, int op) { - super(line, column); + public ExprInfix(SourceCodePosition position, int op) { + super(position); this.operationCode = op; this.operation = Objects.requireNonNull(infixOps.get(op), "Unknown infix operation"); // children are: left, right } - public ExprInfix(Token op) { - this(op.getLine(), op.getCharPositionInLine(), op.getType()); + public ExprInfix(String fileName, Token op) { + this(new SourceCodePosition(op.getLine(), op.getCharPositionInLine(), fileName), op.getType()); } @Override @@ -89,7 +90,7 @@ public Optional eval(Optional currentAddress, NameSpace env) if (left.isPresent() && right.isPresent()) { int l = left.get().value; int r = right.get().value; - return Optional.of(new Evaluated(line, column, operation.apply(l, r))); + return Optional.of(new Evaluated(position, operation.apply(l, r))); } return Optional.empty(); @@ -102,7 +103,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new ExprInfix(line, column, operationCode); + return new ExprInfix(position, operationCode); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprNumber.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprNumber.java index 2b04ddda2..58d81e840 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprNumber.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprNumber.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.NameSpace; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -30,18 +31,18 @@ public class ExprNumber extends Node { public final int number; - public ExprNumber(int line, int column, int number) { - super(line, column); + public ExprNumber(SourceCodePosition position, int number) { + super(position); this.number = number; } - public ExprNumber(Token number, Function parser) { - this(number.getLine(), number.getCharPositionInLine(), parser.apply(number)); + public ExprNumber(String fileName, Token number, Function parser) { + this(new SourceCodePosition(number.getLine(), number.getCharPositionInLine(), fileName), parser.apply(number)); } @Override public Optional eval(Optional currentAddress, NameSpace env) { - return Optional.of(new Evaluated(line, column, number)); + return Optional.of(new Evaluated(position, number)); } @Override @@ -56,7 +57,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new ExprNumber(line, column, number); + return new ExprNumber(position, number); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprString.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprString.java index 6f2ccd0a9..965e65f0c 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprString.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprString.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.NameSpace; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -32,13 +33,13 @@ public class ExprString extends Node { public final String string; - public ExprString(int line, int column, String string) { - super(line, column); + public ExprString(SourceCodePosition position, String string) { + super(position); this.string = Objects.requireNonNull(string); } - public ExprString(Token str) { - this(str.getLine(), str.getCharPositionInLine(), parseLitString(str)); + public ExprString(String fileName, Token str) { + this(new SourceCodePosition(str.getLine(), str.getCharPositionInLine(), fileName), parseLitString(str)); } @Override @@ -48,13 +49,13 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new ExprString(line, column, string); + return new ExprString(position, string); } @Override public Optional eval(Optional currentAddress, NameSpace env) { if (string.length() == 1) { - return Optional.of(new Evaluated(line, column, string.charAt(0) & 0xFF)); + return Optional.of(new Evaluated(position, string.charAt(0) & 0xFF)); } return Optional.empty(); } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprUnary.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprUnary.java index 64a9f2a0f..2449c33e2 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprUnary.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/expr/ExprUnary.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.NameSpace; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -41,15 +42,15 @@ public class ExprUnary extends Node { public final int operationCode; private final Function operation; - public ExprUnary(int line, int column, int op) { - super(line, column); + public ExprUnary(SourceCodePosition position, int op) { + super(position); this.operationCode = op; this.operation = Objects.requireNonNull(unaryOps.get(op), "Unknown unary operation"); // child is expr } - public ExprUnary(Token op) { - this(op.getLine(), op.getCharPositionInLine(), op.getType()); + public ExprUnary(String fileName, Token op) { + this(new SourceCodePosition(op.getLine(), op.getCharPositionInLine(), fileName), op.getType()); } @Override @@ -61,7 +62,7 @@ public void accept(NodeVisitor visitor) { public Optional eval(Optional currentAddress, NameSpace env) { return getChild(0) .eval(currentAddress, env) - .map(childEval -> new Evaluated(line, column, operation.apply(childEval.value))); + .map(childEval -> new Evaluated(position, operation.apply(childEval.value))); } @Override @@ -71,7 +72,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new ExprUnary(line, column, operationCode); + return new ExprUnary(position, operationCode); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrExpr.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrExpr.java index 4c74be3c1..2afa7eaff 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrExpr.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrExpr.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; @@ -80,14 +81,14 @@ public class InstrExpr extends Node { public final int opcode; - public InstrExpr(int line, int column, int opcode) { - super(line, column); + public InstrExpr(SourceCodePosition position, int opcode) { + super(position); this.opcode = opcode; // child is expr } - public InstrExpr(Token opcode) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType()); + public InstrExpr(String fileName, Token opcode) { + this(new SourceCodePosition(opcode.getLine(), opcode.getCharPositionInLine(), fileName), opcode.getType()); } public int getExprSizeBytes() { @@ -122,7 +123,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new InstrExpr(line, column, opcode); + return new InstrExpr(position, opcode); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrNoArgs.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrNoArgs.java index b7da20465..fa420dc73 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrNoArgs.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrNoArgs.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -60,13 +61,13 @@ public class InstrNoArgs extends Node { public final int opcode; - public InstrNoArgs(int line, int column, int opcode) { - super(line, column); + public InstrNoArgs(SourceCodePosition position, int opcode) { + super(position); this.opcode = opcode; } - public InstrNoArgs(Token opcode) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType()); + public InstrNoArgs(String fileName, Token opcode) { + this(new SourceCodePosition(opcode.getLine(), opcode.getCharPositionInLine(), fileName), opcode.getType()); } public byte eval() { @@ -85,7 +86,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new InstrNoArgs(line, column, opcode); + return new InstrNoArgs(position, opcode); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrReg.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrReg.java index 7ff5faebf..c8127255a 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrReg.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrReg.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -56,14 +57,14 @@ public class InstrReg extends Node { public final int opcode; public final int reg; - public InstrReg(int line, int column, int opcode, int reg) { - super(line, column); + public InstrReg(SourceCodePosition position, int opcode, int reg) { + super(position); this.opcode = opcode; this.reg = reg; } - public InstrReg(Token opcode, Token reg) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), reg.getType()); + public InstrReg(String fileName, Token opcode, Token reg) { + this(new SourceCodePosition(opcode.getLine(), opcode.getCharPositionInLine(), fileName), opcode.getType(), reg.getType()); } public byte eval() { @@ -87,7 +88,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new InstrReg(line, column, opcode, reg); + return new InstrReg(position, opcode, reg); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegExpr.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegExpr.java index 862c62121..e6a32035f 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegExpr.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegExpr.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -26,15 +27,15 @@ public class InstrRegExpr extends Node { public final int opcode; // MVI only public final int reg; - public InstrRegExpr(int line, int column, int opcode, int reg) { - super(line, column); + public InstrRegExpr(SourceCodePosition position, int opcode, int reg) { + super(position); this.opcode = opcode; this.reg = reg; // child is expr } - public InstrRegExpr(Token opcode, Token reg) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), reg.getType()); + public InstrRegExpr(String fileName, Token opcode, Token reg) { + this(new SourceCodePosition(opcode.getLine(), opcode.getCharPositionInLine(), fileName), opcode.getType(), reg.getType()); } public byte eval() { @@ -54,7 +55,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new InstrRegExpr(line, column, opcode, reg); + return new InstrRegExpr(position, opcode, reg); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegPair.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegPair.java index 8cf35c5f5..5451ab4dd 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegPair.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegPair.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -50,14 +51,14 @@ public class InstrRegPair extends Node { public final int opcode; public final int regPair; - public InstrRegPair(int line, int column, int opcode, int regPair) { - super(line, column); + public InstrRegPair(SourceCodePosition position, int opcode, int regPair) { + super(position); this.opcode = opcode; this.regPair = regPair; } - public InstrRegPair(Token opcode, Token regPair) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), regPair.getType()); + public InstrRegPair(String fileName, Token opcode, Token regPair) { + this(new SourceCodePosition(opcode.getLine(), opcode.getCharPositionInLine(), fileName), opcode.getType(), regPair.getType()); } public byte eval() { @@ -78,7 +79,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new InstrRegPair(line, column, opcode, regPair); + return new InstrRegPair(position, opcode, regPair); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegPairExpr.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegPairExpr.java index a83a35c57..0c6abca3c 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegPairExpr.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegPairExpr.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -26,15 +27,15 @@ public class InstrRegPairExpr extends Node { public final int opcode; public final int regPair; - public InstrRegPairExpr(int line, int column, int opcode, int regPair) { - super(line, column); + public InstrRegPairExpr(SourceCodePosition position, int opcode, int regPair) { + super(position); this.opcode = opcode; this.regPair = regPair; // child is expr } - public InstrRegPairExpr(Token opcode, Token regPair) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), regPair.getType()); + public InstrRegPairExpr(String fileName, Token opcode, Token regPair) { + this(new SourceCodePosition(opcode.getLine(), opcode.getCharPositionInLine(), fileName), opcode.getType(), regPair.getType()); } public byte eval() { @@ -54,7 +55,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new InstrRegPairExpr(line, column, opcode, regPair); + return new InstrRegPairExpr(position, opcode, regPair); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegReg.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegReg.java index f058fdcdc..7b758c7be 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegReg.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/instr/InstrRegReg.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,15 +28,15 @@ public class InstrRegReg extends Node { public final int srcReg; public final int dstReg; - public InstrRegReg(int line, int column, int opcode, int dst, int src) { - super(line, column); + public InstrRegReg(SourceCodePosition position, int opcode, int dst, int src) { + super(position); this.opcode = opcode; this.srcReg = src; this.dstReg = dst; } - public InstrRegReg(Token opcode, Token dst, Token src) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), dst.getType(), src.getType()); + public InstrRegReg(String fileName, Token opcode, Token dst, Token src) { + this(new SourceCodePosition(opcode.getLine(), opcode.getCharPositionInLine(), fileName), opcode.getType(), dst.getType(), src.getType()); } public byte eval() { @@ -56,7 +57,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new InstrRegReg(line, column, opcode, dstReg, srcReg); + return new InstrRegReg(position, opcode, dstReg, srcReg); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoEqu.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoEqu.java index 34d736ada..759b5b309 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoEqu.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoEqu.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,14 +28,14 @@ public class PseudoEqu extends Node { public final String id; - public PseudoEqu(int line, int column, String id) { - super(line, column); + public PseudoEqu(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); // expr is the only child } - public PseudoEqu(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public PseudoEqu(String fileName, Token id) { + this(new SourceCodePosition(id.getLine(), id.getCharPositionInLine(), fileName), id.getText()); } @Override @@ -49,7 +50,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoEqu(line, column, id); + return new PseudoEqu(position, id); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoIf.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoIf.java index fe25fec0f..f26af0f8a 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoIf.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoIf.java @@ -18,13 +18,14 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; public class PseudoIf extends Node { - public PseudoIf(int line, int column) { - super(line, column); + public PseudoIf(SourceCodePosition position) { + super(position); // expr is the first child // statement is the second child } @@ -36,6 +37,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoIf(line, column); + return new PseudoIf(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoIfExpression.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoIfExpression.java index bfba16399..bc281ee02 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoIfExpression.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoIfExpression.java @@ -18,12 +18,13 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; public class PseudoIfExpression extends Node { - public PseudoIfExpression(int line, int column) { - super(line, column); + public PseudoIfExpression(SourceCodePosition position) { + super(position); } @Override @@ -33,6 +34,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoIfExpression(line, column); + return new PseudoIfExpression(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoInclude.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoInclude.java index 1c79cf785..68f588e80 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoInclude.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoInclude.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ParsingUtils; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; @@ -28,13 +29,13 @@ public class PseudoInclude extends Node { public final String filename; - public PseudoInclude(int line, int column, String fileName) { - super(line, column); + public PseudoInclude(SourceCodePosition position, String fileName) { + super(position); this.filename = Objects.requireNonNull(fileName); } - public PseudoInclude(Token fileName) { - this(fileName.getLine(), fileName.getCharPositionInLine(), ParsingUtils.parseLitString(fileName)); + public PseudoInclude(String srcFileName, Token fileName) { + this(new SourceCodePosition(fileName.getLine(), fileName.getCharPositionInLine(), srcFileName), ParsingUtils.parseLitString(fileName)); } @Override @@ -49,7 +50,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoInclude(line, column, filename); + return new PseudoInclude(position, filename); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoLabel.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoLabel.java index 80351cc16..d55955cea 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoLabel.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoLabel.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.NameSpace; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -32,18 +33,18 @@ public class PseudoLabel extends Node { public final String label; - public PseudoLabel(int line, int column, String label) { - super(line, column); + public PseudoLabel(SourceCodePosition position, String label) { + super(position); this.label = Objects.requireNonNull(label); } - public PseudoLabel(Token label) { - this(label.getLine(), label.getCharPositionInLine(), parseLabel(label)); + public PseudoLabel(String fileName, Token label) { + this(new SourceCodePosition(label.getLine(), label.getCharPositionInLine(), fileName), parseLabel(label)); } @Override public Optional eval(Optional currentAddress, NameSpace env) { - return currentAddress.map(addr -> new Evaluated(line, column, addr)); + return currentAddress.map(addr -> new Evaluated(position, addr)); } @Override @@ -58,7 +59,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoLabel(line, column, label); + return new PseudoLabel(position, label); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroArgument.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroArgument.java index 3686bb349..cdf2e3e81 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroArgument.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroArgument.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; @@ -26,8 +27,8 @@ */ public class PseudoMacroArgument extends Node { - public PseudoMacroArgument(int line, int column) { - super(line, column); + public PseudoMacroArgument(SourceCodePosition position) { + super(position); // the only child is expr } @@ -38,6 +39,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoMacroArgument(line, column); + return new PseudoMacroArgument(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroCall.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroCall.java index 88548eb10..7ef478da3 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroCall.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroCall.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,14 +28,14 @@ public class PseudoMacroCall extends Node { public final String id; - public PseudoMacroCall(int line, int column, String id) { - super(line, column); + public PseudoMacroCall(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); // children are exprs (arguments) } - public PseudoMacroCall(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public PseudoMacroCall(String fileName, Token id) { + this(new SourceCodePosition(id.getLine(), id.getCharPositionInLine(), fileName), id.getText()); } @Override @@ -49,7 +50,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoMacroCall(line, column, id); + return new PseudoMacroCall(position, id); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroDef.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroDef.java index 6f17a5c9c..971882b29 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroDef.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroDef.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,15 +28,15 @@ public class PseudoMacroDef extends Node { public final String id; - public PseudoMacroDef(int line, int column, String id) { - super(line, column); + public PseudoMacroDef(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); // parameters are the first children // statements are followed } - public PseudoMacroDef(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public PseudoMacroDef(String fileName, Token id) { + this(new SourceCodePosition(id.getLine(), id.getCharPositionInLine(), fileName), id.getText()); } @Override @@ -58,6 +59,6 @@ public boolean equals(Object o) { } public PseudoMacroDef mkCopy() { - return new PseudoMacroDef(line, column, id); + return new PseudoMacroDef(position, id); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroParameter.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroParameter.java index 29ead291e..6fc0ba994 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroParameter.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoMacroParameter.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; @@ -26,8 +27,8 @@ */ public class PseudoMacroParameter extends Node { - public PseudoMacroParameter(int line, int column) { - super(line, column); + public PseudoMacroParameter(SourceCodePosition position) { + super(position); // the only child is ExprId } @@ -38,6 +39,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoMacroParameter(line, column); + return new PseudoMacroParameter(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoOrg.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoOrg.java index fd863c683..25d72f556 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoOrg.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoOrg.java @@ -18,13 +18,14 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; public class PseudoOrg extends Node { - public PseudoOrg(int line, int column) { - super(line, column); + public PseudoOrg(SourceCodePosition position) { + super(position); // expr is the only child } @@ -35,6 +36,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoOrg(line, column); + return new PseudoOrg(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoSet.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoSet.java index 62ddff1b0..efe9ec271 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoSet.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/ast/pseudo/PseudoSet.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,14 +28,14 @@ public class PseudoSet extends Node { public final String id; - public PseudoSet(int line, int column, String id) { - super(line, column); + public PseudoSet(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); // expr is the only child } - public PseudoSet(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public PseudoSet(String fileName, Token id) { + this(new SourceCodePosition(id.getLine(), id.getCharPositionInLine(), fileName), id.getText()); } @Override @@ -49,7 +50,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoSet(line, column, id); + return new PseudoSet(position, id); } @Override diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/CompileException.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/CompileException.java index 6f9f6971c..adbac5b9a 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/CompileException.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/CompileException.java @@ -18,21 +18,20 @@ */ package net.emustudio.plugins.compiler.as8080.exceptions; -public class CompileException extends RuntimeException { - public final int line; - public final int column; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; - public CompileException(int line, int column, String message) { - super("[" + line + "," + column + "] " + message); +import java.util.Objects; - this.column = column; - this.line = line; - } +public class CompileException extends RuntimeException { + public final SourceCodePosition position; - public CompileException(int line, int column, String message, Throwable cause) { - super("[" + line + "," + column + "] " + message, cause); + public CompileException(SourceCodePosition position, String message) { + super(position + " " + message); + this.position = Objects.requireNonNull(position); + } - this.column = column; - this.line = line; + public CompileException(SourceCodePosition position, String message, Throwable cause) { + super(position + " " + message, cause); + this.position = Objects.requireNonNull(position); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/FatalError.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/FatalError.java index 95f908302..9f80c900a 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/FatalError.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/FatalError.java @@ -18,19 +18,20 @@ */ package net.emustudio.plugins.compiler.as8080.exceptions; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.CompileError; public class FatalError extends CompileException { - public FatalError(int line, int column, String why) { - super(line, column, "Fatal error (cannot continue): " + why); + public FatalError(SourceCodePosition position, String why) { + super(position, "Fatal error (cannot continue): " + why); } - public static void now(int line, int column, String why) { - throw new FatalError(line, column, why); + public static void now(SourceCodePosition position, String why) { + throw new FatalError(position, why); } public static void now(CompileError error) { - now(error.line, error.column, error.msg); + now(error.position, error.msg); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/SyntaxErrorException.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/SyntaxErrorException.java index 22969794d..f072de80b 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/SyntaxErrorException.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/exceptions/SyntaxErrorException.java @@ -18,12 +18,14 @@ */ package net.emustudio.plugins.compiler.as8080.exceptions; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; + public class SyntaxErrorException extends CompileException { - public SyntaxErrorException(int line, int column, String message) { - super(line, column, message); + public SyntaxErrorException(SourceCodePosition position, String message) { + super(position, message); } - public SyntaxErrorException(int line, int column, String message, Throwable cause) { - super(line, column, message, cause); + public SyntaxErrorException(SourceCodePosition position, String message, Throwable cause) { + super(position, message, cause); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateDataVisitor.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateDataVisitor.java index 3ad8d4dea..e9c23688e 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateDataVisitor.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateDataVisitor.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.As8080Parser.*; import net.emustudio.plugins.compiler.as8080.As8080ParserBaseVisitor; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -26,18 +27,25 @@ import net.emustudio.plugins.compiler.as8080.ast.data.DataDW; import org.antlr.v4.runtime.Token; +import java.util.Objects; + public class CreateDataVisitor extends As8080ParserBaseVisitor { + private final String sourceFileName; + + public CreateDataVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } @Override public Node visitDataDB(DataDBContext ctx) { Token start = ctx.getStart(); - DataDB db = new DataDB(start.getLine(), start.getCharPositionInLine()); + DataDB db = new DataDB(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); for (RDBdataContext next : ctx.rDBdata()) { if (next.expr != null) { - db.addChild(CreateVisitors.expr.visit(next.expr)); + db.addChild(exprVisitor().visit(next.expr)); } else if (next.instr != null) { - db.addChild(CreateVisitors.instr.visit(next.instr)); + db.addChild(instrVisitor().visit(next.instr)); } } return db; @@ -46,11 +54,11 @@ public Node visitDataDB(DataDBContext ctx) { @Override public Node visitDataDW(DataDWContext ctx) { Token start = ctx.getStart(); - DataDW dw = new DataDW(start.getLine(), start.getCharPositionInLine()); + DataDW dw = new DataDW(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); for (RDWdataContext next : ctx.rDWdata()) { if (next.expr != null) { - dw.addChild(CreateVisitors.expr.visit(next.expr)); + dw.addChild(exprVisitor().visit(next.expr)); } } @@ -60,8 +68,15 @@ public Node visitDataDW(DataDWContext ctx) { @Override public Node visitDataDS(DataDSContext ctx) { Token start = ctx.getStart(); - DataDS ds = new DataDS(start.getLine(), start.getCharPositionInLine()); - ds.addChild(CreateVisitors.expr.visit(ctx.data)); + DataDS ds = new DataDS(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); + ds.addChild(exprVisitor().visit(ctx.data)); return ds; } + + private CreateExprVisitor exprVisitor() { + return CreateVisitors.expr(sourceFileName); + }; + private CreateInstrVisitor instrVisitor() { + return CreateVisitors.instr(sourceFileName); + } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateExprVisitor.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateExprVisitor.java index 7cdfa2e49..724d7b3a5 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateExprVisitor.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateExprVisitor.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.As8080Parser; import net.emustudio.plugins.compiler.as8080.As8080ParserBaseVisitor; import net.emustudio.plugins.compiler.as8080.ParsingUtils; @@ -25,53 +26,61 @@ import net.emustudio.plugins.compiler.as8080.ast.expr.*; import org.antlr.v4.runtime.Token; +import java.util.Objects; + public class CreateExprVisitor extends As8080ParserBaseVisitor { + private final String sourceFileName; + + public CreateExprVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } + @Override public Node visitExprOct(As8080Parser.ExprOctContext ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitOct); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitOct); } @Override public Node visitExprHex1(As8080Parser.ExprHex1Context ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitHex1); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitHex1); } @Override public Node visitExprHex2(As8080Parser.ExprHex2Context ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitHex2); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitHex2); } @Override public Node visitExprDec(As8080Parser.ExprDecContext ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitDec); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitDec); } @Override public Node visitExprBin(As8080Parser.ExprBinContext ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitBin); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitBin); } @Override public Node visitExprId(As8080Parser.ExprIdContext ctx) { - return new ExprId(ctx.id); + return new ExprId(sourceFileName, ctx.id); } @Override public Node visitExprString(As8080Parser.ExprStringContext ctx) { - return new ExprString(ctx.str); + return new ExprString(sourceFileName, ctx.str); } @Override public Node visitExprUnary(As8080Parser.ExprUnaryContext ctx) { - ExprUnary unary = new ExprUnary(ctx.unaryop); + ExprUnary unary = new ExprUnary(sourceFileName, ctx.unaryop); unary.addChild(visit(ctx.expr)); return unary; } @Override public Node visitExprInfix(As8080Parser.ExprInfixContext ctx) { - ExprInfix infix = new ExprInfix(ctx.op); + ExprInfix infix = new ExprInfix(sourceFileName, ctx.op); infix.addChild(visit(ctx.expr1)); infix.addChild(visit(ctx.expr2)); return infix; @@ -85,6 +94,6 @@ public Node visitExprParens(As8080Parser.ExprParensContext ctx) { @Override public Node visitExprCurrentAddress(As8080Parser.ExprCurrentAddressContext ctx) { Token start = ctx.getStart(); - return new ExprCurrentAddress(start.getLine(), start.getCharPositionInLine()); + return new ExprCurrentAddress(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateInstrVisitor.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateInstrVisitor.java index a0dd79174..c8f080817 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateInstrVisitor.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateInstrVisitor.java @@ -23,53 +23,64 @@ import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.ast.instr.*; +import java.util.Objects; + public class CreateInstrVisitor extends As8080ParserBaseVisitor { + private final String sourceFileName; + + public CreateInstrVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } @Override public Node visitInstrNoArgs(As8080Parser.InstrNoArgsContext ctx) { - return new InstrNoArgs(ctx.opcode); + return new InstrNoArgs(sourceFileName, ctx.opcode); } @Override public Node visitInstrReg(As8080Parser.InstrRegContext ctx) { - return new InstrReg(ctx.opcode, ctx.reg.getStart()); + return new InstrReg(sourceFileName, ctx.opcode, ctx.reg.getStart()); } @Override public Node visitInstrRegReg(As8080Parser.InstrRegRegContext ctx) { - return new InstrRegReg(ctx.opcode, ctx.dst.getStart(), ctx.src.getStart()); + return new InstrRegReg(sourceFileName, ctx.opcode, ctx.dst.getStart(), ctx.src.getStart()); } @Override public Node visitInstrRegPair(As8080Parser.InstrRegPairContext ctx) { - return new InstrRegPair(ctx.opcode, ctx.regpair); + return new InstrRegPair(sourceFileName, ctx.opcode, ctx.regpair); } @Override public Node visitInstrRegPairExpr(As8080Parser.InstrRegPairExprContext ctx) { - InstrRegPairExpr instr = new InstrRegPairExpr(ctx.opcode, ctx.regpair); - instr.addChild(CreateVisitors.expr.visit(ctx.expr)); + InstrRegPairExpr instr = new InstrRegPairExpr(sourceFileName, ctx.opcode, ctx.regpair); + instr.addChild(exprVisitor().visit(ctx.expr)); return instr; } @Override public Node visitInstrRegExpr(As8080Parser.InstrRegExprContext ctx) { - InstrRegExpr instr = new InstrRegExpr(ctx.opcode, ctx.reg.getStart()); - instr.addChild(CreateVisitors.expr.visit(ctx.expr)); + InstrRegExpr instr = new InstrRegExpr(sourceFileName, ctx.opcode, ctx.reg.getStart()); + instr.addChild(exprVisitor().visit(ctx.expr)); return instr; } @Override public Node visitInstrExpr(As8080Parser.InstrExprContext ctx) { - InstrExpr instr = new InstrExpr(ctx.opcode); - instr.addChild(CreateVisitors.expr.visit(ctx.expr)); + InstrExpr instr = new InstrExpr(sourceFileName, ctx.opcode); + instr.addChild(exprVisitor().visit(ctx.expr)); return instr; } @Override public Node visitInstr8bitExpr(As8080Parser.Instr8bitExprContext ctx) { - InstrExpr instr = new InstrExpr(ctx.opcode); - instr.addChild(CreateVisitors.expr.visit(ctx.expr)); + InstrExpr instr = new InstrExpr(sourceFileName, ctx.opcode); + instr.addChild(exprVisitor().visit(ctx.expr)); return instr; } + + private CreateExprVisitor exprVisitor() { + return CreateVisitors.expr(sourceFileName); + }; } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateLineVisitor.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateLineVisitor.java index 60804be05..2008caf22 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateLineVisitor.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateLineVisitor.java @@ -23,13 +23,21 @@ import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.ast.pseudo.PseudoLabel; +import java.util.Objects; + public class CreateLineVisitor extends As8080ParserBaseVisitor { + private final String sourceFileName; + + public CreateLineVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } + @Override public Node visitRLine(As8080Parser.RLineContext ctx) { Node label = null; if (ctx.label != null) { - label = new PseudoLabel(ctx.label); + label = new PseudoLabel(sourceFileName, ctx.label); } Node statement = null; if (ctx.statement != null) { @@ -47,12 +55,26 @@ public Node visitRLine(As8080Parser.RLineContext ctx) { @Override public Node visitRStatement(As8080Parser.RStatementContext ctx) { if (ctx.instr != null) { - return CreateVisitors.instr.visit(ctx.instr); + return instrVisitor().visit(ctx.instr); } else if (ctx.data != null) { - return CreateVisitors.data.visit(ctx.data); + return dataVisitor().visit(ctx.data); } else if (ctx.pseudo != null) { - return CreateVisitors.pseudo.visit(ctx.pseudo); + return pseudoVisitor().visit(ctx.pseudo); } throw new IllegalStateException("No statement defined!"); } + + private CreateInstrVisitor instrVisitor() { + return CreateVisitors.instr(sourceFileName); + } + + ; + + private CreateDataVisitor dataVisitor() { + return CreateVisitors.data(sourceFileName); + } + + private CreatePseudoVisitor pseudoVisitor() { + return CreateVisitors.pseudo(sourceFileName); + } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateProgramVisitor.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateProgramVisitor.java index 3abf56e32..1fb3d292a 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateProgramVisitor.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateProgramVisitor.java @@ -37,10 +37,14 @@ public CreateProgramVisitor(Program program) { @Override public Program visitRLine(As8080Parser.RLineContext ctx) { - Node statement = CreateVisitors.line.visitRLine(ctx); + Node statement = lineVisitor().visitRLine(ctx); if (statement != null) { program.addChild(statement); } return program; } + + private CreateLineVisitor lineVisitor() { + return CreateVisitors.line(program.position.fileName); + } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreatePseudoVisitor.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreatePseudoVisitor.java index 21df51874..3525f27dd 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreatePseudoVisitor.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreatePseudoVisitor.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.As8080Parser.*; import net.emustudio.plugins.compiler.as8080.As8080ParserBaseVisitor; import net.emustudio.plugins.compiler.as8080.ast.Node; @@ -26,27 +27,34 @@ import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.TerminalNode; +import java.util.Objects; + public class CreatePseudoVisitor extends As8080ParserBaseVisitor { + private final String sourceFileName; + + public CreatePseudoVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } @Override public Node visitPseudoOrg(PseudoOrgContext ctx) { Token start = ctx.getStart(); - PseudoOrg pseudo = new PseudoOrg(start.getLine(), start.getCharPositionInLine()); - pseudo.addChild(CreateVisitors.expr.visit(ctx.expr)); + PseudoOrg pseudo = new PseudoOrg(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); + pseudo.addChild(exprVisitor().visit(ctx.expr)); return pseudo; } @Override public Node visitPseudoEqu(PseudoEquContext ctx) { - PseudoEqu pseudo = new PseudoEqu(ctx.id); - pseudo.addChild(CreateVisitors.expr.visit(ctx.expr)); + PseudoEqu pseudo = new PseudoEqu(sourceFileName, ctx.id); + pseudo.addChild(exprVisitor().visit(ctx.expr)); return pseudo; } @Override public Node visitPseudoVar(PseudoVarContext ctx) { - PseudoSet pseudo = new PseudoSet(ctx.id); - pseudo.addChild(CreateVisitors.expr.visit(ctx.expr)); + PseudoSet pseudo = new PseudoSet(sourceFileName, ctx.id); + pseudo.addChild(exprVisitor().visit(ctx.expr)); return pseudo; } @@ -54,13 +62,13 @@ public Node visitPseudoVar(PseudoVarContext ctx) { public Node visitPseudoIf(PseudoIfContext ctx) { Token start = ctx.getStart(); - PseudoIf pseudo = new PseudoIf(start.getLine(), start.getCharPositionInLine()); - Node expr = CreateVisitors.expr.visit(ctx.expr); - PseudoIfExpression ifExpr = new PseudoIfExpression(expr.line, expr.column); + PseudoIf pseudo = new PseudoIf(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); + Node expr = exprVisitor().visit(ctx.expr); + PseudoIfExpression ifExpr = new PseudoIfExpression(expr.position); ifExpr.addChild(expr); pseudo.addChild(ifExpr); for (RLineContext line : ctx.rLine()) { - Node rLine = CreateVisitors.line.visitRLine(line); + Node rLine = lineVisitor().visitRLine(line); if (rLine != null) { pseudo.addChild(rLine); } @@ -70,18 +78,18 @@ public Node visitPseudoIf(PseudoIfContext ctx) { @Override public Node visitPseudoMacroDef(PseudoMacroDefContext ctx) { - PseudoMacroDef pseudo = new PseudoMacroDef(ctx.id); + PseudoMacroDef pseudo = new PseudoMacroDef(sourceFileName, ctx.id); if (ctx.params != null) { for (TerminalNode next : ctx.params.ID_IDENTIFIER()) { Token symbol = next.getSymbol(); - PseudoMacroParameter parameter = new PseudoMacroParameter(symbol.getLine(), symbol.getCharPositionInLine()); - parameter.addChild(new ExprId(next.getSymbol())); + PseudoMacroParameter parameter = new PseudoMacroParameter(new SourceCodePosition(symbol.getLine(), symbol.getCharPositionInLine(), sourceFileName)); + parameter.addChild(new ExprId(sourceFileName, next.getSymbol())); pseudo.addChild(parameter); } } for (RLineContext line : ctx.rLine()) { - Node rLine = CreateVisitors.line.visitRLine(line); + Node rLine = lineVisitor().visitRLine(line); if (rLine != null) { pseudo.addChild(rLine); } @@ -91,13 +99,13 @@ public Node visitPseudoMacroDef(PseudoMacroDefContext ctx) { @Override public Node visitPseudoMacroCall(PseudoMacroCallContext ctx) { - PseudoMacroCall pseudo = new PseudoMacroCall(ctx.id); + PseudoMacroCall pseudo = new PseudoMacroCall(sourceFileName, ctx.id); if (ctx.args != null) { for (RExpressionContext next : ctx.args.rExpression()) { Token start = next.getStart(); - PseudoMacroArgument argument = new PseudoMacroArgument(start.getLine(), start.getCharPositionInLine()); - pseudo.addChild(argument.addChild(CreateVisitors.expr.visit(next))); + PseudoMacroArgument argument = new PseudoMacroArgument(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); + pseudo.addChild(argument.addChild(exprVisitor().visit(next))); } } return pseudo; @@ -105,6 +113,13 @@ public Node visitPseudoMacroCall(PseudoMacroCallContext ctx) { @Override public Node visitPseudoInclude(PseudoIncludeContext ctx) { - return new PseudoInclude(ctx.filename); + return new PseudoInclude(sourceFileName, ctx.filename); + } + + private CreateExprVisitor exprVisitor() { + return CreateVisitors.expr(sourceFileName); + }; + private CreateLineVisitor lineVisitor() { + return CreateVisitors.line(sourceFileName); } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateVisitors.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateVisitors.java index 7d7617454..c98ad9536 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateVisitors.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/CreateVisitors.java @@ -18,12 +18,38 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + public class CreateVisitors { + private final static Map PSEUDO_CACHE = new ConcurrentHashMap<>(); + private final static Map EXPR_CACHE = new ConcurrentHashMap<>(); + private final static Map INSTR_CACHE = new ConcurrentHashMap<>(); + private final static Map DATA_CACHE = new ConcurrentHashMap<>(); + private final static Map LINE_CACHE = new ConcurrentHashMap<>(); + + static CreatePseudoVisitor pseudo(String sourceFileName) { + PSEUDO_CACHE.putIfAbsent(sourceFileName, new CreatePseudoVisitor(sourceFileName)); + return PSEUDO_CACHE.get(sourceFileName); + } + + static CreateExprVisitor expr(String sourceFileName) { + EXPR_CACHE.putIfAbsent(sourceFileName, new CreateExprVisitor(sourceFileName)); + return EXPR_CACHE.get(sourceFileName); + } + + static CreateInstrVisitor instr(String sourceFileName) { + INSTR_CACHE.putIfAbsent(sourceFileName, new CreateInstrVisitor(sourceFileName)); + return INSTR_CACHE.get(sourceFileName); + } - static CreatePseudoVisitor pseudo = new CreatePseudoVisitor(); - static CreateExprVisitor expr = new CreateExprVisitor(); - static CreateInstrVisitor instr = new CreateInstrVisitor(); - static CreateDataVisitor data = new CreateDataVisitor(); - static CreateLineVisitor line = new CreateLineVisitor(); + static CreateDataVisitor data(String sourceFileName) { + DATA_CACHE.putIfAbsent(sourceFileName, new CreateDataVisitor(sourceFileName)); + return DATA_CACHE.get(sourceFileName); + } + static CreateLineVisitor line(String sourceFileName) { + LINE_CACHE.putIfAbsent(sourceFileName, new CreateLineVisitor(sourceFileName)); + return LINE_CACHE.get(sourceFileName); + } } diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/EvaluateExprVisitor.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/EvaluateExprVisitor.java index f07b2b75a..a57f94611 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/EvaluateExprVisitor.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/EvaluateExprVisitor.java @@ -341,12 +341,12 @@ public void visit(ExprString node) { if (strLen > 1) { result |= (node.string.charAt(1) << 8); } - Node evaluated = new Evaluated(node.line, node.column, result); + Node evaluated = new Evaluated(node.position, result); parent.ifPresent(p -> p.addChild(evaluated)); currentAddress += sizeBytes; } else { for (int i = 0; i < strLen; i++) { - Node evaluated = new Evaluated(node.line, node.column, node.string.charAt(i)); + Node evaluated = new Evaluated(node.position, node.string.charAt(i)); parent.ifPresent(p -> p.addChild(evaluated)); } if (sizeBytes != 0) { diff --git a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandIncludesVisitor.java b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandIncludesVisitor.java index 13aa39ac9..bb4d72cf0 100644 --- a/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandIncludesVisitor.java +++ b/plugins/compiler/as-8080/src/main/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandIncludesVisitor.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.As8080Lexer; import net.emustudio.plugins.compiler.as8080.As8080Parser; import net.emustudio.plugins.compiler.as8080.ast.Program; @@ -51,7 +52,7 @@ public ExpandIncludesVisitor(Set includedFiles) { @Override public void visit(Program node) { - this.inputFileName = node.getFileName(); + this.inputFileName = Optional.ofNullable(node.position.fileName); super.visit(node); } @@ -68,8 +69,7 @@ public void visit(PseudoInclude node) { As8080Parser parser = new As8080Parser(stream); stream.fill(); ParseTree tree = parser.rStart(); - Program program = new Program(node.line, node.column, env); - program.setFileName(absoluteFileName); + Program program = new Program(new SourceCodePosition(node.position.line, node.position.column, absoluteFileName), env); new CreateProgramVisitor(program).visit(tree); diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/Utils.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/Utils.java index aec4f2c42..c3ff48957 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/Utils.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/Utils.java @@ -81,14 +81,14 @@ public static ParseTree parse(String program) { CommonTokenStream stream = new CommonTokenStream(lexer); As8080Parser parser = new As8080Parser(stream); parser.removeErrorListeners(); - parser.addErrorListener(new ParserErrorListener()); + parser.addErrorListener(new ParserErrorListener("")); stream.fill(); return parser.rStart(); } public static Program parseProgram(String programString) { ParseTree tree = parse(programString); - Program program = new Program(); + Program program = new Program(""); CreateProgramVisitor visitor = new CreateProgramVisitor(program); visitor.visit(tree); return program; diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/e2e/AbstractCompilerTest.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/e2e/AbstractCompilerTest.java index cfa7d13a5..f7c220316 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/e2e/AbstractCompilerTest.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/e2e/AbstractCompilerTest.java @@ -35,6 +35,7 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.StandardOpenOption; +import java.util.Optional; import static org.easymock.EasyMock.*; import static org.junit.Assert.assertEquals; @@ -44,6 +45,7 @@ public abstract class AbstractCompilerTest { public TemporaryFolder folder = new TemporaryFolder(); protected Assembler8080 compiler; protected MemoryStub memoryStub; + private int errorCount; @SuppressWarnings("unchecked") @Before @@ -59,6 +61,7 @@ public void setUp() throws Exception { replay(applicationApi); compiler = new Assembler8080(0L, applicationApi, PluginSettings.UNAVAILABLE); + errorCount = 0; compiler.addCompilerListener(new CompilerListener() { @Override public void onStart() { @@ -69,6 +72,9 @@ public void onMessage(CompilerMessage message) { if (message.getMessageType() != CompilerMessage.MessageType.TYPE_INFO) { System.out.println(message); } + if (message.getMessageType() == CompilerMessage.MessageType.TYPE_ERROR) { + errorCount++; + } } @Override @@ -83,8 +89,9 @@ protected void compile(String content) throws Exception { Files.write(sourceFile.toPath(), content.getBytes(), StandardOpenOption.WRITE); File outputFile = folder.newFile(); - if (!compiler.compile(sourceFile.getAbsolutePath(), outputFile.getAbsolutePath())) { - throw new Exception("Compilation failed"); + compiler.compile(sourceFile.toPath(), Optional.of(outputFile.toPath())); + if (errorCount > 0) { + throw new Exception("Compilation failed with " + errorCount + " errors"); } } diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseDataTest.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseDataTest.java index 1df4d4b14..a56662de9 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseDataTest.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseDataTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.parser; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Program; import net.emustudio.plugins.compiler.as8080.ast.data.DataDB; import net.emustudio.plugins.compiler.as8080.ast.data.DataDS; @@ -34,13 +35,14 @@ import static net.emustudio.plugins.compiler.as8080.Utils.parseProgram; public class ParseDataTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); @Test public void testDBstring1() { Program program = parseProgram("db 'hello'"); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprString(0, 0, "hello"))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprString(POSITION, "hello"))), program ); } @@ -48,9 +50,9 @@ public void testDBstring1() { @Test public void testDBstring2() { Program program = parseProgram("db \"hello\""); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprString(0, 0, "hello"))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprString(POSITION, "hello"))), program ); } @@ -59,9 +61,9 @@ public void testDBstring2() { public void testDBinstruction() { Program program = parseProgram("db stc"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new InstrNoArgs(0, 0, OPCODE_STC))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new InstrNoArgs(POSITION, OPCODE_STC))), program ); } @@ -69,12 +71,12 @@ public void testDBinstruction() { @Test public void testMultipleDB() { Program program = parseProgram("db -1,2,3"); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))), program ); } @@ -82,10 +84,10 @@ public void testMultipleDB() { @Test public void testDBwithNegativeValue() { Program program = parseProgram("db -1"); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1)))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1)))), program ); } @@ -93,12 +95,12 @@ public void testDBwithNegativeValue() { @Test public void testMultipleDBstringNumberString() { Program program = parseProgram("db -1,'hello',3"); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprString(0, 0, "hello")) - .addChild(new ExprNumber(0, 0, 3))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprString(POSITION, "hello")) + .addChild(new ExprNumber(POSITION, 3))), program ); } @@ -106,12 +108,12 @@ public void testMultipleDBstringNumberString() { @Test public void testMultipleDW() { Program program = parseProgram("dw -1,2,3"); - assertTrees(new Program() - .addChild(new DataDW(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))), + assertTrees(new Program("") + .addChild(new DataDW(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))), program ); } @@ -119,10 +121,10 @@ public void testMultipleDW() { @Test public void testDWwithNegativeValue() { Program program = parseProgram("dw -1"); - assertTrees(new Program() - .addChild(new DataDW(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1)))), + assertTrees(new Program("") + .addChild(new DataDW(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1)))), program ); } @@ -130,9 +132,9 @@ public void testDWwithNegativeValue() { @Test public void testDS() { Program program = parseProgram("ds 0x55"); - assertTrees(new Program() - .addChild(new DataDS(0, 0) - .addChild(new ExprNumber(0, 0, 0x55))), + assertTrees(new Program("") + .addChild(new DataDS(POSITION) + .addChild(new ExprNumber(POSITION, 0x55))), program ); } diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseExprTest.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseExprTest.java index 2c63647a5..3b5ccc2bd 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseExprTest.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseExprTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.parser; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Program; import net.emustudio.plugins.compiler.as8080.ast.data.DataDB; import net.emustudio.plugins.compiler.as8080.ast.expr.ExprInfix; @@ -30,18 +31,19 @@ import static net.emustudio.plugins.compiler.as8080.Utils.parseProgram; public class ParseExprTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); @Test public void testPrioritiesAddMul() { Program program = parseProgram("db 2+3*4"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprNumber(0, 0, 3)) - .addChild(new ExprNumber(0, 0, 4))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprNumber(POSITION, 3)) + .addChild(new ExprNumber(POSITION, 4))))), program ); } @@ -50,13 +52,13 @@ public void testPrioritiesAddMul() { public void testPrioritiesMulAdd() { Program program = parseProgram("db 2*3+4"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new ExprNumber(0, 0, 4)))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new ExprNumber(POSITION, 4)))), program ); } @@ -65,15 +67,15 @@ public void testPrioritiesMulAdd() { public void testAssociativityPlusMinus() { Program program = parseProgram("db 2-3+4-9"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new ExprNumber(0, 0, 4))) - .addChild(new ExprNumber(0, 0, 9)))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new ExprNumber(POSITION, 4))) + .addChild(new ExprNumber(POSITION, 9)))), program ); } @@ -82,15 +84,15 @@ public void testAssociativityPlusMinus() { public void testAssociativitMulDiv() { Program program = parseProgram("db 2/3*4/9"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_DIVIDE) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprInfix(0, 0, OP_DIVIDE) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new ExprNumber(0, 0, 4))) - .addChild(new ExprNumber(0, 0, 9)))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_DIVIDE) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprInfix(POSITION, OP_DIVIDE) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new ExprNumber(POSITION, 4))) + .addChild(new ExprNumber(POSITION, 9)))), program ); } @@ -99,19 +101,19 @@ public void testAssociativitMulDiv() { public void testPrecedencePlusMinusMulDivMod() { Program program = parseProgram("db 2+3*4-9/2 mod 3"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprNumber(0, 0, 3)) - .addChild(new ExprNumber(0, 0, 4)))) - .addChild(new ExprInfix(0, 0, OP_MOD) - .addChild(new ExprInfix(0, 0, OP_DIVIDE) - .addChild(new ExprNumber(0, 0, 9)) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprNumber(0, 0, 3))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprNumber(POSITION, 3)) + .addChild(new ExprNumber(POSITION, 4)))) + .addChild(new ExprInfix(POSITION, OP_MOD) + .addChild(new ExprInfix(POSITION, OP_DIVIDE) + .addChild(new ExprNumber(POSITION, 9)) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprNumber(POSITION, 3))))), program ); } @@ -120,21 +122,21 @@ public void testPrecedencePlusMinusMulDivMod() { public void testAssociativityEqual() { Program program = parseProgram("db 1 + 2 + 2 = 5 = 5 = 6 - 1"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprInfix(0, 0, OP_ADD) // 1 + 2 + 2 associates to left - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 1)) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprNumber(0, 0, 5)) // ... = 5 associates to right - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprNumber(0, 0, 5)) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) // minus has > precedence than = - .addChild(new ExprNumber(0, 0, 6)) - .addChild(new ExprNumber(0, 0, 1))))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprInfix(POSITION, OP_ADD) // 1 + 2 + 2 associates to left + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 1)) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprNumber(POSITION, 5)) // ... = 5 associates to right + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprNumber(POSITION, 5)) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) // minus has > precedence than = + .addChild(new ExprNumber(POSITION, 6)) + .addChild(new ExprNumber(POSITION, 1))))))), program ); } @@ -143,27 +145,27 @@ public void testAssociativityEqual() { public void testAndMulXorDivNotPlusMinus() { Program program = parseProgram("db not 1 and 2 or 2 xor 5 = - 5 * 6 shl 4 - 1 shr 2"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_OR) - .addChild(new ExprInfix(0, 0, OP_AND) - .addChild(new ExprUnary(0, 0, OP_NOT) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprInfix(0, 0, OP_XOR) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprNumber(0, 0, 5)) - .addChild(new ExprInfix(0, 0, OP_SHR) - .addChild(new ExprInfix(0, 0, OP_SHL) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 5))) - .addChild(new ExprNumber(0, 0, 6))) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 4)) - .addChild(new ExprNumber(0, 0, 1)))) - .addChild(new ExprNumber(0, 0, 2))))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_OR) + .addChild(new ExprInfix(POSITION, OP_AND) + .addChild(new ExprUnary(POSITION, OP_NOT) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprInfix(POSITION, OP_XOR) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprNumber(POSITION, 5)) + .addChild(new ExprInfix(POSITION, OP_SHR) + .addChild(new ExprInfix(POSITION, OP_SHL) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 5))) + .addChild(new ExprNumber(POSITION, 6))) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 4)) + .addChild(new ExprNumber(POSITION, 1)))) + .addChild(new ExprNumber(POSITION, 2))))))), program ); } @@ -172,27 +174,27 @@ public void testAndMulXorDivNotPlusMinus() { public void testAndMulXorDivNotPlusMinusWithOperators() { Program program = parseProgram("db ~1 & 2 | 2 ^ 5 = -5 * 6 << 4 - 1 >> 2"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_OR_2) - .addChild(new ExprInfix(0, 0, OP_AND_2) - .addChild(new ExprUnary(0, 0, OP_NOT_2) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprInfix(0, 0, OP_XOR_2) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprNumber(0, 0, 5)) - .addChild(new ExprInfix(0, 0, OP_SHR_2) - .addChild(new ExprInfix(0, 0, OP_SHL_2) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 5))) - .addChild(new ExprNumber(0, 0, 6))) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 4)) - .addChild(new ExprNumber(0, 0, 1)))) - .addChild(new ExprNumber(0, 0, 2))))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_OR_2) + .addChild(new ExprInfix(POSITION, OP_AND_2) + .addChild(new ExprUnary(POSITION, OP_NOT_2) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprInfix(POSITION, OP_XOR_2) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprNumber(POSITION, 5)) + .addChild(new ExprInfix(POSITION, OP_SHR_2) + .addChild(new ExprInfix(POSITION, OP_SHL_2) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 5))) + .addChild(new ExprNumber(POSITION, 6))) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 4)) + .addChild(new ExprNumber(POSITION, 1)))) + .addChild(new ExprNumber(POSITION, 2))))))), program ); } @@ -201,15 +203,15 @@ public void testAndMulXorDivNotPlusMinusWithOperators() { public void testParenthesis() { Program program = parseProgram("db (2 + 3) * (4 - 2)"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 4)) - .addChild(new ExprNumber(0, 0, 2))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 4)) + .addChild(new ExprNumber(POSITION, 2))))), program ); } diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseInstrTest.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseInstrTest.java index 520caf438..ba42bcd96 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseInstrTest.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/parser/ParseInstrTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.parser; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.ast.Program; import net.emustudio.plugins.compiler.as8080.ast.expr.ExprCurrentAddress; @@ -33,6 +34,7 @@ import static net.emustudio.plugins.compiler.as8080.Utils.*; public class ParseInstrTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); @Test public void testInstrNoArgs() { @@ -126,9 +128,9 @@ public void testRegPair() { @Test public void testMVI() { - Node expr = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node expr = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); forStringCaseVariations("mvi", instrVariation -> { for (Map.Entry register : registers.entrySet()) { @@ -136,8 +138,8 @@ public void testMVI() { String row = instrVariation + " " + registerVariation + ", $ + 5"; Program program = parseProgram(row); assertTrees( - new Program() - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, register.getValue()) + new Program("") + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, register.getValue()) .addChild(expr)), program ); @@ -148,9 +150,9 @@ public void testMVI() { @Test public void testLXI() { - Node expr = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node expr = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); forStringCaseVariations("lxi", instrVariation -> { for (Map.Entry regPair : regPairsBDHSP.entrySet()) { @@ -158,8 +160,8 @@ public void testLXI() { String row = instrVariation + " " + registerVariation + ", $ + 5"; Program program = parseProgram(row); assertTrees( - new Program() - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, regPair.getValue()) + new Program("") + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, regPair.getValue()) .addChild(expr)), program ); @@ -179,8 +181,8 @@ public void testMOV() { String row = instrVariation + " " + registerVariation1 + ", " + registerVariation2; Program program = parseProgram(row); assertTrees( - new Program() - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, register1.getValue(), register2.getValue())), + new Program("") + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, register1.getValue(), register2.getValue())), program ); } @@ -194,7 +196,7 @@ public void testMOV() { private void assertInstrNoArgs(String instr, int instrType) { forStringCaseVariations(instr, variation -> { Program program = parseProgram(variation); - assertTrees(new Program().addChild(new InstrNoArgs(0, 0, instrType)), program); + assertTrees(new Program("").addChild(new InstrNoArgs(POSITION, instrType)), program); }); } @@ -205,7 +207,7 @@ private void assertInstrReg(String instr, int instrType) { String row = instrVariation + " " + registerVariation; Program program = parseProgram(row); assertTrees( - new Program().addChild(new InstrReg(0, 0, instrType, register.getValue())), + new Program("").addChild(new InstrReg(POSITION, instrType, register.getValue())), program ); }); @@ -214,13 +216,13 @@ private void assertInstrReg(String instr, int instrType) { } private void assertInstrExpr(String instr, int instrType) { - Node expr = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node expr = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); forStringCaseVariations(instr, variation -> { Program program = parseProgram(variation + " $ + 5"); - assertTrees(new Program().addChild(new InstrExpr(0, 0, instrType).addChild(expr)), program); + assertTrees(new Program("").addChild(new InstrExpr(POSITION, instrType).addChild(expr)), program); }); } @@ -231,7 +233,7 @@ private void assertInstrRegPair(String instr, int instrType, Map constants = List.of("one", "two", "three", "four", "five"); for (String c : constants) { @@ -200,31 +202,31 @@ public void testEvaluateEQUfivePasses() { @Test public void testEvaluateIFwithForwardConst() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_A) - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 2)))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new ExprNumber(0, 0, 0)))) - .addChild(new PseudoEqu(0, 0, "const") - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprCurrentAddress(0, 0)))); + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_A) + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 2)))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new ExprNumber(POSITION, 0)))) + .addChild(new PseudoEqu(POSITION, "const") + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprCurrentAddress(POSITION)))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_A) - .addChild(new Evaluated(0, 0, 6))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 0))), + new Program("") + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_A) + .addChild(new Evaluated(POSITION, 6))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 0))), program ); assertEquals(0, program.getChild(0).getAddress()); @@ -233,19 +235,19 @@ public void testEvaluateIFwithForwardConst() { @Test public void testEvaluateIFwithForwardAddressReference() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprId(0, 0, "const")))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new ExprNumber(0, 0, 0)))) - .addChild(new PseudoEqu(0, 0, "const") - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprCurrentAddress(0, 0)))); + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprId(POSITION, "const")))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new ExprNumber(POSITION, 0)))) + .addChild(new PseudoEqu(POSITION, "const") + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprCurrentAddress(POSITION)))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); @@ -255,173 +257,173 @@ public void testEvaluateIFwithForwardAddressReference() { @Test public void testEvaluateIFexcludeBlock() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprNumber(0, 0, 0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new ExprNumber(0, 0, 0)))); + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprNumber(POSITION, 0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new ExprNumber(POSITION, 0)))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); - assertTrees(new Program(), program); + assertTrees(new Program(""), program); } @Test public void testEvaluateSETforwardTwoTimes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_A) - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoSet(0, 0, "const") - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_B) - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoSet(0, 0, "const") - .addChild(new ExprNumber(0, 0, 2))); + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_A) + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoSet(POSITION, "const") + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_B) + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoSet(POSITION, "const") + .addChild(new ExprNumber(POSITION, 2))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_A) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoSet(0, 0, "const") - .addChild(new Evaluated(0, 0, 1))) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_B) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoSet(0, 0, "const") - .addChild(new Evaluated(0, 0, 2))), + new Program("") + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_A) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoSet(POSITION, "const") + .addChild(new Evaluated(POSITION, 1))) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_B) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoSet(POSITION, "const") + .addChild(new Evaluated(POSITION, 2))), program ); } @Test public void testEvaluateSETforwardMoreTimes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new ExprId(0, 0, "id"))) - .addChild(new PseudoSet(0, 0, "id") - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoSet(0, 0, "id") - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoEqu(0, 0, "const") - .addChild(new ExprNumber(0, 0, 1))); + .addChild(new DataDB(POSITION) + .addChild(new ExprId(POSITION, "id"))) + .addChild(new PseudoSet(POSITION, "id") + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoSet(POSITION, "id") + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoEqu(POSITION, "const") + .addChild(new ExprNumber(POSITION, 1))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoSet(0, 0, "id") - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoSet(0, 0, "id") - .addChild(new Evaluated(0, 0, 2))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoSet(POSITION, "id") + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoSet(POSITION, "id") + .addChild(new Evaluated(POSITION, 2))), program ); } @Test public void testTwoSETthenReference() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoSet(0, 0, "id") - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoSet(0, 0, "id") - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoEqu(0, 0, "const") - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new DataDB(0, 0) - .addChild(new ExprId(0, 0, "id"))); + .addChild(new PseudoSet(POSITION, "id") + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoSet(POSITION, "id") + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoEqu(POSITION, "const") + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new DataDB(POSITION) + .addChild(new ExprId(POSITION, "id"))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoSet(0, 0, "id") - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoSet(0, 0, "id") - .addChild(new Evaluated(0, 0, 2))) - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 2))), + new Program("") + .addChild(new PseudoSet(POSITION, "id") + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoSet(POSITION, "id") + .addChild(new Evaluated(POSITION, 2))) + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 2))), program ); } @Test public void testEvaluateLABEL() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprId(0, 0, "label"))) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprId(0, 0, "label"))) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprId(0, 0, "label")))) - .addChild(new PseudoLabel(0, 0, "label")); + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprId(POSITION, "label"))) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprId(POSITION, "label"))) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprId(POSITION, "label")))) + .addChild(new PseudoLabel(POSITION, "label")); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 3)) - .addChild(new Evaluated(0, 0, 4)) - .addChild(new Evaluated(0, 0, 5))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 3)) + .addChild(new Evaluated(POSITION, 4)) + .addChild(new Evaluated(POSITION, 5))), program ); } @Test public void testEvaluateMacroCalls() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoLabel(0, 0, "label")) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "addr")) - .addChild(new ExprId(0, 0, "label"))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new ExprId(0, 0, "addr")))); + .addChild(new PseudoLabel(POSITION, "label")) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "addr")) + .addChild(new ExprId(POSITION, "label"))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new ExprId(POSITION, "addr")))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "addr")) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new Evaluated(0, 0, 0)))), + new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "addr")) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new Evaluated(POSITION, 0)))), program ); } @Test public void testEvaluateMacroCallAmbiguous() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "label")) - .addChild(new ExprId(0, 0, "addr"))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new ExprId(0, 0, "addr")))) - .addChild(new PseudoLabel(0, 0, "label")); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "label")) + .addChild(new ExprId(POSITION, "addr"))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new ExprId(POSITION, "addr")))) + .addChild(new PseudoLabel(POSITION, "label")); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); @@ -431,58 +433,58 @@ public void testEvaluateMacroCallAmbiguous() { @Test public void testEvaluateMacroScopedArguments() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new ExprNumber(0, 0, 0))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new ExprId(0, 0, "arg"))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new ExprId(0, 0, "arg")))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new ExprId(0, 0, "arg")))); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new ExprNumber(POSITION, 0))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new ExprId(POSITION, "arg"))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new ExprId(POSITION, "arg")))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new ExprId(POSITION, "arg")))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new Evaluated(0, 0, 1)))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new Evaluated(0, 0, 0)))), + new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new Evaluated(POSITION, 1)))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new Evaluated(POSITION, 0)))), program ); } @Test public void testLabelKeepsChildren() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoLabel(0, 0, "label") - .addChild(new InstrNoArgs(0, 0, OPCODE_RET))); + .addChild(new PseudoLabel(POSITION, "label") + .addChild(new InstrNoArgs(POSITION, OPCODE_RET))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program().addChild(new InstrNoArgs(0, 0, OPCODE_RET)), + new Program("").addChild(new InstrNoArgs(POSITION, OPCODE_RET)), program ); } diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandIncludesVisitorTest.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandIncludesVisitorTest.java index 28ee18e29..08e5b84f7 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandIncludesVisitorTest.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandIncludesVisitorTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.ast.Program; import net.emustudio.plugins.compiler.as8080.ast.expr.ExprNumber; @@ -38,6 +39,8 @@ import static org.junit.Assert.assertTrue; public class ExpandIncludesVisitorTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Rule public TemporaryFolder folder = new TemporaryFolder(); @@ -48,12 +51,12 @@ public void testExpandInclude() { ExpandIncludesVisitor visitor = new ExpandIncludesVisitor(); visitor.visit(program); - Node expected = new Program() - .addChild(new InstrNoArgs(0, 0, OPCODE_CMC)) - .addChild(new PseudoLabel(0, 0, "sample")) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_A) - .addChild(new ExprNumber(0, 0, 0))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RET)); + Node expected = new Program("") + .addChild(new InstrNoArgs(POSITION, OPCODE_CMC)) + .addChild(new PseudoLabel(POSITION, "sample")) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_A) + .addChild(new ExprNumber(POSITION, 0))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RET)); assertTrees(expected, program); } @@ -70,9 +73,9 @@ public void testExpandIncludeTwoTimes() throws IOException { ExpandIncludesVisitor visitor = new ExpandIncludesVisitor(); visitor.visit(program); - Node expected = new Program() - .addChild(new InstrNoArgs(0, 0, OPCODE_RRC)) - .addChild(new InstrNoArgs(0, 0, OPCODE_RRC)); + Node expected = new Program("") + .addChild(new InstrNoArgs(POSITION, OPCODE_RRC)) + .addChild(new InstrNoArgs(POSITION, OPCODE_RRC)); assertTrees(expected, program); } diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandMacrosTest.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandMacrosTest.java index a3ef94be0..c19d97f9b 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandMacrosTest.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/ExpandMacrosTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Program; import net.emustudio.plugins.compiler.as8080.ast.expr.ExprId; import net.emustudio.plugins.compiler.as8080.ast.expr.ExprNumber; @@ -38,6 +39,8 @@ import static org.junit.Assert.assertTrue; public class ExpandMacrosTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Rule public TemporaryFolder folder = new TemporaryFolder(); @@ -47,9 +50,9 @@ public void testMacroDefinitionThenMacroCall() { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))), program ); } @@ -60,9 +63,9 @@ public void testMacroCallThenMacroDefinition() { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))), program ); } @@ -73,11 +76,11 @@ public void testMacroCallThenMacroDefinitionThenMacroCall() { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))), program ); } @@ -93,9 +96,9 @@ public void testMacroCallThenMacroDefinitionInsideInclude() throws IOException { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))), program ); } @@ -120,21 +123,21 @@ public void testMacroCallWithArguments() { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "r"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "t"))))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "r"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "t"))))), program ); } diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/GenerateCodeVisitorTest.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/GenerateCodeVisitorTest.java index d04a78706..8e581781a 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/GenerateCodeVisitorTest.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/GenerateCodeVisitorTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.emulib.runtime.io.IntelHEX; import net.emustudio.plugins.compiler.as8080.ast.Evaluated; import net.emustudio.plugins.compiler.as8080.ast.Program; @@ -35,27 +36,28 @@ import static org.junit.Assert.assertEquals; public class GenerateCodeVisitorTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); @Test public void testCodeGeneration() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 255)) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 4)))) - .addChild(new DataDW(0, 0) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new DataDS(0, 0) - .addChild(new Evaluated(0, 0, 5))) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new Evaluated(0, 0, 0xFEAB))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_D) - .addChild(new Evaluated(0, 0, 1)))) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_H) - .addChild(new Evaluated(0, 0, 0x1234)))); + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 255)) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 4)))) + .addChild(new DataDW(POSITION) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new DataDS(POSITION) + .addChild(new Evaluated(POSITION, 5))) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new Evaluated(POSITION, 0xFEAB))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_D) + .addChild(new Evaluated(POSITION, 1)))) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_H) + .addChild(new Evaluated(POSITION, 0x1234)))); IntelHEX hex = new IntelHEX(); GenerateCodeVisitor visitor = new GenerateCodeVisitor(hex); @@ -84,15 +86,15 @@ public void testCodeGeneration() { @Test public void testPseudoOrg() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoOrg(0, 0) - .addChild(new Evaluated(0, 0, 5))) - .addChild(new InstrExpr(0, 0, OPCODE_CNZ) - .addChild(new Evaluated(0, 0, 0x400))) - .addChild(new PseudoOrg(0, 0) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new InstrNoArgs(0, 0, OPCODE_XCHG)); + .addChild(new PseudoOrg(POSITION) + .addChild(new Evaluated(POSITION, 5))) + .addChild(new InstrExpr(POSITION, OPCODE_CNZ) + .addChild(new Evaluated(POSITION, 0x400))) + .addChild(new PseudoOrg(POSITION) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new InstrNoArgs(POSITION, OPCODE_XCHG)); IntelHEX hex = new IntelHEX(); GenerateCodeVisitor visitor = new GenerateCodeVisitor(hex); @@ -107,304 +109,304 @@ public void testPseudoOrg() { @Test public void testGenerateInstructions() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new InstrNoArgs(0, 0, OPCODE_NOP)) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_B) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrRegPair(0, 0, OPCODE_STAX, REG_B)) - .addChild(new InstrRegPair(0, 0, OPCODE_INX, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_INR, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_DCR, REG_B)) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_B) - .addChild(new Evaluated(0, 0, 7))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RLC)) - .addChild(new InstrRegPair(0, 0, OPCODE_DAD, REG_B)) - .addChild(new InstrRegPair(0, 0, OPCODE_LDAX, REG_B)) - .addChild(new InstrRegPair(0, 0, OPCODE_DCX, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_INR, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_DCR, REG_C)) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_C) - .addChild(new Evaluated(0, 0, 8))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RRC)) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_D) - .addChild(new Evaluated(0, 0, 0x2345))) - .addChild(new InstrRegPair(0, 0, OPCODE_STAX, REG_D)) - .addChild(new InstrRegPair(0, 0, OPCODE_INX, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_INR, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_DCR, REG_D)) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_D) - .addChild(new Evaluated(0, 0, 9))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RAL)) - .addChild(new InstrRegPair(0, 0, OPCODE_DAD, REG_D)) - .addChild(new InstrRegPair(0, 0, OPCODE_LDAX, REG_D)) - .addChild(new InstrRegPair(0, 0, OPCODE_DCX, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_INR, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_DCR, REG_E)) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_E) - .addChild(new Evaluated(0, 0, 10))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RAR)) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_H) - .addChild(new Evaluated(0, 0, 0x2345))) - .addChild(new InstrExpr(0, 0, OPCODE_SHLD) - .addChild(new Evaluated(0, 0, 0x2345))) - .addChild(new InstrRegPair(0, 0, OPCODE_INX, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_INR, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_DCR, REG_H)) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_H) - .addChild(new Evaluated(0, 0, 0x28))) - .addChild(new InstrNoArgs(0, 0, OPCODE_DAA)) - .addChild(new InstrRegPair(0, 0, OPCODE_DAD, REG_H)) - .addChild(new InstrExpr(0, 0, OPCODE_LHLD) - .addChild(new Evaluated(0, 0, 0x2345))) - .addChild(new InstrRegPair(0, 0, OPCODE_DCX, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_INR, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_DCR, REG_L)) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_L) - .addChild(new Evaluated(0, 0, 10))) - .addChild(new InstrNoArgs(0, 0, OPCODE_CMA)) - .addChild(new InstrRegPairExpr(0, 0, OPCODE_LXI, REG_SP) - .addChild(new Evaluated(0, 0, 0x2345))) - .addChild(new InstrExpr(0, 0, OPCODE_STA) - .addChild(new Evaluated(0, 0, 0x2345))) - .addChild(new InstrRegPair(0, 0, OPCODE_INX, REG_SP)) - .addChild(new InstrReg(0, 0, OPCODE_INR, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_DCR, REG_M)) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_M) - .addChild(new Evaluated(0, 0, 7))) - .addChild(new InstrNoArgs(0, 0, OPCODE_STC)) - .addChild(new InstrRegPair(0, 0, OPCODE_DAD, REG_SP)) - .addChild(new InstrExpr(0, 0, OPCODE_LDA) - .addChild(new Evaluated(0, 0, 0x2345))) - .addChild(new InstrRegPair(0, 0, OPCODE_DCX, REG_SP)) - .addChild(new InstrReg(0, 0, OPCODE_INR, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_DCR, REG_A)) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_A) - .addChild(new Evaluated(0, 0, -128))) - .addChild(new InstrNoArgs(0, 0, OPCODE_CMC)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_B, REG_B)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_B, REG_C)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_B, REG_D)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_B, REG_E)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_B, REG_H)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_B, REG_L)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_B, REG_M)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_B, REG_A)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_C, REG_B)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_C, REG_C)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_C, REG_D)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_C, REG_E)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_C, REG_H)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_C, REG_L)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_C, REG_M)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_C, REG_A)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_D, REG_B)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_D, REG_C)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_D, REG_D)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_D, REG_E)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_D, REG_H)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_D, REG_L)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_D, REG_M)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_D, REG_A)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_E, REG_B)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_E, REG_C)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_E, REG_D)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_E, REG_E)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_E, REG_H)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_E, REG_L)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_E, REG_M)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_E, REG_A)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_H, REG_B)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_H, REG_C)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_H, REG_D)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_H, REG_E)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_H, REG_H)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_H, REG_L)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_H, REG_M)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_H, REG_A)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_L, REG_B)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_L, REG_C)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_L, REG_D)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_L, REG_E)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_L, REG_H)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_L, REG_L)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_L, REG_M)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_L, REG_A)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_M, REG_B)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_M, REG_C)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_M, REG_D)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_M, REG_E)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_M, REG_H)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_M, REG_L)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_M, REG_M)) // HLT - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_M, REG_A)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_A, REG_B)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_A, REG_C)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_A, REG_D)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_A, REG_E)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_A, REG_H)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_A, REG_L)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_A, REG_M)) - .addChild(new InstrRegReg(0, 0, OPCODE_MOV, REG_A, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_ADD, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_ADD, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_ADD, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_ADD, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_ADD, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_ADD, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_ADD, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_ADD, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_ADC, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_ADC, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_ADC, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_ADC, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_ADC, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_ADC, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_ADC, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_ADC, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_SUB, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_SUB, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_SUB, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_SUB, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_SUB, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_SUB, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_SUB, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_SUB, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_SBB, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_SBB, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_SBB, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_SBB, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_SBB, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_SBB, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_SBB, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_SBB, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_ANA, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_ANA, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_ANA, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_ANA, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_ANA, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_ANA, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_ANA, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_ANA, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_XRA, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_XRA, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_XRA, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_XRA, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_XRA, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_XRA, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_XRA, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_XRA, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_ORA, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_ORA, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_ORA, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_ORA, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_ORA, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_ORA, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_ORA, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_ORA, REG_A)) - .addChild(new InstrReg(0, 0, OPCODE_CMP, REG_B)) - .addChild(new InstrReg(0, 0, OPCODE_CMP, REG_C)) - .addChild(new InstrReg(0, 0, OPCODE_CMP, REG_D)) - .addChild(new InstrReg(0, 0, OPCODE_CMP, REG_E)) - .addChild(new InstrReg(0, 0, OPCODE_CMP, REG_H)) - .addChild(new InstrReg(0, 0, OPCODE_CMP, REG_L)) - .addChild(new InstrReg(0, 0, OPCODE_CMP, REG_M)) - .addChild(new InstrReg(0, 0, OPCODE_CMP, REG_A)) - .addChild(new InstrNoArgs(0, 0, OPCODE_RNZ)) - .addChild(new InstrRegPair(0, 0, OPCODE_POP, REG_B)) - .addChild(new InstrExpr(0, 0, OPCODE_JNZ) - .addChild(new Evaluated(0, 0, 2))) - .addChild(new InstrExpr(0, 0, OPCODE_JMP) - .addChild(new Evaluated(0, 0, 0x200))) - .addChild(new InstrExpr(0, 0, OPCODE_CNZ) - .addChild(new Evaluated(0, 0, 0xF0A0))) - .addChild(new InstrRegPair(0, 0, OPCODE_PUSH, REG_B)) - .addChild(new InstrExpr(0, 0, OPCODE_ADI) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RZ)) - .addChild(new InstrNoArgs(0, 0, OPCODE_RET)) - .addChild(new InstrExpr(0, 0, OPCODE_JZ) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrExpr(0, 0, OPCODE_CZ) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrExpr(0, 0, OPCODE_CALL) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrExpr(0, 0, OPCODE_ACI) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RNC)) - .addChild(new InstrRegPair(0, 0, OPCODE_POP, REG_D)) - .addChild(new InstrExpr(0, 0, OPCODE_JNC) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrExpr(0, 0, OPCODE_OUT) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_CNC) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrRegPair(0, 0, OPCODE_PUSH, REG_D)) - .addChild(new InstrExpr(0, 0, OPCODE_SUI) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 2))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RC)) - .addChild(new InstrExpr(0, 0, OPCODE_JC) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrExpr(0, 0, OPCODE_IN) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_CC) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrExpr(0, 0, OPCODE_SBI) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 3))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RPO)) - .addChild(new InstrRegPair(0, 0, OPCODE_POP, REG_H)) - .addChild(new InstrExpr(0, 0, OPCODE_JPO) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrNoArgs(0, 0, OPCODE_XTHL)) - .addChild(new InstrExpr(0, 0, OPCODE_CPO) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrRegPair(0, 0, OPCODE_PUSH, REG_H)) - .addChild(new InstrExpr(0, 0, OPCODE_ANI) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 4))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RPE)) - .addChild(new InstrNoArgs(0, 0, OPCODE_PCHL)) - .addChild(new InstrExpr(0, 0, OPCODE_JPE) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrNoArgs(0, 0, OPCODE_XCHG)) - .addChild(new InstrExpr(0, 0, OPCODE_CPE) - .addChild(new Evaluated(0, 0, 0x1234))) - .addChild(new InstrExpr(0, 0, OPCODE_XRI) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 5))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RP)) - .addChild(new InstrRegPair(0, 0, OPCODE_POP, REG_PSW)) - .addChild(new InstrExpr(0, 0, OPCODE_JP) - .addChild(new Evaluated(0, 0, 0x200))) - .addChild(new InstrNoArgs(0, 0, OPCODE_DI)) - .addChild(new InstrExpr(0, 0, OPCODE_CP) - .addChild(new Evaluated(0, 0, 0x200))) - .addChild(new InstrRegPair(0, 0, OPCODE_PUSH, REG_PSW)) - .addChild(new InstrExpr(0, 0, OPCODE_ORI) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 6))) - .addChild(new InstrNoArgs(0, 0, OPCODE_RM)) - .addChild(new InstrNoArgs(0, 0, OPCODE_SPHL)) - .addChild(new InstrExpr(0, 0, OPCODE_JM) - .addChild(new Evaluated(0, 0, 0x200))) - .addChild(new InstrNoArgs(0, 0, OPCODE_EI)) - .addChild(new InstrExpr(0, 0, OPCODE_CM) - .addChild(new Evaluated(0, 0, 0x200))) - .addChild(new InstrExpr(0, 0, OPCODE_CPI) - .addChild(new Evaluated(0, 0, 0xF0))) - .addChild(new InstrExpr(0, 0, OPCODE_RST) - .addChild(new Evaluated(0, 0, 7))); + .addChild(new InstrNoArgs(POSITION, OPCODE_NOP)) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_B) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrRegPair(POSITION, OPCODE_STAX, REG_B)) + .addChild(new InstrRegPair(POSITION, OPCODE_INX, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_INR, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_DCR, REG_B)) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_B) + .addChild(new Evaluated(POSITION, 7))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RLC)) + .addChild(new InstrRegPair(POSITION, OPCODE_DAD, REG_B)) + .addChild(new InstrRegPair(POSITION, OPCODE_LDAX, REG_B)) + .addChild(new InstrRegPair(POSITION, OPCODE_DCX, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_INR, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_DCR, REG_C)) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_C) + .addChild(new Evaluated(POSITION, 8))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RRC)) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_D) + .addChild(new Evaluated(POSITION, 0x2345))) + .addChild(new InstrRegPair(POSITION, OPCODE_STAX, REG_D)) + .addChild(new InstrRegPair(POSITION, OPCODE_INX, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_INR, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_DCR, REG_D)) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_D) + .addChild(new Evaluated(POSITION, 9))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RAL)) + .addChild(new InstrRegPair(POSITION, OPCODE_DAD, REG_D)) + .addChild(new InstrRegPair(POSITION, OPCODE_LDAX, REG_D)) + .addChild(new InstrRegPair(POSITION, OPCODE_DCX, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_INR, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_DCR, REG_E)) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_E) + .addChild(new Evaluated(POSITION, 10))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RAR)) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_H) + .addChild(new Evaluated(POSITION, 0x2345))) + .addChild(new InstrExpr(POSITION, OPCODE_SHLD) + .addChild(new Evaluated(POSITION, 0x2345))) + .addChild(new InstrRegPair(POSITION, OPCODE_INX, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_INR, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_DCR, REG_H)) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_H) + .addChild(new Evaluated(POSITION, 0x28))) + .addChild(new InstrNoArgs(POSITION, OPCODE_DAA)) + .addChild(new InstrRegPair(POSITION, OPCODE_DAD, REG_H)) + .addChild(new InstrExpr(POSITION, OPCODE_LHLD) + .addChild(new Evaluated(POSITION, 0x2345))) + .addChild(new InstrRegPair(POSITION, OPCODE_DCX, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_INR, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_DCR, REG_L)) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_L) + .addChild(new Evaluated(POSITION, 10))) + .addChild(new InstrNoArgs(POSITION, OPCODE_CMA)) + .addChild(new InstrRegPairExpr(POSITION, OPCODE_LXI, REG_SP) + .addChild(new Evaluated(POSITION, 0x2345))) + .addChild(new InstrExpr(POSITION, OPCODE_STA) + .addChild(new Evaluated(POSITION, 0x2345))) + .addChild(new InstrRegPair(POSITION, OPCODE_INX, REG_SP)) + .addChild(new InstrReg(POSITION, OPCODE_INR, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_DCR, REG_M)) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_M) + .addChild(new Evaluated(POSITION, 7))) + .addChild(new InstrNoArgs(POSITION, OPCODE_STC)) + .addChild(new InstrRegPair(POSITION, OPCODE_DAD, REG_SP)) + .addChild(new InstrExpr(POSITION, OPCODE_LDA) + .addChild(new Evaluated(POSITION, 0x2345))) + .addChild(new InstrRegPair(POSITION, OPCODE_DCX, REG_SP)) + .addChild(new InstrReg(POSITION, OPCODE_INR, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_DCR, REG_A)) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_A) + .addChild(new Evaluated(POSITION, -128))) + .addChild(new InstrNoArgs(POSITION, OPCODE_CMC)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_B, REG_B)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_B, REG_C)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_B, REG_D)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_B, REG_E)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_B, REG_H)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_B, REG_L)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_B, REG_M)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_B, REG_A)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_C, REG_B)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_C, REG_C)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_C, REG_D)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_C, REG_E)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_C, REG_H)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_C, REG_L)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_C, REG_M)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_C, REG_A)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_D, REG_B)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_D, REG_C)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_D, REG_D)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_D, REG_E)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_D, REG_H)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_D, REG_L)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_D, REG_M)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_D, REG_A)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_E, REG_B)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_E, REG_C)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_E, REG_D)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_E, REG_E)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_E, REG_H)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_E, REG_L)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_E, REG_M)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_E, REG_A)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_H, REG_B)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_H, REG_C)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_H, REG_D)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_H, REG_E)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_H, REG_H)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_H, REG_L)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_H, REG_M)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_H, REG_A)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_L, REG_B)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_L, REG_C)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_L, REG_D)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_L, REG_E)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_L, REG_H)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_L, REG_L)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_L, REG_M)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_L, REG_A)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_M, REG_B)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_M, REG_C)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_M, REG_D)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_M, REG_E)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_M, REG_H)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_M, REG_L)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_M, REG_M)) // HLT + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_M, REG_A)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_A, REG_B)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_A, REG_C)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_A, REG_D)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_A, REG_E)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_A, REG_H)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_A, REG_L)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_A, REG_M)) + .addChild(new InstrRegReg(POSITION, OPCODE_MOV, REG_A, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_ADD, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_ADD, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_ADD, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_ADD, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_ADD, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_ADD, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_ADD, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_ADD, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_ADC, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_ADC, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_ADC, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_ADC, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_ADC, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_ADC, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_ADC, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_ADC, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_SUB, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_SUB, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_SUB, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_SUB, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_SUB, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_SUB, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_SUB, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_SUB, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_SBB, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_SBB, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_SBB, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_SBB, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_SBB, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_SBB, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_SBB, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_SBB, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_ANA, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_ANA, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_ANA, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_ANA, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_ANA, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_ANA, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_ANA, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_ANA, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_XRA, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_XRA, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_XRA, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_XRA, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_XRA, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_XRA, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_XRA, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_XRA, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_ORA, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_ORA, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_ORA, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_ORA, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_ORA, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_ORA, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_ORA, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_ORA, REG_A)) + .addChild(new InstrReg(POSITION, OPCODE_CMP, REG_B)) + .addChild(new InstrReg(POSITION, OPCODE_CMP, REG_C)) + .addChild(new InstrReg(POSITION, OPCODE_CMP, REG_D)) + .addChild(new InstrReg(POSITION, OPCODE_CMP, REG_E)) + .addChild(new InstrReg(POSITION, OPCODE_CMP, REG_H)) + .addChild(new InstrReg(POSITION, OPCODE_CMP, REG_L)) + .addChild(new InstrReg(POSITION, OPCODE_CMP, REG_M)) + .addChild(new InstrReg(POSITION, OPCODE_CMP, REG_A)) + .addChild(new InstrNoArgs(POSITION, OPCODE_RNZ)) + .addChild(new InstrRegPair(POSITION, OPCODE_POP, REG_B)) + .addChild(new InstrExpr(POSITION, OPCODE_JNZ) + .addChild(new Evaluated(POSITION, 2))) + .addChild(new InstrExpr(POSITION, OPCODE_JMP) + .addChild(new Evaluated(POSITION, 0x200))) + .addChild(new InstrExpr(POSITION, OPCODE_CNZ) + .addChild(new Evaluated(POSITION, 0xF0A0))) + .addChild(new InstrRegPair(POSITION, OPCODE_PUSH, REG_B)) + .addChild(new InstrExpr(POSITION, OPCODE_ADI) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RZ)) + .addChild(new InstrNoArgs(POSITION, OPCODE_RET)) + .addChild(new InstrExpr(POSITION, OPCODE_JZ) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrExpr(POSITION, OPCODE_CZ) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrExpr(POSITION, OPCODE_CALL) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrExpr(POSITION, OPCODE_ACI) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RNC)) + .addChild(new InstrRegPair(POSITION, OPCODE_POP, REG_D)) + .addChild(new InstrExpr(POSITION, OPCODE_JNC) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrExpr(POSITION, OPCODE_OUT) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_CNC) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrRegPair(POSITION, OPCODE_PUSH, REG_D)) + .addChild(new InstrExpr(POSITION, OPCODE_SUI) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 2))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RC)) + .addChild(new InstrExpr(POSITION, OPCODE_JC) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrExpr(POSITION, OPCODE_IN) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_CC) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrExpr(POSITION, OPCODE_SBI) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 3))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RPO)) + .addChild(new InstrRegPair(POSITION, OPCODE_POP, REG_H)) + .addChild(new InstrExpr(POSITION, OPCODE_JPO) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrNoArgs(POSITION, OPCODE_XTHL)) + .addChild(new InstrExpr(POSITION, OPCODE_CPO) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrRegPair(POSITION, OPCODE_PUSH, REG_H)) + .addChild(new InstrExpr(POSITION, OPCODE_ANI) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 4))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RPE)) + .addChild(new InstrNoArgs(POSITION, OPCODE_PCHL)) + .addChild(new InstrExpr(POSITION, OPCODE_JPE) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrNoArgs(POSITION, OPCODE_XCHG)) + .addChild(new InstrExpr(POSITION, OPCODE_CPE) + .addChild(new Evaluated(POSITION, 0x1234))) + .addChild(new InstrExpr(POSITION, OPCODE_XRI) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 5))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RP)) + .addChild(new InstrRegPair(POSITION, OPCODE_POP, REG_PSW)) + .addChild(new InstrExpr(POSITION, OPCODE_JP) + .addChild(new Evaluated(POSITION, 0x200))) + .addChild(new InstrNoArgs(POSITION, OPCODE_DI)) + .addChild(new InstrExpr(POSITION, OPCODE_CP) + .addChild(new Evaluated(POSITION, 0x200))) + .addChild(new InstrRegPair(POSITION, OPCODE_PUSH, REG_PSW)) + .addChild(new InstrExpr(POSITION, OPCODE_ORI) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 6))) + .addChild(new InstrNoArgs(POSITION, OPCODE_RM)) + .addChild(new InstrNoArgs(POSITION, OPCODE_SPHL)) + .addChild(new InstrExpr(POSITION, OPCODE_JM) + .addChild(new Evaluated(POSITION, 0x200))) + .addChild(new InstrNoArgs(POSITION, OPCODE_EI)) + .addChild(new InstrExpr(POSITION, OPCODE_CM) + .addChild(new Evaluated(POSITION, 0x200))) + .addChild(new InstrExpr(POSITION, OPCODE_CPI) + .addChild(new Evaluated(POSITION, 0xF0))) + .addChild(new InstrExpr(POSITION, OPCODE_RST) + .addChild(new Evaluated(POSITION, 7))); IntelHEX hex = new IntelHEX(); GenerateCodeVisitor visitor = new GenerateCodeVisitor(hex); diff --git a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/SortMacroArgumentsVisitorTest.java b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/SortMacroArgumentsVisitorTest.java index 10aac1d73..53260fd94 100644 --- a/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/SortMacroArgumentsVisitorTest.java +++ b/plugins/compiler/as-8080/src/test/java/net/emustudio/plugins/compiler/as8080/visitors/SortMacroArgumentsVisitorTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.as8080.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.as8080.ast.Node; import net.emustudio.plugins.compiler.as8080.ast.Program; import net.emustudio.plugins.compiler.as8080.ast.expr.ExprId; @@ -33,132 +34,133 @@ import static org.junit.Assert.assertTrue; public class SortMacroArgumentsVisitorTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); @Test public void testMacroArgumentsAreConnectedWithIds() { - Node program = new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "r"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "t"))) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_A) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoEqu(0, 0, "uu") - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprId(0, 0, "r")) - .addChild(new ExprId(0, 0, "t")))))); + Node program = new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "r"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "t"))) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_A) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoEqu(POSITION, "uu") + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprId(POSITION, "r")) + .addChild(new ExprId(POSITION, "t")))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "r")) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "t")) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new InstrRegExpr(0, 0, OPCODE_MVI, REG_A) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoEqu(0, 0, "uu") - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprId(0, 0, "r")) - .addChild(new ExprId(0, 0, "t"))))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "r")) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "t")) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new InstrRegExpr(POSITION, OPCODE_MVI, REG_A) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoEqu(POSITION, "uu") + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprId(POSITION, "r")) + .addChild(new ExprId(POSITION, "t"))))), program ); } @Test public void testMultipleMacroCalls() { - Node program = new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))))) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))))); + Node program = new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))))) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 1)))) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 2)))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 1)))) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 2)))), program ); } @Test public void testNestedMacroCallWithSameNamedArgs() { - Node program = new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new PseudoMacroDef(0, 0, "y") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))))))); + Node program = new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new PseudoMacroDef(POSITION, "y") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 3))))), + new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 3))))), program ); } @Test public void testMoreMacroArgumentsThanParameters() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))))); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); @@ -168,16 +170,16 @@ public void testMoreMacroArgumentsThanParameters() { @Test public void testMoreMacroParametersThanArguments() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "r"))))); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "r"))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/CompileException.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/CompileException.java index 5b8464e2a..78bbca7d9 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/CompileException.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/CompileException.java @@ -18,18 +18,20 @@ */ package net.emustudio.plugins.compiler.ssem; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; + +import java.util.Objects; + public class CompileException extends RuntimeException { - final int line; - final int column; + public final SourceCodePosition position; - public CompileException(int line, int column, String message) { + public CompileException(SourceCodePosition position, String message) { super(message); - this.line = line; - this.column = column; + this.position = Objects.requireNonNull(position); } @Override public String toString() { - return "line " + line + ":" + column + " " + super.getMessage(); + return position + " " + super.getMessage(); } } diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/CompilerChecks.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/CompilerChecks.java index 48b3f4896..d14b93943 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/CompilerChecks.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/CompilerChecks.java @@ -18,51 +18,50 @@ */ package net.emustudio.plugins.compiler.ssem; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import org.antlr.v4.runtime.Token; import java.util.function.Function; public class CompilerChecks { - public static void checkStartLineDefined(boolean defined, Position pos, int startLine) { + public static void checkStartLineDefined(boolean defined, SourceCodePosition position, int startLine) { if (defined) { - throw new CompileException(pos.line, pos.column, "Start line is already defined (at line " + startLine + ")!"); + throw new CompileException(position, "Start line is already defined (at line " + startLine + ")!"); } } - public static void checkLineOutOfBounds(Position pos, int line) { + public static void checkLineOutOfBounds(SourceCodePosition position, int line) { if (line < 0 || line > 31) { - throw new CompileException(pos.line, pos.column, "Line number is out of bounds <0;31>: " + line); + throw new CompileException(position, "Line number is out of bounds <0;31>: " + line); } } - public static void checkDuplicateLineDefinition(boolean duplicate, Position pos, int line) { + public static void checkDuplicateLineDefinition(boolean duplicate, SourceCodePosition position, int line) { if (duplicate) { - throw new CompileException(pos.line, pos.column, "Duplicate line definition: " + line); + throw new CompileException(position, "Duplicate line definition: " + line); } } - public static void checkUnknownInstruction(boolean unknown, Position pos) { + public static void checkUnknownInstruction(boolean unknown, SourceCodePosition position) { if (unknown) { - throw new CompileException(pos.line, pos.column, "Unrecognized instruction"); + throw new CompileException(position, "Unrecognized instruction"); } } - public static void checkOperandOutOfBounds(Position pos, int tokenType, long operand) { + public static void checkOperandOutOfBounds(SourceCodePosition position, int tokenType, long operand) { if (tokenType != SSEMLexer.BNUM && tokenType != SSEMLexer.NUM && (operand < 0 || operand > 31)) { throw new CompileException( - pos.line, pos.column, "Operand must be between <0, 31>; it was " + operand + position, "Operand must be between <0, 31>; it was " + operand ); } } - public static T checkedParseNumber(Token token, Function parser) { + public static T checkedParseNumber(String fileName, Token token, Function parser) { try { return parser.apply(token); } catch (NumberFormatException e) { - throw new CompileException( - token.getLine(), token.getCharPositionInLine(), "Could not parse number: " + token.getText() - ); + throw new CompileException(Position.of(fileName, token), "Could not parse number: " + token.getText()); } } } diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ParserErrorListener.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ParserErrorListener.java index a93e1e96e..eccd94a18 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ParserErrorListener.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ParserErrorListener.java @@ -18,11 +18,20 @@ */ package net.emustudio.plugins.compiler.ssem; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; +import java.util.Objects; + class ParserErrorListener extends BaseErrorListener { + private final String fileName; + + ParserErrorListener(String fileName) { + this.fileName = Objects.requireNonNull(fileName); + } + @Override public void syntaxError( Recognizer recognizer, @@ -31,6 +40,6 @@ public void syntaxError( int charPositionInLine, String msg, RecognitionException e) { - throw new CompileException(line, charPositionInLine, msg); + throw new CompileException(new SourceCodePosition(line, charPositionInLine, fileName), msg); } } diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/Position.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/Position.java index d997e8124..d92cd9261 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/Position.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/Position.java @@ -18,29 +18,12 @@ */ package net.emustudio.plugins.compiler.ssem; -import net.jcip.annotations.Immutable; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import org.antlr.v4.runtime.Token; -@Immutable public class Position { - public final static Position UNKNOWN = new Position(-1, -1); - public final int line; - public final int column; - - public Position(int line, int column) { - this.line = line; - this.column = column; - } - - public static Position of(Token token) { - if (token == null) { - return UNKNOWN; - } - return new Position(token.getLine(), token.getCharPositionInLine()); - } - - public static Position unknown() { - return UNKNOWN; + public static SourceCodePosition of(String fileName, Token token) { + return new SourceCodePosition(token.getLine(), token.getCharPositionInLine(), fileName); } } diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/Runner.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/Runner.java index bbc047d6f..62fdad1c3 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/Runner.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/Runner.java @@ -23,6 +23,9 @@ import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.settings.PluginSettings; +import java.nio.file.Path; +import java.util.Optional; + public class Runner { public static void main(String... args) { @@ -49,15 +52,6 @@ public static void main(String... args) { return; } inputFile = args[i]; - if (outputFile == null) { - int index = inputFile.lastIndexOf('.'); - if (index != -1) { - outputFile = inputFile.substring(0, index); - } else { - outputFile = inputFile; - } - outputFile += ".bin"; - } SSEMCompiler compiler = new SSEMCompiler(0L, ApplicationApi.UNAVAILABLE, PluginSettings.UNAVAILABLE); compiler.addCompilerListener(new CompilerListener() { @@ -77,7 +71,7 @@ public void onFinish() { } }); try { - compiler.compile(inputFile, outputFile); + compiler.compile(Path.of(inputFile), Optional.ofNullable(outputFile).map(Path::of)); } catch (Exception e) { System.err.println(e.getMessage()); } diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/SSEMCompiler.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/SSEMCompiler.java index 4ae776a38..771eb2a8e 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/SSEMCompiler.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/SSEMCompiler.java @@ -42,13 +42,12 @@ import java.io.IOException; import java.io.Reader; import java.nio.ByteBuffer; +import java.nio.file.Path; import java.util.List; import java.util.MissingResourceException; import java.util.Optional; import java.util.ResourceBundle; -import static net.emustudio.emulib.plugins.compiler.FileExtension.stripKnownExtension; - @PluginRoot( type = PLUGIN_TYPE.COMPILER, title = "SSEM Assembler" @@ -71,9 +70,10 @@ public void initialize() { Optional.ofNullable(applicationApi.getContextPool()).ifPresent(pool -> { try { memory = pool.getMemoryContext(pluginID, MemoryContext.class); - if (memory.getDataType() != Byte.class) { + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { throw new InvalidContextException( - "Unexpected memory cell type. Expected Byte but was: " + memory.getDataType() + "Unexpected memory cell type. Expected Byte but was: " + cellTypeClass ); } } catch (InvalidContextException | ContextNotFoundException e) { @@ -83,19 +83,20 @@ public void initialize() { } @Override - public boolean compile(String inputFileName, String outputFileName) { + public void compile(Path inputPath, Optional outputPath) { notifyCompileStart(); notifyInfo(getTitle() + ", version " + getVersion()); - try (Reader reader = new FileReader(inputFileName)) { + Path finalOutputPath = outputPath.orElse(convertInputToOutputPath(inputPath, ".bssem")); + try (Reader reader = new FileReader(inputPath.toFile())) { Lexer lexer = createLexer(CharStreams.fromReader(reader)); - lexer.addErrorListener(new ParserErrorListener()); + lexer.addErrorListener(new ParserErrorListener(inputPath.toString())); CommonTokenStream tokens = new CommonTokenStream(lexer); SSEMParser parser = createParser(tokens); - parser.addErrorListener(new ParserErrorListener()); + parser.addErrorListener(new ParserErrorListener(inputPath.toString())); - ProgramParser programParser = new ProgramParser(); + ProgramParser programParser = new ProgramParser(inputPath.toString()); programParser.visit(parser.start()); Program program = programParser.getProgram(); @@ -103,7 +104,7 @@ public boolean compile(String inputFileName, String outputFileName) { ByteBuffer code = codeGenerator.generateCode(program); if (code.hasRemaining()) { - writeToFile(code, outputFileName); + writeToFile(code, finalOutputPath); writeToMemory(code); } @@ -112,46 +113,16 @@ public boolean compile(String inputFileName, String outputFileName) { notifyInfo(String.format( "Compile was successful.\n\tOutput: %s\n\tProgram starts at 0x%s", - outputFileName, RadixUtils.formatWordHexString(programLocation) + finalOutputPath, RadixUtils.formatWordHexString(programLocation) )); } catch (CompileException e) { - notifyError(e.line, e.column, e.getMessage()); - return false; + notifyError(e.position, e.getMessage()); } catch (IOException e) { notifyError("Compilation error: " + e); LOGGER.error("Compilation error", e); - return false; } finally { notifyCompileFinish(); } - - return true; - } - - private void writeToFile(ByteBuffer code, String outputFileName) throws IOException { - code.rewind(); - try (FileOutputStream fos = new FileOutputStream(outputFileName, false)) { - fos.getChannel().write(code); - } - } - - private void writeToMemory(ByteBuffer code) { - if (memory != null) { - code.rewind(); - code.position(4); // First 4 bytes is start line - byte[] data = new byte[code.remaining()]; - code.get(data); - memory.clear(); - memory.write(0, NumberUtils.nativeBytesToBytes(data)); - } else { - notifyWarning("Memory is not available."); - } - } - - @Override - public boolean compile(String inputFileName) { - String outputFileName = stripKnownExtension(inputFileName, SOURCE_FILE_EXTENSIONS) + ".bssem"; - return compile(inputFileName, outputFileName); } @Override @@ -198,4 +169,24 @@ private Optional getResourceBundle() { return Optional.empty(); } } + + private void writeToFile(ByteBuffer code, Path outputPath) throws IOException { + code.rewind(); + try (FileOutputStream fos = new FileOutputStream(outputPath.toFile(), false)) { + fos.getChannel().write(code); + } + } + + private void writeToMemory(ByteBuffer code) { + if (memory != null) { + code.rewind(); + code.position(4); // First 4 bytes is start line + byte[] data = new byte[code.remaining()]; + code.get(data); + memory.clear(); + memory.write(0, NumberUtils.nativeBytesToBytes(data)); + } else { + notifyWarning("Memory is not available."); + } + } } diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Instruction.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Instruction.java index ac7b317bb..4c9bc2f70 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Instruction.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Instruction.java @@ -18,12 +18,13 @@ */ package net.emustudio.plugins.compiler.ssem.ast; -import net.emustudio.plugins.compiler.ssem.Position; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.ssem.SSEMParser; import net.jcip.annotations.Immutable; import java.util.Map; import java.util.Objects; +import java.util.Optional; import static net.emustudio.plugins.compiler.ssem.CompilerChecks.checkOperandOutOfBounds; import static net.emustudio.plugins.compiler.ssem.CompilerChecks.checkUnknownInstruction; @@ -45,9 +46,9 @@ public class Instruction { public final int tokenType; public final long operand; - public Instruction(int tokenType, long operand, Position instrPosition, Position operandPosition) { + public Instruction(int tokenType, long operand, SourceCodePosition instrPosition, Optional operandPosition) { checkUnknownInstruction(!OPCODES.containsKey(tokenType), instrPosition); - checkOperandOutOfBounds(operandPosition, tokenType, operand); + operandPosition.ifPresent(t -> checkOperandOutOfBounds(t, tokenType, operand)); this.tokenType = tokenType; this.operand = operand; } diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Program.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Program.java index 422a170da..e2ece0d7c 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Program.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Program.java @@ -18,7 +18,7 @@ */ package net.emustudio.plugins.compiler.ssem.ast; -import net.emustudio.plugins.compiler.ssem.Position; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import java.util.Collections; import java.util.HashMap; @@ -32,9 +32,9 @@ public class Program { private int startLine; private boolean startLineDefined; - public void setStartLine(int startLine, Position pos) { - checkStartLineDefined(startLineDefined, pos, this.startLine); - checkLineOutOfBounds(pos, startLine); + public void setStartLine(int startLine, SourceCodePosition position) { + checkStartLineDefined(startLineDefined, position, this.startLine); + checkLineOutOfBounds(position, startLine); this.startLine = startLine; startLineDefined = true; } @@ -43,9 +43,9 @@ public int getStartLine() { return startLine; } - public void add(int line, Instruction instruction, Position pos) { - checkDuplicateLineDefinition(instructions.containsKey(line), pos, line); - checkLineOutOfBounds(pos, line); + public void add(int line, Instruction instruction, SourceCodePosition position) { + checkDuplicateLineDefinition(instructions.containsKey(line), position, line); + checkLineOutOfBounds(position, line); instructions.put(line, instruction); } diff --git a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/ProgramParser.java b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/ProgramParser.java index 912f5a6dd..98f4d0b3c 100644 --- a/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/ProgramParser.java +++ b/plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/ProgramParser.java @@ -23,10 +23,19 @@ import net.emustudio.plugins.compiler.ssem.SSEMParserBaseVisitor; import org.antlr.v4.runtime.Token; +import java.util.Objects; +import java.util.Optional; + import static net.emustudio.plugins.compiler.ssem.CompilerChecks.checkedParseNumber; public class ProgramParser extends SSEMParserBaseVisitor { private final Program program = new Program(); + private final String fileName; + + public ProgramParser(String fileName) { + this.fileName = Objects.requireNonNull(fileName); + } + @Override public Program visitLine(SSEMParser.LineContext ctx) { @@ -35,25 +44,25 @@ public Program visitLine(SSEMParser.LineContext ctx) { if (ctx.command != null) { Token tokenInstr = ctx.command.instr; - Token tokenOperand = ctx.command.operand; + Optional tokenOperand = Optional.ofNullable(ctx.command.operand); long operand = 0; - if (tokenOperand != null) { + if (tokenOperand.isPresent()) { if (tokenInstr.getType() == SSEMParser.BNUM) { - operand = parseBinary(tokenOperand); + operand = parseBinary(tokenOperand.get()); } else { - operand = parseNumber(tokenOperand); + operand = parseNumber(tokenOperand.get()); } } int instrType = tokenInstr.getType(); if (instrType == SSEMParser.START) { - program.setStartLine(line, Position.of(ctx.linenumber)); + program.setStartLine(line, Position.of(fileName, ctx.linenumber)); } else { program.add( line, - new Instruction(instrType, operand, Position.of(tokenInstr), Position.of(tokenOperand)), - Position.of(ctx.linenumber) + new Instruction(instrType, operand, Position.of(fileName, tokenInstr), tokenOperand.map(o -> Position.of(fileName, o))), + Position.of(fileName, ctx.linenumber) ); } } @@ -66,11 +75,11 @@ public Program getProgram() { } private long parseBinary(Token token) { - return checkedParseNumber(token, t -> Long.parseLong(t.getText(), 2)); + return checkedParseNumber(fileName, token, t -> Long.parseLong(t.getText(), 2)); } private long parseNumber(Token token) { - return checkedParseNumber(token, t -> { + return checkedParseNumber(fileName, token, t -> { if (t.getType() == SSEMParser.HEXNUMBER) { return Long.decode(t.getText()); } else { @@ -81,7 +90,7 @@ private long parseNumber(Token token) { } private int parsePositiveInteger(Token token) { - return checkedParseNumber(token, t -> { + return checkedParseNumber(fileName, token, t -> { if (t.getType() == SSEMParser.HEXNUMBER) { return Integer.decode(t.getText()); } else { diff --git a/plugins/compiler/as-ssem/src/test/java/net/emustudio/plugins/compiler/ssem/SSEMCompilerTest.java b/plugins/compiler/as-ssem/src/test/java/net/emustudio/plugins/compiler/ssem/SSEMCompilerTest.java index 70f2b61cd..8dd7180de 100644 --- a/plugins/compiler/as-ssem/src/test/java/net/emustudio/plugins/compiler/ssem/SSEMCompilerTest.java +++ b/plugins/compiler/as-ssem/src/test/java/net/emustudio/plugins/compiler/ssem/SSEMCompilerTest.java @@ -20,6 +20,8 @@ import net.emustudio.cpu.testsuite.memory.ByteMemoryStub; import net.emustudio.cpu.testsuite.memory.MemoryStub; +import net.emustudio.emulib.plugins.compiler.CompilerListener; +import net.emustudio.emulib.plugins.compiler.CompilerMessage; import net.emustudio.emulib.plugins.memory.MemoryContext; import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.ContextPool; @@ -33,6 +35,7 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.StandardOpenOption; +import java.util.Optional; import static org.easymock.EasyMock.*; import static org.junit.Assert.assertArrayEquals; @@ -43,6 +46,7 @@ public class SSEMCompilerTest { public TemporaryFolder folder = new TemporaryFolder(); private SSEMCompiler compiler; private MemoryStub memoryStub; + private int errorCount; @SuppressWarnings("unchecked") @Before @@ -56,7 +60,26 @@ public void setUp() throws Exception { expect(applicationApi.getContextPool()).andReturn(pool).anyTimes(); replay(applicationApi); + errorCount = 0; compiler = new SSEMCompiler(0L, applicationApi, PluginSettings.UNAVAILABLE); + compiler.addCompilerListener(new CompilerListener() { + @Override + public void onStart() { + + } + + @Override + public void onMessage(CompilerMessage compilerMessage) { + if (compilerMessage.getMessageType() == CompilerMessage.MessageType.TYPE_ERROR) { + errorCount++; + } + } + + @Override + public void onFinish() { + + } + }); compiler.initialize(); } @@ -65,8 +88,9 @@ private void compile(String content) throws Exception { Files.write(sourceFile.toPath(), content.getBytes(), StandardOpenOption.WRITE); File outputFile = folder.newFile(); - if (!compiler.compile(sourceFile.getAbsolutePath(), outputFile.getAbsolutePath())) { - throw new Exception("Compilation failed"); + compiler.compile(sourceFile.toPath(), Optional.of(outputFile.toPath())); + if (errorCount > 0) { + throw new Exception("Compilation failed with " + errorCount + " errors"); } } diff --git a/plugins/compiler/as-ssem/src/test/java/net/emustudio/plugins/compiler/ssem/Utils.java b/plugins/compiler/as-ssem/src/test/java/net/emustudio/plugins/compiler/ssem/Utils.java index 59c826ff8..212ae3d9d 100644 --- a/plugins/compiler/as-ssem/src/test/java/net/emustudio/plugins/compiler/ssem/Utils.java +++ b/plugins/compiler/as-ssem/src/test/java/net/emustudio/plugins/compiler/ssem/Utils.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.ssem; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.ssem.ast.Instruction; import net.emustudio.plugins.compiler.ssem.ast.Program; import net.emustudio.plugins.compiler.ssem.ast.ProgramParser; @@ -26,10 +27,7 @@ import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.ParseTree; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Random; +import java.util.*; import static org.junit.Assert.assertEquals; @@ -48,10 +46,10 @@ public static Program parseProgram(String program) { CommonTokenStream tokens = new CommonTokenStream(lexer); SSEMParser parser = new SSEMParser(tokens); parser.removeErrorListeners(); - parser.addErrorListener(new ParserErrorListener()); + parser.addErrorListener(new ParserErrorListener("")); ParseTree tree = parser.start(); - ProgramParser programParser = new ProgramParser(); + ProgramParser programParser = new ProgramParser(""); programParser.visit(tree); return programParser.getProgram(); } @@ -97,7 +95,7 @@ public static void assertInstructions(Program program, ParsedInstruction... inst assertEquals(instructions.length, pinstr.size()); for (ParsedInstruction instruction : instructions) { assertEquals( - new Instruction(instruction.opcode, instruction.operand, Position.unknown(), Position.unknown()), + new Instruction(instruction.opcode, instruction.operand, new SourceCodePosition(0, 0, ""), Optional.empty()), pinstr.get(instruction.line) ); } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/AssemblerZ80.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/AssemblerZ80.java index ac9fbfa87..b7f645d3e 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/AssemblerZ80.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/AssemblerZ80.java @@ -43,9 +43,11 @@ import java.io.FileReader; import java.io.IOException; import java.io.Reader; -import java.util.*; - -import static net.emustudio.emulib.plugins.compiler.FileExtension.stripKnownExtension; +import java.nio.file.Path; +import java.util.List; +import java.util.MissingResourceException; +import java.util.Optional; +import java.util.ResourceBundle; @PluginRoot( type = PLUGIN_TYPE.COMPILER, @@ -71,9 +73,10 @@ public void initialize() { Optional.ofNullable(applicationApi.getContextPool()).ifPresent(pool -> { try { memory = pool.getMemoryContext(pluginID, MemoryContext.class); - if (memory.getDataType() != Byte.class) { + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { throw new InvalidContextException( - "Unexpected memory cell type. Expected Byte but was: " + memory.getDataType() + "Unexpected memory cell type. Expected Byte but was: " + cellTypeClass ); } } catch (InvalidContextException | ContextNotFoundException e) { @@ -94,7 +97,7 @@ public String getCopyright() { @Override public String getDescription() { - return "Assembler targetting Z80 microprocessor"; + return "Assembler targeting Z80 microprocessor"; } @Override @@ -103,20 +106,20 @@ public LexicalAnalyzer createLexer() { } @Override - public boolean compile(String inputFileName, String outputFileName) { + public void compile(Path inputPath, Optional outputPath) { notifyCompileStart(); notifyInfo(getTitle() + ", version " + getVersion()); - try (Reader reader = new FileReader(inputFileName)) { + Path finalOutputPath = outputPath.orElse(convertInputToOutputPath(inputPath, ".hex")); + try (Reader reader = new FileReader(inputPath.toFile())) { AsZ80Lexer lexer = createLexer(CharStreams.fromReader(reader)); - lexer.addErrorListener(new ParserErrorListener()); + lexer.addErrorListener(new ParserErrorListener(inputPath.toString())); CommonTokenStream tokens = new CommonTokenStream(lexer); AsZ80Parser parser = createParser(tokens); - parser.addErrorListener(new ParserErrorListener()); + parser.addErrorListener(new ParserErrorListener(inputPath.toString())); - Program program = new Program(); - program.setFileName(inputFileName); + Program program = new Program(inputPath.toString()); new CreateProgramVisitor(program).visit(parser.rStart()); IntelHEX hex = new IntelHEX(); @@ -139,13 +142,13 @@ public boolean compile(String inputFileName, String outputFileName) { } if (program.env().hasNoErrors()) { - hex.generate(outputFileName); + hex.generate(finalOutputPath); int programLocation = hex.findProgramLocation(); applicationApi.setProgramLocation(programLocation); notifyInfo(String.format( "Compile was successful.\n\tOutput: %s\n\tProgram starts at 0x%s", - outputFileName, RadixUtils.formatWordHexString(programLocation) + finalOutputPath, RadixUtils.formatWordHexString(programLocation) )); if (memory != null) { @@ -154,30 +157,20 @@ public boolean compile(String inputFileName, String outputFileName) { } else { notifyWarning("Memory is not available."); } - return true; } else { for (CompileError error : program.env().getErrors()) { - notifyError(error.line, error.column, error.msg); + notifyError(error.position, error.msg); } - return false; } } catch (CompileException e) { - notifyError(e.line, e.column, e.getMessage()); - return false; + notifyError(e.position, e.getMessage()); } catch (IOException e) { notifyError("Compilation error: " + e); - return false; } finally { notifyCompileFinish(); } } - @Override - public boolean compile(String inputFileName) { - String outputFileName = stripKnownExtension(inputFileName, SOURCE_FILE_EXTENSIONS) + ".hex"; - return compile(inputFileName, outputFileName); - } - @Override public List getSourceFileExtensions() { return SOURCE_FILE_EXTENSIONS; diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/CompileError.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/CompileError.java index 611e65143..f2054ef3f 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/CompileError.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/CompileError.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import java.io.IOException; @@ -39,20 +40,18 @@ public class CompileError { public static final int ERROR_VALUE_MUST_BE_POSITIVE = 10; public static final int ERROR_VALUE_OUT_OF_BOUNDS = 11; - public final int line; - public final int column; public final String msg; public final int errorCode; + public final SourceCodePosition position; - private CompileError(int line, int column, int errorCode, String msg) { - this.line = line; - this.column = column; + private CompileError(SourceCodePosition position, int errorCode, String msg) { + this.position = Objects.requireNonNull(position); this.errorCode = errorCode; this.msg = Objects.requireNonNull(msg); } private CompileError(Node node, int errorCode, String msg) { - this(node.line, node.column, errorCode, msg); + this(node.position, errorCode, msg); } @@ -129,8 +128,7 @@ public static CompileError valueOutOfBounds(Node node, Set allowedValue @Override public String toString() { return "CompileError{" + - "line=" + line + - ", column=" + column + + position + ", msg='" + msg + '\'' + ", errorCode=" + errorCode + '}'; diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ParserErrorListener.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ParserErrorListener.java index 5d0fbb5ee..081f733da 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ParserErrorListener.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ParserErrorListener.java @@ -18,12 +18,21 @@ */ package net.emustudio.plugins.compiler.asZ80; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.exceptions.SyntaxErrorException; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; +import java.util.Objects; + class ParserErrorListener extends BaseErrorListener { + private final String sourceFileName; + + ParserErrorListener(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } + // TODO: parse message expected tokens to token categories @Override public void syntaxError( @@ -35,9 +44,9 @@ public void syntaxError( RecognitionException e) { if (e == null) { - throw new SyntaxErrorException(line, charPositionInLine, msg); + throw new SyntaxErrorException(new SourceCodePosition(line, charPositionInLine, sourceFileName), msg); } else { - throw new SyntaxErrorException(line, charPositionInLine, msg, e); + throw new SyntaxErrorException(new SourceCodePosition(line, charPositionInLine, sourceFileName), msg, e); } } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/Runner.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/Runner.java index 27cee3ac9..d6ed72c85 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/Runner.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/Runner.java @@ -23,6 +23,9 @@ import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.settings.PluginSettings; +import java.nio.file.Path; +import java.util.Optional; + public class Runner { public static void main(String... args) { @@ -49,15 +52,6 @@ public static void main(String... args) { return; } inputFile = args[i]; - if (outputFile == null) { - int index = inputFile.lastIndexOf('.'); - if (index != -1) { - outputFile = inputFile.substring(0, index); - } else { - outputFile = inputFile; - } - outputFile += ".hex"; - } AssemblerZ80 compiler = new AssemblerZ80(0L, ApplicationApi.UNAVAILABLE, PluginSettings.UNAVAILABLE); compiler.addCompilerListener(new CompilerListener() { @@ -76,7 +70,7 @@ public void onFinish() { } }); try { - compiler.compile(inputFile, outputFile); + compiler.compile(Path.of(inputFile), Optional.ofNullable(outputFile).map(Path::of)); } catch (Exception e) { System.err.println(e.getMessage()); } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Evaluated.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Evaluated.java index f446f3a4d..9873eb8fa 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Evaluated.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Evaluated.java @@ -18,25 +18,26 @@ */ package net.emustudio.plugins.compiler.asZ80.ast; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; public class Evaluated extends Node { public final int value; public final boolean isAddress; - public Evaluated(int line, int column, int value, boolean isAddress) { - super(line, column); + public Evaluated(SourceCodePosition position, int value, boolean isAddress) { + super(position); this.value = value; this.isAddress = isAddress; } - public Evaluated(int line, int column, int value) { - this(line, column, value, false); + public Evaluated(SourceCodePosition position, int value) { + this(position, value, false); } @Override protected Node mkCopy() { - return new Evaluated(line, column, value, isAddress); + return new Evaluated(position, value, isAddress); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Node.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Node.java index 281100203..625b564d0 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Node.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Node.java @@ -18,24 +18,25 @@ */ package net.emustudio.plugins.compiler.asZ80.ast; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; +import org.antlr.v4.runtime.Token; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; public abstract class Node { - public final int line; - public final int column; + public final SourceCodePosition position; protected final List children = new ArrayList<>(); protected Node parent; private int address; private Optional maxValue = Optional.empty(); private Optional sizeBytes = Optional.empty(); - public Node(int line, int column) { - this.line = line; - this.column = column; + public Node(SourceCodePosition position) { + this.position = Objects.requireNonNull(position); } public void addChildFirst(Node node) { @@ -187,4 +188,8 @@ public Node setSizeBytes(int bytes) { this.maxValue = Optional.of(value); return this; } + + public static SourceCodePosition positionFromToken(String fileName, Token token) { + return new SourceCodePosition(token.getLine(), token.getCharPositionInLine(), fileName); + } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Program.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Program.java index 5ca097ad1..fd8ba0035 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Program.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/Program.java @@ -18,34 +18,25 @@ */ package net.emustudio.plugins.compiler.asZ80.ast; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import java.util.Objects; -import java.util.Optional; public class Program extends Node { private final NameSpace env; - private String filename; - public Program(int line, int column, NameSpace env) { - super(line, column); + public Program(SourceCodePosition position, NameSpace env) { + super(position); this.env = Objects.requireNonNull(env); } - public Program(NameSpace env) { - this(0, 0, env); + public Program(String fileName, NameSpace env) { + this(new SourceCodePosition(0, 0, fileName), env); } - public Program() { - this(new NameSpace()); - } - - public Optional getFileName() { - return Optional.ofNullable(filename); - } - - public void setFileName(String filename) { - this.filename = filename; + public Program(String fileName) { + this(fileName, new NameSpace()); } public NameSpace env() { @@ -59,8 +50,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - Program program = new Program(line, column, env); - program.setFileName(filename); - return program; + return new Program(position, env); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDB.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDB.java index 886841cad..2065e7c1c 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDB.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDB.java @@ -18,13 +18,14 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.data; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; public class DataDB extends Node { - public DataDB(int line, int column) { - super(line, column); + public DataDB(SourceCodePosition position) { + super(position); // child is string, expr or 8-bit instruction } @@ -35,6 +36,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new DataDB(line, column); + return new DataDB(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDS.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDS.java index 4e46b5cff..9778114e2 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDS.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDS.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.data; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; @@ -26,8 +27,9 @@ * Child is an expression which must not use forward references and must not be negative. */ public class DataDS extends Node { - public DataDS(int line, int column) { - super(line, column); + + public DataDS(SourceCodePosition position) { + super(position); } @Override @@ -37,6 +39,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new DataDS(line, column); + return new DataDS(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDW.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDW.java index 0ec9bd7da..c9ff29cfb 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDW.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/data/DataDW.java @@ -18,13 +18,14 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.data; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; public class DataDW extends Node { - public DataDW(int line, int column) { - super(line, column); + public DataDW(SourceCodePosition position) { + super(position); // child is expr 2 byte } @@ -35,6 +36,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new DataDW(line, column); + return new DataDW(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprCurrentAddress.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprCurrentAddress.java index 8462866ea..49568c738 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprCurrentAddress.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprCurrentAddress.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.NameSpace; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -27,8 +28,8 @@ public class ExprCurrentAddress extends Node { - public ExprCurrentAddress(int line, int column) { - super(line, column); + public ExprCurrentAddress(SourceCodePosition position) { + super(position); } @Override @@ -38,11 +39,11 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new ExprCurrentAddress(line, column); + return new ExprCurrentAddress(position); } @Override public Optional eval(Optional currentAddress, NameSpace env) { - return currentAddress.map(addr -> new Evaluated(line, column, addr, true)); + return currentAddress.map(addr -> new Evaluated(position, addr, true)); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprId.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprId.java index 0a4fd3d8b..2c9bf8908 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprId.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprId.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.NameSpace; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -32,13 +33,13 @@ public class ExprId extends Node { public final String id; - public ExprId(int line, int column, String id) { - super(line, column); + public ExprId(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); } - public ExprId(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public ExprId(String fileName, Token id) { + this(positionFromToken(fileName, id), id.getText()); } @Override @@ -58,7 +59,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new ExprId(line, column, id); + return new ExprId(position, id); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprInfix.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprInfix.java index f27f16c08..196e0034a 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprInfix.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprInfix.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.NameSpace; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -59,15 +60,15 @@ public class ExprInfix extends Node { public final int operationCode; private final BiFunction operation; - public ExprInfix(int line, int column, int op) { - super(line, column); + public ExprInfix(SourceCodePosition position, int op) { + super(position); this.operationCode = op; this.operation = Objects.requireNonNull(infixOps.get(op), "Unknown infix operation"); // children are: left, right } - public ExprInfix(Token op) { - this(op.getLine(), op.getCharPositionInLine(), op.getType()); + public ExprInfix(String fileName, Token op) { + this(positionFromToken(fileName, op), op.getType()); } @Override @@ -86,7 +87,7 @@ public Optional eval(Optional currentAddress, NameSpace env) if (left.isPresent() && right.isPresent()) { int l = left.get().value; int r = right.get().value; - return Optional.of(new Evaluated(line, column, operation.apply(l, r))); + return Optional.of(new Evaluated(position, operation.apply(l, r))); } return Optional.empty(); @@ -99,7 +100,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new ExprInfix(line, column, operationCode); + return new ExprInfix(position, operationCode); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprNumber.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprNumber.java index debc9568c..dcc24b7a9 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprNumber.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprNumber.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.NameSpace; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -30,18 +31,18 @@ public class ExprNumber extends Node { public final int number; - public ExprNumber(int line, int column, int number) { - super(line, column); + public ExprNumber(SourceCodePosition position, int number) { + super(position); this.number = number; } - public ExprNumber(Token number, Function parser) { - this(number.getLine(), number.getCharPositionInLine(), parser.apply(number)); + public ExprNumber(String fileName, Token number, Function parser) { + this(positionFromToken(fileName, number), parser.apply(number)); } @Override public Optional eval(Optional currentAddress, NameSpace env) { - return Optional.of(new Evaluated(line, column, number)); + return Optional.of(new Evaluated(position, number)); } @Override @@ -56,7 +57,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new ExprNumber(line, column, number); + return new ExprNumber(position, number); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprString.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprString.java index af91e69d0..f32aa5ccc 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprString.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprString.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.NameSpace; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -32,13 +33,13 @@ public class ExprString extends Node { public final String string; - public ExprString(int line, int column, String string) { - super(line, column); + public ExprString(SourceCodePosition position, String string) { + super(position); this.string = Objects.requireNonNull(string); } - public ExprString(Token str) { - this(str.getLine(), str.getCharPositionInLine(), parseLitString(str)); + public ExprString(String fileName, Token str) { + this(positionFromToken(fileName, str), parseLitString(str)); } @Override @@ -48,13 +49,13 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new ExprString(line, column, string); + return new ExprString(position, string); } @Override public Optional eval(Optional currentAddress, NameSpace env) { if (string.length() == 1) { - return Optional.of(new Evaluated(line, column, string.charAt(0) & 0xFF)); + return Optional.of(new Evaluated(position, string.charAt(0) & 0xFF)); } return Optional.empty(); } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprUnary.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprUnary.java index a60b78add..99369ea8c 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprUnary.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/expr/ExprUnary.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.expr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.NameSpace; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -41,15 +42,15 @@ public class ExprUnary extends Node { public final int operationCode; private final Function operation; - public ExprUnary(int line, int column, int op) { - super(line, column); + public ExprUnary(SourceCodePosition position, int op) { + super(position); this.operationCode = op; this.operation = Objects.requireNonNull(unaryOps.get(op), "Unknown unary operation"); // child is expr } - public ExprUnary(Token op) { - this(op.getLine(), op.getCharPositionInLine(), op.getType()); + public ExprUnary(String fileName, Token op) { + this(positionFromToken(fileName, op), op.getType()); } @Override @@ -61,7 +62,7 @@ public void accept(NodeVisitor visitor) { public Optional eval(Optional currentAddress, NameSpace env) { return getChild(0) .eval(currentAddress, env) - .map(childEval -> new Evaluated(line, column, operation.apply(childEval.value))); + .map(childEval -> new Evaluated(position, operation.apply(childEval.value))); } @Override @@ -71,7 +72,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new ExprUnary(line, column, operationCode); + return new ExprUnary(position, operationCode); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/Instr.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/Instr.java index 737ad25ae..1a0f686c9 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/Instr.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/Instr.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -28,8 +29,8 @@ public class Instr extends Node { public final int z; private int y; - public Instr(int line, int column, int opcode, int x, int y, int z) { - super(line, column); + public Instr(SourceCodePosition position, int opcode, int x, int y, int z) { + super(position); this.opcode = opcode; this.x = x; this.y = y; @@ -38,12 +39,12 @@ public Instr(int line, int column, int opcode, int x, int y, int z) { // children might be expr in the same order as when compiled } - public Instr(Token opcode, int x, int y, int z) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), x, y, z); + public Instr(String fileName, Token opcode, int x, int y, int z) { + this(positionFromToken(fileName, opcode), opcode.getType(), x, y, z); } - public Instr(Token opcode, int x, int q, int p, int z) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), x, (p << 1) | q, z); + public Instr(String fileName, Token opcode, int x, int q, int p, int z) { + this(positionFromToken(fileName, opcode), opcode.getType(), x, (p << 1) | q, z); } public void setY(int y) { @@ -67,7 +68,7 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new Instr(line, column, opcode, x, y, z); + return new Instr(position, opcode, x, y, z); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrCB.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrCB.java index 169cd2e1c..d01a0361a 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrCB.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrCB.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -49,8 +50,8 @@ public class InstrCB extends Node { public final int z; private int y; - public InstrCB(int line, int column, int opcode, int y, int z) { - super(line, column); + public InstrCB(SourceCodePosition position, int opcode, int y, int z) { + super(position); this.opcode = opcode; this.x = xmap.get(opcode); this.y = y; @@ -59,8 +60,8 @@ public InstrCB(int line, int column, int opcode, int y, int z) { // possibly a child is expr: if so, then it's new y } - public InstrCB(Token opcode, int y, int z) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), y, z); + public InstrCB(String fileName, Token opcode, int y, int z) { + this(positionFromToken(fileName, opcode), opcode.getType(), y, z); } public void setY(int bit) { @@ -81,7 +82,7 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new InstrCB(line, column, opcode, y, z); + return new InstrCB(position, opcode, y, z); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrED.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrED.java index 66d6e4b56..3562fdf89 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrED.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrED.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -65,8 +66,8 @@ public class InstrED extends Node { public final int y; public final int z; - public InstrED(int line, int column, int opcode, int y, int z) { - super(line, column); + public InstrED(SourceCodePosition position, int opcode, int y, int z) { + super(position); this.opcode = opcode; this.x = xmap.get(opcode); this.y = y; @@ -75,12 +76,12 @@ public InstrED(int line, int column, int opcode, int y, int z) { // possibly child is expr } - public InstrED(Token opcode, int y, int z) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), y, z); + public InstrED(String fileName, Token opcode, int y, int z) { + this(positionFromToken(fileName, opcode), opcode.getType(), y, z); } - public InstrED(Token opcode, int p, int q, int z) { - this(opcode, (p << 1) | q, z); + public InstrED(String fileName, Token opcode, int p, int q, int z) { + this(fileName, opcode, (p << 1) | q, z); } public byte[] eval() { @@ -97,7 +98,7 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new InstrED(line, column, opcode, y, z); + return new InstrED(position, opcode, y, z); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrXD.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrXD.java index 1f4350de8..8e8e12126 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrXD.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrXD.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -29,8 +30,8 @@ public class InstrXD extends Node { public final int y; public final int z; - public InstrXD(int line, int column, int opcode, int prefix, int x, int y, int z) { - super(line, column); + public InstrXD(SourceCodePosition position, int opcode, int prefix, int x, int y, int z) { + super(position); this.opcode = opcode; this.prefix = prefix; this.x = x; @@ -41,12 +42,12 @@ public InstrXD(int line, int column, int opcode, int prefix, int x, int y, int z // 2. child is maybe N if (II+d) is defined } - public InstrXD(Token opcode, int prefix, int x, int y, int z) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), prefix, x, y, z); + public InstrXD(String fileName, Token opcode, int prefix, int x, int y, int z) { + this(positionFromToken(fileName, opcode), opcode.getType(), prefix, x, y, z); } - public InstrXD(Token opcode, int prefix, int x, int q, int p, int z) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), prefix, x, (p << 1) | q, z); + public InstrXD(String fileName, Token opcode, int prefix, int x, int q, int p, int z) { + this(positionFromToken(fileName, opcode), opcode.getType(), prefix, x, (p << 1) | q, z); } public byte[] eval() { @@ -63,7 +64,7 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new InstrXD(line, column, opcode, prefix, x, y, z); + return new InstrXD(position, opcode, prefix, x, y, z); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrXDCB.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrXDCB.java index 20f302657..d2c45949c 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrXDCB.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/instr/InstrXDCB.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.instr; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -53,8 +54,8 @@ public class InstrXDCB extends Node { public final int prefix; private int y; - public InstrXDCB(int line, int column, int opcode, int prefix, int y, int z) { - super(line, column); + public InstrXDCB(SourceCodePosition position, int opcode, int prefix, int y, int z) { + super(position); this.opcode = opcode; this.prefix = prefix; @@ -67,8 +68,8 @@ public InstrXDCB(int line, int column, int opcode, int prefix, int y, int z) { // 2. possibly another expr child } - public InstrXDCB(Token opcode, int prefix, int y, int z) { - this(opcode.getLine(), opcode.getCharPositionInLine(), opcode.getType(), prefix, y, z); + public InstrXDCB(String fileName, Token opcode, int prefix, int y, int z) { + this(positionFromToken(fileName, opcode), opcode.getType(), prefix, y, z); } public void setY(int y) { @@ -90,7 +91,7 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new InstrXDCB(line, column, opcode, prefix, y, z); + return new InstrXDCB(position, opcode, prefix, y, z); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoEqu.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoEqu.java index aa369f2cc..1602cca4b 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoEqu.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoEqu.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,14 +28,14 @@ public class PseudoEqu extends Node { public final String id; - public PseudoEqu(int line, int column, String id) { - super(line, column); + public PseudoEqu(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); // expr is the only child } - public PseudoEqu(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public PseudoEqu(String fileName, Token id) { + this(positionFromToken(fileName, id), id.getText()); } @Override @@ -49,7 +50,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoEqu(line, column, id); + return new PseudoEqu(position, id); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoIf.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoIf.java index 91b9f3303..4a16f23b4 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoIf.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoIf.java @@ -18,13 +18,14 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; public class PseudoIf extends Node { - public PseudoIf(int line, int column) { - super(line, column); + public PseudoIf(SourceCodePosition position) { + super(position); // expr is the first child // statement is the second child } @@ -36,6 +37,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoIf(line, column); + return new PseudoIf(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoIfExpression.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoIfExpression.java index 1153e9d69..d1c231c2b 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoIfExpression.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoIfExpression.java @@ -18,12 +18,13 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; public class PseudoIfExpression extends Node { - public PseudoIfExpression(int line, int column) { - super(line, column); + public PseudoIfExpression(SourceCodePosition position) { + super(position); } @Override @@ -33,6 +34,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoIfExpression(line, column); + return new PseudoIfExpression(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoInclude.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoInclude.java index 27924ec3b..17a71a794 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoInclude.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoInclude.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ParsingUtils; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; @@ -28,13 +29,13 @@ public class PseudoInclude extends Node { public final String filename; - public PseudoInclude(int line, int column, String fileName) { - super(line, column); + public PseudoInclude(SourceCodePosition position, String fileName) { + super(position); this.filename = Objects.requireNonNull(fileName); } - public PseudoInclude(Token fileName) { - this(fileName.getLine(), fileName.getCharPositionInLine(), ParsingUtils.parseLitString(fileName)); + public PseudoInclude(String srcFileName, Token fileName) { + this(positionFromToken(srcFileName, fileName), ParsingUtils.parseLitString(fileName)); } @Override @@ -49,7 +50,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoInclude(line, column, filename); + return new PseudoInclude(position, filename); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoLabel.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoLabel.java index d84255156..fd3234a82 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoLabel.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoLabel.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.NameSpace; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -32,18 +33,18 @@ public class PseudoLabel extends Node { public final String label; - public PseudoLabel(int line, int column, String label) { - super(line, column); + public PseudoLabel(SourceCodePosition position, String label) { + super(position); this.label = Objects.requireNonNull(label); } - public PseudoLabel(Token label) { - this(label.getLine(), label.getCharPositionInLine(), parseLabel(label)); + public PseudoLabel(String fileName, Token label) { + this(positionFromToken(fileName, label), parseLabel(label)); } @Override public Optional eval(Optional currentAddress, NameSpace env) { - return currentAddress.map(addr -> new Evaluated(line, column, addr, true)); + return currentAddress.map(addr -> new Evaluated(position, addr, true)); } @Override @@ -58,7 +59,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoLabel(line, column, label); + return new PseudoLabel(position, label); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroArgument.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroArgument.java index 7e0023a1f..659f73a47 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroArgument.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroArgument.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; @@ -26,8 +27,8 @@ */ public class PseudoMacroArgument extends Node { - public PseudoMacroArgument(int line, int column) { - super(line, column); + public PseudoMacroArgument(SourceCodePosition position) { + super(position); // the only child is expr } @@ -38,6 +39,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoMacroArgument(line, column); + return new PseudoMacroArgument(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroCall.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroCall.java index f7abf7dc2..9c04dc807 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroCall.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroCall.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,14 +28,14 @@ public class PseudoMacroCall extends Node { public final String id; - public PseudoMacroCall(int line, int column, String id) { - super(line, column); + public PseudoMacroCall(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); // children are exprs (arguments) } - public PseudoMacroCall(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public PseudoMacroCall(String fileName, Token id) { + this(positionFromToken(fileName, id), id.getText()); } @Override @@ -49,7 +50,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoMacroCall(line, column, id); + return new PseudoMacroCall(position, id); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroDef.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroDef.java index 327489af6..758fd72a0 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroDef.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroDef.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,15 +28,15 @@ public class PseudoMacroDef extends Node { public final String id; - public PseudoMacroDef(int line, int column, String id) { - super(line, column); + public PseudoMacroDef(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); // parameters are the first children // statements are followed } - public PseudoMacroDef(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public PseudoMacroDef(String fileName, Token id) { + this(positionFromToken(fileName, id), id.getText()); } @Override @@ -58,6 +59,6 @@ public boolean equals(Object o) { } public PseudoMacroDef mkCopy() { - return new PseudoMacroDef(line, column, id); + return new PseudoMacroDef(position, id); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroParameter.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroParameter.java index 2376e948d..8fc66d668 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroParameter.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoMacroParameter.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; @@ -26,8 +27,8 @@ */ public class PseudoMacroParameter extends Node { - public PseudoMacroParameter(int line, int column) { - super(line, column); + public PseudoMacroParameter(SourceCodePosition position) { + super(position); // the only child is ExprId } @@ -38,6 +39,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoMacroParameter(line, column); + return new PseudoMacroParameter(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoOrg.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoOrg.java index 408fb5b1c..e2824c956 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoOrg.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoOrg.java @@ -18,13 +18,14 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; public class PseudoOrg extends Node { - public PseudoOrg(int line, int column) { - super(line, column); + public PseudoOrg(SourceCodePosition position) { + super(position); // expr is the only child } @@ -35,6 +36,6 @@ public void accept(NodeVisitor visitor) { @Override protected Node mkCopy() { - return new PseudoOrg(line, column); + return new PseudoOrg(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoVar.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoVar.java index 2c12577af..65149c605 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoVar.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/ast/pseudo/PseudoVar.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.ast.pseudo; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.visitors.NodeVisitor; import org.antlr.v4.runtime.Token; @@ -27,14 +28,14 @@ public class PseudoVar extends Node { public final String id; - public PseudoVar(int line, int column, String id) { - super(line, column); + public PseudoVar(SourceCodePosition position, String id) { + super(position); this.id = Objects.requireNonNull(id); // expr is the only child } - public PseudoVar(Token id) { - this(id.getLine(), id.getCharPositionInLine(), id.getText()); + public PseudoVar(String fileName, Token id) { + this(positionFromToken(fileName, id), id.getText()); } @Override @@ -49,7 +50,7 @@ protected String toStringShallow() { @Override protected Node mkCopy() { - return new PseudoVar(line, column, id); + return new PseudoVar(position, id); } @Override diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/CompileException.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/CompileException.java index 938d65fbf..472622d83 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/CompileException.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/CompileException.java @@ -18,21 +18,20 @@ */ package net.emustudio.plugins.compiler.asZ80.exceptions; -public class CompileException extends RuntimeException { - public final int line; - public final int column; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; - public CompileException(int line, int column, String message) { - super("[" + line + "," + column + "] " + message); +import java.util.Objects; - this.column = column; - this.line = line; - } +public class CompileException extends RuntimeException { + public final SourceCodePosition position; - public CompileException(int line, int column, String message, Throwable cause) { - super("[" + line + "," + column + "] " + message, cause); + public CompileException(SourceCodePosition position, String message) { + super(position + " " + message); + this.position = Objects.requireNonNull(position); + } - this.column = column; - this.line = line; + public CompileException(SourceCodePosition position, String message, Throwable cause) { + super(position + " " + message, cause); + this.position = Objects.requireNonNull(position); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/FatalError.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/FatalError.java index 755fa153b..0099b4233 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/FatalError.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/FatalError.java @@ -18,19 +18,20 @@ */ package net.emustudio.plugins.compiler.asZ80.exceptions; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.CompileError; public class FatalError extends CompileException { - public FatalError(int line, int column, String why) { - super(line, column, "Fatal error (cannot continue): " + why); + public FatalError(SourceCodePosition position, String why) { + super(position, "Fatal error (cannot continue): " + why); } - public static void now(int line, int column, String why) { - throw new FatalError(line, column, why); + public static void now(SourceCodePosition position, String why) { + throw new FatalError(position, why); } public static void now(CompileError error) { - now(error.line, error.column, error.msg); + now(error.position, error.msg); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/SyntaxErrorException.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/SyntaxErrorException.java index 8777f4944..adb3a403a 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/SyntaxErrorException.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/exceptions/SyntaxErrorException.java @@ -18,12 +18,14 @@ */ package net.emustudio.plugins.compiler.asZ80.exceptions; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; + public class SyntaxErrorException extends CompileException { - public SyntaxErrorException(int line, int column, String message) { - super(line, column, message); + public SyntaxErrorException(SourceCodePosition position, String message) { + super(position, message); } - public SyntaxErrorException(int line, int column, String message, Throwable cause) { - super(line, column, message, cause); + public SyntaxErrorException(SourceCodePosition position, String message, Throwable cause) { + super(position, message, cause); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateDataVisitor.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateDataVisitor.java index e1347cb5a..52cf8262a 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateDataVisitor.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateDataVisitor.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.AsZ80Parser.*; import net.emustudio.plugins.compiler.asZ80.AsZ80ParserBaseVisitor; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -26,18 +27,26 @@ import net.emustudio.plugins.compiler.asZ80.ast.data.DataDW; import org.antlr.v4.runtime.Token; +import java.util.Objects; + public class CreateDataVisitor extends AsZ80ParserBaseVisitor { + private final String sourceFileName; + + public CreateDataVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } + @Override public Node visitDataDB(DataDBContext ctx) { Token start = ctx.getStart(); - DataDB db = new DataDB(start.getLine(), start.getCharPositionInLine()); + DataDB db = new DataDB(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); for (RDBdataContext next : ctx.rDBdata()) { if (next.expr != null) { - db.addChild(CreateVisitors.expr.visit(next.expr)); + db.addChild(exprVisitor().visit(next.expr)); } else if (next.instr != null) { - db.addChild(CreateVisitors.instr.visit(next.instr)); + db.addChild(instrVisitor().visit(next.instr)); } } return db; @@ -46,11 +55,11 @@ public Node visitDataDB(DataDBContext ctx) { @Override public Node visitDataDW(DataDWContext ctx) { Token start = ctx.getStart(); - DataDW dw = new DataDW(start.getLine(), start.getCharPositionInLine()); + DataDW dw = new DataDW(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); for (RDWdataContext next : ctx.rDWdata()) { if (next.expr != null) { - dw.addChild(CreateVisitors.expr.visit(next.expr)); + dw.addChild(exprVisitor().visit(next.expr)); } } @@ -60,8 +69,16 @@ public Node visitDataDW(DataDWContext ctx) { @Override public Node visitDataDS(DataDSContext ctx) { Token start = ctx.getStart(); - DataDS ds = new DataDS(start.getLine(), start.getCharPositionInLine()); - ds.addChild(CreateVisitors.expr.visit(ctx.data)); + DataDS ds = new DataDS(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); + ds.addChild(exprVisitor().visit(ctx.data)); return ds; } + + private CreateExprVisitor exprVisitor() { + return CreateVisitors.expr(sourceFileName); + }; + + private CreateInstrVisitor instrVisitor() { + return CreateVisitors.instr(sourceFileName); + }; } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateExprVisitor.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateExprVisitor.java index b73cbd0a4..07af904d9 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateExprVisitor.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateExprVisitor.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.AsZ80Parser.*; import net.emustudio.plugins.compiler.asZ80.AsZ80ParserBaseVisitor; import net.emustudio.plugins.compiler.asZ80.ParsingUtils; @@ -25,53 +26,60 @@ import net.emustudio.plugins.compiler.asZ80.ast.expr.*; import org.antlr.v4.runtime.Token; +import java.util.Objects; + public class CreateExprVisitor extends AsZ80ParserBaseVisitor { + private final String sourceFileName; + + public CreateExprVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } @Override public Node visitExprOct(ExprOctContext ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitOct); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitOct); } @Override public Node visitExprHex1(ExprHex1Context ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitHex1); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitHex1); } @Override public Node visitExprHex2(ExprHex2Context ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitHex2); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitHex2); } @Override public Node visitExprDec(ExprDecContext ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitDec); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitDec); } @Override public Node visitExprBin(ExprBinContext ctx) { - return new ExprNumber(ctx.num, ParsingUtils::parseLitBin); + return new ExprNumber(sourceFileName, ctx.num, ParsingUtils::parseLitBin); } @Override public Node visitExprId(ExprIdContext ctx) { - return new ExprId(ctx.id); + return new ExprId(sourceFileName, ctx.id); } @Override public Node visitExprString(ExprStringContext ctx) { - return new ExprString(ctx.str); + return new ExprString(sourceFileName, ctx.str); } @Override public Node visitExprUnary(ExprUnaryContext ctx) { - ExprUnary unary = new ExprUnary(ctx.unaryop); + ExprUnary unary = new ExprUnary(sourceFileName, ctx.unaryop); unary.addChild(visit(ctx.expr)); return unary; } @Override public Node visitExprInfix(ExprInfixContext ctx) { - ExprInfix infix = new ExprInfix(ctx.op); + ExprInfix infix = new ExprInfix(sourceFileName, ctx.op); infix.addChild(visit(ctx.expr1)); infix.addChild(visit(ctx.expr2)); return infix; @@ -85,6 +93,6 @@ public Node visitExprParens(ExprParensContext ctx) { @Override public Node visitExprCurrentAddress(ExprCurrentAddressContext ctx) { Token start = ctx.getStart(); - return new ExprCurrentAddress(start.getLine(), start.getCharPositionInLine()); + return new ExprCurrentAddress(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateInstrVisitor.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateInstrVisitor.java index bb3c902e2..753575bc8 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateInstrVisitor.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateInstrVisitor.java @@ -26,10 +26,16 @@ import java.util.HashMap; import java.util.Map; +import java.util.Objects; import static net.emustudio.plugins.compiler.asZ80.AsZ80Parser.*; public class CreateInstrVisitor extends AsZ80ParserBaseVisitor { + private final String sourceFileName; + + public CreateInstrVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } @Override public Node visitInstrXDCB_R(InstrXDCB_RContext ctx) { @@ -44,8 +50,8 @@ public Node visitInstrXDCB_R(InstrXDCB_RContext ctx) { int prefix = CompilerTables.prefix.get(ctx.d.ii.start.getType()); int y = CompilerTables.rot.get(ctx.opcode.getType()); int z = CompilerTables.registers.get(ctx.r.start.getType()); - Node instr = new InstrXDCB(ctx.opcode, prefix, y, z).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXDCB(sourceFileName, ctx.opcode, prefix, y, z).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } @@ -61,8 +67,8 @@ public Node visitInstrXDCB(InstrXDCBContext ctx) { // | opcode=OPCODE_SLL d=rDisplacement # instrXDCB int prefix = CompilerTables.prefix.get(ctx.d.ii.start.getType()); int y = CompilerTables.rot.get(ctx.opcode.getType()); - Node instr = new InstrXDCB(ctx.opcode, prefix, y, 6).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXDCB(sourceFileName, ctx.opcode, prefix, y, 6).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } @@ -72,9 +78,9 @@ public Node visitInstrXDCB_N(InstrXDCB_NContext ctx) { // | opcode=OPCODE_RES n=rExpression SEP_COMMA d=rDisplacement # instrXDCB_N // | opcode=OPCODE_SET n=rExpression SEP_COMMA d=rDisplacement # instrXDCB_N int prefix = CompilerTables.prefix.get(ctx.d.ii.start.getType()); - Node instr = new InstrXDCB(ctx.opcode, prefix, 0, 6).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.n).setMaxValue(7)); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXDCB(sourceFileName, ctx.opcode, prefix, 0, 6).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.n).setMaxValue(7)); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } @@ -84,9 +90,9 @@ public Node visitInstrXDCB_N_R(InstrXDCB_N_RContext ctx) { // | opcode=OPCODE_SET n=rExpression SEP_COMMA d=rDisplacement SEP_COMMA r=rRegister2 # instrXDCB_N_R int prefix = CompilerTables.prefix.get(ctx.d.ii.start.getType()); int z = CompilerTables.registers.get(ctx.r.start.getType()); - Node instr = new InstrXDCB(ctx.opcode, prefix, 0, z).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.n).setMaxValue(7)); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXDCB(sourceFileName, ctx.opcode, prefix, 0, z).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.n).setMaxValue(7)); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } @@ -96,7 +102,7 @@ public Node visitInstrED_R2(InstrED_R2Context ctx) { // | opcode=OPCODE_OUT SEP_LPAR REG_C SEP_RPAR SEP_COMMA r=rRegister2 # instrED_R2 int y = CompilerTables.registers.get(ctx.r.start.getType()); int z = (ctx.opcode.getType() == OPCODE_IN) ? 0 : 1; - return new InstrED(ctx.opcode, y, z).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, y, z).setSizeBytes(2); } @Override @@ -104,7 +110,7 @@ public Node visitInstrED_C(InstrED_CContext ctx) { // | opcode=OPCODE_IN SEP_LPAR REG_C SEP_RPAR # instrED_C // | opcode=OPCODE_OUT SEP_LPAR REG_C SEP_RPAR SEP_COMMA n=LIT_NUMBER # instrED_C int z = (ctx.opcode.getType() == OPCODE_IN) ? 0 : 1; - return new InstrED(ctx.opcode, 6, z).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, 6, z).setSizeBytes(2); } @Override @@ -113,7 +119,7 @@ public Node visitInstrED_RP(InstrED_RPContext ctx) { // | opcode=OPCODE_ADC REG_HL SEP_COMMA rp=rRegPair # instrED_RP int q = (ctx.opcode.getType() == OPCODE_SBC) ? 0 : 1; int p = CompilerTables.regPairs.get(ctx.rp.start.getType()); - return new InstrED(ctx.opcode, p, q, 2).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, p, q, 2).setSizeBytes(2); } @Override @@ -121,8 +127,8 @@ public Node visitInstrED_NN_RP(InstrED_NN_RPContext ctx) { // | opcode=OPCODE_LD SEP_LPAR nn=rExpression SEP_RPAR SEP_COMMA rp=rRegPair # instrED_NN_RP int q = 0; int p = CompilerTables.regPairs.get(ctx.rp.getType()); - Node instr = new InstrED(ctx.opcode, p, q, 3).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new InstrED(sourceFileName, ctx.opcode, p, q, 3).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -131,8 +137,8 @@ public Node visitInstrED_RP_NN(InstrED_RP_NNContext ctx) { // | opcode=OPCODE_LD rp=rRegPair SEP_COMMA SEP_LPAR nn=rExpression SEP_RPAR # instrED_RP_NN int q = 1; int p = CompilerTables.regPairs.get(ctx.rp.getType()); - Node instr = new InstrED(ctx.opcode, p, q, 3).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new InstrED(sourceFileName, ctx.opcode, p, q, 3).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -140,7 +146,7 @@ public Node visitInstrED_RP_NN(InstrED_RP_NNContext ctx) { public Node visitInstrED_IM(InstrED_IMContext ctx) { // | opcode=OPCODE_IM im=(IM_0|IM_1|IM_2|IM_01) # instrED_IM int y = CompilerTables.im.get(ctx.im.getType()); - return new InstrED(ctx.opcode, y, 6).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, y, 6).setSizeBytes(2); } @Override @@ -157,7 +163,7 @@ public Node visitInstrED_RIA_RIA(InstrED_RIA_RIAContext ctx) { } else if (ctx.src.getType() == REG_R) { y = 3; } - return new InstrED(ctx.opcode, y, 7).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, y, 7).setSizeBytes(2); } @Override @@ -185,19 +191,19 @@ public Node visitInstrED(InstrEDContext ctx) { // | opcode=OPCODE_OTDR # instrED switch (ctx.opcode.getType()) { case OPCODE_NEG: - return new InstrED(ctx.opcode, 0, 4).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, 0, 4).setSizeBytes(2); case OPCODE_RETN: - return new InstrED(ctx.opcode, 0, 5).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, 0, 5).setSizeBytes(2); case OPCODE_RETI: - return new InstrED(ctx.opcode, 1, 5).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, 1, 5).setSizeBytes(2); case OPCODE_RRD: - return new InstrED(ctx.opcode, 4, 7).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, 4, 7).setSizeBytes(2); case OPCODE_RLD: - return new InstrED(ctx.opcode, 5, 7).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, 5, 7).setSizeBytes(2); } Pair yz = CompilerTables.block.get(ctx.opcode.getType()); - return new InstrED(ctx.opcode, yz.l, yz.r).setSizeBytes(2); + return new InstrED(sourceFileName, ctx.opcode, yz.l, yz.r).setSizeBytes(2); } @Override @@ -212,7 +218,7 @@ public Node visitInstrCB(InstrCBContext ctx) { // | opcode=OPCODE_SRL r=rRegister # instrCB int y = CompilerTables.rot.get(ctx.opcode.getType()); int z = CompilerTables.registers.get(ctx.r.r.getType()); - return new InstrCB(ctx.opcode, y, z).setSizeBytes(2); + return new InstrCB(sourceFileName, ctx.opcode, y, z).setSizeBytes(2); } @Override @@ -222,8 +228,8 @@ public Node visitInstrCB_N_R(InstrCB_N_RContext ctx) { // | opcode=OPCODE_SET n=rExpression SEP_COMMA r=rRegister # instrCB_N_R int z = CompilerTables.registers.get(ctx.r.r.getType()); // y needs to be computed from expr - Node instr = new InstrCB(ctx.opcode, 0, z).setSizeBytes(2); - instr.addChild(CreateVisitors.expr.visit(ctx.n).setMaxValue(7)); + Node instr = new InstrCB(sourceFileName, ctx.opcode, 0, z).setSizeBytes(2); + instr.addChild(exprVisitor().visit(ctx.n).setMaxValue(7)); return instr; } @@ -231,8 +237,8 @@ public Node visitInstrCB_N_R(InstrCB_N_RContext ctx) { public Node visitInstrXD_II_NN(InstrXD_II_NNContext ctx) { // | opcode=OPCODE_LD ii=rII SEP_COMMA nn=rExpression # instrXD_II_NN int prefix = CompilerTables.prefix.get(ctx.ii.start.getType()); - Node instr = new InstrXD(ctx.opcode, prefix, 0, 0, 2, 1).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 0, 0, 2, 1).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -241,15 +247,15 @@ public Node visitInstrXD_II_RP(InstrXD_II_RPContext ctx) { // | opcode=OPCODE_ADD ii=rII SEP_COMMA rp=(REG_BC|REG_DE|REG_IX|REG_IY|REG_SP) # instrXD_II_RP int prefix = CompilerTables.prefix.get(ctx.ii.start.getType()); int p = CompilerTables.regPairsII.get(ctx.rp.getType()); - return new InstrXD(ctx.opcode, prefix, 0, 1, p, 1).setSizeBytes(2); + return new InstrXD(sourceFileName, ctx.opcode, prefix, 0, 1, p, 1).setSizeBytes(2); } @Override public Node visitInstrXD_Ref_NN_II(InstrXD_Ref_NN_IIContext ctx) { // | opcode=OPCODE_LD SEP_LPAR nn=rExpression SEP_RPAR SEP_COMMA ii=rII # instrXD_Ref_NN_II int prefix = CompilerTables.prefix.get(ctx.ii.start.getType()); - Node instr = new InstrXD(ctx.opcode, prefix, 0, 0, 2, 2).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 0, 0, 2, 2).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -257,8 +263,8 @@ public Node visitInstrXD_Ref_NN_II(InstrXD_Ref_NN_IIContext ctx) { public Node visitInstrXD_II_Ref_NN(InstrXD_II_Ref_NNContext ctx) { // | opcode=OPCODE_LD ii=rII SEP_COMMA SEP_LPAR nn=rExpression SEP_RPAR # instrXD_II_Ref_NN int prefix = CompilerTables.prefix.get(ctx.ii.start.getType()); - Node instr = new InstrXD(ctx.opcode, prefix, 0, 1, 2, 2).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 0, 1, 2, 2).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -267,8 +273,8 @@ public Node visitInstrXD_IIHL_N(InstrXD_IIHL_NContext ctx) { // | opcode=OPCODE_LD ii=rII_HL SEP_COMMA n=rExpression # instrXD_IIHL_N int prefix = CompilerTables.prefix.get(ctx.ii.start.getType()); int y = CompilerTables.registers.get(ctx.ii.start.getType()); - Node instr = new InstrXD(ctx.opcode, prefix, 0, y, 6).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.n).setSizeBytes(1)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 0, y, 6).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.n).setSizeBytes(1)); return instr; } @@ -276,9 +282,9 @@ public Node visitInstrXD_IIHL_N(InstrXD_IIHL_NContext ctx) { public Node visitInstrXD_Ref_II_N_N(InstrXD_Ref_II_N_NContext ctx) { // | opcode=OPCODE_LD d=rDisplacement SEP_COMMA n=rExpression # instrXD_Ref_II_N_N int prefix = CompilerTables.prefix.get(ctx.d.ii.start.getType()); - Node instr = new InstrXD(ctx.opcode, prefix, 0, 6, 6).setSizeBytes(4); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); - instr.addChild(CreateVisitors.expr.visit(ctx.n).setSizeBytes(1)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 0, 6, 6).setSizeBytes(4); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); + instr.addChild(exprVisitor().visit(ctx.n).setSizeBytes(1)); return instr; } @@ -288,7 +294,7 @@ public Node visitInstrXD_IIHL_R(InstrXD_IIHL_RContext ctx) { int prefix = CompilerTables.prefix.get(ctx.ii.start.getType()); int y = CompilerTables.registers.get(ctx.ii.start.getType()); int z = CompilerTables.registers.get(ctx.r.start.getType()); - return new InstrXD(ctx.opcode, prefix, 1, y, z).setSizeBytes(2); + return new InstrXD(sourceFileName, ctx.opcode, prefix, 1, y, z).setSizeBytes(2); } @Override @@ -297,7 +303,7 @@ public Node visitInstrXD_R_IIHL(InstrXD_R_IIHLContext ctx) { int prefix = CompilerTables.prefix.get(ctx.ii.start.getType()); int y = CompilerTables.registers.get(ctx.r.start.getType()); int z = CompilerTables.registers.get(ctx.ii.start.getType()); - return new InstrXD(ctx.opcode, prefix, 1, y, z).setSizeBytes(2); + return new InstrXD(sourceFileName, ctx.opcode, prefix, 1, y, z).setSizeBytes(2); } @Override @@ -305,8 +311,8 @@ public Node visitInstrXD_Ref_II_N_R(InstrXD_Ref_II_N_RContext ctx) { // | opcode=OPCODE_LD d=rDisplacement SEP_COMMA r=rRegister2 # instrXD_Ref_II_N_R int prefix = CompilerTables.prefix.get(ctx.d.ii.start.getType()); int z = CompilerTables.registers.get(ctx.r.start.getType()); - Node instr = new InstrXD(ctx.opcode, prefix, 1, 6, z).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 1, 6, z).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } @@ -315,8 +321,8 @@ public Node visitInstrXD_R_Ref_II_N(InstrXD_R_Ref_II_NContext ctx) { // | opcode=OPCODE_LD r=rRegister2 SEP_COMMA d=rDisplacement # instrXD_R_Ref_II_N int prefix = CompilerTables.prefix.get(ctx.d.ii.start.getType()); int y = CompilerTables.registers.get(ctx.r.start.getType()); - Node instr = new InstrXD(ctx.opcode, prefix, 1, y, 6).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 1, y, 6).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } @@ -334,18 +340,18 @@ public Node visitInstrXD_Ref_II_N(InstrXD_Ref_II_NContext ctx) { // | opcode=OPCODE_CP d=rDisplacement # instrXD_Ref_II_N int prefix = CompilerTables.prefix.get(ctx.d.ii.start.getType()); if (ctx.opcode.getType() == OPCODE_INC) { - Node instr = new InstrXD(ctx.opcode, prefix, 0, 6, 4).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 0, 6, 4).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } else if (ctx.opcode.getType() == OPCODE_DEC) { - Node instr = new InstrXD(ctx.opcode, prefix, 0, 6, 5).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 0, 6, 5).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } int y = CompilerTables.alu.get(ctx.opcode.getType()); - Node instr = new InstrXD(ctx.opcode, prefix, 2, y, 6).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.d.n).setSizeBytes(1)); + Node instr = new InstrXD(sourceFileName, ctx.opcode, prefix, 2, y, 6).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.d.n).setSizeBytes(1)); return instr; } @@ -365,12 +371,12 @@ public Node visitInstrXD_IIHL(InstrXD_IIHLContext ctx) { int r = CompilerTables.registers.get(ctx.ii.start.getType()); if (ctx.opcode.getType() == OPCODE_INC) { - return new InstrXD(ctx.opcode, prefix, 0, r, 4).setSizeBytes(2); + return new InstrXD(sourceFileName, ctx.opcode, prefix, 0, r, 4).setSizeBytes(2); } else if (ctx.opcode.getType() == OPCODE_DEC) { - return new InstrXD(ctx.opcode, prefix, 0, r, 5).setSizeBytes(2); + return new InstrXD(sourceFileName, ctx.opcode, prefix, 0, r, 5).setSizeBytes(2); } int y = CompilerTables.alu.get(ctx.opcode.getType()); - return new InstrXD(ctx.opcode, prefix, 2, y, r).setSizeBytes(2); + return new InstrXD(sourceFileName, ctx.opcode, prefix, 2, y, r).setSizeBytes(2); } @Override @@ -397,7 +403,7 @@ public Node visitInstrXD_II(InstrXD_IIContext ctx) { break; } - return new InstrXD(ctx.opcode, prefix, x, q, p, z).setSizeBytes(2); + return new InstrXD(sourceFileName, ctx.opcode, prefix, x, q, p, z).setSizeBytes(2); } @Override @@ -405,24 +411,24 @@ public Node visitInstrRef_NN_R(InstrRef_NN_RContext ctx) { // | opcode=OPCODE_LD SEP_LPAR nn=rExpression SEP_RPAR SEP_COMMA r=REG_HL # instrRef_NN_R // x=0, z=2, q=0, p=2 // | opcode=OPCODE_LD SEP_LPAR nn=rExpression SEP_RPAR SEP_COMMA r=REG_A # instrRef_NN_R // x=0, z=2, q=0, p=3 int p = (ctx.r.getType() == REG_HL) ? 2 : 3; - Node instr = new Instr(ctx.opcode, 0, 0, p, 2).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new Instr(sourceFileName, ctx.opcode, 0, 0, p, 2).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @Override public Node visitInstrRP_Ref_NN(InstrRP_Ref_NNContext ctx) { // | opcode=OPCODE_LD rp=REG_HL SEP_COMMA SEP_LPAR nn=rExpression SEP_RPAR # instrRP_Ref_NN // x=0, z=2, q=1, p=2 - Node instr = new Instr(ctx.opcode, 0, 1, 2, 2).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new Instr(sourceFileName, ctx.opcode, 0, 1, 2, 2).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @Override public Node visitInstrR_Ref_NN(InstrR_Ref_NNContext ctx) { // | opcode=OPCODE_LD r=REG_A SEP_COMMA SEP_LPAR nn=rExpression SEP_RPAR # instrR_Ref_NN // x=0, z=2, q=1, p=3 - Node instr = new Instr(ctx.opcode, 0, 1, 3, 2).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new Instr(sourceFileName, ctx.opcode, 0, 1, 3, 2).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -430,7 +436,7 @@ public Node visitInstrR_Ref_NN(InstrR_Ref_NNContext ctx) { public Node visitInstrA_Ref_RP(InstrA_Ref_RPContext ctx) { // | opcode=OPCODE_LD REG_A SEP_COMMA SEP_LPAR rp=(REG_BC|REG_DE) SEP_RPAR # instrA_Ref_RP // x=0, z=2, q=1, p=rp int p = CompilerTables.regPairs.get(ctx.rp.getType()); - return new Instr(ctx.opcode, 0, 1, p, 2).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, 0, 1, p, 2).setSizeBytes(1); } @Override @@ -441,13 +447,13 @@ public Node visitInstrRef_RP(InstrRef_RPContext ctx) { int x = (ctx.opcode.getType() == OPCODE_LD) ? 0 : 3; int z = (ctx.opcode.getType() == OPCODE_LD) ? 2 : 1; int q = (ctx.opcode.getType() == OPCODE_LD) ? 0 : 1; - return new Instr(ctx.opcode, x, q, p, z).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, x, q, p, z).setSizeBytes(1); } @Override public Node visitInstrRef_RP_RP(InstrRef_RP_RPContext ctx) { // | opcode=OPCODE_EX SEP_LPAR dst=REG_SP SEP_RPAR SEP_COMMA src=REG_HL # instrRef_RP_RP // x=3, z=3, y=4 - return new Instr(ctx.opcode, 3, 4, 3).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, 3, 4, 3).setSizeBytes(1); } @Override @@ -455,15 +461,15 @@ public Node visitInstrR_R(InstrR_RContext ctx) { // | opcode=OPCODE_LD dst=rRegister SEP_COMMA src=rRegister # instrR_R // x=1, y=dst, z=src int y = CompilerTables.registers.get(ctx.dst.r.getType()); int z = CompilerTables.registers.get(ctx.src.r.getType()); - return new Instr(ctx.opcode, 1, y, z).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, 1, y, z).setSizeBytes(1); } @Override public Node visitInstrR_N(InstrR_NContext ctx) { // | opcode=OPCODE_LD r=rRegister SEP_COMMA n=rExpression # instrR_N // x=0, z=6, y=r int y = CompilerTables.registers.get(ctx.r.r.getType()); - Node instr = new Instr(ctx.opcode, 0, y, 6).setSizeBytes(2); - instr.addChild(CreateVisitors.expr.visit(ctx.n).setSizeBytes(1)); + Node instr = new Instr(sourceFileName, ctx.opcode, 0, y, 6).setSizeBytes(2); + instr.addChild(exprVisitor().visit(ctx.n).setSizeBytes(1)); return instr; } @@ -471,8 +477,8 @@ public Node visitInstrR_N(InstrR_NContext ctx) { public Node visitInstrC_N(InstrC_NContext ctx) { // | opcode=OPCODE_JR c=(COND_NZ|COND_Z|COND_NC|COND_C) SEP_COMMA n=rExpression # instrC_N // x=0, z=0, y=4..7 int y = CompilerTables.conditions.get(ctx.c.getType()) + 4; - Node instr = new Instr(ctx.opcode, 0, y, 0).setSizeBytes(2); - instr.addChild(CreateVisitors.expr.visit(ctx.n).setSizeBytes(1)); + Node instr = new Instr(sourceFileName, ctx.opcode, 0, y, 0).setSizeBytes(2); + instr.addChild(exprVisitor().visit(ctx.n).setSizeBytes(1)); return instr; } @@ -480,7 +486,7 @@ public Node visitInstrC_N(InstrC_NContext ctx) { public Node visitInstrC(InstrCContext ctx) { // | opcode=OPCODE_RET c=cCondition # instrC // x=3, z=0, y=cc int y = CompilerTables.conditions.get(ctx.c.start.getType()); - return new Instr(ctx.opcode, 3, y, 0).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, 3, y, 0).setSizeBytes(1); } @Override @@ -489,8 +495,8 @@ public Node visitInstrC_NN(InstrC_NNContext ctx) { // | opcode=OPCODE_CALL c=cCondition SEP_COMMA nn=rExpression # instrC_NN // x=3, z=4, y=cc int y = CompilerTables.conditions.get(ctx.c.start.getType()); int z = (ctx.opcode.getType() == OPCODE_JP) ? 2 : 4; - Node instr = new Instr(ctx.opcode, 3, y, z).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new Instr(sourceFileName, ctx.opcode, 3, y, z).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -498,8 +504,8 @@ public Node visitInstrC_NN(InstrC_NNContext ctx) { public Node visitInstrRP_NN(InstrRP_NNContext ctx) { // | opcode=OPCODE_LD rp=rRegPair SEP_COMMA nn=rExpression # instrRP_NN // x=0, z=1, q=0, p=rp int p = CompilerTables.regPairs.get(ctx.rp.start.getType()); - Node instr = new Instr(ctx.opcode, 0, 0, p, 1).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new Instr(sourceFileName, ctx.opcode, 0, 0, p, 1).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -511,7 +517,7 @@ public Node visitInstrRP_RP(InstrRP_RPContext ctx) { int x = (ctx.opcode.getType() == OPCODE_EX && ctx.dst.getType() == REG_AF) ? 0 : 3; int z = (ctx.opcode.getType() == OPCODE_LD) ? 1 : ((ctx.dst.getType() == REG_AF) ? 0 : 3); int p = (ctx.opcode.getType() == OPCODE_LD) ? 3 : ((ctx.dst.getType() == REG_AF) ? 0 : 2); - return new Instr(ctx.opcode, x, 1, p, z).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, x, 1, p, z).setSizeBytes(1); } @Override @@ -520,8 +526,8 @@ public Node visitInstrNN(InstrNNContext ctx) { // | opcode=OPCODE_CALL nn=rExpression # instrNN // x=3, z=5, y=1 int z = (ctx.opcode.getType() == OPCODE_JP) ? 3 : 5; int y = (ctx.opcode.getType() == OPCODE_JP) ? 0 : 1; - Node instr = new Instr(ctx.opcode, 3, y, z).setSizeBytes(3); - instr.addChild(CreateVisitors.expr.visit(ctx.nn).setSizeBytes(2)); + Node instr = new Instr(sourceFileName, ctx.opcode, 3, y, z).setSizeBytes(3); + instr.addChild(exprVisitor().visit(ctx.nn).setSizeBytes(2)); return instr; } @@ -550,8 +556,8 @@ public Node visitInstrN(InstrNContext ctx) { int z = (djnzOrJr) ? 0 : ((opcode == OPCODE_OUT || opcode == OPCODE_IN) ? 3 : (rst ? 7 : 6)); int y = djnzOrOut ? 2 : ((opcode == OPCODE_JR || opcode == OPCODE_IN) ? 3 : (rst ? 0 : CompilerTables.alu.get(opcode))); - Node instr = new Instr(ctx.opcode, x, y, z).setSizeBytes(rst ? 1 : 2); - instr.addChild(CreateVisitors.expr.visit(ctx.n).setSizeBytes(1)); + Node instr = new Instr(sourceFileName, ctx.opcode, x, y, z).setSizeBytes(rst ? 1 : 2); + instr.addChild(exprVisitor().visit(ctx.n).setSizeBytes(1)); return instr; } @@ -563,7 +569,7 @@ public Node visitInstrRP(InstrRPContext ctx) { int q = (ctx.opcode.getType() == OPCODE_INC) ? 0 : 1; int p = CompilerTables.regPairs.get(ctx.rp.start.getType()); int z = (ctx.opcode.getType() == OPCODE_ADD) ? 1 : 3; - return new Instr(ctx.opcode, 0, q, p, z).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, 0, q, p, z).setSizeBytes(1); } @Override @@ -572,7 +578,7 @@ public Node visitInstrRP2(InstrRP2Context ctx) { // | opcode=OPCODE_PUSH rp2=rRegPair2 # instrRP2 // x=3, z=5, q=0, p=rp2 int p = CompilerTables.regPairs2.get(ctx.rp2.start.getType()); int z = (ctx.opcode.getType() == OPCODE_POP) ? 1 : 5; - return new Instr(ctx.opcode, 3, 0, p, z).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, 3, 0, p, z).setSizeBytes(1); } @Override @@ -594,7 +600,7 @@ public Node visitInstrR(InstrRContext ctx) { int x = incDec ? 0 : 2; int y = incDec ? reg : CompilerTables.alu.get(ctx.opcode.getType()); int z = (opcode == OPCODE_INC) ? 4 : ((opcode == OPCODE_DEC) ? 5 : reg); - return new Instr(ctx.opcode, x, y, z).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, x, y, z).setSizeBytes(1); } @Override @@ -631,6 +637,10 @@ public Node visitInstr(InstrContext ctx) { xyz.put(OPCODE_EI, new int[]{3, 7, 3}); int[] xyzValues = xyz.get(ctx.opcode.getType()); - return new Instr(ctx.opcode, xyzValues[0], xyzValues[1], xyzValues[2]).setSizeBytes(1); + return new Instr(sourceFileName, ctx.opcode, xyzValues[0], xyzValues[1], xyzValues[2]).setSizeBytes(1); } + + private CreateExprVisitor exprVisitor() { + return CreateVisitors.expr(sourceFileName); + }; } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateLineVisitor.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateLineVisitor.java index 3c0702c28..9018f4c9f 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateLineVisitor.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateLineVisitor.java @@ -24,13 +24,20 @@ import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.ast.pseudo.PseudoLabel; +import java.util.Objects; + public class CreateLineVisitor extends AsZ80ParserBaseVisitor { + private final String sourceFileName; + + public CreateLineVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } @Override public Node visitRLine(RLineContext ctx) { Node label = null; if (ctx.label != null) { - label = new PseudoLabel(ctx.label); + label = new PseudoLabel(sourceFileName, ctx.label); } Node statement = null; if (ctx.statement != null) { @@ -48,12 +55,24 @@ public Node visitRLine(RLineContext ctx) { @Override public Node visitRStatement(RStatementContext ctx) { if (ctx.instr != null) { - return CreateVisitors.instr.visit(ctx.instr); + return instrVisitor().visit(ctx.instr); } else if (ctx.data != null) { - return CreateVisitors.data.visit(ctx.data); + return dataVisitor().visit(ctx.data); } else if (ctx.pseudo != null) { - return CreateVisitors.pseudo.visit(ctx.pseudo); + return pseudoVisitor().visit(ctx.pseudo); } throw new IllegalStateException("No statement defined!"); } + + private CreateInstrVisitor instrVisitor() { + return CreateVisitors.instr(sourceFileName); + } + + private CreateDataVisitor dataVisitor() { + return CreateVisitors.data(sourceFileName); + } + + private CreatePseudoVisitor pseudoVisitor() { + return CreateVisitors.pseudo(sourceFileName); + } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateProgramVisitor.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateProgramVisitor.java index d2e84e6c1..ddde64fac 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateProgramVisitor.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateProgramVisitor.java @@ -37,10 +37,14 @@ public CreateProgramVisitor(Program program) { @Override public Program visitRLine(RLineContext ctx) { - Node statement = CreateVisitors.line.visitRLine(ctx); + Node statement = lineVisitor().visitRLine(ctx); if (statement != null) { program.addChild(statement); } return program; } + + private CreateLineVisitor lineVisitor() { + return CreateVisitors.line(program.position.fileName); + } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreatePseudoVisitor.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreatePseudoVisitor.java index da49206b5..86115c1ee 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreatePseudoVisitor.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreatePseudoVisitor.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.AsZ80Parser.*; import net.emustudio.plugins.compiler.asZ80.AsZ80ParserBaseVisitor; import net.emustudio.plugins.compiler.asZ80.ast.Node; @@ -26,27 +27,34 @@ import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.TerminalNode; +import java.util.Objects; + public class CreatePseudoVisitor extends AsZ80ParserBaseVisitor { + private final String sourceFileName; + + public CreatePseudoVisitor(String sourceFileName) { + this.sourceFileName = Objects.requireNonNull(sourceFileName); + } @Override public Node visitPseudoOrg(PseudoOrgContext ctx) { Token start = ctx.getStart(); - Node pseudo = new PseudoOrg(start.getLine(), start.getCharPositionInLine()).setSizeBytes(2); - pseudo.addChild(CreateVisitors.expr.visit(ctx.expr).setSizeBytes(2)); + Node pseudo = new PseudoOrg(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)).setSizeBytes(2); + pseudo.addChild(exprVisitor().visit(ctx.expr).setSizeBytes(2)); return pseudo; } @Override public Node visitPseudoEqu(PseudoEquContext ctx) { - PseudoEqu pseudo = new PseudoEqu(ctx.id); - pseudo.addChild(CreateVisitors.expr.visit(ctx.expr)); + PseudoEqu pseudo = new PseudoEqu(sourceFileName, ctx.id); + pseudo.addChild(exprVisitor().visit(ctx.expr)); return pseudo; } @Override public Node visitPseudoVar(PseudoVarContext ctx) { - PseudoVar pseudo = new PseudoVar(ctx.id); - pseudo.addChild(CreateVisitors.expr.visit(ctx.expr)); + PseudoVar pseudo = new PseudoVar(sourceFileName, ctx.id); + pseudo.addChild(exprVisitor().visit(ctx.expr)); return pseudo; } @@ -54,13 +62,13 @@ public Node visitPseudoVar(PseudoVarContext ctx) { public Node visitPseudoIf(PseudoIfContext ctx) { Token start = ctx.getStart(); - PseudoIf pseudo = new PseudoIf(start.getLine(), start.getCharPositionInLine()); - Node expr = CreateVisitors.expr.visit(ctx.expr); - PseudoIfExpression ifExpr = new PseudoIfExpression(expr.line, expr.column); + PseudoIf pseudo = new PseudoIf(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); + Node expr = exprVisitor().visit(ctx.expr); + PseudoIfExpression ifExpr = new PseudoIfExpression(expr.position); ifExpr.addChild(expr); pseudo.addChild(ifExpr); for (RLineContext line : ctx.rLine()) { - Node lineNode = CreateVisitors.line.visitRLine(line); + Node lineNode = lineVisitor().visitRLine(line); if (lineNode != null) { pseudo.addChild(lineNode); } @@ -70,18 +78,18 @@ public Node visitPseudoIf(PseudoIfContext ctx) { @Override public Node visitPseudoMacroDef(PseudoMacroDefContext ctx) { - PseudoMacroDef pseudo = new PseudoMacroDef(ctx.id); + PseudoMacroDef pseudo = new PseudoMacroDef(sourceFileName, ctx.id); if (ctx.params != null) { for (TerminalNode next : ctx.params.ID_IDENTIFIER()) { Token symbol = next.getSymbol(); - PseudoMacroParameter parameter = new PseudoMacroParameter(symbol.getLine(), symbol.getCharPositionInLine()); - parameter.addChild(new ExprId(next.getSymbol())); + PseudoMacroParameter parameter = new PseudoMacroParameter(new SourceCodePosition(symbol.getLine(), symbol.getCharPositionInLine(), sourceFileName)); + parameter.addChild(new ExprId(sourceFileName, next.getSymbol())); pseudo.addChild(parameter); } } for (RLineContext line : ctx.rLine()) { - Node lineNode = CreateVisitors.line.visitRLine(line); + Node lineNode = lineVisitor().visitRLine(line); if (lineNode != null) { pseudo.addChild(lineNode); } @@ -91,13 +99,13 @@ public Node visitPseudoMacroDef(PseudoMacroDefContext ctx) { @Override public Node visitPseudoMacroCall(PseudoMacroCallContext ctx) { - PseudoMacroCall pseudo = new PseudoMacroCall(ctx.id); + PseudoMacroCall pseudo = new PseudoMacroCall(sourceFileName, ctx.id); if (ctx.args != null) { for (RExpressionContext next : ctx.args.rExpression()) { Token start = next.getStart(); - PseudoMacroArgument argument = new PseudoMacroArgument(start.getLine(), start.getCharPositionInLine()); - pseudo.addChild(argument.addChild(CreateVisitors.expr.visit(next))); + PseudoMacroArgument argument = new PseudoMacroArgument(new SourceCodePosition(start.getLine(), start.getCharPositionInLine(), sourceFileName)); + pseudo.addChild(argument.addChild(exprVisitor().visit(next))); } } return pseudo; @@ -105,6 +113,14 @@ public Node visitPseudoMacroCall(PseudoMacroCallContext ctx) { @Override public Node visitPseudoInclude(PseudoIncludeContext ctx) { - return new PseudoInclude(ctx.filename); + return new PseudoInclude(sourceFileName, ctx.filename); + } + + private CreateExprVisitor exprVisitor() { + return CreateVisitors.expr(sourceFileName); + } + + private CreateLineVisitor lineVisitor() { + return CreateVisitors.line(sourceFileName); } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateVisitors.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateVisitors.java index 5426cbe6e..29f85ec20 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateVisitors.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/CreateVisitors.java @@ -18,12 +18,38 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + public class CreateVisitors { + private final static Map PSEUDO_CACHE = new ConcurrentHashMap<>(); + private final static Map EXPR_CACHE = new ConcurrentHashMap<>(); + private final static Map INSTR_CACHE = new ConcurrentHashMap<>(); + private final static Map DATA_CACHE = new ConcurrentHashMap<>(); + private final static Map LINE_CACHE = new ConcurrentHashMap<>(); + + static CreatePseudoVisitor pseudo(String sourceFileName) { + PSEUDO_CACHE.putIfAbsent(sourceFileName, new CreatePseudoVisitor(sourceFileName)); + return PSEUDO_CACHE.get(sourceFileName); + } + + static CreateExprVisitor expr(String sourceFileName) { + EXPR_CACHE.putIfAbsent(sourceFileName, new CreateExprVisitor(sourceFileName)); + return EXPR_CACHE.get(sourceFileName); + } + + static CreateInstrVisitor instr(String sourceFileName) { + INSTR_CACHE.putIfAbsent(sourceFileName, new CreateInstrVisitor(sourceFileName)); + return INSTR_CACHE.get(sourceFileName); + } - static CreatePseudoVisitor pseudo = new CreatePseudoVisitor(); - static CreateExprVisitor expr = new CreateExprVisitor(); - static CreateInstrVisitor instr = new CreateInstrVisitor(); - static CreateDataVisitor data = new CreateDataVisitor(); - static CreateLineVisitor line = new CreateLineVisitor(); + static CreateDataVisitor data(String sourceFileName) { + DATA_CACHE.putIfAbsent(sourceFileName, new CreateDataVisitor(sourceFileName)); + return DATA_CACHE.get(sourceFileName); + } + static CreateLineVisitor line(String sourceFileName) { + LINE_CACHE.putIfAbsent(sourceFileName, new CreateLineVisitor(sourceFileName)); + return LINE_CACHE.get(sourceFileName); + } } diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/EvaluateExprVisitor.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/EvaluateExprVisitor.java index 473492d3e..5ebcfad77 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/EvaluateExprVisitor.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/EvaluateExprVisitor.java @@ -333,13 +333,13 @@ public void visit(ExprString node) { if (strLen > 1) { result |= (node.string.charAt(1) << 8); } - Node evaluated = new Evaluated(node.line, node.column, result).setSizeBytes(2); + Node evaluated = new Evaluated(node.position, result).setSizeBytes(2); parent.ifPresent(p -> p.addChild(evaluated)); currentAddress += sizeBytes; } else { int maxValue = node.getMaxValue().map(v -> Math.min(v, 0xFF)).orElse(0xFF); for (int i = 0; i < strLen; i++) { - Node evaluated = new Evaluated(node.line, node.column, node.string.charAt(i)).setMaxValue(maxValue); + Node evaluated = new Evaluated(node.position, node.string.charAt(i)).setMaxValue(maxValue); parent.ifPresent(p -> p.addChild(evaluated)); } if (sizeBytes != 0) { diff --git a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandIncludesVisitor.java b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandIncludesVisitor.java index d0e298896..81ef1e0d5 100644 --- a/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandIncludesVisitor.java +++ b/plugins/compiler/as-z80/src/main/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandIncludesVisitor.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.AsZ80Lexer; import net.emustudio.plugins.compiler.asZ80.AsZ80Parser; import net.emustudio.plugins.compiler.asZ80.ast.Program; @@ -51,7 +52,7 @@ public ExpandIncludesVisitor(Set includedFiles) { @Override public void visit(Program node) { - this.inputFileName = node.getFileName(); + this.inputFileName = Optional.ofNullable(node.position.fileName); super.visit(node); } @@ -68,8 +69,7 @@ public void visit(PseudoInclude node) { AsZ80Parser parser = new AsZ80Parser(stream); stream.fill(); ParseTree tree = parser.rStart(); - Program program = new Program(node.line, node.column, env); - program.setFileName(absoluteFileName); + Program program = new Program(new SourceCodePosition(node.position.line, node.position.column, absoluteFileName), env); new CreateProgramVisitor(program).visit(tree); diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/Utils.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/Utils.java index 37e2ec82c..60c434288 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/Utils.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/Utils.java @@ -100,14 +100,14 @@ public static ParseTree parse(String program) { CommonTokenStream stream = new CommonTokenStream(lexer); AsZ80Parser parser = new AsZ80Parser(stream); parser.removeErrorListeners(); - parser.addErrorListener(new ParserErrorListener()); + parser.addErrorListener(new ParserErrorListener("")); stream.fill(); return parser.rStart(); } public static Program parseProgram(String programString) { ParseTree tree = parse(programString); - Program program = new Program(); + Program program = new Program(""); CreateProgramVisitor visitor = new CreateProgramVisitor(program); visitor.visit(tree); return program; diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/e2e/AbstractCompilerTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/e2e/AbstractCompilerTest.java index a5fcef461..4ada6e13d 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/e2e/AbstractCompilerTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/e2e/AbstractCompilerTest.java @@ -36,6 +36,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardOpenOption; +import java.util.Optional; import static org.easymock.EasyMock.*; import static org.junit.Assert.assertEquals; @@ -45,6 +46,7 @@ public abstract class AbstractCompilerTest { public TemporaryFolder folder = new TemporaryFolder(); protected AssemblerZ80 compiler; protected MemoryStub memoryStub; + private int errorCount; @SuppressWarnings("unchecked") @Before @@ -59,6 +61,7 @@ public void setUp() throws Exception { expect(applicationApi.getContextPool()).andReturn(contextPool); replay(applicationApi); + errorCount = 0; compiler = new AssemblerZ80(0L, applicationApi, PluginSettings.UNAVAILABLE); compiler.addCompilerListener(new CompilerListener() { @Override @@ -70,6 +73,9 @@ public void onMessage(CompilerMessage message) { if (message.getMessageType() != CompilerMessage.MessageType.TYPE_INFO) { System.out.println(message); } + if (message.getMessageType() == CompilerMessage.MessageType.TYPE_ERROR) { + errorCount++; + } } @Override @@ -85,8 +91,9 @@ protected void compile(String content) { Files.write(sourceFile.toPath(), content.getBytes(), StandardOpenOption.WRITE); File outputFile = folder.newFile(); - if (!compiler.compile(sourceFile.getAbsolutePath(), outputFile.getAbsolutePath())) { - throw new RuntimeException("Compilation failed"); + compiler.compile(sourceFile.toPath(), Optional.of(outputFile.toPath())); + if (errorCount > 0) { + throw new RuntimeException("Compilation failed with " + errorCount + " errors"); } } catch (IOException e) { throw new RuntimeException(e); diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseDataTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseDataTest.java index b7be0488e..8f607ceb9 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseDataTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseDataTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.parser; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Program; import net.emustudio.plugins.compiler.asZ80.ast.data.DataDB; import net.emustudio.plugins.compiler.asZ80.ast.data.DataDS; @@ -34,13 +35,14 @@ import static net.emustudio.plugins.compiler.asZ80.Utils.parseProgram; public class ParseDataTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); @Test public void testDBstring1() { Program program = parseProgram("db 'hello'"); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprString(0, 0, "hello"))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprString(POSITION, "hello"))), program ); } @@ -48,9 +50,9 @@ public void testDBstring1() { @Test public void testDBstring2() { Program program = parseProgram("db \"hello\""); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprString(0, 0, "hello"))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprString(POSITION, "hello"))), program ); } @@ -59,9 +61,9 @@ public void testDBstring2() { public void testDBinstruction() { Program program = parseProgram("db ret"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new Instr(0, 0, OPCODE_RET, 3, 1, 1))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new Instr(POSITION, OPCODE_RET, 3, 1, 1))), program ); } @@ -69,12 +71,12 @@ public void testDBinstruction() { @Test public void testMultipleDB() { Program program = parseProgram("db -1,2,3"); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))), program ); } @@ -82,10 +84,10 @@ public void testMultipleDB() { @Test public void testDBwithNegativeValue() { Program program = parseProgram("db -1"); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1)))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1)))), program ); } @@ -93,12 +95,12 @@ public void testDBwithNegativeValue() { @Test public void testMultipleDBstringNumberString() { Program program = parseProgram("db -1,'hello',3"); - assertTrees(new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprString(0, 0, "hello")) - .addChild(new ExprNumber(0, 0, 3))), + assertTrees(new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprString(POSITION, "hello")) + .addChild(new ExprNumber(POSITION, 3))), program ); } @@ -106,12 +108,12 @@ public void testMultipleDBstringNumberString() { @Test public void testMultipleDW() { Program program = parseProgram("dw -1,2,3"); - assertTrees(new Program() - .addChild(new DataDW(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))), + assertTrees(new Program("") + .addChild(new DataDW(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))), program ); } @@ -119,10 +121,10 @@ public void testMultipleDW() { @Test public void testDWwithNegativeValue() { Program program = parseProgram("dw -1"); - assertTrees(new Program() - .addChild(new DataDW(0, 0) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 1)))), + assertTrees(new Program("") + .addChild(new DataDW(POSITION) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 1)))), program ); } @@ -130,9 +132,9 @@ public void testDWwithNegativeValue() { @Test public void testDS() { Program program = parseProgram("ds 0x55"); - assertTrees(new Program() - .addChild(new DataDS(0, 0) - .addChild(new ExprNumber(0, 0, 0x55))), + assertTrees(new Program("") + .addChild(new DataDS(POSITION) + .addChild(new ExprNumber(POSITION, 0x55))), program ); } diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseExprTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseExprTest.java index 4c41ef52a..4a6a2240b 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseExprTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseExprTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.parser; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Program; import net.emustudio.plugins.compiler.asZ80.ast.data.DataDB; import net.emustudio.plugins.compiler.asZ80.ast.expr.ExprInfix; @@ -30,18 +31,19 @@ import static net.emustudio.plugins.compiler.asZ80.Utils.parseProgram; public class ParseExprTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); @Test public void testPrioritiesAddMul() { Program program = parseProgram("db 2+3*4"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprNumber(0, 0, 3)) - .addChild(new ExprNumber(0, 0, 4))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprNumber(POSITION, 3)) + .addChild(new ExprNumber(POSITION, 4))))), program ); } @@ -50,13 +52,13 @@ public void testPrioritiesAddMul() { public void testPrioritiesMulAdd() { Program program = parseProgram("db 2*3+4"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new ExprNumber(0, 0, 4)))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new ExprNumber(POSITION, 4)))), program ); } @@ -65,15 +67,15 @@ public void testPrioritiesMulAdd() { public void testAssociativityPlusMinus() { Program program = parseProgram("db 2-3+4-9"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new ExprNumber(0, 0, 4))) - .addChild(new ExprNumber(0, 0, 9)))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new ExprNumber(POSITION, 4))) + .addChild(new ExprNumber(POSITION, 9)))), program ); } @@ -82,15 +84,15 @@ public void testAssociativityPlusMinus() { public void testAssociativitMulDiv() { Program program = parseProgram("db 2/3*4/9"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_DIVIDE) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprInfix(0, 0, OP_DIVIDE) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new ExprNumber(0, 0, 4))) - .addChild(new ExprNumber(0, 0, 9)))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_DIVIDE) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprInfix(POSITION, OP_DIVIDE) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new ExprNumber(POSITION, 4))) + .addChild(new ExprNumber(POSITION, 9)))), program ); } @@ -99,19 +101,19 @@ public void testAssociativitMulDiv() { public void testPrecedencePlusMinusMulDivMod() { Program program = parseProgram("db 2+3*4-9/2 mod 3"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprNumber(0, 0, 3)) - .addChild(new ExprNumber(0, 0, 4)))) - .addChild(new ExprInfix(0, 0, OP_MOD) - .addChild(new ExprInfix(0, 0, OP_DIVIDE) - .addChild(new ExprNumber(0, 0, 9)) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprNumber(0, 0, 3))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprNumber(POSITION, 3)) + .addChild(new ExprNumber(POSITION, 4)))) + .addChild(new ExprInfix(POSITION, OP_MOD) + .addChild(new ExprInfix(POSITION, OP_DIVIDE) + .addChild(new ExprNumber(POSITION, 9)) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprNumber(POSITION, 3))))), program ); } @@ -120,21 +122,21 @@ public void testPrecedencePlusMinusMulDivMod() { public void testAssociativityEqual() { Program program = parseProgram("db 1 + 2 + 2 = 5 = 5 = 6 - 1"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprInfix(0, 0, OP_ADD) // 1 + 2 + 2 associates to left - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 1)) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprNumber(0, 0, 5)) // ... = 5 associates to right - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprNumber(0, 0, 5)) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) // minus has > precedence than = - .addChild(new ExprNumber(0, 0, 6)) - .addChild(new ExprNumber(0, 0, 1))))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprInfix(POSITION, OP_ADD) // 1 + 2 + 2 associates to left + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 1)) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprNumber(POSITION, 5)) // ... = 5 associates to right + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprNumber(POSITION, 5)) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) // minus has > precedence than = + .addChild(new ExprNumber(POSITION, 6)) + .addChild(new ExprNumber(POSITION, 1))))))), program ); } @@ -143,27 +145,27 @@ public void testAssociativityEqual() { public void testAndMulXorDivNotPlusMinus() { Program program = parseProgram("db not 1 & 2 | 2 ^ 5 = - 5 * 6 shl 4 - 1 shr 2"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_OR) - .addChild(new ExprInfix(0, 0, OP_AND) - .addChild(new ExprUnary(0, 0, OP_NOT) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprInfix(0, 0, OP_XOR) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprNumber(0, 0, 5)) - .addChild(new ExprInfix(0, 0, OP_SHR) - .addChild(new ExprInfix(0, 0, OP_SHL) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 5))) - .addChild(new ExprNumber(0, 0, 6))) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 4)) - .addChild(new ExprNumber(0, 0, 1)))) - .addChild(new ExprNumber(0, 0, 2))))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_OR) + .addChild(new ExprInfix(POSITION, OP_AND) + .addChild(new ExprUnary(POSITION, OP_NOT) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprInfix(POSITION, OP_XOR) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprNumber(POSITION, 5)) + .addChild(new ExprInfix(POSITION, OP_SHR) + .addChild(new ExprInfix(POSITION, OP_SHL) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 5))) + .addChild(new ExprNumber(POSITION, 6))) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 4)) + .addChild(new ExprNumber(POSITION, 1)))) + .addChild(new ExprNumber(POSITION, 2))))))), program ); } @@ -173,27 +175,27 @@ public void testAndMulXorDivNotPlusMinusWithOperators() { //Program program = parseProgram("db ((~1) & 2) | (2 ^ (5 = ((((-5) * 6) << (4 - 1)) >> 2)))"); Program program = parseProgram("db ~1 & 2 | 2 ^ 5 = -5 * 6 << 4 - 1 >> 2"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_OR) - .addChild(new ExprInfix(0, 0, OP_AND) - .addChild(new ExprUnary(0, 0, OP_NOT_2) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprInfix(0, 0, OP_XOR) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprNumber(0, 0, 5)) - .addChild(new ExprInfix(0, 0, OP_SHR_2) - .addChild(new ExprInfix(0, 0, OP_SHL_2) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprUnary(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 5))) - .addChild(new ExprNumber(0, 0, 6))) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 4)) - .addChild(new ExprNumber(0, 0, 1)))) - .addChild(new ExprNumber(0, 0, 2))))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_OR) + .addChild(new ExprInfix(POSITION, OP_AND) + .addChild(new ExprUnary(POSITION, OP_NOT_2) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprInfix(POSITION, OP_XOR) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprNumber(POSITION, 5)) + .addChild(new ExprInfix(POSITION, OP_SHR_2) + .addChild(new ExprInfix(POSITION, OP_SHL_2) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprUnary(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 5))) + .addChild(new ExprNumber(POSITION, 6))) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 4)) + .addChild(new ExprNumber(POSITION, 1)))) + .addChild(new ExprNumber(POSITION, 2))))))), program ); } @@ -202,15 +204,15 @@ public void testAndMulXorDivNotPlusMinusWithOperators() { public void testParenthesis() { Program program = parseProgram("db (2 + 3) * (4 - 2)"); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_MULTIPLY) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 2)) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new ExprInfix(0, 0, OP_SUBTRACT) - .addChild(new ExprNumber(0, 0, 4)) - .addChild(new ExprNumber(0, 0, 2))))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_MULTIPLY) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 2)) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new ExprInfix(POSITION, OP_SUBTRACT) + .addChild(new ExprNumber(POSITION, 4)) + .addChild(new ExprNumber(POSITION, 2))))), program ); } diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseInstrTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseInstrTest.java index 0bbdd3d67..e51230712 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseInstrTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParseInstrTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.parser; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.CompilerTables; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.ast.Program; @@ -35,6 +36,8 @@ import static net.emustudio.plugins.compiler.asZ80.Utils.*; public class ParseInstrTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Test public void testInstrNoArgs() { @@ -196,10 +199,10 @@ public void testInstrExpr() { @Test public void testCallLabelWithConditionPrefix() { Program program = parseProgram("peter: call peter"); - assertTrees(new Program() - .addChild(new PseudoLabel(0, 0, "peter") - .addChild(new Instr(0, 0, OPCODE_CALL, 3, 1, 5) - .addChild(new ExprId(0, 0, "peter")))), + assertTrees(new Program("") + .addChild(new PseudoLabel(POSITION, "peter") + .addChild(new Instr(POSITION, OPCODE_CALL, 3, 1, 5) + .addChild(new ExprId(POSITION, "peter")))), program ); } @@ -309,7 +312,7 @@ public void testInstrXD() { private void assertInstr(String instr, int instrType, int x, int y, int z) { forStringCaseVariations(instr, variation -> { Program program = parseProgram(variation); - assertTrees(new Program().addChild(new Instr(0, 0, instrType, x, y, z)), program); + assertTrees(new Program("").addChild(new Instr(POSITION, instrType, x, y, z)), program); }); } @@ -320,36 +323,36 @@ private void assertInstr(String instr, int instrType, int x, int p, int q, int z private void assertInstrED(String instr, int instrType, int y, int z) { forStringCaseVariations(instr, variation -> { Program program = parseProgram(variation); - assertTrees(new Program().addChild(new InstrED(0, 0, instrType, y, z)), program); + assertTrees(new Program("").addChild(new InstrED(POSITION, instrType, y, z)), program); }); } private void assertInstrEDExpr(String instrPrefix, String instrPostfix, int y) { - Node expr = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node expr = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); forStringCaseVariations(instrPrefix, prefixVariation -> forStringCaseVariations(instrPostfix, postfixVariation -> { Program program = parseProgram(prefixVariation + " $ + 5" + postfixVariation); - assertTrees(new Program().addChild(new InstrED(0, 0, OPCODE_LD, y, 3).addChild(expr)), program); + assertTrees(new Program("").addChild(new InstrED(POSITION, OPCODE_LD, y, 3).addChild(expr)), program); })); } private void assertInstrCB(String instr, int instrType, int y, int z) { forStringCaseVariations(instr, variation -> { Program program = parseProgram(variation); - assertTrees(new Program().addChild(new InstrCB(0, 0, instrType, y, z)), program); + assertTrees(new Program("").addChild(new InstrCB(POSITION, instrType, y, z)), program); }); } private void assertInstrExpr(String instrPrefix, String instrPostfix, int instrType, int x, int y, int z) { - Node expr = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node expr = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); forStringCaseVariations(instrPrefix, prefixVariation -> forStringCaseVariations(instrPostfix, postfixVariation -> { Program program = parseProgram(prefixVariation + " $ + 5" + postfixVariation); - assertTrees(new Program().addChild(new Instr(0, 0, instrType, x, y, z).addChild(expr)), program); + assertTrees(new Program("").addChild(new Instr(POSITION, instrType, x, y, z).addChild(expr)), program); })); } @@ -362,36 +365,36 @@ private void assertInstrExpr(String instr, int instrType, int x, int p, int q, i } private void assertInstrCBExprBit(String instr, int instrType, int y, int z) { - Node expr = new ExprNumber(0, 0, y); + Node expr = new ExprNumber(POSITION, y); forStringCaseVariations(instr, variation -> { Program program = parseProgram(variation); - assertTrees(new Program().addChild(new InstrCB(0, 0, instrType, 0, z).addChild(expr)), program); + assertTrees(new Program("").addChild(new InstrCB(POSITION, instrType, 0, z).addChild(expr)), program); }); } private void assertInstrXDCBExpr(String instrPrefix, String instrPostfix, int instrType, int prefix, int y, int z) { - Node expr = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node expr = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); forStringCaseVariations(instrPrefix, instrPrefixVariation -> forStringCaseVariations(instrPostfix, instrPostfixVariation -> { Program program = parseProgram(instrPrefixVariation + " $ + 5" + instrPostfixVariation); - assertTrees(new Program().addChild(new InstrXDCB(0, 0, instrType, prefix, y, z).addChild(expr)), program); + assertTrees(new Program("").addChild(new InstrXDCB(POSITION, instrType, prefix, y, z).addChild(expr)), program); })); } private void assertInstrXDCBExprBit(String instrPrefix, String instrPostfix, int instrType, int prefix, int y, int z) { - Node expr = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node expr = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); - Node yExpr = new ExprNumber(0, 0, y); + Node yExpr = new ExprNumber(POSITION, y); forStringCaseVariations(instrPrefix, instrPrefixVariation -> forStringCaseVariations(instrPostfix, instrPostfixVariation -> { Program program = parseProgram(instrPrefixVariation + " $ + 5" + instrPostfixVariation); - assertTrees(new Program() - .addChild(new InstrXDCB(0, 0, instrType, prefix, 0, z) + assertTrees(new Program("") + .addChild(new InstrXDCB(POSITION, instrType, prefix, 0, z) .addChild(yExpr) .addChild(expr)), program); })); @@ -400,7 +403,7 @@ private void assertInstrXDCBExprBit(String instrPrefix, String instrPostfix, int private void assertInstrXD(String instr, int instrType, int prefix, int x, int y, int z) { forStringCaseVariations(instr, variation -> { Program program = parseProgram(variation); - assertTrees(new Program().addChild(new InstrXD(0, 0, instrType, prefix, x, y, z)), program); + assertTrees(new Program("").addChild(new InstrXD(POSITION, instrType, prefix, x, y, z)), program); }); } @@ -409,29 +412,29 @@ private void assertInstrXD(String instr, int instrType, int prefix, int x, int p } private void assertInstrXDExpr(String instrPrefix, String instrPostfix, int instrType, int prefix, int x, int y, int z) { - Node expr = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node expr = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); forStringCaseVariations(instrPrefix, prefixVariation -> { forStringCaseVariations(instrPostfix, postfixVariation -> { Program program = parseProgram(prefixVariation + " $ + 5" + postfixVariation); - assertTrees(new Program().addChild(new InstrXD(0, 0, instrType, prefix, x, y, z).addChild(expr)), program); + assertTrees(new Program("").addChild(new InstrXD(POSITION, instrType, prefix, x, y, z).addChild(expr)), program); }); }); } private void assertInstrXDExprExpr(String instrPrefix, int prefix) { - Node disp = new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 5)); + Node disp = new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 5)); - Node expr = new ExprNumber(0, 0, 5); + Node expr = new ExprNumber(POSITION, 5); forStringCaseVariations(instrPrefix, prefixVariation -> { Program program = parseProgram(prefixVariation + " $ + 5), 5"); - assertTrees(new Program() - .addChild(new InstrXD(0, 0, OPCODE_LD, prefix, 0, 6, 6) + assertTrees(new Program("") + .addChild(new InstrXD(POSITION, OPCODE_LD, prefix, 0, 6, 6) .addChild(disp) .addChild(expr)), program); }); diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParsePseudoTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParsePseudoTest.java index 5ce1a2fae..865a451ab 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParsePseudoTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/parser/ParsePseudoTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.parser; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.ast.Program; import net.emustudio.plugins.compiler.asZ80.ast.expr.ExprId; @@ -35,13 +36,15 @@ import static net.emustudio.plugins.compiler.asZ80.Utils.parseProgram; public class ParsePseudoTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Test public void testConstant() { Program program = parseProgram("here equ 0x55"); - assertTrees(new Program() - .addChild(new PseudoEqu(0, 0, "here") - .addChild(new ExprNumber(0, 0, 0x55))), + assertTrees(new Program("") + .addChild(new PseudoEqu(POSITION, "here") + .addChild(new ExprNumber(POSITION, 0x55))), program ); } @@ -49,9 +52,9 @@ public void testConstant() { @Test public void testVariable() { Program program = parseProgram("here var 0x55"); - assertTrees(new Program() - .addChild(new PseudoVar(0, 0, "here") - .addChild(new ExprNumber(0, 0, 0x55))), + assertTrees(new Program("") + .addChild(new PseudoVar(POSITION, "here") + .addChild(new ExprNumber(POSITION, 0x55))), program ); } @@ -59,11 +62,11 @@ public void testVariable() { @Test public void testOrg() { Program program = parseProgram("org 55+88"); - assertTrees(new Program() - .addChild(new PseudoOrg(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 55)) - .addChild(new ExprNumber(0, 0, 88)))), + assertTrees(new Program("") + .addChild(new PseudoOrg(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 55)) + .addChild(new ExprNumber(POSITION, 88)))), program ); } @@ -75,12 +78,12 @@ public void testIf() { + " rrca\n" + "endif"); - assertTrees(new Program() - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new Instr(0, 0, OPCODE_RRCA, 0, 1, 7)) - .addChild(new Instr(0, 0, OPCODE_RRCA, 0, 1, 7))), + assertTrees(new Program("") + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new Instr(POSITION, OPCODE_RRCA, 0, 1, 7)) + .addChild(new Instr(POSITION, OPCODE_RRCA, 0, 1, 7))), program ); } @@ -95,10 +98,10 @@ public void testIfEmpty() { for (String src : programs) { Program program = parseProgram(src); - Node expected = new Program() - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprNumber(0, 0, 1)))); + Node expected = new Program("") + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprNumber(POSITION, 1)))); assertTrees(expected, program); } } @@ -115,12 +118,12 @@ public void testTwoLabelsInsideIf() { + " label2:\n" + "endif"); - assertTrees(new Program() - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoLabel(0, 0, "label1")) - .addChild(new PseudoLabel(0, 0, "label2"))), + assertTrees(new Program("") + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoLabel(POSITION, "label1")) + .addChild(new PseudoLabel(POSITION, "label2"))), program ); } @@ -129,7 +132,7 @@ public void testTwoLabelsInsideIf() { public void testInclude() { Program program = parseProgram("include 'filename.asm'"); assertTrees( - new Program().addChild(new PseudoInclude(0, 0, "filename.asm")), + new Program("").addChild(new PseudoInclude(POSITION, "filename.asm")), program ); } @@ -141,16 +144,16 @@ public void testMacroDef() { + " heylabel: and 7Fh\n" + "endm\n\n"); - Node expected = new Program() - .addChild(new PseudoMacroDef(0, 0, "shrt") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "param1"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "param2"))) - .addChild(new Instr(0, 0, OPCODE_RRCA, 0, 1, 7)) - .addChild(new PseudoLabel(0, 0, "heylabel") - .addChild(new Instr(0, 0, OPCODE_AND, 3, 4, 6) - .addChild(new ExprNumber(0, 0, 0x7F))))); + Node expected = new Program("") + .addChild(new PseudoMacroDef(POSITION, "shrt") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "param1"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "param2"))) + .addChild(new Instr(POSITION, OPCODE_RRCA, 0, 1, 7)) + .addChild(new PseudoLabel(POSITION, "heylabel") + .addChild(new Instr(POSITION, OPCODE_AND, 3, 4, 6) + .addChild(new ExprNumber(POSITION, 0x7F))))); assertTrees(expected, program); } @@ -165,7 +168,7 @@ public void testMacroDefEmpty() { for (String src : programs) { Program program = parseProgram(src); - Node expected = new Program().addChild(new PseudoMacroDef(0, 0, "shrt")); + Node expected = new Program("").addChild(new PseudoMacroDef(POSITION, "shrt")); assertTrees(expected, program); } } @@ -178,7 +181,7 @@ public void testMacroDefEndmMustBeOnNewLine() { @Test public void testMacroCallNoParams() { Program program = parseProgram("shrt"); - Node expected = new Program().addChild(new PseudoMacroCall(0, 0, "shrt")); + Node expected = new Program("").addChild(new PseudoMacroCall(POSITION, "shrt")); assertTrees(expected, program); } @@ -186,12 +189,12 @@ public void testMacroCallNoParams() { public void testMacroCallWithParams() { Program program = parseProgram("shrt param1, 45"); - Node expected = new Program() - .addChild(new PseudoMacroCall(0, 0, "shrt") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "param1"))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 45)))); + Node expected = new Program("") + .addChild(new PseudoMacroCall(POSITION, "shrt") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "param1"))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 45)))); assertTrees(expected, program); } diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/CheckExprSizesVisitorTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/CheckExprSizesVisitorTest.java index 23922e03b..88a9b7470 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/CheckExprSizesVisitorTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/CheckExprSizesVisitorTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.Program; import net.emustudio.plugins.compiler.asZ80.ast.data.DataDB; @@ -37,13 +38,15 @@ import static org.junit.Assert.assertTrue; public class CheckExprSizesVisitorTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Test public void testDBoneByte() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 0xFF))); + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 0xFF))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -53,11 +56,11 @@ public void testDBoneByte() { @Test public void testDBtwoBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 0xFF)) - .addChild(new Evaluated(0, 0, 0x100))); // bad size + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 0xFF)) + .addChild(new Evaluated(POSITION, 0x100))); // bad size CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -67,10 +70,10 @@ public void testDBtwoBytes() { @Test public void testDWtwoBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDW(0, 0) - .addChild(new Evaluated(0, 0, 0xFFFF))); + .addChild(new DataDW(POSITION) + .addChild(new Evaluated(POSITION, 0xFFFF))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -80,11 +83,11 @@ public void testDWtwoBytes() { @Test public void testDWthreeBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDW(0, 0) - .addChild(new Evaluated(0, 0, 0xFFFF)) - .addChild(new Evaluated(0, 0, 0x10000))); + .addChild(new DataDW(POSITION) + .addChild(new Evaluated(POSITION, 0xFFFF)) + .addChild(new Evaluated(POSITION, 0x10000))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -94,10 +97,10 @@ public void testDWthreeBytes() { @Test public void testDStwoBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDS(0, 0) - .addChild(new Evaluated(0, 0, 0xFFFF))); + .addChild(new DataDS(POSITION) + .addChild(new Evaluated(POSITION, 0xFFFF))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -107,10 +110,10 @@ public void testDStwoBytes() { @Test public void testDSthreeBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDS(0, 0) - .addChild(new Evaluated(0, 0, 0x10000))); + .addChild(new DataDS(POSITION) + .addChild(new Evaluated(POSITION, 0x10000))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -120,10 +123,10 @@ public void testDSthreeBytes() { @Test public void testInstrExprTwoBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new Instr(0, 0, OPCODE_ADD, 3, 0, 6).setSizeBytes(2) - .addChild(new Evaluated(0, 0, 0xFF00).setSizeBytes(1))); + .addChild(new Instr(POSITION, OPCODE_ADD, 3, 0, 6).setSizeBytes(2) + .addChild(new Evaluated(POSITION, 0xFF00).setSizeBytes(1))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -133,10 +136,10 @@ public void testInstrExprTwoBytes() { @Test public void testInstrExprThreeBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new Instr(0, 0, OPCODE_JP, 3, 0, 3).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0xFF000).setSizeBytes(2))); + .addChild(new Instr(POSITION, OPCODE_JP, 3, 0, 3).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 0xFF000).setSizeBytes(2))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -146,10 +149,10 @@ public void testInstrExprThreeBytes() { @Test public void testInstrRegExprOneByte() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6).setSizeBytes(2) - .addChild(new Evaluated(0, 0, 0xFF).setSizeBytes(1))); + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6).setSizeBytes(2) + .addChild(new Evaluated(POSITION, 0xFF).setSizeBytes(1))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -159,10 +162,10 @@ public void testInstrRegExprOneByte() { @Test public void testInstrRegExprTwoBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6).setSizeBytes(2) - .addChild(new Evaluated(0, 0, 0x100).setSizeBytes(1))); // bad size + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6).setSizeBytes(2) + .addChild(new Evaluated(POSITION, 0x100).setSizeBytes(1))); // bad size CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -172,10 +175,10 @@ public void testInstrRegExprTwoBytes() { @Test public void testInstrRegPairExprTwoBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0xFFFF).setSizeBytes(2))); + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 0xFFFF).setSizeBytes(2))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -185,10 +188,10 @@ public void testInstrRegPairExprTwoBytes() { @Test public void testInstrRegPairExprThreeBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0x10000).setSizeBytes(2))); // bad size + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 0x10000).setSizeBytes(2))); // bad size CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -198,10 +201,10 @@ public void testInstrRegPairExprThreeBytes() { @Test public void testPseudoOrgTwoBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoOrg(0, 0).setSizeBytes(2) - .addChild(new Evaluated(0, 0, 0xFFFF).setSizeBytes(2))); + .addChild(new PseudoOrg(POSITION).setSizeBytes(2) + .addChild(new Evaluated(POSITION, 0xFFFF).setSizeBytes(2))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -211,10 +214,10 @@ public void testPseudoOrgTwoBytes() { @Test public void testPseudoOrgThreeBytes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoOrg(0, 0).setSizeBytes(2) - .addChild(new Evaluated(0, 0, 0x10000).setSizeBytes(2))); // bad size + .addChild(new PseudoOrg(POSITION).setSizeBytes(2) + .addChild(new Evaluated(POSITION, 0x10000).setSizeBytes(2))); // bad size CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); @@ -224,36 +227,36 @@ public void testPseudoOrgThreeBytes() { @Test public void testMacroArgumentsAreRemoved() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0).setSizeBytes(2))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 1).setSizeBytes(2)))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0).setSizeBytes(2)))); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 0).setSizeBytes(2))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 1).setSizeBytes(2)))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 0).setSizeBytes(2)))); CheckExprSizesVisitor visitor = new CheckExprSizesVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0).setSizeBytes(2))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 1).setSizeBytes(2)))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1).setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0).setSizeBytes(2)))), + new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 0).setSizeBytes(2))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 1).setSizeBytes(2)))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1).setSizeBytes(3) + .addChild(new Evaluated(POSITION, 0).setSizeBytes(2)))), program ); } diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/EvaluateExprVisitorTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/EvaluateExprVisitorTest.java index b18cd1793..074dc2a9c 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/EvaluateExprVisitorTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/EvaluateExprVisitorTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.Program; import net.emustudio.plugins.compiler.asZ80.ast.data.DataDB; @@ -41,58 +42,60 @@ import static org.junit.Assert.assertTrue; public class EvaluateExprVisitorTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Test public void testEvaluateDB() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 1)) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new ExprNumber(0, 0, 'h')) - .addChild(new ExprNumber(0, 0, 'e')) - .addChild(new ExprNumber(0, 0, 'l')) - .addChild(new ExprNumber(0, 0, 'l')) - .addChild(new ExprNumber(0, 0, 'o')) + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 1)) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new ExprNumber(POSITION, 'h')) + .addChild(new ExprNumber(POSITION, 'e')) + .addChild(new ExprNumber(POSITION, 'l')) + .addChild(new ExprNumber(POSITION, 'l')) + .addChild(new ExprNumber(POSITION, 'o')) ); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 3)) - .addChild(new Evaluated(0, 0, 'h')) - .addChild(new Evaluated(0, 0, 'e')) - .addChild(new Evaluated(0, 0, 'l')) - .addChild(new Evaluated(0, 0, 'l')) - .addChild(new Evaluated(0, 0, 'o'))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 3)) + .addChild(new Evaluated(POSITION, 'h')) + .addChild(new Evaluated(POSITION, 'e')) + .addChild(new Evaluated(POSITION, 'l')) + .addChild(new Evaluated(POSITION, 'l')) + .addChild(new Evaluated(POSITION, 'o'))), program ); } @Test public void testEvaluateDW() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDW(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 1)) - .addChild(new ExprNumber(0, 0, 2)))) - .addChild(new DataDW(0, 0) - .addChild(new ExprNumber(0, 0, 0))); + .addChild(new DataDW(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 1)) + .addChild(new ExprNumber(POSITION, 2)))) + .addChild(new DataDW(POSITION) + .addChild(new ExprNumber(POSITION, 0))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new DataDW(0, 0) - .addChild(new Evaluated(0, 0, 3))) - .addChild(new DataDW(0, 0) - .addChild(new Evaluated(0, 0, 0))), + new Program("") + .addChild(new DataDW(POSITION) + .addChild(new Evaluated(POSITION, 3))) + .addChild(new DataDW(POSITION) + .addChild(new Evaluated(POSITION, 0))), program ); assertEquals(0, program.getChild(0).getAddress()); @@ -101,24 +104,24 @@ public void testEvaluateDW() { @Test public void testEvaluateDS() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDS(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprNumber(0, 0, 1)) - .addChild(new ExprNumber(0, 0, 2)))) - .addChild(new DataDB(0, 0) - .addChild(new ExprNumber(0, 0, 0))); + .addChild(new DataDS(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprNumber(POSITION, 1)) + .addChild(new ExprNumber(POSITION, 2)))) + .addChild(new DataDB(POSITION) + .addChild(new ExprNumber(POSITION, 0))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new DataDS(0, 0) - .addChild(new Evaluated(0, 0, 3))) - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 0))), + new Program("") + .addChild(new DataDS(POSITION) + .addChild(new Evaluated(POSITION, 3))) + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 0))), program ); assertEquals(0, program.getChild(0).getAddress()); @@ -127,11 +130,11 @@ public void testEvaluateDS() { @Test public void testEvaluateDSambiguous() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDS(0, 0) - .addChild(new ExprId(0, 0, "label"))) - .addChild(new PseudoLabel(0, 0, "label")); + .addChild(new DataDS(POSITION) + .addChild(new ExprId(POSITION, "label"))) + .addChild(new PseudoLabel(POSITION, "label")); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); @@ -141,12 +144,12 @@ public void testEvaluateDSambiguous() { @Test public void testEvaluateDSconstReference() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDS(0, 0) - .addChild(new ExprId(0, 0, "label"))) - .addChild(new PseudoEqu(0, 0, "label") - .addChild(new ExprNumber(0, 0, 5))); + .addChild(new DataDS(POSITION) + .addChild(new ExprId(POSITION, "label"))) + .addChild(new PseudoEqu(POSITION, "label") + .addChild(new ExprNumber(POSITION, 5))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); @@ -158,33 +161,33 @@ public void testEvaluateDSconstReference() { assertEquals(0, label.get().getAddress()); assertTrees( - new Program() - .addChild(new DataDS(0, 0) - .addChild(new Evaluated(0, 0, 5))), + new Program("") + .addChild(new DataDS(POSITION) + .addChild(new Evaluated(POSITION, 5))), program ); } @Test public void testEvaluateEQUfivePasses() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoEqu(0, 0, "one") - .addChild(new ExprId(0, 0, "two"))) - .addChild(new PseudoEqu(0, 0, "two") - .addChild(new ExprId(0, 0, "three"))) - .addChild(new PseudoEqu(0, 0, "three") - .addChild(new ExprId(0, 0, "four"))) - .addChild(new PseudoEqu(0, 0, "four") - .addChild(new ExprId(0, 0, "five"))) - .addChild(new PseudoEqu(0, 0, "five") - .addChild(new ExprCurrentAddress(0, 0))); + .addChild(new PseudoEqu(POSITION, "one") + .addChild(new ExprId(POSITION, "two"))) + .addChild(new PseudoEqu(POSITION, "two") + .addChild(new ExprId(POSITION, "three"))) + .addChild(new PseudoEqu(POSITION, "three") + .addChild(new ExprId(POSITION, "four"))) + .addChild(new PseudoEqu(POSITION, "four") + .addChild(new ExprId(POSITION, "five"))) + .addChild(new PseudoEqu(POSITION, "five") + .addChild(new ExprCurrentAddress(POSITION))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrue(program.env().hasNoErrors()); - assertTrees(new Program(), program); + assertTrees(new Program(""), program); List constants = List.of("one", "two", "three", "four", "five"); for (String c : constants) { @@ -197,33 +200,33 @@ public void testEvaluateEQUfivePasses() { @Test public void testEvaluateIFwithForwardConst() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6) .setSizeBytes(2) - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprNumber(0, 0, 2)))) - .addChild(new Instr(0, 0, OPCODE_RST, 3, 0, 7) + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprNumber(POSITION, 2)))) + .addChild(new Instr(POSITION, OPCODE_RST, 3, 0, 7) .setSizeBytes(1) - .addChild(new ExprNumber(0, 0, 0)))) - .addChild(new PseudoEqu(0, 0, "const") - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprCurrentAddress(0, 0)))); + .addChild(new ExprNumber(POSITION, 0)))) + .addChild(new PseudoEqu(POSITION, "const") + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprCurrentAddress(POSITION)))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6) - .addChild(new Evaluated(0, 0, 6))) - .addChild(new Instr(0, 0, OPCODE_RST, 3, 0, 7) - .addChild(new Evaluated(0, 0, 0))), + new Program("") + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6) + .addChild(new Evaluated(POSITION, 6))) + .addChild(new Instr(POSITION, OPCODE_RST, 3, 0, 7) + .addChild(new Evaluated(POSITION, 0))), program ); assertEquals(0, program.getChild(0).getAddress()); @@ -232,19 +235,19 @@ public void testEvaluateIFwithForwardConst() { @Test public void testEvaluateIFwithForwardAddressReference() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprInfix(0, 0, OP_EQUAL) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprId(0, 0, "const")))) - .addChild(new Instr(0, 0, OPCODE_RST, 3, 0, 7) - .addChild(new ExprNumber(0, 0, 0)))) - .addChild(new PseudoEqu(0, 0, "const") - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprCurrentAddress(0, 0)))); + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprInfix(POSITION, OP_EQUAL) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprId(POSITION, "const")))) + .addChild(new Instr(POSITION, OPCODE_RST, 3, 0, 7) + .addChild(new ExprNumber(POSITION, 0)))) + .addChild(new PseudoEqu(POSITION, "const") + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprCurrentAddress(POSITION)))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); @@ -254,173 +257,173 @@ public void testEvaluateIFwithForwardAddressReference() { @Test public void testEvaluateIFexcludeBlock() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoIf(0, 0) - .addChild(new PseudoIfExpression(0, 0) - .addChild(new ExprNumber(0, 0, 0))) - .addChild(new Instr(0, 0, OPCODE_RST, 3, 0, 7) - .addChild(new ExprNumber(0, 0, 0)))); + .addChild(new PseudoIf(POSITION) + .addChild(new PseudoIfExpression(POSITION) + .addChild(new ExprNumber(POSITION, 0))) + .addChild(new Instr(POSITION, OPCODE_RST, 3, 0, 7) + .addChild(new ExprNumber(POSITION, 0)))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); - assertTrees(new Program(), program); + assertTrees(new Program(""), program); } @Test public void testEvaluateSETforwardTwoTimes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6) - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoVar(0, 0, "const") - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 6) - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoVar(0, 0, "const") - .addChild(new ExprNumber(0, 0, 2))); + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6) + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoVar(POSITION, "const") + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 6) + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoVar(POSITION, "const") + .addChild(new ExprNumber(POSITION, 2))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoVar(0, 0, "const") - .addChild(new Evaluated(0, 0, 1))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 6) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoVar(0, 0, "const") - .addChild(new Evaluated(0, 0, 2))), + new Program("") + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoVar(POSITION, "const") + .addChild(new Evaluated(POSITION, 1))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 6) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoVar(POSITION, "const") + .addChild(new Evaluated(POSITION, 2))), program ); } @Test public void testEvaluateSETforwardMoreTimes() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new ExprId(0, 0, "id"))) - .addChild(new PseudoVar(0, 0, "id") - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoVar(0, 0, "id") - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoEqu(0, 0, "const") - .addChild(new ExprNumber(0, 0, 1))); + .addChild(new DataDB(POSITION) + .addChild(new ExprId(POSITION, "id"))) + .addChild(new PseudoVar(POSITION, "id") + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoVar(POSITION, "id") + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoEqu(POSITION, "const") + .addChild(new ExprNumber(POSITION, 1))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoVar(0, 0, "id") - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoVar(0, 0, "id") - .addChild(new Evaluated(0, 0, 2))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoVar(POSITION, "id") + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoVar(POSITION, "id") + .addChild(new Evaluated(POSITION, 2))), program ); } @Test public void testTwoSETthenReference() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoVar(0, 0, "id") - .addChild(new ExprId(0, 0, "const"))) - .addChild(new PseudoVar(0, 0, "id") - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoEqu(0, 0, "const") - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new DataDB(0, 0) - .addChild(new ExprId(0, 0, "id"))); + .addChild(new PseudoVar(POSITION, "id") + .addChild(new ExprId(POSITION, "const"))) + .addChild(new PseudoVar(POSITION, "id") + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoEqu(POSITION, "const") + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new DataDB(POSITION) + .addChild(new ExprId(POSITION, "id"))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoVar(0, 0, "id") - .addChild(new Evaluated(0, 0, 1))) - .addChild(new PseudoVar(0, 0, "id") - .addChild(new Evaluated(0, 0, 2))) - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 2))), + new Program("") + .addChild(new PseudoVar(POSITION, "id") + .addChild(new Evaluated(POSITION, 1))) + .addChild(new PseudoVar(POSITION, "id") + .addChild(new Evaluated(POSITION, 2))) + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 2))), program ); } @Test public void testEvaluateLABEL() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprId(0, 0, "label"))) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprId(0, 0, "label"))) - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprCurrentAddress(0, 0)) - .addChild(new ExprId(0, 0, "label")))) - .addChild(new PseudoLabel(0, 0, "label")); + .addChild(new DataDB(POSITION) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprId(POSITION, "label"))) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprId(POSITION, "label"))) + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprCurrentAddress(POSITION)) + .addChild(new ExprId(POSITION, "label")))) + .addChild(new PseudoLabel(POSITION, "label")); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 3)) - .addChild(new Evaluated(0, 0, 4)) - .addChild(new Evaluated(0, 0, 5))), + new Program("") + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 3)) + .addChild(new Evaluated(POSITION, 4)) + .addChild(new Evaluated(POSITION, 5))), program ); } @Test public void testEvaluateMacroCalls() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoLabel(0, 0, "label")) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "addr")) - .addChild(new ExprId(0, 0, "label"))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new ExprId(0, 0, "addr")))); + .addChild(new PseudoLabel(POSITION, "label")) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "addr")) + .addChild(new ExprId(POSITION, "label"))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new ExprId(POSITION, "addr")))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "addr")) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new Evaluated(0, 0, 0)))), + new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "addr")) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new Evaluated(POSITION, 0)))), program ); } @Test public void testEvaluateMacroCallAmbiguous() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "label")) - .addChild(new ExprId(0, 0, "addr"))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new ExprId(0, 0, "addr")))) - .addChild(new PseudoLabel(0, 0, "label")); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "label")) + .addChild(new ExprId(POSITION, "addr"))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new ExprId(POSITION, "addr")))) + .addChild(new PseudoLabel(POSITION, "label")); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); @@ -430,58 +433,58 @@ public void testEvaluateMacroCallAmbiguous() { @Test public void testEvaluateMacroScopedArguments() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new ExprNumber(0, 0, 0))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new ExprId(0, 0, "arg"))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new ExprId(0, 0, "arg")))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new ExprId(0, 0, "arg")))); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new ExprNumber(POSITION, 0))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new ExprId(POSITION, "arg"))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new ExprId(POSITION, "arg")))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new ExprId(POSITION, "arg")))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "arg")) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new Evaluated(0, 0, 1)))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) - .addChild(new Evaluated(0, 0, 0)))), + new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "arg")) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new Evaluated(POSITION, 1)))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) + .addChild(new Evaluated(POSITION, 0)))), program ); } @Test public void testLabelKeepsChildren() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoLabel(0, 0, "label") - .addChild(new Instr(0, 0, OPCODE_RET, 3, 1, 1))); + .addChild(new PseudoLabel(POSITION, "label") + .addChild(new Instr(POSITION, OPCODE_RET, 3, 1, 1))); EvaluateExprVisitor visitor = new EvaluateExprVisitor(); visitor.visit(program); assertTrees( - new Program().addChild(new Instr(0, 0, OPCODE_RET, 3, 1, 1)), + new Program("").addChild(new Instr(POSITION, OPCODE_RET, 3, 1, 1)), program ); } diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandIncludesVisitorTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandIncludesVisitorTest.java index 0735dc6f9..4f801d7b6 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandIncludesVisitorTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandIncludesVisitorTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.ast.Program; import net.emustudio.plugins.compiler.asZ80.ast.expr.ExprNumber; @@ -37,6 +38,8 @@ import static org.junit.Assert.assertTrue; public class ExpandIncludesVisitorTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Rule public TemporaryFolder folder = new TemporaryFolder(); @@ -47,12 +50,12 @@ public void testExpandInclude() { ExpandIncludesVisitor visitor = new ExpandIncludesVisitor(); visitor.visit(program); - Node expected = new Program() - .addChild(new Instr(0, 0, OPCODE_CCF, 0, 7, 7)) - .addChild(new PseudoLabel(0, 0, "sample")) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6) - .addChild(new ExprNumber(0, 0, 0))) - .addChild(new Instr(0, 0, OPCODE_RET, 3, 1, 1)); + Node expected = new Program("") + .addChild(new Instr(POSITION, OPCODE_CCF, 0, 7, 7)) + .addChild(new PseudoLabel(POSITION, "sample")) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6) + .addChild(new ExprNumber(POSITION, 0))) + .addChild(new Instr(POSITION, OPCODE_RET, 3, 1, 1)); assertTrees(expected, program); } @@ -69,9 +72,9 @@ public void testExpandIncludeTwoTimes() throws IOException { ExpandIncludesVisitor visitor = new ExpandIncludesVisitor(); visitor.visit(program); - Node expected = new Program() - .addChild(new Instr(0, 0, OPCODE_RRCA, 0, 1, 7)) - .addChild(new Instr(0, 0, OPCODE_RRCA, 0, 1, 7)); + Node expected = new Program("") + .addChild(new Instr(POSITION, OPCODE_RRCA, 0, 1, 7)) + .addChild(new Instr(POSITION, OPCODE_RRCA, 0, 1, 7)); assertTrees(expected, program); } diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandMacrosTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandMacrosTest.java index 93b4d9c37..a4ff0d183 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandMacrosTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/ExpandMacrosTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Program; import net.emustudio.plugins.compiler.asZ80.ast.expr.ExprId; import net.emustudio.plugins.compiler.asZ80.ast.expr.ExprNumber; @@ -38,6 +39,8 @@ import static org.junit.Assert.assertTrue; public class ExpandMacrosTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Rule public TemporaryFolder folder = new TemporaryFolder(); @@ -47,9 +50,9 @@ public void testMacroDefinitionThenMacroCall() { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))), program ); } @@ -60,9 +63,9 @@ public void testMacroCallThenMacroDefinition() { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))), program ); } @@ -73,11 +76,11 @@ public void testMacroCallThenMacroDefinitionThenMacroCall() { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))), program ); } @@ -93,9 +96,9 @@ public void testMacroCallThenMacroDefinitionInsideInclude() throws IOException { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroDef(0, 0, "x"))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroDef(POSITION, "x"))), program ); } @@ -120,21 +123,21 @@ public void testMacroCallWithArguments() { ExpandMacrosVisitor macrosVisitor = new ExpandMacrosVisitor(); macrosVisitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "u"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "v"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "w"))))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "u"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "v"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "w"))))), program ); } diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/GenerateCodeVisitorTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/GenerateCodeVisitorTest.java index 8887375d1..64f2d6ff6 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/GenerateCodeVisitorTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/GenerateCodeVisitorTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.emulib.runtime.io.IntelHEX; import net.emustudio.plugins.compiler.asZ80.ast.Evaluated; import net.emustudio.plugins.compiler.asZ80.ast.Program; @@ -35,30 +36,32 @@ import static org.junit.Assert.assertEquals; public class GenerateCodeVisitorTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Test public void testCodeGeneration() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new DataDB(0, 0) - .addChild(new Evaluated(0, 0, 255)) - .addChild(new Instr(0, 0, OPCODE_RST, 3, 0, 7) - .addChild(new Evaluated(0, 0, 4)))) - .addChild(new DataDW(0, 0) - .addChild(new Evaluated(0, 0, 1))) - .addChild(new DataDS(0, 0) - .addChild(new Evaluated(0, 0, 5))) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new Instr(0, 0, OPCODE_LD, 0, 0, 1) + .addChild(new DataDB(POSITION) + .addChild(new Evaluated(POSITION, 255)) + .addChild(new Instr(POSITION, OPCODE_RST, 3, 0, 7) + .addChild(new Evaluated(POSITION, 4)))) + .addChild(new DataDW(POSITION) + .addChild(new Evaluated(POSITION, 1))) + .addChild(new DataDS(POSITION) + .addChild(new Evaluated(POSITION, 5))) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new Instr(POSITION, OPCODE_LD, 0, 0, 1) .setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0xFEAB).setSizeBytes(2))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new Instr(0, 0, OPCODE_LD, 0, 2, 1) + .addChild(new Evaluated(POSITION, 0xFEAB).setSizeBytes(2))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new Instr(POSITION, OPCODE_LD, 0, 2, 1) .setSizeBytes(3) - .addChild(new Evaluated(0, 0, 1).setSizeBytes(2)))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 4, 1) + .addChild(new Evaluated(POSITION, 1).setSizeBytes(2)))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 4, 1) .setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0x1234).setSizeBytes(2)))); + .addChild(new Evaluated(POSITION, 0x1234).setSizeBytes(2)))); IntelHEX hex = new IntelHEX(); GenerateCodeVisitor visitor = new GenerateCodeVisitor(hex); @@ -87,16 +90,16 @@ public void testCodeGeneration() { @Test public void testPseudoOrg() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoOrg(0, 0) - .addChild(new Evaluated(0, 0, 5))) - .addChild(new Instr(0, 0, OPCODE_CALL, 3, 0, 4) + .addChild(new PseudoOrg(POSITION) + .addChild(new Evaluated(POSITION, 5))) + .addChild(new Instr(POSITION, OPCODE_CALL, 3, 0, 4) .setSizeBytes(3) - .addChild(new Evaluated(0, 0, 0x400).setSizeBytes(2))) - .addChild(new PseudoOrg(0, 0) - .addChild(new Evaluated(0, 0, 0))) - .addChild(new Instr(0, 0, OPCODE_EX, 3, 5, 3)); + .addChild(new Evaluated(POSITION, 0x400).setSizeBytes(2))) + .addChild(new PseudoOrg(POSITION) + .addChild(new Evaluated(POSITION, 0))) + .addChild(new Instr(POSITION, OPCODE_EX, 3, 5, 3)); IntelHEX hex = new IntelHEX(); GenerateCodeVisitor visitor = new GenerateCodeVisitor(hex); diff --git a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/SortMacroArgumentsVisitorTest.java b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/SortMacroArgumentsVisitorTest.java index fc6036bd1..3d0932056 100644 --- a/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/SortMacroArgumentsVisitorTest.java +++ b/plugins/compiler/as-z80/src/test/java/net/emustudio/plugins/compiler/asZ80/visitors/SortMacroArgumentsVisitorTest.java @@ -18,6 +18,7 @@ */ package net.emustudio.plugins.compiler.asZ80.visitors; +import net.emustudio.emulib.plugins.compiler.SourceCodePosition; import net.emustudio.plugins.compiler.asZ80.ast.Node; import net.emustudio.plugins.compiler.asZ80.ast.Program; import net.emustudio.plugins.compiler.asZ80.ast.expr.ExprId; @@ -34,132 +35,134 @@ import static org.junit.Assert.assertTrue; public class SortMacroArgumentsVisitorTest { + private final static SourceCodePosition POSITION = new SourceCodePosition(0, 0, ""); + @Test public void testMacroArgumentsAreConnectedWithIds() { - Node program = new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "r"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "t"))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoEqu(0, 0, "uu") - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprId(0, 0, "r")) - .addChild(new ExprId(0, 0, "t")))))); + Node program = new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "r"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "t"))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoEqu(POSITION, "uu") + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprId(POSITION, "r")) + .addChild(new ExprId(POSITION, "t")))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "r")) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "t")) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new Instr(0, 0, OPCODE_LD, 0, 7, 6) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoEqu(0, 0, "uu") - .addChild(new ExprInfix(0, 0, OP_ADD) - .addChild(new ExprId(0, 0, "r")) - .addChild(new ExprId(0, 0, "t"))))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "r")) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "t")) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new Instr(POSITION, OPCODE_LD, 0, 7, 6) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoEqu(POSITION, "uu") + .addChild(new ExprInfix(POSITION, OP_ADD) + .addChild(new ExprId(POSITION, "r")) + .addChild(new ExprId(POSITION, "t"))))), program ); } @Test public void testMultipleMacroCalls() { - Node program = new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))))) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))))); + Node program = new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))))) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); - assertTrees(new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 1)))) - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 2)))), + assertTrees(new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 1)))) + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 2)))), program ); } @Test public void testNestedMacroCallWithSameNamedArgs() { - Node program = new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 3))) - .addChild(new PseudoMacroDef(0, 0, "y") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))))))); + Node program = new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 3))) + .addChild(new PseudoMacroDef(POSITION, "y") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); assertTrees( - new Program() - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroCall(0, 0, "y") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprId(0, 0, "q")) - .addChild(new ExprNumber(0, 0, 3))))), + new Program("") + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroCall(POSITION, "y") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprId(POSITION, "q")) + .addChild(new ExprNumber(POSITION, 3))))), program ); } @Test public void testMoreMacroArgumentsThanParameters() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 2))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))))); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 2))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); @@ -169,16 +172,16 @@ public void testMoreMacroArgumentsThanParameters() { @Test public void testMoreMacroParametersThanArguments() { - Program program = new Program(); + Program program = new Program(""); program - .addChild(new PseudoMacroCall(0, 0, "x") - .addChild(new PseudoMacroArgument(0, 0) - .addChild(new ExprNumber(0, 0, 1))) - .addChild(new PseudoMacroDef(0, 0, "x") - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "q"))) - .addChild(new PseudoMacroParameter(0, 0) - .addChild(new ExprId(0, 0, "r"))))); + .addChild(new PseudoMacroCall(POSITION, "x") + .addChild(new PseudoMacroArgument(POSITION) + .addChild(new ExprNumber(POSITION, 1))) + .addChild(new PseudoMacroDef(POSITION, "x") + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "q"))) + .addChild(new PseudoMacroParameter(POSITION) + .addChild(new ExprId(POSITION, "r"))))); SortMacroArgumentsVisitor visitor = new SortMacroArgumentsVisitor(); visitor.visit(program); diff --git a/plugins/compiler/brainc-brainduck/src/main/java/net/emustudio/plugins/compiler/brainduck/CompilerBrainduck.java b/plugins/compiler/brainc-brainduck/src/main/java/net/emustudio/plugins/compiler/brainduck/CompilerBrainduck.java index 210f86c40..de49a7090 100644 --- a/plugins/compiler/brainc-brainduck/src/main/java/net/emustudio/plugins/compiler/brainduck/CompilerBrainduck.java +++ b/plugins/compiler/brainc-brainduck/src/main/java/net/emustudio/plugins/compiler/brainduck/CompilerBrainduck.java @@ -41,10 +41,9 @@ import java.io.FileReader; import java.io.Reader; +import java.nio.file.Path; import java.util.*; -import static net.emustudio.emulib.plugins.compiler.FileExtension.stripKnownExtension; - @PluginRoot(type = PLUGIN_TYPE.COMPILER, title = "BrainDuck Compiler") @SuppressWarnings("unused") public class CompilerBrainduck extends AbstractCompiler { @@ -65,8 +64,9 @@ public void initialize() { Optional.ofNullable(applicationApi.getContextPool()).ifPresent(pool -> { try { memory = pool.getMemoryContext(pluginID, MemoryContext.class); - if (memory.getDataType() != Byte.class) { - throw new InvalidContextException("Unexpected memory cell type. Expected Byte but was: " + memory.getDataType()); + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { + throw new InvalidContextException("Unexpected memory cell type. Expected Byte but was: " + cellTypeClass); } } catch (ContextNotFoundException | InvalidContextException e) { LOGGER.warn("Memory is not available", e); @@ -95,18 +95,20 @@ public LexicalAnalyzer createLexer() { } @Override - public boolean compile(String inputFileName, String outputFileName) { + public void compile(Path inputPath, Optional outputPath) { try { notifyCompileStart(); - IntelHEX hex = compileToHex(inputFileName); - hex.generate(outputFileName); + Path finalOutputPath = outputPath.orElse(convertInputToOutputPath(inputPath, ".hex")); + IntelHEX hex = compileToHex(inputPath); + + hex.generate(finalOutputPath); int programLocation = hex.findProgramLocation(); applicationApi.setProgramLocation(programLocation); notifyInfo(String.format( "Compile was successful.\n\tOutput: %s\n\tProgram starts at 0x%s", - outputFileName, RadixUtils.formatWordHexString(programLocation) + finalOutputPath, RadixUtils.formatWordHexString(programLocation) )); if (memory != null) { @@ -117,33 +119,23 @@ public boolean compile(String inputFileName, String outputFileName) { } else { notifyWarning("Memory is not available."); } - return true; } catch (Exception e) { - LOGGER.trace("Compilation error", e); notifyError("Compilation error: " + e); - e.printStackTrace(); - return false; } finally { notifyCompileFinish(); } } - @Override - public boolean compile(String inputFileName) { - String outputFileName = stripKnownExtension(inputFileName, SOURCE_FILE_EXTENSIONS) + ".hex"; - return compile(inputFileName, outputFileName); - } - @Override public List getSourceFileExtensions() { return SOURCE_FILE_EXTENSIONS; } - private IntelHEX compileToHex(String inputFileName) throws Exception { - Objects.requireNonNull(inputFileName); + private IntelHEX compileToHex(Path inputPath) throws Exception { + Objects.requireNonNull(inputPath); notifyInfo(getTitle() + ", version " + getVersion()); - try (Reader reader = new FileReader(inputFileName)) { + try (Reader reader = new FileReader(inputPath.toFile())) { org.antlr.v4.runtime.Lexer lexer = createLexer(CharStreams.fromReader(reader)); lexer.addErrorListener(new ParserErrorListener()); CommonTokenStream tokens = new CommonTokenStream(lexer); diff --git a/plugins/compiler/brainc-brainduck/src/main/java/net/emustudio/plugins/compiler/brainduck/Runner.java b/plugins/compiler/brainc-brainduck/src/main/java/net/emustudio/plugins/compiler/brainduck/Runner.java index 0cc08955d..69143a9e1 100644 --- a/plugins/compiler/brainc-brainduck/src/main/java/net/emustudio/plugins/compiler/brainduck/Runner.java +++ b/plugins/compiler/brainc-brainduck/src/main/java/net/emustudio/plugins/compiler/brainduck/Runner.java @@ -23,6 +23,9 @@ import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.settings.PluginSettings; +import java.nio.file.Path; +import java.util.Optional; + public class Runner { public static void main(String... args) { @@ -49,15 +52,6 @@ public static void main(String... args) { return; } inputFile = args[i]; - if (outputFile == null) { - int index = inputFile.lastIndexOf('.'); - if (index != -1) { - outputFile = inputFile.substring(0, index); - } else { - outputFile = inputFile; - } - outputFile += ".hex"; - } CompilerBrainduck compiler = new CompilerBrainduck(0L, ApplicationApi.UNAVAILABLE, PluginSettings.UNAVAILABLE); compiler.addCompilerListener(new CompilerListener() { @@ -77,7 +71,7 @@ public void onFinish() { }); try { - compiler.compile(inputFile, outputFile); + compiler.compile(Path.of(inputFile), Optional.ofNullable(outputFile).map(Path::of)); } catch (Exception e) { System.err.println(e.getMessage()); } diff --git a/plugins/compiler/brainc-brainduck/src/test/java/net/emustudio/plugins/compiler/brainduck/AbstractCompilerTest.java b/plugins/compiler/brainc-brainduck/src/test/java/net/emustudio/plugins/compiler/brainduck/AbstractCompilerTest.java index 9f7cd1062..bb0876691 100644 --- a/plugins/compiler/brainc-brainduck/src/test/java/net/emustudio/plugins/compiler/brainduck/AbstractCompilerTest.java +++ b/plugins/compiler/brainc-brainduck/src/test/java/net/emustudio/plugins/compiler/brainduck/AbstractCompilerTest.java @@ -34,6 +34,7 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.StandardOpenOption; +import java.util.Optional; import static org.easymock.EasyMock.*; import static org.junit.Assert.assertEquals; @@ -43,6 +44,7 @@ public abstract class AbstractCompilerTest { public TemporaryFolder folder = new TemporaryFolder(); protected CompilerBrainduck compiler; protected MemoryStub memoryStub; + private int errorCount; @SuppressWarnings("unchecked") @Before @@ -57,6 +59,7 @@ public void setUp() throws Exception { expect(applicationApi.getContextPool()).andReturn(pool).anyTimes(); replay(applicationApi); + errorCount = 0; compiler = new CompilerBrainduck(0L, applicationApi, PluginSettings.UNAVAILABLE); compiler.addCompilerListener(new CompilerListener() { @Override @@ -66,6 +69,9 @@ public void onStart() { @Override public void onMessage(CompilerMessage message) { System.out.println(message); + if (message.getMessageType() == CompilerMessage.MessageType.TYPE_ERROR) { + errorCount++; + } } @Override @@ -80,8 +86,9 @@ protected void compile(String content) throws Exception { Files.write(sourceFile.toPath(), content.getBytes(), StandardOpenOption.WRITE); File outputFile = folder.newFile(); - if (!compiler.compile(sourceFile.getAbsolutePath(), outputFile.getAbsolutePath())) { - throw new Exception("Compilation failed"); + compiler.compile(sourceFile.toPath(), Optional.of(outputFile.toPath())); + if (errorCount > 0) { + throw new Exception("Compilation failed with " + errorCount + " errors"); } } diff --git a/plugins/compiler/brainc-brainduck/src/test/java/net/emustudio/plugins/compiler/brainduck/InstructionTest.java b/plugins/compiler/brainc-brainduck/src/test/java/net/emustudio/plugins/compiler/brainduck/InstructionTest.java index 2f286c362..213a79487 100644 --- a/plugins/compiler/brainc-brainduck/src/test/java/net/emustudio/plugins/compiler/brainduck/InstructionTest.java +++ b/plugins/compiler/brainc-brainduck/src/test/java/net/emustudio/plugins/compiler/brainduck/InstructionTest.java @@ -24,6 +24,9 @@ import net.emustudio.emulib.runtime.settings.PluginSettings; import org.junit.Test; +import java.nio.file.Path; +import java.util.Optional; + import static org.easymock.EasyMock.*; import static org.junit.Assert.assertNotEquals; @@ -102,7 +105,7 @@ public void testNullProgramDoesNotChangeMemory() throws Exception { expect(applicationApi.getContextPool()).andReturn(contextPool).anyTimes(); replay(applicationApi); - new CompilerBrainduck(0L, applicationApi, PluginSettings.UNAVAILABLE).compile("nonexistant"); + new CompilerBrainduck(0L, applicationApi, PluginSettings.UNAVAILABLE).compile(Path.of("nonexistant"), Optional.empty()); assertProgram( 1, 1 diff --git a/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/CompilerRAM.java b/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/CompilerRAM.java index 269b93252..fac8060eb 100644 --- a/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/CompilerRAM.java +++ b/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/CompilerRAM.java @@ -38,9 +38,11 @@ import java.io.FileReader; import java.io.Reader; -import java.util.*; - -import static net.emustudio.emulib.plugins.compiler.FileExtension.stripKnownExtension; +import java.nio.file.Path; +import java.util.List; +import java.util.MissingResourceException; +import java.util.Optional; +import java.util.ResourceBundle; @PluginRoot(type = PLUGIN_TYPE.COMPILER, title = "RAM Machine Assembler") @SuppressWarnings("unused") @@ -82,12 +84,13 @@ public void initialize() { } @Override - public boolean compile(String inputFileName, String outputFileName) { + public void compile(Path inputPath, Optional outputPath) { try { this.notifyCompileStart(); notifyInfo(getTitle() + ", version " + getVersion()); - try (Reader reader = new FileReader(inputFileName)) { + Path finalOutputPath = outputPath.orElse(convertInputToOutputPath(inputPath, ".bram")); + try (Reader reader = new FileReader(inputPath.toFile())) { org.antlr.v4.runtime.Lexer lexer = createLexer(CharStreams.fromReader(reader)); lexer.addErrorListener(new ParserErrorListener()); CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -100,9 +103,9 @@ public boolean compile(String inputFileName, String outputFileName) { program.assignLabels(); program.check(); - program.saveToFile(outputFileName); + program.saveToFile(finalOutputPath); - notifyInfo(String.format("Compile was successful.\n\tOutput: %s", outputFileName)); + notifyInfo(String.format("Compile was successful.\n\tOutput: %s", finalOutputPath)); if (memory != null) { memory.clear(); @@ -116,17 +119,9 @@ public boolean compile(String inputFileName, String outputFileName) { } catch (Exception e) { LOGGER.trace("Compilation failed", e); notifyError("Compilation failed: " + e.getMessage()); - return false; } finally { notifyCompileFinish(); } - return true; - } - - @Override - public boolean compile(String inputFileName) { - String outputFileName = stripKnownExtension(inputFileName, SOURCE_FILE_EXTENSIONS) + ".bram"; - return compile(inputFileName, outputFileName); } @Override diff --git a/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/Runner.java b/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/Runner.java index 0517c57f6..0d676d027 100644 --- a/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/Runner.java +++ b/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/Runner.java @@ -24,6 +24,9 @@ import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.settings.PluginSettings; +import java.nio.file.Path; +import java.util.Optional; + public class Runner { public static void main(String... args) { @@ -50,15 +53,6 @@ public static void main(String... args) { return; } inputFile = args[i]; - if (outputFile == null) { - int index = inputFile.lastIndexOf('.'); - if (index != -1) { - outputFile = inputFile.substring(0, index); - } else { - outputFile = inputFile; - } - outputFile += ".bram"; - } CompilerRAM compiler = new CompilerRAM(0L, ApplicationApi.UNAVAILABLE, PluginSettings.UNAVAILABLE); compiler.addCompilerListener(new CompilerListener() { @@ -78,7 +72,7 @@ public void onFinish() { }); try { - compiler.compile(inputFile, outputFile); + compiler.compile(Path.of(inputFile), Optional.ofNullable(outputFile).map(Path::of)); } catch (Exception e) { System.err.println(e.getMessage()); } diff --git a/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/ast/Program.java b/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/ast/Program.java index 08b100430..9fc486759 100644 --- a/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/ast/Program.java +++ b/plugins/compiler/ramc-ram/src/main/java/net/emustudio/plugins/compiler/ram/ast/Program.java @@ -25,6 +25,7 @@ import net.emustudio.plugins.memory.ram.api.RamValue; import java.io.*; +import java.nio.file.Path; import java.util.*; public class Program { @@ -89,7 +90,7 @@ public void loadIntoMemory(RamMemoryContext memory) { } } - public void saveToFile(String filename) throws IOException { + public void saveToFile(Path filename) throws IOException { Map programMemory = new HashMap<>(); for (RamInstruction instruction : instructions) { programMemory.put(instruction.getAddress(), instruction); diff --git a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/AbstractCompilerTest.java b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/AbstractCompilerTest.java index 5623d0287..8f0753c88 100644 --- a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/AbstractCompilerTest.java +++ b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/AbstractCompilerTest.java @@ -20,6 +20,7 @@ import net.emustudio.emulib.plugins.compiler.CompilerListener; import net.emustudio.emulib.plugins.compiler.CompilerMessage; +import net.emustudio.emulib.plugins.memory.annotations.Annotations; import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.ContextPool; import net.emustudio.emulib.runtime.settings.PluginSettings; @@ -32,6 +33,7 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.StandardOpenOption; +import java.util.Optional; import static org.easymock.EasyMock.*; import static org.junit.Assert.assertEquals; @@ -42,10 +44,11 @@ public abstract class AbstractCompilerTest { public TemporaryFolder folder = new TemporaryFolder(); protected CompilerRAM compiler; protected MemoryStub memoryStub; + private int errorCount; @Before public void setUp() throws Exception { - memoryStub = new MemoryStub(); + memoryStub = new MemoryStub(new Annotations()); ContextPool pool = createNiceMock(ContextPool.class); expect(pool.getMemoryContext(0, RamMemoryContext.class)).andReturn(memoryStub).anyTimes(); @@ -55,6 +58,7 @@ public void setUp() throws Exception { expect(applicationApi.getContextPool()).andReturn(pool).anyTimes(); replay(applicationApi); + errorCount = 0; compiler = new CompilerRAM(0L, applicationApi, PluginSettings.UNAVAILABLE); compiler.initialize(); compiler.addCompilerListener(new CompilerListener() { @@ -68,6 +72,9 @@ public void onMessage(CompilerMessage compilerMessage) { if (compilerMessage.getMessageType() != CompilerMessage.MessageType.TYPE_INFO) { System.out.println(compilerMessage); } + if (compilerMessage.getMessageType() == CompilerMessage.MessageType.TYPE_ERROR) { + errorCount++; + } } @Override @@ -82,8 +89,9 @@ protected void compile(String content) throws Exception { Files.write(sourceFile.toPath(), content.getBytes(), StandardOpenOption.WRITE); File outputFile = folder.newFile(); - if (!compiler.compile(sourceFile.getAbsolutePath(), outputFile.getAbsolutePath())) { - throw new Exception("Compilation failed"); + compiler.compile(sourceFile.toPath(), Optional.of(outputFile.toPath())); + if (errorCount > 0) { + throw new Exception("Compilation failed with " + errorCount + " errors"); } } diff --git a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/CompilerTest.java b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/CompilerTest.java index 62baf7460..3f10a19d9 100644 --- a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/CompilerTest.java +++ b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/CompilerTest.java @@ -219,7 +219,7 @@ public void testCompileWithoutSpecifyingOutputDoesNotOverwriteSource() throws Ex File sourceFile = folder.newFile("test-ram.ram"); Files.write(sourceFile.toPath(), "HALT".getBytes(), StandardOpenOption.WRITE); - tmpCompiler.compile(sourceFile.getPath()); + tmpCompiler.compile(sourceFile.toPath(), Optional.empty()); assertTrue(sourceFile.getParentFile().toPath().resolve("test-ram.bram").toFile().exists()); } diff --git a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java index 65b366ad7..474a4b84b 100644 --- a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java +++ b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java @@ -19,6 +19,7 @@ package net.emustudio.plugins.compiler.ram; import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import net.emustudio.plugins.memory.ram.api.RamInstruction; import net.emustudio.plugins.memory.ram.api.RamLabel; import net.emustudio.plugins.memory.ram.api.RamMemoryContext; @@ -31,6 +32,10 @@ public class MemoryStub extends AbstractMemoryContext implements private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + protected MemoryStub(MemoryContextAnnotations annotations) { + super(annotations); + } + @Override public RamInstruction read(int address) { return memory[address]; @@ -52,7 +57,7 @@ public void write(int address, RamInstruction[] instructions, int count) { } @Override - public Class getDataType() { + public Class getCellTypeClass() { return RamInstruction.class; } diff --git a/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/CompilerRASP.java b/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/CompilerRASP.java index 039f7d8cb..754737c00 100644 --- a/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/CompilerRASP.java +++ b/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/CompilerRASP.java @@ -40,10 +40,9 @@ import java.io.FileReader; import java.io.Reader; +import java.nio.file.Path; import java.util.*; -import static net.emustudio.emulib.plugins.compiler.FileExtension.stripKnownExtension; - @PluginRoot( type = PLUGIN_TYPE.COMPILER, title = "RASP Machine Assembler" @@ -72,12 +71,13 @@ public void initialize() { } @Override - public boolean compile(String inputFileName, String outputFileName) { + public void compile(Path inputPath, Optional outputPathX) { try { this.notifyCompileStart(); notifyInfo(getTitle() + ", version " + getVersion()); - try (Reader reader = new FileReader(inputFileName)) { + Path finalOutputPath = outputPathX.orElse(convertInputToOutputPath(inputPath, ".brasp")); + try (Reader reader = new FileReader(inputPath.toFile())) { org.antlr.v4.runtime.Lexer lexer = createLexer(CharStreams.fromReader(reader)); lexer.addErrorListener(new ParserErrorListener()); CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -89,14 +89,14 @@ public boolean compile(String inputFileName, String outputFileName) { new ProgramParser(program).visit(parser.rStart()); Map compiled = program.compile(); - program.saveToFile(outputFileName, compiled); + program.saveToFile(finalOutputPath, compiled); int programLocation = program.getProgramLocation(compiled); applicationApi.setProgramLocation(programLocation); notifyInfo(String.format( "Compile was successful.\n\tOutput: %s\n\tProgram starts at 0x%s", - outputFileName, RadixUtils.formatWordHexString(programLocation) + finalOutputPath, RadixUtils.formatWordHexString(programLocation) )); if (memory != null) { @@ -111,17 +111,9 @@ public boolean compile(String inputFileName, String outputFileName) { } catch (Exception e) { LOGGER.trace("Compilation failed", e); notifyError("Compilation failed: " + e.getMessage()); - return false; } finally { notifyCompileFinish(); } - return true; - } - - @Override - public boolean compile(String inputFileName) { - String outputFileName = stripKnownExtension(inputFileName, SOURCE_FILE_EXTENSIONS) + ".brasp"; - return compile(inputFileName, outputFileName); } @Override diff --git a/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/Runner.java b/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/Runner.java index 354980f4f..6ccb8f3f1 100644 --- a/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/Runner.java +++ b/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/Runner.java @@ -24,6 +24,9 @@ import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.settings.PluginSettings; +import java.nio.file.Path; +import java.util.Optional; + public class Runner { public static void main(String... args) { @@ -50,15 +53,6 @@ public static void main(String... args) { return; } inputFile = args[i]; - if (outputFile == null) { - int index = inputFile.lastIndexOf('.'); - if (index != -1) { - outputFile = inputFile.substring(0, index); - } else { - outputFile = inputFile; - } - outputFile += ".brasp"; - } CompilerRASP compiler = new CompilerRASP(0L, ApplicationApi.UNAVAILABLE, PluginSettings.UNAVAILABLE); compiler.addCompilerListener(new CompilerListener() { @@ -78,7 +72,7 @@ public void onFinish() { }); try { - compiler.compile(inputFile, outputFile); + compiler.compile(Path.of(inputFile), Optional.ofNullable(outputFile).map(Path::of)); } catch (Exception e) { System.err.println(e.getMessage()); } diff --git a/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/ast/Program.java b/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/ast/Program.java index 5b4e272aa..85f3908ff 100644 --- a/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/ast/Program.java +++ b/plugins/compiler/raspc-rasp/src/main/java/net/emustudio/plugins/compiler/rasp/ast/Program.java @@ -23,6 +23,7 @@ import net.emustudio.plugins.memory.rasp.api.RaspMemoryContext; import java.io.*; +import java.nio.file.Path; import java.util.*; import static net.emustudio.plugins.memory.rasp.gui.Disassembler.READ; @@ -77,7 +78,7 @@ public void loadIntoMemory(RaspMemoryContext memory, Map compi } } - public void saveToFile(String filename, Map compiled) throws IOException { + public void saveToFile(Path filename, Map compiled) throws IOException { RaspMemoryContext.serialize(filename, getProgramLocation(compiled), new RaspMemoryContext.RaspMemory( this.labels.values(), compiled, inputs )); diff --git a/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/AbstractCompilerTest.java b/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/AbstractCompilerTest.java index e0eb2cc5f..42da4a0e0 100644 --- a/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/AbstractCompilerTest.java +++ b/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/AbstractCompilerTest.java @@ -20,6 +20,7 @@ import net.emustudio.emulib.plugins.compiler.CompilerListener; import net.emustudio.emulib.plugins.compiler.CompilerMessage; +import net.emustudio.emulib.plugins.memory.annotations.Annotations; import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.ContextPool; import net.emustudio.emulib.runtime.settings.PluginSettings; @@ -31,6 +32,7 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.StandardOpenOption; +import java.util.Optional; import static org.easymock.EasyMock.*; import static org.junit.Assert.assertEquals; @@ -41,10 +43,11 @@ public abstract class AbstractCompilerTest { public TemporaryFolder folder = new TemporaryFolder(); protected CompilerRASP compiler; protected MemoryStub memoryStub; + private int errorCount; @Before public void setUp() throws Exception { - memoryStub = new MemoryStub(); + memoryStub = new MemoryStub(new Annotations()); ContextPool pool = createNiceMock(ContextPool.class); expect(pool.getMemoryContext(0, RaspMemoryContext.class)).andReturn(memoryStub).anyTimes(); @@ -54,15 +57,8 @@ public void setUp() throws Exception { expect(applicationApi.getContextPool()).andReturn(pool).anyTimes(); replay(applicationApi); + errorCount = 0; compiler = new CompilerRASP(0L, applicationApi, PluginSettings.UNAVAILABLE); - compiler.initialize(); - } - - protected void compile(String content) throws Exception { - File sourceFile = folder.newFile(); - Files.write(sourceFile.toPath(), content.getBytes(), StandardOpenOption.WRITE); - - File outputFile = folder.newFile(); compiler.addCompilerListener(new CompilerListener() { @Override public void onStart() { @@ -72,6 +68,9 @@ public void onStart() { @Override public void onMessage(CompilerMessage compilerMessage) { System.out.println(compilerMessage); + if (compilerMessage.getMessageType() == CompilerMessage.MessageType.TYPE_ERROR) { + errorCount++; + } } @Override @@ -79,8 +78,17 @@ public void onFinish() { } }); - if (!compiler.compile(sourceFile.getAbsolutePath(), outputFile.getAbsolutePath())) { - throw new Exception("Compilation failed"); + compiler.initialize(); + } + + protected void compile(String content) throws Exception { + File sourceFile = folder.newFile(); + Files.write(sourceFile.toPath(), content.getBytes(), StandardOpenOption.WRITE); + + File outputFile = folder.newFile(); + compiler.compile(sourceFile.toPath(), Optional.of(outputFile.toPath())); + if (errorCount > 0) { + throw new Exception("Compilation failed with " + errorCount + " errors"); } } diff --git a/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java b/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java index e380119e2..60d2f5534 100644 --- a/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java +++ b/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java @@ -19,6 +19,7 @@ package net.emustudio.plugins.compiler.rasp; import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import net.emustudio.plugins.memory.rasp.api.RaspLabel; import net.emustudio.plugins.memory.rasp.api.RaspMemoryContext; @@ -29,6 +30,10 @@ public class MemoryStub extends AbstractMemoryContext implements RaspMe private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + protected MemoryStub(MemoryContextAnnotations annotations) { + super(annotations); + } + @Override public Integer read(int address) { return memory[address]; diff --git a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/DefaultInitializer.java b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/DefaultInitializer.java index 09d1c4244..9a9851558 100644 --- a/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/DefaultInitializer.java +++ b/plugins/cpu/8080-cpu/src/main/java/net/emustudio/plugins/cpu/intel8080/api/DefaultInitializer.java @@ -60,9 +60,10 @@ public DefaultInitializer(Plugin plugin, long pluginId, ContextPool contextPool, public final void initialize() throws PluginInitializationException { try { MemoryContext memory = contextPool.getMemoryContext(pluginId, MemoryContext.class); - if (memory.getDataType() != Byte.class) { + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { throw new InvalidContextException( - "Unexpected memory cell type. Expected Byte but was: " + memory.getDataType() + "Unexpected memory cell type. Expected Byte but was: " + cellTypeClass ); } diff --git a/plugins/cpu/brainduck-cpu/src/test/java/net/emustudio/plugins/cpu/brainduck/MemoryStub.java b/plugins/cpu/brainduck-cpu/src/test/java/net/emustudio/plugins/cpu/brainduck/MemoryStub.java index 63078fc01..c295fb8e3 100644 --- a/plugins/cpu/brainduck-cpu/src/test/java/net/emustudio/plugins/cpu/brainduck/MemoryStub.java +++ b/plugins/cpu/brainduck-cpu/src/test/java/net/emustudio/plugins/cpu/brainduck/MemoryStub.java @@ -20,6 +20,7 @@ import net.emustudio.emulib.plugins.annotations.PluginContext; import net.emustudio.emulib.plugins.memory.Memory; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import net.emustudio.plugins.memory.bytemem.api.ByteMemoryContext; import java.util.Arrays; @@ -103,11 +104,11 @@ public void clear() { } @Override - public void addMemoryListener(Memory.MemoryListener listener) { + public void addMemoryListener(MemoryListener listener) { } @Override - public void removeMemoryListener(Memory.MemoryListener listener) { + public void removeMemoryListener(MemoryListener listener) { } @Override @@ -120,6 +121,11 @@ public boolean areMemoryNotificationsEnabled() { return false; } + @Override + public MemoryContextAnnotations annotations() { + return null; + } + @Override public void setMemoryNotificationsEnabled(boolean enabled) { } @@ -146,7 +152,7 @@ public void write(int memoryPosition, Byte[] cells, int count) { } @Override - public Class getDataType() { + public Class getCellTypeClass() { return null; } } diff --git a/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/EmulatorEngineTest.java b/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/EmulatorEngineTest.java index 19766facb..454a0fe28 100644 --- a/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/EmulatorEngineTest.java +++ b/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/EmulatorEngineTest.java @@ -19,6 +19,7 @@ package net.emustudio.plugins.cpu.rasp; import net.emustudio.emulib.plugins.cpu.CPU; +import net.emustudio.emulib.plugins.memory.annotations.Annotations; import net.emustudio.plugins.cpu.rasp.api.RaspCpuContext; import net.emustudio.plugins.device.abstracttape.api.AbstractTapeContext; import net.emustudio.plugins.memory.rasp.api.RaspLabel; @@ -74,7 +75,7 @@ private EmulatorEngine setup(List memoryContent, List labels expect(context.getInputTape()).andReturn(inputTape).anyTimes(); replay(context); - MemoryStub memory = new MemoryStub(); + MemoryStub memory = new MemoryStub(new Annotations()); memory.setLabels(labels); int address = 0; for (int item : memoryContent) { diff --git a/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java b/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java index 049f5a4cc..26a7d0aee 100644 --- a/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java +++ b/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java @@ -19,6 +19,7 @@ package net.emustudio.plugins.cpu.rasp; import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import net.emustudio.plugins.memory.rasp.api.RaspLabel; import net.emustudio.plugins.memory.rasp.api.RaspMemoryContext; @@ -29,6 +30,10 @@ public class MemoryStub extends AbstractMemoryContext implements RaspMe private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + protected MemoryStub(MemoryContextAnnotations annotations) { + super(annotations); + } + @Override public Integer read(int address) { return memory[address]; @@ -50,7 +55,7 @@ public void write(int address, Integer[] instructions, int count) { } @Override - public Class getDataType() { + public Class getCellTypeClass() { return Integer.class; } diff --git a/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/CpuImpl.java b/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/CpuImpl.java index f002ab7da..e812d39e8 100644 --- a/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/CpuImpl.java +++ b/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/CpuImpl.java @@ -63,9 +63,10 @@ public CpuImpl(long pluginID, ApplicationApi applicationApi, PluginSettings sett @Override public void initialize() throws PluginInitializationException { memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); - if (memory.getDataType() != Byte.class) { + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { throw new PluginInitializationException( - "Unexpected memory cell type. Expected Byte but was: " + memory.getDataType() + "Unexpected memory cell type. Expected Byte but was: " + cellTypeClass ); } Decoder decoder = new DecoderImpl(memory); diff --git a/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java b/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java index 72d762e39..c9f276ca2 100644 --- a/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java +++ b/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java @@ -20,6 +20,7 @@ import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.Annotations; import net.emustudio.emulib.runtime.helpers.NumberUtils; import java.util.Arrays; @@ -61,7 +62,7 @@ public class TimingEstimator { 0x3F, 0xFF, 0xE0, 0x50 }; - private final MemoryContext memoryContext = new AbstractMemoryContext<>() { + private final MemoryContext memoryContext = new AbstractMemoryContext<>(new Annotations()) { @Override public Byte read(int position) { @@ -84,7 +85,7 @@ public void write(int position, Byte[] bytes, int length) { } @Override - public Class getDataType() { + public Class getCellTypeClass() { return Byte.class; } diff --git a/plugins/device/ssem-display/src/main/java/net/emustudio/plugins/device/ssem/display/DeviceImpl.java b/plugins/device/ssem-display/src/main/java/net/emustudio/plugins/device/ssem/display/DeviceImpl.java index 7ea8cb371..681463813 100644 --- a/plugins/device/ssem-display/src/main/java/net/emustudio/plugins/device/ssem/display/DeviceImpl.java +++ b/plugins/device/ssem-display/src/main/java/net/emustudio/plugins/device/ssem/display/DeviceImpl.java @@ -51,9 +51,10 @@ public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings s @Override public void initialize() throws PluginInitializationException { memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); - if (memory.getDataType() != Byte.class) { + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { throw new PluginInitializationException( - "Unexpected memory cell type. Expected Byte but was: " + memory.getDataType() + "Unexpected memory cell type. Expected Byte but was: " + cellTypeClass ); } } diff --git a/plugins/device/ssem-display/src/main/java/net/emustudio/plugins/device/ssem/display/DisplayGui.java b/plugins/device/ssem-display/src/main/java/net/emustudio/plugins/device/ssem/display/DisplayGui.java index dc2013b4d..250198fc7 100644 --- a/plugins/device/ssem-display/src/main/java/net/emustudio/plugins/device/ssem/display/DisplayGui.java +++ b/plugins/device/ssem-display/src/main/java/net/emustudio/plugins/device/ssem/display/DisplayGui.java @@ -18,7 +18,6 @@ */ package net.emustudio.plugins.device.ssem.display; -import net.emustudio.emulib.plugins.memory.Memory; import net.emustudio.emulib.plugins.memory.MemoryContext; import javax.swing.*; @@ -44,15 +43,17 @@ class DisplayGui extends JDialog { } private void initListener() { - memory.addMemoryListener(new Memory.MemoryListener() { + memory.addMemoryListener(new MemoryContext.MemoryListener() { @Override - public void memoryChanged(int bytePosition) { - if (bytePosition == -1) { + public void memoryContentChanged(int fromLocation, int toLocation) { + if (fromLocation == -1) { displayPanel.reset(memory); } else { - int row = bytePosition / 4; - int rowBytePosition = row * 4; - displayPanel.writeRow(memory.read(rowBytePosition, 4), row); + for (int location = fromLocation; location <= toLocation; location++) { + int row = location / 4; + int rowBytePosition = row * 4; + displayPanel.writeRow(memory.read(rowBytePosition, 4), row); + } } } diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java index 5c16b014e..be9001985 100644 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java @@ -73,7 +73,8 @@ public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings s @Override public void initialize() throws PluginInitializationException { MemoryContext memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); - if (memory.getDataType() != Byte.class) { + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { throw new PluginInitializationException("Could not find Byte-cell memory"); } Context8080 cpu = applicationApi.getContextPool().getCPUContext(pluginID, Context8080.class); diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java index fd8e2b666..ddfed6105 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java @@ -20,6 +20,7 @@ import net.emustudio.emulib.plugins.annotations.PluginContext; import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import net.emustudio.plugins.memory.bytemem.api.ByteMemoryContext; import java.util.Arrays; @@ -35,6 +36,10 @@ public class MemoryContextImpl extends AbstractMemoryContext implements By private int bankSelect = 0; private int bankCommon = 0; + protected MemoryContextImpl(MemoryContextAnnotations annotations) { + super(annotations); + } + void init(int size, int banks, int bankCommon) { if (banks <= 0) { throw new IllegalArgumentException("Number of banks must be >= 1!"); @@ -51,7 +56,7 @@ public void clear() { for (Byte[] bank : mem) { Arrays.fill(bank, (byte) 0); } - notifyMemoryChanged(-1); + notifyMemoryContentChanged(-1); } void destroy() { @@ -107,7 +112,7 @@ public Byte[] read(int from, int count) { public void write(int to, Byte value) { if (!isReadOnly(to)) { mem[bank(to)][to] = value; - notifyMemoryChanged(to); + notifyMemoryContentChanged(to); } } @@ -115,21 +120,19 @@ public void writeBank(int to, byte val, int bank) { if (!isReadOnly(to)) { int activeBank = (to < bankCommon) ? bank : 0; mem[activeBank][to] = val; - notifyMemoryChanged(to); + notifyMemoryContentChanged(to); } } public void write(int to, Byte[] values, int count) { if (!romRanges.intersects(to, to + count)) { System.arraycopy(values, 0, mem[bank(to)], to, count); - for (int i = 0; i < values.length; i++) { - notifyMemoryChanged(to + i); - } + notifyMemoryContentChanged(to, to + values.length); } } @Override - public Class getDataType() { + public Class getCellTypeClass() { return Byte.class; } diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryImpl.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryImpl.java index 353dd2a4e..cf2c1bade 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryImpl.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryImpl.java @@ -51,13 +51,14 @@ public class MemoryImpl extends AbstractMemory { private final static Logger LOGGER = LoggerFactory.getLogger(MemoryImpl.class); - private final MemoryContextImpl context = new MemoryContextImpl(); + private final MemoryContextImpl context; private final boolean guiNotSupported; private MemoryGui gui; public MemoryImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { super(pluginID, applicationApi, settings); + this.context = new MemoryContextImpl(getAnnotations()); this.guiNotSupported = settings.getBoolean(PluginSettings.EMUSTUDIO_NO_GUI, false); try { ContextPool contextPool = applicationApi.getContextPool(); @@ -95,11 +96,6 @@ public void destroy() { context.destroy(); } - @Override - public int getSize() { - return context.getSize(); - } - @Override public void initialize() throws PluginInitializationException { try { @@ -236,4 +232,9 @@ private Optional getResourceBundle() { return Optional.empty(); } } + + @Override + public int getSize() { + return context.getSize(); + } } diff --git a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java index 749f4c67d..9bda7f9f3 100644 --- a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java +++ b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java @@ -19,6 +19,8 @@ package net.emustudio.plugins.memory.ram; import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; +import net.emustudio.emulib.runtime.helpers.ReadWriteLockSupport; import net.emustudio.plugins.memory.ram.api.RamInstruction; import net.emustudio.plugins.memory.ram.api.RamLabel; import net.emustudio.plugins.memory.ram.api.RamMemoryContext; @@ -27,41 +29,42 @@ import java.io.*; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Supplier; public class MemoryContextImpl extends AbstractMemoryContext implements RamMemoryContext { private final Map memory = new HashMap<>(); private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); - private final ReadWriteLock rwl = new ReentrantReadWriteLock(); + private final ReadWriteLockSupport rwl = new ReadWriteLockSupport(); + + protected MemoryContextImpl(MemoryContextAnnotations annotations) { + super(annotations); + } @Override public void clear() { - writeLock(() -> { + rwl.lockWrite(() -> { memory.clear(); labels.clear(); inputs.clear(); }); - notifyMemoryChanged(-1); + notifyMemoryContentChanged(-1); notifyMemorySizeChanged(); } @Override public int getSize() { - return readLock(memory::size); + return rwl.lockRead(memory::size); } @Override public RamInstruction read(int address) { - return readLock(() -> memory.get(address)); + return rwl.lockRead(() -> memory.get(address)); } @Override public RamInstruction[] read(int address, int count) { List copy = new ArrayList<>(); - readLock(() -> { + rwl.lockRead(() -> { for (int i = address; i < address + count; i++) { copy.add(memory.get(i)); } @@ -72,20 +75,20 @@ public RamInstruction[] read(int address, int count) { @Override public void write(int address, RamInstruction value) { AtomicBoolean sizeChanged = new AtomicBoolean(); - writeLock(() -> { + rwl.lockWrite(() -> { sizeChanged.set(!memory.containsKey(address)); memory.put(address, value); }); if (sizeChanged.get()) { notifyMemorySizeChanged(); } - notifyMemoryChanged(address); + notifyMemoryContentChanged(address); } @Override public void write(int address, RamInstruction[] values, int count) { AtomicBoolean sizeChanged = new AtomicBoolean(); - writeLock(() -> { + rwl.lockWrite(() -> { for (int i = 0; i < count; i++) { sizeChanged.set(sizeChanged.get() || !memory.containsKey(address)); memory.put(address + i, values[i]); @@ -95,13 +98,13 @@ public void write(int address, RamInstruction[] values, int count) { notifyMemorySizeChanged(); } for (int i = 0; i < count; i++) { - notifyMemoryChanged(address + i); + notifyMemoryContentChanged(address + i); } } @Override public void setLabels(List labels) { - writeLock(() -> { + rwl.lockWrite(() -> { this.labels.clear(); for (RamLabel label : labels) { this.labels.put(label.getAddress(), label); @@ -116,48 +119,49 @@ public Optional getLabel(int address) { @Override public void setInputs(List inputs) { - writeLock(() -> { + rwl.lockWrite(() -> { this.inputs.clear(); this.inputs.addAll(inputs); }); } + // Do not remove IOException, ClassNotFoundException @SuppressWarnings("unchecked") public void deserialize(String filename) throws IOException, ClassNotFoundException { - rwl.writeLock().lock(); - try { - InputStream file = new FileInputStream(filename); - InputStream buffer = new BufferedInputStream(file); - ObjectInput input = new ObjectInputStream(buffer); - - labels.clear(); - inputs.clear(); - memory.clear(); - - Map rawLabels = (Map) input.readObject(); - for (Map.Entry rawLabel : rawLabels.entrySet()) { - this.labels.put(rawLabel.getKey(), new RamLabel() { - @Override - public int getAddress() { - return rawLabel.getKey(); - } - - @Override - public String getLabel() { - return rawLabel.getValue(); - } - }); + rwl.lockWrite(() -> { + try { + InputStream file = new FileInputStream(filename); + InputStream buffer = new BufferedInputStream(file); + ObjectInput input = new ObjectInputStream(buffer); + + labels.clear(); + inputs.clear(); + memory.clear(); + + Map rawLabels = (Map) input.readObject(); + for (Map.Entry rawLabel : rawLabels.entrySet()) { + this.labels.put(rawLabel.getKey(), new RamLabel() { + @Override + public int getAddress() { + return rawLabel.getKey(); + } + + @Override + public String getLabel() { + return rawLabel.getValue(); + } + }); + } + + inputs.addAll((List) input.readObject()); + memory.putAll((Map) input.readObject()); + + input.close(); + } finally { + notifyMemoryContentChanged(-1); + notifyMemorySizeChanged(); } - - inputs.addAll((List) input.readObject()); - memory.putAll((Map) input.readObject()); - - input.close(); - } finally { - rwl.writeLock().unlock(); - notifyMemoryChanged(-1); - notifyMemorySizeChanged(); - } + }); } public void destroy() { @@ -166,33 +170,6 @@ public void destroy() { @Override public RamMemory getSnapshot() { - return readLock(() -> new RamMemory(labels.values(), memory, inputs)); - } - - private void writeLock(Runnable r) { - rwl.writeLock().lock(); - try { - r.run(); - } finally { - rwl.writeLock().unlock(); - } - } - - private T readLock(Supplier r) { - rwl.readLock().lock(); - try { - return r.get(); - } finally { - rwl.readLock().unlock(); - } - } - - private void readLock(Runnable r) { - rwl.readLock().lock(); - try { - r.run(); - } finally { - rwl.readLock().unlock(); - } + return rwl.lockRead(() -> new RamMemory(labels.values(), memory, inputs)); } } diff --git a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryImpl.java b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryImpl.java index cb7512a2d..c692f535f 100644 --- a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryImpl.java +++ b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryImpl.java @@ -47,7 +47,7 @@ public MemoryImpl(long pluginID, ApplicationApi applicationApi, PluginSettings s ContextPool contextPool = applicationApi.getContextPool(); this.guiNotSupported = settings.getBoolean(PluginSettings.EMUSTUDIO_NO_GUI, false); - context = new MemoryContextImpl(); + context = new MemoryContextImpl(getAnnotations()); try { contextPool.register(pluginID, context, RamMemoryContext.class); contextPool.register(pluginID, context, MemoryContext.class); @@ -71,11 +71,6 @@ public String getDescription() { return "Read-only program tape for abstract RAM machine."; } - @Override - public int getSize() { - return context.getSize(); - } - @Override public void showSettings(JFrame parent) { if (!guiNotSupported) { @@ -107,4 +102,9 @@ private Optional getResourceBundle() { return Optional.empty(); } } + + @Override + public int getSize() { + return context.getSize(); + } } diff --git a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/api/RamMemoryContext.java b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/api/RamMemoryContext.java index 6d7bacce0..a459df23d 100644 --- a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/api/RamMemoryContext.java +++ b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/api/RamMemoryContext.java @@ -24,6 +24,7 @@ import net.jcip.annotations.ThreadSafe; import java.io.*; +import java.nio.file.Path; import java.util.*; @ThreadSafe @@ -31,7 +32,7 @@ public interface RamMemoryContext extends MemoryContext { @Override - default Class getDataType() { + default Class getCellTypeClass() { return RamInstruction.class; } @@ -43,13 +44,13 @@ default Class getDataType() { RamMemory getSnapshot(); - static void serialize(String filename, RamMemory memory) throws IOException { + static void serialize(Path filename, RamMemory memory) throws IOException { Map labels = new HashMap<>(); for (RamLabel label : memory.labels) { labels.put(label.getAddress(), label.getLabel()); } - OutputStream file = new FileOutputStream(filename); + OutputStream file = new FileOutputStream(filename.toFile()); OutputStream buffer = new BufferedOutputStream(file); try (ObjectOutput output = new ObjectOutputStream(buffer)) { output.writeObject(labels); diff --git a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/gui/actions/DumpMemoryAction.java b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/gui/actions/DumpMemoryAction.java index e94007f77..0d2cfe878 100644 --- a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/gui/actions/DumpMemoryAction.java +++ b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/gui/actions/DumpMemoryAction.java @@ -71,7 +71,7 @@ public void actionPerformed(ActionEvent e) { } } } else { - RamMemoryContext.serialize(path.toString(), context.getSnapshot()); + RamMemoryContext.serialize(path, context.getSnapshot()); } } catch (IOException ex) { LOGGER.error("Memory dump could not be created", ex); diff --git a/plugins/memory/ram-mem/src/test/java/net/emustudio/plugins/memory/ram/MemoryContextImplTest.java b/plugins/memory/ram-mem/src/test/java/net/emustudio/plugins/memory/ram/MemoryContextImplTest.java index 797957aaf..0b546bd12 100644 --- a/plugins/memory/ram-mem/src/test/java/net/emustudio/plugins/memory/ram/MemoryContextImplTest.java +++ b/plugins/memory/ram-mem/src/test/java/net/emustudio/plugins/memory/ram/MemoryContextImplTest.java @@ -18,7 +18,8 @@ */ package net.emustudio.plugins.memory.ram; -import net.emustudio.emulib.plugins.memory.Memory; +import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.Annotations; import net.emustudio.plugins.memory.ram.api.RamInstruction; import org.junit.Before; import org.junit.Test; @@ -35,7 +36,7 @@ public class MemoryContextImplTest { @Before public void setUp() { - this.memory = new MemoryContextImpl(); + this.memory = new MemoryContextImpl(new Annotations()); } @Test @@ -48,9 +49,9 @@ public void testNotifyMemoryChangesOnWrite() { AtomicInteger memoryChanges = new AtomicInteger(); AtomicInteger memorySizeChanges = new AtomicInteger(); - memory.addMemoryListener(new Memory.MemoryListener() { + memory.addMemoryListener(new MemoryContext.MemoryListener() { @Override - public void memoryChanged(int memoryPosition) { + public void memoryContentChanged(int from, int to) { memoryChanges.incrementAndGet(); } @@ -72,9 +73,9 @@ public void testNotifyMemoryChangesOnWrite2() { AtomicInteger memoryChanges = new AtomicInteger(); AtomicInteger memorySizeChanges = new AtomicInteger(); - memory.addMemoryListener(new Memory.MemoryListener() { + memory.addMemoryListener(new MemoryContext.MemoryListener() { @Override - public void memoryChanged(int memoryPosition) { + public void memoryContentChanged(int from, int to) { memoryChanges.incrementAndGet(); } @@ -95,9 +96,9 @@ public void testMemoryChangesAreNotNotifiedOnRead() { AtomicInteger memoryChanges = new AtomicInteger(); AtomicInteger memorySizeChanges = new AtomicInteger(); - memory.addMemoryListener(new Memory.MemoryListener() { + memory.addMemoryListener(new MemoryContext.MemoryListener() { @Override - public void memoryChanged(int memoryPosition) { + public void memoryContentChanged(int from, int to) { memoryChanges.incrementAndGet(); } diff --git a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java index 295f687e2..171a0c842 100644 --- a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java +++ b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java @@ -21,6 +21,8 @@ package net.emustudio.plugins.memory.rasp; import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; +import net.emustudio.emulib.runtime.helpers.ReadWriteLockSupport; import net.emustudio.plugins.memory.rasp.api.RaspLabel; import net.emustudio.plugins.memory.rasp.api.RaspMemoryContext; @@ -36,33 +38,37 @@ public class MemoryContextImpl extends AbstractMemoryContext implements private final Map memory = new HashMap<>(); private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); - private final ReadWriteLock rwl = new ReentrantReadWriteLock(); + private final ReadWriteLockSupport rwl = new ReadWriteLockSupport(); + + protected MemoryContextImpl(MemoryContextAnnotations annotations) { + super(annotations); + } @Override public void clear() { - writeLock(() -> { + rwl.lockWrite(() -> { memory.clear(); labels.clear(); inputs.clear(); }); - notifyMemoryChanged(-1); + notifyMemoryContentChanged(-1); notifyMemorySizeChanged(); } @Override public int getSize() { - return readLock(() -> memory.keySet().stream().max(Comparator.naturalOrder()).orElse(0)); + return rwl.lockRead(() -> memory.keySet().stream().max(Comparator.naturalOrder()).orElse(0)); } @Override public Integer read(int address) { - return readLock(() -> memory.getOrDefault(address, 0)); + return rwl.lockRead(() -> memory.getOrDefault(address, 0)); } @Override public Integer[] read(int address, int count) { List copy = new ArrayList<>(); - readLock(() -> { + rwl.lockRead(() -> { for (int i = address; i < address + count; i++) { copy.add(memory.getOrDefault(i, 0)); } @@ -73,20 +79,20 @@ public Integer[] read(int address, int count) { @Override public void write(int address, Integer value) { AtomicBoolean sizeChanged = new AtomicBoolean(); - writeLock(() -> { + rwl.lockWrite(() -> { sizeChanged.set(!memory.containsKey(address)); memory.put(address, value); }); if (sizeChanged.get()) { notifyMemorySizeChanged(); } - notifyMemoryChanged(address); + notifyMemoryContentChanged(address); } @Override public void write(int address, Integer[] values, int count) { AtomicBoolean sizeChanged = new AtomicBoolean(); - writeLock(() -> { + rwl.lockWrite(() -> { for (int i = 0; i < count; i++) { sizeChanged.set(sizeChanged.get() || !memory.containsKey(address + i)); memory.put(address + i, values[i]); @@ -96,13 +102,13 @@ public void write(int address, Integer[] values, int count) { notifyMemorySizeChanged(); } for (int i = 0; i < count; i++) { - notifyMemoryChanged(address + i); + notifyMemoryContentChanged(address + i); } } @Override public void setLabels(List labels) { - writeLock(() -> { + rwl.lockWrite(() -> { this.labels.clear(); for (RaspLabel label : labels) { this.labels.put(label.getAddress(), label); @@ -112,94 +118,65 @@ public void setLabels(List labels) { @Override public Optional getLabel(int address) { - return readLock(() -> Optional.ofNullable(labels.get(address))); + return rwl.lockRead(() -> Optional.ofNullable(labels.get(address))); } @Override public void setInputs(List inputs) { - rwl.writeLock().lock(); - try { + rwl.lockWrite(() -> { this.inputs.clear(); this.inputs.addAll(inputs); - } finally { - rwl.writeLock().unlock(); - } + }); } @Override public RaspMemory getSnapshot() { - return readLock(() -> new RaspMemory(labels.values(), memory, inputs)); + return rwl.lockRead(() -> new RaspMemory(labels.values(), memory, inputs)); } + // Keep throws IOException, ClassNotFoundException due to lock sneaky throw @SuppressWarnings("unchecked") public void deserialize(String filename, Consumer setProgramLocation) throws IOException, ClassNotFoundException { - rwl.writeLock().lock(); - try { - InputStream file = new FileInputStream(filename); - InputStream buffer = new BufferedInputStream(file); - ObjectInput input = new ObjectInputStream(buffer); - - labels.clear(); - inputs.clear(); - memory.clear(); - - int programLocation = (Integer) input.readObject(); - setProgramLocation.accept(programLocation); - - Map rawLabels = (Map) input.readObject(); - for (Map.Entry rawLabel : rawLabels.entrySet()) { - this.labels.put(rawLabel.getKey(), new RaspLabel() { - @Override - public int getAddress() { - return rawLabel.getKey(); - } - - @Override - public String getLabel() { - return rawLabel.getValue(); - } - }); + rwl.lockWrite(() -> { + try { + InputStream file = new FileInputStream(filename); + InputStream buffer = new BufferedInputStream(file); + ObjectInput input = new ObjectInputStream(buffer); + + labels.clear(); + inputs.clear(); + memory.clear(); + + int programLocation = (Integer) input.readObject(); + setProgramLocation.accept(programLocation); + + Map rawLabels = (Map) input.readObject(); + for (Map.Entry rawLabel : rawLabels.entrySet()) { + this.labels.put(rawLabel.getKey(), new RaspLabel() { + @Override + public int getAddress() { + return rawLabel.getKey(); + } + + @Override + public String getLabel() { + return rawLabel.getValue(); + } + }); + } + + inputs.addAll((List) input.readObject()); + memory.putAll((Map) input.readObject()); + + input.close(); + } finally { + notifyMemorySizeChanged(); + notifyMemoryContentChanged(-1); } - - inputs.addAll((List) input.readObject()); - memory.putAll((Map) input.readObject()); - - input.close(); - } finally { - rwl.writeLock().unlock(); - notifyMemorySizeChanged(); - notifyMemoryChanged(-1); - } + }); } public void destroy() { clear(); } - - private void writeLock(Runnable r) { - rwl.writeLock().lock(); - try { - r.run(); - } finally { - rwl.writeLock().unlock(); - } - } - - private T readLock(Supplier r) { - rwl.readLock().lock(); - try { - return r.get(); - } finally { - rwl.readLock().unlock(); - } - } - - private void readLock(Runnable r) { - rwl.readLock().lock(); - try { - r.run(); - } finally { - rwl.readLock().unlock(); - } - } } diff --git a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryImpl.java b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryImpl.java index ebb79278d..213ba04e0 100644 --- a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryImpl.java +++ b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryImpl.java @@ -52,7 +52,7 @@ public class MemoryImpl extends AbstractMemory { public MemoryImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { super(pluginID, applicationApi, settings); - this.context = new MemoryContextImpl(); + this.context = new MemoryContextImpl(getAnnotations()); this.guiNotSupported = settings.getBoolean(PluginSettings.EMUSTUDIO_NO_GUI, false); Optional.ofNullable(applicationApi.getContextPool()).ifPresent(pool -> { @@ -68,11 +68,6 @@ public MemoryImpl(long pluginID, ApplicationApi applicationApi, PluginSettings s }); } - @Override - public int getSize() { - return context.getSize(); - } - @Override public void destroy() { context.destroy(); @@ -119,4 +114,9 @@ private Optional getResourceBundle() { return Optional.empty(); } } + + @Override + public int getSize() { + return context.getSize(); + } } diff --git a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/api/RaspMemoryContext.java b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/api/RaspMemoryContext.java index a310d6737..ae14919d3 100644 --- a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/api/RaspMemoryContext.java +++ b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/api/RaspMemoryContext.java @@ -27,6 +27,7 @@ import net.jcip.annotations.ThreadSafe; import java.io.*; +import java.nio.file.Path; import java.util.*; /** @@ -45,7 +46,8 @@ public interface RaspMemoryContext extends MemoryContext { RaspMemory getSnapshot(); - default Class getDataType() { + @Override + default Class getCellTypeClass() { return Integer.class; } @@ -57,13 +59,13 @@ default Optional disassembleMnemo(int opcode) { return Disassembler.disassembleMnemo(opcode); } - static void serialize(String filename, int programLocation, RaspMemory memory) throws IOException { + static void serialize(Path filename, int programLocation, RaspMemory memory) throws IOException { Map labels = new HashMap<>(); for (RaspLabel label : memory.labels) { labels.put(label.getAddress(), label.getLabel()); } - OutputStream file = new FileOutputStream(filename); + OutputStream file = new FileOutputStream(filename.toFile()); OutputStream buffer = new BufferedOutputStream(file); try (ObjectOutput output = new ObjectOutputStream(buffer)) { output.writeObject(programLocation); diff --git a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/gui/actions/DumpMemoryAction.java b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/gui/actions/DumpMemoryAction.java index 0ee8b4000..c93cda168 100644 --- a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/gui/actions/DumpMemoryAction.java +++ b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/gui/actions/DumpMemoryAction.java @@ -76,7 +76,7 @@ public void actionPerformed(ActionEvent e) { } } } else { - RaspMemoryContext.serialize(path.toString(), programLocation.get(), context.getSnapshot()); + RaspMemoryContext.serialize(path, programLocation.get(), context.getSnapshot()); } } catch (IOException ex) { LOGGER.error("Memory dump could not be created", ex); diff --git a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java index 5411f4efa..5e6c842be 100644 --- a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java +++ b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java @@ -19,6 +19,7 @@ package net.emustudio.plugins.memory.ssem; import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import java.util.Arrays; @@ -28,14 +29,15 @@ public class MemoryContextImpl extends AbstractMemoryContext { // byte type is atomic in JVM memory model private final Byte[] memory = new Byte[NUMBER_OF_CELLS]; - public MemoryContextImpl() { + public MemoryContextImpl(MemoryContextAnnotations annotations) { + super(annotations); Arrays.fill(memory, (byte) 0); } @Override public void clear() { Arrays.fill(memory, (byte) 0); - notifyMemoryChanged(-1); // notify that all memory has changed + notifyMemoryContentChanged(-1); // notify that all memory has changed } @Override @@ -52,19 +54,17 @@ public Byte[] read(int from, int count) { @Override public void write(int to, Byte value) { memory[to] = value; - notifyMemoryChanged(to); + notifyMemoryContentChanged(to); } @Override public void write(int to, Byte[] values, int count) { System.arraycopy(values, 0, memory, to, count); - for (int i = 0; i < values.length; i++) { - notifyMemoryChanged(to + i); - } + notifyMemoryContentChanged(to, to + values.length); } @Override - public Class getDataType() { + public Class getCellTypeClass() { return Byte.class; } diff --git a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryImpl.java b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryImpl.java index ef7b67eac..0c87b8c6f 100644 --- a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryImpl.java +++ b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryImpl.java @@ -43,16 +43,17 @@ public class MemoryImpl extends AbstractMemory { private final static Logger LOGGER = LoggerFactory.getLogger(MemoryImpl.class); - private final MemoryContextImpl memContext = new MemoryContextImpl(); + private final MemoryContextImpl context; private final boolean guiNotSupported; private MemoryGui memoryGUI; public MemoryImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { super(pluginID, applicationApi, settings); + this.context = new MemoryContextImpl(getAnnotations()); this.guiNotSupported = settings.getBoolean(PluginSettings.EMUSTUDIO_NO_GUI, false); try { - applicationApi.getContextPool().register(pluginID, memContext, MemoryContext.class); + applicationApi.getContextPool().register(pluginID, context, MemoryContext.class); } catch (InvalidContextException | ContextAlreadyRegisteredException e) { LOGGER.error("Could not register SSEM memory context", e); applicationApi.getDialogs().showError( @@ -80,16 +81,11 @@ public String getDescription() { public void destroy() { } - @Override - public int getSize() { - return MemoryContextImpl.NUMBER_OF_CELLS; - } - @Override public void showSettings(JFrame parent) { if (!guiNotSupported) { if (memoryGUI == null) { - memoryGUI = new MemoryGui(parent, memContext, applicationApi); + memoryGUI = new MemoryGui(parent, context, applicationApi); } memoryGUI.setVisible(true); } @@ -107,4 +103,9 @@ private Optional getResourceBundle() { return Optional.empty(); } } + + @Override + public int getSize() { + return context.getSize(); + } } diff --git a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/gui/MemoryGui.java b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/gui/MemoryGui.java index 732c5449f..86654306d 100644 --- a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/gui/MemoryGui.java +++ b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/gui/MemoryGui.java @@ -18,7 +18,6 @@ */ package net.emustudio.plugins.memory.ssem.gui; -import net.emustudio.emulib.plugins.memory.Memory; import net.emustudio.emulib.plugins.memory.MemoryContext; import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.interaction.ToolbarButton; @@ -92,11 +91,11 @@ private void initComponents() { pack(); } - private class MemoryListenerImpl implements Memory.MemoryListener { + private class MemoryListenerImpl implements MemoryContext.MemoryListener { @Override - public void memoryChanged(int memoryPosition) { - tableModel.dataChangedAt(memoryPosition); + public void memoryContentChanged(int fromLocation, int toLocation) { + tableModel.dataChangedAt(fromLocation, toLocation); } @Override diff --git a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/gui/table/MemoryTableModel.java b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/gui/table/MemoryTableModel.java index 75dfca5b2..a0dc304a7 100644 --- a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/gui/table/MemoryTableModel.java +++ b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/gui/table/MemoryTableModel.java @@ -195,10 +195,12 @@ public boolean isCellEditable(int rowIndex, int columnIndex) { return columnIndex >= 0 && columnIndex <= 34; } - public void dataChangedAt(int address) { - int row = address / 4; - for (int i = 0; i < COLUMN_COUNT; i++) { - fireTableCellUpdated(row, i); + public void dataChangedAt(int fromAddress, int toAddress) { + for (int address = fromAddress; address <= toAddress; address++) { + int row = address / 4; + for (int i = 0; i < COLUMN_COUNT; i++) { + fireTableCellUpdated(row, i); + } } } } diff --git a/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/MemoryContextImplTest.java b/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/MemoryContextImplTest.java index 98b3e8adf..22f5fb97f 100644 --- a/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/MemoryContextImplTest.java +++ b/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/MemoryContextImplTest.java @@ -18,7 +18,8 @@ */ package net.emustudio.plugins.memory.ssem; -import net.emustudio.emulib.plugins.memory.Memory; +import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.Annotations; import org.junit.Test; import static org.easymock.EasyMock.*; @@ -29,10 +30,10 @@ public class MemoryContextImplTest { @Test public void testAfterClearObserversAreNotified() { - MemoryContextImpl context = new MemoryContextImpl(); + MemoryContextImpl context = new MemoryContextImpl(new Annotations()); - Memory.MemoryListener listener = createMock(Memory.MemoryListener.class); - listener.memoryChanged(eq(-1)); + MemoryContext.MemoryListener listener = createMock(MemoryContext.MemoryListener.class); + listener.memoryContentChanged(eq(-1), eq(-1)); expectLastCall().once(); replay(listener); @@ -44,23 +45,23 @@ public void testAfterClearObserversAreNotified() { @Test public void testReadWithoutWritReturnsZero() { - MemoryContextImpl context = new MemoryContextImpl(); + MemoryContextImpl context = new MemoryContextImpl(new Annotations()); assertEquals(0L, (long) context.read(10)); } @Test(expected = IndexOutOfBoundsException.class) public void testReadAtInvalidLocationThrows() { - MemoryContextImpl context = new MemoryContextImpl(); + MemoryContextImpl context = new MemoryContextImpl(new Annotations()); context.read(-1); } @Test public void testAfterReadNoObserversAreNotified() { - MemoryContextImpl context = new MemoryContextImpl(); + MemoryContextImpl context = new MemoryContextImpl(new Annotations()); - Memory.MemoryListener listener = createMock(Memory.MemoryListener.class); + MemoryContext.MemoryListener listener = createMock(MemoryContext.MemoryListener.class); replay(listener); context.addMemoryListener(listener); @@ -71,10 +72,10 @@ public void testAfterReadNoObserversAreNotified() { @Test public void testAfterWriteObserversAreNotified() { - MemoryContextImpl context = new MemoryContextImpl(); + MemoryContextImpl context = new MemoryContextImpl(new Annotations()); - Memory.MemoryListener listener = createMock(Memory.MemoryListener.class); - listener.memoryChanged(eq(10)); + MemoryContext.MemoryListener listener = createMock(MemoryContext.MemoryListener.class); + listener.memoryContentChanged(eq(10), eq(10)); expectLastCall().once(); replay(listener); @@ -86,7 +87,7 @@ public void testAfterWriteObserversAreNotified() { @Test public void testWriteReallyWritesCorrectValueAtCorrectLocation() { - MemoryContextImpl context = new MemoryContextImpl(); + MemoryContextImpl context = new MemoryContextImpl(new Annotations()); context.write(10, (byte) 134); assertEquals((byte) 134, (byte) context.read(10)); @@ -94,31 +95,31 @@ public void testWriteReallyWritesCorrectValueAtCorrectLocation() { @Test(expected = IndexOutOfBoundsException.class) public void testWriteAtInvalidLocationThrows() { - MemoryContextImpl context = new MemoryContextImpl(); + MemoryContextImpl context = new MemoryContextImpl(new Annotations()); context.write(-1, (byte) 134); } @Test public void testGetSizeReturnsNumberOfCells() { - MemoryContextImpl context = new MemoryContextImpl(); + MemoryContextImpl context = new MemoryContextImpl(new Annotations()); assertEquals(MemoryContextImpl.NUMBER_OF_CELLS, context.getSize()); } @Test public void testClassTypeIsByte() { - assertEquals(Byte.class, new MemoryContextImpl().getDataType()); + assertEquals(Byte.class, new MemoryContextImpl(new Annotations()).getCellTypeClass()); } @Test public void testReadArrayIsSupported() { - assertArrayEquals(new Byte[]{0, 0, 0, 0}, new MemoryContextImpl().read(0, 4)); + assertArrayEquals(new Byte[]{0, 0, 0, 0}, new MemoryContextImpl(new Annotations()).read(0, 4)); } @Test public void testWriteArrayIsSupported() { - MemoryContextImpl mem = new MemoryContextImpl(); + MemoryContextImpl mem = new MemoryContextImpl(new Annotations()); Byte[] row = new Byte[]{1, 2, 3, 4}; mem.write(0, row); diff --git a/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/DumpMemoryActionTest.java b/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/DumpMemoryActionTest.java index 9e3a7b6cb..425c38bd1 100644 --- a/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/DumpMemoryActionTest.java +++ b/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/DumpMemoryActionTest.java @@ -19,6 +19,7 @@ package net.emustudio.plugins.memory.ssem.gui.actions; import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.Annotations; import net.emustudio.emulib.runtime.ApplicationApi; import net.emustudio.emulib.runtime.interaction.Dialogs; import net.emustudio.emulib.runtime.interaction.FileExtensionsFilter; @@ -45,7 +46,7 @@ public class DumpMemoryActionTest { @Test public void testNoFileIsChosen() { - DumpMemoryAction action = new DumpMemoryAction(mockApi(), new MemoryContextImpl()); + DumpMemoryAction action = new DumpMemoryAction(mockApi(), new MemoryContextImpl(new Annotations())); action.actionPerformed(null); } @@ -137,7 +138,7 @@ public static ByteBuffer read(Path path) throws IOException { } private MemoryContext prepareMemory() { - MemoryContextImpl mem = new MemoryContextImpl(); + MemoryContextImpl mem = new MemoryContextImpl(new Annotations()); for (int i = 0; i < 32 * 4; i += 4) { mem.write(i, new Byte[] { (byte)i, (byte)(i+1), (byte)(i+2), (byte)(i+3) }); } diff --git a/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/LoadImageActionTest.java b/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/LoadImageActionTest.java index a3147c417..b31a121df 100644 --- a/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/LoadImageActionTest.java +++ b/plugins/memory/ssem-mem/src/test/java/net/emustudio/plugins/memory/ssem/gui/actions/LoadImageActionTest.java @@ -19,6 +19,7 @@ package net.emustudio.plugins.memory.ssem.gui.actions; import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.Annotations; import net.emustudio.plugins.memory.ssem.MemoryContextImpl; import org.junit.Rule; import org.junit.Test; @@ -42,7 +43,7 @@ public class LoadImageActionTest { public void testNoFileIsChosenWorks() { Runnable repaint = createMock(Runnable.class); replay(repaint); - new LoadImageAction(mockApi(), new MemoryContextImpl(), repaint).actionPerformed(null); + new LoadImageAction(mockApi(), new MemoryContextImpl(new Annotations()), repaint).actionPerformed(null); verify(repaint); } From 8669265b6247c43f7734310ac30dbd30409cc0ce Mon Sep 17 00:00:00 2001 From: Peter Jakubco Date: Tue, 25 Apr 2023 12:33:21 +0200 Subject: [PATCH 5/6] [#314] Implement ZX-spectrum bus --- application/build.gradle | 2 + .../src/main/files/config/ZxSpectrum48K.toml | 49 ++++-- .../virtualcomputer/ContextPoolImpl.java | 2 +- .../virtualcomputer/VirtualComputer.java | 3 +- .../plugins/compiler/ram/MemoryStub.java | 8 +- .../plugins/compiler/rasp/MemoryStub.java | 8 +- .../plugins/cpu/rasp/MemoryStub.java | 8 +- .../plugins/cpu/ssem/TimingEstimator.java | 10 +- .../plugins/cpu/zilogZ80/CpuImpl.java | 2 + .../plugins/cpu/zilogZ80/api/ContextZ80.java | 2 + plugins/device/cassette-player/build.gradle | 2 +- .../device/cassette_player/DeviceImpl.java | 2 +- .../cassette_player/PlaybackListenerImpl.java | 8 +- .../cassette_player/loaders/TapLoader.java | 2 +- plugins/device/zxspectrum-bus/build.gradle | 57 +++++++ .../device/zxspectrum/bus/DeviceImpl.java | 138 ++++++++++++++++ .../zxspectrum/bus/ZxSpectrumBusImpl.java | 155 ++++++++++++++++++ .../zxspectrum/bus/api/ZxSpectrumBus.java | 89 ++++++++++ .../version.properties | 20 +++ plugins/device/zxspectrum-ula/build.gradle | 1 + .../device/zxspectrum/ula/DeviceImpl.java | 36 +--- .../plugins/device/zxspectrum/ula/ULA.java | 33 ++-- .../device/zxspectrum/ula/api/LineInPort.java | 42 ----- .../zxspectrum/ula/gui/DisplayCanvas.java | 5 +- .../memory/bytemem/MemoryContextImpl.java | 9 +- .../plugins/memory/ram/MemoryContextImpl.java | 8 +- .../memory/rasp/MemoryContextImpl.java | 11 +- .../memory/ssem/MemoryContextImpl.java | 9 +- settings.gradle | 1 + 29 files changed, 595 insertions(+), 127 deletions(-) create mode 100644 plugins/device/zxspectrum-bus/build.gradle create mode 100644 plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/DeviceImpl.java create mode 100644 plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/ZxSpectrumBusImpl.java create mode 100644 plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/api/ZxSpectrumBus.java create mode 100644 plugins/device/zxspectrum-bus/src/main/resources/net.emustudio.plugins.device.zxspectrum.bus/version.properties delete mode 100644 plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java diff --git a/application/build.gradle b/application/build.gradle index c3d209d05..dc114de65 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -75,6 +75,7 @@ dependencies { providedRuntime project(":plugins:device:vt100-terminal") providedRuntime project(":plugins:device:simh-pseudo") providedRuntime project(":plugins:device:ssem-display") + providedRuntime project(":plugins:device:zxspectrum-bus") providedRuntime project(":plugins:device:zxspectrum-ula") providedRuntime project(":plugins:device:cassette-player") @@ -218,6 +219,7 @@ distributions { from(output(":plugins:device:vt100-terminal")) from(output(":plugins:device:simh-pseudo")) from(output(":plugins:device:ssem-display")) + from(output(":plugins:device:zxspectrum-bus")) from(output(":plugins:device:zxspectrum-ula")) from(output(":plugins:device:cassette-player")) } diff --git a/application/src/main/files/config/ZxSpectrum48K.toml b/application/src/main/files/config/ZxSpectrum48K.toml index 113a159ee..fa65fe0b4 100644 --- a/application/src/main/files/config/ZxSpectrum48K.toml +++ b/application/src/main/files/config/ZxSpectrum48K.toml @@ -1,7 +1,7 @@ name = "ZX Spectrum 48K" [MEMORY] - schemaPoint = "220,60" + schemaPoint = "80,180" path = "byte-mem.jar" name = "byte-mem" id = "1e13a25d-fb23-4061-853a-5fe996b03281" @@ -10,9 +10,11 @@ name = "ZX Spectrum 48K" [MEMORY.settings] #memorySize = 49152 banksCount = 0 - ROMfrom0 = 0 + imageName0 = "/home/vbmacher/tmp/emuStudio/examples/zxspectrum-48k/48.rom" # TODO: change! + imageBank1 = 0 + imageBank0 = 0 commonBoundary = 0 - ROMto0 = 16383 + imageAddress0 = 0 # memorySize = 65536 # ROM areas are stored as pairs ROMfromN and ROMtoN, where N is 0-based counter. There can be multiple rom areas. @@ -36,15 +38,14 @@ name = "ZX Spectrum 48K" type = "COMPILER" [CPU] - schemaPoint = "220,180" + schemaPoint = "260,300" path = "z80-cpu.jar" - settings = {} name = "z80-cpu" id = "b86d4bc2-632c-46e3-bba1-c088c9177983" type = "CPU" [CPU.settings] - frequency_khz = 3500 + frequency_khz = 3500 # Uncomment the following for specific settings (and remove settings = {} above) # [CPU.settings] @@ -52,13 +53,29 @@ name = "ZX Spectrum 48K" # printCodeUseCache = true # printCodeFileName = "syserr" # Or custom path to a file [[DEVICE]] - schemaPoint = "380,180" + schemaPoint = "420,60" path = "zxspectrum-ula.jar" settings = {} name = "zxspectrum-ula" id = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" type = "DEVICE" +[[DEVICE]] + schemaPoint = "420,180" + path = "cassette-player.jar" + settings = {} + name = "cassette-player" + id = "581cc598-3beb-4a67-b1e3-b4ec1731a9a7" + type = "DEVICE" + +[[DEVICE]] + schemaPoint = "260,180" + path = "zxspectrum-bus.jar" + settings = {} + name = "zxspectrum-bus" + id = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" + type = "DEVICE" + [[connections]] bidirectional = true from = "9233e0c2-b53c-41e7-9eca-bbb264fcd9da" @@ -68,18 +85,24 @@ name = "ZX Spectrum 48K" [[connections]] bidirectional = true from = "1e13a25d-fb23-4061-853a-5fe996b03281" - to = "b86d4bc2-632c-46e3-bba1-c088c9177983" + to = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" points = [] [[connections]] bidirectional = true - from = "b86d4bc2-632c-46e3-bba1-c088c9177983" - to = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" + from = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" + to = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" + points = ["260,60"] + +[[connections]] + bidirectional = true + from = "581cc598-3beb-4a67-b1e3-b4ec1731a9a7" + to = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" points = [] [[connections]] bidirectional = true - from = "1e13a25d-fb23-4061-853a-5fe996b03281" - to = "1436ac2d-982f-4a52-b7c6-ecb6f2a0440d" - points = ["360,60"] + from = "c16f6ea4-c26f-4dbf-972b-893c22a0d92c" + to = "b86d4bc2-632c-46e3-bba1-c088c9177983" + points = [] diff --git a/application/src/main/java/net/emustudio/application/virtualcomputer/ContextPoolImpl.java b/application/src/main/java/net/emustudio/application/virtualcomputer/ContextPoolImpl.java index 3eb4513b3..1aab99e5e 100644 --- a/application/src/main/java/net/emustudio/application/virtualcomputer/ContextPoolImpl.java +++ b/application/src/main/java/net/emustudio/application/virtualcomputer/ContextPoolImpl.java @@ -267,7 +267,7 @@ private void verifyPluginContext(Class contextInterface) thro throw new InvalidContextException("Given class is not an interface"); } if (!contextInterface.isAnnotationPresent(PluginContext.class)) { - throw new InvalidContextException("The interface is not annotated with 'PluginContext' annotation"); + throw new InvalidContextException("The interface is not annotated with 'PluginContext' annotation: " + contextInterface); } } } diff --git a/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java b/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java index 97efb74ef..edaf09121 100644 --- a/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java +++ b/application/src/main/java/net/emustudio/application/virtualcomputer/VirtualComputer.java @@ -151,8 +151,7 @@ private static Plugin createPluginInstance(long pluginID, Class constructor = mainClass.getDeclaredConstructor(PLUGIN_CONSTRUCTOR_PARAMS); return (Plugin) constructor.newInstance(pluginID, applicationApi, pluginSettings); diff --git a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java index 474a4b84b..36bfdee69 100644 --- a/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java +++ b/plugins/compiler/ramc-ram/src/test/java/net/emustudio/plugins/compiler/ram/MemoryStub.java @@ -31,9 +31,10 @@ public class MemoryStub extends AbstractMemoryContext implements private final RamInstruction[] memory = new RamInstruction[1000]; private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + private final MemoryContextAnnotations annotations; protected MemoryStub(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -73,6 +74,11 @@ public int getSize() { return memory.length; } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public void setLabels(List labels) { this.labels.clear(); diff --git a/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java b/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java index 60d2f5534..9b53dbde0 100644 --- a/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java +++ b/plugins/compiler/raspc-rasp/src/test/java/net/emustudio/plugins/compiler/rasp/MemoryStub.java @@ -29,9 +29,10 @@ public class MemoryStub extends AbstractMemoryContext implements RaspMe private final Integer[] memory = new Integer[1000]; private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + private final MemoryContextAnnotations annotations; protected MemoryStub(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -66,6 +67,11 @@ public int getSize() { return memory.length; } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public void setLabels(List labels) { this.labels.clear(); diff --git a/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java b/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java index 26a7d0aee..afd9a9b56 100644 --- a/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java +++ b/plugins/cpu/rasp-cpu/src/test/java/net/emustudio/plugins/cpu/rasp/MemoryStub.java @@ -29,9 +29,10 @@ public class MemoryStub extends AbstractMemoryContext implements RaspMe private final Integer[] memory = new Integer[1000]; private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); + private final MemoryContextAnnotations annotations; protected MemoryStub(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -71,6 +72,11 @@ public int getSize() { return memory.length; } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public void setLabels(List labels) { this.labels.clear(); diff --git a/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java b/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java index c9f276ca2..5ef53e1bc 100644 --- a/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java +++ b/plugins/cpu/ssem-cpu/src/main/java/net/emustudio/plugins/cpu/ssem/TimingEstimator.java @@ -20,7 +20,9 @@ import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.Annotation; import net.emustudio.emulib.plugins.memory.annotations.Annotations; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import net.emustudio.emulib.runtime.helpers.NumberUtils; import java.util.Arrays; @@ -62,7 +64,8 @@ public class TimingEstimator { 0x3F, 0xFF, 0xE0, 0x50 }; - private final MemoryContext memoryContext = new AbstractMemoryContext<>(new Annotations()) { + private final MemoryContext memoryContext = new AbstractMemoryContext<>() { + private final Annotations annotations = new Annotations(); @Override public Byte read(int position) { @@ -98,6 +101,11 @@ public void clear() { public int getSize() { return memory.length; } + + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } }; public long estimateWaitNanos(int instructionsPerSecond) { diff --git a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java index 02ac2403c..ec012e572 100644 --- a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java +++ b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/CpuImpl.java @@ -29,6 +29,7 @@ import net.emustudio.emulib.runtime.settings.PluginSettings; import net.emustudio.plugins.cpu.intel8080.api.Context8080; import net.emustudio.plugins.cpu.intel8080.api.FrequencyUpdater; +import net.emustudio.plugins.cpu.zilogZ80.api.ContextZ80; import net.emustudio.plugins.cpu.zilogZ80.gui.StatusPanel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +66,7 @@ public CpuImpl(long pluginID, ApplicationApi applicationApi, PluginSettings sett super(pluginID, applicationApi, settings); try { applicationApi.getContextPool().register(pluginID, context, Context8080.class); + applicationApi.getContextPool().register(pluginID, context, ContextZ80.class); } catch (InvalidContextException | ContextAlreadyRegisteredException e) { LOGGER.error("Could not register Z80 CPU context", e); applicationApi.getDialogs().showError( diff --git a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java index 066c8ff8e..24fe594e2 100644 --- a/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java +++ b/plugins/cpu/z80-cpu/src/main/java/net/emustudio/plugins/cpu/zilogZ80/api/ContextZ80.java @@ -18,9 +18,11 @@ */ package net.emustudio.plugins.cpu.zilogZ80.api; +import net.emustudio.emulib.plugins.annotations.PluginContext; import net.emustudio.plugins.cpu.intel8080.api.Context8080; @SuppressWarnings("unused") +@PluginContext public interface ContextZ80 extends Context8080 { /** diff --git a/plugins/device/cassette-player/build.gradle b/plugins/device/cassette-player/build.gradle index dacd46629..18f3889ca 100644 --- a/plugins/device/cassette-player/build.gradle +++ b/plugins/device/cassette-player/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation libs.emuLib implementation libs.slf4JApi implementation libs.jcipAnnotations -// cpuLib project(":plugins:cpu:8080-cpu") + deviceLib project(":plugins:device:zxspectrum-bus") testImplementation libs.junit testImplementation libs.slf4JSimple diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java index d0f652694..41aaf1ec4 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/DeviceImpl.java @@ -54,7 +54,7 @@ public void initialize() throws PluginInitializationException { // a cassette player needs a device to which it will write at its own pace DeviceContext lineIn = applicationApi.getContextPool().getDeviceContext(pluginID, DeviceContext.class); if (lineIn.getDataType() != Byte.class) { - throw new PluginInitializationException("Could not find Byte device"); + throw new PluginInitializationException("Could not find line-in device"); } this.cassetteListener = new PlaybackListenerImpl(lineIn); this.controller = new CassetteController(cassetteListener); diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java index 8e36f5f77..ffee671c2 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/PlaybackListenerImpl.java @@ -26,12 +26,14 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; +//Machine Pilot pulse Length Sync1 Sync2 Bit 0 Bit 1 +//ZX Spectrum 2168 (1) 667 735 855 1710 public class PlaybackListenerImpl implements Loader.PlaybackListener { - private final DeviceContext lineIn; + private final DeviceContext bus; private final AtomicReference gui = new AtomicReference<>(); - public PlaybackListenerImpl(DeviceContext lineIn) { - this.lineIn = Objects.requireNonNull(lineIn); + public PlaybackListenerImpl(DeviceContext bus) { + this.bus = Objects.requireNonNull(bus); } public void setGui(CassettePlayerGui gui) { diff --git a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java index 71d4ba0c7..4e02dc3bf 100644 --- a/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java +++ b/plugins/device/cassette-player/src/main/java/net/emustudio/plugins/device/cassette_player/loaders/TapLoader.java @@ -79,7 +79,7 @@ private void interpret(byte[] content, PlaybackListener listener) { if (flagByte == 255) { listener.onData(data); } else { - LOGGER.warn("TAP: Unknwon flag: " + flagByte); + LOGGER.warn("TAP: unknown flag: " + flagByte); } } buffer.get(); // checksum diff --git a/plugins/device/zxspectrum-bus/build.gradle b/plugins/device/zxspectrum-bus/build.gradle new file mode 100644 index 000000000..fff9a4635 --- /dev/null +++ b/plugins/device/zxspectrum-bus/build.gradle @@ -0,0 +1,57 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import org.apache.tools.ant.filters.ReplaceTokens + +plugins { + id 'java' + id 'com.adarshr.test-logger' version '3.1.0' +} + +dependencies { + implementation libs.emuLib + implementation libs.slf4JApi + implementation libs.jcipAnnotations + cpuLib project(":plugins:cpu:z80-cpu") + cpuLib project(":plugins:cpu:8080-cpu") + + testImplementation libs.junit + testImplementation libs.slf4JSimple + testImplementation libs.easyMock +} + +jar { + archiveVersion = '' + manifest { + attributes manifestAttributes('') + } +} + +processResources { + filesMatching("**/*.properties") { + filter ReplaceTokens, tokens: [ + "project.version": project.version, + "today.year" : new Date().format("yyyy") + ] + } +} + +compileJava.options.encoding = 'UTF-8' +compileTestJava.options.encoding = 'UTF-8' +javadoc.options.encoding = 'UTF-8' diff --git a/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/DeviceImpl.java b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/DeviceImpl.java new file mode 100644 index 000000000..ea84a7ca6 --- /dev/null +++ b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/DeviceImpl.java @@ -0,0 +1,138 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.zxspectrum.bus; + +import net.emustudio.emulib.plugins.PluginInitializationException; +import net.emustudio.emulib.plugins.annotations.PLUGIN_TYPE; +import net.emustudio.emulib.plugins.annotations.PluginRoot; +import net.emustudio.emulib.plugins.device.AbstractDevice; +import net.emustudio.emulib.plugins.device.DeviceContext; +import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.runtime.ApplicationApi; +import net.emustudio.emulib.runtime.ContextAlreadyRegisteredException; +import net.emustudio.emulib.runtime.ContextPool; +import net.emustudio.emulib.runtime.InvalidContextException; +import net.emustudio.emulib.runtime.settings.PluginSettings; +import net.emustudio.plugins.cpu.zilogZ80.api.ContextZ80; +import net.emustudio.plugins.device.zxspectrum.bus.api.ZxSpectrumBus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.*; +import java.util.MissingResourceException; +import java.util.Optional; +import java.util.ResourceBundle; + +/** + * ZX Spectrum Bus + *

+ * - controls access to memory + * - provides access to cycle counter (TimeEventProcessor) + * - provides memory and I/O contention + *

+ * Example usage: + * a cassette player plays a tape = puts data on the bus in given time intervals. Z80 CPU reads the data from the bus + * when convenient. + */ +@PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "ZX Spectrum48K Bus") +public class DeviceImpl extends AbstractDevice { + private final static Logger LOGGER = LoggerFactory.getLogger(DeviceImpl.class); + private final ZxSpectrumBusImpl bus = new ZxSpectrumBusImpl(); + + public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings settings) { + super(pluginID, applicationApi, settings); + + try { + ContextPool contextPool = applicationApi.getContextPool(); + contextPool.register(pluginID, bus, ZxSpectrumBus.class); + contextPool.register(pluginID, bus, MemoryContext.class); + contextPool.register(pluginID, bus, DeviceContext.class); + } catch (InvalidContextException | ContextAlreadyRegisteredException e) { + LOGGER.error("Could not register zx-spectrum bus context", e); + applicationApi.getDialogs().showError( + "Could not register zx-spectrum bus. Please see log file for more details", getTitle() + ); + } + } + + @SuppressWarnings("unchecked") + @Override + public void initialize() throws PluginInitializationException { + MemoryContext memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); + Class cellTypeClass = memory.getCellTypeClass(); + if (cellTypeClass != Byte.class) { + throw new PluginInitializationException("Could not find Byte-cell memory"); + } + ContextZ80 cpu = applicationApi.getContextPool().getCPUContext(pluginID, ContextZ80.class); + this.bus.initialize(cpu, memory); + } + + @Override + public void showGUI(JFrame parent) { + + } + + @Override + public boolean isGuiSupported() { + return false; + } + + @Override + public void destroy() { + + } + + @Override + public void showSettings(JFrame jFrame) { + + } + + @Override + public boolean isShowSettingsSupported() { + return false; + } + + @Override + public boolean isAutomationSupported() { + return true; + } + + @Override + public String getVersion() { + return getResourceBundle().map(b -> b.getString("version")).orElse("(unknown)"); + } + + @Override + public String getCopyright() { + return getResourceBundle().map(b -> b.getString("copyright")).orElse("(unknown)"); + } + + @Override + public String getDescription() { + return "ZX Spectrum48K Bus"; + } + + private Optional getResourceBundle() { + try { + return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.device.zxspectrum.bus.version")); + } catch (MissingResourceException e) { + return Optional.empty(); + } + } +} diff --git a/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/ZxSpectrumBusImpl.java b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/ZxSpectrumBusImpl.java new file mode 100644 index 000000000..4ddc96a7d --- /dev/null +++ b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/ZxSpectrumBusImpl.java @@ -0,0 +1,155 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.zxspectrum.bus; + +import net.emustudio.emulib.plugins.annotations.PluginContext; +import net.emustudio.emulib.plugins.cpu.TimedEventsProcessor; +import net.emustudio.emulib.plugins.memory.AbstractMemoryContext; +import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; +import net.emustudio.plugins.cpu.intel8080.api.Context8080; +import net.emustudio.plugins.cpu.zilogZ80.api.ContextZ80; +import net.emustudio.plugins.device.zxspectrum.bus.api.ZxSpectrumBus; +import net.jcip.annotations.NotThreadSafe; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * Also a memory proxy + */ +@NotThreadSafe +public class ZxSpectrumBusImpl extends AbstractMemoryContext implements ZxSpectrumBus { + private ContextZ80 cpu; + private MemoryContext memory; + private volatile byte busData; // data on the bus + + private final Map deferredAttachments = new HashMap<>(); + + + public void initialize(ContextZ80 cpu, MemoryContext memory) { + this.cpu = Objects.requireNonNull(cpu); + this.memory = Objects.requireNonNull(memory); + + for (Map.Entry attachment : deferredAttachments.entrySet()) { + // TODO: contended device proxy if needed + if (!cpu.attachDevice(attachment.getKey(), attachment.getValue())) { + throw new RuntimeException("Could not attach device " + attachment.getValue().getName() + " to CPU"); + } + } + } + + @Override + public void attachDevice(int port, Context8080.CpuPortDevice device) { + if (cpu == null) { + deferredAttachments.put(port, device); + } else { + // TODO: contended device proxy if needed + if (!cpu.attachDevice(port, device)) { + throw new RuntimeException("Could not attach device " + device.getName() + " to CPU"); + } + } + } + + @Override + public void signalNonMaskableInterrupt() { + cpu.signalNonMaskableInterrupt(); + } + + @Override + public void signalInterrupt(byte[] data) { + cpu.signalInterrupt(data); + } + + @Override + public Optional getTimedEventsProcessor() { + return cpu.getTimedEventsProcessor(); + } + + @Override + public byte readMemoryNotContended(int location) { + return memory.read(location); + } + + @Override + public void writeMemoryNotContended(int location, byte data) { + memory.write(location, data); + } + + @Override + public Byte readData() { + return busData; + } + + @Override + public void writeData(Byte data) { + this.busData = data; + } + + @Override + public Byte read(int location) { + // TODO: contention + return memory.read(location); + } + + @Override + public Byte[] read(int location, int count) { + // TODO: contention + return memory.read(location, count); + } + + @Override + public void write(int location, Byte data) { + // TODO: contention + memory.write(location, data); + } + + @Override + public void write(int location, Byte[] data, int count) { + // TODO: contention + memory.write(location, data, count); + } + + @Override + public Class getCellTypeClass() { + return Byte.class; + } + + @Override + public Class getDataType() { + return Byte.class; + } + + @Override + public void clear() { + memory.clear(); + } + + @Override + public int getSize() { + return memory.getSize(); + } + + @Override + public MemoryContextAnnotations annotations() { + return memory.annotations(); + } +} diff --git a/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/api/ZxSpectrumBus.java b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/api/ZxSpectrumBus.java new file mode 100644 index 000000000..1b63267c0 --- /dev/null +++ b/plugins/device/zxspectrum-bus/src/main/java/net/emustudio/plugins/device/zxspectrum/bus/api/ZxSpectrumBus.java @@ -0,0 +1,89 @@ +/* + * This file is part of emuStudio. + * + * Copyright (C) 2006-2023 Peter Jakubčo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.emustudio.plugins.device.zxspectrum.bus.api; + +import net.emustudio.emulib.plugins.annotations.PluginContext; +import net.emustudio.emulib.plugins.cpu.TimedEventsProcessor; +import net.emustudio.emulib.plugins.device.DeviceContext; +import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.plugins.cpu.intel8080.api.Context8080; + +import java.util.Optional; + +/** + * ZX Spectrum bus. + *

+ * It's a proxy between CPU, memory and devices. Mostly due to contention, but also for CPU cycles synchronization + * (devices are usually not connected to CPU directly). + */ +@PluginContext +public interface ZxSpectrumBus extends DeviceContext, MemoryContext { + + /** + * Attach a device on the bus. + *

+ * Under the hood, it will be attached to the CPU on given port. If the port adheres to contention, + * device access will be contended. + * + * @param port CPU port where the device should be attached + * @param device the device + */ + void attachDevice(int port, Context8080.CpuPortDevice device); + + /** + * Signals a NMI to the CPU + */ + void signalNonMaskableInterrupt(); + + /** + * Signals an interrupt to the CPU + * + * @param data interrupt data + */ + void signalInterrupt(byte[] data); + + /** + * For synchronizing with Z80 T-state cycles. + * + * @return CPU timed events processor if any + */ + Optional getTimedEventsProcessor(); + + /** + * Read data from memory, a non-contended variant. + *

+ * Under the hood it uses existing byte-memory. The reason for this method is the default readMemory() applies + * contention on specific location. + * + * @param location memory location + * @return data read by memory + */ + byte readMemoryNotContended(int location); + + /** + * Write data from memory, a non-contended variant. + *

+ * Under the hood it uses existing byte-memory. The reason for this method is the default writeMemory() applies + * contention on specific memory location. + * + * @param location memory location + * @param data data to write + */ + void writeMemoryNotContended(int location, byte data); +} diff --git a/plugins/device/zxspectrum-bus/src/main/resources/net.emustudio.plugins.device.zxspectrum.bus/version.properties b/plugins/device/zxspectrum-bus/src/main/resources/net.emustudio.plugins.device.zxspectrum.bus/version.properties new file mode 100644 index 000000000..8061ed30f --- /dev/null +++ b/plugins/device/zxspectrum-bus/src/main/resources/net.emustudio.plugins.device.zxspectrum.bus/version.properties @@ -0,0 +1,20 @@ +# +# This file is part of emuStudio. +# +# Copyright (C) 2006-2023 Peter Jakubčo +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +version=@project.version@ +copyright=\u00A9 Copyright 2006-@today.year@, Peter Jakubčo diff --git a/plugins/device/zxspectrum-ula/build.gradle b/plugins/device/zxspectrum-ula/build.gradle index 2e07bf53e..7a5a3b601 100644 --- a/plugins/device/zxspectrum-ula/build.gradle +++ b/plugins/device/zxspectrum-ula/build.gradle @@ -29,6 +29,7 @@ dependencies { implementation libs.slf4JApi implementation libs.jcipAnnotations cpuLib project(":plugins:cpu:8080-cpu") + deviceLib project(":plugins:device:zxspectrum-bus") testImplementation libs.junit testImplementation libs.slf4JSimple diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java index be9001985..c902111f5 100644 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/DeviceImpl.java @@ -22,20 +22,12 @@ import net.emustudio.emulib.plugins.annotations.PLUGIN_TYPE; import net.emustudio.emulib.plugins.annotations.PluginRoot; import net.emustudio.emulib.plugins.device.AbstractDevice; -import net.emustudio.emulib.plugins.device.DeviceContext; -import net.emustudio.emulib.plugins.memory.MemoryContext; import net.emustudio.emulib.runtime.ApplicationApi; -import net.emustudio.emulib.runtime.ContextAlreadyRegisteredException; -import net.emustudio.emulib.runtime.ContextPool; -import net.emustudio.emulib.runtime.InvalidContextException; import net.emustudio.emulib.runtime.interaction.GuiUtils; import net.emustudio.emulib.runtime.settings.PluginSettings; -import net.emustudio.plugins.cpu.intel8080.api.Context8080; -import net.emustudio.plugins.device.zxspectrum.ula.api.LineInPort; +import net.emustudio.plugins.device.zxspectrum.bus.api.ZxSpectrumBus; import net.emustudio.plugins.device.zxspectrum.ula.gui.Keyboard; import net.emustudio.plugins.device.zxspectrum.ula.gui.TerminalWindow; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.swing.*; import java.util.MissingResourceException; @@ -44,7 +36,6 @@ @PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "ZX Spectrum48K ULA") public class DeviceImpl extends AbstractDevice { - private final static Logger LOGGER = LoggerFactory.getLogger(DeviceImpl.class); private final boolean guiSupported; private final Keyboard keyboard = new Keyboard(); @@ -57,32 +48,14 @@ public DeviceImpl(long pluginID, ApplicationApi applicationApi, PluginSettings s super(pluginID, applicationApi, settings); this.guiSupported = !settings.getBoolean(PluginSettings.EMUSTUDIO_NO_GUI, false); - - try { - ContextPool contextPool = applicationApi.getContextPool(); - contextPool.register(pluginID, new LineInPort(), DeviceContext.class); - } catch (InvalidContextException | ContextAlreadyRegisteredException e) { - LOGGER.error("Could not register memory context", e); - applicationApi.getDialogs().showError( - "Could not register memory. Please see log file for more details", getTitle() - ); - } } - @SuppressWarnings("unchecked") @Override public void initialize() throws PluginInitializationException { - MemoryContext memory = applicationApi.getContextPool().getMemoryContext(pluginID, MemoryContext.class); - Class cellTypeClass = memory.getCellTypeClass(); - if (cellTypeClass != Byte.class) { - throw new PluginInitializationException("Could not find Byte-cell memory"); - } - Context8080 cpu = applicationApi.getContextPool().getCPUContext(pluginID, Context8080.class); - - this.ula = new ULA(memory, cpu); + ZxSpectrumBus bus = applicationApi.getContextPool().getDeviceContext(pluginID, ZxSpectrumBus.class); + this.ula = new ULA(bus); keyboard.addOnKeyListener(ula); - - cpu.attachDevice(0xFE, ula); + bus.attachDevice(0xFE, ula); } @Override @@ -148,7 +121,6 @@ public boolean isAutomationSupported() { return true; } - private Optional getResourceBundle() { try { return Optional.of(ResourceBundle.getBundle("net.emustudio.plugins.device.zxspectrum.ula.version")); diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java index 349fb5502..7c92e6b7b 100644 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/ULA.java @@ -18,12 +18,14 @@ */ package net.emustudio.plugins.device.zxspectrum.ula; -import net.emustudio.emulib.plugins.memory.MemoryContext; +import net.emustudio.emulib.plugins.cpu.TimedEventsProcessor; import net.emustudio.plugins.cpu.intel8080.api.Context8080; +import net.emustudio.plugins.device.zxspectrum.bus.api.ZxSpectrumBus; import net.emustudio.plugins.device.zxspectrum.ula.gui.Keyboard; import java.awt.event.KeyEvent; import java.util.Arrays; +import java.util.NoSuchElementException; import java.util.Objects; /** @@ -71,8 +73,7 @@ public class ULA implements Context8080.CpuPortDevice, Keyboard.OnKeyListener { public final byte[][] attributeMemory = new byte[SCREEN_WIDTH][ATTRIBUTE_HEIGHT]; private final static int[] lineStartOffsets = computeLineStartOffsets(); - private final MemoryContext memory; - private final Context8080 cpu; + private final ZxSpectrumBus bus; private int borderColor; private boolean microphoneAndEar; @@ -85,41 +86,41 @@ private static int[] computeLineStartOffsets() { return result; } - public ULA(MemoryContext memory, Context8080 cpu) { - this.memory = Objects.requireNonNull(memory); - this.cpu = Objects.requireNonNull(cpu); + public ULA(ZxSpectrumBus bus) { + this.bus = Objects.requireNonNull(bus); Arrays.fill(keymap, (byte) 0xBF); } - // little hack.. - public Context8080 getCpu() { - return cpu; - } - public void readScreen() { for (int x = 0; x < SCREEN_WIDTH; x++) { for (int y = 0; y < SCREEN_HEIGHT; y++) { - videoMemory[x][y] = memory.read(0x4000 + lineStartOffsets[y] + x); + videoMemory[x][y] = bus.readMemoryNotContended(0x4000 + lineStartOffsets[y] + x); if (y < ATTRIBUTE_HEIGHT) { int off = ((y >>> 3) << 8) | (((y & 0x07) << 5) | x); int attributeAddress = 0x5800 + off; - attributeMemory[x][y] = memory.read(attributeAddress); + attributeMemory[x][y] = bus.readMemoryNotContended(attributeAddress); } } } } public void triggerInterrupt() { - cpu.signalInterrupt(RST_7); + bus.signalInterrupt(RST_7); + } + + public TimedEventsProcessor getTimedEventsProcessor() { + return bus + .getTimedEventsProcessor() + .orElseThrow(() -> new NoSuchElementException("The CPU does not provide TimedEventProcessor")); } public void readLine(int y) { for (int x = 0; x < SCREEN_WIDTH; x++) { - videoMemory[x][y] = memory.read(0x4000 + lineStartOffsets[y] + x); + videoMemory[x][y] = bus.readMemoryNotContended(0x4000 + lineStartOffsets[y] + x); if (y < ATTRIBUTE_HEIGHT) { int off = ((y >>> 3) << 8) | (((y & 0x07) << 5) | x); int attributeAddress = 0x5800 + off; - attributeMemory[x][y] = memory.read(attributeAddress); + attributeMemory[x][y] = bus.readMemoryNotContended(attributeAddress); } } } diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java deleted file mode 100644 index c7beed31a..000000000 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/api/LineInPort.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of emuStudio. - * - * Copyright (C) 2006-2023 Peter Jakubčo - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package net.emustudio.plugins.device.zxspectrum.ula.api; - -import net.emustudio.emulib.plugins.annotations.PluginContext; -import net.emustudio.emulib.plugins.device.DeviceContext; - -// cassette receiver -@PluginContext(id = "line-in port") -public class LineInPort implements DeviceContext { - - @Override - public Byte readData() { - return null; - } - - @Override - public void writeData(Byte data) { - System.out.println("Received: " + Integer.toHexString(data & 0xFF)); - } - - @Override - public Class getDataType() { - return Byte.class; - } -} diff --git a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java index 1418f51ba..1e728974d 100644 --- a/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java +++ b/plugins/device/zxspectrum-ula/src/main/java/net/emustudio/plugins/device/zxspectrum/ula/gui/DisplayCanvas.java @@ -25,7 +25,6 @@ import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; @@ -88,9 +87,7 @@ public class DisplayCanvas extends Canvas implements AutoCloseable { public DisplayCanvas(ULA ula) { this.ula = Objects.requireNonNull(ula); - this.ted = ula.getCpu() - .getTimedEventsProcessor() - .orElseThrow(() -> new NoSuchElementException("The CPU does not provide TimedEventProcessor")); + this.ted = ula.getTimedEventsProcessor(); this.screenImage.setAccelerationPriority(1.0f); this.screenImageData = ((DataBufferInt) this.screenImage.getRaster().getDataBuffer()).getData(); } diff --git a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java index ddfed6105..78e3e20fc 100644 --- a/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java +++ b/plugins/memory/byte-mem/src/main/java/net/emustudio/plugins/memory/bytemem/MemoryContextImpl.java @@ -25,19 +25,21 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; @PluginContext(id = "Byte Memory") public class MemoryContextImpl extends AbstractMemoryContext implements ByteMemoryContext { final static int DEFAULT_MEM_SIZE = 65536; private final RangeTree romRanges = new RangeTree(); + private final MemoryContextAnnotations annotations; private Byte[][] mem = new Byte[1][0]; private int banksCount; private int bankSelect = 0; private int bankCommon = 0; protected MemoryContextImpl(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } void init(int size, int banks, int bankCommon) { @@ -141,6 +143,11 @@ public int getSize() { return mem[0].length; } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public void setReadWrite(AddressRange range) { if (range.getStartAddress() > range.getStopAddress()) { diff --git a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java index 9bda7f9f3..af3c3f369 100644 --- a/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java +++ b/plugins/memory/ram-mem/src/main/java/net/emustudio/plugins/memory/ram/MemoryContextImpl.java @@ -35,9 +35,10 @@ public class MemoryContextImpl extends AbstractMemoryContext imp private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); private final ReadWriteLockSupport rwl = new ReadWriteLockSupport(); + private final MemoryContextAnnotations annotations; protected MemoryContextImpl(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -56,6 +57,11 @@ public int getSize() { return rwl.lockRead(memory::size); } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public RamInstruction read(int address) { return rwl.lockRead(() -> memory.get(address)); diff --git a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java index 171a0c842..b615e3bc7 100644 --- a/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java +++ b/plugins/memory/rasp-mem/src/main/java/net/emustudio/plugins/memory/rasp/MemoryContextImpl.java @@ -29,19 +29,17 @@ import java.io.*; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; -import java.util.function.Supplier; public class MemoryContextImpl extends AbstractMemoryContext implements RaspMemoryContext { private final Map memory = new HashMap<>(); private final Map labels = new HashMap<>(); private final List inputs = new ArrayList<>(); private final ReadWriteLockSupport rwl = new ReadWriteLockSupport(); + private final MemoryContextAnnotations annotations; protected MemoryContextImpl(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); } @Override @@ -60,6 +58,11 @@ public int getSize() { return rwl.lockRead(() -> memory.keySet().stream().max(Comparator.naturalOrder()).orElse(0)); } + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } + @Override public Integer read(int address) { return rwl.lockRead(() -> memory.getOrDefault(address, 0)); diff --git a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java index 5e6c842be..4406e4f39 100644 --- a/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java +++ b/plugins/memory/ssem-mem/src/main/java/net/emustudio/plugins/memory/ssem/MemoryContextImpl.java @@ -22,15 +22,17 @@ import net.emustudio.emulib.plugins.memory.annotations.MemoryContextAnnotations; import java.util.Arrays; +import java.util.Objects; public class MemoryContextImpl extends AbstractMemoryContext { public static final int NUMBER_OF_CELLS = 32 * 4; // byte type is atomic in JVM memory model private final Byte[] memory = new Byte[NUMBER_OF_CELLS]; + private final MemoryContextAnnotations annotations; public MemoryContextImpl(MemoryContextAnnotations annotations) { - super(annotations); + this.annotations = Objects.requireNonNull(annotations); Arrays.fill(memory, (byte) 0); } @@ -72,4 +74,9 @@ public Class getCellTypeClass() { public int getSize() { return memory.length; } + + @Override + public MemoryContextAnnotations annotations() { + return annotations; + } } diff --git a/settings.gradle b/settings.gradle index b4cba9e94..ec5c26c10 100644 --- a/settings.gradle +++ b/settings.gradle @@ -49,6 +49,7 @@ include ':plugins:device:adm3A-terminal' include ':plugins:device:vt100-terminal' include ':plugins:device:simh-pseudo' include ':plugins:device:ssem-display' +include ':plugins:device:zxspectrum-bus' include ':plugins:device:zxspectrum-ula' include ':plugins:device:cassette-player' From ce7aed4081b3710ef8039cba064b377747985ae2 Mon Sep 17 00:00:00 2001 From: Peter Jakubco Date: Thu, 27 Apr 2023 21:46:01 +0200 Subject: [PATCH 6/6] [#314] cpu-testsuite snapshot --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 619a1ce84..1b95bead4 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ ext.versions = [ ext.libs = [ emuLib : "net.emustudio:emulib:12.1.0-SNAPSHOT", - cpuTestSuite : "net.emustudio:cpu-testsuite_12.1:1.2.0", + cpuTestSuite : "net.emustudio:cpu-testsuite_12.1:1.2.0-SNAPSHOT", jcipAnnotations : "net.jcip:jcip-annotations:1.0", antlr : "org.antlr:antlr4:4.12.0",