Component attr values should be working.

This commit is contained in:
JesseBrault0709 2024-05-31 08:49:17 +02:00
parent 58e9f60530
commit 5ada84dfed
18 changed files with 397 additions and 4 deletions

View File

@ -23,6 +23,7 @@ channels {
@header { @header {
import java.util.Set; import java.util.Set;
import groowt.view.component.web.WebViewComponentBugError;
import static groowt.view.component.web.antlr.LexerSemanticPredicates.*; import static groowt.view.component.web.antlr.LexerSemanticPredicates.*;
} }
@ -109,6 +110,10 @@ channels {
this.pushMode(GROOVY_CODE); this.pushMode(GROOVY_CODE);
} }
private boolean inAttrComponent() {
return this.peekMode(1) == COMPONENT_ATTR_VALUE;
}
} }
// ---------------------------------------- // ----------------------------------------
@ -262,11 +267,30 @@ TagStartError
mode IN_TAG; mode IN_TAG;
ComponentClose ComponentClose
: GT -> popMode : GT
{
if (this.inAttrComponent() && this.attrComponentFinished()) {
this.popMode();
this.popMode();
} else {
this.popMode();
}
}
; ;
ComponentSelfClose ComponentSelfClose
: FS GT -> popMode : FS GT
{
if (this.inAttrComponent()) {
this.exitAttrComponent();
if (this.attrComponentFinished()) {
this.popMode();
this.popMode();
}
} else {
this.popMode();
}
}
; ;
ConstructorOpen ConstructorOpen
@ -313,10 +337,14 @@ ClosureAttrValueStart
ComponentAttrValueStart ComponentAttrValueStart
: LEFT_CURLY InTagNlws? { this.isNext('<') }? : LEFT_CURLY InTagNlws? { this.isNext('<') }?
{
this.enterAttrComponent();
this.pushMode(COMPONENT_ATTR_VALUE);
}
; ;
ComponentAttrValueEnd ComponentAttrValueEnd
: GT RIGHT_CURLY : InTagNlws? RIGHT_CURLY { this.popAttrComponent(); }
; ;
InTagNlws InTagNlws
@ -327,6 +355,85 @@ TagError
: . -> channel(ERROR) : . -> channel(ERROR)
; ;
// ----------------------------------------
mode COMPONENT_ATTR_VALUE;
AttrComponentOpen
: LT { !isAnyOf(this.getNextChar(), '/', '>') }? -> type(ComponentOpen), pushMode(TAG_START)
;
AttrClosingComponentOpen
: LT FS { !this.isNext('>') }?
{
this.exitAttrComponent();
} -> type(ClosingComponentOpen), pushMode(TAG_START)
;
AttrFragmentOpen
: LT GT -> type(FragmentOpen)
;
AttrFragmentClose
: LT FS GT {
this.exitAttrComponent();
} -> type(FragmentClose), popMode
;
AttrEqualsScriptletOpen
: LT PERCENT EQ -> type(EqualsScriptletOpen), pushMode(GROOVY_CODE)
;
AttrPlainScriptletOpen
: LT PERCENT -> type(PlainScriptletOpen), pushMode(GROOVY_CODE)
;
AttrDollarScriptletOpen
: DOLLAR LEFT_CURLY {
this.curlies.push(() -> {
this.setType(DollarScriptletClose);
this.popMode();
});
this.curlies.increment();
this.setType(DollarScriptletOpen);
this.pushMode(GROOVY_CODE);
}
;
AttrDollarReferenceStart
: DOLLAR { isGStringIdentifierStartChar(this.getNextChar()) }?
-> type(DollarReferenceStart), pushMode(IN_G_STRING_PATH)
;
AttrQuestionTagOpen
: LT QUESTION -> type(QuestionTagOpen)
;
AttrQuestionTagClose
: QUESTION GT -> type(QuestionTagClose)
;
AttrHtmlCommentOpen
: LT BANG TWO_DASH -> type(HtmlCommentOpen)
;
AttrHtmlCommentClose
: TWO_DASH GT -> type(HtmlCommentClose)
;
AttrRawText
: ( ~[-<$?]
| MINUS { !this.isNext("->") }?
| LT { canFollowLessThan(this.getNextCharAsString()) }?
| LT BANG { !this.isNext("--") }?
| DOLLAR { !(this.isNext('{') || isIdentifierStartChar(this.getNextChar())) }?
| QUESTION { !this.isNext('>') }?
)+ -> type(RawText)
;
AttrError
: . -> type(ErrorChar), channel(ERROR)
;
// ---------------------------------------- // ----------------------------------------
mode GROOVY_CODE; mode GROOVY_CODE;
@ -542,8 +649,11 @@ GStringPathEnd
yield new StringContinueEndSpec(); yield new StringContinueEndSpec();
} }
} }
case COMPONENT_ATTR_VALUE -> new StringContinueEndSpec();
case MAIN -> new StringContinueEndSpec(); case MAIN -> new StringContinueEndSpec();
default -> throw new IllegalStateException("not a valid gString context: " + this.getModeName(this.peekMode(1))); default -> throw new IllegalStateException(
"not a valid gStringPath context: " + this.getModeName(this.peekMode(1))
);
}; };
switch (endSpec) { switch (endSpec) {
case StringContinueEndSpec ignored -> { case StringContinueEndSpec ignored -> {

View File

@ -1,6 +1,7 @@
package groowt.view.component.web.antlr; package groowt.view.component.web.antlr;
import groovyjarjarantlr4.runtime.Token; import groovyjarjarantlr4.runtime.Token;
import groowt.view.component.web.WebViewComponentBugError;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.atn.ATN; import org.antlr.v4.runtime.atn.ATN;
@ -13,6 +14,7 @@ import org.slf4j.LoggerFactory;
import java.util.Arrays; import java.util.Arrays;
import java.util.Deque; import java.util.Deque;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -57,6 +59,8 @@ public abstract class AbstractWebViewComponentsLexer extends Lexer {
private boolean canPreamble = true; private boolean canPreamble = true;
private boolean inPreamble; private boolean inPreamble;
private boolean inConstructor; private boolean inConstructor;
private Deque<AtomicBoolean> attrComponentFinishedStack = new LinkedList<>();
public AbstractWebViewComponentsLexer(CharStream input) { public AbstractWebViewComponentsLexer(CharStream input) {
super(input); super(input);
@ -115,6 +119,14 @@ public abstract class AbstractWebViewComponentsLexer extends Lexer {
this.inConstructor = inConstructor; this.inConstructor = inConstructor;
} }
public Deque<AtomicBoolean> getAttrComponentFinishedStack() {
return this.attrComponentFinishedStack;
}
public void setAttrComponentFinishedStack(Deque<AtomicBoolean> attrComponentFinishedStack) {
this.attrComponentFinishedStack = attrComponentFinishedStack;
}
@Override @Override
public void reset() { public void reset() {
this.curlies.clear(); this.curlies.clear();
@ -122,6 +134,7 @@ public abstract class AbstractWebViewComponentsLexer extends Lexer {
this.canPreamble = true; this.canPreamble = true;
this.inPreamble = false; this.inPreamble = false;
this.inConstructor = false; this.inConstructor = false;
this.attrComponentFinishedStack = new LinkedList<>();
super.reset(); super.reset();
} }
@ -204,6 +217,30 @@ public abstract class AbstractWebViewComponentsLexer extends Lexer {
this.inConstructor = false; this.inConstructor = false;
} }
protected void enterAttrComponent() {
this.attrComponentFinishedStack.push(new AtomicBoolean());
}
protected void exitAttrComponent() {
final AtomicBoolean attrComponentFinished = this.attrComponentFinishedStack.peek();
if (attrComponentFinished == null) {
throw new WebViewComponentBugError(new IllegalStateException());
}
attrComponentFinished.set(true);
}
protected boolean attrComponentFinished() {
final AtomicBoolean attrComponentFinished = this.attrComponentFinishedStack.peek();
if (attrComponentFinished == null) {
throw new WebViewComponentBugError(new IllegalStateException());
}
return attrComponentFinished.get();
}
protected void popAttrComponent() {
this.attrComponentFinishedStack.pop();
}
protected String getNextCharsAsString(int numberOfChars) { protected String getNextCharsAsString(int numberOfChars) {
final var b = new StringBuilder(); final var b = new StringBuilder();
for (int i = 1; i <= numberOfChars; i++) { for (int i = 1; i <= numberOfChars; i++) {
@ -224,6 +261,10 @@ public abstract class AbstractWebViewComponentsLexer extends Lexer {
return this._input.LA(1); return this._input.LA(1);
} }
protected boolean isPrevious(char test) {
return this._input.LA(-2) == test;
}
protected boolean isNext(char test) { protected boolean isNext(char test) {
return this._input.LA(1) == test; return this._input.LA(1) == test;
} }

View File

@ -0,0 +1 @@
<Test transform={<p>$it</p>} />

View File

@ -0,0 +1 @@
<Test transform={<Test transform={<Test />} />} />

View File

@ -0,0 +1 @@
<Test transform={<Test transform={<p>$it</p>} />} />

View File

@ -0,0 +1 @@
<Test transform={<Test />} />

View File

@ -0,0 +1 @@
<Test test={ <Test /> } />

View File

@ -0,0 +1,27 @@
0: ComponentOpen[1,1](<)
1: TypedIdentifier[1,2](Test)
2: Nlws[1,6]( )
3: AttributeIdentifier[1,7](transform)
4: Equals[1,16](=)
5: ComponentAttrValueStart[1,17]({)
6: ComponentOpen[1,18](<)
7: TypedIdentifier[1,19](Test)
8: Nlws[1,23]( )
9: AttributeIdentifier[1,24](transform)
10: Equals[1,33](=)
11: ComponentAttrValueStart[1,34]({)
12: ComponentOpen[1,35](<)
13: StringIdentifier[1,36](p)
14: ComponentClose[1,37](>)
15: DollarReferenceStart[1,38]($)
16: GroovyCode[1,39](it)
17: ClosingComponentOpen[1,41](</)
18: StringIdentifier[1,43](p)
19: ComponentClose[1,44](>)
20: ComponentAttrValueEnd[1,45](})
21: Nlws[1,46]( )
22: ComponentSelfClose[1,47](/>)
23: ComponentAttrValueEnd[1,49](})
24: Nlws[1,50]( )
25: ComponentSelfClose[1,51](/>)
26: RawText[1,53](\n)

View File

@ -0,0 +1,23 @@
0: ComponentOpen[1,1](<)
1: TypedIdentifier[1,2](Test)
2: Nlws[1,6]( )
3: AttributeIdentifier[1,7](transform)
4: Equals[1,16](=)
5: ComponentAttrValueStart[1,17]({)
6: ComponentOpen[1,18](<)
7: TypedIdentifier[1,19](Test)
8: Nlws[1,23]( )
9: AttributeIdentifier[1,24](transform)
10: Equals[1,33](=)
11: ComponentAttrValueStart[1,34]({)
12: ComponentOpen[1,35](<)
13: TypedIdentifier[1,36](Test)
14: Nlws[1,40]( )
15: ComponentSelfClose[1,41](/>)
16: ComponentAttrValueEnd[1,43](})
17: Nlws[1,44]( )
18: ComponentSelfClose[1,45](/>)
19: ComponentAttrValueEnd[1,47](})
20: Nlws[1,48]( )
21: ComponentSelfClose[1,49](/>)
22: RawText[1,51](\n)

View File

@ -0,0 +1,14 @@
0: ComponentOpen[1,1](<)
1: TypedIdentifier[1,2](Test)
2: Nlws[1,6]( )
3: AttributeIdentifier[1,7](transform)
4: Equals[1,16](=)
5: ComponentAttrValueStart[1,17]({)
6: ComponentOpen[1,18](<)
7: TypedIdentifier[1,19](Test)
8: Nlws[1,23]( )
9: ComponentSelfClose[1,24](/>)
10: ComponentAttrValueEnd[1,26](})
11: Nlws[1,27]( )
12: ComponentSelfClose[1,28](/>)
13: RawText[1,30](\n)

View File

@ -0,0 +1,14 @@
0: ComponentOpen[1,1](<)
1: TypedIdentifier[1,2](Test)
2: Nlws[1,6]( )
3: AttributeIdentifier[1,7](test)
4: Equals[1,11](=)
5: ComponentAttrValueStart[1,12]({ )
6: ComponentOpen[1,14](<)
7: TypedIdentifier[1,15](Test)
8: Nlws[1,19]( )
9: ComponentSelfClose[1,20](/>)
10: ComponentAttrValueEnd[1,22]( })
11: Nlws[1,24]( )
12: ComponentSelfClose[1,25](/>)
13: RawText[1,27](\n)

View File

@ -0,0 +1,18 @@
0: ComponentOpen[1,1](<)
1: TypedIdentifier[1,2](Test)
2: Nlws[1,6]( )
3: AttributeIdentifier[1,7](transform)
4: Equals[1,16](=)
5: ComponentAttrValueStart[1,17]({)
6: ComponentOpen[1,18](<)
7: StringIdentifier[1,19](p)
8: ComponentClose[1,20](>)
9: DollarReferenceStart[1,21]($)
10: GroovyCode[1,22](it)
11: ClosingComponentOpen[1,24](</)
12: StringIdentifier[1,26](p)
13: ComponentClose[1,27](>)
14: ComponentAttrValueEnd[1,28](})
15: Nlws[1,29]( )
16: ComponentSelfClose[1,30](/>)
17: RawText[1,32](\n)

View File

@ -0,0 +1 @@
<Test test={<p>$it</p>} />

View File

@ -0,0 +1 @@
<Test test={<Test test={<Test />} />} />

View File

@ -0,0 +1 @@
<Test test={<Test test={<p>$it</p>} />} />

View File

@ -0,0 +1,55 @@
compilationUnit[1,1..2,1]
body[1,1..1,43]
component[1,1..1,43]
selfClosingComponent[1,1..1,43]
ComponentOpen[1,1](<)
componentArgs[1,2..1,39]
componentType[1,2..1,6]
TypedIdentifier[1,2](Test)
attr[1,7..1,39]
keyValueAttr[1,7..1,39]
AttributeIdentifier[1,7](test)
Equals[1,11](=)
value[1,12..1,39]
componentAttrValue[1,12..1,39]
ComponentAttrValueStart[1,12]({)
component[1,13..1,39]
selfClosingComponent[1,13..1,39]
ComponentOpen[1,13](<)
componentArgs[1,14..1,35]
componentType[1,14..1,18]
TypedIdentifier[1,14](Test)
attr[1,19..1,35]
keyValueAttr[1,19..1,35]
AttributeIdentifier[1,19](test)
Equals[1,23](=)
value[1,24..1,35]
componentAttrValue[1,24..1,35]
ComponentAttrValueStart[1,24]({)
component[1,25..1,34]
componentWithChildren[1,25..1,34]
openComponent[1,25..1,27]
ComponentOpen[1,25](<)
componentArgs[1,26..1,26]
componentType[1,26..1,26]
StringIdentifier[1,26](p)
ComponentClose[1,27](>)
body[1,28..1,31]
bodyText[1,28..1,31]
bodyTextGroovyElement[1,28..1,31]
dollarReference[1,28..1,31]
DollarReferenceStart[1,28]($)
GroovyCode[1,29](it)
closingComponent[1,31..1,34]
ClosingComponentOpen[1,31](</)
componentType[1,33..1,33]
StringIdentifier[1,33](p)
ComponentClose[1,34](>)
ComponentAttrValueEnd[1,35](})
ComponentSelfClose[1,37](/>)
ComponentAttrValueEnd[1,39](})
ComponentSelfClose[1,41](/>)
bodyText[1,43..1,43]
text[1,43..1,43]
RawText[1,43](\n)
EOF[2,1](<EOF>)

View File

@ -0,0 +1,43 @@
compilationUnit[1,1..2,1]
body[1,1..1,41]
component[1,1..1,41]
selfClosingComponent[1,1..1,41]
ComponentOpen[1,1](<)
componentArgs[1,2..1,37]
componentType[1,2..1,6]
TypedIdentifier[1,2](Test)
attr[1,7..1,37]
keyValueAttr[1,7..1,37]
AttributeIdentifier[1,7](test)
Equals[1,11](=)
value[1,12..1,37]
componentAttrValue[1,12..1,37]
ComponentAttrValueStart[1,12]({)
component[1,13..1,37]
selfClosingComponent[1,13..1,37]
ComponentOpen[1,13](<)
componentArgs[1,14..1,33]
componentType[1,14..1,18]
TypedIdentifier[1,14](Test)
attr[1,19..1,33]
keyValueAttr[1,19..1,33]
AttributeIdentifier[1,19](test)
Equals[1,23](=)
value[1,24..1,33]
componentAttrValue[1,24..1,33]
ComponentAttrValueStart[1,24]({)
component[1,25..1,33]
selfClosingComponent[1,25..1,33]
ComponentOpen[1,25](<)
componentArgs[1,26..1,30]
componentType[1,26..1,30]
TypedIdentifier[1,26](Test)
ComponentSelfClose[1,31](/>)
ComponentAttrValueEnd[1,33](})
ComponentSelfClose[1,35](/>)
ComponentAttrValueEnd[1,37](})
ComponentSelfClose[1,39](/>)
bodyText[1,41..1,41]
text[1,41..1,41]
RawText[1,41](\n)
EOF[2,1](<EOF>)

View File

@ -0,0 +1,40 @@
compilationUnit[1,1..2,1]
body[1,1..1,27]
component[1,1..1,27]
selfClosingComponent[1,1..1,27]
ComponentOpen[1,1](<)
componentArgs[1,2..1,23]
componentType[1,2..1,6]
TypedIdentifier[1,2](Test)
attr[1,7..1,23]
keyValueAttr[1,7..1,23]
AttributeIdentifier[1,7](test)
Equals[1,11](=)
value[1,12..1,23]
componentAttrValue[1,12..1,23]
ComponentAttrValueStart[1,12]({)
component[1,13..1,22]
componentWithChildren[1,13..1,22]
openComponent[1,13..1,15]
ComponentOpen[1,13](<)
componentArgs[1,14..1,14]
componentType[1,14..1,14]
StringIdentifier[1,14](p)
ComponentClose[1,15](>)
body[1,16..1,19]
bodyText[1,16..1,19]
bodyTextGroovyElement[1,16..1,19]
dollarReference[1,16..1,19]
DollarReferenceStart[1,16]($)
GroovyCode[1,17](it)
closingComponent[1,19..1,22]
ClosingComponentOpen[1,19](</)
componentType[1,21..1,21]
StringIdentifier[1,21](p)
ComponentClose[1,22](>)
ComponentAttrValueEnd[1,23](})
ComponentSelfClose[1,25](/>)
bodyText[1,27..1,27]
text[1,27..1,27]
RawText[1,27](\n)
EOF[2,1](<EOF>)