Skip to content

Commit

Permalink
SPEL syntax highlighting and validation
Browse files Browse the repository at this point in the history
  • Loading branch information
BoykoAlex committed Jun 12, 2024
1 parent c482135 commit 15f20b6
Show file tree
Hide file tree
Showing 44 changed files with 19,124 additions and 14,151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ public class Constants {

public static final String PREF_SCAN_JAVA_TEST_SOURCES = "boot-java.scan-java-test-sources";

public static final String PREF_VALIDATION_SPEL_EXPRESSIONS = "boot-java.validation.spel.on";

public static final String PREF_SUPPORT_SPRING_XML_CONFIGS = "boot-java.support-spring-xml-config.on";
public static final String PREF_XML_CONFIGS_SCAN_FOLDERS = "boot-java.support-spring-xml-config.scan-folders-globs";
public static final String PREF_XML_CONFIGS_HYPERLINKS = "boot-java.support-spring-xml-config.hyperlinks";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ private void sendConfiguration() {
Map<String, Object> bootChangeDetection = new HashMap<>();
Map<String, Object> scanTestJavaSources = new HashMap<>();
Map<String, Object> validation = new HashMap<>();
Map<String, Object> validationSpelExpressions = new HashMap<>();
Map<String, Object> javaValidation = new HashMap<>();

IPreferenceStore preferenceStore = BootLanguageServerPlugin.getDefault().getPreferenceStore();
Expand All @@ -202,8 +201,6 @@ private void sendConfiguration() {
scanTestJavaSources.put("on", preferenceStore.getBoolean(Constants.PREF_SCAN_JAVA_TEST_SOURCES));

javaValidation.put("reconcilers", preferenceStore.getBoolean(Constants.PREF_JAVA_RECONCILE));
validationSpelExpressions.put("on", preferenceStore.getBoolean(Constants.PREF_VALIDATION_SPEL_EXPRESSIONS));
validation.put("spel", validationSpelExpressions);
validation.put("java", javaValidation);

bootJavaObj.put("jpql", preferenceStore.getBoolean(Constants.PREF_JPQL));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ public void initializeDefaultPreferences() {
preferenceStore.setDefault(Constants.PREF_XML_CONFIGS_SCAN_FOLDERS, "src/main");

preferenceStore.setDefault(Constants.PREF_CHANGE_DETECTION, false);
preferenceStore.setDefault(Constants.PREF_VALIDATION_SPEL_EXPRESSIONS, true);

preferenceStore.setDefault(Constants.PREF_SCAN_JAVA_TEST_SOURCES, false);

Expand Down
4 changes: 4 additions & 0 deletions headless-services/commons/jpql/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@
/src/main/java/org/springframework/ide/vscode/parser/sql/MySqlParser.tokens
/src/main/java/org/springframework/ide/vscode/parser/sql/MySqlLexer.interp
/src/main/java/org/springframework/ide/vscode/parser/sql/MySqlLexer.tokens
/src/main/java/org/springframework/ide/vscode/parser/spel/SpelParser.interp
/src/main/java/org/springframework/ide/vscode/parser/spel/SpelParser.tokens
/src/main/java/org/springframework/ide/vscode/parser/spel/SpelLexer.interp
/src/main/java/org/springframework/ide/vscode/parser/spel/SpelLexer.tokens
/target
1 change: 1 addition & 0 deletions headless-services/commons/jpql/generate-parsers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ cd grammars
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
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar MySqlLexer.g4 MySqlParser.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode/parser/sql -package org.springframework.ide.vscode.parser.sql
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar SpelLexer.g4 SpelParser.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode/parser/spel -package org.springframework.ide.vscode.parser.spel

6 changes: 4 additions & 2 deletions headless-services/commons/jpql/grammars/MySqlLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ channels {
ERRORCHANNEL
}

SPEL : ('#')('{')(.)*?('}') ;

// SKIP

SPACE : [ \t\r\n]+ -> channel(HIDDEN);
Expand Down Expand Up @@ -1251,6 +1249,8 @@ DOUBLE_QUOTE_SYMB : '"';
REVERSE_QUOTE_SYMB : '`';
COLON_SYMB : ':';

QUESTION_SYMB : '?';

fragment QUOTE_SYMB: SINGLE_QUOTE_SYMB | DOUBLE_QUOTE_SYMB | REVERSE_QUOTE_SYMB;

// Charsets
Expand Down Expand Up @@ -1293,6 +1293,8 @@ HOST_IP_ADDRESS : (AT_SIGN IP_ADDRESS);
LOCAL_ID : AT_SIGN ( STRING_LITERAL | [A-Z0-9._$\u0080-\uFFFF]+);
GLOBAL_ID : AT_SIGN AT_SIGN ( [A-Z0-9._$\u0080-\uFFFF]+ | BQUOTA_STRING);

SPEL : ('#')('{')(.)*?('}') ;

// Fragments for Literal primitives

fragment CHARSET_NAME:
Expand Down
4 changes: 2 additions & 2 deletions headless-services/commons/jpql/grammars/MySqlParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -2544,15 +2544,15 @@ predicate

// Add in ASTVisitor nullNotnull in constant
expressionAtom
: constant # constantExpressionAtom
: (QUESTION_SYMB | COLON_SYMB) SPEL # spelExpressionAtom
| constant # constantExpressionAtom
| fullColumnName # fullColumnNameExpressionAtom
| functionCall # functionCallExpressionAtom
| expressionAtom COLLATE collationName # collateExpressionAtom
| mysqlVariable # mysqlVariableExpressionAtom
| unaryOperator expressionAtom # unaryExpressionAtom
| BINARY expressionAtom # binaryExpressionAtom
| LOCAL_ID VAR_ASSIGN expressionAtom # variableAssignExpressionAtom
| SPEL # spelExpressionAtom
| '(' expression (',' expression)* ')' # nestedExpressionAtom
| ROW '(' expression (',' expression)+ ')' # nestedRowExpressionAtom
| EXISTS '(' selectStatement ')' # existsExpressionAtom
Expand Down
193 changes: 193 additions & 0 deletions headless-services/commons/jpql/grammars/SpelLexer.g4
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*******************************************************************************
* 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
*******************************************************************************/

lexer grammar SpelLexer;

@header {
/*******************************************************************************
* 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
*******************************************************************************/
}

@members {
int nesting = 0;
}

SEMICOLON: ';';

fragment NEWLINE
: '\r\n'
| [\r\n\u2028\u2029]
;

WS
: [ \t\r\n]+ -> channel(HIDDEN)
;

// ========================== S P E L ====================================================

INC: '++';
PLUS: '+';
DEC: '--';
MINUS: '-';
COLON: ':';
DOT: '.';
COMMA: ',';
STAR: '*';
DIV: '/';
MOD: '%';
LPAREN: '(';
RPAREN: ')';
LSQUARE: '[';
RSQUARE: ']';
HASH: '#';
BEAN_REF: '@';
SELECT_FIRST: '^[';
POWER: '^';
NE: '!=';
PROJECT: '![';
NOT: '!';
EQ: '==';
ASSIGN: '=';
SYMBOLIC_AND: '&&';
FACTORY_BEAN_REF: '&';
SYMBOLIC_OR: '||';
SELECT: '?[';
ELVIS: '?:';
SAFE_NAVI: '?.';
QMARK: '?';
SELECT_LAST: '$[';
GE: '>=';
GT: '>';
LE: '<=';
LT: '<';

// Special treatment to support template literals
LCURLY: '{' { nesting++; } -> pushMode(DEFAULT_MODE);

RCURLY: '}' {
if (nesting > 0) {
nesting--;
}
} -> popMode;

BACKTICK
: '`' -> pushMode(IN_TEMPLATE_STRING)
;






OR: 'or';
AND: 'and';

TRUE: 'true';
FALSE: 'false';
NEW: 'new';
NULL: 'null';
T: 'T';
MATCHES: 'matches';
GT_KEYWORD: 'gt';
GE_KEYWORD: 'ge';
LE_KEYWORD: 'le';
LT_KEYWORD: 'lt';
EQ_KEYWORD: 'eq';
NE_KEYWORD: 'ne';

// IDENTIFIER appearing AFTER tokens like OR and AND make those lex as special tokens,
// like SpEL's lexIdentifier() does
IDENTIFIER
: (ALPHABETIC | '_') (ALPHABETIC | DIGIT | '_' | '$')*
;

NUMERIC_LITERAL
: REAL_LITERAL
| INTEGER_LITERAL
;


REAL_LITERAL
: '.' DECIMAL_DIGIT+ EXPONENT_PART? REAL_TYPE_SUFFIX?
| DECIMAL_DIGIT+ '.' DECIMAL_DIGIT+ EXPONENT_PART? REAL_TYPE_SUFFIX?
| DECIMAL_DIGIT+ EXPONENT_PART REAL_TYPE_SUFFIX?
| DECIMAL_DIGIT+ REAL_TYPE_SUFFIX
;

INTEGER_LITERAL
: DECIMAL_DIGIT+ INTEGER_TYPE_SUFFIX?
;

STRING_LITERAL
: SINGLE_QUOTED_STRING
| DOUBLE_QUOTED_STRING
;

SINGLE_QUOTED_STRING
: '\'' ( '\'\'' | ~['\n] )* '\''
;

DOUBLE_QUOTED_STRING
: '"' ( '""' | ~["\n] )* '"'
;
fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' );
fragment HEX_DIGIT : [0-9A-Fa-f];
fragment DECIMAL_DIGIT: [0-9];
fragment EXPONENT_PART
: 'e' (SIGN)* (DECIMAL_DIGIT)+
| 'E' (SIGN)* (DECIMAL_DIGIT)+
;
fragment SIGN : '+' | '-' ;
fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd';
fragment ALPHABETIC
// See Character.isLetter()
// and https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md#lexer-rule-elements
// and https://github.com/spring-projects/spring-framework/commit/c8c8f5722bc58452894742534954c0935653771f
: [\p{Lu}] // UPPERCASE_LETTER
| [\p{Ll}] // LOWERCASE_LETTER
| [\p{Lt}] // TITLECASE_LETTER
| [\p{Lm}] // MODIFIER_LETTER
| [\p{Lo}] // OTHER_LETTER
;
fragment DIGIT
: [0-9]
;
mode IN_TEMPLATE_STRING;
ESCAPED_BACKTICK
: '``'
;
SPEL_IN_TEMPLATE_STRING_OPEN: '#{' { nesting++; } -> pushMode(DEFAULT_MODE);
TEMPLATE_TEXT
: ~[`\n]
;
BACKTICK_IN_TEMPLATE
: '`' -> type(BACKTICK), popMode
;
Loading

0 comments on commit 15f20b6

Please sign in to comment.