diff --git a/modules/spin-tools/src-tests/com/maccasoft/propeller/spin2/Spin2DebugTest.java b/modules/spin-tools/src-tests/com/maccasoft/propeller/spin2/Spin2DebugTest.java index 17483f49..724dd1cf 100644 --- a/modules/spin-tools/src-tests/com/maccasoft/propeller/spin2/Spin2DebugTest.java +++ b/modules/spin-tools/src-tests/com/maccasoft/propeller/spin2/Spin2DebugTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; import com.maccasoft.propeller.CompilerException; import com.maccasoft.propeller.SpinObject.DataObject; @@ -326,6 +327,21 @@ void testSpinString() { + "", actual); } + @Test + void testSpinStringConcatenate() { + String text = "debug(\"start\", 13, 10, \"end\", 13, 10)"; + + Spin2Debug subject = new Spin2Debug(); + String actual = dumpDebugData(subject.compileDebugStatement(parse(text))); + Assertions.assertEquals("" + + "00000 00000 04 COGN\n" + + "00001 00001 06 73 74 61 72 STRING (start..end..)\n" + + "00006 00006 74 0D 0A 65 6E\n" + + "0000B 0000B 64 0D 0A 00\n" + + "0000F 0000F 00 DONE\n" + + "", actual); + } + @Test void testSpinStringAndVars() { String text = "debug(udec(reg1), \"start\", udec(reg2,reg3))"; @@ -739,6 +755,21 @@ void testPAsmChar() { + "", actual); } + @Test + void testUnknownDebugCommand() { + String text = "debug(`MyPlot `unknown_command(a))"; + + Spin2Debug subject = new Spin2Debug(); + Assertions.assertThrows(CompilerException.class, new Executable() { + + @Override + public void execute() throws Throwable { + subject.compileDebugStatement(parse(text)); + } + + }); + } + List parseTokens(String text) { List tokens = new ArrayList(); diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2BytecodeCompiler.java b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2BytecodeCompiler.java index 27d7872d..445067a0 100644 --- a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2BytecodeCompiler.java +++ b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2BytecodeCompiler.java @@ -749,6 +749,7 @@ else if (arg.getType() == Token.STRING) { stack += 4; } } + debug.compileDebugStatement(node); node.setData("context", context); if (isDebugEnabled()) { method.debugNodes.add(node); diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2Debug.java b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2Debug.java index 98a1807e..7e04d808 100644 --- a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2Debug.java +++ b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2Debug.java @@ -15,6 +15,7 @@ import java.io.OutputStream; import com.maccasoft.propeller.CompilerException; +import com.maccasoft.propeller.expressions.NumberLiteral; import com.maccasoft.propeller.model.Token; import com.maccasoft.propeller.spin2.Spin2PAsmDebugLine.Spin2DebugCommand; import com.maccasoft.propeller.spin2.Spin2PAsmDebugLine.Spin2DebugExpression; @@ -50,6 +51,7 @@ public class Spin2Debug { public byte[] compileDebugStatement(Spin2StatementNode root) { boolean skipCogN = false; + StringBuilder sb = new StringBuilder(); ByteArrayOutputStream os = new ByteArrayOutputStream(); if (root.getChildCount() != 0) { @@ -76,26 +78,30 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { first = true; for (Spin2StatementNode node : root.getChilds()) { - try { if (node.getType() == Token.STRING) { - try { - String s = node.getText(); - if (s.startsWith("\"")) { - s = s.substring(1, s.length() - 1); - } - os.write(DBC_STRING); - os.write(s.getBytes()); - os.write(0x00); - } catch (IOException e) { - + String s = node.getText(); + if (s.startsWith("\"")) { + s = s.substring(1, s.length() - 1); } - first = true; + sb.append(s); + } + else if (node.getType() == Token.NUMBER) { + NumberLiteral v = new NumberLiteral(node.getText()); + sb.append((char) v.getNumber().intValue()); } else { int flags = 0; - String cmd = node.getText().toUpperCase(); + if (sb.length() != 0) { + os.write(DBC_STRING); + os.write(sb.toString().getBytes()); + os.write(0x00); + sb = new StringBuilder(); + first = true; + } + + String cmd = node.getText(); if (cmd.startsWith("`")) { flags |= DBC_FLAG_NOEXPR; cmd = cmd.substring(1); @@ -105,7 +111,7 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { cmd = cmd.substring(0, cmd.length() - "_".length()); } - switch (cmd) { + switch (cmd.toUpperCase()) { case "#": for (int i = 0; i < node.getChildCount(); i++) { os.write(DBC_CHAR); @@ -142,6 +148,7 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { compileSpinArrayStatement(node, os, DBC_TYPE_DEC | DBC_SIZE_LONG | DBC_FLAG_ARRAY | flags); break; + case "": case "SDEC": compileSpinStatement(node, os, DBC_TYPE_DEC | DBC_FLAG_SIGNED | flags); break; @@ -281,8 +288,7 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { break; default: - compileSpinStatement(node, os, DBC_TYPE_DEC | DBC_FLAG_SIGNED | flags); - break; + throw new CompilerException("Unknown debug statement '" + cmd + "'", node.getToken()); } } } catch (IOException e) { @@ -290,6 +296,16 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { } } + if (sb.length() != 0) { + try { + os.write(DBC_STRING); + os.write(sb.toString().getBytes()); + os.write(0x00); + } catch (Exception e) { + // Do nothing + } + } + os.write(DBC_DONE); return os.toByteArray(); @@ -331,6 +347,7 @@ void compileSpinArrayStatement(Spin2StatementNode node, OutputStream os, int op) public byte[] compilePAsmDebugStatement(Spin2PAsmDebugLine root) { boolean skipCogN = false; + StringBuilder sb = new StringBuilder(); ByteArrayOutputStream os = new ByteArrayOutputStream(); os.write(DBC_ASMMODE); @@ -359,26 +376,30 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { first = true; for (Spin2DebugCommand node : root.getStatements()) { - try { if (node.getType() == Token.STRING) { - try { - String s = node.getText(); - if (s.startsWith("\"")) { - s = s.substring(1, s.length() - 1); - } - os.write(DBC_STRING); - os.write(s.getBytes()); - os.write(0x00); - } catch (IOException e) { - + String s = node.getText(); + if (s.startsWith("\"")) { + s = s.substring(1, s.length() - 1); } - first = true; + sb.append(s); + } + else if (node.getType() == Token.NUMBER) { + NumberLiteral v = new NumberLiteral(node.getText()); + sb.append((char) v.getNumber().intValue()); } else { int flags = 0; - String cmd = node.getText().toUpperCase(); + if (sb.length() != 0) { + os.write(DBC_STRING); + os.write(sb.toString().getBytes()); + os.write(0x00); + sb = new StringBuilder(); + first = true; + } + + String cmd = node.getText(); if (cmd.startsWith("`")) { flags |= DBC_FLAG_NOEXPR; cmd = cmd.substring(1); @@ -388,7 +409,7 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { cmd = cmd.substring(0, cmd.length() - "_".length()); } - switch (cmd) { + switch (cmd.toUpperCase()) { case "#": for (Spin2DebugExpression child : node.getArguments()) { os.write(DBC_CHAR); @@ -432,6 +453,7 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { compileArrayStatement(node, os, DBC_TYPE_DEC | DBC_SIZE_LONG | DBC_FLAG_ARRAY | flags); break; + case "": case "SDEC": compileSimpleStatement(node, os, DBC_TYPE_DEC | DBC_FLAG_SIGNED | flags); break; @@ -598,8 +620,7 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { break; default: - compileSimpleStatement(node, os, DBC_TYPE_DEC | DBC_FLAG_SIGNED | flags); - break; + throw new CompilerException("Unknown debug statement '" + cmd + "'", node.getToken()); } } } catch (IOException e) { @@ -607,6 +628,16 @@ else if ("IF".equalsIgnoreCase(cmd) || "IFNOT".equalsIgnoreCase(cmd)) { } } + if (sb.length() != 0) { + try { + os.write(DBC_STRING); + os.write(sb.toString().getBytes()); + os.write(0x00); + } catch (Exception e) { + // Do nothing + } + } + os.write(DBC_DONE); return os.toByteArray(); diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2ObjectCompiler.java b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2ObjectCompiler.java index 58c1b613..8cabf00d 100644 --- a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2ObjectCompiler.java +++ b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2ObjectCompiler.java @@ -495,7 +495,6 @@ public List getObjectLinks() { @Override public Spin2Object generateObject(int memoryOffset) { Spin2Object object = new Spin2Object(); - Spin2Debug debug = new Spin2Debug(); Expression exp = scope.getSystemSymbol("CLKFREQ_"); if (exp != null) { diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2PasmCompiler.java b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2PasmCompiler.java index 0a192827..079fb1bc 100644 --- a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2PasmCompiler.java +++ b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2PasmCompiler.java @@ -35,6 +35,7 @@ public abstract class Spin2PasmCompiler extends ObjectCompiler { protected Spin2Compiler compiler; + protected Spin2Debug debug = new Spin2Debug(); private Map pendingAlias = new HashMap(); @@ -218,6 +219,7 @@ protected Spin2PAsmLine compileDataLine(Context globalScope, Context lineScope, tokens.remove(node.label); } Spin2PAsmDebugLine debugLine = Spin2PAsmDebugLine.buildFrom(pasmLine.getScope(), tokens); + debugSource.add(debugLine); compiler.debugStatements.add(debugLine); pasmLine.setData("debug", debugLine);