diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/expression/scanner/ExpressionScanner.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/expression/scanner/ExpressionScanner.java index afcfd4bff..eae15e4cb 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/expression/scanner/ExpressionScanner.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/expression/scanner/ExpressionScanner.java @@ -19,8 +19,8 @@ public class ExpressionScanner extends AbstractScanner { private static final int[] QUOTE_OR_PAREN = new int[] { '(', ')', '"', '\'', }; - private static final int[] SPACE_PERIOD_LBRACKET = new int[] {' ', '.', '['}; - private static final int[] SPACE_PERIOD_LBRACKET_LPAREN_COLON = new int[] {' ', '.', '[', '(', ':'}; + private static final int[] SPACE_PERIOD_LBRACKET = new int[] { ' ', '.', '[' }; + private static final int[] SPACE_PERIOD_LBRACKET_LPAREN_COLON = new int[] { ' ', '.', '[', '(', ':' }; public static ExpressionScanner createScanner(String input, boolean canSupportInfixNotation) { return createScanner(input, canSupportInfixNotation, 0, input.length()); @@ -62,97 +62,105 @@ protected TokenType internalScan() { String errorMessage = null; switch (state) { - case WithinExpression: { - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - if (!canSupportInfixNotation) { - if (stream.advanceIfChar('"') || stream.advanceIfChar('\'')) { - state = ScannerState.WithinString; - return finishToken(stream.pos() - 1, TokenType.StartString); + case WithinExpression: { + if (stream.skipWhitespace()) { + return finishToken(offset, TokenType.Whitespace); } + if (!canSupportInfixNotation) { + if (stream.advanceIfChar('"') || stream.advanceIfChar('\'')) { + state = ScannerState.WithinString; + return finishToken(stream.pos() - 1, TokenType.StartString); + } + } + nextJavaIdentifierPart(); + return finishTokenPart(offset); } - nextJavaIdentifierPart(); - return finishTokenPart(offset); - } - case WithinParts: - case AfterNamespace: { - if (stream.skipWhitespace()) { - nbParts++; - return finishToken(offset, TokenType.Whitespace); - } - if (!canSupportInfixNotation) { - if (stream.advanceIfChar('"') || stream.advanceIfChar('\'')) { - state = ScannerState.WithinString; - return finishToken(stream.pos() - 1, TokenType.StartString); + case WithinParts: + case AfterNamespace: { + if (stream.skipWhitespace()) { + nbParts++; + return finishToken(offset, TokenType.Whitespace); } - } - if (stream.advanceIfChar('.')) { - // item.| - return finishToken(offset, TokenType.Dot); - } - if (stream.advanceIfChar('[')) { - // item[| - if (stream.advanceUntilChar(']')) { - stream.advance(1); - // item['name']| + if (!canSupportInfixNotation) { + if (stream.advanceIfChar('"') || stream.advanceIfChar('\'')) { + state = ScannerState.WithinString; + return finishToken(stream.pos() - 1, TokenType.StartString); + } } - return finishToken(offset, TokenType.PropertyPart); - } - if (stream.advanceIfChar(':')) { - // data:| - return finishToken(offset, TokenType.ColonSpace); + if (state == ScannerState.AfterNamespace) { + if (stream.peekChar() == '"' || stream.peekChar() == '\'') { + // config:" + stream.advance(1); + state = ScannerState.WithinString; + return finishToken(stream.pos() - 1, TokenType.StartString); + } + } + if (stream.advanceIfChar('.')) { + // item.| + return finishToken(offset, TokenType.Dot); + } + if (stream.advanceIfChar('[')) { + // item[| + if (stream.advanceUntilChar(']')) { + stream.advance(1); + // item['name']| + } + return finishToken(offset, TokenType.PropertyPart); + } + if (stream.advanceIfChar(':')) { + // data:| + return finishToken(offset, TokenType.ColonSpace); + } + nextJavaIdentifierPart(); + // item.name| + return finishTokenPart(offset); } - nextJavaIdentifierPart(); - // item.name| - return finishTokenPart(offset); - } - case WithinMethod: { - if (stream.advanceIfChar('(')) { - bracket++; - return finishToken(offset, TokenType.OpenBracket); - } - stream.advanceUntilChar(QUOTE_OR_PAREN); - if (stream.peekChar() == '(') { - stream.advance(1); - bracket++; - return internalScan(); - } - if (stream.peekChar() == '"' || stream.peekChar() == '\'') { - stream.advance(1); - state = ScannerState.WithinString; - inMethod = true; - return finishToken(stream.pos() - 1, TokenType.StartString); - } else if (stream.peekChar() == ')') { - stream.advance(1); - bracket--; - if (bracket > 0) { + case WithinMethod: { + if (stream.advanceIfChar('(')) { + bracket++; + return finishToken(offset, TokenType.OpenBracket); + } + stream.advanceUntilChar(QUOTE_OR_PAREN); + if (stream.peekChar() == '(') { + stream.advance(1); + bracket++; return internalScan(); } - state = ScannerState.WithinParts; - inMethod = false; - return finishToken(stream.pos() - 1, TokenType.CloseBracket); + if (stream.peekChar() == '"' || stream.peekChar() == '\'') { + stream.advance(1); + state = ScannerState.WithinString; + inMethod = true; + return finishToken(stream.pos() - 1, TokenType.StartString); + } else if (stream.peekChar() == ')') { + stream.advance(1); + bracket--; + if (bracket > 0) { + return internalScan(); + } + state = ScannerState.WithinParts; + inMethod = false; + return finishToken(stream.pos() - 1, TokenType.CloseBracket); + } + return internalScan(); } - return internalScan(); - } - case WithinString: { - if (stream.advanceIfAnyOfChars(QUOTE_C)) { - if (inMethod) { - state = ScannerState.WithinMethod; - } else { - state = ScannerState.WithinExpression; + case WithinString: { + if (stream.advanceIfAnyOfChars(QUOTE_C)) { + if (inMethod) { + state = ScannerState.WithinMethod; + } else { + state = ScannerState.WithinExpression; + } + return finishToken(offset, TokenType.EndString); } - return finishToken(offset, TokenType.EndString); + stream.advanceUntilChar(QUOTE); + return finishToken(offset, TokenType.String); } - stream.advanceUntilChar(QUOTE); - return finishToken(offset, TokenType.String); - } - default: - inMethod = false; + default: + inMethod = false; } stream.advance(1); return finishToken(offset, TokenType.Unknown, errorMessage); diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/parser/expression/scanner/ExpressionScannerTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/parser/expression/scanner/ExpressionScannerTest.java index 187b3d00a..5262776bd 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/parser/expression/scanner/ExpressionScannerTest.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/parser/expression/scanner/ExpressionScannerTest.java @@ -67,7 +67,7 @@ public void testObjectAndMethodPartWithParameters() { assertOffsetAndToken(25, TokenType.CloseBracket, ")"); assertOffsetAndToken(26, TokenType.EOS, ""); } - + @Test public void testNamespaceStartWithObject() { scanner = createInfixNotationScanner("data:foo"); @@ -127,6 +127,17 @@ public void testNamespaceWithMethodAndProperty() { assertOffsetAndToken(18, TokenType.EOS, ""); } + @Test + public void configNamespaceWithString() { + scanner = createInfixNotationScanner("config:\"quarkus.application.name\""); + assertOffsetAndToken(0, TokenType.NamespacePart, "config"); + assertOffsetAndToken(6, TokenType.ColonSpace, ":"); + assertOffsetAndToken(7, TokenType.StartString, "\""); + assertOffsetAndToken(8, TokenType.String, "quarkus.application.name"); + assertOffsetAndToken(32, TokenType.EndString, "\""); + assertOffsetAndToken(33, TokenType.EOS, ""); + } + /** * @see https://quarkus.io/guides/qute-reference#built-in-resolvers */ @@ -155,7 +166,7 @@ public void underscore() { } // Infix notation tests - + @Test public void testTwoPartsWithInfixNotation() { scanner = createInfixNotationScanner("a b"); @@ -173,7 +184,7 @@ public void testTwoPartsWithoutInfixNotation() { assertOffsetAndToken(2, TokenType.ObjectPart, "b"); // No infix notation -> object part assertOffsetAndToken(3, TokenType.EOS, ""); } - + @Test public void testThreePartsWithInfixNotation() { scanner = createInfixNotationScanner("a b c"); @@ -184,7 +195,7 @@ public void testThreePartsWithInfixNotation() { assertOffsetAndToken(4, TokenType.InfixParameter, "c"); assertOffsetAndToken(5, TokenType.EOS, ""); } - + @Test public void testSeveralPartsWithInfixNotation() { scanner = createInfixNotationScanner("a b c d e"); @@ -199,7 +210,7 @@ public void testSeveralPartsWithInfixNotation() { assertOffsetAndToken(8, TokenType.InfixParameter, "e"); assertOffsetAndToken(9, TokenType.EOS, ""); } - + @Test public void testThreePartsWithoutInfixNotation() { scanner = createNoInfixNotationScanner("a b c"); @@ -210,7 +221,7 @@ public void testThreePartsWithoutInfixNotation() { assertOffsetAndToken(4, TokenType.ObjectPart, "c"); assertOffsetAndToken(5, TokenType.EOS, ""); } - + @Test public void testOrInfixNotation() { scanner = createInfixNotationScanner("person.name or 'John'"); @@ -223,7 +234,7 @@ public void testOrInfixNotation() { assertOffsetAndToken(15, TokenType.InfixParameter, "'John'"); assertOffsetAndToken(21, TokenType.EOS, ""); } - + @Test public void testCharAtInfixNotation() { scanner = createInfixNotationScanner("foo charAt '1'"); @@ -234,7 +245,7 @@ public void testCharAtInfixNotation() { assertOffsetAndToken(11, TokenType.InfixParameter, "'1'"); assertOffsetAndToken(14, TokenType.EOS, ""); } - + @Test public void testCharAtNoInfixNotation() { scanner = createNoInfixNotationScanner("foo charAt '1'"); @@ -247,7 +258,7 @@ public void testCharAtNoInfixNotation() { assertOffsetAndToken(13, TokenType.EndString, "'"); assertOffsetAndToken(14, TokenType.EOS, ""); } - + @Test public void testMethodsAndInfixNotation() { scanner = createInfixNotationScanner("items.get(0) or 1"); @@ -262,7 +273,7 @@ public void testMethodsAndInfixNotation() { assertOffsetAndToken(16, TokenType.InfixParameter, "1"); assertOffsetAndToken(17, TokenType.EOS, ""); } - + @Test public void dotSpace() { scanner = createInfixNotationScanner("items. "); @@ -271,7 +282,7 @@ public void dotSpace() { assertOffsetAndToken(6, TokenType.Whitespace, " "); assertOffsetAndToken(7, TokenType.EOS, ""); } - + @Test public void twoMethodsWithOr() { scanner = createInfixNotationScanner("item.name or item.name"); @@ -284,7 +295,7 @@ public void twoMethodsWithOr() { assertOffsetAndToken(13, TokenType.InfixParameter, "item.name"); assertOffsetAndToken(22, TokenType.EOS, ""); } - + @Test public void infixNotationWithBracket() { scanner = createInfixNotationScanner("foo getBytes()"); @@ -304,7 +315,7 @@ public void elvisOperator() { assertOffsetAndToken(8, TokenType.InfixParameter, "\"Quarkus Insights\""); assertOffsetAndToken(26, TokenType.EOS, ""); } - + private void assertOffsetAndToken(int tokenOffset, TokenType tokenType, String tokenText) { TokenType token = scanner.scan(); assertEquals(tokenOffset, scanner.getTokenOffset()); @@ -315,7 +326,7 @@ private void assertOffsetAndToken(int tokenOffset, TokenType tokenType, String t private ExpressionScanner createInfixNotationScanner(String input) { return ExpressionScanner.createScanner(input, true); } - + private ExpressionScanner createNoInfixNotationScanner(String input) { return ExpressionScanner.createScanner(input, false); } diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java index dfb2eda1e..e665fb512 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java @@ -690,4 +690,11 @@ public void escape() throws Exception { String template = "function gtag()\\{dataLayer.push(arguments);\\}"; testDiagnosticsFor(template); } + + @Test + public void configNamepscaeWithString() throws Exception { + String template = "{config:\"quarkus.application.name\"}"; + testDiagnosticsFor(template); + } + }