Skip to content

Commit

Permalink
feat: support line continuations in declarations and fix shape declar…
Browse files Browse the repository at this point in the history
…ations

Implicit semicolons allow not matching declarations that include continuations properly.
  • Loading branch information
goto1134 committed Feb 3, 2024
1 parent 9fbb810 commit df54a8c
Show file tree
Hide file tree
Showing 15 changed files with 1,524 additions and 1,233 deletions.
1 change: 1 addition & 0 deletions src/gen/org/jetbrains/plugins/d2/lang/D2ElementTypes.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2,265 changes: 1,183 additions & 1,082 deletions src/gen/org/jetbrains/plugins/d2/lang/D2FlexLexer.java

Large diffs are not rendered by default.

48 changes: 33 additions & 15 deletions src/gen/org/jetbrains/plugins/d2/lang/D2Parser.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/src/completion/D2BasicCompletionContributor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private class D2BasicCompletionContributor : CompletionContributor() {
// for `test.<caret> ->` a new "shape" is created, so, we must resolve parent for it,
// otherwise we cannot check siblings (to forbid reserved keyword completion in edges)
val newParent = parent.parent
if (newParent is ShapeId) {
if (newParent is ShapeDeclaration) {
parent = newParent
}
}
Expand Down
80 changes: 41 additions & 39 deletions src/src/lang/D2Lexer.flex
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,17 @@ Color={SingleQuotedColor}|{DoubleQuotedColor}
True=t{ContinuationClosure}?r{ContinuationClosure}?u{ContinuationClosure}?e
False=f{ContinuationClosure}?a{ContinuationClosure}?l{ContinuationClosure}?s{ContinuationClosure}?e

// does not match newline, see Dot (.) at https://jflex.de/manual.html
EscapeSequence=\\.
LabelSymbol=[^\s;{}#]
UnquotedLabelString = [{LabelSymbol}&&[^|]]{LabelSymbol}*({SpaceContinuation}+{LabelSymbol}+)*
LabelSymbol=[^\s;{}#\\]
LabelSymbolOrEscape={LabelSymbol}|{EscapeSequence}
UnquotedLabelString = ([{LabelSymbol}&&[^|]]|{EscapeSequence}){LabelSymbolOrEscape}*({SpaceContinuation}+{LabelSymbolOrEscape}+)*
// [] is not supported - it is array
ValueSymbol=[{LabelSymbol}&&[^\[\]]]
UnquotedString = [{ValueSymbol}&&[^|]]{ValueSymbol}*({SpaceContinuation}+{ValueSymbol}+)*
ValueSymbolOrEscape={ValueSymbol}|{EscapeSequence}
UnquotedString = ([{ValueSymbol}&&[^|]]|{EscapeSequence}){ValueSymbolOrEscape}*({SpaceContinuation}+{ValueSymbolOrEscape}+)*

IdSymbol=[[^:.<>&\\-]&&{ValueSymbol}]
IdSymbol=[[^:.<>&-]&&{ValueSymbol}]
IdDashSubstring=-{SpaceContinuation}*([{IdSymbol}&&[^->*]]|{EscapeSequence})
AllowedInId=({IdSymbol}|{EscapeSequence}|{IdDashSubstring})
IdBody={AllowedInId}*({SpaceContinuation}+{AllowedInId}+)*
Expand All @@ -108,49 +111,53 @@ RBrace="}"
LBracket="["
RBracket="]"

%states LABEL_STATE PROPERTY_VALUE_BEGIN_STATE PROPERTY_VALUE_STATE BLOCK_STRING_LANG_STATE BLOCK_STRING_BODY_STATE ARRAY_STATE
%states LABEL_STATE PROPERTY_VALUE_BEGIN_STATE PROPERTY_VALUE_STATE BLOCK_STRING_LANG_STATE BLOCK_STRING_BODY_STATE ARRAY_STATE EXPECT_IMPLICIT_SEMICOLON

%%
<YYINITIAL> {
{WhiteSpace} { return WHITE_SPACE; }

{LBrace} { return LBRACE; }
{RBrace} { return RBRACE; }
"." { return DOT; }
{Semicolon} { return SEMICOLON; }
}

<EXPECT_IMPLICIT_SEMICOLON, PROPERTY_VALUE_BEGIN_STATE, PROPERTY_VALUE_STATE, LABEL_STATE> {
{WhiteSpaceWithoutNewLines} { return WHITE_SPACE; }
{WhiteSpace} { yybegin(YYINITIAL); yypushback(yylength()); return IMPLICIT_SEMICOLON; }
}

<YYINITIAL, EXPECT_IMPLICIT_SEMICOLON> {
{LBrace} { yybegin(YYINITIAL); return LBRACE; }
{RBrace} { yybegin(YYINITIAL); return RBRACE; }
"." { yybegin(EXPECT_IMPLICIT_SEMICOLON); return DOT; }
{Semicolon} { yybegin(YYINITIAL); return SEMICOLON; }
":" { yybegin(LABEL_STATE); return COLON; }

{ARROW} { return ARROW; }
{REVERSE_ARROW} { return REVERSE_ARROW; }
{DOUBLE_HYPHEN_ARROW} { return DOUBLE_HYPHEN_ARROW; }
{DOUBLE_ARROW} { return DOUBLE_ARROW; }
{Comment} | {BlockComment} { return COMMENT; }
{ARROW} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return ARROW; }
{REVERSE_ARROW} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return REVERSE_ARROW; }
{DOUBLE_HYPHEN_ARROW} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return DOUBLE_HYPHEN_ARROW; }
{DOUBLE_ARROW} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return DOUBLE_ARROW; }
{Comment} | {BlockComment} { yybegin(YYINITIAL); return COMMENT; }

{CompositeReservedKeywords} { return COMPOSITE_RESERVED_KEYWORDS; }
{CompositeReservedKeywords} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return COMPOSITE_RESERVED_KEYWORDS; }
{SimpleReservedKeywords} { yybegin(PROPERTY_VALUE_BEGIN_STATE); return SIMPLE_RESERVED_KEYWORDS; }
{ReservedKeywordHolders} { return RESERVED_KEYWORD_HOLDERS; }
{StyleKeyword} { return STYLE_KEYWORD; }
{ReservedKeywordHolders} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return RESERVED_KEYWORD_HOLDERS; }
{StyleKeyword} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return STYLE_KEYWORD; }
{StyleKeywords} { yybegin(PROPERTY_VALUE_BEGIN_STATE); return STYLE_KEYWORDS; }
{ContainerLessKeywords} { yybegin(PROPERTY_VALUE_BEGIN_STATE); return CONTAINER_LESS_KEYWORDS; }

"_" { return PARENT_SHAPE_REF; }
{Id} { return ID; }
"_" { yybegin(EXPECT_IMPLICIT_SEMICOLON); return PARENT_SHAPE_REF; }
{Id} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return ID; }

{String} { return STRING; }
// allows to avoid using regex for completion/color provider and other functionality that utilizes color
{Color} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return COLOR; }
{String} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return STRING; }
{BlockStringStart} { return startBlockString(); }
// allows to avoid using regex for completion/color provider and other functionality that utilizes color
{Color} { return COLOR; }
}

<PROPERTY_VALUE_BEGIN_STATE> {
":" { yybegin(PROPERTY_VALUE_STATE); return COLON; }
{WhiteSpace} { return WHITE_SPACE; }
":" { yybegin(PROPERTY_VALUE_STATE); return COLON; }
}

// block string is not allowed for property value
<PROPERTY_VALUE_STATE> {
":" { return COLON; }

{Int} { return INT; }
{Float} { return FLOAT; }
{True} { return TRUE; }
Expand All @@ -161,8 +168,6 @@ RBracket="]"
{RBracket} { return RBRACKET; }
{UnquotedString} { return UNQUOTED_STRING; }

{WhiteSpaceWithoutNewLines} { return WHITE_SPACE; }
{WhiteSpace} { yybegin(YYINITIAL); return WHITE_SPACE; }
{Semicolon} { yybegin(YYINITIAL); return SEMICOLON; }

// inline shape definition: {shape: person}
Expand All @@ -173,22 +178,19 @@ RBracket="]"
{Semicolon} { return SEMICOLON; }
// D2 supports nested arrays, but we don't for now (nested states are nnot supported, can be implemented, but not clear yet for what)
{LBracket} { return LBRACKET; }
{RBracket} { yybegin(YYINITIAL); return RBRACKET; }
{RBracket} { yybegin(EXPECT_IMPLICIT_SEMICOLON); return RBRACKET; }
{UnquotedString} { return UNQUOTED_STRING; }

{WhiteSpace} { return WHITE_SPACE; }
}

<LABEL_STATE> {
{BlockStringStart} { return startBlockString(); }

{String} { return STRING; }
{UnquotedLabelString} { return UNQUOTED_STRING; }
{WhiteSpaceWithoutNewLines} { return WHITE_SPACE; }
{WhiteSpace} { yybegin(YYINITIAL); return WHITE_SPACE; }
{LBrace} { yybegin(YYINITIAL); return LBRACE; }
// inline shape definition: {shape: person}
{RBrace} { yybegin(YYINITIAL); return RBRACE; }
{Semicolon} { return SEMICOLON; }
{String} { return STRING; }
{UnquotedLabelString} { return UNQUOTED_STRING; }
{LBrace} { yybegin(YYINITIAL); return LBRACE; }
// inline shape definition: {shape: person}
{RBrace} { yybegin(YYINITIAL); return RBRACE; }
}

<BLOCK_STRING_LANG_STATE> {
Expand Down
7 changes: 3 additions & 4 deletions src/src/lang/d2.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

File ::= !<<eof>> ContainerContent*

private ContainerContent ::= ShapeDeclaration | ShapeIdWithProperty | ShapeConnection | ShapeId | IdPropertyMap | COMMENT | SEMICOLON
private ContainerContent ::= ShapeIdWithProperty | ShapeConnection | ShapeDeclaration | IdPropertyMap | COMMENT | SEMICOLON | IMPLICIT_SEMICOLON

// same as for file level, but Property is allowed without ShapeIdChain
BlockDefinition ::= LBRACE ContainerContent* RBRACE {
Expand All @@ -31,8 +31,7 @@ private ShapeIdChain ::= ShapeId (DOT ShapeId)*
ParentShapeRefPsi ::= PARENT_SHAPE_REF
ShapeRef ::= (ParentShapeRefPsi DOT)? ShapeIdChain

// declaration means `id + label` (not implicit shape via just ID)
ShapeDeclaration ::= ShapeIdChain COLON (ShapeLabel | BlockString)? BlockDefinition?
ShapeDeclaration ::= ShapeIdChain (COLON (ShapeLabel | BlockString)?)? BlockDefinition?

ShapeConnection ::= ShapeRef (Connector ShapeRef)+ (COLON (ShapeLabel | BlockString)?)? BlockDefinition?
Connector ::= ARROW | REVERSE_ARROW | DOUBLE_ARROW | DOUBLE_HYPHEN_ARROW
Expand All @@ -59,7 +58,7 @@ ShapePropertyKey ::= PropertyKey
private ShapePropertyValue ::= UnquotedStringValue | StringValue | ColorValue | OtherValue | Array

IdPropertyMap ::= (COMPOSITE_RESERVED_KEYWORDS | STYLE_KEYWORD) COLON LBRACE PropertyMapContent* RBRACE
private PropertyMapContent ::= SubIdPropertyMap | IdProperty | COMMENT | SEMICOLON
private PropertyMapContent ::= SubIdPropertyMap | IdProperty | COMMENT | SEMICOLON | IMPLICIT_SEMICOLON

SubIdPropertyMap ::= IdPropertyKey COLON LBRACE PropertyMapContent* RBRACE

Expand Down
Loading

0 comments on commit df54a8c

Please sign in to comment.