summaryrefslogtreecommitdiff
path: root/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-03 14:03:48 -0700
committerCliff Click <cliffc@acm.org>2026-10-04 13:30:41 -0700
commit3476d99690805b3ebe69219b326e5e1b64ebd0a4 (patch)
treecb05c136d87603d292c44ac4e5df38d8136f1872 /src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java
parent9a5ca20d2537179f3a8e01762c8db6b52a4db2d9 (diff)
downloadSimple-linear-chapter17b.tar.gz
Simple-linear-chapter17b.zip
Chapter 17b: Syntax Sugarlinear-chapter17b
Diffstat (limited to 'src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java')
-rw-r--r--src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java b/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java
new file mode 100644
index 00000000..0fa4283b
--- /dev/null
+++ b/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java
@@ -0,0 +1,77 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.evaluator.Evaluator;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class CompoundAssignmentTest {
+ private static final String[] OPS = {"&=", "|=", "^=", "<<=", ">>=", ">>>="};
+
+ private static long apply(String op, long lhs, long rhs) {
+ return switch (op) {
+ case "&=" -> lhs & rhs;
+ case "|=" -> lhs | rhs;
+ case "^=" -> lhs ^ rhs;
+ case "<<=" -> lhs << rhs;
+ case ">>=" -> lhs >> rhs;
+ case ">>>=" -> lhs >>> rhs;
+ default -> throw new AssertionError(op);
+ };
+ }
+
+ @Test public void testLocals() {
+ for (String op : OPS)
+ for (long arg : new long[]{-8, 0, 5, 64}) {
+ long expected = apply(op, arg, 3);
+ check("int x=arg; int r=(x " + op + " 3); return x*10+r;",
+ arg, expected*11);
+ }
+ }
+
+ @Test public void testRhsOnce() {
+ for (String op : OPS) {
+ long expected = apply(op, 5, 1);
+ check("int x=arg; int count=0; int r=(x " + op +
+ " (count=count+1)); return count*1000+x*10+r;", 5, 1000+expected*11);
+ }
+ }
+
+ @Test public void testNarrowingAndChaining() {
+ check("u8 x=255; x <<= 1; return x;", 0, 254);
+ check("u8 x=255; x ^= 256; return x;", 0, 255);
+ check("int x=1; int y=3; x |= y <<= 2; return x*100+y;", 0, 1312);
+ check("int x=-8; x >>= 65; return x;", 0, -4);
+ check("int x=-8; x >>>= 65; return x;", 0, Long.MAX_VALUE-3);
+ }
+
+ @Test public void testExistingOperators() {
+ check("int x=8; x+=2; x-=1; x*=3; x/=9; return x;", 0, 3);
+ check("int x=arg; int y=x++; int z=x--; return x*100+y*10+z;", 5, 556);
+ check("return (arg << 2) + (arg >> 1) + (arg >>> 1);", 8, 40);
+ check("return arg <= 8;", 8, 1);
+ check("return arg >= 8;", 8, 1);
+ }
+
+ @Test public void testRejectedAssignments() {
+ for (String op : OPS) {
+ rejected("val x=3; x " + op + " 1; return x;");
+ rejected("int x=3; x " + op + " 1.5; return x;");
+ }
+ }
+
+ private static void rejected(String src) {
+ try {
+ check(src, 0, 0);
+ fail("Accepted invalid assignment: " + src);
+ } catch (RuntimeException e) {
+ assertEquals("Must report a language error", RuntimeException.class, e.getClass());
+ assertNotNull(e.getMessage());
+ assertFalse("Must report a language error: " + e, e.getMessage().contains("Not yet implemented"));
+ }
+ }
+
+ private static void check(String src, long arg, long expected) {
+ var stop = new Parser(src).parse().iterate();
+ assertEquals(src, Long.valueOf(expected), Evaluator.evaluate(stop, arg));
+ }
+}