HQL semantic tokens provider initial work
This commit is contained in:
12
headless-services/commons/jpql/.gitignore
vendored
12
headless-services/commons/jpql/.gitignore
vendored
@@ -1,6 +1,10 @@
|
||||
/antlr-4.13.1.jar
|
||||
/src/main/java/org/springframework/ide/vscode/jpql/antlr/parser/Jpql.interp
|
||||
/src/main/java/org/springframework/ide/vscode/jpql/antlr/parser/Jpql.tokens
|
||||
/src/main/java/org/springframework/ide/vscode/jpql/antlr/parser/JpqlLexer.interp
|
||||
/src/main/java/org/springframework/ide/vscode/jpql/antlr/parser/JpqlLexer.tokens
|
||||
/src/main/java/org/springframework/ide/vscode/parser/jpql/Jpql.interp
|
||||
/src/main/java/org/springframework/ide/vscode/parser/jpql/Jpql.tokens
|
||||
/src/main/java/org/springframework/ide/vscode/parser/jpql/JpqlLexer.interp
|
||||
/src/main/java/org/springframework/ide/vscode/parser/jpql/JpqlLexer.tokens
|
||||
/src/main/java/org/springframework/ide/vscode/parser/hql/Hql.interp
|
||||
/src/main/java/org/springframework/ide/vscode/parser/hql/Hql.tokens
|
||||
/src/main/java/org/springframework/ide/vscode/parser/hql/HqlLexer.interp
|
||||
/src/main/java/org/springframework/ide/vscode/parser/hql/HqlLexer.tokens
|
||||
/target
|
||||
|
||||
@@ -6,5 +6,6 @@ if [ ! -f antlr-${ANTLR_VERSION}.jar ]; then
|
||||
fi
|
||||
workdir=$(pwd)
|
||||
cd grammars
|
||||
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar Jpql.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode/jpql/antlr/parser -package org.springframework.ide.vscode.jpql.antlr.parser
|
||||
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar Jpql.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode/parser/jpql -package org.springframework.ide.vscode.parser.jpql
|
||||
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar Hql.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode//parser/hql -package org.springframework.ide.vscode.parser.hql
|
||||
|
||||
1094
headless-services/commons/jpql/grammars/Hql.g4
Normal file
1094
headless-services/commons/jpql/grammars/Hql.g4
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
// Generated from Jpql.g4 by ANTLR 4.13.1
|
||||
package org.springframework.ide.vscode.jpql.antlr.parser;
|
||||
package org.springframework.ide.vscode.parser.jpql;
|
||||
|
||||
/**
|
||||
* JPQL per https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1.html#bnf
|
||||
@@ -1,5 +1,5 @@
|
||||
// Generated from Jpql.g4 by ANTLR 4.13.1
|
||||
package org.springframework.ide.vscode.jpql.antlr.parser;
|
||||
package org.springframework.ide.vscode.parser.jpql;
|
||||
|
||||
/**
|
||||
* JPQL per https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1.html#bnf
|
||||
@@ -1,5 +1,5 @@
|
||||
// Generated from Jpql.g4 by ANTLR 4.13.1
|
||||
package org.springframework.ide.vscode.jpql.antlr.parser;
|
||||
package org.springframework.ide.vscode.parser.jpql;
|
||||
|
||||
/**
|
||||
* JPQL per https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1.html#bnf
|
||||
@@ -1,5 +1,5 @@
|
||||
// Generated from Jpql.g4 by ANTLR 4.13.1
|
||||
package org.springframework.ide.vscode.jpql.antlr.parser;
|
||||
package org.springframework.ide.vscode.parser.jpql;
|
||||
|
||||
/**
|
||||
* JPQL per https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1.html#bnf
|
||||
@@ -0,0 +1,133 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.ErrorNode;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokensDataProvider;
|
||||
import org.springframework.ide.vscode.parser.hql.HqlBaseListener;
|
||||
import org.springframework.ide.vscode.parser.hql.HqlLexer;
|
||||
import org.springframework.ide.vscode.parser.hql.HqlParser;
|
||||
import org.springframework.ide.vscode.parser.hql.HqlParser.EntityNameContext;
|
||||
import org.springframework.ide.vscode.parser.hql.HqlParser.SimplePathElementContext;
|
||||
|
||||
public class HqlSemanticTokens implements SemanticTokensDataProvider {
|
||||
|
||||
private static List<String> TOKEN_TYPES = List.of("keyword", "type", "class", "string", "number", "operator",
|
||||
"variable", "method", "modifier", "regexp");
|
||||
|
||||
@Override
|
||||
public List<String> getTokenTypes() {
|
||||
return TOKEN_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
|
||||
List<SemanticTokenData> tokens = new ArrayList<>();
|
||||
HqlLexer lexer = new HqlLexer(CharStreams.fromString(text));
|
||||
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
|
||||
HqlParser parser = new HqlParser(antlrTokens);
|
||||
LinkedHashSet<Token> coloredTokens = new LinkedHashSet<>();
|
||||
|
||||
Stack<SimplePathElementContext> pathContexts = new Stack<>();
|
||||
|
||||
parser.addParseListener(new HqlBaseListener() {
|
||||
|
||||
private void addToken(Token token, String tokenType) {
|
||||
tokens.add(new SemanticTokenData(token.getStartIndex() + initialOffset,
|
||||
token.getStartIndex() + token.getText().length() + initialOffset, tokenType, new String[0]));
|
||||
coloredTokens.add(token);
|
||||
}
|
||||
|
||||
private void processTerminalNode(TerminalNode node) {
|
||||
if (coloredTokens.contains(node.getSymbol())) {
|
||||
return;
|
||||
}
|
||||
int type = node.getSymbol().getType();
|
||||
switch (type) {
|
||||
case HqlParser.STRINGLITERAL:
|
||||
case HqlParser.CHARACTER:
|
||||
addToken(node.getSymbol(), "string");
|
||||
break;
|
||||
case HqlParser.HEXLITERAL:
|
||||
case HqlParser.INTEGER_LITERAL:
|
||||
case HqlParser.FLOAT_LITERAL:
|
||||
case HqlParser.BINARY_LITERAL:
|
||||
addToken(node.getSymbol(), "number");
|
||||
break;
|
||||
case HqlParser.IDENTIFICATION_VARIABLE:
|
||||
if (pathContexts.isEmpty()) {
|
||||
addToken(node.getSymbol(), "variable");
|
||||
} else {
|
||||
addToken(node.getSymbol(), "method");
|
||||
}
|
||||
break;
|
||||
case HqlParser.JAVASTRINGLITERAL:
|
||||
addToken(node.getSymbol(), "class");
|
||||
break;
|
||||
case HqlParser.WS:
|
||||
break;
|
||||
// case JpqlParser.SPEL:
|
||||
// addToken(node.getSymbol(), "regexp");
|
||||
// break;
|
||||
default:
|
||||
if (HqlParser.WS < type && type <= HqlParser.YEAR) {
|
||||
addToken(node.getSymbol(), "keyword");
|
||||
} else {
|
||||
addToken(node.getSymbol(), "modifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTerminal(TerminalNode node) {
|
||||
processTerminalNode(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitErrorNode(ErrorNode node) {
|
||||
processTerminalNode(node);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void enterEntityName(EntityNameContext ctx) {
|
||||
addToken(ctx.getStart(), "class");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void enterSimplePathElement(SimplePathElementContext ctx) {
|
||||
pathContexts.push(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSimplePathElement(SimplePathElementContext ctx) {
|
||||
pathContexts.pop();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
parser.ql_statement();
|
||||
return tokens;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,14 +21,14 @@ import org.antlr.v4.runtime.tree.ErrorNode;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokensDataProvider;
|
||||
import org.springframework.ide.vscode.jpql.antlr.parser.JpqlBaseListener;
|
||||
import org.springframework.ide.vscode.jpql.antlr.parser.JpqlLexer;
|
||||
import org.springframework.ide.vscode.jpql.antlr.parser.JpqlParser;
|
||||
import org.springframework.ide.vscode.jpql.antlr.parser.JpqlParser.Collection_valued_fieldContext;
|
||||
import org.springframework.ide.vscode.jpql.antlr.parser.JpqlParser.Entity_nameContext;
|
||||
import org.springframework.ide.vscode.jpql.antlr.parser.JpqlParser.Entity_type_literalContext;
|
||||
import org.springframework.ide.vscode.jpql.antlr.parser.JpqlParser.Single_valued_object_fieldContext;
|
||||
import org.springframework.ide.vscode.jpql.antlr.parser.JpqlParser.State_fieldContext;
|
||||
import org.springframework.ide.vscode.parser.jpql.JpqlBaseListener;
|
||||
import org.springframework.ide.vscode.parser.jpql.JpqlLexer;
|
||||
import org.springframework.ide.vscode.parser.jpql.JpqlParser;
|
||||
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Collection_valued_fieldContext;
|
||||
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Entity_nameContext;
|
||||
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Entity_type_literalContext;
|
||||
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Single_valued_object_fieldContext;
|
||||
import org.springframework.ide.vscode.parser.jpql.JpqlParser.State_fieldContext;
|
||||
|
||||
public class JpqlSemanticTokens implements SemanticTokensDataProvider {
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
|
||||
|
||||
public class HqlSemanticTokensTest {
|
||||
|
||||
private HqlSemanticTokens provider = new HqlSemanticTokens();
|
||||
|
||||
@Test
|
||||
void simpleQuery_1() {
|
||||
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner", 0);
|
||||
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
|
||||
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 12, "variable", new String[0]));
|
||||
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(13, 17, "keyword", new String[0]));
|
||||
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(18, 23, "class", new String[0]));
|
||||
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(24, 29, "variable", new String[0]));
|
||||
|
||||
assertThat(tokens.size()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void initialOffset() {
|
||||
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner", 3);
|
||||
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(3, 9, "keyword", new String[0]));
|
||||
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(10, 15, "variable", new String[0]));
|
||||
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(16, 20, "keyword", new String[0]));
|
||||
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(21, 26, "class", new String[0]));
|
||||
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(27, 32, "variable", new String[0]));
|
||||
|
||||
assertThat(tokens.size()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void query_with_conflicting_groupby() {
|
||||
List<SemanticTokenData> tokens = provider.computeTokens("SELECT g FROM Group g GROUP BY g.name", 0);
|
||||
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
|
||||
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 8, "variable", new String[0]));
|
||||
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(9, 13, "keyword", new String[0]));
|
||||
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(14, 19, "class", new String[0]));
|
||||
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(20, 21, "variable", new String[0]));
|
||||
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(22, 27, "keyword", new String[0]));
|
||||
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(28, 30, "keyword", new String[0]));
|
||||
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(31, 32, "variable", new String[0]));
|
||||
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(32, 33, "modifier", new String[0]));
|
||||
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(33, 37, "method", new String[0]));
|
||||
|
||||
assertThat(tokens.size()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void query_with_parameter() {
|
||||
List<SemanticTokenData> tokens = provider.computeTokens("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :lastName%", 0);
|
||||
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0])); // SELECT
|
||||
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 15, "keyword", new String[0])); // DISTINCT
|
||||
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(16, 21, "variable", new String[0])); // owner
|
||||
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(22, 26, "keyword", new String[0])); // FROM
|
||||
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(27, 32, "class", new String[0])); // Owner
|
||||
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(33, 38, "variable", new String[0])); // owner
|
||||
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(39, 43, "keyword", new String[0])); // left
|
||||
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(44, 48, "keyword", new String[0])); // join
|
||||
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(50, 55, "variable", new String[0])); // owner
|
||||
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(55, 56, "modifier", new String[0])); // .
|
||||
assertThat(tokens.get(10)).isEqualTo(new SemanticTokenData(56, 60, "method", new String[0])); // pets
|
||||
assertThat(tokens.get(11)).isEqualTo(new SemanticTokenData(61, 66, "keyword", new String[0])); // WHERE
|
||||
assertThat(tokens.get(12)).isEqualTo(new SemanticTokenData(67, 72, "variable", new String[0])); // owner
|
||||
assertThat(tokens.get(13)).isEqualTo(new SemanticTokenData(72, 73, "modifier", new String[0])); // .
|
||||
assertThat(tokens.get(14)).isEqualTo(new SemanticTokenData(73, 81, "method", new String[0])); // lastName
|
||||
assertThat(tokens.get(15)).isEqualTo(new SemanticTokenData(82, 86, "keyword", new String[0])); // LIKE
|
||||
assertThat(tokens.get(16)).isEqualTo(new SemanticTokenData(87, 88, "modifier", new String[0])); // :
|
||||
assertThat(tokens.get(17)).isEqualTo(new SemanticTokenData(88, 96, "variable", new String[0])); // lastName
|
||||
assertThat(tokens.get(18)).isEqualTo(new SemanticTokenData(96, 97, "modifier", new String[0])); // lastName
|
||||
|
||||
assertThat(tokens.size()).isEqualTo(19);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user