diff --git a/.gitignore b/.gitignore
index 191a0a5a7..e988c9d64 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ out/
/.idea/misc.xml
/.gradle
/build
+/src/main/gen
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 58d1b1919..02795a8e5 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -13,6 +13,8 @@ plugins {
id("org.jetbrains.changelog") version "1.3.1"
// Gradle Qodana Plugin
id("org.jetbrains.qodana") version "0.1.13"
+ // Gradle Grammar-Kit Plugin
+ id("org.jetbrains.grammarkit") version "2021.2.2"
}
group = properties("pluginGroup")
@@ -112,4 +114,29 @@ tasks {
includeEngines("junit-vintage")
}
}
+
+ generateLexer {
+ source.set("src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.flex")
+ targetDir.set("src/main/gen/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/")
+ targetClass.set("ExpressionLanguageLexer")
+ purgeOldFiles.set(true)
+ }
+
+ generateParser {
+ source.set("src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.bnf")
+ targetRoot.set("src/main/gen")
+ pathToParser.set("fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageParser.java")
+ pathToPsiRoot.set("fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi")
+ purgeOldFiles.set(true)
+ }
+
+ compileJava {
+ dependsOn("generateLexer")
+ dependsOn("generateParser")
+ }
}
+
+java.sourceSets["main"].java {
+ // Include the generated files in the source set
+ srcDir("src/main/gen")
+}
\ No newline at end of file
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/xml/XmlLanguageInjector.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/xml/XmlLanguageInjector.java
new file mode 100644
index 000000000..3e4ff8ad5
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/xml/XmlLanguageInjector.java
@@ -0,0 +1,87 @@
+package fr.adrienbrault.idea.symfony2plugin.config.xml;
+
+import com.intellij.lang.injection.MultiHostInjector;
+import com.intellij.lang.injection.MultiHostRegistrar;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.patterns.XmlElementPattern;
+import com.intellij.patterns.XmlPatterns;
+import com.intellij.psi.ElementManipulators;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiLanguageInjectionHost;
+import com.intellij.psi.xml.XmlText;
+import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguage;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.List;
+
+public class XmlLanguageInjector implements MultiHostInjector {
+
+ @Override
+ public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
+ if (!Symfony2ProjectComponent.isEnabled(context.getProject())) {
+ return;
+ }
+
+ if (isExpressionLanguageString(context)) {
+ registrar
+ .startInjecting(ExpressionLanguage.INSTANCE)
+ .addPlace(null, null, (PsiLanguageInjectionHost) context, ElementManipulators.getValueTextRange(context))
+ .doneInjecting();
+ }
+ }
+
+ @Override
+ public @NotNull List extends Class extends PsiElement>> elementsToInjectIn() {
+ return Collections.singletonList(XmlText.class);
+ }
+
+ private boolean isExpressionLanguageString(@NotNull PsiElement element) {
+ return PlatformPatterns.or(
+ getExpressionArgumentPattern(),
+ getRouteConditionPattern()
+ ).accepts(element);
+ }
+
+ /**
+ * container.get('service_id')
+ */
+ private XmlElementPattern.XmlTextPattern getExpressionArgumentPattern() {
+ return XmlPatterns
+ .xmlText()
+ .withParent(XmlPatterns
+ .xmlTag()
+ .withName("argument")
+ .withAttributeValue("type", "expression")
+ )
+ .inside(
+ XmlHelper.getInsideTagPattern("services")
+ ).inFile(XmlHelper.getXmlFilePattern());
+ }
+
+ /**
+ *
+ *
+ * context.getMethod() in ['GET', 'HEAD']
+ *
+ *
+ */
+ private XmlElementPattern.XmlTextPattern getRouteConditionPattern() {
+ return XmlPatterns
+ .xmlText()
+ .withParent(XmlPatterns
+ .xmlTag()
+ .withName("condition")
+ .withParent(XmlPatterns
+ .xmlTag()
+ .withName("route")
+ .withParent(XmlPatterns
+ .xmlTag()
+ .withName("routes")
+ )
+ )
+ )
+ .inFile(XmlHelper.getXmlFilePattern());
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlLanguageInjector.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlLanguageInjector.java
new file mode 100644
index 000000000..9603ca17d
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/config/yaml/YamlLanguageInjector.java
@@ -0,0 +1,79 @@
+package fr.adrienbrault.idea.symfony2plugin.config.yaml;
+
+import com.intellij.lang.injection.MultiHostInjector;
+import com.intellij.lang.injection.MultiHostRegistrar;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.psi.ElementManipulators;
+import com.intellij.psi.PsiElement;
+import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguage;
+import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.yaml.psi.YAMLPsiElement;
+import org.jetbrains.yaml.psi.YAMLQuotedText;
+
+import java.util.Collections;
+import java.util.List;
+
+public class YamlLanguageInjector implements MultiHostInjector {
+
+ private static final String EXPRESSION_LANGUAGE_PREFIX = "@=";
+
+ @Override
+ public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
+ if (!Symfony2ProjectComponent.isEnabled(context.getProject())) {
+ return;
+ }
+
+ if (!(context instanceof YAMLQuotedText)) {
+ return;
+ }
+
+ var file = context.getContainingFile();
+ if (file == null) {
+ return;
+ }
+
+ var element = (YAMLQuotedText) context;
+ var value = element.getTextValue();
+
+ if (YamlHelper.isServicesFile(file) && isExpressionLanguageString(value) && isExpressionLanguageStringAllowed(element)) {
+ registrar
+ .startInjecting(ExpressionLanguage.INSTANCE)
+ .addPlace(null, null, element, getExpressionLanguageTextRange(value))
+ .doneInjecting();
+ } else if (YamlHelper.isRoutingFile(file) && isInsideRouteConditionKey(element)) {
+ registrar
+ .startInjecting(ExpressionLanguage.INSTANCE)
+ .addPlace(null, null, element, ElementManipulators.getValueTextRange(element))
+ .doneInjecting();
+ }
+ }
+
+ @NotNull
+ @Override
+ public List extends Class extends PsiElement>> elementsToInjectIn() {
+ return Collections.singletonList(YAMLQuotedText.class);
+ }
+
+ private boolean isExpressionLanguageString(@NotNull String str) {
+ return str.startsWith(EXPRESSION_LANGUAGE_PREFIX) && str.length() > EXPRESSION_LANGUAGE_PREFIX.length();
+ }
+
+ private boolean isExpressionLanguageStringAllowed(@NotNull YAMLPsiElement element) {
+ return PlatformPatterns.and(
+ YamlElementPatternHelper.getInsideKeyValue("services"),
+ YamlElementPatternHelper.getInsideKeyValue("arguments", "properties", "calls", "configurator")
+ ).accepts(element);
+ }
+
+ @NotNull
+ private TextRange getExpressionLanguageTextRange(@NotNull String str) {
+ return new TextRange(EXPRESSION_LANGUAGE_PREFIX.length() + 1, str.length() + 1);
+ }
+
+ private boolean isInsideRouteConditionKey(@NotNull YAMLPsiElement element) {
+ return YamlElementPatternHelper.getInsideKeyValue("condition").accepts(element);
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.bnf b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.bnf
new file mode 100644
index 000000000..13469b157
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.bnf
@@ -0,0 +1,154 @@
+{
+ parserClass="fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguageParser"
+
+ extends="com.intellij.extapi.psi.ASTWrapperPsiElement"
+
+ psiClassPrefix="ExpressionLanguage"
+ psiImplClassSuffix="Impl"
+ psiPackage="fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi"
+ psiImplPackage="fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.impl"
+
+ elementTypeHolderClass="fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageTypes"
+ elementTypeClass="fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageElementType"
+ tokenTypeClass="fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageTokenType"
+
+ extends(".*expr")=expr
+ tokens=[
+ space='regexp:\s+'
+ number='regexp:\d+(\.\d*)?([Ee][+\-]\d+)?'
+ null="regexp:NULL|null"
+ true="regexp:TRUE|true"
+ false="regexp:FALSE|false"
+ id='regexp:\p{Alpha}\w*'
+ string="regexp:('([^'\\]|\\.)*'|\"([^\"\\]|\\.)*\")"
+ OP_OR="||"
+ OP_OR_KW="or"
+ OP_AND="&&"
+ OP_AND_KW="and"
+ OP_BIT_OR="|"
+ OP_BIT_XOR="^"
+ OP_BIT_AND="&"
+ OP_IDENTICAL="==="
+ OP_EQ="=="
+ OP_NOT_IDENTICAL="!=="
+ OP_NEQ="!="
+ OP_LT="<"
+ OP_GT=">"
+ OP_GTE=">="
+ OP_LTE="<="
+ OP_NOT_IN="not in"
+ OP_IN="in"
+ OP_MATCHES="matches"
+ OP_RANGE=".."
+ OP_PLUS="+"
+ OP_MINUS="-"
+ OP_CONCAT="~"
+ OP_MUL="*"
+ OP_DIV="/"
+ OP_MOD="%"
+ OP_POW="**"
+ OP_NOT='!'
+ OP_NOT_KW='not'
+
+ L_ROUND_BRACKET="("
+ R_ROUND_BRACKET=")"
+ L_CURLY_BRACKET="{"
+ R_CURLY_BRACKET="}"
+ L_SQUARE_BRACKET="["
+ R_SQUARE_BRACKET="]"
+
+ syntax='regexp:[?:.,]'
+ ]
+}
+
+root ::= expr
+
+expr ::= ternary_group
+ | or_expr
+ | and_expr
+ | bit_or_expr
+ | bit_xor_expr
+ | bit_and_expr
+ | rel_group
+ | range_expr
+ | add_group
+ | concat_expr
+ | mul_group
+ | not_expr
+ | exp_expr
+ | sign_group
+ | qualification_expr
+ | array_access_expr
+ | primary_group
+
+private sign_group ::= unary_plus_expr | unary_min_expr
+private mul_group ::= mul_expr | div_expr | mod_expr
+private add_group ::= plus_expr | minus_expr
+private ternary_group ::= elvis_expr | ternary_expr
+
+private rel_group ::= identical_expr
+ | eq_expr
+ | not_identical_expr
+ | neq_expr
+ | gte_expr
+ | gt_expr
+ | lt_expr
+ | lte_expr
+ | not_in_expr
+ | in_expr
+ | matches_expr
+
+private primary_group ::= simple_ref_expr | literal_expr | array_expr | hash_expr | call_expr | paren_expr
+
+not_expr ::= (OP_NOT|OP_NOT_KW) expr
+unary_min_expr ::= OP_MINUS expr
+unary_plus_expr ::= OP_PLUS expr
+div_expr ::= expr OP_DIV expr
+mul_expr ::= expr OP_MUL expr
+mod_expr ::= expr OP_MOD expr
+concat_expr ::= expr OP_CONCAT expr
+minus_expr ::= expr OP_MINUS expr
+plus_expr ::= expr OP_PLUS expr
+range_expr ::= expr OP_RANGE expr
+identical_expr ::= expr OP_IDENTICAL expr
+not_identical_expr ::= expr OP_NOT_IDENTICAL expr
+eq_expr ::= expr OP_EQ expr
+neq_expr ::= expr OP_NEQ expr
+gt_expr ::= expr OP_GT expr
+gte_expr ::= expr OP_GTE expr
+lt_expr ::= expr OP_LT expr
+lte_expr ::= expr OP_LTE expr
+not_in_expr ::= expr OP_NOT_IN expr
+in_expr ::= expr OP_IN expr
+matches_expr ::= expr OP_MATCHES expr
+or_expr ::= expr (OP_OR|OP_OR_KW) expr
+and_expr ::= expr (OP_AND|OP_AND_KW) expr
+bit_and_expr ::= expr OP_BIT_AND expr
+bit_or_expr ::= expr OP_BIT_OR expr
+bit_xor_expr ::= expr OP_BIT_XOR expr
+exp_expr ::= expr (OP_POW expr)+
+paren_expr ::= L_ROUND_BRACKET expr R_ROUND_BRACKET
+ternary_expr ::= expr '?' expr (':' expr)?
+elvis_expr ::= expr '?:' expr
+
+fake ref_expr ::= expr? '.' identifier
+simple_ref_expr ::= identifier {extends=ref_expr elementType=ref_expr}
+qualification_expr ::= expr '.' identifier {extends=ref_expr elementType=ref_expr}
+array_access_expr ::= expr L_SQUARE_BRACKET expr R_SQUARE_BRACKET {extends=ref_expr elementType=ref_expr}
+
+literal_expr ::= number_literal | string_literal | boolean_literal | null_literal
+string_literal ::= string
+number_literal ::= number
+boolean_literal ::= true | false
+null_literal ::= null
+
+array_expr ::= L_SQUARE_BRACKET expr_list? R_SQUARE_BRACKET
+hash_expr ::= L_CURLY_BRACKET hash_entries? R_CURLY_BRACKET
+
+call_expr ::= expr L_ROUND_BRACKET expr_list? R_ROUND_BRACKET
+
+private hash_entries ::= hash_entry (',' hash_entry)*
+private hash_entry ::= identifier ':' expr
+private expr_list ::= expr (',' expr_list)*
+
+identifier ::= id
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.flex b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.flex
new file mode 100644
index 000000000..b3755c8cc
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.flex
@@ -0,0 +1,86 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.tree.IElementType;
+
+import static com.intellij.psi.TokenType.BAD_CHARACTER;
+import static com.intellij.psi.TokenType.WHITE_SPACE;
+import static fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageTypes.*;
+
+%%
+
+%{
+ public ExpressionLanguageLexer() {
+ this((java.io.Reader)null);
+ }
+%}
+
+%public
+%class ExpressionLanguageLexer
+%implements FlexLexer
+%function advance
+%type IElementType
+%unicode
+
+WHITE_SPACE=\s+
+
+SPACE=[ \t\n\x0B\f\r]+
+NUMBER=[0-9]+(\.[0-9]*)?([Ee][+\-][0-9]+)?
+NULL=NULL|null
+TRUE=TRUE|true
+FALSE=FALSE|false
+ID=[:letter:][a-zA-Z_0-9]*
+STRING=('([^'\\]|\\.)*'|\"([^\"\\]|\\.)*\")
+SYNTAX=[?:.,]
+
+%%
+ {
+ {WHITE_SPACE} { return WHITE_SPACE; }
+
+ "||" { return OP_OR; }
+ "or" { return OP_OR_KW; }
+ "&&" { return OP_AND; }
+ "and" { return OP_AND_KW; }
+ "|" { return OP_BIT_OR; }
+ "^" { return OP_BIT_XOR; }
+ "&" { return OP_BIT_AND; }
+ "===" { return OP_IDENTICAL; }
+ "==" { return OP_EQ; }
+ "!==" { return OP_NOT_IDENTICAL; }
+ "!=" { return OP_NEQ; }
+ "<" { return OP_LT; }
+ ">" { return OP_GT; }
+ ">=" { return OP_GTE; }
+ "<=" { return OP_LTE; }
+ "not in" { return OP_NOT_IN; }
+ "in" { return OP_IN; }
+ "matches" { return OP_MATCHES; }
+ ".." { return OP_RANGE; }
+ "+" { return OP_PLUS; }
+ "-" { return OP_MINUS; }
+ "~" { return OP_CONCAT; }
+ "*" { return OP_MUL; }
+ "/" { return OP_DIV; }
+ "%" { return OP_MOD; }
+ "**" { return OP_POW; }
+ "!" { return OP_NOT; }
+ "not" { return OP_NOT_KW; }
+ "(" { return L_ROUND_BRACKET; }
+ ")" { return R_ROUND_BRACKET; }
+ "{" { return L_CURLY_BRACKET; }
+ "}" { return R_CURLY_BRACKET; }
+ "[" { return L_SQUARE_BRACKET; }
+ "]" { return R_SQUARE_BRACKET; }
+
+ {SPACE} { return SPACE; }
+ {NUMBER} { return NUMBER; }
+ {NULL} { return NULL; }
+ {TRUE} { return TRUE; }
+ {FALSE} { return FALSE; }
+ {ID} { return ID; }
+ {STRING} { return STRING; }
+ {SYNTAX} { return SYNTAX; }
+
+}
+
+[^] { return BAD_CHARACTER; }
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.java
new file mode 100644
index 000000000..85a41c250
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguage.java
@@ -0,0 +1,12 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.lang.Language;
+
+public class ExpressionLanguage extends Language {
+
+ public static final ExpressionLanguage INSTANCE = new ExpressionLanguage();
+
+ private ExpressionLanguage() {
+ super("Symfony Expression Language");
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageBraceMatcher.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageBraceMatcher.java
new file mode 100644
index 000000000..1a663c409
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageBraceMatcher.java
@@ -0,0 +1,44 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.lang.BracePair;
+import com.intellij.lang.PairedBraceMatcher;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.tree.IElementType;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageTypes;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class ExpressionLanguageBraceMatcher implements PairedBraceMatcher {
+ private static BracePair[] PAIRS = {
+ new BracePair(
+ ExpressionLanguageTypes.L_ROUND_BRACKET,
+ ExpressionLanguageTypes.R_ROUND_BRACKET,
+ true
+ ),
+ new BracePair(
+ ExpressionLanguageTypes.L_SQUARE_BRACKET,
+ ExpressionLanguageTypes.R_SQUARE_BRACKET,
+ true
+ ),
+ new BracePair(
+ ExpressionLanguageTypes.L_CURLY_BRACKET,
+ ExpressionLanguageTypes.R_CURLY_BRACKET,
+ true
+ ),
+ };
+
+ @Override
+ public BracePair[] getPairs() {
+ return PAIRS;
+ }
+
+ @Override
+ public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) {
+ return false;
+ }
+
+ @Override
+ public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
+ return openingBraceOffset;
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageColorSettingsPage.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageColorSettingsPage.java
new file mode 100644
index 000000000..2b4c4cce6
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageColorSettingsPage.java
@@ -0,0 +1,66 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.options.colors.AttributesDescriptor;
+import com.intellij.openapi.options.colors.ColorDescriptor;
+import com.intellij.openapi.options.colors.ColorSettingsPage;
+import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Map;
+
+public class ExpressionLanguageColorSettingsPage implements ColorSettingsPage {
+
+ private static final AttributesDescriptor[] ATTRIBUTE_DESCRIPTORS = new AttributesDescriptor[]{
+ new AttributesDescriptor("Number", ExpressionLanguageSyntaxHighlighter.NUMBER),
+ new AttributesDescriptor("String", ExpressionLanguageSyntaxHighlighter.STRING),
+ new AttributesDescriptor("Identifier", ExpressionLanguageSyntaxHighlighter.IDENTIFIER),
+ new AttributesDescriptor("Keyword", ExpressionLanguageSyntaxHighlighter.KEYWORD),
+ };
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ return Symfony2Icons.SYMFONY;
+ }
+
+ @NotNull
+ @Override
+ public SyntaxHighlighter getHighlighter() {
+ return new ExpressionLanguageSyntaxHighlighter();
+ }
+
+ @NotNull
+ @Override
+ public String getDemoText() {
+ return "article.getCommentCount(true) > 100 and article.category not in [\"misc\", null, true] === false";
+ }
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return "Symfony Expression Language";
+ }
+
+ @NotNull
+ @Override
+ public AttributesDescriptor[] getAttributeDescriptors() {
+ return ATTRIBUTE_DESCRIPTORS;
+ }
+
+ @NotNull
+ @Override
+ public ColorDescriptor[] getColorDescriptors() {
+ return ColorDescriptor.EMPTY_ARRAY;
+ }
+
+ @Override
+ public @Nullable
+ Map getAdditionalHighlightingTagToDescriptorMap() {
+ return null;
+ }
+}
+
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageFileType.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageFileType.java
new file mode 100644
index 000000000..bf7d5b88b
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageFileType.java
@@ -0,0 +1,41 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class ExpressionLanguageFileType extends LanguageFileType {
+
+ public static final ExpressionLanguageFileType INSTANCE = new ExpressionLanguageFileType();
+
+ private ExpressionLanguageFileType() {
+ super(ExpressionLanguage.INSTANCE);
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return "Expression Language File";
+ }
+
+ @NotNull
+ @Override
+ public String getDescription() {
+ return "Expression Language file";
+ }
+
+ @NotNull
+ @Override
+ public String getDefaultExtension() {
+ return "sfel";
+ }
+
+ @Override
+ @Nullable
+ public Icon getIcon() {
+ return Symfony2Icons.SYMFONY;
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageLexerAdapter.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageLexerAdapter.java
new file mode 100644
index 000000000..6505ab5da
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageLexerAdapter.java
@@ -0,0 +1,9 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.lexer.FlexAdapter;
+
+public class ExpressionLanguageLexerAdapter extends FlexAdapter {
+ public ExpressionLanguageLexerAdapter() {
+ super(new ExpressionLanguageLexer());
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageParserDefinition.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageParserDefinition.java
new file mode 100644
index 000000000..b965dd39f
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageParserDefinition.java
@@ -0,0 +1,56 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.ParserDefinition;
+import com.intellij.lang.PsiParser;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.tree.IFileElementType;
+import com.intellij.psi.tree.TokenSet;
+
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageFile;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageTypes;
+import org.jetbrains.annotations.NotNull;
+
+public class ExpressionLanguageParserDefinition implements ParserDefinition {
+
+ public static final IFileElementType FILE = new IFileElementType(ExpressionLanguage.INSTANCE);
+
+ @Override
+ public @NotNull Lexer createLexer(Project project) {
+ return new ExpressionLanguageLexerAdapter();
+ }
+
+ @Override
+ public @NotNull PsiParser createParser(Project project) {
+ return new ExpressionLanguageParser();
+ }
+
+ @Override
+ public @NotNull IFileElementType getFileNodeType() {
+ return FILE;
+ }
+
+ @Override
+ public @NotNull TokenSet getCommentTokens() {
+ return TokenSet.EMPTY;
+ }
+
+ @Override
+ public @NotNull TokenSet getStringLiteralElements() {
+ return TokenSet.create(ExpressionLanguageTypes.STRING);
+ }
+
+ @Override
+ public @NotNull PsiElement createElement(ASTNode node) {
+ return ExpressionLanguageTypes.Factory.createElement(node);
+ }
+
+ @Override
+ public @NotNull PsiFile createFile(@NotNull FileViewProvider viewProvider) {
+ return new ExpressionLanguageFile(viewProvider);
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageQuoteHandler.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageQuoteHandler.java
new file mode 100644
index 000000000..6dde6bbed
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageQuoteHandler.java
@@ -0,0 +1,13 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler;
+import com.intellij.psi.TokenType;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageTypes;
+
+public class ExpressionLanguageQuoteHandler extends SimpleTokenSetQuoteHandler {
+
+ public ExpressionLanguageQuoteHandler() {
+ super(ExpressionLanguageTypes.STRING, TokenType.BAD_CHARACTER);
+ }
+
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageSyntaxHighlighter.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageSyntaxHighlighter.java
new file mode 100644
index 000000000..cb40e6248
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageSyntaxHighlighter.java
@@ -0,0 +1,63 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
+import com.intellij.psi.tree.IElementType;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageTypes;
+import org.jetbrains.annotations.NotNull;
+
+import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey;
+
+public class ExpressionLanguageSyntaxHighlighter extends SyntaxHighlighterBase {
+
+ public static final TextAttributesKey NUMBER = createTextAttributesKey("NUMBER", DefaultLanguageHighlighterColors.NUMBER);
+ public static final TextAttributesKey STRING = createTextAttributesKey("STRING", DefaultLanguageHighlighterColors.STRING);
+ public static final TextAttributesKey IDENTIFIER = createTextAttributesKey("IDENTIFIER", DefaultLanguageHighlighterColors.IDENTIFIER);
+ public static final TextAttributesKey KEYWORD = createTextAttributesKey("KEYWORD", DefaultLanguageHighlighterColors.KEYWORD);
+
+ private static final TextAttributesKey[] NUMBER_KEYS = new TextAttributesKey[]{NUMBER};
+ private static final TextAttributesKey[] STRING_KEYS = new TextAttributesKey[]{STRING};
+ private static final TextAttributesKey[] IDENTIFIER_KEYS = new TextAttributesKey[]{IDENTIFIER};
+ private static final TextAttributesKey[] KEYWORD_KEYS = new TextAttributesKey[]{KEYWORD};
+ private static final TextAttributesKey[] EMPTY_KEYS = new TextAttributesKey[0];
+
+ @NotNull
+ @Override
+ public Lexer getHighlightingLexer() {
+ return new ExpressionLanguageLexerAdapter();
+ }
+
+ @NotNull
+ @Override
+ public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
+ if (tokenType.equals(ExpressionLanguageTypes.NUMBER)) {
+ return NUMBER_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.STRING)) {
+ return STRING_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.ID)) {
+ return IDENTIFIER_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.TRUE)) {
+ return KEYWORD_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.FALSE)) {
+ return KEYWORD_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.NULL)) {
+ return KEYWORD_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.OP_IN)) {
+ return KEYWORD_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.OP_NOT_IN)) {
+ return KEYWORD_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.OP_MATCHES)) {
+ return KEYWORD_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.OP_AND_KW)) {
+ return KEYWORD_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.OP_OR_KW)) {
+ return KEYWORD_KEYS;
+ } else if (tokenType.equals(ExpressionLanguageTypes.OP_NOT_KW)) {
+ return KEYWORD_KEYS;
+ }
+
+ return EMPTY_KEYS;
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageSyntaxHighlighterFactory.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageSyntaxHighlighterFactory.java
new file mode 100644
index 000000000..1fb31364b
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/ExpressionLanguageSyntaxHighlighterFactory.java
@@ -0,0 +1,17 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage;
+
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class ExpressionLanguageSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
+
+ @NotNull
+ @Override
+ public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) {
+ return new ExpressionLanguageSyntaxHighlighter();
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageElementType.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageElementType.java
new file mode 100644
index 000000000..be49f0989
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageElementType.java
@@ -0,0 +1,12 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi;
+
+import com.intellij.psi.tree.IElementType;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguage;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class ExpressionLanguageElementType extends IElementType {
+ public ExpressionLanguageElementType(@NonNls @NotNull String debugName) {
+ super(debugName, ExpressionLanguage.INSTANCE);
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageFile.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageFile.java
new file mode 100644
index 000000000..a14089a61
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageFile.java
@@ -0,0 +1,25 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi;
+
+import com.intellij.extapi.psi.PsiFileBase;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.psi.FileViewProvider;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguage;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguageFileType;
+import org.jetbrains.annotations.NotNull;
+
+public class ExpressionLanguageFile extends PsiFileBase {
+
+ public ExpressionLanguageFile(@NotNull FileViewProvider viewProvider) {
+ super(viewProvider, ExpressionLanguage.INSTANCE);
+ }
+
+ @Override
+ public @NotNull FileType getFileType() {
+ return ExpressionLanguageFileType.INSTANCE;
+ }
+
+ @Override
+ public String toString() {
+ return "Expression Language File";
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageTokenType.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageTokenType.java
new file mode 100644
index 000000000..70b7aca73
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/expressionLanguage/psi/ExpressionLanguageTokenType.java
@@ -0,0 +1,18 @@
+package fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi;
+
+import com.intellij.psi.tree.IElementType;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguage;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class ExpressionLanguageTokenType extends IElementType {
+
+ public ExpressionLanguageTokenType(@NonNls @NotNull String debugName) {
+ super(debugName, ExpressionLanguage.INSTANCE);
+ }
+
+ @Override
+ public String toString() {
+ return " ExpressionLanguageType." + super.toString();
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/LanguageInjection.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/LanguageInjection.java
new file mode 100644
index 000000000..781de74cf
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/LanguageInjection.java
@@ -0,0 +1,114 @@
+package fr.adrienbrault.idea.symfony2plugin.lang;
+
+import com.intellij.lang.Language;
+import com.intellij.patterns.ElementPattern;
+import com.intellij.patterns.StandardPatterns;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class LanguageInjection {
+ @NotNull
+ private final String languageId;
+ @Nullable
+ private final String prefix;
+ @Nullable
+ private final String suffix;
+ @NotNull
+ private final ElementPattern extends PsiElement> pattern;
+
+ protected LanguageInjection(@NotNull String languageId, @Nullable String prefix, @Nullable String suffix, @NotNull ElementPattern extends PsiElement> pattern) {
+ this.languageId = languageId;
+ this.prefix = prefix;
+ this.suffix = suffix;
+ this.pattern = pattern;
+ }
+
+ @Nullable
+ public Language getLanguage() {
+ return Language.findLanguageByID(languageId);
+ }
+
+ @Nullable
+ public String getPrefix() {
+ return prefix;
+ }
+
+ @Nullable
+ public String getSuffix() {
+ return suffix;
+ }
+
+ @NotNull
+ public ElementPattern extends PsiElement> getPattern() {
+ return pattern;
+ }
+
+ public static class Builder {
+ @NotNull
+ private final String languageId;
+ @NotNull
+ private final List> patterns;
+ @Nullable
+ private String prefix;
+ @Nullable
+ private String suffix;
+
+ public Builder(@NotNull String languageId) {
+ this.languageId = languageId;
+ this.patterns = new ArrayList<>();
+ }
+
+ public Builder withPrefix(@Nullable String prefix) {
+ this.prefix = prefix;
+
+ return this;
+ }
+
+ public Builder withSuffix(@Nullable String suffix) {
+ this.suffix = suffix;
+
+ return this;
+ }
+
+ public final Builder matchingPattern(@NotNull ElementPattern extends PsiElement> pattern) {
+ patterns.add(pattern);
+ return this;
+ }
+
+ public Builder matchingAttributeArgument(@NotNull String classFQN, @NotNull String argumentName, int argumentIndex) {
+ return matchingPattern(LanguageInjectionPatterns.getAttributeArgumentPattern(classFQN, argumentName, argumentIndex));
+ }
+
+ public Builder matchingAnnotationProperty(@NotNull String classFQN, @NotNull String propertyName, boolean isDefaultProperty) {
+ return matchingPattern(LanguageInjectionPatterns.getAnnotationPropertyPattern(classFQN, propertyName, isDefaultProperty));
+ }
+
+ public Builder matchingConstructorCallArgument(@NotNull String classFQN, @NotNull String argumentName, int argumentIndex) {
+ return matchingPattern(LanguageInjectionPatterns.getConstructorCallArgumentPattern(classFQN, argumentName, argumentIndex));
+ }
+
+ public Builder matchingConstructorCallWithArrayArgumentPattern(@NotNull String classFQN, @NotNull String argumentName, int argumentIndex, @NotNull String keyName) {
+ return matchingPattern(LanguageInjectionPatterns.getConstructorCallWithArrayArgumentPattern(classFQN, argumentName, argumentIndex, keyName));
+ }
+
+ public Builder matchingFunctionCallArgument(@NotNull String functionFQN, @NotNull String argumentName, int argumentIndex) {
+ return matchingPattern(LanguageInjectionPatterns.getFunctionCallArgumentPattern(functionFQN, argumentName, argumentIndex));
+ }
+
+ public Builder matchingMethodCallArgument(@NotNull String classFQN, @NotNull String methodName, @NotNull String argumentName, int argumentIndex) {
+ return matchingPattern(LanguageInjectionPatterns.getMethodCallArgumentPattern(classFQN, methodName, argumentName, argumentIndex));
+ }
+
+ public Builder matchingVariableAssigment(@NotNull String variableName) {
+ return matchingPattern(LanguageInjectionPatterns.getVariableAssignmentPattern(variableName));
+ }
+
+ public LanguageInjection build() {
+ return new LanguageInjection(languageId, prefix, suffix, StandardPatterns.or(patterns.toArray(new ElementPattern[0])));
+ }
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/LanguageInjectionPatterns.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/LanguageInjectionPatterns.java
new file mode 100644
index 000000000..0fd5711e6
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/LanguageInjectionPatterns.java
@@ -0,0 +1,304 @@
+package fr.adrienbrault.idea.symfony2plugin.lang;
+
+import com.intellij.patterns.ElementPattern;
+import com.intellij.patterns.PatternCondition;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.util.ProcessingContext;
+import com.jetbrains.php.lang.documentation.phpdoc.lexer.PhpDocTokenTypes;
+import com.jetbrains.php.lang.documentation.phpdoc.parser.PhpDocElementTypes;
+import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag;
+import com.jetbrains.php.lang.parser.PhpElementTypes;
+import com.jetbrains.php.lang.patterns.PhpPatterns;
+import com.jetbrains.php.lang.psi.elements.*;
+import com.jetbrains.php.lang.psi.elements.impl.ParameterListImpl;
+import de.espend.idea.php.annotation.util.AnnotationUtil;
+import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public final class LanguageInjectionPatterns {
+
+ public static ElementPattern extends PsiElement> getAnnotationPropertyPattern(
+ @NotNull String classFQN,
+ @NotNull String propertyName,
+ boolean isDefaultProperty) {
+ return PlatformPatterns
+ .psiElement(StringLiteralExpression.class)
+ .with(new IsAnnotationProperty(classFQN, propertyName, isDefaultProperty));
+ }
+
+ public static ElementPattern extends PsiElement> getAttributeArgumentPattern(
+ @NotNull String classFQN,
+ @NotNull String argumentName,
+ int argumentIndex
+ ) {
+ return PlatformPatterns.psiElement()
+ .with(new IsArgument(argumentName, argumentIndex))
+ .withParent(PlatformPatterns
+ .psiElement(ParameterList.class)
+ .withParent(
+ PlatformPatterns.psiElement(PhpAttribute.class)
+ .with(new IsAttribute(classFQN))
+ )
+ );
+ }
+
+ public static ElementPattern extends PsiElement> getMethodCallArgumentPattern(
+ @NotNull String classFQN,
+ @NotNull String methodName,
+ @NotNull String argumentName,
+ int argumentIndex
+ ) {
+ return PlatformPatterns.psiElement()
+ .with(new IsArgument(argumentName, argumentIndex))
+ .withParent(PlatformPatterns
+ .psiElement(ParameterList.class)
+ .withParent(
+ PlatformPatterns.psiElement(MethodReference.class)
+ .with(new IsMethodReference(classFQN, methodName))
+ )
+ );
+ }
+
+ public static ElementPattern extends PsiElement> getConstructorCallArgumentPattern(
+ @NotNull String classFQN,
+ @NotNull String argumentName,
+ int argumentIndex
+ ) {
+ return PlatformPatterns.psiElement()
+ .with(new IsArgument(argumentName, argumentIndex))
+ .withParent(PlatformPatterns
+ .psiElement(ParameterList.class)
+ .withParent(
+ PlatformPatterns.psiElement(NewExpression.class)
+ .with(new IsConstructorReference(classFQN))
+ )
+ );
+ }
+
+ public static ElementPattern extends PsiElement> getConstructorCallWithArrayArgumentPattern(
+ @NotNull String classFQN,
+ @NotNull String argumentName,
+ int argumentIndex,
+ @NotNull String keyName
+ ) {
+ return PlatformPatterns.psiElement()
+ .withParent(PlatformPatterns
+ .psiElement(PhpPsiElement.class)
+ .withElementType(PhpElementTypes.ARRAY_VALUE)
+ .withParent(PlatformPatterns
+ .psiElement(ArrayHashElement.class)
+ .with(new IsArrayHashElementKey(keyName))
+ .withParent(PlatformPatterns
+ .psiElement(ArrayCreationExpression.class)
+ .with(new IsArgument(argumentName, argumentIndex))
+ .withParent(PlatformPatterns
+ .psiElement(ParameterList.class)
+ .withParent(
+ PlatformPatterns.psiElement(NewExpression.class)
+ .with(new IsConstructorReference(classFQN))
+ )
+ )
+ )
+ )
+ );
+ }
+
+ public static ElementPattern extends PsiElement> getFunctionCallArgumentPattern(
+ @NotNull String functionFQN,
+ @NotNull String argumentName,
+ int argumentIndex
+ ) {
+ return PlatformPatterns.psiElement()
+ .with(new IsArgument(argumentName, argumentIndex))
+ .withParent(PlatformPatterns
+ .psiElement(ParameterList.class)
+ .withParent(
+ PlatformPatterns.psiElement(FunctionReference.class)
+ .with(new IsFunctionReference(functionFQN))
+ )
+ );
+ }
+
+ public static ElementPattern extends PsiElement> getVariableAssignmentPattern(@NotNull String variableName) {
+ return PlatformPatterns.psiElement()
+ .withParent(PlatformPatterns
+ .psiElement(AssignmentExpression.class)
+ .withFirstChild(PlatformPatterns
+ .psiElement(Variable.class)
+ .withName(variableName)
+ )
+ );
+ }
+
+ private static class IsAnnotationProperty extends PatternCondition {
+ @NotNull
+ private final String classFQN;
+ @NotNull
+ private final String propertyName;
+ private final boolean isDefaultProperty;
+
+ public IsAnnotationProperty(@NotNull String classFQN, @NotNull String propertyName, boolean isDefaultProperty) {
+ super(String.format("IsAnnotationProperty(%s, %s)", classFQN, propertyName));
+ this.classFQN = classFQN;
+ this.propertyName = propertyName;
+ this.isDefaultProperty = isDefaultProperty;
+ }
+
+ @Override
+ public boolean accepts(@NotNull StringLiteralExpression element, ProcessingContext context) {
+ if (element.getParent() == null || !(element.getParent().getParent() instanceof PhpDocTag)) {
+ return false;
+ }
+
+ var phpDocTag = (PhpDocTag) element.getParent().getParent();
+
+ var annotationClass = AnnotationUtil.getAnnotationReference(phpDocTag);
+ if (annotationClass != null && annotationClass.getFQN().equals(classFQN)) {
+ return element.equals(getPropertyValuePsiElement(phpDocTag));
+ }
+
+ return false;
+ }
+
+ @Nullable
+ private PsiElement getPropertyValuePsiElement(@NotNull PhpDocTag phpDocTag) {
+ PsiElement property = AnnotationUtil.getPropertyValueAsPsiElement(phpDocTag, propertyName);
+
+ if (property == null && isDefaultProperty) {
+ var phpDocAttrList = phpDocTag.getFirstPsiChild();
+ if (phpDocAttrList != null && phpDocAttrList.getNode().getElementType() == PhpDocElementTypes.phpDocAttributeList) {
+ PhpPsiElement firstPhpPsiElement = phpDocAttrList.getFirstPsiChild();
+ if (firstPhpPsiElement instanceof StringLiteralExpression && !hasIdentifier(firstPhpPsiElement)) {
+ property = firstPhpPsiElement;
+ }
+ }
+ }
+
+ return property;
+ }
+
+ private boolean hasIdentifier(@NotNull PsiElement property) {
+ return PlatformPatterns.psiElement()
+ .afterLeafSkipping(
+ PlatformPatterns.or(
+ PlatformPatterns.psiElement(PsiWhiteSpace.class),
+ PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_TEXT).withText("=")
+ ),
+ PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER)
+ )
+ .accepts(property);
+ }
+ }
+
+ private static class IsAttribute extends PatternCondition {
+ @NotNull
+ private final String classFQN;
+
+ public IsAttribute(@NotNull String classFQN) {
+ super(String.format("IsAttribute(%s)", classFQN));
+ this.classFQN = classFQN;
+ }
+
+ @Override
+ public boolean accepts(@NotNull PhpAttribute phpAttribute, ProcessingContext context) {
+ return classFQN.equals(phpAttribute.getFQN());
+ }
+ }
+
+ private static class IsArrayHashElementKey extends PatternCondition {
+ @NotNull
+ private final String name;
+
+ public IsArrayHashElementKey(@NotNull String name) {
+ super(String.format("IsArrayHashElementKey(%s)", name));
+ this.name = name;
+ }
+
+ @Override
+ public boolean accepts(@NotNull ArrayHashElement arrayHashElement, ProcessingContext context) {
+ var key = arrayHashElement.getKey();
+ if (key instanceof StringLiteralExpression) {
+ return ((StringLiteralExpression) key).getContents().equals(name);
+ }
+
+ return false;
+ }
+ }
+
+ private static class IsArgument extends PatternCondition {
+ @NotNull
+ private final String name;
+ private final int index;
+
+ public IsArgument(@NotNull String name, int index) {
+ super(String.format("isArgument(%s, %d)", name, index));
+ this.name = name;
+ this.index = index;
+ }
+
+ @Override
+ public boolean accepts(@NotNull PsiElement parameter, ProcessingContext context) {
+ if (parameter.getParent() instanceof ParameterListImpl) {
+ var parameterList = (ParameterListImpl) parameter.getParent();
+ if (parameterList.getParameter(name) == parameter) {
+ return true;
+ }
+
+ return parameterList.getParameter(index) == parameter && ParameterListImpl.getNameIdentifier(parameter) == null;
+ }
+
+ return false;
+ }
+ }
+
+ private static class IsFunctionReference extends PatternCondition {
+ @NotNull
+ private final String name;
+
+ public IsFunctionReference(@NotNull String name) {
+ super(String.format("IsFunctionReference(%s)", name));
+ this.name = name;
+ }
+
+ @Override
+ public boolean accepts(@NotNull FunctionReference element, ProcessingContext context) {
+ return name.equals(element.getFQN());
+ }
+ }
+
+ private static class IsMethodReference extends PatternCondition {
+ @NotNull
+ private final String classFQN;
+ @NotNull
+ private final String methodName;
+
+ public IsMethodReference(@NotNull String classFQN, @NotNull String methodName) {
+ super(String.format("IsMethodReference(%s::%s)", classFQN, methodName));
+ this.classFQN = classFQN;
+ this.methodName = methodName;
+ }
+
+ @Override
+ public boolean accepts(@NotNull MethodReference element, ProcessingContext context) {
+ return PhpElementsUtil.isMethodReferenceInstanceOf(element, classFQN, methodName);
+ }
+ }
+
+ private static class IsConstructorReference extends PatternCondition {
+ @NotNull
+ private final String classFQN;
+
+ public IsConstructorReference(@NotNull String classFQN) {
+ super(String.format("IsConstructorReference(%s)", classFQN));
+ this.classFQN = classFQN;
+ }
+
+ @Override
+ public boolean accepts(@NotNull NewExpression newExpression, ProcessingContext context) {
+ return PhpElementsUtil.isNewExpressionPhpClassWithInstance(newExpression, classFQN);
+ }
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/ParameterLanguageInjector.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/ParameterLanguageInjector.java
index 4db1a1ca5..7b99009a5 100644
--- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/ParameterLanguageInjector.java
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/ParameterLanguageInjector.java
@@ -16,6 +16,7 @@
import java.util.Collections;
import java.util.List;
+@Deprecated
public class ParameterLanguageInjector implements MultiHostInjector {
private static final MethodMatcher.CallToSignature[] CSS_SELECTOR_SIGNATURES = {
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/StringLiteralLanguageInjector.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/StringLiteralLanguageInjector.java
new file mode 100644
index 000000000..21fe9ac8d
--- /dev/null
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/lang/StringLiteralLanguageInjector.java
@@ -0,0 +1,95 @@
+package fr.adrienbrault.idea.symfony2plugin.lang;
+
+import com.intellij.lang.injection.MultiHostInjector;
+import com.intellij.lang.injection.MultiHostRegistrar;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiLanguageInjectionHost;
+import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
+import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+public class StringLiteralLanguageInjector implements MultiHostInjector {
+
+ public static final String LANGUAGE_ID_CSS = "CSS";
+ public static final String LANGUAGE_ID_XPATH = "XPath";
+ public static final String LANGUAGE_ID_JSON = "JSON";
+ public static final String LANGUAGE_ID_DQL = "DQL";
+ public static final String LANGUAGE_ID_EXPRESSION_LANGUAGE = "Symfony Expression Language";
+
+ private final LanguageInjection[] LANGUAGE_INJECTIONS = {
+ new LanguageInjection.Builder(LANGUAGE_ID_CSS)
+ .withPrefix("@media all { ")
+ .withSuffix(" }")
+ .matchingMethodCallArgument("\\Symfony\\Component\\DomCrawler\\Crawler", "filter", "selector", 0)
+ .matchingMethodCallArgument("\\Symfony\\Component\\DomCrawler\\Crawler", "children", "selector", 0)
+ .matchingMethodCallArgument("\\Symfony\\Component\\CssSelector\\CssSelectorConverter", "toXPath", "cssExpr", 0)
+ .build(),
+ new LanguageInjection.Builder(LANGUAGE_ID_XPATH)
+ .matchingMethodCallArgument("\\Symfony\\Component\\DomCrawler\\Crawler", "filterXPath", "xpath", 0)
+ .matchingMethodCallArgument("\\Symfony\\Component\\DomCrawler\\Crawler", "evaluate", "xpath", 0)
+ .build(),
+ new LanguageInjection.Builder(LANGUAGE_ID_JSON)
+ .matchingMethodCallArgument("\\Symfony\\Component\\HttpFoundation\\JsonResponse", "fromJsonString", "data", 0)
+ .matchingMethodCallArgument("\\Symfony\\Component\\HttpFoundation\\JsonResponse", "setJson", "json", 0)
+ .build(),
+ new LanguageInjection.Builder(LANGUAGE_ID_DQL)
+ .matchingMethodCallArgument("\\Doctrine\\ORM\\EntityManager", "createQuery", "dql", 0)
+ .matchingMethodCallArgument("\\Doctrine\\ORM\\Query", "setDQL", "dqlQuery", 0)
+ .matchingVariableAssigment("dql")
+ .build(),
+ new LanguageInjection.Builder(LANGUAGE_ID_EXPRESSION_LANGUAGE)
+ .matchingConstructorCallArgument("\\Symfony\\Component\\ExpressionLanguage\\Expression", "expression", 0)
+ .matchingConstructorCallWithArrayArgumentPattern("\\Symfony\\Component\\Validator\\Constraints\\Expression", "expression", 0, "expression")
+ .matchingFunctionCallArgument("\\Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\expr", "expression", 0)
+ .matchingMethodCallArgument("\\Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage", "evaluate", "expression", 0)
+ .matchingMethodCallArgument("\\Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage", "compile", "expression", 0)
+ .matchingMethodCallArgument("\\Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage", "parse", "expression", 0)
+ .matchingMethodCallArgument("\\Symfony\\Component\\Routing\\Loader\\Configurator\\Traits\\RouteTrait", "condition", "condition", 0)
+ .matchingAttributeArgument("\\Symfony\\Component\\Validator\\Constraints\\Expression", "expression", 0)
+ .matchingAttributeArgument("\\Symfony\\Component\\Routing\\Annotation\\Route", "condition", 9)
+ .matchingAttributeArgument("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Cache", "lastModified", 7)
+ .matchingAttributeArgument("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Cache", "etag", 8)
+ .matchingAttributeArgument("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Security", "data", 0)
+ .matchingAttributeArgument("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Entity", "expr", 1)
+ .matchingAnnotationProperty("\\Symfony\\Component\\Validator\\Constraints\\Expression", "expression", true)
+ .matchingAnnotationProperty("\\Symfony\\Component\\Routing\\Annotation\\Route", "condition", false)
+ .matchingAnnotationProperty("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route", "condition", false)
+ .matchingAnnotationProperty("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Security", "expression", true)
+ .matchingAnnotationProperty("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Cache", "lastModified", false)
+ .matchingAnnotationProperty("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Cache", "Etag", false)
+ .matchingAnnotationProperty("\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Entity", "expr", false)
+ .build()
+ };
+
+ @Override
+ public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement element) {
+ if (!(element instanceof StringLiteralExpression) || !((PsiLanguageInjectionHost) element).isValidHost()) {
+ return;
+ }
+
+ if (!Symfony2ProjectComponent.isEnabled(element.getProject())) {
+ return;
+ }
+
+ for (var injection : LANGUAGE_INJECTIONS) {
+ if (injection.getPattern().accepts(element)) {
+ var literal = (StringLiteralExpression) element;
+ var language = injection.getLanguage();
+
+ if (language != null) {
+ registrar.startInjecting(language);
+ registrar.addPlace(injection.getPrefix(), injection.getSuffix(), literal, literal.getValueRange());
+ registrar.doneInjecting();
+ }
+ }
+ }
+ }
+
+ @Override
+ public @NotNull
+ List extends Class extends PsiElement>> elementsToInjectIn() {
+ return Collections.singletonList(StringLiteralExpression.class);
+ }
+}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/security/AnnotationExpressionGotoCompletionRegistrar.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/security/AnnotationExpressionGotoCompletionRegistrar.java
index 9c3ef3caf..842f60f72 100644
--- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/security/AnnotationExpressionGotoCompletionRegistrar.java
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/security/AnnotationExpressionGotoCompletionRegistrar.java
@@ -1,78 +1,50 @@
package fr.adrienbrault.idea.symfony2plugin.security;
-import com.intellij.codeInsight.completion.CompletionResultSet;
-import com.intellij.patterns.PatternCondition;
import com.intellij.patterns.PlatformPatterns;
-import com.intellij.patterns.PsiElementPattern;
+import com.intellij.patterns.StandardPatterns;
import com.intellij.psi.PsiElement;
-import com.intellij.util.ProcessingContext;
-import com.jetbrains.php.lang.documentation.phpdoc.lexer.PhpDocTokenTypes;
-import com.jetbrains.php.lang.documentation.phpdoc.parser.PhpDocElementTypes;
-import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag;
-import com.jetbrains.php.lang.lexer.PhpTokenTypes;
-import com.jetbrains.php.lang.psi.elements.ParameterList;
-import com.jetbrains.php.lang.psi.elements.PhpAttribute;
-import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
-import de.espend.idea.php.annotation.util.AnnotationUtil;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProvider;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProviderLookupArguments;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrar;
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrarParameter;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageCallExpr;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageLiteralExpr;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageRefExpr;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.psi.ExpressionLanguageStringLiteral;
import fr.adrienbrault.idea.symfony2plugin.security.utils.VoterUtil;
-import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
-import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* @author Daniel Espendiller
*/
public class AnnotationExpressionGotoCompletionRegistrar implements GotoCompletionRegistrar {
- private static final String SECURITY_ANNOTATION = "\\Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Security";
-
@Override
public void register(@NotNull GotoCompletionRegistrarParameter registrar) {
// "@Security("is_granted('POST_SHOW', post) and has_role('ROLE_ADMIN')")"
registrar.register(
- PlatformPatterns.or(getDocTagStringPattern(), getAttributeStringPattern()),
+ PlatformPatterns.psiElement()
+ .withParent(PlatformPatterns
+ .psiElement(ExpressionLanguageStringLiteral.class)
+ .withParent(PlatformPatterns
+ .psiElement(ExpressionLanguageLiteralExpr.class)
+ .withParent(PlatformPatterns
+ .psiElement(ExpressionLanguageCallExpr.class)
+ .withFirstChild(PlatformPatterns
+ .psiElement(ExpressionLanguageRefExpr.class)
+ .withText(StandardPatterns.string().oneOf("has_role", "is_granted"))
+ )
+ )
+ )
+ ),
MyGotoCompletionProvider::new
);
}
- @NotNull
- private PsiElementPattern.Capture getAttributeStringPattern() {
- // #[Security("is_granted('POST_SHOW')")]
- return PlatformPatterns.psiElement().withElementType(PlatformPatterns.elementType().or(
- PhpTokenTypes.STRING_LITERAL_SINGLE_QUOTE,
- PhpTokenTypes.STRING_LITERAL
- ))
- .withParent(PlatformPatterns.psiElement(StringLiteralExpression.class)
- .withParent(PlatformPatterns.psiElement(ParameterList.class)
- .withParent(PlatformPatterns.psiElement(PhpAttribute.class)
- .with(PhpDocInstancePatternCondition.INSTANCE)
- )
- )
- );
- }
-
- @NotNull
- private PsiElementPattern.Capture getDocTagStringPattern() {
- return PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_STRING)
- .withParent(PlatformPatterns.psiElement(StringLiteralExpression.class)
- .withParent(PlatformPatterns.psiElement(PhpDocElementTypes.phpDocAttributeList)
- .withParent(PlatformPatterns.psiElement(PhpDocTag.class)
- .with(PhpDocInstancePatternCondition.INSTANCE)
- )
- )
- );
- }
-
/**
* "@Security("has_role('ROLE_FOOBAR')")"
* "@Security("is_granted('POST_SHOW', post) and has_role('ROLE_ADMIN')")"
@@ -84,65 +56,25 @@ private static class MyGotoCompletionProvider extends GotoCompletionProvider {
@Override
public void getLookupElements(@NotNull GotoCompletionProviderLookupArguments arguments) {
- final CompletionResultSet resultSet = arguments.getResultSet();
- String blockNamePrefix = resultSet.getPrefixMatcher().getPrefix();
-
- // find caret position:
- // - "has_role('"
- // - "has_role('YAML_ROLE_"
- if(!blockNamePrefix.matches("^.*(has_role|is_granted)\\s*\\(\\s*['|\"][\\w-]*$")) {
- return;
- }
-
- // clear prefix caret string; for a clean completion independent from inside content
- String substring = blockNamePrefix.replaceAll("^(.*(has_role|is_granted)\\s*\\(\\s*['|\"])", "");
- CompletionResultSet myResultSet = resultSet.withPrefixMatcher(substring);
-
- VoterUtil.LookupElementPairConsumer consumer = new VoterUtil.LookupElementPairConsumer();
+ var consumer = new VoterUtil.LookupElementPairConsumer();
VoterUtil.visitAttribute(getProject(), consumer);
- myResultSet.addAllElements(consumer.getLookupElements());
+ arguments.getResultSet().addAllElements(consumer.getLookupElements());
}
@NotNull
@Override
public Collection getPsiTargets(PsiElement element) {
- String contents = null;
- if(getElement().getNode().getElementType() == PhpDocTokenTypes.DOC_STRING) {
- // @Security
- PsiElement parent = getElement().getParent();
- if(!(parent instanceof StringLiteralExpression)) {
- return Collections.emptyList();
- }
-
- contents = ((StringLiteralExpression) parent).getContents();
- } else {
- // @Security
- PsiElement parent = getElement().getParent();
- if (parent instanceof StringLiteralExpression) {
- contents = ((StringLiteralExpression) parent).getContents();
- }
- }
-
- if (StringUtils.isBlank(contents)) {
+ var text = getElement().getText();
+ if (text.length() < 2) {
return Collections.emptyList();
}
- Collection roles = new HashSet<>();
- for (String regex : new String[]{"is_granted\\s*\\(\\s*['|\"]([^'\"]+)['|\"]\\s*[\\)|,]", "has_role\\s*\\(\\s*['|\"]([^'\"]+)['|\"]\\s*\\)"}) {
- Matcher matcher = Pattern.compile(regex).matcher(contents);
- while(matcher.find()){
- roles.add(matcher.group(1));
- }
- }
-
- if(roles.size() == 0) {
- return Collections.emptyList();
- }
-
- Collection targets = new HashSet<>();
+ // Strip quotes
+ var role = text.substring(1, text.length() - 1);
+ var targets = new HashSet();
VoterUtil.visitAttribute(getProject(), pair -> {
- if(roles.contains(pair.getFirst())) {
+ if(pair.getFirst().equals(role)) {
targets.add(pair.getSecond());
}
});
@@ -150,26 +82,4 @@ public Collection getPsiTargets(PsiElement element) {
return targets;
}
}
-
- /**
- * Check if given PhpDocTag is instance of given Annotation class
- */
- private static class PhpDocInstancePatternCondition extends PatternCondition {
- private static final PhpDocInstancePatternCondition INSTANCE = new PhpDocInstancePatternCondition();
-
- PhpDocInstancePatternCondition() {
- super("PhpDoc/Attribute Instance");
- }
-
- @Override
- public boolean accepts(@NotNull PsiElement psiElement, ProcessingContext processingContext) {
- if (psiElement instanceof PhpDocTag) {
- return PhpElementsUtil.isEqualClassName(AnnotationUtil.getAnnotationReference((PhpDocTag) psiElement), SECURITY_ANNOTATION);
- } else if (psiElement instanceof PhpAttribute) {
- return SECURITY_ANNOTATION.equals(((PhpAttribute) psiElement).getFQN());
- }
-
- return false;
- }
- }
}
diff --git a/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/yaml/YamlHelper.java b/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/yaml/YamlHelper.java
index 1e69847dc..961cd5d9b 100644
--- a/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/yaml/YamlHelper.java
+++ b/src/main/java/fr/adrienbrault/idea/symfony2plugin/util/yaml/YamlHelper.java
@@ -519,15 +519,28 @@ public static void processKeysAfterRoot(@NotNull PsiFile psiFile, @NotNull Proce
}
public static boolean isRoutingFile(PsiFile psiFile) {
- return psiFile.getName().contains("routing") || psiFile.getVirtualFile().getPath().contains("/routing");
+ return fileNameOrPathContains(psiFile, "routing");
}
public static boolean isConfigFile(@NotNull PsiFile psiFile) {
- return psiFile.getName().contains("config") || psiFile.getVirtualFile().getPath().contains("/config");
+ return fileNameOrPathContains(psiFile, "config");
}
public static boolean isServicesFile(@NotNull PsiFile psiFile) {
- return psiFile.getName().contains("services") || psiFile.getVirtualFile().getPath().contains("/services");
+ return fileNameOrPathContains(psiFile, "services");
+ }
+
+ private static boolean fileNameOrPathContains(@NotNull PsiFile psiFile, @NotNull String text) {
+ if (psiFile.getName().contains(text)) {
+ return true;
+ }
+
+ var virtualFile = psiFile.getVirtualFile();
+ if (virtualFile != null) {
+ return virtualFile.getPath().contains("/" + text);
+ }
+
+ return false;
}
public static boolean isInsideServiceDefinition(@NotNull PsiElement psiElement) {
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index bb626e780..a6d591aed 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -228,6 +228,13 @@
+
+
+
+
+
+
+
@@ -258,6 +265,10 @@
+
+
+
+
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/xml/XmlLanguageInjectorTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/xml/XmlLanguageInjectorTest.java
new file mode 100644
index 000000000..5f0e0ff95
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/xml/XmlLanguageInjectorTest.java
@@ -0,0 +1,46 @@
+package fr.adrienbrault.idea.symfony2plugin.tests.config.xml;
+
+import com.intellij.testFramework.fixtures.InjectionTestFixture;
+import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
+import org.jetbrains.annotations.NotNull;
+
+public class XmlLanguageInjectorTest extends SymfonyLightCodeInsightFixtureTestCase {
+
+ private InjectionTestFixture injectionTestFixture;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ injectionTestFixture = new InjectionTestFixture(myFixture);
+ }
+
+ public void testLanguageInjections() {
+ assertExpressionLanguageIsInjectedAtCaret(
+ "services.xml",
+ "\n" +
+ "\n" +
+ " \n" +
+ " \n" +
+ " container.hasParameter('some_param') ?\n" +
+ " \n" +
+ " \n" +
+ ""
+ );
+
+ assertExpressionLanguageIsInjectedAtCaret(
+ "routing.xml",
+ "\n" +
+ "\n" +
+ " \n" +
+ " context.getMethod() in \n" +
+ " \n" +
+ ""
+ );
+ }
+
+ private void assertExpressionLanguageIsInjectedAtCaret(@NotNull String fileName, @NotNull String text) {
+ myFixture.configureByText(fileName, text);
+ injectionTestFixture.assertInjectedLangAtCaret("Symfony Expression Language");
+ }
+}
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlLanguageInjectorTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlLanguageInjectorTest.java
new file mode 100644
index 000000000..36642bbaf
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/config/yaml/YamlLanguageInjectorTest.java
@@ -0,0 +1,63 @@
+package fr.adrienbrault.idea.symfony2plugin.tests.config.yaml;
+
+import com.intellij.testFramework.fixtures.InjectionTestFixture;
+import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
+import org.jetbrains.annotations.NotNull;
+
+public class YamlLanguageInjectorTest extends SymfonyLightCodeInsightFixtureTestCase {
+
+ private InjectionTestFixture injectionTestFixture;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ injectionTestFixture = new InjectionTestFixture(myFixture);
+ }
+
+ public void testLanguageInjections() {
+ assertExpressionLanguageIsInjectedAtCaret(
+ "services.yaml",
+ "services:\n" +
+ " App\\Service\\ExampleService:\n" +
+ " arguments:\n" +
+ " $example: '@=service('\n"
+ );
+
+ assertExpressionLanguageIsInjectedAtCaret(
+ "services.yaml",
+ "services:\n" +
+ " App\\Service\\ExampleService:\n" +
+ " calls:\n" +
+ " - example: ['@=service(']\n"
+ );
+
+ assertExpressionLanguageIsInjectedAtCaret(
+ "services.yaml",
+ "services:\n" +
+ " App\\Service\\ExampleService:\n" +
+ " properties:\n" +
+ " example: '@=service(']\n"
+ );
+
+ assertExpressionLanguageIsInjectedAtCaret(
+ "services.yaml",
+ "services:\n" +
+ " App\\Service\\ExampleService:\n" +
+ " configurator: ['@=service(', 'configure']\n"
+ );
+
+ assertExpressionLanguageIsInjectedAtCaret(
+ "routing.yaml",
+ "app.contact:\n" +
+ " path: /contact\n" +
+ " controller: 'App\\Controller\\DefaultController::contact'\n" +
+ " condition: 'context.getMethod() in '\n"
+ );
+ }
+
+ private void assertExpressionLanguageIsInjectedAtCaret(@NotNull String fileName, @NotNull String text) {
+ myFixture.configureByText(fileName, text);
+ injectionTestFixture.assertInjectedLangAtCaret("Symfony Expression Language");
+ }
+}
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/ExpressionLanguageParsingTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/ExpressionLanguageParsingTest.java
new file mode 100644
index 000000000..1ebc704b5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/ExpressionLanguageParsingTest.java
@@ -0,0 +1,220 @@
+package fr.adrienbrault.idea.symfony2plugin.tests.expressionLanguage;
+
+import com.intellij.testFramework.ParsingTestCase;
+import fr.adrienbrault.idea.symfony2plugin.expressionLanguage.ExpressionLanguageParserDefinition;
+
+public class ExpressionLanguageParsingTest extends ParsingTestCase {
+
+ public ExpressionLanguageParsingTest() {
+ super("", "test", new ExpressionLanguageParserDefinition());
+ }
+
+ public void testNotExpr() {
+ doTest(true);
+ }
+
+ public void testNotKwExpr() {
+ doTest(true);
+ }
+
+ public void testUnaryMinus() {
+ doTest(true);
+ }
+
+ public void testUnaryPlus() {
+ doTest(true);
+ }
+
+ public void testDivExpr() {
+ doTest(true);
+ }
+
+ public void testMulExpr() {
+ doTest(true);
+ }
+
+ public void testModExpr() {
+ doTest(true);
+ }
+
+ public void testPlusExpr() {
+ doTest(true);
+ }
+
+ public void testMinusExpr() {
+ doTest(true);
+ }
+
+ public void testRangeExpr() {
+ doTest(true);
+ }
+
+ public void testIdenticalExpr() {
+ doTest(true);
+ }
+
+ public void testNotIdenticalExpr() {
+ doTest(true);
+ }
+
+ public void testEqExpr() {
+ doTest(true);
+ }
+
+ public void testNotEqExpr() {
+ doTest(true);
+ }
+
+ public void testGtExpr() {
+ doTest(true);
+ }
+
+ public void testGteExpr() {
+ doTest(true);
+ }
+
+ public void testLtExpr() {
+ doTest(true);
+ }
+
+ public void testLteExpr() {
+ doTest(true);
+ }
+
+ public void testNotInExpr() {
+ doTest(true);
+ }
+
+ public void testInExpr() {
+ doTest(true);
+ }
+
+ public void testMatchesExpr() {
+ doTest(true);
+ }
+
+ public void testOrExpr() {
+ doTest(true);
+ }
+
+ public void testAndExpr() {
+ doTest(true);
+ }
+
+ public void testBitAndExpr() {
+ doTest(true);
+ }
+
+ public void testBitOrExpr() {
+ doTest(true);
+ }
+
+ public void testBitXorExpr() {
+ doTest(true);
+ }
+
+ public void testExpExpr() {
+ doTest(true);
+ }
+
+ public void testParenExpr() {
+ doTest(true);
+ }
+
+ public void testNumberLiteral() {
+ doTest(true);
+ }
+
+ public void testNumberLiteralWithFraction() {
+ doTest(true);
+ }
+
+ public void testExponentialNotationLiteral() {
+ doTest(true);
+ }
+
+ public void testStringDoubleQuoteLiteral() {
+ doTest(true);
+ }
+
+ public void testEmptyStringDoubleQuoteLiteral() {
+ doTest(true);
+ }
+
+ public void testStringSingleQuoteLiteral() {
+ doTest(true);
+ }
+
+ public void testEmptyStringSingleQuoteLiteral() {
+ doTest(true);
+ }
+
+ public void testTrueLiteral() {
+ doTest(true);
+ }
+
+ public void testTrueUppercaseLiteral() {
+ doTest(true);
+ }
+
+ public void testFalseLiteral() {
+ doTest(true);
+ }
+
+ public void testFalseUppercaseLiteral() {
+ doTest(true);
+ }
+
+ public void testNullLiteral() {
+ doTest(true);
+ }
+
+ public void testNullUppercaseLiteral() {
+ doTest(true);
+ }
+
+ public void testEmptyArrayLiteral() {
+ doTest(true);
+ }
+
+ public void testArrayLiteral() {
+ doTest(true);
+ }
+
+ public void testEmptyHashLiteral() {
+ doTest(true);
+ }
+
+ public void testHashLiteral() {
+ doTest(true);
+ }
+
+ public void testFunctionCallWithoutArgs() {
+ doTest(true);
+ }
+
+ public void testFunctionCallWithArgs() {
+ doTest(true);
+ }
+
+ public void testMethodCallWithoutArgs() {
+ doTest(true);
+ }
+
+ public void testMethodCallWithArgs() {
+ doTest(true);
+ }
+
+ public void testTernaryExpr() {
+ doTest(true);
+ }
+
+ public void testElvisExpr() {
+ doTest(true);
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return "src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData";
+ }
+}
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/AndExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/AndExpr.test
new file mode 100644
index 000000000..6d38cb10b
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/AndExpr.test
@@ -0,0 +1 @@
+a && b and c
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/AndExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/AndExpr.txt
new file mode 100644
index 000000000..def6dfdaf
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/AndExpr.txt
@@ -0,0 +1,18 @@
+Expression Language File
+ ExpressionLanguageAndExprImpl(AND_EXPR)
+ ExpressionLanguageAndExprImpl(AND_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.&&)('&&')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.and)('and')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('c')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ArrayLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ArrayLiteral.test
new file mode 100644
index 000000000..2fcbb6e9d
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ArrayLiteral.test
@@ -0,0 +1 @@
+[1, a, "string", [], [1, 2, 3], {}, { foo: "Foo", bar: "Bar" }]
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ArrayLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ArrayLiteral.txt
new file mode 100644
index 000000000..bf3a4848e
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ArrayLiteral.txt
@@ -0,0 +1,68 @@
+Expression Language File
+ ExpressionLanguageArrayExprImpl(ARRAY_EXPR)
+ PsiElement( ExpressionLanguageType.[)('[')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)('"string"')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageArrayExprImpl(ARRAY_EXPR)
+ PsiElement( ExpressionLanguageType.[)('[')
+ PsiElement( ExpressionLanguageType.])(']')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageArrayExprImpl(ARRAY_EXPR)
+ PsiElement( ExpressionLanguageType.[)('[')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('2')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('3')
+ PsiElement( ExpressionLanguageType.])(']')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageHashExprImpl(HASH_EXPR)
+ PsiElement( ExpressionLanguageType.{)('{')
+ PsiElement( ExpressionLanguageType.})('}')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageHashExprImpl(HASH_EXPR)
+ PsiElement( ExpressionLanguageType.{)('{')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('foo')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)('"Foo"')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('bar')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)('"Bar"')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.})('}')
+ PsiElement( ExpressionLanguageType.])(']')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitAndExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitAndExpr.test
new file mode 100644
index 000000000..dd0f82162
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitAndExpr.test
@@ -0,0 +1 @@
+a & b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitAndExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitAndExpr.txt
new file mode 100644
index 000000000..c3ecb5940
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitAndExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageBitAndExprImpl(BIT_AND_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.&)('&')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitOrExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitOrExpr.test
new file mode 100644
index 000000000..66d32a465
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitOrExpr.test
@@ -0,0 +1 @@
+a | b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitOrExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitOrExpr.txt
new file mode 100644
index 000000000..daebc8e28
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitOrExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageBitOrExprImpl(BIT_OR_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.|)('|')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitXorExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitXorExpr.test
new file mode 100644
index 000000000..0b02b73e3
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitXorExpr.test
@@ -0,0 +1 @@
+a ^ b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitXorExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitXorExpr.txt
new file mode 100644
index 000000000..7ca83cff5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/BitXorExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageBitXorExprImpl(BIT_XOR_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.^)('^')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/DivExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/DivExpr.test
new file mode 100644
index 000000000..c6ef76fbf
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/DivExpr.test
@@ -0,0 +1 @@
+4 / 2
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/DivExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/DivExpr.txt
new file mode 100644
index 000000000..d87b8a918
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/DivExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageDivExprImpl(DIV_EXPR)
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('4')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType./)('/')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('2')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ElvisExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ElvisExpr.test
new file mode 100644
index 000000000..6c00bb74b
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ElvisExpr.test
@@ -0,0 +1 @@
+a ?: b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ElvisExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ElvisExpr.txt
new file mode 100644
index 000000000..23d4a0dd8
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ElvisExpr.txt
@@ -0,0 +1,12 @@
+Expression Language File
+ ExpressionLanguageElvisExprImpl(ELVIS_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.syntax)('?')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyArrayLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyArrayLiteral.test
new file mode 100644
index 000000000..0637a088a
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyArrayLiteral.test
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyArrayLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyArrayLiteral.txt
new file mode 100644
index 000000000..e0ad31de5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyArrayLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageArrayExprImpl(ARRAY_EXPR)
+ PsiElement( ExpressionLanguageType.[)('[')
+ PsiElement( ExpressionLanguageType.])(']')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyHashLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyHashLiteral.test
new file mode 100644
index 000000000..9e26dfeeb
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyHashLiteral.test
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyHashLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyHashLiteral.txt
new file mode 100644
index 000000000..362f6d935
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyHashLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageHashExprImpl(HASH_EXPR)
+ PsiElement( ExpressionLanguageType.{)('{')
+ PsiElement( ExpressionLanguageType.})('}')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringDoubleQuoteLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringDoubleQuoteLiteral.test
new file mode 100644
index 000000000..3cc762b55
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringDoubleQuoteLiteral.test
@@ -0,0 +1 @@
+""
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringDoubleQuoteLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringDoubleQuoteLiteral.txt
new file mode 100644
index 000000000..d10e25e5a
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringDoubleQuoteLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)('""')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringSingleQuoteLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringSingleQuoteLiteral.test
new file mode 100644
index 000000000..942309095
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringSingleQuoteLiteral.test
@@ -0,0 +1 @@
+''
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringSingleQuoteLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringSingleQuoteLiteral.txt
new file mode 100644
index 000000000..0dc89ed48
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EmptyStringSingleQuoteLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)('''')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EqExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EqExpr.test
new file mode 100644
index 000000000..e4bd773f2
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EqExpr.test
@@ -0,0 +1 @@
+a == b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EqExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EqExpr.txt
new file mode 100644
index 000000000..969d54b5b
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/EqExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageEqExprImpl(EQ_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.==)('==')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExpExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExpExpr.test
new file mode 100644
index 000000000..73a65695f
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExpExpr.test
@@ -0,0 +1 @@
+a**2
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExpExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExpExpr.txt
new file mode 100644
index 000000000..6bb86b5be
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExpExpr.txt
@@ -0,0 +1,9 @@
+Expression Language File
+ ExpressionLanguageExpExprImpl(EXP_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiElement( ExpressionLanguageType.**)('**')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('2')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExponentialNotationLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExponentialNotationLiteral.test
new file mode 100644
index 000000000..c66df7ac5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExponentialNotationLiteral.test
@@ -0,0 +1 @@
+1.99E+3
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExponentialNotationLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExponentialNotationLiteral.txt
new file mode 100644
index 000000000..b77b5491c
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ExponentialNotationLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1.99E+3')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseLiteral.test
new file mode 100644
index 000000000..02e4a84d6
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseLiteral.test
@@ -0,0 +1 @@
+false
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseLiteral.txt
new file mode 100644
index 000000000..a9764936d
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageBooleanLiteralImpl(BOOLEAN_LITERAL)
+ PsiElement( ExpressionLanguageType.false)('false')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseUppercaseLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseUppercaseLiteral.test
new file mode 100644
index 000000000..5a03bd3f5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseUppercaseLiteral.test
@@ -0,0 +1 @@
+FALSE
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseUppercaseLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseUppercaseLiteral.txt
new file mode 100644
index 000000000..4d4229d4c
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FalseUppercaseLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageBooleanLiteralImpl(BOOLEAN_LITERAL)
+ PsiElement( ExpressionLanguageType.false)('FALSE')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithArgs.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithArgs.test
new file mode 100644
index 000000000..b64982b85
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithArgs.test
@@ -0,0 +1 @@
+sum(a, b)
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithArgs.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithArgs.txt
new file mode 100644
index 000000000..d6f98ac8b
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithArgs.txt
@@ -0,0 +1,15 @@
+Expression Language File
+ ExpressionLanguageCallExprImpl(CALL_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('sum')
+ PsiElement( ExpressionLanguageType.()('(')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
+ PsiElement( ExpressionLanguageType.))(')')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithoutArgs.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithoutArgs.test
new file mode 100644
index 000000000..a57d16823
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithoutArgs.test
@@ -0,0 +1 @@
+foo()
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithoutArgs.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithoutArgs.txt
new file mode 100644
index 000000000..6b28da9e5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/FunctionCallWithoutArgs.txt
@@ -0,0 +1,7 @@
+Expression Language File
+ ExpressionLanguageCallExprImpl(CALL_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('foo')
+ PsiElement( ExpressionLanguageType.()('(')
+ PsiElement( ExpressionLanguageType.))(')')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GtExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GtExpr.test
new file mode 100644
index 000000000..ef203a499
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GtExpr.test
@@ -0,0 +1 @@
+a > b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GtExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GtExpr.txt
new file mode 100644
index 000000000..954913b20
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GtExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageGtExprImpl(GT_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.>)('>')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GteExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GteExpr.test
new file mode 100644
index 000000000..79e707c7d
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GteExpr.test
@@ -0,0 +1 @@
+a >= b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GteExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GteExpr.txt
new file mode 100644
index 000000000..6ef777bdf
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/GteExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageGteExprImpl(GTE_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.>=)('>=')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/HashLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/HashLiteral.test
new file mode 100644
index 000000000..f2a60e7e8
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/HashLiteral.test
@@ -0,0 +1 @@
+{ a: 1, b: "string", c: [], d: {}, e: { foo: 1, bar: "bar" }, f: [], g: [1, 2, 3] }
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/HashLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/HashLiteral.txt
new file mode 100644
index 000000000..848dc719a
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/HashLiteral.txt
@@ -0,0 +1,98 @@
+Expression Language File
+ ExpressionLanguageHashExprImpl(HASH_EXPR)
+ PsiElement( ExpressionLanguageType.{)('{')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)('"string"')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('c')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageArrayExprImpl(ARRAY_EXPR)
+ PsiElement( ExpressionLanguageType.[)('[')
+ PsiElement( ExpressionLanguageType.])(']')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('d')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageHashExprImpl(HASH_EXPR)
+ PsiElement( ExpressionLanguageType.{)('{')
+ PsiElement( ExpressionLanguageType.})('}')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('e')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageHashExprImpl(HASH_EXPR)
+ PsiElement( ExpressionLanguageType.{)('{')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('foo')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('bar')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)('"bar"')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.})('}')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('f')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageArrayExprImpl(ARRAY_EXPR)
+ PsiElement( ExpressionLanguageType.[)('[')
+ PsiElement( ExpressionLanguageType.])(']')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('g')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageArrayExprImpl(ARRAY_EXPR)
+ PsiElement( ExpressionLanguageType.[)('[')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('2')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('3')
+ PsiElement( ExpressionLanguageType.])(']')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.})('}')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/IdenticalExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/IdenticalExpr.test
new file mode 100644
index 000000000..62de40f2b
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/IdenticalExpr.test
@@ -0,0 +1 @@
+a === b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/IdenticalExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/IdenticalExpr.txt
new file mode 100644
index 000000000..bc3e8fc15
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/IdenticalExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageIdenticalExprImpl(IDENTICAL_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.===)('===')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/InExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/InExpr.test
new file mode 100644
index 000000000..1261e6ae6
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/InExpr.test
@@ -0,0 +1 @@
+a in b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/InExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/InExpr.txt
new file mode 100644
index 000000000..4978363df
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/InExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageInExprImpl(IN_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.in)('in')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LtExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LtExpr.test
new file mode 100644
index 000000000..96f1c8dc8
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LtExpr.test
@@ -0,0 +1 @@
+a < b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LtExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LtExpr.txt
new file mode 100644
index 000000000..549ee98a5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LtExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageLtExprImpl(LT_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.<)('<')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LteExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LteExpr.test
new file mode 100644
index 000000000..8d0a32a20
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LteExpr.test
@@ -0,0 +1 @@
+a <= b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LteExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LteExpr.txt
new file mode 100644
index 000000000..f58aace18
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/LteExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageLteExprImpl(LTE_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.<=)('<=')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MatchesExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MatchesExpr.test
new file mode 100644
index 000000000..b9ca3bd9f
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MatchesExpr.test
@@ -0,0 +1 @@
+a matches b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MatchesExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MatchesExpr.txt
new file mode 100644
index 000000000..03b3fbd77
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MatchesExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageMatchesExprImpl(MATCHES_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.matches)('matches')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithArgs.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithArgs.test
new file mode 100644
index 000000000..235ec16fd
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithArgs.test
@@ -0,0 +1 @@
+calc.sum(a, b)
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithArgs.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithArgs.txt
new file mode 100644
index 000000000..606a0ca0f
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithArgs.txt
@@ -0,0 +1,19 @@
+Expression Language File
+ ExpressionLanguageCallExprImpl(CALL_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('calc')
+ PsiElement( ExpressionLanguageType.syntax)('.')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('sum')
+ PsiElement( ExpressionLanguageType.()('(')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiElement( ExpressionLanguageType.syntax)(',')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
+ PsiElement( ExpressionLanguageType.))(')')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithoutArgs.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithoutArgs.test
new file mode 100644
index 000000000..11911d947
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithoutArgs.test
@@ -0,0 +1 @@
+foo.bar()
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithoutArgs.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithoutArgs.txt
new file mode 100644
index 000000000..cc2832d53
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MethodCallWithoutArgs.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageCallExprImpl(CALL_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('foo')
+ PsiElement( ExpressionLanguageType.syntax)('.')
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('bar')
+ PsiElement( ExpressionLanguageType.()('(')
+ PsiElement( ExpressionLanguageType.))(')')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MinusExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MinusExpr.test
new file mode 100644
index 000000000..b8053d76d
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MinusExpr.test
@@ -0,0 +1 @@
+5 - 1
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MinusExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MinusExpr.txt
new file mode 100644
index 000000000..61e68e57e
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MinusExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageMinusExprImpl(MINUS_EXPR)
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('5')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.-)('-')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ModExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ModExpr.test
new file mode 100644
index 000000000..4f46f47c8
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ModExpr.test
@@ -0,0 +1 @@
+17 % 10
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ModExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ModExpr.txt
new file mode 100644
index 000000000..08d452431
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ModExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageModExprImpl(MOD_EXPR)
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('17')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.%)('%')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('10')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MulExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MulExpr.test
new file mode 100644
index 000000000..7e7c2074d
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MulExpr.test
@@ -0,0 +1 @@
+2 * 2
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MulExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MulExpr.txt
new file mode 100644
index 000000000..92c9355ee
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/MulExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageMulExprImpl(MUL_EXPR)
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('2')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.*)('*')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('2')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotEqExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotEqExpr.test
new file mode 100644
index 000000000..d40d18795
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotEqExpr.test
@@ -0,0 +1 @@
+a != b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotEqExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotEqExpr.txt
new file mode 100644
index 000000000..0d674c4cd
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotEqExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageNeqExprImpl(NEQ_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.!=)('!=')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotExpr.test
new file mode 100644
index 000000000..fa7cdb18c
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotExpr.test
@@ -0,0 +1 @@
+!a
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotExpr.txt
new file mode 100644
index 000000000..319cb8a82
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotExpr.txt
@@ -0,0 +1,6 @@
+Expression Language File
+ ExpressionLanguageNotExprImpl(NOT_EXPR)
+ PsiElement( ExpressionLanguageType.!)('!')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotIdenticalExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotIdenticalExpr.test
new file mode 100644
index 000000000..acd006279
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotIdenticalExpr.test
@@ -0,0 +1 @@
+a !== b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotIdenticalExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotIdenticalExpr.txt
new file mode 100644
index 000000000..21173c3d9
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotIdenticalExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageNotIdenticalExprImpl(NOT_IDENTICAL_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.!==)('!==')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotInExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotInExpr.test
new file mode 100644
index 000000000..fa7961a94
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotInExpr.test
@@ -0,0 +1 @@
+a not in b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotInExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotInExpr.txt
new file mode 100644
index 000000000..a7ee48d5a
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotInExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguageNotInExprImpl(NOT_IN_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.not in)('not in')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotKwExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotKwExpr.test
new file mode 100644
index 000000000..4a7240aa4
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotKwExpr.test
@@ -0,0 +1 @@
+not a
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotKwExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotKwExpr.txt
new file mode 100644
index 000000000..10f47b565
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NotKwExpr.txt
@@ -0,0 +1,7 @@
+Expression Language File
+ ExpressionLanguageNotExprImpl(NOT_EXPR)
+ PsiElement( ExpressionLanguageType.not)('not')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullLiteral.test
new file mode 100644
index 000000000..ec747fa47
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullLiteral.test
@@ -0,0 +1 @@
+null
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullLiteral.txt
new file mode 100644
index 000000000..c588739da
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNullLiteralImpl(NULL_LITERAL)
+ PsiElement( ExpressionLanguageType.null)('null')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullUppercaseLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullUppercaseLiteral.test
new file mode 100644
index 000000000..fe3a0735d
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullUppercaseLiteral.test
@@ -0,0 +1 @@
+NULL
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullUppercaseLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullUppercaseLiteral.txt
new file mode 100644
index 000000000..23c401175
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NullUppercaseLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNullLiteralImpl(NULL_LITERAL)
+ PsiElement( ExpressionLanguageType.null)('NULL')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteral.test
new file mode 100644
index 000000000..d8263ee98
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteral.test
@@ -0,0 +1 @@
+2
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteral.txt
new file mode 100644
index 000000000..83b27bf6c
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('2')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteralWithFraction.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteralWithFraction.test
new file mode 100644
index 000000000..d0d018ed5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteralWithFraction.test
@@ -0,0 +1 @@
+2.123
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteralWithFraction.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteralWithFraction.txt
new file mode 100644
index 000000000..9a1d1e447
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/NumberLiteralWithFraction.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('2.123')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/OrExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/OrExpr.test
new file mode 100644
index 000000000..87bcccb97
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/OrExpr.test
@@ -0,0 +1 @@
+a || b or c
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/OrExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/OrExpr.txt
new file mode 100644
index 000000000..9029447a6
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/OrExpr.txt
@@ -0,0 +1,18 @@
+Expression Language File
+ ExpressionLanguageOrExprImpl(OR_EXPR)
+ ExpressionLanguageOrExprImpl(OR_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.||)('||')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.or)('or')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('c')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ParenExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ParenExpr.test
new file mode 100644
index 000000000..17199769a
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ParenExpr.test
@@ -0,0 +1 @@
+(a + b) * c
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ParenExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ParenExpr.txt
new file mode 100644
index 000000000..d4ff26542
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/ParenExpr.txt
@@ -0,0 +1,21 @@
+Expression Language File
+ ExpressionLanguageMulExprImpl(MUL_EXPR)
+ ExpressionLanguageParenExprImpl(PAREN_EXPR)
+ PsiElement( ExpressionLanguageType.()('(')
+ ExpressionLanguagePlusExprImpl(PLUS_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.+)('+')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
+ PsiElement( ExpressionLanguageType.))(')')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.*)('*')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('c')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/PlusExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/PlusExpr.test
new file mode 100644
index 000000000..21e13ad67
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/PlusExpr.test
@@ -0,0 +1 @@
+5 + 1
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/PlusExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/PlusExpr.txt
new file mode 100644
index 000000000..4b1922be9
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/PlusExpr.txt
@@ -0,0 +1,11 @@
+Expression Language File
+ ExpressionLanguagePlusExprImpl(PLUS_EXPR)
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('5')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.+)('+')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/RangeExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/RangeExpr.test
new file mode 100644
index 000000000..09ecfe69b
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/RangeExpr.test
@@ -0,0 +1 @@
+a..b
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/RangeExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/RangeExpr.txt
new file mode 100644
index 000000000..7b9bfe3ae
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/RangeExpr.txt
@@ -0,0 +1,9 @@
+Expression Language File
+ ExpressionLanguageRangeExprImpl(RANGE_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiElement( ExpressionLanguageType...)('..')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringDoubleQuoteLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringDoubleQuoteLiteral.test
new file mode 100644
index 000000000..693cf43e5
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringDoubleQuoteLiteral.test
@@ -0,0 +1 @@
+"Hello World!"
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringDoubleQuoteLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringDoubleQuoteLiteral.txt
new file mode 100644
index 000000000..2079382a8
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringDoubleQuoteLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)('"Hello World!"')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringSingleQuoteLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringSingleQuoteLiteral.test
new file mode 100644
index 000000000..a691b75fe
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringSingleQuoteLiteral.test
@@ -0,0 +1 @@
+'Hello World!'
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringSingleQuoteLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringSingleQuoteLiteral.txt
new file mode 100644
index 000000000..6aef40b4d
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/StringSingleQuoteLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageStringLiteralImpl(STRING_LITERAL)
+ PsiElement( ExpressionLanguageType.string)(''Hello World!'')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TernaryExpr.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TernaryExpr.test
new file mode 100644
index 000000000..c3fdbcd74
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TernaryExpr.test
@@ -0,0 +1 @@
+a ? b : c
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TernaryExpr.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TernaryExpr.txt
new file mode 100644
index 000000000..a471a0a32
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TernaryExpr.txt
@@ -0,0 +1,17 @@
+Expression Language File
+ ExpressionLanguageTernaryExprImpl(TERNARY_EXPR)
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('a')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.syntax)('?')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('b')
+ PsiWhiteSpace(' ')
+ PsiElement( ExpressionLanguageType.syntax)(':')
+ PsiWhiteSpace(' ')
+ ExpressionLanguageRefExprImpl(REF_EXPR)
+ ExpressionLanguageIdentifierImpl(IDENTIFIER)
+ PsiElement( ExpressionLanguageType.id)('c')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueLiteral.test
new file mode 100644
index 000000000..f32a5804e
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueLiteral.test
@@ -0,0 +1 @@
+true
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueLiteral.txt
new file mode 100644
index 000000000..c60aeee81
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageBooleanLiteralImpl(BOOLEAN_LITERAL)
+ PsiElement( ExpressionLanguageType.true)('true')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueUppercaseLiteral.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueUppercaseLiteral.test
new file mode 100644
index 000000000..51cb8b0f7
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueUppercaseLiteral.test
@@ -0,0 +1 @@
+TRUE
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueUppercaseLiteral.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueUppercaseLiteral.txt
new file mode 100644
index 000000000..bb5a4388c
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/TrueUppercaseLiteral.txt
@@ -0,0 +1,4 @@
+Expression Language File
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageBooleanLiteralImpl(BOOLEAN_LITERAL)
+ PsiElement( ExpressionLanguageType.true)('TRUE')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryMinus.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryMinus.test
new file mode 100644
index 000000000..d7d17fcbe
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryMinus.test
@@ -0,0 +1 @@
+-1
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryMinus.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryMinus.txt
new file mode 100644
index 000000000..6f6a71b32
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryMinus.txt
@@ -0,0 +1,6 @@
+Expression Language File
+ ExpressionLanguageUnaryMinExprImpl(UNARY_MIN_EXPR)
+ PsiElement( ExpressionLanguageType.-)('-')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryPlus.test b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryPlus.test
new file mode 100644
index 000000000..c57a1950b
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryPlus.test
@@ -0,0 +1 @@
++1
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryPlus.txt b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryPlus.txt
new file mode 100644
index 000000000..b72f840b8
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/expressionLanguage/testData/UnaryPlus.txt
@@ -0,0 +1,6 @@
+Expression Language File
+ ExpressionLanguageUnaryPlusExprImpl(UNARY_PLUS_EXPR)
+ PsiElement( ExpressionLanguageType.+)('+')
+ ExpressionLanguageLiteralExprImpl(LITERAL_EXPR)
+ ExpressionLanguageNumberLiteralImpl(NUMBER_LITERAL)
+ PsiElement( ExpressionLanguageType.number)('1')
\ No newline at end of file
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/ParameterLanguageInjectorTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/ParameterLanguageInjectorTest.java
index dd1598d90..615d5d1e3 100644
--- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/ParameterLanguageInjectorTest.java
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/ParameterLanguageInjectorTest.java
@@ -6,9 +6,12 @@
import com.jetbrains.php.lang.PhpFileType;
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
import junit.framework.TestCase;
+import org.junit.Ignore;
import static fr.adrienbrault.idea.symfony2plugin.lang.ParameterLanguageInjector.*;
+@Deprecated
+@Ignore("ParameterLanguageInjectorTest is deprecated")
public class ParameterLanguageInjectorTest extends SymfonyLightCodeInsightFixtureTestCase {
private InjectionTestFixture injectionTestFixture;
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/StringLiteralLanguageInjectorTest.java b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/StringLiteralLanguageInjectorTest.java
new file mode 100644
index 000000000..b709985f7
--- /dev/null
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/StringLiteralLanguageInjectorTest.java
@@ -0,0 +1,403 @@
+package fr.adrienbrault.idea.symfony2plugin.tests.lang;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.testFramework.fixtures.InjectionTestFixture;
+import com.jetbrains.php.lang.PhpFileType;
+import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
+import junit.framework.TestCase;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static fr.adrienbrault.idea.symfony2plugin.lang.StringLiteralLanguageInjector.LANGUAGE_ID_CSS;
+import static fr.adrienbrault.idea.symfony2plugin.lang.StringLiteralLanguageInjector.LANGUAGE_ID_DQL;
+import static fr.adrienbrault.idea.symfony2plugin.lang.StringLiteralLanguageInjector.LANGUAGE_ID_EXPRESSION_LANGUAGE;
+import static fr.adrienbrault.idea.symfony2plugin.lang.StringLiteralLanguageInjector.LANGUAGE_ID_JSON;
+import static fr.adrienbrault.idea.symfony2plugin.lang.StringLiteralLanguageInjector.LANGUAGE_ID_XPATH;
+
+public class StringLiteralLanguageInjectorTest extends SymfonyLightCodeInsightFixtureTestCase {
+
+ private InjectionTestFixture injectionTestFixture;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ myFixture.copyFileToProject("classes.php");
+ injectionTestFixture = new InjectionTestFixture(myFixture);
+ }
+
+ public String getTestDataPath() {
+ return "src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/fixtures";
+ }
+
+ public void skipTestCssLanguageInjections() {
+ // skip as we dont have CSS module in >= 2020 test builds
+ String base = "filter('html > body');", LANGUAGE_ID_CSS);
+ assertInjectedLangAtCaret(base + "$c->filter('');", LANGUAGE_ID_CSS);
+ assertInjectedLangAtCaret(base + "$c->children('html > body');", LANGUAGE_ID_CSS);
+ assertInjectedLangAtCaret(base + "$c->children('');", LANGUAGE_ID_CSS);
+
+ base = "toXPath('html > body');", LANGUAGE_ID_CSS);
+ assertInjectedLangAtCaret(base + "$c->toXPath('');", LANGUAGE_ID_CSS);
+ }
+
+ public void testXPathLanguageInjections() {
+ String base = "filterXPath('//dummy');", LANGUAGE_ID_XPATH);
+ assertInjectedLangAtCaret(base + "$c->filterXPath('');", LANGUAGE_ID_XPATH);
+ assertInjectedLangAtCaret(base + "$c->evaluate('//dummy');", LANGUAGE_ID_XPATH);
+ assertInjectedLangAtCaret(base + "$c->evaluate('');", LANGUAGE_ID_XPATH);
+ }
+
+ public void testJsonLanguageInjections() {
+ String base = "');", LANGUAGE_ID_JSON);
+ assertInjectedLangAtCaret(base + "JsonResponse::fromJsonString('{\"foo\": }');", LANGUAGE_ID_JSON);
+
+ base = "setJson('');", LANGUAGE_ID_JSON);
+ assertInjectedLangAtCaret(base + "$r->setJson('{\"foo\": }');", LANGUAGE_ID_JSON);
+ }
+
+ public void testDqlLanguageInjections() {
+ String base = "createQuery('SELECT b FROM \\Foo\\Bar b');", LANGUAGE_ID_DQL);
+ assertInjectedLangAtCaret(base + "$em->createQuery('');", LANGUAGE_ID_DQL);
+ assertInjectedLangAtCaret(base + "$em->createQuery(<<createQuery(<<T\nAAA\n);", "SELECT");
+ assertInjectedFragmentText(base + "$em->createQuery(<<<'AAA'\nSELECT a\nAAA\n);", "SELECT a");
+ base = "setDQL('SELECT b FROM \\Foo\\Bar b');", LANGUAGE_ID_DQL);
+ assertInjectedLangAtCaret(base + "$q->setDQL('');", LANGUAGE_ID_DQL);
+
+ assertInjectedLangAtCaret("OM \\Foo\\Bar b\");", LANGUAGE_ID_DQL);
+ assertInjectedLangAtCaret("\");", LANGUAGE_ID_DQL);
+ }
+
+ public void testExpressionLanguageLanguageInjections() {
+ assertInjectedLangAtCaret(
+ "');",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "evaluate('');\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "compile('');\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "parse('');\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "condition('');\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "condition(condition: '');\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")]\n" +
+ " public function contact() {}\n" +
+ "}\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "')]\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")]\n" +
+ "class BlogPost {}\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ " '']);\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ "class BlogPost {}\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ "class BlogPost {}\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")]\n" +
+ "class BlogPost {}\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")]\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")]\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "')]\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "')]\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ " public function contact() {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "')]\n" +
+ " public function contact($post) {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "')]\n" +
+ " public function contact($post) {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\")\n" +
+ " */\n" +
+ " public function contact($post) {}\n" +
+ "}",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\");\n",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+
+ assertInjectedLangAtCaret(
+ "\");",
+ LANGUAGE_ID_EXPRESSION_LANGUAGE
+ );
+ }
+
+ private void assertInjectedLangAtCaret(@NotNull String configureByText, @Nullable String lang) {
+ myFixture.configureByText(PhpFileType.INSTANCE, configureByText);
+ injectionTestFixture.assertInjectedLangAtCaret(lang);
+ }
+
+ private void assertInjectedFragmentText(@NotNull String configureByText, String text) {
+ myFixture.configureByText(PhpFileType.INSTANCE, configureByText);
+ PsiElement injectedElement = injectionTestFixture.getInjectedElement();
+ assertNotNull(injectedElement);
+ TestCase.assertEquals(text, injectedElement.getContainingFile().getText());
+ }
+}
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/fixtures/classes.php b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/fixtures/classes.php
index b113d0fa9..0efda91dd 100644
--- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/fixtures/classes.php
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/lang/fixtures/classes.php
@@ -23,6 +23,143 @@ public static function fromJsonString() {}
public function setJson() {}
}
}
+
+namespace Symfony\Component\DependencyInjection\Loader\Configurator {
+ function expr(string $expression) {}
+}
+
+namespace Symfony\Component\ExpressionLanguage {
+ class ExpressionLanguage
+ {
+ public function compile($expression, array $names = []) {}
+ public function evaluate($expression, array $values = []) {}
+ public function parse($expression, array $names = []) {}
+ }
+
+ class Expression
+ {
+ public function __construct(string $expression) {}
+ }
+}
+
+namespace Symfony\Component\Routing\Annotation {
+ /**
+ * @Annotation
+ * @Target({"CLASS", "METHOD"})
+ */
+ #[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
+ class Route
+ {
+ public function __construct(
+ $data = [],
+ $path = null,
+ string $name = null,
+ array $requirements = [],
+ array $options = [],
+ array $defaults = [],
+ string $host = null,
+ array $methods = [],
+ array $schemes = [],
+ string $condition = null,
+ int $priority = null,
+ string $locale = null,
+ string $format = null,
+ bool $utf8 = null,
+ bool $stateless = null
+ ) {}
+ }
+}
+
+namespace Symfony\Component\Routing\Loader\Configurator\Traits {
+ trait RouteTrait
+ {
+ public function condition(string $condition): {}
+ }
+}
+
+namespace Symfony\Component\Routing\Loader\Configurator {
+ class RoutingConfigurator
+ {
+ use \Symfony\Component\Routing\Loader\Configurator\Traits\RouteTrait;
+ }
+}
+
+namespace Symfony\Component\Validator\Constraints {
+ /**
+ * @Annotation
+ * @Target({"CLASS", "PROPERTY", "METHOD", "ANNOTATION"})
+ */
+ #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
+ class Expression
+ {
+ public function __construct(
+ $expression,
+ string $message = null,
+ array $values = null,
+ array $groups = null,
+ $payload = null,
+ array $options = []
+ ) {}
+ }
+}
+
+namespace Sensio\Bundle\FrameworkExtraBundle\Configuration {
+ /**
+ * @Annotation
+ */
+ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
+ class Cache
+ {
+ public function __construct(
+ array $values = [],
+ string $expires = null,
+ $maxage = null,
+ $smaxage = null,
+ bool $public = null,
+ bool $mustRevalidate = null,
+ array $vary = null,
+ string $lastModified = null,
+ string $etag = null,
+ $maxstale = null,
+ $staleWhileRevalidate = null,
+ $staleIfError = null
+ ) {}
+ }
+
+ /**
+ * @Annotation
+ */
+ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
+ class Entity {
+ public function __construct(
+ $data = [],
+ string $expr = null,
+ string $class = null,
+ array $options = [],
+ bool $isOptional = false,
+ string $converter = null
+ ) {}
+ }
+
+ /**
+ * @Annotation
+ */
+ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
+ class Security
+ {
+ public function __construct(
+ $data = [],
+ string $message = null,
+ ?int $statusCode = null
+ ) {}
+ }
+
+ /**
+ * @Annotation
+ */
+ class Route extends \Symfony\Component\Routing\Annotation\Route {}
+}
+
namespace Doctrine\ORM {
class EntityManager {
public function createQuery() {}
diff --git a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/security/fixtures/security.yml b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/security/fixtures/security.yml
index 5e89380a5..87f829b43 100644
--- a/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/security/fixtures/security.yml
+++ b/src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/security/fixtures/security.yml
@@ -1,3 +1,4 @@
security:
access_control:
- { path: /foobar, roles: YAML_ROLE_USER_FOOBAR }
+ - { path: /foo, roles: YAML_ROLE_USER_FOO }
\ No newline at end of file