diff --git a/pkl-cli/src/test/kotlin/org/pkl/cli/repl/ReplMessagesTest.kt b/pkl-cli/src/test/kotlin/org/pkl/cli/repl/ReplMessagesTest.kt index 145707e7..0ea92910 100644 --- a/pkl-cli/src/test/kotlin/org/pkl/cli/repl/ReplMessagesTest.kt +++ b/pkl-cli/src/test/kotlin/org/pkl/cli/repl/ReplMessagesTest.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. + * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,4 +64,11 @@ class ReplMessagesTest { startIndex = examples.indexOf("```", endIndex + 3) } } + + @Test + fun `handle single backtick`() { + val responses = server.handleRequest(ReplRequest.Eval("1", "`", true, true)) + assertThat(responses.size).isEqualTo(1) + assertThat(responses).hasOnlyElementsOfType(ReplResponse.EvalError::class.java) + } } diff --git a/pkl-core/src/test/files/LanguageSnippetTests/input/errors/singleBacktick.pkl b/pkl-core/src/test/files/LanguageSnippetTests/input/errors/singleBacktick.pkl new file mode 100644 index 00000000..b37663f1 --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/errors/singleBacktick.pkl @@ -0,0 +1 @@ +` diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/errors/singleBacktick.err b/pkl-core/src/test/files/LanguageSnippetTests/output/errors/singleBacktick.err new file mode 100644 index 00000000..7448f433 --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/errors/singleBacktick.err @@ -0,0 +1,7 @@ +–– Pkl Error –– +Unexpected character ` +`. Did you mean `backquote`? + +x | ` + ^ +at singleBacktick (file:///$snippetsDir/input/errors/singleBacktick.pkl) diff --git a/pkl-parser/src/main/java/org/pkl/parser/Lexer.java b/pkl-parser/src/main/java/org/pkl/parser/Lexer.java index 5b7ee93a..296ecd19 100644 --- a/pkl-parser/src/main/java/org/pkl/parser/Lexer.java +++ b/pkl-parser/src/main/java/org/pkl/parser/Lexer.java @@ -489,7 +489,7 @@ public class Lexer { } private void lexQuotedIdentifier() { - while (lookahead != '`' && lookahead != '\n' && lookahead != '\r') { + while (lookahead != '`' && lookahead != '\n' && lookahead != '\r' && lookahead != EOF) { nextChar(); } if (lookahead == '`') { @@ -705,6 +705,13 @@ public class Lexer { } private ParserError unexpectedChar(char got, String didYouMean) { + if (got == EOF) { + return unexpectedChar("EOF", didYouMean); + } + return lexError("unexpectedCharacter", got, didYouMean); + } + + private ParserError unexpectedChar(String got, String didYouMean) { return lexError("unexpectedCharacter", got, didYouMean); } diff --git a/pkl-parser/src/test/kotlin/org/pkl/parser/LexerTest.kt b/pkl-parser/src/test/kotlin/org/pkl/parser/LexerTest.kt index 6cd9fbfd..e76eebab 100644 --- a/pkl-parser/src/test/kotlin/org/pkl/parser/LexerTest.kt +++ b/pkl-parser/src/test/kotlin/org/pkl/parser/LexerTest.kt @@ -17,6 +17,7 @@ package org.pkl.parser import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows class LexerTest { @@ -46,4 +47,10 @@ class LexerTest { assertThat(Lexer.maybeQuoteIdentifier("this")).isEqualTo("`this`") assertThat(Lexer.maybeQuoteIdentifier("😀")).isEqualTo("`😀`") } + + @Test + fun lexSingleBacktick() { + val thrown = assertThrows { Lexer("`").next() } + assertThat(thrown).hasMessageContaining("Unexpected character `EOF`") + } }