summaryrefslogtreecommitdiff
path: root/chapter24
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-09-17 14:36:22 -0700
committerCliff Click <cliffc@acm.org>2026-09-17 14:36:22 -0700
commit0c99d74c85b937e5d566a7f2899d75025d9c54ea (patch)
tree9f4834d3fb1ec936fbea575d241f05a53c09336e /chapter24
parent410ee209ba1db89959f8e6be9cdaf2350e70fd27 (diff)
downloadSimple-0c99d74c85b937e5d566a7f2899d75025d9c54ea.tar.gz
Simple-0c99d74c85b937e5d566a7f2899d75025d9c54ea.zip
Get makefiles and fuzzer testing uniform across chapters
Diffstat (limited to 'chapter24')
-rw-r--r--chapter24/Makefile6
-rw-r--r--chapter24/README.md18
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/FuzzerWrap.java27
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java14
4 files changed, 50 insertions, 15 deletions
diff --git a/chapter24/Makefile b/chapter24/Makefile
index 6547a73a..deca5c76 100644
--- a/chapter24/Makefile
+++ b/chapter24/Makefile
@@ -89,7 +89,7 @@ $(CLZDIR)/main/.mtag: $(main_classes) $(main_javas)
@# This crap is really just "javac", but with a beautiful error message.
@# The very very long list of java files is suppressed and counted.
@# The required output "Note: blah blah deprecated blah" is suppressed.
- $(file > .argsM.txt , $(OODM))
+ $(file >.argsM.txt,$(OODM))
@if [ ! -z "$(OODM)" ] ; then \
echo "compiling main because " $< " and " `wc -w < .argsM.txt` " more files" ; \
if ! javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(OODM) >& .out.txt ; then \
@@ -111,7 +111,7 @@ $(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java
OODT :=
$(CLZDIR)/test/.ttag: $(test_classes) $(test_javas) $(CLZDIR)/main/.mtag
@[ -d $(CLZDIR)/test ] || mkdir -p $(CLZDIR)/test
- $(file > .argsT.txt $(OODT))
+ $(file >.argsT.txt,$(OODT))
@if [ ! -z "$(OODT)" ] ; then \
echo "compiling test because " $< " and " `wc -w < .argsT.txt` " more files" ; \
if ! javac $(JAVAC_ARGS) -cp "$(CLZDIR)/test$(SEP)$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(TST) -d $(CLZDIR)/test $(OODT) >& .out.txt ; then \
@@ -177,4 +177,4 @@ lib/hamcrest-core-1.3.jar:
# Build emacs tags (part of a tasty emacs ide experience)
tags: $(main_javas) $(test_javas)
@rm -f TAGS
- @$(CTAGS) -e --recurse=yes --extras=+q --fields=+fksaiS $(SRC) $(TST)
+ @$(CTAGS) -e --recurse=yes --extra=+q --fields=+fksaiS $(SRC) $(TST)
diff --git a/chapter24/README.md b/chapter24/README.md
index 22fda399..3774c80a 100644
--- a/chapter24/README.md
+++ b/chapter24/README.md
@@ -3,8 +3,12 @@
In this Chapter we allow *chaining* conditionals, e.g. `(60 <= score < 90)`
where `score` in the middle does not have to be repeated.
-We also present an Interprocedural Sparse Conditional Constant Propagation
-algorithm.
+The main compiler change is Interprocedural Sparse Conditional Constant
+Propagation (SCCP): an optimistic type solve which also discovers call-graph
+edges. This snapshot still uses the earlier parser/type and memory machinery;
+Chapter 25 currently contains the larger incomplete-types SSA redesign and
+separate compilation. Independent correctness fixes will move backward first;
+see the [backport review queue](../docs/chapter-backports.md).
You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter24) in a linear Git revision history on the [linear](https://github.com/SeaOfNodes/Simple/tree/linear) branch and [compare](https://github.com/SeaOfNodes/Simple/compare/linear-chapter23...linear-chapter24) it to the previous chapter.
@@ -37,7 +41,7 @@ if (60 <= score < 90) {
This checks if score is between 60 (inclusive) and 90 (exclusive), without repeating `score`.
Expressions that mix opposite directions of comparison, like using both
-`<=` and `=>`, are not allowed, because they create ambiguous logic.
+`<=` and `>=`, are not allowed by Simple's direction rule.
```java
if (a <= b >= c)
@@ -52,7 +56,8 @@ Stacked comparisons are *only* valid if all the comparison operators
- `>` with `>`
- `>` with `>=`
-All operators above can be combined with `==` and `!=`.
+Equality operators (`==` and `!=`) have their normal, lower precedence; they
+are not links in a relational chain.
It is not allowed to mix directions in a single chain:
```java
@@ -87,7 +92,8 @@ a < b && b == c
```
Comparisons can be chained together in any length, and different comparison operators may be
mixed freely as long as they point in the same direction.
-Equality(`==`) and inequality(`!=`) operators may be combined with any other comparisons at any point in the chain.
+Each intermediate operand is evaluated once. Later operands are evaluated only
+if earlier comparisons succeed, so calls and updates in a chain short-circuit.
E.g:
```
@@ -167,7 +173,7 @@ Without SCCP, this small program cannot remove the computation of `x` and hence
the loop either. A glance at the program tells us `x` must always be a `1` but
the bottom-up (pessimistic) approach decides that since x1 is BOT, x2 must be
BOT so x1 must be BOT. We need the optimistic approach to break the
-statemate, and just *assume* x1 is `1`, and then we can discover than x2 is
+stalemate, and just *assume* x1 is `1`, and then we can discover that x2 is
also a `1`.
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/FuzzerWrap.java b/chapter24/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
index d67b2065..b022bec9 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
@@ -7,15 +7,30 @@ import org.junit.Test;
import static org.junit.Assert.assertTrue;
/**
- * To use the fuzzer run the <code>fuzzPeeps</code> methods.
- * This can be done from IntelliJ Gui or remove the `@Ignore` annotation and start the test case from the command line
- * via <code>mvn clean test -Dtest=com.seaofnodes.simple.Fuzzer08Test#fuzzPeeps</code>
+ * Normal tests run chapter-local regression seeds. Open failures and exploratory
+ * fuzzing are opt-in (run directly in the IDE or temporarily remove Ignore).
+ * Seeds depend on this chapter's generator; do not copy them between chapters.
*/
public class FuzzerWrap {
+ private static final long[] REGRESSION_SEEDS = {
+ };
+
+ private static final long[] OPEN_FAILING_SEEDS = {
+ };
+
+ @Test public void fuzzPeepsRegression () { fuzzPeepsSeeds(REGRESSION_SEEDS); }
+ @Test @Ignore public void fuzzPeepsOpenFailures() { fuzzPeepsSeeds(OPEN_FAILING_SEEDS); }
+
+ private static void fuzzPeepsSeeds(long... seeds) {
+ var fuzzer = new Fuzzer();
+ for (long seed : seeds)
+ fuzzer.fuzzPeepsRegression(seed);
+ }
+
@Ignore
@Test
- public void fuzzPeeps() {
+ public void fuzzPeepsLarge() {
var fuzzer = new Fuzzer();
for (int i=0; i<1000000; i++)
fuzzer.fuzzPeeps(i);
@@ -23,8 +38,8 @@ public class FuzzerWrap {
}
- @Test
- public void fuzzPeepsSmall() {
+ @Test @Ignore
+ public void fuzzPeepsRandom() {
Random R = new Random(System.currentTimeMillis());
var fuzzer = new Fuzzer();
for (int i=0; i<100; i++)
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
index 77e61b42..962202a6 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
@@ -171,4 +171,18 @@ public class Fuzzer {
public boolean noExceptions() {
return exceptions.isEmpty();
}
+
+ /** Run a fixed chapter-local seed without reducing or swallowing failures. */
+ public void fuzzPeepsRegression(long seed) {
+ var rand = new Random(seed);
+ var sb = new StringBuilder();
+ var valid = new ScriptGenerator(rand, sb, true).genProgram();
+ try {
+ runCheck(sb.toString(), valid);
+ } catch (Throwable e) {
+ AssertionError ae = new AssertionError("Fuzzer regression seed failed: " + seed);
+ ae.initCause(e);
+ throw ae;
+ }
+ }
}