From 4b3209b65fb4aad2678712c5810e191e19672724 Mon Sep 17 00:00:00 2001 From: Associate 1 Date: Tue, 3 Mar 2026 18:51:52 -0700 Subject: [PATCH] Support *" string escape sequence in lexer The lexer's readString() did not handle occam's * escape character, causing *" inside string literals to prematurely terminate the string. Added escape tracking to match the pattern already used in readByteLiteral(). Fixes #65 Co-Authored-By: Claude Opus 4.6 --- codegen/e2e_strings_test.go | 12 ++++++++++++ lexer/lexer.go | 14 +++++++++++++- lexer/lexer_test2_test.go | 14 ++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/codegen/e2e_strings_test.go b/codegen/e2e_strings_test.go index b36f2cd..7eaf6bc 100644 --- a/codegen/e2e_strings_test.go +++ b/codegen/e2e_strings_test.go @@ -65,3 +65,15 @@ func TestE2E_StringWithEscapes(t *testing.T) { t.Errorf("expected %q, got %q", expected, output) } } + +func TestE2E_StringWithEscapedQuote(t *testing.T) { + // *" inside a string literal should produce a literal double-quote + occam := `SEQ + print.string("He said *"hello*"") +` + output := transpileCompileRun(t, occam) + expected := "He said \"hello\"\n" + if output != expected { + t.Errorf("expected %q, got %q", expected, output) + } +} diff --git a/lexer/lexer.go b/lexer/lexer.go index be7ab24..30cfd78 100644 --- a/lexer/lexer.go +++ b/lexer/lexer.go @@ -303,9 +303,21 @@ func (l *Lexer) readHexNumber() string { func (l *Lexer) readString() string { position := l.position + 1 + escaped := false for { l.readChar() - if l.ch == '"' || l.ch == 0 { + if l.ch == 0 { + break + } + if escaped { + escaped = false + continue + } + if l.ch == '*' { + escaped = true + continue + } + if l.ch == '"' { break } } diff --git a/lexer/lexer_test2_test.go b/lexer/lexer_test2_test.go index 98c81ac..db26727 100644 --- a/lexer/lexer_test2_test.go +++ b/lexer/lexer_test2_test.go @@ -161,6 +161,20 @@ func TestStringEscapeSequences(t *testing.T) { } } +func TestStringEscapeQuote(t *testing.T) { + // *" inside a string should not terminate the string + input := `"He said *"hello*""` + "\n" + l := New(input) + tok := l.NextToken() + if tok.Type != STRING { + t.Fatalf("expected STRING, got %q", tok.Type) + } + expected := `He said *"hello*"` + if tok.Literal != expected { + t.Fatalf("expected literal %q, got %q", expected, tok.Literal) + } +} + func TestByteLiteralToken(t *testing.T) { input := "'A'\n" l := New(input)