summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chapter01/README.md2
-rw-r--r--chapter01/docs/Makefile12
-rw-r--r--chapter01/src/main/java/com/seaofnodes/simple/Parser.java39
-rw-r--r--chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java23
-rw-r--r--chapter02/README.md2
-rw-r--r--chapter02/docs/Makefile12
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/Parser.java39
-rw-r--r--chapter02/src/test/java/com/seaofnodes/simple/Chapter01Test.java99
-rw-r--r--chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java86
-rw-r--r--chapter03/README.md2
-rw-r--r--chapter03/docs/Makefile12
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter03/src/test/java/com/seaofnodes/simple/Chapter01Test.java99
-rw-r--r--chapter03/src/test/java/com/seaofnodes/simple/Chapter02Test.java66
-rw-r--r--chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java138
-rw-r--r--chapter04/README.md2
-rw-r--r--chapter04/docs/Makefile12
-rw-r--r--chapter04/docs/build-graphs.sh1
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter04/src/test/java/com/seaofnodes/simple/Chapter01Test.java99
-rw-r--r--chapter04/src/test/java/com/seaofnodes/simple/Chapter02Test.java66
-rw-r--r--chapter04/src/test/java/com/seaofnodes/simple/Chapter03Test.java68
-rw-r--r--chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java227
-rw-r--r--chapter05/README.md2
-rw-r--r--chapter05/docs/Makefile12
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter05/src/test/java/com/seaofnodes/simple/Chapter01Test.java100
-rw-r--r--chapter05/src/test/java/com/seaofnodes/simple/Chapter02Test.java66
-rw-r--r--chapter05/src/test/java/com/seaofnodes/simple/Chapter03Test.java68
-rw-r--r--chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java128
-rw-r--r--chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java350
-rw-r--r--chapter06/README.md2
-rw-r--r--chapter06/docs/Makefile12
-rw-r--r--chapter06/docs/build-graphs.sh12
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter01Test.java100
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter02Test.java66
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter03Test.java68
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java128
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java214
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java533
-rw-r--r--chapter07/README.md2
-rw-r--r--chapter07/docs/Makefile12
-rw-r--r--chapter07/docs/build-graphs.sh6
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter07/src/test/java/com/seaofnodes/simple/Chapter01Test.java100
-rw-r--r--chapter07/src/test/java/com/seaofnodes/simple/Chapter02Test.java66
-rw-r--r--chapter07/src/test/java/com/seaofnodes/simple/Chapter03Test.java68
-rw-r--r--chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java128
-rw-r--r--chapter07/src/test/java/com/seaofnodes/simple/Chapter05Test.java214
-rw-r--r--chapter07/src/test/java/com/seaofnodes/simple/Chapter06Test.java294
-rw-r--r--chapter07/src/test/java/com/seaofnodes/simple/Chapter07Test.java812
-rw-r--r--chapter08/README.md2
-rw-r--r--chapter08/docs/Makefile12
-rw-r--r--chapter08/docs/build-graphs.sh6
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter01Test.java100
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter02Test.java66
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter03Test.java68
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java128
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter05Test.java212
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter06Test.java294
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter07Test.java240
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter08Test.java1050
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/FuzzerWrap.java (renamed from chapter08/src/test/java/com/seaofnodes/simple/Fuzzer08Test.java)4
-rw-r--r--chapter09/README.md2
-rw-r--r--chapter09/docs/Makefile12
-rw-r--r--chapter09/docs/build-graphs.sh6
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/Chapter01Test.java54
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/Chapter02Test.java33
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/Chapter03Test.java4
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java2
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/Chapter05Test.java14
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/Chapter06Test.java2
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/Chapter07Test.java6
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/FuzzerWrap.java3
-rw-r--r--chapter10/README.md2
-rw-r--r--chapter10/docs/Makefile12
-rw-r--r--chapter10/docs/build-graphs.sh5
-rw-r--r--chapter10/src/main/java/com/seaofnodes/simple/Parser.java10
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter01Test.java54
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter02Test.java33
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter03Test.java4
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java2
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter05Test.java14
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter06Test.java2
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter07Test.java5
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter10Test.java1
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/FuzzerWrap.java4
90 files changed, 3892 insertions, 3315 deletions
diff --git a/chapter01/README.md b/chapter01/README.md
index d4882f8a..e7ea73bc 100644
--- a/chapter01/README.md
+++ b/chapter01/README.md
@@ -1,4 +1,4 @@
-# Chapter 1
+# Chapter 1: Introduction
In this chapter we aim to compile simple scripts such as:
diff --git a/chapter01/docs/Makefile b/chapter01/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter01/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter01/src/main/java/com/seaofnodes/simple/Parser.java b/chapter01/src/main/java/com/seaofnodes/simple/Parser.java
index d79d23ff..8975a165 100644
--- a/chapter01/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter01/src/main/java/com/seaofnodes/simple/Parser.java
@@ -31,8 +31,22 @@ public class Parser {
}
public ReturnNode parse() {
- require("return");
- return parseReturn();
+ var ret = (ReturnNode) parseStatement();
+ if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken());
+ return ret;
+ }
+
+ /**
+ * Parses a statement
+ *
+ * <pre>
+ * returnStatement
+ * </pre>
+ * @return a {@link Node} or {@code null}
+ */
+ private Node parseStatement() {
+ if (matchx("return")) return parseReturn();
+ throw errorSyntax("a statement");
}
/**
@@ -89,7 +103,9 @@ public class Parser {
// Utilities for lexical analysis
// Return true and skip if "syntax" is next in the stream.
- private boolean match(String syntax) { return _lexer.match(syntax); }
+ private boolean match (String syntax) { return _lexer.match (syntax); }
+ // Match must be "exact", not be followed by more id letters
+ private boolean matchx(String syntax) { return _lexer.matchx(syntax); }
// Require an exact match
private void require(String syntax) { require(null, syntax); }
@@ -174,10 +190,18 @@ public class Parser {
return true;
}
+ boolean matchx(String syntax) {
+ if( !match(syntax) ) return false;
+ if( !isIdLetter(peek()) ) return true;
+ _position -= syntax.length();
+ return false;
+ }
+
// Used for errors
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -186,13 +210,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private long parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return Long.parseLong(snum);
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java
index 738ed702..6989d0b9 100644
--- a/chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java
+++ b/chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -44,7 +44,7 @@ public class Chapter01Test {
new Parser("ret").parse();
fail();
} catch( RuntimeException e ) {
- assertEquals("Syntax error, expected return: ret",e.getMessage());
+ assertEquals("Syntax error, expected a statement: ret",e.getMessage());
}
}
@@ -82,4 +82,25 @@ public class Chapter01Test {
exceptionRule.expectMessage("Syntax error, expected integer literal");
new Parser("return -100;").parse();
}
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected a statement: return100",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
}
diff --git a/chapter02/README.md b/chapter02/README.md
index 4b912465..500e9ae8 100644
--- a/chapter02/README.md
+++ b/chapter02/README.md
@@ -1,4 +1,4 @@
-# Chapter 2
+# Chapter 2: Arithmetic
In this chapter we extend the language grammar to include arithmetic operations such as addition, subtraction,
multiplication, division, and unary minus. This allows us to write statements such as:
diff --git a/chapter02/docs/Makefile b/chapter02/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter02/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/Parser.java b/chapter02/src/main/java/com/seaofnodes/simple/Parser.java
index 155cd353..f106bd47 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter02/src/main/java/com/seaofnodes/simple/Parser.java
@@ -34,8 +34,22 @@ public class Parser {
String src() { return new String( _lexer._input ); }
public ReturnNode parse() {
- require("return");
- return (ReturnNode) parseReturn();
+ var ret = (ReturnNode) parseStatement();
+ if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken());
+ return ret;
+ }
+
+ /**
+ * Parses a statement
+ *
+ * <pre>
+ * returnStatement
+ * </pre>
+ * @return a {@link Node} or {@code null}
+ */
+ private Node parseStatement() {
+ if (matchx("return")) return parseReturn();
+ throw errorSyntax("a statement");
}
/**
@@ -133,7 +147,9 @@ public class Parser {
// Utilities for lexical analysis
// Return true and skip if "syntax" is next in the stream.
- private boolean match(String syntax) { return _lexer.match(syntax); }
+ private boolean match (String syntax) { return _lexer.match (syntax); }
+ // Match must be "exact", not be followed by more id letters
+ private boolean matchx(String syntax) { return _lexer.matchx(syntax); }
// Require an exact match
private void require(String syntax) { require(null, syntax); }
@@ -224,10 +240,18 @@ public class Parser {
return true;
}
+ boolean matchx(String syntax) {
+ if( !match(syntax) ) return false;
+ if( !isIdLetter(peek()) ) return true;
+ _position -= syntax.length();
+ return false;
+ }
+
// Used for errors
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -236,13 +260,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter02/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter02/src/test/java/com/seaofnodes/simple/Chapter01Test.java
new file mode 100644
index 00000000..49edfb5b
--- /dev/null
+++ b/chapter02/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -0,0 +1,99 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter01Test {
+
+ @Test
+ public void testSimpleProgram() {
+ Parser parser = new Parser("return 1;");
+ ReturnNode ret = parser.parse();
+ StartNode start = Parser.START;
+
+ assertEquals(start, ret.ctrl());
+ Node expr = ret.expr();
+ if( expr instanceof ConstantNode con ) {
+ assertEquals(start,con.in(0));
+ assertEquals(TypeInteger.constant(1), con._type);
+ } else {
+ fail();
+ }
+ }
+
+ @Test
+ public void testZero() {
+ Parser parser = new Parser("return 0;");
+ parser.parse();
+ StartNode start = Parser.START;
+ for( Node use : start._outputs )
+ if( use instanceof ConstantNode con )
+ assertEquals(TypeInteger.constant(0),con._type);
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected a statement: ret",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad2() {
+ try {
+ new Parser("return 0123;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected a statement: return100",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java
index 35464955..36e62f9b 100644
--- a/chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java
+++ b/chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -2,19 +2,14 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import static org.junit.Assert.*;
public class Chapter02Test {
- @Rule
- public ExpectedException exceptionRule = ExpectedException.none();
-
@Test
- public void testChapter2ParseGrammar() {
+ public void testParseGrammar() {
Node._disablePeephole = true; // disable peephole so we can observe full graph
Parser parser = new Parser("return 1+2*3+-5;");
ReturnNode ret = parser.parse();
@@ -25,42 +20,42 @@ public class Chapter02Test {
}
@Test
- public void testChapter2AddPeephole() {
+ public void testAddPeephole() {
Parser parser = new Parser("return 1+2;");
ReturnNode ret = parser.parse();
assertEquals("return 3;", ret.print());
}
@Test
- public void testChapter2SubPeephole() {
+ public void testSubPeephole() {
Parser parser = new Parser("return 1-2;");
ReturnNode ret = parser.parse();
assertEquals("return -1;", ret.print());
}
@Test
- public void testChapter2MulPeephole() {
+ public void testMulPeephole() {
Parser parser = new Parser("return 2*3;");
ReturnNode ret = parser.parse();
assertEquals("return 6;", ret.print());
}
@Test
- public void testChapter2DivPeephole() {
+ public void testDivPeephole() {
Parser parser = new Parser("return 6/3;");
ReturnNode ret = parser.parse();
assertEquals("return 2;", ret.print());
}
@Test
- public void testChapter2MinusPeephole() {
+ public void testMinusPeephole() {
Parser parser = new Parser("return 6/-3;");
ReturnNode ret = parser.parse();
assertEquals("return -2;", ret.print());
}
@Test
- public void testChapter2Example() {
+ public void testExample() {
Parser parser = new Parser("return 1+2*3+-5;");
ReturnNode ret = parser.parse();
assertEquals("return 2;", ret.print());
@@ -68,71 +63,4 @@ public class Chapter02Test {
System.out.println(gv.generateDotOutput(parser));
}
- @Test
- public void testSimpleProgram() {
- Parser parser = new Parser("return 1;");
- ReturnNode ret = parser.parse();
- StartNode start = Parser.START;
-
- assertEquals(start, ret.ctrl());
- Node expr = ret.expr();
- if( expr instanceof ConstantNode con ) {
- assertEquals(start,con.in(0));
- assertEquals(TypeInteger.constant(1), con._type);
- } else {
- fail();
- }
- }
-
- @Test
- public void testZero() {
- Parser parser = new Parser("return 0;");
- parser.parse();
- StartNode start = Parser.START;
- for( Node use : start._outputs )
- if( use instanceof ConstantNode con )
- assertEquals(TypeInteger.constant(0),con._type);
- }
-
- @Test
- public void testBad1() {
- try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected return: ret",e.getMessage());
- }
- }
-
- @Test
- public void testBad2() {
- try {
- new Parser("return 0123;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
}
diff --git a/chapter03/README.md b/chapter03/README.md
index 7b0d22cb..0fb08e9a 100644
--- a/chapter03/README.md
+++ b/chapter03/README.md
@@ -1,4 +1,4 @@
-# Chapter 3
+# Chapter 3: Variable Declarations
In this chapter we extend the language grammar to allow variable declarations. This allows us to write:
diff --git a/chapter03/docs/Makefile b/chapter03/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter03/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/Parser.java b/chapter03/src/main/java/com/seaofnodes/simple/Parser.java
index 9c7ebaca..4fb5b6ed 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/Parser.java
@@ -363,6 +363,7 @@ public class Parser {
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -371,13 +372,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter03/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter03/src/test/java/com/seaofnodes/simple/Chapter01Test.java
new file mode 100644
index 00000000..311ca23b
--- /dev/null
+++ b/chapter03/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -0,0 +1,99 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter01Test {
+
+ @Test
+ public void testSimpleProgram() {
+ Parser parser = new Parser("return 1;");
+ ReturnNode ret = parser.parse();
+ StartNode start = Parser.START;
+
+ assertEquals(start, ret.ctrl());
+ Node expr = ret.expr();
+ if( expr instanceof ConstantNode con ) {
+ assertEquals(start,con.in(0));
+ assertEquals(TypeInteger.constant(1), con._type);
+ } else {
+ fail();
+ }
+ }
+
+ @Test
+ public void testZero() {
+ Parser parser = new Parser("return 0;");
+ parser.parse();
+ StartNode start = Parser.START;
+ for( Node use : start._outputs )
+ if( use instanceof ConstantNode con )
+ assertEquals(TypeInteger.constant(0),con._type);
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad2() {
+ try {
+ new Parser("return 0123;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter03/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter03/src/test/java/com/seaofnodes/simple/Chapter02Test.java
new file mode 100644
index 00000000..60ee8874
--- /dev/null
+++ b/chapter03/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -0,0 +1,66 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter02Test {
+
+ @Test
+ public void testParseGrammar() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ Node._disablePeephole = true; // disable peephole so we can observe full graph
+ ReturnNode ret = parser.parse();
+ assertEquals("return (1+((2*3)+(-5)));", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testAddPeephole() {
+ Parser parser = new Parser("return 1+2;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testSubPeephole() {
+ Parser parser = new Parser("return 1-2;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return -1;", ret.print());
+ }
+
+ @Test
+ public void testMulPeephole() {
+ Parser parser = new Parser("return 2*3;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 6;", ret.print());
+ }
+
+ @Test
+ public void testDivPeephole() {
+ Parser parser = new Parser("return 6/3;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testMinusPeephole() {
+ Parser parser = new Parser("return 6/-3;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return -2;", ret.print());
+ }
+
+ @Test
+ public void testExample() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ }
+
+}
diff --git a/chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java
index 965a100a..950d87fe 100644
--- a/chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java
+++ b/chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -2,17 +2,12 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import static org.junit.Assert.*;
public class Chapter03Test {
- @Rule
- public ExpectedException exceptionRule = ExpectedException.none();
-
@Test
public void testVarDecl() {
Parser parser = new Parser("int a=1; return a;");
@@ -61,131 +56,8 @@ public class Chapter03Test {
}
@Test
- public void testChapter2ParseGrammar() {
- Parser parser = new Parser("return 1+2*3+-5;");
- Node._disablePeephole = true; // disable peephole so we can observe full graph
- ReturnNode ret = parser.parse();
- assertEquals("return (1+((2*3)+(-5)));", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter2AddPeephole() {
- Parser parser = new Parser("return 1+2;");
- ReturnNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testChapter2SubPeephole() {
- Parser parser = new Parser("return 1-2;");
- ReturnNode ret = parser.parse();
- assertEquals("return -1;", ret.print());
- }
-
- @Test
- public void testChapter2MulPeephole() {
- Parser parser = new Parser("return 2*3;");
- ReturnNode ret = parser.parse();
- assertEquals("return 6;", ret.print());
- }
-
- @Test
- public void testChapter2DivPeephole() {
- Parser parser = new Parser("return 6/3;");
- ReturnNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter2MinusPeephole() {
- Parser parser = new Parser("return 6/-3;");
- ReturnNode ret = parser.parse();
- assertEquals("return -2;", ret.print());
- }
-
- @Test
- public void testChapter2Example() {
- Parser parser = new Parser("return 1+2*3+-5;");
- ReturnNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- }
-
- @Test
- public void testSimpleProgram() {
- Parser parser = new Parser("return 1;");
- ReturnNode ret = parser.parse();
- StartNode start = Parser.START;
-
- assertEquals(start, ret.ctrl());
- Node expr = ret.expr();
- if( expr instanceof ConstantNode con ) {
- assertEquals(start,con.in(0));
- assertEquals(TypeInteger.constant(1), con._type);
- } else {
- fail();
- }
- }
-
- @Test
- public void testZero() {
- Parser parser = new Parser("return 0;");
- parser.parse();
- StartNode start = Parser.START;
- for( Node use : start._outputs )
- if( use instanceof ConstantNode con )
- assertEquals(TypeInteger.constant(0),con._type);
- }
-
- @Test
public void testBad1() {
try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad2() {
- try {
- new Parser("return 0123;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
-
- @Test
- public void testBad6() {
- try {
new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
fail();
} catch( RuntimeException e ) {
@@ -193,14 +65,4 @@ public class Chapter03Test {
}
}
- @Test
- public void testBad7() {
- try {
- new Parser("return 1;}").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
- }
- }
-
}
diff --git a/chapter04/README.md b/chapter04/README.md
index 03c6c53f..1f300937 100644
--- a/chapter04/README.md
+++ b/chapter04/README.md
@@ -1,4 +1,4 @@
-# Chapter 4
+# Chapter 4: External Argument and Comparisons
In this chapter we extend the language grammar with following features:
diff --git a/chapter04/docs/Makefile b/chapter04/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter04/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter04/docs/build-graphs.sh b/chapter04/docs/build-graphs.sh
deleted file mode 100644
index e736a386..00000000
--- a/chapter04/docs/build-graphs.sh
+++ /dev/null
@@ -1 +0,0 @@
-dot -Tsvg lattice.gv > lattice.svg
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/Parser.java b/chapter04/src/main/java/com/seaofnodes/simple/Parser.java
index e42613e2..3359f14e 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/Parser.java
@@ -406,6 +406,7 @@ public class Parser {
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -414,13 +415,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter04/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter04/src/test/java/com/seaofnodes/simple/Chapter01Test.java
new file mode 100644
index 00000000..3d568337
--- /dev/null
+++ b/chapter04/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -0,0 +1,99 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter01Test {
+
+ @Test
+ public void testSimpleProgram() {
+ Parser parser = new Parser("return 1;");
+ ReturnNode ret = parser.parse();
+ StartNode start = Parser.START;
+
+ assertTrue(ret.ctrl() instanceof ProjNode);
+ Node expr = ret.expr();
+ if( expr instanceof ConstantNode con ) {
+ assertEquals(start,con.in(0));
+ assertEquals(TypeInteger.constant(1), con._type);
+ } else {
+ fail();
+ }
+ }
+
+ @Test
+ public void testZero() {
+ Parser parser = new Parser("return 0;");
+ parser.parse();
+ StartNode start = Parser.START;
+ for( Node use : start._outputs )
+ if( use instanceof ConstantNode con )
+ assertEquals(TypeInteger.constant(0),con._type);
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad2() {
+ try {
+ new Parser("return 0123;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter04/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter04/src/test/java/com/seaofnodes/simple/Chapter02Test.java
new file mode 100644
index 00000000..60ee8874
--- /dev/null
+++ b/chapter04/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -0,0 +1,66 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter02Test {
+
+ @Test
+ public void testParseGrammar() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ Node._disablePeephole = true; // disable peephole so we can observe full graph
+ ReturnNode ret = parser.parse();
+ assertEquals("return (1+((2*3)+(-5)));", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testAddPeephole() {
+ Parser parser = new Parser("return 1+2;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testSubPeephole() {
+ Parser parser = new Parser("return 1-2;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return -1;", ret.print());
+ }
+
+ @Test
+ public void testMulPeephole() {
+ Parser parser = new Parser("return 2*3;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 6;", ret.print());
+ }
+
+ @Test
+ public void testDivPeephole() {
+ Parser parser = new Parser("return 6/3;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testMinusPeephole() {
+ Parser parser = new Parser("return 6/-3;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return -2;", ret.print());
+ }
+
+ @Test
+ public void testExample() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ }
+
+}
diff --git a/chapter04/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter04/src/test/java/com/seaofnodes/simple/Chapter03Test.java
new file mode 100644
index 00000000..950d87fe
--- /dev/null
+++ b/chapter04/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -0,0 +1,68 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter03Test {
+
+ @Test
+ public void testVarDecl() {
+ Parser parser = new Parser("int a=1; return a;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testVarAdd() {
+ Parser parser = new Parser("int a=1; int b=2; return a+b;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testVarScope() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 4;", ret.print());
+ }
+
+ @Test
+ public void testVarScopeNoPeephole() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
+ Node._disablePeephole = true;
+ ReturnNode ret = parser.parse();
+ Node._disablePeephole = false;
+ assertEquals("return (1+3);", ret.print());
+ }
+
+ @Test
+ public void testVarDist() {
+ Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
+ ReturnNode ret = parser.parse();
+ assertEquals("return 8;", ret.print());
+ }
+
+ @Test
+ public void testSelfAssign() {
+ try {
+ new Parser("int a=a; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'a'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected }: ",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java
index 5757fc59..9f1535b3 100644
--- a/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java
+++ b/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -2,61 +2,56 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import static org.junit.Assert.*;
public class Chapter04Test {
- @Rule
- public ExpectedException exceptionRule = ExpectedException.none();
-
@Test
- public void testChapter4Peephole() {
+ public void testPeephole() {
Parser parser = new Parser("return 1+arg+2; #showGraph;");
ReturnNode ret = parser.parse();
assertEquals("return (arg+3);", ret.print());
}
@Test
- public void testChapter4Peephole2() {
+ public void testPeephole2() {
Parser parser = new Parser("return (1+arg)+2;");
ReturnNode ret = parser.parse();
assertEquals("return (arg+3);", ret.print());
}
@Test
- public void testChapter4Add0() {
+ public void testAdd0() {
Parser parser = new Parser("return 0+arg;");
ReturnNode ret = parser.parse();
assertEquals("return arg;", ret.print());
}
@Test
- public void testChapter4AddAddMul() {
+ public void testAddAddMul() {
Parser parser = new Parser("return arg+0+arg;");
ReturnNode ret = parser.parse();
assertEquals("return (arg*2);", ret.print());
}
@Test
- public void testChapter4Peephole3() {
+ public void testPeephole3() {
Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
ReturnNode ret = parser.parse();
assertEquals("return ((arg*2)+6);", ret.print());
}
@Test
- public void testChapter4Mul1() {
+ public void testMul1() {
Parser parser = new Parser("return 1*arg;");
ReturnNode ret = parser.parse();
assertEquals("return arg;", ret.print());
}
@Test
- public void testChapter4VarArg() {
+ public void testVarArg() {
Parser parser = new Parser("return arg; #showGraph;", TypeInteger.BOT);
ReturnNode ret = parser.parse();
assertTrue(ret.in(0) instanceof ProjNode);
@@ -64,56 +59,56 @@ public class Chapter04Test {
}
@Test
- public void testChapter4ConstantArg() {
+ public void testConstantArg() {
Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
ReturnNode ret = parser.parse();
assertEquals("return 2;", ret.print());
}
@Test
- public void testChapter4CompEq() {
+ public void testCompEq() {
Parser parser = new Parser("return 3==3; #showGraph;");
ReturnNode ret = parser.parse();
assertEquals("return 1;", ret.print());
}
@Test
- public void testChapter4CompEq2() {
+ public void testCompEq2() {
Parser parser = new Parser("return 3==4; #showGraph;");
ReturnNode ret = parser.parse();
assertEquals("return 0;", ret.print());
}
@Test
- public void testChapter4CompNEq() {
+ public void testCompNEq() {
Parser parser = new Parser("return 3!=3; #showGraph;");
ReturnNode ret = parser.parse();
assertEquals("return 0;", ret.print());
}
@Test
- public void testChapter4CompNEq2() {
+ public void testCompNEq2() {
Parser parser = new Parser("return 3!=4; #showGraph;");
ReturnNode ret = parser.parse();
assertEquals("return 1;", ret.print());
}
@Test
- public void testChapter4Bug1() {
+ public void testBug1() {
Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
ReturnNode ret = parser.parse();
assertEquals("return (arg+3);", ret.print());
}
@Test
- public void testChapter4Bug2() {
+ public void testBug2() {
Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
ReturnNode ret = parser.parse();
assertEquals("return (arg+1);", ret.print());
}
@Test
- public void testChapter4Bug3() {
+ public void testBug3() {
try {
new Parser("inta=1; return a;").parse();
fail();
@@ -123,200 +118,10 @@ public class Chapter04Test {
}
@Test
- public void testChapter4Bug4() {
+ public void testBug4() {
Parser parser = new Parser("return -arg;");
ReturnNode ret = parser.parse();
assertEquals("return (-arg);", ret.print());
}
- @Test
- public void testVarDecl() {
- Parser parser = new Parser("int a=1; return a;");
- ReturnNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testVarAdd() {
- Parser parser = new Parser("int a=1; int b=2; return a+b;");
- ReturnNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testVarScope() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
- ReturnNode ret = parser.parse();
- assertEquals("return 4;", ret.print());
- }
-
- @Test
- public void testVarScopeNoPeephole() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
- Node._disablePeephole = true;
- ReturnNode ret = parser.parse();
- Node._disablePeephole = false;
- assertEquals("return (1+3);", ret.print());
- }
-
- @Test
- public void testVarDist() {
- Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
- ReturnNode ret = parser.parse();
- assertEquals("return 8;", ret.print());
- }
-
- @Test
- public void testSelfAssign() {
- try {
- new Parser("int a=a; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'a'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter2ParseGrammar() {
- Parser parser = new Parser("return 1+2*3+-5;");
- Node._disablePeephole = true; // disable peephole so we can observe full graph
- ReturnNode ret = parser.parse();
- assertEquals("return (1+((2*3)+(-5)));", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter2AddPeephole() {
- Parser parser = new Parser("return 1+2;");
- ReturnNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testChapter2SubPeephole() {
- Parser parser = new Parser("return 1-2;");
- ReturnNode ret = parser.parse();
- assertEquals("return -1;", ret.print());
- }
-
- @Test
- public void testChapter2MulPeephole() {
- Parser parser = new Parser("return 2*3;");
- ReturnNode ret = parser.parse();
- assertEquals("return 6;", ret.print());
- }
-
- @Test
- public void testChapter2DivPeephole() {
- Parser parser = new Parser("return 6/3;");
- ReturnNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter2MinusPeephole() {
- Parser parser = new Parser("return 6/-3;");
- ReturnNode ret = parser.parse();
- assertEquals("return -2;", ret.print());
- }
-
- @Test
- public void testChapter2Example() {
- Parser parser = new Parser("return 1+2*3+-5;");
- ReturnNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- }
-
- @Test
- public void testSimpleProgram() {
- Parser parser = new Parser("return 1;");
- ReturnNode ret = parser.parse();
- StartNode start = Parser.START;
-
- assertTrue(ret.ctrl() instanceof ProjNode);
- Node expr = ret.expr();
- if( expr instanceof ConstantNode con ) {
- assertEquals(start,con.in(0));
- assertEquals(TypeInteger.constant(1), con._type);
- } else {
- fail();
- }
- }
-
- @Test
- public void testZero() {
- Parser parser = new Parser("return 0;");
- parser.parse();
- StartNode start = Parser.START;
- for( Node use : start._outputs )
- if( use instanceof ConstantNode con )
- assertEquals(TypeInteger.constant(0),con._type);
- }
-
- @Test
- public void testBad1() {
- try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad2() {
- try {
- new Parser("return 0123;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
-
- @Test
- public void testBad6() {
- try {
- new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected }: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad7() {
- try {
- new Parser("return 1;}").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
- }
- }
-
}
diff --git a/chapter05/README.md b/chapter05/README.md
index cf95b545..4d36e40c 100644
--- a/chapter05/README.md
+++ b/chapter05/README.md
@@ -1,4 +1,4 @@
-# Chapter 5
+# Chapter 5: If Statement, Phi, and Region
In this chapter we extend the language grammar with the following features:
diff --git a/chapter05/docs/Makefile b/chapter05/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter05/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/Parser.java b/chapter05/src/main/java/com/seaofnodes/simple/Parser.java
index ff58fc25..8a02766f 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/Parser.java
@@ -476,6 +476,7 @@ public class Parser {
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -484,13 +485,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter05/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter05/src/test/java/com/seaofnodes/simple/Chapter01Test.java
new file mode 100644
index 00000000..547c36f8
--- /dev/null
+++ b/chapter05/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -0,0 +1,100 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter01Test {
+
+ @Test
+ public void testSimpleProgram() {
+ Parser parser = new Parser("return 1;");
+ StopNode stop = parser.parse();
+ StartNode start = Parser.START;
+ ReturnNode ret = (ReturnNode)stop.in(0);
+
+ assertTrue(ret.ctrl() instanceof ProjNode);
+ Node expr = ret.expr();
+ if( expr instanceof ConstantNode con ) {
+ assertEquals(start,con.in(0));
+ assertEquals(TypeInteger.constant(1), con._type);
+ } else {
+ fail();
+ }
+ }
+
+ @Test
+ public void testZero() {
+ Parser parser = new Parser("return 0;");
+ parser.parse();
+ StartNode start = Parser.START;
+ for( Node use : start._outputs )
+ if( use instanceof ConstantNode con )
+ assertEquals(TypeInteger.constant(0),con._type);
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad2() {
+ try {
+ new Parser("return 0123;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter05/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter05/src/test/java/com/seaofnodes/simple/Chapter02Test.java
new file mode 100644
index 00000000..4085ed7e
--- /dev/null
+++ b/chapter05/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -0,0 +1,66 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter02Test {
+
+ @Test
+ public void testParseGrammar() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ Node._disablePeephole = true; // disable peephole so we can observe full graph
+ StopNode ret = parser.parse();
+ assertEquals("return (1+((2*3)+(-5)));", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testAddPeephole() {
+ Parser parser = new Parser("return 1+2;");
+ StopNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testSubPeephole() {
+ Parser parser = new Parser("return 1-2;");
+ StopNode ret = parser.parse();
+ assertEquals("return -1;", ret.print());
+ }
+
+ @Test
+ public void testMulPeephole() {
+ Parser parser = new Parser("return 2*3;");
+ StopNode ret = parser.parse();
+ assertEquals("return 6;", ret.print());
+ }
+
+ @Test
+ public void testDivPeephole() {
+ Parser parser = new Parser("return 6/3;");
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testMinusPeephole() {
+ Parser parser = new Parser("return 6/-3;");
+ StopNode ret = parser.parse();
+ assertEquals("return -2;", ret.print());
+ }
+
+ @Test
+ public void testExample() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ }
+
+}
diff --git a/chapter05/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter05/src/test/java/com/seaofnodes/simple/Chapter03Test.java
new file mode 100644
index 00000000..407fbe48
--- /dev/null
+++ b/chapter05/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -0,0 +1,68 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter03Test {
+
+ @Test
+ public void testVarDecl() {
+ Parser parser = new Parser("int a=1; return a;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testVarAdd() {
+ Parser parser = new Parser("int a=1; int b=2; return a+b;");
+ StopNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testVarScope() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
+ StopNode ret = parser.parse();
+ assertEquals("return 4;", ret.print());
+ }
+
+ @Test
+ public void testVarScopeNoPeephole() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
+ Node._disablePeephole = true;
+ StopNode ret = parser.parse();
+ Node._disablePeephole = false;
+ assertEquals("return (1+3);", ret.print());
+ }
+
+ @Test
+ public void testVarDist() {
+ Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 8;", ret.print());
+ }
+
+ @Test
+ public void testSelfAssign() {
+ try {
+ new Parser("int a=a; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'a'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected }: ",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java
new file mode 100644
index 00000000..cde23324
--- /dev/null
+++ b/chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -0,0 +1,128 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter04Test {
+
+ @Test
+ public void testPeephole() {
+ Parser parser = new Parser("return 1+arg+2; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testPeephole2() {
+ Parser parser = new Parser("return (1+arg)+2;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testAdd0() {
+ Parser parser = new Parser("return 0+arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return arg;", ret.print());
+ }
+
+ @Test
+ public void testAddAddMul() {
+ Parser parser = new Parser("return arg+0+arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg*2);", ret.print());
+ }
+
+ @Test
+ public void testPeephole3() {
+ Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return ((arg*2)+6);", ret.print());
+ }
+
+ @Test
+ public void testMul1() {
+ Parser parser = new Parser("return 1*arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return arg;", ret.print());
+ }
+
+ @Test
+ public void testVarArg() {
+ Parser parser = new Parser("return arg; #showGraph;");
+ StopNode stop = parser.parse();
+ ReturnNode ret = stop.ret();
+ assertTrue(ret.in(0) instanceof ProjNode);
+ assertTrue(ret.in(1) instanceof ProjNode);
+ }
+
+ @Test
+ public void testConstantArg() {
+ Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testCompEq() {
+ Parser parser = new Parser("return 3==3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testCompEq2() {
+ Parser parser = new Parser("return 3==4; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 0;", ret.print());
+ }
+
+ @Test
+ public void testCompNEq() {
+ Parser parser = new Parser("return 3!=3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 0;", ret.print());
+ }
+
+ @Test
+ public void testCompNEq2() {
+ Parser parser = new Parser("return 3!=4; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testBug1() {
+ Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testBug2() {
+ Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+1);", ret.print());
+ }
+
+ @Test
+ public void testBug3() {
+ try {
+ new Parser("inta=1; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'inta'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBug4() {
+ Parser parser = new Parser("return -arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return (-arg);", ret.print());
+ }
+
+}
diff --git a/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java
index 97666d27..b5fcbeaf 100644
--- a/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java
+++ b/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -2,16 +2,14 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import static org.junit.Assert.*;
public class Chapter05Test {
@Test
- public void testChapter5IfStmt() {
+ public void testIfStmt() {
Parser parser = new Parser(
"""
int a = 1;
@@ -28,7 +26,7 @@ return a;""");
}
@Test
- public void testChapter5Test() {
+ public void testTest() {
Parser parser = new Parser(
"""
int c = 3;
@@ -43,7 +41,7 @@ return c;""", TypeInteger.BOT);
}
@Test
- public void testChapter5Return2() {
+ public void testReturn2() {
Parser parser = new Parser(
"""
if( arg==1 )
@@ -56,7 +54,7 @@ else
}
@Test
- public void testChapter5IfMergeB() {
+ public void testIfMergeB() {
Parser parser = new Parser(
"""
int a=arg+1;
@@ -71,7 +69,7 @@ return a+b;""");
}
@Test
- public void testChapter5IfMerge2() {
+ public void testIfMerge2() {
Parser parser = new Parser(
"""
int a=arg+1;
@@ -86,7 +84,7 @@ return a+b;""");
}
@Test
- public void testChapter5Merge3() {
+ public void testMerge3() {
Parser parser = new Parser(
"""
int a=1;
@@ -106,7 +104,7 @@ return a;
}
@Test
- public void testChapter5Merge4() {
+ public void testMerge4() {
Parser parser = new Parser(
"""
int a=0;
@@ -122,7 +120,7 @@ return arg+a+b;
}
@Test
- public void testChapter5Merge5() {
+ public void testMerge5() {
Parser parser = new Parser(
"""
int a=arg==2;
@@ -136,13 +134,13 @@ return a;""");
}
@Test
- public void testChapter5True() {
+ public void testTrue() {
StopNode stop = new Parser("return true;").parse();
assertEquals("return 1;",stop.toString());
}
@Test
- public void testChapter5HalfDef() {
+ public void testHalfDef() {
try {
new Parser("if( arg==1 ) int b=2; return b;").parse();
fail();
@@ -152,7 +150,7 @@ return a;""");
}
@Test
- public void testChapter5HalfDef2() {
+ public void testHalfDef2() {
try {
new Parser("if( arg==1 ) { int b=2; } else { int b=3; } return b;").parse();
fail();
@@ -162,7 +160,17 @@ return a;""");
}
@Test
- public void testChapter5BadNum() {
+ public void testRegress1() {
+ try {
+ new Parser("if(arg==2) int a=1; else int b=2; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadNum() {
try {
new Parser("return 1-;").parse();
fail();
@@ -172,7 +180,7 @@ return a;""");
}
@Test
- public void testChapter5Keyword1() {
+ public void testKeyword1() {
try {
new Parser("int true=0; return true;").parse();
fail();
@@ -182,7 +190,7 @@ return a;""");
}
@Test
- public void testChapter5Keyword2() {
+ public void testKeyword2() {
try {
new Parser("int else=arg; if(else) else=2; else else=1; return else;").parse();
fail();
@@ -192,7 +200,7 @@ return a;""");
}
@Test
- public void testChapter5Keyword3() {
+ public void testKeyword3() {
try {
new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
fail();
@@ -201,312 +209,4 @@ return a;""");
}
}
- @Test
- public void testChapter4Peephole() {
- Parser parser = new Parser("return 1+arg+2; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Peephole2() {
- Parser parser = new Parser("return (1+arg)+2;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Add0() {
- Parser parser = new Parser("return 0+arg;");
- StopNode ret = parser.parse();
- assertEquals("return arg;", ret.print());
- }
-
- @Test
- public void testChapter4AddAddMul() {
- Parser parser = new Parser("return arg+0+arg;");
- StopNode ret = parser.parse();
- assertEquals("return (arg*2);", ret.print());
- }
-
- @Test
- public void testChapter4Peephole3() {
- Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return ((arg*2)+6);", ret.print());
- }
-
- @Test
- public void testChapter4Mul1() {
- Parser parser = new Parser("return 1*arg;");
- StopNode ret = parser.parse();
- assertEquals("return arg;", ret.print());
- }
-
- @Test
- public void testChapter4VarArg() {
- Parser parser = new Parser("return arg; #showGraph;");
- StopNode stop = parser.parse();
- ReturnNode ret = stop.ret();
- assertTrue(ret.in(0) instanceof ProjNode);
- assertTrue(ret.in(1) instanceof ProjNode);
- }
-
- @Test
- public void testChapter4ConstantArg() {
- Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter4CompEq() {
- Parser parser = new Parser("return 3==3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testChapter4CompEq2() {
- Parser parser = new Parser("return 3==4; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 0;", ret.print());
- }
-
- @Test
- public void testChapter4CompNEq() {
- Parser parser = new Parser("return 3!=3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 0;", ret.print());
- }
-
- @Test
- public void testChapter4CompNEq2() {
- Parser parser = new Parser("return 3!=4; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testChapter4Bug1() {
- Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Bug2() {
- Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+1);", ret.print());
- }
-
- @Test
- public void testChapter4Bug3() {
- try {
- new Parser("inta=1; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'inta'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter4Bug4() {
- Parser parser = new Parser("return -arg;");
- StopNode ret = parser.parse();
- assertEquals("return (-arg);", ret.print());
- }
-
- @Test
- public void testVarDecl() {
- Parser parser = new Parser("int a=1; return a;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testVarAdd() {
- Parser parser = new Parser("int a=1; int b=2; return a+b;");
- StopNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testVarScope() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
- StopNode ret = parser.parse();
- assertEquals("return 4;", ret.print());
- }
-
- @Test
- public void testVarScopeNoPeephole() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
- Node._disablePeephole = true;
- StopNode ret = parser.parse();
- Node._disablePeephole = false;
- assertEquals("return (1+3);", ret.print());
- }
-
- @Test
- public void testVarDist() {
- Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 8;", ret.print());
- }
-
- @Test
- public void testSelfAssign() {
- try {
- new Parser("int a=a; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'a'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter2ParseGrammar() {
- Parser parser = new Parser("return 1+2*3+-5;");
- Node._disablePeephole = true; // disable peephole so we can observe full graph
- StopNode ret = parser.parse();
- assertEquals("return (1+((2*3)+(-5)));", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter2AddPeephole() {
- Parser parser = new Parser("return 1+2;");
- StopNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testChapter2SubPeephole() {
- Parser parser = new Parser("return 1-2;");
- StopNode ret = parser.parse();
- assertEquals("return -1;", ret.print());
- }
-
- @Test
- public void testChapter2MulPeephole() {
- Parser parser = new Parser("return 2*3;");
- StopNode ret = parser.parse();
- assertEquals("return 6;", ret.print());
- }
-
- @Test
- public void testChapter2DivPeephole() {
- Parser parser = new Parser("return 6/3;");
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter2MinusPeephole() {
- Parser parser = new Parser("return 6/-3;");
- StopNode ret = parser.parse();
- assertEquals("return -2;", ret.print());
- }
-
- @Test
- public void testChapter2Example() {
- Parser parser = new Parser("return 1+2*3+-5;");
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- }
-
- @Test
- public void testSimpleProgram() {
- Parser parser = new Parser("return 1;");
- StopNode stop = parser.parse();
- StartNode start = Parser.START;
- ReturnNode ret = (ReturnNode)stop.in(0);
-
- assertTrue(ret.ctrl() instanceof ProjNode);
- Node expr = ret.expr();
- if( expr instanceof ConstantNode con ) {
- assertEquals(start,con.in(0));
- assertEquals(TypeInteger.constant(1), con._type);
- } else {
- fail();
- }
- }
-
- @Test
- public void testZero() {
- Parser parser = new Parser("return 0;");
- parser.parse();
- StartNode start = Parser.START;
- for( Node use : start._outputs )
- if( use instanceof ConstantNode con )
- assertEquals(TypeInteger.constant(0),con._type);
- }
-
- @Test
- public void testBad1() {
- try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad2() {
- try {
- new Parser("return 0123;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
-
- @Test
- public void testBad6() {
- try {
- new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected }: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad7() {
- try {
- new Parser("return 1;}").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
- }
- }
-
}
diff --git a/chapter06/README.md b/chapter06/README.md
index cb265f5b..1c09be27 100644
--- a/chapter06/README.md
+++ b/chapter06/README.md
@@ -1,4 +1,4 @@
-# Chapter 6
+# Chapter 6: Peepholes for If
In this chapter we do not add new language features. Our goal is to add peephole optimization to `if` statements.
diff --git a/chapter06/docs/Makefile b/chapter06/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter06/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter06/docs/build-graphs.sh b/chapter06/docs/build-graphs.sh
deleted file mode 100644
index 6b3f5bb2..00000000
--- a/chapter06/docs/build-graphs.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-dot -Tsvg 06-graph1-pre.gv > 06-graph1-pre.svg
-dot -Tsvg 06-graph1-post.gv > 06-graph1-post.svg
-dot -Tsvg 06-graph2-pre.gv > 06-graph2-pre.svg
-dot -Tsvg 06-graph2-post.gv > 06-graph2-post.svg
-dot -Tsvg 06-graph3-nonconst.gv > 06-graph3-nonconst.svg
-dot -Tsvg 06-graph3-nonconst-peephole.gv > 06-graph3-nonconst-peephole.svg
-dot -Tsvg 06-graph3-true.gv > 06-graph3-true.svg
-dot -Tsvg 06-graph3-false.gv > 06-graph3-false.svg
-dot -Tsvg 06-graph4-nonconst.gv > 06-graph4-nonconst.svg
-dot -Tsvg 06-graph4-true.gv > 06-graph4-true.svg
-dot -Tsvg 06-graph4-arg2.gv > 06-graph4-arg2.svg
-dot -Tsvg lattice.gv > lattice.svg
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/Parser.java b/chapter06/src/main/java/com/seaofnodes/simple/Parser.java
index 54c5b15c..83eaa099 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/Parser.java
@@ -477,6 +477,7 @@ public class Parser {
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -485,13 +486,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter01Test.java
new file mode 100644
index 00000000..547c36f8
--- /dev/null
+++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -0,0 +1,100 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter01Test {
+
+ @Test
+ public void testSimpleProgram() {
+ Parser parser = new Parser("return 1;");
+ StopNode stop = parser.parse();
+ StartNode start = Parser.START;
+ ReturnNode ret = (ReturnNode)stop.in(0);
+
+ assertTrue(ret.ctrl() instanceof ProjNode);
+ Node expr = ret.expr();
+ if( expr instanceof ConstantNode con ) {
+ assertEquals(start,con.in(0));
+ assertEquals(TypeInteger.constant(1), con._type);
+ } else {
+ fail();
+ }
+ }
+
+ @Test
+ public void testZero() {
+ Parser parser = new Parser("return 0;");
+ parser.parse();
+ StartNode start = Parser.START;
+ for( Node use : start._outputs )
+ if( use instanceof ConstantNode con )
+ assertEquals(TypeInteger.constant(0),con._type);
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad2() {
+ try {
+ new Parser("return 0123;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter02Test.java
new file mode 100644
index 00000000..4085ed7e
--- /dev/null
+++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -0,0 +1,66 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter02Test {
+
+ @Test
+ public void testParseGrammar() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ Node._disablePeephole = true; // disable peephole so we can observe full graph
+ StopNode ret = parser.parse();
+ assertEquals("return (1+((2*3)+(-5)));", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testAddPeephole() {
+ Parser parser = new Parser("return 1+2;");
+ StopNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testSubPeephole() {
+ Parser parser = new Parser("return 1-2;");
+ StopNode ret = parser.parse();
+ assertEquals("return -1;", ret.print());
+ }
+
+ @Test
+ public void testMulPeephole() {
+ Parser parser = new Parser("return 2*3;");
+ StopNode ret = parser.parse();
+ assertEquals("return 6;", ret.print());
+ }
+
+ @Test
+ public void testDivPeephole() {
+ Parser parser = new Parser("return 6/3;");
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testMinusPeephole() {
+ Parser parser = new Parser("return 6/-3;");
+ StopNode ret = parser.parse();
+ assertEquals("return -2;", ret.print());
+ }
+
+ @Test
+ public void testExample() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ }
+
+}
diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter03Test.java
new file mode 100644
index 00000000..407fbe48
--- /dev/null
+++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -0,0 +1,68 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter03Test {
+
+ @Test
+ public void testVarDecl() {
+ Parser parser = new Parser("int a=1; return a;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testVarAdd() {
+ Parser parser = new Parser("int a=1; int b=2; return a+b;");
+ StopNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testVarScope() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
+ StopNode ret = parser.parse();
+ assertEquals("return 4;", ret.print());
+ }
+
+ @Test
+ public void testVarScopeNoPeephole() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
+ Node._disablePeephole = true;
+ StopNode ret = parser.parse();
+ Node._disablePeephole = false;
+ assertEquals("return (1+3);", ret.print());
+ }
+
+ @Test
+ public void testVarDist() {
+ Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 8;", ret.print());
+ }
+
+ @Test
+ public void testSelfAssign() {
+ try {
+ new Parser("int a=a; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'a'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected }: ",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java
new file mode 100644
index 00000000..cde23324
--- /dev/null
+++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -0,0 +1,128 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter04Test {
+
+ @Test
+ public void testPeephole() {
+ Parser parser = new Parser("return 1+arg+2; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testPeephole2() {
+ Parser parser = new Parser("return (1+arg)+2;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testAdd0() {
+ Parser parser = new Parser("return 0+arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return arg;", ret.print());
+ }
+
+ @Test
+ public void testAddAddMul() {
+ Parser parser = new Parser("return arg+0+arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg*2);", ret.print());
+ }
+
+ @Test
+ public void testPeephole3() {
+ Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return ((arg*2)+6);", ret.print());
+ }
+
+ @Test
+ public void testMul1() {
+ Parser parser = new Parser("return 1*arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return arg;", ret.print());
+ }
+
+ @Test
+ public void testVarArg() {
+ Parser parser = new Parser("return arg; #showGraph;");
+ StopNode stop = parser.parse();
+ ReturnNode ret = stop.ret();
+ assertTrue(ret.in(0) instanceof ProjNode);
+ assertTrue(ret.in(1) instanceof ProjNode);
+ }
+
+ @Test
+ public void testConstantArg() {
+ Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testCompEq() {
+ Parser parser = new Parser("return 3==3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testCompEq2() {
+ Parser parser = new Parser("return 3==4; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 0;", ret.print());
+ }
+
+ @Test
+ public void testCompNEq() {
+ Parser parser = new Parser("return 3!=3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 0;", ret.print());
+ }
+
+ @Test
+ public void testCompNEq2() {
+ Parser parser = new Parser("return 3!=4; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testBug1() {
+ Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testBug2() {
+ Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+1);", ret.print());
+ }
+
+ @Test
+ public void testBug3() {
+ try {
+ new Parser("inta=1; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'inta'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBug4() {
+ Parser parser = new Parser("return -arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return (-arg);", ret.print());
+ }
+
+}
diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java
new file mode 100644
index 00000000..fa576700
--- /dev/null
+++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -0,0 +1,214 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.junit.Assert.*;
+
+public class Chapter05Test {
+
+ @Test
+ public void testIfStmt() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+if (arg == 1)
+ a = arg+2;
+else {
+ a = arg-3;
+ #showGraph;
+}
+#showGraph;
+return a;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return Phi(Region17,(arg+2),(arg-3));", ret.toString());
+ }
+
+ @Test
+ public void testTest() {
+ Parser parser = new Parser(
+"""
+int c = 3;
+int b = 2;
+if (arg == 1) {
+ b = 3;
+ c = 4;
+}
+return c;""", TypeInteger.BOT);
+ StopNode ret = parser.parse(true);
+ assertEquals("return Phi(Region16,4,3);", ret.toString());
+ }
+
+ @Test
+ public void testReturn2() {
+ Parser parser = new Parser(
+"""
+if( arg==1 )
+ return 3;
+else
+ return 4;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("Stop[ return 3; return 4; ]", stop.toString());
+ }
+
+ @Test
+ public void testIfMergeB() {
+ Parser parser = new Parser(
+"""
+int a=arg+1;
+int b=0;
+if( arg==1 )
+ b=a;
+else
+ b=a+1;
+return a+b;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return ((arg*2)+Phi(Region20,2,3));", ret.toString());
+ }
+
+ @Test
+ public void testIfMerge2() {
+ Parser parser = new Parser(
+"""
+int a=arg+1;
+int b=arg+2;
+if( arg==1 )
+ b=b+a;
+else
+ a=b+1;
+return a+b;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region31,4,5));", ret.toString());
+ }
+
+ @Test
+ public void testMerge3() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( arg==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("return Phi(Region33,Phi(Region21,2,3),Phi(Region31,4,5));", stop.toString());
+ }
+
+ @Test
+ public void testMerge4() {
+ Parser parser = new Parser(
+"""
+int a=0;
+int b=0;
+if( arg )
+ a=1;
+if( arg==0 )
+ b=2;
+return arg+a+b;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("return ((arg+Phi(Region13,1,0))+Phi(Region22,2,0));", stop.toString());
+ }
+
+ @Test
+ public void testMerge5() {
+ Parser parser = new Parser(
+"""
+int a=arg==2;
+if( arg==1 )
+{
+ a=arg==3;
+}
+return a;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return (arg==Phi(Region16,3,2));", ret.toString());
+ }
+
+ @Test
+ public void testTrue() {
+ StopNode stop = new Parser("return true;").parse();
+ assertEquals("return 1;",stop.toString());
+ }
+
+ @Test
+ public void testHalfDef() {
+ try {
+ new Parser("if( arg==1 ) int b=2; return b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testHalfDef2() {
+ try {
+ new Parser("if( arg==1 ) { int b=2; } else { int b=3; } return b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'b'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testRegress1() {
+ try {
+ new Parser("if(arg==2) int a=1; else int b=2; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadNum() {
+ try {
+ new Parser("return 1-;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected an identifier or expression: ;",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword1() {
+ try {
+ new Parser("int true=0; return true;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Expected an identifier, found 'true'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword2() {
+ try {
+ new Parser("int else=arg; if(else) else=2; else else=1; return else;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Expected an identifier, found 'else'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword3() {
+ try {
+ new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: (",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java
index fbafad2f..0a61d358 100644
--- a/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java
+++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -9,7 +9,7 @@ import static org.junit.Assert.*;
public class Chapter06Test {
@Test
- public void testChapter6PeepholeReturn() {
+ public void testPeepholeReturn() {
Parser parser = new Parser(
"""
if( true ) return 2;
@@ -21,7 +21,7 @@ return 1;
}
@Test
- public void testChapter6PeepholeRotate() {
+ public void testPeepholeRotate() {
Parser parser = new Parser(
"""
int a = 1;
@@ -34,7 +34,7 @@ return (arg < a) < 3;
}
@Test
- public void testChapter6PeepholeCFG() {
+ public void testPeepholeCFG() {
Parser parser = new Parser(
"""
int a=1;
@@ -50,7 +50,7 @@ return a;
}
@Test
- public void testChapter6IfIf() {
+ public void testIfIf() {
Parser parser = new Parser(
"""
int a=1;
@@ -69,7 +69,7 @@ return b;""", TypeInteger.BOT);
}
@Test
- public void testChapter6IfArgIf() {
+ public void testIfArgIf() {
Parser parser = new Parser(
"""
int a=1;
@@ -88,7 +88,7 @@ return b;""", TypeInteger.BOT);
}
@Test
- public void testChapter6Merge3With2() {
+ public void testMerge3With2() {
Parser parser = new Parser(
"""
int a=1;
@@ -108,7 +108,7 @@ return a;
}
@Test
- public void testChapter6Merge3With1() {
+ public void testMerge3With1() {
Parser parser = new Parser(
"""
int a=1;
@@ -128,7 +128,7 @@ return a;
}
@Test
- public void testChapter6Merge3Peephole() {
+ public void testMerge3Peephole() {
Parser parser = new Parser(
"""
int a=1;
@@ -148,7 +148,7 @@ return a;
}
@Test
- public void testChapter6Merge3Peephole1() {
+ public void testMerge3Peephole1() {
Parser parser = new Parser(
"""
int a=1;
@@ -168,7 +168,7 @@ return a;
}
@Test
- public void testChapter6Merge3Peephole3() {
+ public void testMerge3Peephole3() {
Parser parser = new Parser(
"""
int a=1;
@@ -188,7 +188,7 @@ return a;
}
@Test
- public void testChapter6Demo1NonConst() {
+ public void testDemo1NonConst() {
Parser parser = new Parser("""
int a = 0;
int b = 1;
@@ -205,7 +205,7 @@ return a+b;
@Test
- public void testChapter6Demo1True() {
+ public void testDemo1True() {
Parser parser = new Parser("""
int a = 0;
int b = 1;
@@ -221,7 +221,7 @@ return a+b;
}
@Test
- public void testChapter6Demo1False() {
+ public void testDemo1False() {
Parser parser = new Parser("""
int a = 0;
int b = 1;
@@ -237,7 +237,7 @@ return a+b;
}
@Test
- public void testChapter6Demo2NonConst() {
+ public void testDemo2NonConst() {
Parser parser = new Parser("""
int a = 0;
int b = 1;
@@ -256,7 +256,7 @@ return a+b+c;
@Test
- public void testChapter6Demo2True() {
+ public void testDemo2True() {
Parser parser = new Parser("""
int a = 0;
int b = 1;
@@ -274,7 +274,7 @@ return a+b+c;
}
@Test
- public void testChapter6Demo2arg2() {
+ public void testDemo2arg2() {
Parser parser = new Parser("""
int a = 0;
int b = 1;
@@ -291,505 +291,4 @@ return a+b+c;
assertEquals("return 5;", ret.toString());
}
-
-
- @Test
- public void testChapter5IfStmt() {
- Parser parser = new Parser(
-"""
-int a = 1;
-if (arg == 1)
- a = arg+2;
-else {
- a = arg-3;
- #showGraph;
-}
-#showGraph;
-return a;""");
- StopNode ret = parser.parse(true);
- assertEquals("return Phi(Region17,(arg+2),(arg-3));", ret.toString());
- }
-
- @Test
- public void testChapter5Test() {
- Parser parser = new Parser(
-"""
-int c = 3;
-int b = 2;
-if (arg == 1) {
- b = 3;
- c = 4;
-}
-return c;""", TypeInteger.BOT);
- StopNode ret = parser.parse(true);
- assertEquals("return Phi(Region16,4,3);", ret.toString());
- }
-
- @Test
- public void testChapter5Return2() {
- Parser parser = new Parser(
-"""
-if( arg==1 )
- return 3;
-else
- return 4;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("Stop[ return 3; return 4; ]", stop.toString());
- }
-
- @Test
- public void testChapter5IfMergeB() {
- Parser parser = new Parser(
-"""
-int a=arg+1;
-int b=0;
-if( arg==1 )
- b=a;
-else
- b=a+1;
-return a+b;""");
- StopNode ret = parser.parse(true);
- assertEquals("return ((arg*2)+Phi(Region20,2,3));", ret.toString());
- }
-
- @Test
- public void testChapter5IfMerge2() {
- Parser parser = new Parser(
-"""
-int a=arg+1;
-int b=arg+2;
-if( arg==1 )
- b=b+a;
-else
- a=b+1;
-return a+b;""");
- StopNode ret = parser.parse(true);
- assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region31,4,5));", ret.toString());
- }
-
- @Test
- public void testChapter5Merge3() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( arg==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("return Phi(Region33,Phi(Region21,2,3),Phi(Region31,4,5));", stop.toString());
- }
-
- @Test
- public void testChapter5Merge4() {
- Parser parser = new Parser(
-"""
-int a=0;
-int b=0;
-if( arg )
- a=1;
-if( arg==0 )
- b=2;
-return arg+a+b;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("return ((arg+Phi(Region13,1,0))+Phi(Region22,2,0));", stop.toString());
- }
-
- @Test
- public void testChapter5Merge5() {
- Parser parser = new Parser(
-"""
-int a=arg==2;
-if( arg==1 )
-{
- a=arg==3;
-}
-return a;""");
- StopNode ret = parser.parse(true);
- assertEquals("return (arg==Phi(Region16,3,2));", ret.toString());
- }
-
- @Test
- public void testChapter5True() {
- StopNode stop = new Parser("return true;").parse();
- assertEquals("return 1;",stop.toString());
- }
-
- @Test
- public void testChapter5HalfDef() {
- try {
- new Parser("if( arg==1 ) int b=2; return b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5HalfDef2() {
- try {
- new Parser("if( arg==1 ) { int b=2; } else { int b=3; } return b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'b'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5BadNum() {
- try {
- new Parser("return 1-;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected an identifier or expression: ;",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword1() {
- try {
- new Parser("int true=0; return true;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Expected an identifier, found 'true'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword2() {
- try {
- new Parser("int else=arg; if(else) else=2; else else=1; return else;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Expected an identifier, found 'else'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword3() {
- try {
- new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: (",e.getMessage());
- }
- }
-
- @Test
- public void testChapter4Peephole() {
- Parser parser = new Parser("return 1+arg+2; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Peephole2() {
- Parser parser = new Parser("return (1+arg)+2;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Add0() {
- Parser parser = new Parser("return 0+arg;");
- StopNode ret = parser.parse();
- assertEquals("return arg;", ret.print());
- }
-
- @Test
- public void testChapter4AddAddMul() {
- Parser parser = new Parser("return arg+0+arg;");
- StopNode ret = parser.parse();
- assertEquals("return (arg*2);", ret.print());
- }
-
- @Test
- public void testChapter4Peephole3() {
- Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return ((arg*2)+6);", ret.print());
- }
-
- @Test
- public void testChapter4Mul1() {
- Parser parser = new Parser("return 1*arg;");
- StopNode ret = parser.parse();
- assertEquals("return arg;", ret.print());
- }
-
- @Test
- public void testChapter4VarArg() {
- Parser parser = new Parser("return arg; #showGraph;");
- StopNode stop = parser.parse();
- ReturnNode ret = stop.ret();
- assertTrue(ret.in(0) instanceof ProjNode);
- assertTrue(ret.in(1) instanceof ProjNode);
- }
-
- @Test
- public void testChapter4ConstantArg() {
- Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter4CompEq() {
- Parser parser = new Parser("return 3==3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testChapter4CompEq2() {
- Parser parser = new Parser("return 3==4; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 0;", ret.print());
- }
-
- @Test
- public void testChapter4CompNEq() {
- Parser parser = new Parser("return 3!=3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 0;", ret.print());
- }
-
- @Test
- public void testChapter4CompNEq2() {
- Parser parser = new Parser("return 3!=4; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testChapter4Bug1() {
- Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Bug2() {
- Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+1);", ret.print());
- }
-
- @Test
- public void testChapter4Bug3() {
- try {
- new Parser("inta=1; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'inta'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter4Bug4() {
- Parser parser = new Parser("return -arg;");
- StopNode ret = parser.parse();
- assertEquals("return (-arg);", ret.print());
- }
-
- @Test
- public void testVarDecl() {
- Parser parser = new Parser("int a=1; return a;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testVarAdd() {
- Parser parser = new Parser("int a=1; int b=2; return a+b;");
- StopNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testVarScope() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
- StopNode ret = parser.parse();
- assertEquals("return 4;", ret.print());
- }
-
- @Test
- public void testVarScopeNoPeephole() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
- Node._disablePeephole = true;
- StopNode ret = parser.parse();
- Node._disablePeephole = false;
- assertEquals("return (1+3);", ret.print());
- }
-
- @Test
- public void testVarDist() {
- Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 8;", ret.print());
- }
-
- @Test
- public void testSelfAssign() {
- try {
- new Parser("int a=a; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'a'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter2ParseGrammar() {
- Parser parser = new Parser("return 1+2*3+-5;");
- Node._disablePeephole = true; // disable peephole so we can observe full graph
- StopNode ret = parser.parse();
- assertEquals("return (1+((2*3)+(-5)));", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter2AddPeephole() {
- Parser parser = new Parser("return 1+2;");
- StopNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testChapter2SubPeephole() {
- Parser parser = new Parser("return 1-2;");
- StopNode ret = parser.parse();
- assertEquals("return -1;", ret.print());
- }
-
- @Test
- public void testChapter2MulPeephole() {
- Parser parser = new Parser("return 2*3;");
- StopNode ret = parser.parse();
- assertEquals("return 6;", ret.print());
- }
-
- @Test
- public void testChapter2DivPeephole() {
- Parser parser = new Parser("return 6/3;");
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter2MinusPeephole() {
- Parser parser = new Parser("return 6/-3;");
- StopNode ret = parser.parse();
- assertEquals("return -2;", ret.print());
- }
-
- @Test
- public void testChapter2Example() {
- Parser parser = new Parser("return 1+2*3+-5;");
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- }
-
- @Test
- public void testSimpleProgram() {
- Parser parser = new Parser("return 1;");
- StopNode stop = parser.parse();
- StartNode start = Parser.START;
- ReturnNode ret = (ReturnNode)stop.in(0);
-
- assertTrue(ret.ctrl() instanceof ProjNode);
- Node expr = ret.expr();
- if( expr instanceof ConstantNode con ) {
- assertEquals(start,con.in(0));
- assertEquals(TypeInteger.constant(1), con._type);
- } else {
- fail();
- }
- }
-
- @Test
- public void testZero() {
- Parser parser = new Parser("return 0;");
- parser.parse();
- StartNode start = Parser.START;
- for( Node use : start._outputs )
- if( use instanceof ConstantNode con )
- assertEquals(TypeInteger.constant(0),con._type);
- }
-
- @Test
- public void testBad1() {
- try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad2() {
- try {
- new Parser("return 0123;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
-
- @Test
- public void testBad6() {
- try {
- new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected }: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad7() {
- try {
- new Parser("return 1;}").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
- }
- }
-
}
diff --git a/chapter07/README.md b/chapter07/README.md
index 03181d18..fe4c0625 100644
--- a/chapter07/README.md
+++ b/chapter07/README.md
@@ -1,4 +1,4 @@
-# Chapter 7
+# Chapter 7: While Statement
In this chapter we introduce the `while` statement.
diff --git a/chapter07/docs/Makefile b/chapter07/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter07/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter07/docs/build-graphs.sh b/chapter07/docs/build-graphs.sh
deleted file mode 100644
index 27b2b72f..00000000
--- a/chapter07/docs/build-graphs.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-dot -Tsvg 07-graph1.gv > 07-graph1.svg
-dot -Tsvg 07-graph2.gv > 07-graph2.svg
-dot -Tsvg 07-graph3.gv > 07-graph3.svg
-dot -Tsvg 07-graph4.gv > 07-graph4.svg
-
-
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/Parser.java b/chapter07/src/main/java/com/seaofnodes/simple/Parser.java
index 349b2ce7..b4418ced 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/Parser.java
@@ -547,6 +547,7 @@ public class Parser {
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -555,13 +556,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter07/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter07/src/test/java/com/seaofnodes/simple/Chapter01Test.java
new file mode 100644
index 00000000..547c36f8
--- /dev/null
+++ b/chapter07/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -0,0 +1,100 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter01Test {
+
+ @Test
+ public void testSimpleProgram() {
+ Parser parser = new Parser("return 1;");
+ StopNode stop = parser.parse();
+ StartNode start = Parser.START;
+ ReturnNode ret = (ReturnNode)stop.in(0);
+
+ assertTrue(ret.ctrl() instanceof ProjNode);
+ Node expr = ret.expr();
+ if( expr instanceof ConstantNode con ) {
+ assertEquals(start,con.in(0));
+ assertEquals(TypeInteger.constant(1), con._type);
+ } else {
+ fail();
+ }
+ }
+
+ @Test
+ public void testZero() {
+ Parser parser = new Parser("return 0;");
+ parser.parse();
+ StartNode start = Parser.START;
+ for( Node use : start._outputs )
+ if( use instanceof ConstantNode con )
+ assertEquals(TypeInteger.constant(0),con._type);
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad2() {
+ try {
+ new Parser("return 0123;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter07/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter07/src/test/java/com/seaofnodes/simple/Chapter02Test.java
new file mode 100644
index 00000000..4085ed7e
--- /dev/null
+++ b/chapter07/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -0,0 +1,66 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter02Test {
+
+ @Test
+ public void testParseGrammar() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ Node._disablePeephole = true; // disable peephole so we can observe full graph
+ StopNode ret = parser.parse();
+ assertEquals("return (1+((2*3)+(-5)));", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testAddPeephole() {
+ Parser parser = new Parser("return 1+2;");
+ StopNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testSubPeephole() {
+ Parser parser = new Parser("return 1-2;");
+ StopNode ret = parser.parse();
+ assertEquals("return -1;", ret.print());
+ }
+
+ @Test
+ public void testMulPeephole() {
+ Parser parser = new Parser("return 2*3;");
+ StopNode ret = parser.parse();
+ assertEquals("return 6;", ret.print());
+ }
+
+ @Test
+ public void testDivPeephole() {
+ Parser parser = new Parser("return 6/3;");
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testMinusPeephole() {
+ Parser parser = new Parser("return 6/-3;");
+ StopNode ret = parser.parse();
+ assertEquals("return -2;", ret.print());
+ }
+
+ @Test
+ public void testExample() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ }
+
+}
diff --git a/chapter07/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter07/src/test/java/com/seaofnodes/simple/Chapter03Test.java
new file mode 100644
index 00000000..407fbe48
--- /dev/null
+++ b/chapter07/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -0,0 +1,68 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter03Test {
+
+ @Test
+ public void testVarDecl() {
+ Parser parser = new Parser("int a=1; return a;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testVarAdd() {
+ Parser parser = new Parser("int a=1; int b=2; return a+b;");
+ StopNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testVarScope() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
+ StopNode ret = parser.parse();
+ assertEquals("return 4;", ret.print());
+ }
+
+ @Test
+ public void testVarScopeNoPeephole() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
+ Node._disablePeephole = true;
+ StopNode ret = parser.parse();
+ Node._disablePeephole = false;
+ assertEquals("return (1+3);", ret.print());
+ }
+
+ @Test
+ public void testVarDist() {
+ Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 8;", ret.print());
+ }
+
+ @Test
+ public void testSelfAssign() {
+ try {
+ new Parser("int a=a; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'a'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected }: ",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java
new file mode 100644
index 00000000..cde23324
--- /dev/null
+++ b/chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -0,0 +1,128 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter04Test {
+
+ @Test
+ public void testPeephole() {
+ Parser parser = new Parser("return 1+arg+2; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testPeephole2() {
+ Parser parser = new Parser("return (1+arg)+2;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testAdd0() {
+ Parser parser = new Parser("return 0+arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return arg;", ret.print());
+ }
+
+ @Test
+ public void testAddAddMul() {
+ Parser parser = new Parser("return arg+0+arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg*2);", ret.print());
+ }
+
+ @Test
+ public void testPeephole3() {
+ Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return ((arg*2)+6);", ret.print());
+ }
+
+ @Test
+ public void testMul1() {
+ Parser parser = new Parser("return 1*arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return arg;", ret.print());
+ }
+
+ @Test
+ public void testVarArg() {
+ Parser parser = new Parser("return arg; #showGraph;");
+ StopNode stop = parser.parse();
+ ReturnNode ret = stop.ret();
+ assertTrue(ret.in(0) instanceof ProjNode);
+ assertTrue(ret.in(1) instanceof ProjNode);
+ }
+
+ @Test
+ public void testConstantArg() {
+ Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testCompEq() {
+ Parser parser = new Parser("return 3==3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testCompEq2() {
+ Parser parser = new Parser("return 3==4; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 0;", ret.print());
+ }
+
+ @Test
+ public void testCompNEq() {
+ Parser parser = new Parser("return 3!=3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 0;", ret.print());
+ }
+
+ @Test
+ public void testCompNEq2() {
+ Parser parser = new Parser("return 3!=4; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testBug1() {
+ Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testBug2() {
+ Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+1);", ret.print());
+ }
+
+ @Test
+ public void testBug3() {
+ try {
+ new Parser("inta=1; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'inta'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBug4() {
+ Parser parser = new Parser("return -arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return (-arg);", ret.print());
+ }
+
+}
diff --git a/chapter07/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter07/src/test/java/com/seaofnodes/simple/Chapter05Test.java
new file mode 100644
index 00000000..99e35d0a
--- /dev/null
+++ b/chapter07/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -0,0 +1,214 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.junit.Assert.*;
+
+public class Chapter05Test {
+
+ @Test
+ public void testIfStmt() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+if (arg == 1)
+ a = arg+2;
+else {
+ a = arg-3;
+ #showGraph;
+}
+#showGraph;
+return a;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return Phi(Region17,(arg+2),(arg-3));", ret.toString());
+ }
+
+ @Test
+ public void testTest() {
+ Parser parser = new Parser(
+"""
+int c = 3;
+int b = 2;
+if (arg == 1) {
+ b = 3;
+ c = 4;
+}
+return c;""", TypeInteger.BOT);
+ StopNode ret = parser.parse(true);
+ assertEquals("return Phi(Region16,4,3);", ret.toString());
+ }
+
+ @Test
+ public void testReturn2() {
+ Parser parser = new Parser(
+"""
+if( arg==1 )
+ return 3;
+else
+ return 4;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("Stop[ return 3; return 4; ]", stop.toString());
+ }
+
+ @Test
+ public void testIfMergeB() {
+ Parser parser = new Parser(
+"""
+int a=arg+1;
+int b=0;
+if( arg==1 )
+ b=a;
+else
+ b=a+1;
+return a+b;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return ((arg*2)+Phi(Region20,2,3));", ret.toString());
+ }
+
+ @Test
+ public void testIfMerge2() {
+ Parser parser = new Parser(
+"""
+int a=arg+1;
+int b=arg+2;
+if( arg==1 )
+ b=b+a;
+else
+ a=b+1;
+return a+b;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString());
+ }
+
+ @Test
+ public void testMerge3() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( arg==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("return Phi(Region33,Phi(Region21,2,3),Phi(Region31,4,5));", stop.toString());
+ }
+
+ @Test
+ public void testMerge4() {
+ Parser parser = new Parser(
+"""
+int a=0;
+int b=0;
+if( arg )
+ a=1;
+if( arg==0 )
+ b=2;
+return arg+a+b;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("return ((arg+Phi(Region13,1,0))+Phi(Region22,2,0));", stop.toString());
+ }
+
+ @Test
+ public void testMerge5() {
+ Parser parser = new Parser(
+"""
+int a=arg==2;
+if( arg==1 )
+{
+ a=arg==3;
+}
+return a;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return (arg==Phi(Region16,3,2));", ret.toString());
+ }
+
+ @Test
+ public void testTrue() {
+ StopNode stop = new Parser("return true;").parse();
+ assertEquals("return 1;",stop.toString());
+ }
+
+ @Test
+ public void testHalfDef() {
+ try {
+ new Parser("if( arg==1 ) int b=2; return b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testHalfDef2() {
+ try {
+ new Parser("if( arg==1 ) { int b=2; } else { int b=3; } return b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'b'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testRegress1() {
+ try {
+ new Parser("if(arg==2) int a=1; else int b=2; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadNum() {
+ try {
+ new Parser("return 1-;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected an identifier or expression: ;",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword1() {
+ try {
+ new Parser("int true=0; return true;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Expected an identifier, found 'true'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword2() {
+ try {
+ new Parser("int else=arg; if(else) else=2; else else=1; return else;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Expected an identifier, found 'else'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword3() {
+ try {
+ new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: (",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter07/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter07/src/test/java/com/seaofnodes/simple/Chapter06Test.java
new file mode 100644
index 00000000..618c8ca6
--- /dev/null
+++ b/chapter07/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -0,0 +1,294 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter06Test {
+
+ @Test
+ public void testPeepholeReturn() {
+ Parser parser = new Parser(
+"""
+if( true ) return 2;
+return 1;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return 2;", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ }
+
+ @Test
+ public void testPeepholeRotate() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+if (arg)
+ a = 2;
+return (arg < a) < 3;
+""");
+ StopNode stop = parser.parse(false);
+ assertEquals("return ((arg<Phi(Region12,2,1))<3);", stop.toString());
+ }
+
+ @Test
+ public void testPeepholeCFG() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( true )
+ a=2;
+else
+ a=3;
+return a;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return 2;", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ }
+
+ @Test
+ public void testIfIf() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg!=1 )
+ a=2;
+else
+ a=3;
+int b=4;
+if( a==2 )
+ b=42;
+else
+ b=5;
+return b;""", TypeInteger.BOT);
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Region32,42,5);", stop.toString());
+ }
+
+ @Test
+ public void testIfArgIf() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( 1==1 )
+ a=2;
+else
+ a=3;
+int b=4;
+if( arg==2 )
+ b=a;
+else
+ b=5;
+return b;""", TypeInteger.BOT);
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Region28,2,5);", stop.toString());
+ }
+
+ @Test
+ public void testMerge3With2() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( arg==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+#showGraph;""", TypeInteger.constant(2));
+ StopNode stop = parser.parse();
+ assertEquals("return 5;", stop.toString());
+ }
+
+ @Test
+ public void testMerge3With1() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( arg==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+""", TypeInteger.constant(1));
+ StopNode stop = parser.parse(true);
+ assertEquals("return 3;", stop.toString());
+ }
+
+ @Test
+ public void testMerge3Peephole() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( 1==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+""", TypeInteger.BOT);
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Region36,3,Phi(Region34,4,5));", stop.toString());
+ }
+
+ @Test
+ public void testMerge3Peephole1() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( 1==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+""", TypeInteger.constant(1));
+ StopNode stop = parser.parse(true);
+ assertEquals("return 3;", stop.toString());
+ }
+
+ @Test
+ public void testMerge3Peephole3() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( 1==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+""", TypeInteger.constant(3));
+ StopNode stop = parser.parse(true);
+ assertEquals("return 4;", stop.toString());
+ }
+
+ @Test
+ public void testDemo1NonConst() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+if( arg ) {
+ a = 2;
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b;
+""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return Phi(Region22,4,1);", ret.toString());
+ }
+
+
+ @Test
+ public void testDemo1True() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+if( arg ) {
+ a = 2;
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b;
+""", TypeInteger.constant(1));
+ StopNode ret = parser.parse(true);
+ assertEquals("return 4;", ret.toString());
+ }
+
+ @Test
+ public void testDemo1False() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+if( arg ) {
+ a = 2;
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b;
+""", TypeInteger.constant(0));
+ StopNode ret = parser.parse(true);
+ assertEquals("return 1;", ret.toString());
+ }
+
+ @Test
+ public void testDemo2NonConst() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+int c = 0;
+if( arg ) {
+ a = 1;
+ if( arg==2 ) { c=2; } else { c=3; }
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b+c;
+""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return (Phi(Region33,Phi(Region22,2,3),0)+Phi(Region,3,1));", ret.toString());
+ }
+
+
+ @Test
+ public void testDemo2True() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+int c = 0;
+if( arg ) {
+ a = 1;
+ if( arg==2 ) { c=2; } else { c=3; }
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b+c;
+""", TypeInteger.constant(1));
+ StopNode ret = parser.parse(true);
+ assertEquals("return 6;", ret.toString());
+ }
+
+ @Test
+ public void testDemo2arg2() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+int c = 0;
+if( arg ) {
+ a = 1;
+ if( arg==2 ) { c=2; } else { c=3; }
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b+c;
+""", TypeInteger.constant(2));
+ StopNode ret = parser.parse(true);
+ assertEquals("return 5;", ret.toString());
+ }
+
+}
diff --git a/chapter07/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter07/src/test/java/com/seaofnodes/simple/Chapter07Test.java
index 9afcc49a..2e34b520 100644
--- a/chapter07/src/test/java/com/seaofnodes/simple/Chapter07Test.java
+++ b/chapter07/src/test/java/com/seaofnodes/simple/Chapter07Test.java
@@ -9,7 +9,7 @@ import static org.junit.Assert.*;
public class Chapter07Test {
@Test
- public void testChapter7Example() {
+ public void testExample() {
Parser parser = new Parser(
"""
while(arg < 10) {
@@ -26,9 +26,8 @@ public class Chapter07Test {
}
@Test
- public void testChapter7Regression() {
+ public void testRegression() {
Parser parser = new Parser(
-
"""
int a = 1;
if(arg){}else{
@@ -43,9 +42,8 @@ return a;
}
@Test
- public void testChapter7WhileNested() {
+ public void testWhileNested() {
Parser parser = new Parser(
-
"""
int sum = 0;
int i = 0;
@@ -65,7 +63,7 @@ return sum;
}
@Test
- public void testChapter7WhileScope() {
+ public void testWhileScope() {
Parser parser = new Parser(
"""
int a = 1;
@@ -85,7 +83,7 @@ return b;
}
@Test
- public void testChapter7WhileNestedIfAndInc() {
+ public void testWhileNestedIfAndInc() {
Parser parser = new Parser(
"""
int a = 1;
@@ -106,7 +104,7 @@ return b;
@Test
- public void testChapter7While() {
+ public void testWhile() {
Parser parser = new Parser(
"""
int a = 1;
@@ -124,7 +122,7 @@ return a;
}
@Test
- public void testChapter7WhilePeep() {
+ public void testWhilePeep() {
Parser parser = new Parser(
"""
int a = 1;
@@ -140,7 +138,7 @@ return a;
}
@Test
- public void testChapter7While2() {
+ public void testWhile2() {
Parser parser = new Parser(
"""
int a = 1;
@@ -156,7 +154,7 @@ return a;
}
@Test
- public void testChapter7While2Peep() {
+ public void testWhile2Peep() {
Parser parser = new Parser(
"""
int a = 1;
@@ -170,7 +168,7 @@ return a;
}
@Test
- public void testChapter7While3() {
+ public void testWhile3() {
Parser parser = new Parser(
"""
int a = 1;
@@ -188,7 +186,7 @@ return a;
}
@Test
- public void testChapter7While3Peep() {
+ public void testWhile3Peep() {
Parser parser = new Parser(
"""
int a = 1;
@@ -204,7 +202,7 @@ return a;
}
@Test
- public void testChapter7While4() {
+ public void testWhile4() {
Parser parser = new Parser(
"""
int a = 1;
@@ -223,7 +221,7 @@ return a;
}
@Test
- public void testChapter7While4Peep() {
+ public void testWhile4Peep() {
Parser parser = new Parser(
"""
int a = 1;
@@ -239,788 +237,4 @@ return a;
assertTrue(stop.ret().ctrl() instanceof ProjNode);
}
- @Test
- public void testChapter6PeepholeReturn() {
- Parser parser = new Parser(
-"""
-if( true ) return 2;
-return 1;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return 2;", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- }
-
- @Test
- public void testChapter6PeepholeRotate() {
- Parser parser = new Parser(
-"""
-int a = 1;
-if (arg)
- a = 2;
-return (arg < a) < 3;
-""");
- StopNode stop = parser.parse(false);
- assertEquals("return ((arg<Phi(Region12,2,1))<3);", stop.toString());
- }
-
- @Test
- public void testChapter6PeepholeCFG() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( true )
- a=2;
-else
- a=3;
-return a;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return 2;", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- }
-
- @Test
- public void testChapter6IfIf() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg!=1 )
- a=2;
-else
- a=3;
-int b=4;
-if( a==2 )
- b=42;
-else
- b=5;
-return b;""", TypeInteger.BOT);
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Region32,42,5);", stop.toString());
- }
-
- @Test
- public void testChapter6IfArgIf() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( 1==1 )
- a=2;
-else
- a=3;
-int b=4;
-if( arg==2 )
- b=a;
-else
- b=5;
-return b;""", TypeInteger.BOT);
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Region28,2,5);", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3With2() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( arg==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-#showGraph;""", TypeInteger.constant(2));
- StopNode stop = parser.parse();
- assertEquals("return 5;", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3With1() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( arg==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-""", TypeInteger.constant(1));
- StopNode stop = parser.parse(true);
- assertEquals("return 3;", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3Peephole() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( 1==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-""", TypeInteger.BOT);
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Region36,3,Phi(Region34,4,5));", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3Peephole1() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( 1==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-""", TypeInteger.constant(1));
- StopNode stop = parser.parse(true);
- assertEquals("return 3;", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3Peephole3() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( 1==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-""", TypeInteger.constant(3));
- StopNode stop = parser.parse(true);
- assertEquals("return 4;", stop.toString());
- }
-
- @Test
- public void testChapter6Demo1NonConst() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-if( arg ) {
- a = 2;
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b;
-""");
- StopNode ret = parser.parse(true);
- assertEquals("return Phi(Region22,4,1);", ret.toString());
- }
-
-
- @Test
- public void testChapter6Demo1True() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-if( arg ) {
- a = 2;
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b;
-""", TypeInteger.constant(1));
- StopNode ret = parser.parse(true);
- assertEquals("return 4;", ret.toString());
- }
-
- @Test
- public void testChapter6Demo1False() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-if( arg ) {
- a = 2;
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b;
-""", TypeInteger.constant(0));
- StopNode ret = parser.parse(true);
- assertEquals("return 1;", ret.toString());
- }
-
- @Test
- public void testChapter6Demo2NonConst() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-int c = 0;
-if( arg ) {
- a = 1;
- if( arg==2 ) { c=2; } else { c=3; }
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b+c;
-""");
- StopNode ret = parser.parse(true);
- assertEquals("return (Phi(Region33,Phi(Region22,2,3),0)+Phi(Region,3,1));", ret.toString());
- }
-
-
- @Test
- public void testChapter6Demo2True() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-int c = 0;
-if( arg ) {
- a = 1;
- if( arg==2 ) { c=2; } else { c=3; }
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b+c;
-""", TypeInteger.constant(1));
- StopNode ret = parser.parse(true);
- assertEquals("return 6;", ret.toString());
- }
-
- @Test
- public void testChapter6Demo2arg2() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-int c = 0;
-if( arg ) {
- a = 1;
- if( arg==2 ) { c=2; } else { c=3; }
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b+c;
-""", TypeInteger.constant(2));
- StopNode ret = parser.parse(true);
- assertEquals("return 5;", ret.toString());
- }
-
-
-
- @Test
- public void testChapter5IfStmt() {
- Parser parser = new Parser(
-"""
-int a = 1;
-if (arg == 1)
- a = arg+2;
-else {
- a = arg-3;
- #showGraph;
-}
-#showGraph;
-return a;""");
- StopNode ret = parser.parse(true);
- assertEquals("return Phi(Region17,(arg+2),(arg-3));", ret.toString());
- }
-
- @Test
- public void testChapter5Test() {
- Parser parser = new Parser(
-"""
-int c = 3;
-int b = 2;
-if (arg == 1) {
- b = 3;
- c = 4;
-}
-return c;""", TypeInteger.BOT);
- StopNode ret = parser.parse(true);
- assertEquals("return Phi(Region16,4,3);", ret.toString());
- }
-
- @Test
- public void testChapter5Return2() {
- Parser parser = new Parser(
-"""
-if( arg==1 )
- return 3;
-else
- return 4;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("Stop[ return 3; return 4; ]", stop.toString());
- }
-
- @Test
- public void testChapter5IfMergeB() {
- Parser parser = new Parser(
-"""
-int a=arg+1;
-int b=0;
-if( arg==1 )
- b=a;
-else
- b=a+1;
-return a+b;""");
- StopNode ret = parser.parse(true);
- assertEquals("return ((arg*2)+Phi(Region20,2,3));", ret.toString());
- }
-
- @Test
- public void testChapter5IfMerge2() {
- Parser parser = new Parser(
-"""
-int a=arg+1;
-int b=arg+2;
-if( arg==1 )
- b=b+a;
-else
- a=b+1;
-return a+b;""");
- StopNode ret = parser.parse(true);
- assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString());
- }
-
- @Test
- public void testChapter5Merge3() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( arg==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("return Phi(Region33,Phi(Region21,2,3),Phi(Region31,4,5));", stop.toString());
- }
-
- @Test
- public void testChapter5Merge4() {
- Parser parser = new Parser(
-"""
-int a=0;
-int b=0;
-if( arg )
- a=1;
-if( arg==0 )
- b=2;
-return arg+a+b;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("return ((arg+Phi(Region13,1,0))+Phi(Region22,2,0));", stop.toString());
- }
-
- @Test
- public void testChapter5Merge5() {
- Parser parser = new Parser(
-"""
-int a=arg==2;
-if( arg==1 )
-{
- a=arg==3;
-}
-return a;""");
- StopNode ret = parser.parse(true);
- assertEquals("return (arg==Phi(Region16,3,2));", ret.toString());
- }
-
- @Test
- public void testChapter5True() {
- StopNode stop = new Parser("return true;").parse();
- assertEquals("return 1;",stop.toString());
- }
-
- @Test
- public void testChapter5HalfDef() {
- try {
- new Parser("if( arg==1 ) int b=2; return b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5HalfDef2() {
- try {
- new Parser("if( arg==1 ) { int b=2; } else { int b=3; } return b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'b'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5BadNum() {
- try {
- new Parser("return 1-;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected an identifier or expression: ;",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword1() {
- try {
- new Parser("int true=0; return true;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Expected an identifier, found 'true'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword2() {
- try {
- new Parser("int else=arg; if(else) else=2; else else=1; return else;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Expected an identifier, found 'else'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword3() {
- try {
- new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: (",e.getMessage());
- }
- }
-
- @Test
- public void testChapter4Peephole() {
- Parser parser = new Parser("return 1+arg+2; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Peephole2() {
- Parser parser = new Parser("return (1+arg)+2;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Add0() {
- Parser parser = new Parser("return 0+arg;");
- StopNode ret = parser.parse();
- assertEquals("return arg;", ret.print());
- }
-
- @Test
- public void testChapter4AddAddMul() {
- Parser parser = new Parser("return arg+0+arg;");
- StopNode ret = parser.parse();
- assertEquals("return (arg*2);", ret.print());
- }
-
- @Test
- public void testChapter4Peephole3() {
- Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return ((arg*2)+6);", ret.print());
- }
-
- @Test
- public void testChapter4Mul1() {
- Parser parser = new Parser("return 1*arg;");
- StopNode ret = parser.parse();
- assertEquals("return arg;", ret.print());
- }
-
- @Test
- public void testChapter4VarArg() {
- Parser parser = new Parser("return arg; #showGraph;");
- StopNode stop = parser.parse();
- ReturnNode ret = stop.ret();
- assertTrue(ret.in(0) instanceof ProjNode);
- assertTrue(ret.in(1) instanceof ProjNode);
- }
-
- @Test
- public void testChapter4ConstantArg() {
- Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter4CompEq() {
- Parser parser = new Parser("return 3==3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testChapter4CompEq2() {
- Parser parser = new Parser("return 3==4; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 0;", ret.print());
- }
-
- @Test
- public void testChapter4CompNEq() {
- Parser parser = new Parser("return 3!=3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 0;", ret.print());
- }
-
- @Test
- public void testChapter4CompNEq2() {
- Parser parser = new Parser("return 3!=4; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testChapter4Bug1() {
- Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Bug2() {
- Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+1);", ret.print());
- }
-
- @Test
- public void testChapter4Bug3() {
- try {
- new Parser("inta=1; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'inta'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter4Bug4() {
- Parser parser = new Parser("return -arg;");
- StopNode ret = parser.parse();
- assertEquals("return (-arg);", ret.print());
- }
-
- @Test
- public void testVarDecl() {
- Parser parser = new Parser("int a=1; return a;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testVarAdd() {
- Parser parser = new Parser("int a=1; int b=2; return a+b;");
- StopNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testVarScope() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
- StopNode ret = parser.parse();
- assertEquals("return 4;", ret.print());
- }
-
- @Test
- public void testVarScopeNoPeephole() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
- Node._disablePeephole = true;
- StopNode ret = parser.parse();
- Node._disablePeephole = false;
- assertEquals("return (1+3);", ret.print());
- }
-
- @Test
- public void testVarDist() {
- Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 8;", ret.print());
- }
-
- @Test
- public void testSelfAssign() {
- try {
- new Parser("int a=a; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'a'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter2ParseGrammar() {
- Parser parser = new Parser("return 1+2*3+-5;");
- Node._disablePeephole = true; // disable peephole so we can observe full graph
- StopNode ret = parser.parse();
- assertEquals("return (1+((2*3)+(-5)));", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter2AddPeephole() {
- Parser parser = new Parser("return 1+2;");
- StopNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testChapter2SubPeephole() {
- Parser parser = new Parser("return 1-2;");
- StopNode ret = parser.parse();
- assertEquals("return -1;", ret.print());
- }
-
- @Test
- public void testChapter2MulPeephole() {
- Parser parser = new Parser("return 2*3;");
- StopNode ret = parser.parse();
- assertEquals("return 6;", ret.print());
- }
-
- @Test
- public void testChapter2DivPeephole() {
- Parser parser = new Parser("return 6/3;");
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter2MinusPeephole() {
- Parser parser = new Parser("return 6/-3;");
- StopNode ret = parser.parse();
- assertEquals("return -2;", ret.print());
- }
-
- @Test
- public void testChapter2Example() {
- Parser parser = new Parser("return 1+2*3+-5;");
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- }
-
- @Test
- public void testSimpleProgram() {
- Parser parser = new Parser("return 1;");
- StopNode stop = parser.parse();
- StartNode start = Parser.START;
- ReturnNode ret = (ReturnNode)stop.in(0);
-
- assertTrue(ret.ctrl() instanceof ProjNode);
- Node expr = ret.expr();
- if( expr instanceof ConstantNode con ) {
- assertEquals(start,con.in(0));
- assertEquals(TypeInteger.constant(1), con._type);
- } else {
- fail();
- }
- }
-
- @Test
- public void testZero() {
- Parser parser = new Parser("return 0;");
- parser.parse();
- StartNode start = Parser.START;
- for( Node use : start._outputs )
- if( use instanceof ConstantNode con )
- assertEquals(TypeInteger.constant(0),con._type);
- }
-
- @Test
- public void testBad1() {
- try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad2() {
- try {
- new Parser("return 0123;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
-
- @Test
- public void testBad6() {
- try {
- new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected }: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad7() {
- try {
- new Parser("return 1;}").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
- }
- }
-
}
diff --git a/chapter08/README.md b/chapter08/README.md
index 4c095912..41d6c11c 100644
--- a/chapter08/README.md
+++ b/chapter08/README.md
@@ -1,4 +1,4 @@
-# Chapter 8
+# Chapter 8: Lazy Phis, Break, Continue, and Evaluator
In this chapter:
diff --git a/chapter08/docs/Makefile b/chapter08/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter08/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter08/docs/build-graphs.sh b/chapter08/docs/build-graphs.sh
deleted file mode 100644
index f660790b..00000000
--- a/chapter08/docs/build-graphs.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-dot -Tsvg 08-graph1.gv > 08-graph1.svg
-dot -Tsvg 08-graph2.gv > 08-graph2.svg
-dot -Tsvg 08-graph3.gv > 08-graph3.svg
-
-
-
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/Parser.java b/chapter08/src/main/java/com/seaofnodes/simple/Parser.java
index d4b0c327..eae6e0c6 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/Parser.java
@@ -594,6 +594,7 @@ public class Parser {
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -602,13 +603,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter01Test.java
new file mode 100644
index 00000000..13b42f96
--- /dev/null
+++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -0,0 +1,100 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter01Test {
+
+ @Test
+ public void testSimpleProgram() {
+ Parser parser = new Parser("return 1;");
+ StopNode stop = parser.parse();
+ StartNode start = Parser.START;
+ ReturnNode ret = (ReturnNode)stop.in(0);
+
+ assertTrue(ret.ctrl() instanceof ProjNode);
+ Node expr = ret.expr();
+ if( expr instanceof ConstantNode con ) {
+ assertEquals(start,con.in(0));
+ assertEquals(TypeInteger.constant(1), con._type);
+ } else {
+ fail();
+ }
+ }
+
+ @Test
+ public void testZero() {
+ Parser parser = new Parser("return 0;");
+ parser.parse();
+ StartNode start = Parser.START;
+ for( Node use : start._outputs )
+ if( use instanceof ConstantNode con && con._type instanceof TypeInteger )
+ assertEquals(TypeInteger.constant(0),con._type);
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad2() {
+ try {
+ new Parser("return 0123;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter02Test.java
new file mode 100644
index 00000000..4085ed7e
--- /dev/null
+++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -0,0 +1,66 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter02Test {
+
+ @Test
+ public void testParseGrammar() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ Node._disablePeephole = true; // disable peephole so we can observe full graph
+ StopNode ret = parser.parse();
+ assertEquals("return (1+((2*3)+(-5)));", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testAddPeephole() {
+ Parser parser = new Parser("return 1+2;");
+ StopNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testSubPeephole() {
+ Parser parser = new Parser("return 1-2;");
+ StopNode ret = parser.parse();
+ assertEquals("return -1;", ret.print());
+ }
+
+ @Test
+ public void testMulPeephole() {
+ Parser parser = new Parser("return 2*3;");
+ StopNode ret = parser.parse();
+ assertEquals("return 6;", ret.print());
+ }
+
+ @Test
+ public void testDivPeephole() {
+ Parser parser = new Parser("return 6/3;");
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testMinusPeephole() {
+ Parser parser = new Parser("return 6/-3;");
+ StopNode ret = parser.parse();
+ assertEquals("return -2;", ret.print());
+ }
+
+ @Test
+ public void testExample() {
+ Parser parser = new Parser("return 1+2*3+-5;");
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ GraphVisualizer gv = new GraphVisualizer();
+ System.out.println(gv.generateDotOutput(parser));
+ }
+
+}
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter03Test.java
new file mode 100644
index 00000000..407fbe48
--- /dev/null
+++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -0,0 +1,68 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter03Test {
+
+ @Test
+ public void testVarDecl() {
+ Parser parser = new Parser("int a=1; return a;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testVarAdd() {
+ Parser parser = new Parser("int a=1; int b=2; return a+b;");
+ StopNode ret = parser.parse();
+ assertEquals("return 3;", ret.print());
+ }
+
+ @Test
+ public void testVarScope() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
+ StopNode ret = parser.parse();
+ assertEquals("return 4;", ret.print());
+ }
+
+ @Test
+ public void testVarScopeNoPeephole() {
+ Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
+ Node._disablePeephole = true;
+ StopNode ret = parser.parse();
+ Node._disablePeephole = false;
+ assertEquals("return (1+3);", ret.print());
+ }
+
+ @Test
+ public void testVarDist() {
+ Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 8;", ret.print());
+ }
+
+ @Test
+ public void testSelfAssign() {
+ try {
+ new Parser("int a=a; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'a'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected }: ",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java
new file mode 100644
index 00000000..cde23324
--- /dev/null
+++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -0,0 +1,128 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter04Test {
+
+ @Test
+ public void testPeephole() {
+ Parser parser = new Parser("return 1+arg+2; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testPeephole2() {
+ Parser parser = new Parser("return (1+arg)+2;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testAdd0() {
+ Parser parser = new Parser("return 0+arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return arg;", ret.print());
+ }
+
+ @Test
+ public void testAddAddMul() {
+ Parser parser = new Parser("return arg+0+arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg*2);", ret.print());
+ }
+
+ @Test
+ public void testPeephole3() {
+ Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return ((arg*2)+6);", ret.print());
+ }
+
+ @Test
+ public void testMul1() {
+ Parser parser = new Parser("return 1*arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return arg;", ret.print());
+ }
+
+ @Test
+ public void testVarArg() {
+ Parser parser = new Parser("return arg; #showGraph;");
+ StopNode stop = parser.parse();
+ ReturnNode ret = stop.ret();
+ assertTrue(ret.in(0) instanceof ProjNode);
+ assertTrue(ret.in(1) instanceof ProjNode);
+ }
+
+ @Test
+ public void testConstantArg() {
+ Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
+ StopNode ret = parser.parse();
+ assertEquals("return 2;", ret.print());
+ }
+
+ @Test
+ public void testCompEq() {
+ Parser parser = new Parser("return 3==3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testCompEq2() {
+ Parser parser = new Parser("return 3==4; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 0;", ret.print());
+ }
+
+ @Test
+ public void testCompNEq() {
+ Parser parser = new Parser("return 3!=3; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 0;", ret.print());
+ }
+
+ @Test
+ public void testCompNEq2() {
+ Parser parser = new Parser("return 3!=4; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return 1;", ret.print());
+ }
+
+ @Test
+ public void testBug1() {
+ Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+3);", ret.print());
+ }
+
+ @Test
+ public void testBug2() {
+ Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
+ StopNode ret = parser.parse();
+ assertEquals("return (arg+1);", ret.print());
+ }
+
+ @Test
+ public void testBug3() {
+ try {
+ new Parser("inta=1; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'inta'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBug4() {
+ Parser parser = new Parser("return -arg;");
+ StopNode ret = parser.parse();
+ assertEquals("return (-arg);", ret.print());
+ }
+
+}
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter05Test.java
new file mode 100644
index 00000000..ea348968
--- /dev/null
+++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -0,0 +1,212 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter05Test {
+
+ @Test
+ public void testIfStmt() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+if (arg == 1)
+ a = arg+2;
+else {
+ a = arg-3;
+ #showGraph;
+}
+#showGraph;
+return a;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return Phi(Region17,(arg+2),(arg-3));", ret.toString());
+ }
+
+ @Test
+ public void testTest() {
+ Parser parser = new Parser(
+"""
+int c = 3;
+int b = 2;
+if (arg == 1) {
+ b = 3;
+ c = 4;
+}
+return c;""", TypeInteger.BOT);
+ StopNode ret = parser.parse(true);
+ assertEquals("return Phi(Region16,4,3);", ret.toString());
+ }
+
+ @Test
+ public void testReturn2() {
+ Parser parser = new Parser(
+"""
+if( arg==1 )
+ return 3;
+else
+ return 4;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("Stop[ return 3; return 4; ]", stop.toString());
+ }
+
+ @Test
+ public void testIfMergeB() {
+ Parser parser = new Parser(
+"""
+int a=arg+1;
+int b=0;
+if( arg==1 )
+ b=a;
+else
+ b=a+1;
+return a+b;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return ((arg*2)+Phi(Region20,2,3));", ret.toString());
+ }
+
+ @Test
+ public void testIfMerge2() {
+ Parser parser = new Parser(
+"""
+int a=arg+1;
+int b=arg+2;
+if( arg==1 )
+ b=b+a;
+else
+ a=b+1;
+return a+b;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString());
+ }
+
+ @Test
+ public void testMerge3() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( arg==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("return Phi(Region33,Phi(Region21,2,3),Phi(Region31,4,5));", stop.toString());
+ }
+
+ @Test
+ public void testMerge4() {
+ Parser parser = new Parser(
+"""
+int a=0;
+int b=0;
+if( arg )
+ a=1;
+if( arg==0 )
+ b=2;
+return arg+a+b;
+#showGraph;""", TypeInteger.BOT);
+ StopNode stop = parser.parse();
+ assertEquals("return ((arg+Phi(Region13,1,0))+Phi(Region22,2,0));", stop.toString());
+ }
+
+ @Test
+ public void testMerge5() {
+ Parser parser = new Parser(
+"""
+int a=arg==2;
+if( arg==1 )
+{
+ a=arg==3;
+}
+return a;""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return (arg==Phi(Region16,3,2));", ret.toString());
+ }
+
+ @Test
+ public void testTrue() {
+ StopNode stop = new Parser("return true;").parse();
+ assertEquals("return 1;",stop.toString());
+ }
+
+ @Test
+ public void testHalfDef() {
+ try {
+ new Parser("if( arg==1 ) int b=2; return b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testHalfDef2() {
+ try {
+ new Parser("if( arg==1 ) { int b=2; } else { int b=3; } return b;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'b'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testRegress1() {
+ try {
+ new Parser("if(arg==2) int a=1; else int b=2; return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBadNum() {
+ try {
+ new Parser("return 1-;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected an identifier or expression: ;",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword1() {
+ try {
+ new Parser("int true=0; return true;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Expected an identifier, found 'true'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword2() {
+ try {
+ new Parser("int else=arg; if(else) else=2; else else=1; return else;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Expected an identifier, found 'else'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testKeyword3() {
+ try {
+ new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: (",e.getMessage());
+ }
+ }
+
+}
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter06Test.java
new file mode 100644
index 00000000..618c8ca6
--- /dev/null
+++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -0,0 +1,294 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter06Test {
+
+ @Test
+ public void testPeepholeReturn() {
+ Parser parser = new Parser(
+"""
+if( true ) return 2;
+return 1;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return 2;", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ }
+
+ @Test
+ public void testPeepholeRotate() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+if (arg)
+ a = 2;
+return (arg < a) < 3;
+""");
+ StopNode stop = parser.parse(false);
+ assertEquals("return ((arg<Phi(Region12,2,1))<3);", stop.toString());
+ }
+
+ @Test
+ public void testPeepholeCFG() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( true )
+ a=2;
+else
+ a=3;
+return a;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return 2;", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ }
+
+ @Test
+ public void testIfIf() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg!=1 )
+ a=2;
+else
+ a=3;
+int b=4;
+if( a==2 )
+ b=42;
+else
+ b=5;
+return b;""", TypeInteger.BOT);
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Region32,42,5);", stop.toString());
+ }
+
+ @Test
+ public void testIfArgIf() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( 1==1 )
+ a=2;
+else
+ a=3;
+int b=4;
+if( arg==2 )
+ b=a;
+else
+ b=5;
+return b;""", TypeInteger.BOT);
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Region28,2,5);", stop.toString());
+ }
+
+ @Test
+ public void testMerge3With2() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( arg==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+#showGraph;""", TypeInteger.constant(2));
+ StopNode stop = parser.parse();
+ assertEquals("return 5;", stop.toString());
+ }
+
+ @Test
+ public void testMerge3With1() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( arg==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+""", TypeInteger.constant(1));
+ StopNode stop = parser.parse(true);
+ assertEquals("return 3;", stop.toString());
+ }
+
+ @Test
+ public void testMerge3Peephole() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( 1==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+""", TypeInteger.BOT);
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Region36,3,Phi(Region34,4,5));", stop.toString());
+ }
+
+ @Test
+ public void testMerge3Peephole1() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( 1==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+""", TypeInteger.constant(1));
+ StopNode stop = parser.parse(true);
+ assertEquals("return 3;", stop.toString());
+ }
+
+ @Test
+ public void testMerge3Peephole3() {
+ Parser parser = new Parser(
+"""
+int a=1;
+if( arg==1 )
+ if( 1==2 )
+ a=2;
+ else
+ a=3;
+else if( arg==3 )
+ a=4;
+else
+ a=5;
+return a;
+""", TypeInteger.constant(3));
+ StopNode stop = parser.parse(true);
+ assertEquals("return 4;", stop.toString());
+ }
+
+ @Test
+ public void testDemo1NonConst() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+if( arg ) {
+ a = 2;
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b;
+""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return Phi(Region22,4,1);", ret.toString());
+ }
+
+
+ @Test
+ public void testDemo1True() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+if( arg ) {
+ a = 2;
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b;
+""", TypeInteger.constant(1));
+ StopNode ret = parser.parse(true);
+ assertEquals("return 4;", ret.toString());
+ }
+
+ @Test
+ public void testDemo1False() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+if( arg ) {
+ a = 2;
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b;
+""", TypeInteger.constant(0));
+ StopNode ret = parser.parse(true);
+ assertEquals("return 1;", ret.toString());
+ }
+
+ @Test
+ public void testDemo2NonConst() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+int c = 0;
+if( arg ) {
+ a = 1;
+ if( arg==2 ) { c=2; } else { c=3; }
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b+c;
+""");
+ StopNode ret = parser.parse(true);
+ assertEquals("return (Phi(Region33,Phi(Region22,2,3),0)+Phi(Region,3,1));", ret.toString());
+ }
+
+
+ @Test
+ public void testDemo2True() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+int c = 0;
+if( arg ) {
+ a = 1;
+ if( arg==2 ) { c=2; } else { c=3; }
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b+c;
+""", TypeInteger.constant(1));
+ StopNode ret = parser.parse(true);
+ assertEquals("return 6;", ret.toString());
+ }
+
+ @Test
+ public void testDemo2arg2() {
+ Parser parser = new Parser("""
+int a = 0;
+int b = 1;
+int c = 0;
+if( arg ) {
+ a = 1;
+ if( arg==2 ) { c=2; } else { c=3; }
+ if( arg ) { b = 2; }
+ else b = 3;
+}
+return a+b+c;
+""", TypeInteger.constant(2));
+ StopNode ret = parser.parse(true);
+ assertEquals("return 5;", ret.toString());
+ }
+
+}
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter07Test.java
new file mode 100644
index 00000000..696839d9
--- /dev/null
+++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter07Test.java
@@ -0,0 +1,240 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Chapter07Test {
+
+ @Test
+ public void testExample() {
+ Parser parser = new Parser(
+ """
+ while(arg < 10) {
+ arg = arg + 1;
+ #showGraph;
+ }
+ return arg;
+ """);
+ Node._disablePeephole = true;
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop6,arg,(Phi_arg+1));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testRegression() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+if(arg){}else{
+ while(a < 10) {
+ a = a + 1;
+ }
+}
+return a;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Region22,1,Phi(Loop11,1,(Phi_a+1)));", stop.toString());
+ }
+
+ @Test
+ public void testWhileNested() {
+ Parser parser = new Parser(
+"""
+int sum = 0;
+int i = 0;
+while(i < arg) {
+ i = i + 1;
+ int j = 0;
+ while( j < arg ) {
+ sum = sum + j;
+ j = j + 1;
+ }
+}
+return sum;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop8,0,Phi(Loop20,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", stop.toString());
+ System.out.println(IRPrinter.prettyPrint(stop,99));
+ }
+
+ @Test
+ public void testWhileScope() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+int b = 2;
+while(a < 10) {
+ if (a == 2) a = 3;
+ else b = 4;
+}
+return b;
+""");
+ Node._disablePeephole = true;
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop8,2,Phi(Region26,Phi_b,4));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ Node._disablePeephole = false;
+ System.out.println(IRPrinter.prettyPrint(stop,99));
+ }
+
+ @Test
+ public void testWhileNestedIfAndInc() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+int b = 2;
+while(a < 10) {
+ if (a == 2) a = 3;
+ else b = 4;
+ b = b + 1;
+ a = a + 1;
+}
+return b;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop8,2,(Phi(Region26,Phi_b,4)+1));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ System.out.println(IRPrinter.prettyPrint(stop,99));
+ }
+
+
+ @Test
+ public void testWhile() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+while(a < 10) {
+ a = a + 1;
+ a = a + 2;
+}
+return a;
+""");
+ Node._disablePeephole = true;
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop7,1,((Phi_a+1)+2));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testWhilePeep() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+while(a < 10) {
+ a = a + 1;
+ a = a + 2;
+}
+return a;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop7,1,(Phi_a+3));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ }
+
+ @Test
+ public void testWhile2() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+while(arg) a = 2;
+return a;
+""");
+ Node._disablePeephole = true;
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop7,1,2);", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ Node._disablePeephole = false;
+ System.out.println(IRPrinter.prettyPrint(stop,99));
+ }
+
+ @Test
+ public void testWhile2Peep() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+while(arg) a = 2;
+return a;
+""");
+ StopNode stop = parser.parse(false);
+ assertEquals("return Phi(Loop7,1,2);", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ System.out.println(IRPrinter.prettyPrint(stop, 99));
+ }
+
+ @Test
+ public void testWhile3() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+while(a < 10) {
+ int b = a + 1;
+ a = b + 2;
+}
+return a;
+""");
+ Node._disablePeephole = true;
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop7,1,((Phi_a+1)+2));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testWhile3Peep() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+while(a < 10) {
+ int b = a + 1;
+ a = b + 2;
+}
+return a;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop7,1,(Phi_a+3));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ }
+
+ @Test
+ public void testWhile4() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+int b = 2;
+while(a < 10) {
+ int b = a + 1;
+ a = b + 2;
+}
+return a;
+""");
+ Node._disablePeephole = true;
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop8,1,((Phi_a+1)+2));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ Node._disablePeephole = false;
+ }
+
+ @Test
+ public void testWhile4Peep() {
+ Parser parser = new Parser(
+"""
+int a = 1;
+int b = 2;
+while(a < 10) {
+ int b = a + 1;
+ a = b + 2;
+}
+return a;
+""");
+ StopNode stop = parser.parse(true);
+ assertEquals("return Phi(Loop8,1,(Phi_a+3));", stop.toString());
+ assertTrue(stop.ret().ctrl() instanceof ProjNode);
+ }
+
+}
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter08Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter08Test.java
index f8bbfaa3..d7f9f521 100644
--- a/chapter08/src/test/java/com/seaofnodes/simple/Chapter08Test.java
+++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter08Test.java
@@ -20,7 +20,7 @@ public class Chapter08Test {
}
@Test
- public void testChapter8Ex6() {
+ public void testEx6() {
Parser parser = new Parser(
"""
while(arg < 10) {
@@ -41,7 +41,7 @@ return arg;
@Test
- public void testChapter8Ex5() {
+ public void testEx5() {
Parser parser = new Parser(
"""
int a = 1;
@@ -63,7 +63,7 @@ return a;
@Test
- public void testChapter8Ex4() {
+ public void testEx4() {
Parser parser = new Parser(
"""
while(arg < 10) {
@@ -81,7 +81,7 @@ return arg;
}
@Test
- public void testChapter8Ex3() {
+ public void testEx3() {
Parser parser = new Parser(
"""
while(arg < 10) {
@@ -98,7 +98,7 @@ return arg;
@Test
- public void testChapter8Ex2() {
+ public void testEx2() {
Parser parser = new Parser(
"""
while(arg < 10) {
@@ -117,7 +117,7 @@ return arg;
@Test
- public void testChapter8Ex1() {
+ public void testEx1() {
Parser parser = new Parser(
"""
while(arg < 10) {
@@ -133,7 +133,7 @@ return arg;
}
@Test
- public void testChapter8Regress1() {
+ public void testRegress1() {
Parser parser = new Parser(
"""
while( arg < 10 ) {
@@ -149,14 +149,14 @@ return arg;
}
@Test
- public void testChapter8Regress2() {
+ public void testRegress2() {
Parser parser = new Parser("if(1) return 0; else while(arg>--arg) arg=arg+1; return 0;");
StopNode stop = parser.parse(true);
assertEquals("Stop[ return 0; return 0; ]", stop.toString());
}
@Test
- public void testChapter8BreakOutsideLoop() {
+ public void testBreakOutsideLoop() {
try {
new Parser("""
if(arg <= 10) {
@@ -172,7 +172,7 @@ return arg;
}
@Test
- public void testChapter8Regress3() {
+ public void testRegress3() {
Parser parser = new Parser("""
while(arg < 10) {
break;
@@ -184,7 +184,7 @@ return arg;
}
@Test
- public void testChapter8Regress4() {
+ public void testRegress4() {
Parser parser = new Parser("""
int a = 1;
while(arg < 10) {
@@ -202,7 +202,7 @@ return a;
}
@Test
- public void testChapter8Regress5() {
+ public void testRegress5() {
Parser parser = new Parser("""
int a = 1;
while(1) {
@@ -217,1030 +217,4 @@ return a;
assertTrue(stop.ret().ctrl() instanceof RegionNode);
}
- @Test
- public void testChapter7Example() {
- Parser parser = new Parser(
- """
- while(arg < 10) {
- arg = arg + 1;
- #showGraph;
- }
- return arg;
- """);
- Node._disablePeephole = true;
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop6,arg,(Phi_arg+1));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter7Regression() {
- Parser parser = new Parser(
-
-"""
-int a = 1;
-if(arg){}else{
- while(a < 10) {
- a = a + 1;
- }
-}
-return a;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Region22,1,Phi(Loop11,1,(Phi_a+1)));", stop.toString());
- }
-
- @Test
- public void testChapter7WhileNested() {
- Parser parser = new Parser(
-
-"""
-int sum = 0;
-int i = 0;
-while(i < arg) {
- i = i + 1;
- int j = 0;
- while( j < arg ) {
- sum = sum + j;
- j = j + 1;
- }
-}
-return sum;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop8,0,Phi(Loop20,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", stop.toString());
- System.out.println(IRPrinter.prettyPrint(stop,99));
- }
-
- @Test
- public void testChapter7WhileScope() {
- Parser parser = new Parser(
-"""
-int a = 1;
-int b = 2;
-while(a < 10) {
- if (a == 2) a = 3;
- else b = 4;
-}
-return b;
-""");
- Node._disablePeephole = true;
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop8,2,Phi(Region26,Phi_b,4));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- Node._disablePeephole = false;
- System.out.println(IRPrinter.prettyPrint(stop,99));
- }
-
- @Test
- public void testChapter7WhileNestedIfAndInc() {
- Parser parser = new Parser(
-"""
-int a = 1;
-int b = 2;
-while(a < 10) {
- if (a == 2) a = 3;
- else b = 4;
- b = b + 1;
- a = a + 1;
-}
-return b;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop8,2,(Phi(Region26,Phi_b,4)+1));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- System.out.println(IRPrinter.prettyPrint(stop,99));
- }
-
-
- @Test
- public void testChapter7While() {
- Parser parser = new Parser(
-"""
-int a = 1;
-while(a < 10) {
- a = a + 1;
- a = a + 2;
-}
-return a;
-""");
- Node._disablePeephole = true;
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop7,1,((Phi_a+1)+2));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter7WhilePeep() {
- Parser parser = new Parser(
-"""
-int a = 1;
-while(a < 10) {
- a = a + 1;
- a = a + 2;
-}
-return a;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop7,1,(Phi_a+3));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- }
-
- @Test
- public void testChapter7While2() {
- Parser parser = new Parser(
-"""
-int a = 1;
-while(arg) a = 2;
-return a;
-""");
- Node._disablePeephole = true;
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop7,1,2);", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- Node._disablePeephole = false;
- System.out.println(IRPrinter.prettyPrint(stop,99));
- }
-
- @Test
- public void testChapter7While2Peep() {
- Parser parser = new Parser(
-"""
-int a = 1;
-while(arg) a = 2;
-return a;
-""");
- StopNode stop = parser.parse(false);
- assertEquals("return Phi(Loop7,1,2);", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- System.out.println(IRPrinter.prettyPrint(stop, 99));
- }
-
- @Test
- public void testChapter7While3() {
- Parser parser = new Parser(
-"""
-int a = 1;
-while(a < 10) {
- int b = a + 1;
- a = b + 2;
-}
-return a;
-""");
- Node._disablePeephole = true;
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop7,1,((Phi_a+1)+2));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter7While3Peep() {
- Parser parser = new Parser(
-"""
-int a = 1;
-while(a < 10) {
- int b = a + 1;
- a = b + 2;
-}
-return a;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop7,1,(Phi_a+3));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- }
-
- @Test
- public void testChapter7While4() {
- Parser parser = new Parser(
-"""
-int a = 1;
-int b = 2;
-while(a < 10) {
- int b = a + 1;
- a = b + 2;
-}
-return a;
-""");
- Node._disablePeephole = true;
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop8,1,((Phi_a+1)+2));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter7While4Peep() {
- Parser parser = new Parser(
-"""
-int a = 1;
-int b = 2;
-while(a < 10) {
- int b = a + 1;
- a = b + 2;
-}
-return a;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Loop8,1,(Phi_a+3));", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- }
-
- @Test
- public void testChapter6PeepholeReturn() {
- Parser parser = new Parser(
-"""
-if( true ) return 2;
-return 1;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return 2;", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- }
-
- @Test
- public void testChapter6PeepholeRotate() {
- Parser parser = new Parser(
-"""
-int a = 1;
-if (arg)
- a = 2;
-return (arg < a) < 3;
-""");
- StopNode stop = parser.parse(false);
- assertEquals("return ((arg<Phi(Region12,2,1))<3);", stop.toString());
- }
-
- @Test
- public void testChapter6PeepholeCFG() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( true )
- a=2;
-else
- a=3;
-return a;
-""");
- StopNode stop = parser.parse(true);
- assertEquals("return 2;", stop.toString());
- assertTrue(stop.ret().ctrl() instanceof ProjNode);
- }
-
- @Test
- public void testChapter6IfIf() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg!=1 )
- a=2;
-else
- a=3;
-int b=4;
-if( a==2 )
- b=42;
-else
- b=5;
-return b;""", TypeInteger.BOT);
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Region32,42,5);", stop.toString());
- }
-
- @Test
- public void testChapter6IfArgIf() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( 1==1 )
- a=2;
-else
- a=3;
-int b=4;
-if( arg==2 )
- b=a;
-else
- b=5;
-return b;""", TypeInteger.BOT);
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Region28,2,5);", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3With2() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( arg==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-#showGraph;""", TypeInteger.constant(2));
- StopNode stop = parser.parse();
- assertEquals("return 5;", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3With1() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( arg==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-""", TypeInteger.constant(1));
- StopNode stop = parser.parse(true);
- assertEquals("return 3;", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3Peephole() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( 1==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-""", TypeInteger.BOT);
- StopNode stop = parser.parse(true);
- assertEquals("return Phi(Region36,3,Phi(Region34,4,5));", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3Peephole1() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( 1==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-""", TypeInteger.constant(1));
- StopNode stop = parser.parse(true);
- assertEquals("return 3;", stop.toString());
- }
-
- @Test
- public void testChapter6Merge3Peephole3() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( 1==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-""", TypeInteger.constant(3));
- StopNode stop = parser.parse(true);
- assertEquals("return 4;", stop.toString());
- }
-
- @Test
- public void testChapter6Demo1NonConst() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-if( arg ) {
- a = 2;
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b;
-""");
- StopNode ret = parser.parse(true);
- assertEquals("return Phi(Region22,4,1);", ret.toString());
- }
-
-
- @Test
- public void testChapter6Demo1True() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-if( arg ) {
- a = 2;
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b;
-""", TypeInteger.constant(1));
- StopNode ret = parser.parse(true);
- assertEquals("return 4;", ret.toString());
- }
-
- @Test
- public void testChapter6Demo1False() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-if( arg ) {
- a = 2;
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b;
-""", TypeInteger.constant(0));
- StopNode ret = parser.parse(true);
- assertEquals("return 1;", ret.toString());
- }
-
- @Test
- public void testChapter6Demo2NonConst() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-int c = 0;
-if( arg ) {
- a = 1;
- if( arg==2 ) { c=2; } else { c=3; }
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b+c;
-""");
- StopNode ret = parser.parse(true);
- assertEquals("return (Phi(Region33,Phi(Region22,2,3),0)+Phi(Region,3,1));", ret.toString());
- }
-
-
- @Test
- public void testChapter6Demo2True() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-int c = 0;
-if( arg ) {
- a = 1;
- if( arg==2 ) { c=2; } else { c=3; }
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b+c;
-""", TypeInteger.constant(1));
- StopNode ret = parser.parse(true);
- assertEquals("return 6;", ret.toString());
- }
-
- @Test
- public void testChapter6Demo2arg2() {
- Parser parser = new Parser("""
-int a = 0;
-int b = 1;
-int c = 0;
-if( arg ) {
- a = 1;
- if( arg==2 ) { c=2; } else { c=3; }
- if( arg ) { b = 2; }
- else b = 3;
-}
-return a+b+c;
-""", TypeInteger.constant(2));
- StopNode ret = parser.parse(true);
- assertEquals("return 5;", ret.toString());
- }
-
-
-
- @Test
- public void testChapter5IfStmt() {
- Parser parser = new Parser(
-"""
-int a = 1;
-if (arg == 1)
- a = arg+2;
-else {
- a = arg-3;
- #showGraph;
-}
-#showGraph;
-return a;""");
- StopNode ret = parser.parse(true);
- assertEquals("return Phi(Region17,(arg+2),(arg-3));", ret.toString());
- }
-
- @Test
- public void testChapter5Test() {
- Parser parser = new Parser(
-"""
-int c = 3;
-int b = 2;
-if (arg == 1) {
- b = 3;
- c = 4;
-}
-return c;""", TypeInteger.BOT);
- StopNode ret = parser.parse(true);
- assertEquals("return Phi(Region16,4,3);", ret.toString());
- }
-
- @Test
- public void testChapter5Return2() {
- Parser parser = new Parser(
-"""
-if( arg==1 )
- return 3;
-else
- return 4;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("Stop[ return 3; return 4; ]", stop.toString());
- }
-
- @Test
- public void testChapter5IfMergeB() {
- Parser parser = new Parser(
-"""
-int a=arg+1;
-int b=0;
-if( arg==1 )
- b=a;
-else
- b=a+1;
-return a+b;""");
- StopNode ret = parser.parse(true);
- assertEquals("return ((arg*2)+Phi(Region20,2,3));", ret.toString());
- }
-
- @Test
- public void testChapter5IfMerge2() {
- Parser parser = new Parser(
-"""
-int a=arg+1;
-int b=arg+2;
-if( arg==1 )
- b=b+a;
-else
- a=b+1;
-return a+b;""");
- StopNode ret = parser.parse(true);
- assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString());
- }
-
- @Test
- public void testChapter5Merge3() {
- Parser parser = new Parser(
-"""
-int a=1;
-if( arg==1 )
- if( arg==2 )
- a=2;
- else
- a=3;
-else if( arg==3 )
- a=4;
-else
- a=5;
-return a;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("return Phi(Region33,Phi(Region21,2,3),Phi(Region31,4,5));", stop.toString());
- }
-
- @Test
- public void testChapter5Merge4() {
- Parser parser = new Parser(
-"""
-int a=0;
-int b=0;
-if( arg )
- a=1;
-if( arg==0 )
- b=2;
-return arg+a+b;
-#showGraph;""", TypeInteger.BOT);
- StopNode stop = parser.parse();
- assertEquals("return ((arg+Phi(Region13,1,0))+Phi(Region22,2,0));", stop.toString());
- }
-
- @Test
- public void testChapter5Merge5() {
- Parser parser = new Parser(
-"""
-int a=arg==2;
-if( arg==1 )
-{
- a=arg==3;
-}
-return a;""");
- StopNode ret = parser.parse(true);
- assertEquals("return (arg==Phi(Region16,3,2));", ret.toString());
- }
-
- @Test
- public void testChapter5True() {
- StopNode stop = new Parser("return true;").parse();
- assertEquals("return 1;",stop.toString());
- }
-
- @Test
- public void testChapter5HalfDef() {
- try {
- new Parser("if( arg==1 ) int b=2; return b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5HalfDef2() {
- try {
- new Parser("if( arg==1 ) { int b=2; } else { int b=3; } return b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'b'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Regress1() {
- try {
- new Parser("if(arg==2) int a=1; else int b=2; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Cannot define a new name on one arm of an if",e.getMessage());
- }
- }
-
-
- @Test
- public void testChapter5BadNum() {
- try {
- new Parser("return 1-;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected an identifier or expression: ;",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword1() {
- try {
- new Parser("int true=0; return true;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Expected an identifier, found 'true'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword2() {
- try {
- new Parser("int else=arg; if(else) else=2; else else=1; return else;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Expected an identifier, found 'else'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter5Keyword3() {
- try {
- new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: (",e.getMessage());
- }
- }
-
- @Test
- public void testChapter4Peephole() {
- Parser parser = new Parser("return 1+arg+2; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Peephole2() {
- Parser parser = new Parser("return (1+arg)+2;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Add0() {
- Parser parser = new Parser("return 0+arg;");
- StopNode ret = parser.parse();
- assertEquals("return arg;", ret.print());
- }
-
- @Test
- public void testChapter4AddAddMul() {
- Parser parser = new Parser("return arg+0+arg;");
- StopNode ret = parser.parse();
- assertEquals("return (arg*2);", ret.print());
- }
-
- @Test
- public void testChapter4Peephole3() {
- Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return ((arg*2)+6);", ret.print());
- }
-
- @Test
- public void testChapter4Mul1() {
- Parser parser = new Parser("return 1*arg;");
- StopNode ret = parser.parse();
- assertEquals("return arg;", ret.print());
- }
-
- @Test
- public void testChapter4VarArg() {
- Parser parser = new Parser("return arg; #showGraph;");
- StopNode stop = parser.parse();
- ReturnNode ret = stop.ret();
- assertTrue(ret.in(0) instanceof ProjNode);
- assertTrue(ret.in(1) instanceof ProjNode);
- }
-
- @Test
- public void testChapter4ConstantArg() {
- Parser parser = new Parser("return arg; #showGraph;", TypeInteger.constant(2));
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter4CompEq() {
- Parser parser = new Parser("return 3==3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testChapter4CompEq2() {
- Parser parser = new Parser("return 3==4; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 0;", ret.print());
- }
-
- @Test
- public void testChapter4CompNEq() {
- Parser parser = new Parser("return 3!=3; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 0;", ret.print());
- }
-
- @Test
- public void testChapter4CompNEq2() {
- Parser parser = new Parser("return 3!=4; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testChapter4Bug1() {
- Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+3);", ret.print());
- }
-
- @Test
- public void testChapter4Bug2() {
- Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return (arg+1);", ret.print());
- }
-
- @Test
- public void testChapter4Bug3() {
- try {
- new Parser("inta=1; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'inta'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter4Bug4() {
- Parser parser = new Parser("return -arg;");
- StopNode ret = parser.parse();
- assertEquals("return (-arg);", ret.print());
- }
-
- @Test
- public void testVarDecl() {
- Parser parser = new Parser("int a=1; return a;");
- StopNode ret = parser.parse();
- assertEquals("return 1;", ret.print());
- }
-
- @Test
- public void testVarAdd() {
- Parser parser = new Parser("int a=1; int b=2; return a+b;");
- StopNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testVarScope() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; } return c;");
- StopNode ret = parser.parse();
- assertEquals("return 4;", ret.print());
- }
-
- @Test
- public void testVarScopeNoPeephole() {
- Parser parser = new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph;");
- Node._disablePeephole = true;
- StopNode ret = parser.parse();
- Node._disablePeephole = false;
- assertEquals("return (1+3);", ret.print());
- }
-
- @Test
- public void testVarDist() {
- Parser parser = new Parser("int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph;");
- StopNode ret = parser.parse();
- assertEquals("return 8;", ret.print());
- }
-
- @Test
- public void testSelfAssign() {
- try {
- new Parser("int a=a; return a;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'a'",e.getMessage());
- }
- }
-
- @Test
- public void testChapter2ParseGrammar() {
- Parser parser = new Parser("return 1+2*3+-5;");
- Node._disablePeephole = true; // disable peephole so we can observe full graph
- StopNode ret = parser.parse();
- assertEquals("return (1+((2*3)+(-5)));", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- Node._disablePeephole = false;
- }
-
- @Test
- public void testChapter2AddPeephole() {
- Parser parser = new Parser("return 1+2;");
- StopNode ret = parser.parse();
- assertEquals("return 3;", ret.print());
- }
-
- @Test
- public void testChapter2SubPeephole() {
- Parser parser = new Parser("return 1-2;");
- StopNode ret = parser.parse();
- assertEquals("return -1;", ret.print());
- }
-
- @Test
- public void testChapter2MulPeephole() {
- Parser parser = new Parser("return 2*3;");
- StopNode ret = parser.parse();
- assertEquals("return 6;", ret.print());
- }
-
- @Test
- public void testChapter2DivPeephole() {
- Parser parser = new Parser("return 6/3;");
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- }
-
- @Test
- public void testChapter2MinusPeephole() {
- Parser parser = new Parser("return 6/-3;");
- StopNode ret = parser.parse();
- assertEquals("return -2;", ret.print());
- }
-
- @Test
- public void testChapter2Example() {
- Parser parser = new Parser("return 1+2*3+-5;");
- StopNode ret = parser.parse();
- assertEquals("return 2;", ret.print());
- GraphVisualizer gv = new GraphVisualizer();
- System.out.println(gv.generateDotOutput(parser));
- }
-
- @Test
- public void testSimpleProgram() {
- Parser parser = new Parser("return 1;");
- StopNode stop = parser.parse();
- StartNode start = Parser.START;
- ReturnNode ret = (ReturnNode)stop.in(0);
-
- assertTrue(ret.ctrl() instanceof ProjNode);
- Node expr = ret.expr();
- if( expr instanceof ConstantNode con ) {
- assertEquals(start,con.in(0));
- assertEquals(TypeInteger.constant(1), con._type);
- } else {
- fail();
- }
- }
-
- @Test
- public void testZero() {
- Parser parser = new Parser("return 0;");
- parser.parse();
- StartNode start = Parser.START;
- for( Node use : start._outputs )
- if( use instanceof ConstantNode con && con._type instanceof TypeInteger )
- assertEquals(TypeInteger.constant(0),con._type);
- }
-
- @Test
- public void testBad1() {
- try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad2() {
- try {
- new Parser("return 0123;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
-
- @Test
- public void testBad6() {
- try {
- new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected }: ",e.getMessage());
- }
- }
-
- @Test
- public void testBad7() {
- try {
- new Parser("return 1;}").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
- }
- }
-
}
diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Fuzzer08Test.java b/chapter08/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
index ee635c22..82a6a472 100644
--- a/chapter08/src/test/java/com/seaofnodes/simple/Fuzzer08Test.java
+++ b/chapter08/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
@@ -10,9 +10,9 @@ 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>
+ * via <code>mvn clean test -Dtest=com.seaofnodes.simple.FuzzerWrap#fuzzPeeps</code>
*/
-public class Fuzzer08Test {
+public class FuzzerWrap {
@Test
@Ignore
diff --git a/chapter09/README.md b/chapter09/README.md
index c6846bed..b8ff8af1 100644
--- a/chapter09/README.md
+++ b/chapter09/README.md
@@ -1,4 +1,4 @@
-# Chapter 9
+# Chapter 9: Global Value Numbering and Iterative Peepholes
In this chapter:
diff --git a/chapter09/docs/Makefile b/chapter09/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter09/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter09/docs/build-graphs.sh b/chapter09/docs/build-graphs.sh
deleted file mode 100644
index dbd22623..00000000
--- a/chapter09/docs/build-graphs.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-dot -Tsvg 09-graph1.gv > 09-graph1.svg
-dot -Tsvg 09-graph2.gv > 09-graph2.svg
-dot -Tsvg 09-graph3.gv > 09-graph3.svg
-dot -Tsvg 09-graph4.gv > 09-graph4.svg
-dot -Tsvg 09-graph5.gv > 09-graph5.svg
-dot -Tsvg 09-graph6.gv > 09-graph6.svg
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/Parser.java b/chapter09/src/main/java/com/seaofnodes/simple/Parser.java
index b3aeeb22..c4ce71eb 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/Parser.java
@@ -615,6 +615,7 @@ public class Parser {
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -623,13 +624,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter09/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter09/src/test/java/com/seaofnodes/simple/Chapter01Test.java
index 5abfc4cf..13b42f96 100644
--- a/chapter09/src/test/java/com/seaofnodes/simple/Chapter01Test.java
+++ b/chapter09/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
@@ -37,6 +35,15 @@ public class Chapter01Test {
assertEquals(TypeInteger.constant(0),con._type);
}
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
@Test
public void testBad2() {
@@ -47,4 +54,47 @@ public class Chapter01Test {
assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
}
}
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected =: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
}
diff --git a/chapter09/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter09/src/test/java/com/seaofnodes/simple/Chapter02Test.java
index 3dd22e39..2deba460 100644
--- a/chapter09/src/test/java/com/seaofnodes/simple/Chapter02Test.java
+++ b/chapter09/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
@@ -65,35 +63,4 @@ public class Chapter02Test {
System.out.println(gv.generateDotOutput(parser));
}
- @Test
- public void testBad1() {
- try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected =: ",e.getMessage());
- }
- }
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
-
}
diff --git a/chapter09/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter09/src/test/java/com/seaofnodes/simple/Chapter03Test.java
index 6bcfcc4b..407fbe48 100644
--- a/chapter09/src/test/java/com/seaofnodes/simple/Chapter03Test.java
+++ b/chapter09/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
@@ -58,7 +56,7 @@ public class Chapter03Test {
}
@Test
- public void testBad6() {
+ public void testBad1() {
try {
new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
fail();
diff --git a/chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java
index 5a024e77..cde23324 100644
--- a/chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java
+++ b/chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
diff --git a/chapter09/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter09/src/test/java/com/seaofnodes/simple/Chapter05Test.java
index 24ae80b8..c82914a1 100644
--- a/chapter09/src/test/java/com/seaofnodes/simple/Chapter05Test.java
+++ b/chapter09/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
@@ -203,7 +201,7 @@ return a;""");
}
@Test
- public void testKeyword3() {
+ public void testKeyword3() {
try {
new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
fail();
@@ -212,14 +210,4 @@ return a;""");
}
}
- @Test
- public void testBad7() {
- try {
- new Parser("return 1;}").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
- }
- }
-
}
diff --git a/chapter09/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter09/src/test/java/com/seaofnodes/simple/Chapter06Test.java
index 5fece2e2..e5961223 100644
--- a/chapter09/src/test/java/com/seaofnodes/simple/Chapter06Test.java
+++ b/chapter09/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
diff --git a/chapter09/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter09/src/test/java/com/seaofnodes/simple/Chapter07Test.java
index d42af6c3..2c378623 100644
--- a/chapter09/src/test/java/com/seaofnodes/simple/Chapter07Test.java
+++ b/chapter09/src/test/java/com/seaofnodes/simple/Chapter07Test.java
@@ -2,15 +2,12 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
public class Chapter07Test {
-
@Test
public void testExample() {
Parser parser = new Parser(
@@ -31,7 +28,6 @@ public class Chapter07Test {
@Test
public void testRegression() {
Parser parser = new Parser(
-
"""
int a = 1;
if(arg){}else{
@@ -48,7 +44,6 @@ return a;
@Test
public void testWhileNested() {
Parser parser = new Parser(
-
"""
int sum = 0;
int i = 0;
@@ -241,4 +236,5 @@ return a;
assertEquals("return Phi(Loop8,1,(Phi_a+3));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof ProjNode);
}
+
}
diff --git a/chapter09/src/test/java/com/seaofnodes/simple/FuzzerWrap.java b/chapter09/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
index efd76481..bb3bec1c 100644
--- a/chapter09/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
+++ b/chapter09/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
@@ -10,11 +10,12 @@ 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>
+ * via <code>mvn clean test -Dtest=com.seaofnodes.simple.FuzzerWrap#fuzzPeeps</code>
*/
public class FuzzerWrap {
@Test
+ @Ignore
public void fuzzPeeps() {
var fuzzer = new Fuzzer();
for (int i=0; i<1000000; i++)
diff --git a/chapter10/README.md b/chapter10/README.md
index bd46a70e..62c4844b 100644
--- a/chapter10/README.md
+++ b/chapter10/README.md
@@ -1,4 +1,4 @@
-# Chapter 10
+# Chapter 10: Structs and Memory
In this chapter:
diff --git a/chapter10/docs/Makefile b/chapter10/docs/Makefile
new file mode 100644
index 00000000..12659b8f
--- /dev/null
+++ b/chapter10/docs/Makefile
@@ -0,0 +1,12 @@
+GV := $(wildcard *.gv)
+SVG := $(patsubst %.gv,%.svg,$(GV))
+
+.PHONY: all
+all: $(SVG)
+
+%.svg: %.gv
+ dot -Tsvg $< > $@
+
+.PHONY: clean
+clean:
+ @rm -f $(SVG)
diff --git a/chapter10/docs/build-graphs.sh b/chapter10/docs/build-graphs.sh
deleted file mode 100644
index 67dd302f..00000000
--- a/chapter10/docs/build-graphs.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-dot -Tsvg example1.gv > example1.svg
-dot -Tsvg example2a.gv > example2a.svg
-dot -Tsvg example2b.gv > example2b.svg
-dot -Tsvg example2c.gv > example2c.svg
-dot -Tsvg lattice.gv > lattice.svg
diff --git a/chapter10/src/main/java/com/seaofnodes/simple/Parser.java b/chapter10/src/main/java/com/seaofnodes/simple/Parser.java
index def37bae..9a1b4465 100644
--- a/chapter10/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter10/src/main/java/com/seaofnodes/simple/Parser.java
@@ -785,6 +785,7 @@ public class Parser {
String getAnyNextToken() {
if (isEOF()) return "";
if (isIdStart(peek())) return parseId();
+ if (isNumber(peek())) return parseNumberString();
if (isPunctuation(peek())) return parsePunctuation();
return String.valueOf(peek());
}
@@ -793,13 +794,16 @@ public class Parser {
boolean isNumber(char ch) {return Character.isDigit(ch);}
private Type parseNumber() {
- int start = _position;
- while (isNumber(nextChar())) ;
- String snum = new String(_input, start, --_position - start);
+ String snum = parseNumberString();
if (snum.length() > 1 && snum.charAt(0) == '0')
throw error("Syntax error: integer values cannot start with '0'");
return TypeInteger.constant(Long.parseLong(snum));
}
+ private String parseNumberString() {
+ int start = _position;
+ while (isNumber(nextChar())) ;
+ return new String(_input, start, --_position - start);
+ }
// First letter of an identifier
private boolean isIdStart(char ch) {
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter01Test.java
index 5abfc4cf..89882b2f 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter01Test.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter01Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
@@ -37,6 +35,15 @@ public class Chapter01Test {
assertEquals(TypeInteger.constant(0),con._type);
}
+ @Test
+ public void testBad1() {
+ try {
+ new Parser("ret").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'ret'",e.getMessage());
+ }
+ }
@Test
public void testBad2() {
@@ -47,4 +54,47 @@ public class Chapter01Test {
assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage());
}
}
+
+ @Test
+ public void testNotBad3() {
+ // this test used to fail in chapter 1
+ assertEquals("return 12;", new Parser("return --12;").parse().print());
+ }
+
+ @Test
+ public void testBad4() {
+ try {
+ new Parser("return 100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, expected ;: ",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNotBad5() {
+ // this test used to fail in chapter 1
+ assertEquals("return -100;", new Parser("return -100;").parse().print());
+ }
+
+ @Test
+ public void testBad6() {
+ try {
+ new Parser("return100").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Undefined name 'return100'",e.getMessage());
+ }
+ }
+
+ @Test
+ public void testBad7() {
+ try {
+ new Parser("return 1;}").parse();
+ fail();
+ } catch( RuntimeException e ) {
+ assertEquals("Syntax error, unexpected }",e.getMessage());
+ }
+ }
+
}
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter02Test.java
index 107225ae..2deba460 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter02Test.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter02Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
@@ -65,35 +63,4 @@ public class Chapter02Test {
System.out.println(gv.generateDotOutput(parser));
}
- @Test
- public void testBad1() {
- try {
- new Parser("ret").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Undefined name 'ret'",e.getMessage());
- }
- }
- @Test
- public void testNotBad3() {
- // this test used to fail in chapter 1
- assertEquals("return 12;", new Parser("return --12;").parse().print());
- }
-
- @Test
- public void testBad4() {
- try {
- new Parser("return 100").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, expected ;: ",e.getMessage());
- }
- }
-
- @Test
- public void testNotBad5() {
- // this test used to fail in chapter 1
- assertEquals("return -100;", new Parser("return -100;").parse().print());
- }
-
}
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter03Test.java
index 6bcfcc4b..407fbe48 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter03Test.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter03Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
@@ -58,7 +56,7 @@ public class Chapter03Test {
}
@Test
- public void testBad6() {
+ public void testBad1() {
try {
new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse();
fail();
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java
index 5a024e77..cde23324 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter05Test.java
index e82aa7da..44fff0c0 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter05Test.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
@@ -203,7 +201,7 @@ return a;""");
}
@Test
- public void testKeyword3() {
+ public void testKeyword3() {
try {
new Parser("int a=1; ififif(arg)inta=2;return a;").parse();
fail();
@@ -212,14 +210,4 @@ return a;""");
}
}
- @Test
- public void testBad7() {
- try {
- new Parser("return 1;}").parse();
- fail();
- } catch( RuntimeException e ) {
- assertEquals("Syntax error, unexpected }",e.getMessage());
- }
- }
-
}
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter06Test.java
index 6c24992c..d30bd43d 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter06Test.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -2,9 +2,7 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter07Test.java
index 29d16f32..a5cddb68 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter07Test.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter07Test.java
@@ -2,15 +2,12 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import org.junit.Assert;
import org.junit.Test;
-import org.junit.Ignore;
import static org.junit.Assert.*;
public class Chapter07Test {
-
@Test
public void testExample() {
Parser parser = new Parser(
@@ -47,7 +44,6 @@ return a;
@Test
public void testWhileNested() {
Parser parser = new Parser(
-
"""
int sum = 0;
int i = 0;
@@ -240,4 +236,5 @@ return a;
assertEquals("return Phi(Loop8,1,(Phi_a+3));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof ProjNode);
}
+
}
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter10Test.java
index f7388ff9..2e1ae1aa 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter10Test.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter10Test.java
@@ -3,7 +3,6 @@ package com.seaofnodes.simple;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.StopNode;
import com.seaofnodes.simple.type.*;
-import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
diff --git a/chapter10/src/test/java/com/seaofnodes/simple/FuzzerWrap.java b/chapter10/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
index 699711fc..bb3bec1c 100644
--- a/chapter10/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
+++ b/chapter10/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
@@ -10,12 +10,12 @@ 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>
+ * via <code>mvn clean test -Dtest=com.seaofnodes.simple.FuzzerWrap#fuzzPeeps</code>
*/
public class FuzzerWrap {
- @Ignore
@Test
+ @Ignore
public void fuzzPeeps() {
var fuzzer = new Fuzzer();
for (int i=0; i<1000000; i++)