From 0c99d74c85b937e5d566a7f2899d75025d9c54ea Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 17 Sep 2026 14:36:22 -0700 Subject: Get makefiles and fuzzer testing uniform across chapters --- chapter24/Makefile | 6 ++--- chapter24/README.md | 18 ++++++++++----- .../java/com/seaofnodes/simple/FuzzerWrap.java | 27 +++++++++++++++++----- .../java/com/seaofnodes/simple/fuzzer/Fuzzer.java | 14 +++++++++++ 4 files changed, 50 insertions(+), 15 deletions(-) (limited to 'chapter24') 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 fuzzPeeps methods. - * This can be done from IntelliJ Gui or remove the `@Ignore` annotation and start the test case from the command line - * via mvn clean test -Dtest=com.seaofnodes.simple.Fuzzer08Test#fuzzPeeps + * 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; + } + } } -- cgit v1.2.3