# HG changeset patch # User Laurens Holst # Date 1644424829 -3600 # Wed Feb 09 17:40:29 2022 +0100 # Node ID 870710d0b04f9b220e4590de5f171cb59f49bb71 # Parent 43c4b16b75dfdc98171a624ddf51616ce1fa6118 Parser: Support '' and "" escapes in character and string literals. diff --git a/CHANGES.md b/CHANGES.md --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,8 @@ * The `$` prefix can now be used for hexadecimal numbers. * Symbols can no longer start with the `$` character (bc). * The `>>>` unsigned shift right operator is now supported. + * The `'` character can now be written as `''` in character literals. + * The `"` character can now be written as `""` in string literals. Glass 0.5 — 2017-01-18 ---------------------- diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -303,6 +303,9 @@ * Character: `'c'` * String: `"abc"` +Character literals can contain the `'` character by repeating it as `''`, and +string literals can contain the `"` character by repeating it as `""`. + Character and string literals support the following escape sequences: * `\0` (NUL) diff --git a/src/main/java/nl/grauw/glass/Parser.java b/src/main/java/nl/grauw/glass/Parser.java --- a/src/main/java/nl/grauw/glass/Parser.java +++ b/src/main/java/nl/grauw/glass/Parser.java @@ -253,9 +253,7 @@ private class ArgumentStringState extends State { public State parse(char character) { if (character == '"') { - expressionBuilder.addValueToken(new StringLiteral(accumulator.toString())); - accumulator.setLength(0); - return argumentOperatorState; + return argumentStringDoubleQuoteState; } else if (character == '\\') { return argumentStringEscapeState; } else if (character == '\n' || character == '\0') { @@ -267,6 +265,20 @@ } } + private ArgumentStringDoubleQuoteState argumentStringDoubleQuoteState = new ArgumentStringDoubleQuoteState(); + private class ArgumentStringDoubleQuoteState extends State { + public State parse(char character) { + if (character == '"') { + accumulator.append(character); + return argumentStringState; + } else { + expressionBuilder.addValueToken(new StringLiteral(accumulator.toString())); + accumulator.setLength(0); + return argumentOperatorState.parse(character); + } + } + } + private ArgumentStringEscapeState argumentStringEscapeState = new ArgumentStringEscapeState(); private class ArgumentStringEscapeState extends State { public State parse(char character) { @@ -311,9 +323,11 @@ private ArgumentCharacterState argumentCharacterState = new ArgumentCharacterState(); private class ArgumentCharacterState extends State { public State parse(char character) { - if (character == '\\') { + if (character == '\'') { + return argumentCharacterDoubleQuoteState; + } else if (character == '\\') { return argumentCharacterEscapeState; - } else if (character == '\'' || character == '\n' || character == '\0') { + } else if (character == '\n' || character == '\0') { throw new SyntaxError(); } else { accumulator.append(character); @@ -322,6 +336,18 @@ } } + private ArgumentCharacterDoubleQuoteState argumentCharacterDoubleQuoteState = new ArgumentCharacterDoubleQuoteState(); + private class ArgumentCharacterDoubleQuoteState extends State { + public State parse(char character) { + if (character == '\'') { + accumulator.append(character); + return argumentCharacterEndState; + } else { + throw new SyntaxError(); + } + } + } + private ArgumentCharacterEscapeState argumentCharacterEscapeState = new ArgumentCharacterEscapeState(); private class ArgumentCharacterEscapeState extends State { public State parse(char character) { diff --git a/src/test/java/nl/grauw/glass/ParserTest.java b/src/test/java/nl/grauw/glass/ParserTest.java --- a/src/test/java/nl/grauw/glass/ParserTest.java +++ b/src/test/java/nl/grauw/glass/ParserTest.java @@ -116,6 +116,11 @@ } @Test + public void testCharacterLiteralDoubleQuote() { + assertEquals('\'', ((CharacterLiteral)parseExpression("''''")).getCharacter()); + } + + @Test public void testCharacterLiteralEscape() { assertEquals('\0', ((CharacterLiteral)parseExpression("'\\0'")).getCharacter()); assertEquals('\7', ((CharacterLiteral)parseExpression("'\\a'")).getCharacter()); @@ -138,7 +143,7 @@ @Test public void testCharacterLiteralTooShort() { - assertSyntaxError(0, 1, 1, () -> { + assertSyntaxError(0, 1, 2, () -> { parseExpression("''"); }); } @@ -163,6 +168,11 @@ } @Test + public void testStringLiteralDoubleQuote() { + assertEquals("x\"z", ((StringLiteral)parseExpression("\"x\"\"z\"")).getString()); + } + + @Test public void testStringLiteralEscape() { assertEquals("x\0z", ((StringLiteral)parseExpression("\"x\\0z\"")).getString()); assertEquals("x\7z", ((StringLiteral)parseExpression("\"x\\az\"")).getString());