Skip to content

Commit

Permalink
Support {element} and {@State}
Browse files Browse the repository at this point in the history
Partly fixes google#172
  • Loading branch information
Alexander Pavlov committed Dec 20, 2019
1 parent cc62277 commit 227f22f
Show file tree
Hide file tree
Showing 27 changed files with 1,065 additions and 83 deletions.
67 changes: 49 additions & 18 deletions src/main/grammars/Soy.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
elementTypeClass="com.google.bamboo.soy.parser.SoyElementType"
tokenTypeClass="com.google.bamboo.soy.lexer.SoyTokenType"

implements("Begin.*|.*Tag|.*Block")="com.google.bamboo.soy.elements.TagElement"
implements("Begin.*|.*Tag|(Namespace|Alias|DelegatePackage)Block")="com.google.bamboo.soy.elements.TagElement"
implements("(Css|LetSingle|SpecialCharacter|Xid|Print)Statement")
= ["com.google.bamboo.soy.elements.StatementElement" "com.google.bamboo.soy.elements.TagElement"]
implements("LiteralStatement") = ["com.google.bamboo.soy.elements.StatementElement"]
implements(".*Statement")
implements("(Call|Choice|For|Foreach|If|LetCompound|Literal|Msg)Statement")
= ["com.google.bamboo.soy.elements.StatementElement" "com.google.bamboo.soy.elements.TagBlockElement"]

extends(".*Expr|VariableReferenceIdentifier")=Expr
Expand All @@ -31,6 +31,7 @@
AS = "as"
AT_PARAM = "@param"
AT_PARAM_OPT = "@param?"
AT_STATE = "@state"
AT_INJECT = "@inject"
AT_INJECT_OPT = "@inject?"
BOOL_LITERAL = "regexp:false|true"
Expand All @@ -39,6 +40,7 @@
CARRIAGE_RETURN = "\\r"
CASE = "case"
COLON = ":"
COLON_EQUAL = ":="
COMMA = ","
CSS="css"
DEFAULT = "default"
Expand All @@ -48,6 +50,7 @@
DOLLAR = "$"
DOT = "."
DOT_NULL_CHECK = "?."
ELEMENT = "element"
ELSE = "else"
ELSEIF = "elseif"
EQUAL = "="
Expand Down Expand Up @@ -340,13 +343,14 @@ private AliasBody ::= ALIAS NamespaceIdentifier [AS AliasIdentifier] {

// Template block

TemplateBlock ::= LocalTemplateBlock | DelegateTemplateBlock {
TemplateBlock ::= LocalTemplateBlock | DelegateTemplateBlock | LocalElementBlock {
mixin="com.google.bamboo.soy.elements.impl.TemplateBlockMixin"
implements="com.google.bamboo.soy.elements.TemplateBlockElement"
stubClass = "com.google.bamboo.soy.stubs.TemplateBlockStub"
elementTypeFactory = "com.google.bamboo.soy.stubs.StubFactory.getType"
}

private LocalElementBlock ::= <<AbstractElementBlock ELEMENT>>
private LocalTemplateBlock ::= <<AbstractTemplateBlock TEMPLATE>>
private DelegateTemplateBlock ::= <<AbstractTemplateBlock DELTEMPLATE>>

Expand All @@ -358,6 +362,14 @@ private meta AbstractTemplateBlock ::=
pin = 1
}

private meta AbstractElementBlock ::=
<<BeginTemplate <<p>>>>
[AtParamOrStateList]
[<<StatementList !()>>]
<<EndTag <<p>>>> {
pin = 1
}

meta BeginTemplate ::= <<BracedTag <<BeginTemplateBody<<p>>>>>> {
hooks = [wsBinders = "LEADING_COMMENTS_BINDER, TRAILING_COMMENTS_BINDER"]
}
Expand All @@ -369,6 +381,8 @@ private meta BeginTemplateBody ::= <<p>> (TemplateDefinitionIdentifier [Attribut

private AtParamList ::= (AtParamSingle | AtInjectSingle)+

private AtParamOrStateList ::= (AtParamSingle | AtInjectSingle | AtStateSingle)+

AtParamSingle ::= <<BracedTag AtParamBody>> {
implements = "com.google.bamboo.soy.elements.AtParamElement"
mixin = "com.google.bamboo.soy.elements.impl.AtParamMixin"
Expand All @@ -382,6 +396,19 @@ private AtParamBody ::= (AT_PARAM | AT_PARAM_OPT) ParamDefinitionIdentifier COLO
recoverWhile = "recoverEndOfTag"
}

AtStateSingle ::= <<BracedTag AtStateBody>> {
implements = "com.google.bamboo.soy.elements.AtStateElement"
mixin = "com.google.bamboo.soy.elements.impl.AtStateMixin"
stubClass = "com.google.bamboo.soy.stubs.AtStateStub"
elementTypeFactory = "com.google.bamboo.soy.stubs.StubFactory.getType"
hooks = [wsBinders = "LEADING_COMMENTS_BINDER, TRAILING_COMMENTS_BINDER"]
}

private AtStateBody ::= (AT_STATE) ParamDefinitionIdentifier (COLON TypeExpression EQUAL ValueLiteral | COLON_EQUAL ValueLiteral) {
pin = 1
recoverWhile = "recoverEndOfTag"
}

AtInjectSingle ::= <<BracedTag AtInjectBody>> {
implements = "com.google.bamboo.soy.elements.AtInjectElement"
mixin = "com.google.bamboo.soy.elements.impl.AtInjectMixin"
Expand Down Expand Up @@ -430,6 +457,24 @@ private Content ::= OTHER
private Statement ::=
SingleTagStatement
|
BlockTagStatement
|
Content


private SingleTagStatement ::=
CssStatement
|
LetSingleStatement
|
SpecialCharacterStatement
|
XidStatement
|
PrintStatement


private BlockTagStatement ::=
CallStatement
|
ChoiceStatement
Expand All @@ -445,20 +490,6 @@ private Statement ::=
LiteralStatement
|
MsgStatement
|
Content


private SingleTagStatement ::=
CssStatement
|
LetSingleStatement
|
SpecialCharacterStatement
|
XidStatement
|
PrintStatement


// Same as StatementList but cannot empty.
Expand Down Expand Up @@ -616,7 +647,7 @@ private ParamList ::=
recoverWhile = "!(endOfStatementBlock)"
}

ParamListElement ::= !<<ClosedBracedTag BeginParamTagBody>> BlockParamListElement | BeginParamTag {
ParamListElement ::= !(<<ClosedBracedTag BeginParamTagBody>>) BlockParamListElement | BeginParamTag {
implements = "com.google.bamboo.soy.elements.ParamElement"
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/grammars/Soy.flex
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ NonSemantical=({WhiteSpace}|{DoubleSlashComment}|{DocComment}|{Comment})*
"deltemplate"/{NonSemantical}{QualifiedIdentifier} { yybegin(TAG_QUALIFIED_IDENTIFIER); return SoyTypes.DELTEMPLATE; }
"namespace"/{NonSemantical}{QualifiedIdentifier} { yybegin(TAG_QUALIFIED_IDENTIFIER); return SoyTypes.NAMESPACE; }
"template"/{NonSemantical}{QualifiedIdentifier} { yybegin(TAG_QUALIFIED_IDENTIFIER); return SoyTypes.TEMPLATE; }
"element"/{NonSemantical}{QualifiedIdentifier} { yybegin(TAG_QUALIFIED_IDENTIFIER); return SoyTypes.ELEMENT; }

"alias" { return SoyTypes.ALIAS; }
"call" { return SoyTypes.CALL; }
Expand All @@ -123,6 +124,7 @@ NonSemantical=({WhiteSpace}|{DoubleSlashComment}|{DocComment}|{Comment})*
"deltemplate" { return SoyTypes.DELTEMPLATE; }
"namespace" { return SoyTypes.NAMESPACE; }
"template" { return SoyTypes.TEMPLATE; }
"element" { return SoyTypes.ELEMENT; }

/* Tag names that may be followed by CSS or Xid identifier */
"css"/{NonSemantical}{WhiteSpace}{CssXidIdentifier} { yybegin(TAG_CSS_XID); return SoyTypes.CSS; }
Expand All @@ -136,6 +138,7 @@ NonSemantical=({WhiteSpace}|{DoubleSlashComment}|{DocComment}|{Comment})*
"@inject?" { return SoyTypes.AT_INJECT_OPT; }
"@param" { return SoyTypes.AT_PARAM; }
"@param?" { return SoyTypes.AT_PARAM_OPT; }
"@state" { return SoyTypes.AT_STATE; }
"case" { return SoyTypes.CASE; }
"default" { return SoyTypes.DEFAULT; }

Expand Down Expand Up @@ -210,6 +213,7 @@ NonSemantical=({WhiteSpace}|{DoubleSlashComment}|{DocComment}|{Comment})*

"=" { return SoyTypes.EQUAL; }
":" { return SoyTypes.COLON; }
":=" { return SoyTypes.COLON_EQUAL; }
"?" { return SoyTypes.QUESTIONMARK; }
"?:" { return SoyTypes.TERNARY_COALESCER; }

Expand Down
60 changes: 60 additions & 0 deletions src/main/java/com/google/bamboo/soy/elements/AtStateElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.bamboo.soy.elements;

import com.google.bamboo.soy.lang.Parameter;
import com.google.bamboo.soy.lang.StateVariable;
import com.google.bamboo.soy.parser.SoyParamDefinitionIdentifier;
import com.google.bamboo.soy.parser.SoyTypeExpression;
import com.google.bamboo.soy.parser.SoyTypes;
import com.google.bamboo.soy.stubs.AtParamStub;
import com.google.bamboo.soy.stubs.AtStateStub;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.StubBasedPsiElement;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public interface AtStateElement extends StubBasedPsiElement<AtStateStub>, PsiNamedElement,
TagElement {

@Nullable
SoyParamDefinitionIdentifier getParamDefinitionIdentifier();

@Nullable
SoyTypeExpression getTypeExpression();

default PsiElement setName(@NotNull String s) throws IncorrectOperationException {
return null;
}

@NotNull
default String getType() {
if (getStub() != null) {
return getStub().type;
}
if (getTypeExpression() != null) {
return getTypeExpression().getText();
}
return "";
}

default StateVariable toStateVariable() {
return this.getParamDefinitionIdentifier() == null
? null
: new StateVariable(getName(), getType(), this.getParamDefinitionIdentifier());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.google.bamboo.soy.lang.Variable;
import com.google.bamboo.soy.parser.SoyAtInjectSingle;
import com.google.bamboo.soy.parser.SoyAtParamSingle;
import com.google.bamboo.soy.parser.SoyAtStateSingle;
import com.google.bamboo.soy.parser.SoyTemplateDefinitionIdentifier;
import com.google.bamboo.soy.parser.SoyTypes;
import com.google.bamboo.soy.stubs.TemplateBlockStub;
Expand Down Expand Up @@ -46,6 +47,9 @@ public interface TemplateBlockElement
@NotNull
List<SoyAtParamSingle> getAtParamSingleList();

@NotNull
List<SoyAtStateSingle> getAtStateSingleList();

@Override
default PsiElement setName(@NotNull String s) throws IncorrectOperationException {
return null;
Expand Down Expand Up @@ -84,6 +88,7 @@ default List<Variable> getLocalVariables() {
List<Variable> variables = new ArrayList<>();
variables.addAll(getParameters());
variables.addAll(getInjectedVariables());
variables.addAll(getStateVariables());
return variables;
}

Expand All @@ -94,4 +99,12 @@ default List<Variable> getInjectedVariables() {
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

default List<Variable> getStateVariables() {
return getAtStateSingleList()
.stream()
.map(SoyAtStateSingle::toStateVariable)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.bamboo.soy.elements.impl;

import com.google.bamboo.soy.elements.AtParamElement;
import com.google.bamboo.soy.elements.AtStateElement;
import com.google.bamboo.soy.parser.SoyParamDefinitionIdentifier;
import com.google.bamboo.soy.parser.SoyTypeExpression;
import com.google.bamboo.soy.stubs.AtParamStub;
import com.google.bamboo.soy.stubs.AtStateStub;
import com.intellij.lang.ASTNode;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public abstract class AtStateMixin extends SoyStubBasedPsiElementBase<AtStateStub>
implements AtStateElement {

public AtStateMixin(AtStateStub stub, IStubElementType type) {
super(stub, type);
}

public AtStateMixin(ASTNode node) {
super(node);
}

public AtStateMixin(AtStateStub stub, IElementType type, ASTNode node) {
super(stub, type, node);
}

@NotNull
@Override
public String getName() {
if (getStub() != null) {
return getStub().getName();
}
if (getParamDefinitionIdentifier() != null) {
return getParamDefinitionIdentifier().getName();
}
return "";
}

@Nullable
@Override
public SoyParamDefinitionIdentifier getParamDefinitionIdentifier() {
return PsiTreeUtil.getChildOfType(this, SoyParamDefinitionIdentifier.class);
}

@Nullable
@Override
public SoyTypeExpression getTypeExpression() {
return PsiTreeUtil.getChildOfType(this, SoyTypeExpression.class);
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/google/bamboo/soy/format/SoySpacing.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static SpacingBuilder getSpacingBuilder(CommonCodeStyleSettings settings)

// Left brace should not be followed by whitespace.
.after(SoyTokenTypes.LEFT_BRACES).spacing(0, 0, 0, false, 0)
// /} and /} should be preceded by a space.
// /} and /}} should be preceded by a space.
.before(SoyTokenTypes.SLASH_R_BRACES).spacing(1, 1, 0, false, 0)
// } and }} should not be preceded by whitespace.
.before(SoyTokenTypes.RIGHT_BRACES).spacing(0, 0, 0, false, 0)
Expand All @@ -51,6 +51,7 @@ public static SpacingBuilder getSpacingBuilder(CommonCodeStyleSettings settings)
.around(SoyTypes.NAMESPACE_BLOCK).lineBreakInCode()
.around(SoyTypes.AT_INJECT_SINGLE).lineBreakInCode()
.around(SoyTypes.AT_PARAM_SINGLE).lineBreakInCode()
.around(SoyTypes.AT_STATE_SINGLE).lineBreakInCode()
.around(SoyTypes.CHOICE_CLAUSE).lineBreakInCode()
.around(SoyTypes.PARAM_LIST_ELEMENT).lineBreakInCode()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.bamboo.soy.format.SoySpacing;
import com.google.bamboo.soy.parser.SoyAtInjectSingle;
import com.google.bamboo.soy.parser.SoyAtParamSingle;
import com.google.bamboo.soy.parser.SoyAtStateSingle;
import com.google.bamboo.soy.parser.SoyChoiceClause;
import com.google.bamboo.soy.parser.SoyStatementList;
import com.google.bamboo.soy.parser.SoyTypes;
Expand Down Expand Up @@ -74,6 +75,7 @@ private static boolean isAlwaysIndented(PsiElement element) {
return element instanceof ParamElement
|| element instanceof SoyAtParamSingle
|| element instanceof SoyAtInjectSingle
|| element instanceof SoyAtStateSingle
|| element instanceof SoyChoiceClause;
}

Expand Down
Loading

0 comments on commit 227f22f

Please sign in to comment.