diff options
| author | Thalia Archibald <thalia@archibald.dev> | 2024-06-21 12:58:51 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-21 20:58:51 +0100 |
| commit | fd8442075faa603b3956d51d81486424624c5355 (patch) | |
| tree | 029c1afb736ff0e350c2b032318e5fc376c7e1e4 /chapter01 | |
| parent | e5f4f7b85fbb91a293a7d89d7b85adfbaeeb51f4 (diff) | |
| download | Simple-fd8442075faa603b3956d51d81486424624c5355.tar.gz Simple-fd8442075faa603b3956d51d81486424624c5355.zip | |
Backport tests (#87)
* Fix unexpected number parse errors
* Add chapter titles
* Split test files by chapter
* Backport rename Fuzzer08Test to FuzzerWrap
* Replace graph build scripts with Makefile
* Backport Chapter05Test.testRegress1
* Backport require space after 'return'
* Backport check EOF after return statement
Diffstat (limited to 'chapter01')
| -rw-r--r-- | chapter01/README.md | 2 | ||||
| -rw-r--r-- | chapter01/docs/Makefile | 12 | ||||
| -rw-r--r-- | chapter01/src/main/java/com/seaofnodes/simple/Parser.java | 39 | ||||
| -rw-r--r-- | chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java | 23 |
4 files changed, 68 insertions, 8 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()); + } + } + } |
