package org.reasm.m68k.assembly.internal; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.reasm.AssemblyMessage; import org.reasm.SignedIntValue; import org.reasm.SymbolContext; import org.reasm.SymbolType; import org.reasm.UnsignedIntValue; import org.reasm.Value; import org.reasm.m68k.M68KArchitecture; import org.reasm.m68k.messages.CountMustNotBeNegativeErrorMessage; import org.reasm.m68k.messages.InvalidExpressionErrorMessage; import org.reasm.m68k.messages.RegisterExpectedErrorMessage; import org.reasm.m68k.messages.RegisterListExpectedErrorMessage; import org.reasm.messages.DirectiveRequiresLabelErrorMessage; import org.reasm.testhelpers.UserSymbolMatcher; /** * Test class for short M68000 programs consisting of directives that define symbols. * * @author Francis Gagné */ @RunWith(Parameterized.class) public class SymbolsTest extends BaseProgramsTest { @Nonnull private static final UnsignedIntValue UINT_0 = new UnsignedIntValue(0); @Nonnull private static final UnsignedIntValue UINT_1 = new UnsignedIntValue(1); @Nonnull private static final UnsignedIntValue UINT_2 = new UnsignedIntValue(2); @Nonnull private static final RegisterList REGISTER_LIST_D0 = new RegisterList(EnumSet.of(GeneralPurposeRegister.D0)); @Nonnull private static final UserSymbolMatcher<Value> FOO_CONSTANT_UINT_0 = new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, UINT_0); @Nonnull private static final ArrayList<Object[]> TEST_DATA = new ArrayList<>(); static { // No mnemonic addDataItem("foo", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, UINT_0) }); addDataItem("foo:", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, UINT_0) }); addDataItem(" ORG $456\nfoo", 3, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, new UnsignedIntValue(0x456)) }); // = addDataItem("foo = 0", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.VARIABLE, UINT_0) }); // --> see SET for more tests // EQU addDataItem(" EQU", 2, NO_SYMBOLS, new DirectiveRequiresLabelErrorMessage("EQU")); addDataItem("foo EQU", 2, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem("foo EQU 0", 2, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0 }); addDataItem("foo bar: EQU 0", 2, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_0) }); addDataItem("foo EQU UNDEFINED", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, null) }, UNDEFINED_SYMBOL); addDataItem("foo EQU ~", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, null) }, new InvalidExpressionErrorMessage("~")); // EQUR addDataItem(" EQUR", 2, NO_SYMBOLS, new DirectiveRequiresLabelErrorMessage("EQUR")); addDataItem("foo EQUR", 2, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem("foo EQUR D0", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(M68KAssemblyContext.REGISTER_ALIAS, "foo", SymbolType.CONSTANT, GeneralPurposeRegister.D0) }); addDataItem("foo bar: EQUR D0", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(M68KAssemblyContext.REGISTER_ALIAS, "foo", SymbolType.CONSTANT, GeneralPurposeRegister.D0), new UserSymbolMatcher<>(M68KAssemblyContext.REGISTER_ALIAS, "bar", SymbolType.CONSTANT, GeneralPurposeRegister.D0) }); addDataItem("foo EQUR .D0", 2, NO_SYMBOLS, new RegisterExpectedErrorMessage()); addDataItem("foo EQUR 0", 2, NO_SYMBOLS, new RegisterExpectedErrorMessage()); // NAMESPACE addDataItem(" NAMESPACE\n ENDNS", 5, NO_SYMBOLS, new DirectiveRequiresLabelErrorMessage("NAMESPACE")); addDataItem("A NAMESPACE\n ENDNS", 5, NO_SYMBOLS); addDataItem("A NAMESPACE.W\n ENDNS", 5, NO_SYMBOLS, SIZE_ATTRIBUTE_NOT_ALLOWED); addDataItem("A NAMESPACE 1\n ENDNS", 5, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem("A NAMESPACE\nB EQU 1\n ENDNS", 6, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "A.B", SymbolType.CONSTANT, UINT_1) }); addDataItem("A NAMESPACE\nB EQU 1\n ENDNS\nC EQU 1", 7, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "A.B", SymbolType.CONSTANT, UINT_1), new UserSymbolMatcher<>(SymbolContext.VALUE, "C", SymbolType.CONSTANT, UINT_1) }); addDataItem("A: B: NAMESPACE\nC EQU 1\n ENDNS", 6, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "A", SymbolType.CONSTANT, UINT_0), new UserSymbolMatcher<>(SymbolContext.VALUE, "B.C", SymbolType.CONSTANT, UINT_1) }); addDataItem(" NAMESPACE\nA EQU 1\n ENDNS", 6, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "A", SymbolType.CONSTANT, UINT_1) }, new DirectiveRequiresLabelErrorMessage("NAMESPACE")); // REG addDataItem(" REG", 2, NO_SYMBOLS, new DirectiveRequiresLabelErrorMessage("REG")); addDataItem("foo REG", 2, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem("foo REG D0", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(M68KAssemblyContext.REGISTER_LIST_ALIAS, "foo", SymbolType.CONSTANT, REGISTER_LIST_D0) }); addDataItem( "foo REG D0-A7", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(M68KAssemblyContext.REGISTER_LIST_ALIAS, "foo", SymbolType.CONSTANT, new RegisterList(EnumSet.range(GeneralPurposeRegister.D0, GeneralPurposeRegister.A7))) }); addDataItem("foo REG D0/A7", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(M68KAssemblyContext.REGISTER_LIST_ALIAS, "foo", SymbolType.CONSTANT, new RegisterList(EnumSet.of(GeneralPurposeRegister.D0, GeneralPurposeRegister.A7))) }); addDataItem("foo bar: REG D0", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(M68KAssemblyContext.REGISTER_LIST_ALIAS, "foo", SymbolType.CONSTANT, REGISTER_LIST_D0), new UserSymbolMatcher<>(M68KAssemblyContext.REGISTER_LIST_ALIAS, "bar", SymbolType.CONSTANT, REGISTER_LIST_D0) }); addDataItem("foo REG 0", 2, NO_SYMBOLS, new RegisterListExpectedErrorMessage()); // RS addDataItem("foo RS", 2, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem("foo RS 0", 2, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0 }); addDataItem(" RS 0", 2, NO_SYMBOLS); addDataItem("foo RS 0\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_0) }); addDataItem("foo RS 1", 2, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0 }); addDataItem("foo RS 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_2) }); addDataItem(" RS 1\nbar RS 0", 3, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_2) }); addDataItem("foo RS 13\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(26)) }); addDataItem("foo RS $8000000000000000\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_0) }); addDataItem("foo RS -1", 2, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0 }, new CountMustNotBeNegativeErrorMessage()); addDataItem("foo RS ~", 2, NO_SYMBOLS, new InvalidExpressionErrorMessage("~")); addDataItem("foo RS 0, 0", 2, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0 }, WRONG_NUMBER_OF_OPERANDS); addDataItem("foo RS. 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_2) }, INVALID_SIZE_ATTRIBUTE_EMPTY); addDataItem("foo RS.B 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_1) }); addDataItem("foo RS.W 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_2) }); addDataItem("foo RS.L 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(4)) }); addDataItem("foo RS.Q 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(8)) }); addDataItem("foo RS.S 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(4)) }); addDataItem("foo RS.D 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(8)) }); addDataItem("foo RS.X 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(12)) }); addDataItem("foo RS.P 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(12)) }); addDataItem("foo RS.Z 1\nbar RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_2) }, INVALID_SIZE_ATTRIBUTE_Z); addDataItem("foo RS 1\nbar EQU baz\nbaz RS 1", 8, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_2), new UserSymbolMatcher<>(SymbolContext.VALUE, "baz", SymbolType.CONSTANT, UINT_2) }); // RSRESET addDataItem(" RSRESET", 2, NO_SYMBOLS); addDataItem(" RSRESET UNDEFINED", 2, NO_SYMBOLS, UNDEFINED_SYMBOL); addDataItem(" RSRESET 0", 2, NO_SYMBOLS); addDataItem(" RSRESET 0,0", 2, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem(" RSRESET\nfoo RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0 }); addDataItem("foo RS 2\n RSRESET\nbar RS 0", 4, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_0) }); addDataItem(" RSRESET $100\nfoo RS 0", 3, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, new UnsignedIntValue(0x100)) }); addDataItem(" RSRESET -$100\nfoo RS 0", 3, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, new SignedIntValue(-0x100)) }); addDataItem(" RSRESET '256'\nfoo RS 0", 3, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, new SignedIntValue(0x100)) }); addDataItem("foo RS 2\n RSRESET $100\nbar RS 0", 4, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(0x100)) }); addDataItem(" RSRESET ~", 2, NO_SYMBOLS, new InvalidExpressionErrorMessage("~")); // TODO: test with a built-in function symbol //addDataItem(" RSRESET STRLEN", 2, NO_SYMBOLS, new FunctionCannotBeConvertedToIntegerErrorMessage()); // RSSET addDataItem(" RSSET", 2, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem(" RSSET 0", 2, NO_SYMBOLS); addDataItem(" RSSET 0,0", 2, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem(" RSSET 0\nfoo RS 0", 3, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0 }); addDataItem("foo RS 2\n RSSET 0\nbar RS 0", 4, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, UINT_0) }); addDataItem(" RSSET $100\nfoo RS 0", 3, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, new UnsignedIntValue(0x100)) }); addDataItem(" RSSET -$100\nfoo RS 0", 3, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.CONSTANT, new SignedIntValue(-0x100)) }); addDataItem("foo RS 2\n RSSET $100\nbar RS 0", 4, new UserSymbolMatcher[] { FOO_CONSTANT_UINT_0, new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.CONSTANT, new UnsignedIntValue(0x100)) }); addDataItem(" RSSET ~", 2, NO_SYMBOLS, new InvalidExpressionErrorMessage("~")); // SET addDataItem(" SET", 2, NO_SYMBOLS, new DirectiveRequiresLabelErrorMessage("SET")); addDataItem("foo SET", 2, NO_SYMBOLS, WRONG_NUMBER_OF_OPERANDS); addDataItem("foo SET 0", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.VARIABLE, UINT_0) }); addDataItem("foo bar: SET 0", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.VARIABLE, UINT_0), new UserSymbolMatcher<>(SymbolContext.VALUE, "bar", SymbolType.VARIABLE, UINT_0) }); addDataItem("foo SET UNDEFINED", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.VARIABLE, null) }, UNDEFINED_SYMBOL); addDataItem("foo SET ~", 2, new UserSymbolMatcher[] { new UserSymbolMatcher<>(SymbolContext.VALUE, "foo", SymbolType.VARIABLE, null) }, new InvalidExpressionErrorMessage("~")); } /** * Gets the test data for this parameterized test. * * @return the test data */ @Nonnull @Parameters public static List<Object[]> data() { return TEST_DATA; } private static void addDataItem(@Nonnull String code, int steps, @Nonnull UserSymbolMatcher<?>[] symbols) { addDataItem(code, steps, symbols, (AssemblyMessage) null); } private static void addDataItem(@Nonnull String code, int steps, @Nonnull UserSymbolMatcher<?>[] symbols, @CheckForNull AssemblyMessage expectedMessage) { TEST_DATA.add(new Object[] { code, steps, symbols, expectedMessage }); } /** * Initializes a new SymbolsTest. * * @param code * assembly code to assemble * @param steps * the number of steps the program is expected to take to assemble completely * @param symbolMatchers * an array of matchers for the symbols that are expected to be defined in the program * @param expectedMessage * an {@link AssemblyMessage} that is expected to be generated while assembling the code */ public SymbolsTest(@Nonnull String code, int steps, @Nonnull UserSymbolMatcher<?>[] symbolMatchers, @CheckForNull AssemblyMessage expectedMessage) { super(code, steps, NO_DATA, M68KArchitecture.MC68000, expectedMessage, null, symbolMatchers); } }