c4Diagram.jisonā¢15 kB
/** mermaid
* https://mermaidjs.github.io/
* (c) 2022 mzhx.meng@gmail.com
* MIT license.
*/
/* lexical grammar */
%lex
/* context */
%x person
%x person_ext
%x system
%x system_db
%x system_queue
%x system_ext
%x system_ext_db
%x system_ext_queue
%x boundary
%x enterprise_boundary
%x system_boundary
%x rel
%x birel
%x rel_u
%x rel_d
%x rel_l
%x rel_r
/* container */
%x container
%x container_db
%x container_queue
%x container_ext
%x container_ext_db
%x container_ext_queue
%x container_boundary
/* component */
%x component
%x component_db
%x component_queue
%x component_ext
%x component_ext_db
%x component_ext_queue
/* Dynamic diagram */
%x rel_index
%x index
/* Deployment diagram */
%x node
%x node_l
%x node_r
/* Relationship Types */
%x rel
%x rel_bi
%x rel_u
%x rel_d
%x rel_l
%x rel_r
%x rel_b
/* Custom tags/stereotypes */
%x update_el_style
%x update_rel_style
%x update_layout_config
%x attribute
%x string
%x string_kv
%x string_kv_key
%x string_kv_value
%x acc_title
%x acc_descr
%x acc_descr_multiline
%%
.*direction\s+TB[^\n]* return 'direction_tb';
.*direction\s+BT[^\n]* return 'direction_bt';
.*direction\s+RL[^\n]* return 'direction_rl';
.*direction\s+LR[^\n]* return 'direction_lr';
"title"\s[^#\n;]+ return 'title';
"accDescription"\s[^#\n;]+ return 'accDescription';
accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; }
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; }
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
<acc_descr_multiline>[\}] { this.popState(); }
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
\%\%(?!\{)*[^\n]*(\r?\n?)+ /* skip comments */
\%\%[^\n]*(\r?\n)* c /* skip comments */
\s*(\r?\n)+ return 'NEWLINE';
\s+ /* skip whitespace */
"C4Context" return 'C4_CONTEXT';
"C4Container" return 'C4_CONTAINER';
"C4Component" return 'C4_COMPONENT';
"C4Dynamic" return 'C4_DYNAMIC';
"C4Deployment" return 'C4_DEPLOYMENT';
"Person_Ext" { this.begin("person_ext"); return 'PERSON_EXT';}
"Person" { this.begin("person"); return 'PERSON';}
"SystemQueue_Ext" { this.begin("system_ext_queue"); return 'SYSTEM_EXT_QUEUE';}
"SystemDb_Ext" { this.begin("system_ext_db"); return 'SYSTEM_EXT_DB';}
"System_Ext" { this.begin("system_ext"); return 'SYSTEM_EXT';}
"SystemQueue" { this.begin("system_queue"); return 'SYSTEM_QUEUE';}
"SystemDb" { this.begin("system_db"); return 'SYSTEM_DB';}
"System" { this.begin("system"); return 'SYSTEM';}
"Boundary" { this.begin("boundary"); return 'BOUNDARY';}
"Enterprise_Boundary" { this.begin("enterprise_boundary"); return 'ENTERPRISE_BOUNDARY';}
"System_Boundary" { this.begin("system_boundary"); return 'SYSTEM_BOUNDARY';}
"ContainerQueue_Ext" { this.begin("container_ext_queue"); return 'CONTAINER_EXT_QUEUE';}
"ContainerDb_Ext" { this.begin("container_ext_db"); return 'CONTAINER_EXT_DB';}
"Container_Ext" { this.begin("container_ext"); return 'CONTAINER_EXT';}
"ContainerQueue" { this.begin("container_queue"); return 'CONTAINER_QUEUE';}
"ContainerDb" { this.begin("container_db"); return 'CONTAINER_DB';}
"Container" { this.begin("container"); return 'CONTAINER';}
"Container_Boundary" { this.begin("container_boundary"); return 'CONTAINER_BOUNDARY';}
"ComponentQueue_Ext" { this.begin("component_ext_queue"); return 'COMPONENT_EXT_QUEUE';}
"ComponentDb_Ext" { this.begin("component_ext_db"); return 'COMPONENT_EXT_DB';}
"Component_Ext" { this.begin("component_ext"); return 'COMPONENT_EXT';}
"ComponentQueue" { this.begin("component_queue"); return 'COMPONENT_QUEUE';}
"ComponentDb" { this.begin("component_db"); return 'COMPONENT_DB';}
"Component" { this.begin("component"); return 'COMPONENT';}
"Deployment_Node" { this.begin("node"); return 'NODE';}
"Node" { this.begin("node"); return 'NODE';}
"Node_L" { this.begin("node_l"); return 'NODE_L';}
"Node_R" { this.begin("node_r"); return 'NODE_R';}
"Rel" { this.begin("rel"); return 'REL';}
"BiRel" { this.begin("birel"); return 'BIREL';}
"Rel_Up" { this.begin("rel_u"); return 'REL_U';}
"Rel_U" { this.begin("rel_u"); return 'REL_U';}
"Rel_Down" { this.begin("rel_d"); return 'REL_D';}
"Rel_D" { this.begin("rel_d"); return 'REL_D';}
"Rel_Left" { this.begin("rel_l"); return 'REL_L';}
"Rel_L" { this.begin("rel_l"); return 'REL_L';}
"Rel_Right" { this.begin("rel_r"); return 'REL_R';}
"Rel_R" { this.begin("rel_r"); return 'REL_R';}
"Rel_Back" { this.begin("rel_b"); return 'REL_B';}
"RelIndex" { this.begin("rel_index"); return 'REL_INDEX';}
"UpdateElementStyle" { this.begin("update_el_style"); return 'UPDATE_EL_STYLE';}
"UpdateRelStyle" { this.begin("update_rel_style"); return 'UPDATE_REL_STYLE';}
"UpdateLayoutConfig" { this.begin("update_layout_config"); return 'UPDATE_LAYOUT_CONFIG';}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext_queue,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config><<EOF>> return "EOF_IN_STRUCT";
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext_queue,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config>[(][ ]*[,] { this.begin("attribute"); return "ATTRIBUTE_EMPTY";}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext_queue,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config>[(] { this.begin("attribute"); }
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext_queue,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,update_el_style,update_rel_style,update_layout_config,attribute>[)] { this.popState();this.popState();}
<attribute>",," { return 'ATTRIBUTE_EMPTY';}
<attribute>"," { }
<attribute>[ ]*["]["] { return 'ATTRIBUTE_EMPTY';}
<attribute>[ ]*["] { this.begin("string");}
<string>["] { this.popState(); }
<string>[^"]* { return "STR";}
<attribute>[ ]*[\$] { this.begin("string_kv");}
<string_kv>[^=]* { this.begin("string_kv_key"); return "STR_KEY";}
<string_kv_key>[=][ ]*["] { this.popState(); this.begin("string_kv_value"); }
<string_kv_value>[^"]+ { return "STR_VALUE";}
<string_kv_value>["] { this.popState(); this.popState(); }
<attribute>[^,]+ { return "STR";}
'{' { /* this.begin("lbrace"); */ return "LBRACE";}
'}' { /* this.popState(); */ return "RBRACE";}
[\s]+ return 'SPACE';
[\n\r]+ return 'EOL';
<<EOF>> return 'EOF';
/lex
/* operator associations and precedence */
%left '^'
%start start
%% /* language grammar */
start
: mermaidDoc
| direction
;
direction
: direction_tb
{ yy.setDirection('TB');}
| direction_bt
{ yy.setDirection('BT');}
| direction_rl
{ yy.setDirection('RL');}
| direction_lr
{ yy.setDirection('LR');}
;
mermaidDoc
: graphConfig
;
graphConfig
: C4_CONTEXT NEWLINE statements EOF {yy.setC4Type($1)}
| C4_CONTAINER NEWLINE statements EOF {yy.setC4Type($1)}
| C4_COMPONENT NEWLINE statements EOF {yy.setC4Type($1)}
| C4_DYNAMIC NEWLINE statements EOF {yy.setC4Type($1)}
| C4_DEPLOYMENT NEWLINE statements EOF {yy.setC4Type($1)}
;
statements
: otherStatements
| diagramStatements
| otherStatements diagramStatements
;
otherStatements
: otherStatement
| otherStatement NEWLINE
| otherStatement NEWLINE otherStatements
;
otherStatement
: title {yy.setTitle($1.substring(6));$$=$1.substring(6);}
| accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);}
| acc_title acc_title_value { $$=$2.trim();yy.setTitle($$); }
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); }
;
boundaryStatement
: boundaryStartStatement diagramStatements boundaryStopStatement
;
boundaryStartStatement
: boundaryStart LBRACE NEWLINE
| boundaryStart NEWLINE LBRACE
| boundaryStart NEWLINE LBRACE NEWLINE
;
boundaryStart
: ENTERPRISE_BOUNDARY attributes {$2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| SYSTEM_BOUNDARY attributes {$2.splice(2, 0, 'SYSTEM'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| BOUNDARY attributes {yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| CONTAINER_BOUNDARY attributes {$2.splice(2, 0, 'CONTAINER'); yy.addContainerBoundary(...$2); $$=$2;}
| NODE attributes {yy.addDeploymentNode('node', ...$2); $$=$2;}
| NODE_L attributes {yy.addDeploymentNode('nodeL', ...$2); $$=$2;}
| NODE_R attributes {yy.addDeploymentNode('nodeR', ...$2); $$=$2;}
;
boundaryStopStatement
: RBRACE { yy.popBoundaryParseStack() }
;
diagramStatements
: diagramStatement
| diagramStatement NEWLINE
| diagramStatement NEWLINE statements
;
diagramStatement
: PERSON attributes {yy.addPersonOrSystem('person', ...$2); $$=$2;}
| PERSON_EXT attributes {yy.addPersonOrSystem('external_person', ...$2); $$=$2;}
| SYSTEM attributes {yy.addPersonOrSystem('system', ...$2); $$=$2;}
| SYSTEM_DB attributes {yy.addPersonOrSystem('system_db', ...$2); $$=$2;}
| SYSTEM_QUEUE attributes {yy.addPersonOrSystem('system_queue', ...$2); $$=$2;}
| SYSTEM_EXT attributes {yy.addPersonOrSystem('external_system', ...$2); $$=$2;}
| SYSTEM_EXT_DB attributes {yy.addPersonOrSystem('external_system_db', ...$2); $$=$2;}
| SYSTEM_EXT_QUEUE attributes {yy.addPersonOrSystem('external_system_queue', ...$2); $$=$2;}
| CONTAINER attributes {yy.addContainer('container', ...$2); $$=$2;}
| CONTAINER_DB attributes {yy.addContainer('container_db', ...$2); $$=$2;}
| CONTAINER_QUEUE attributes {yy.addContainer('container_queue', ...$2); $$=$2;}
| CONTAINER_EXT attributes {yy.addContainer('external_container', ...$2); $$=$2;}
| CONTAINER_EXT_DB attributes {yy.addContainer('external_container_db', ...$2); $$=$2;}
| CONTAINER_EXT_QUEUE attributes {yy.addContainer('external_container_queue', ...$2); $$=$2;}
| COMPONENT attributes {yy.addComponent('component', ...$2); $$=$2;}
| COMPONENT_DB attributes {yy.addComponent('component_db', ...$2); $$=$2;}
| COMPONENT_QUEUE attributes {yy.addComponent('component_queue', ...$2); $$=$2;}
| COMPONENT_EXT attributes {yy.addComponent('external_component', ...$2); $$=$2;}
| COMPONENT_EXT_DB attributes {yy.addComponent('external_component_db', ...$2); $$=$2;}
| COMPONENT_EXT_QUEUE attributes {yy.addComponent('external_component_queue', ...$2); $$=$2;}
| boundaryStatement
| REL attributes {yy.addRel('rel', ...$2); $$=$2;}
| BIREL attributes {yy.addRel('birel', ...$2); $$=$2;}
| REL_U attributes {yy.addRel('rel_u', ...$2); $$=$2;}
| REL_D attributes {yy.addRel('rel_d', ...$2); $$=$2;}
| REL_L attributes {yy.addRel('rel_l', ...$2); $$=$2;}
| REL_R attributes {yy.addRel('rel_r', ...$2); $$=$2;}
| REL_B attributes {yy.addRel('rel_b', ...$2); $$=$2;}
| REL_INDEX attributes {$2.splice(0, 1); yy.addRel('rel', ...$2); $$=$2;}
| UPDATE_EL_STYLE attributes {yy.updateElStyle('update_el_style', ...$2); $$=$2;}
| UPDATE_REL_STYLE attributes {yy.updateRelStyle('update_rel_style', ...$2); $$=$2;}
| UPDATE_LAYOUT_CONFIG attributes {yy.updateLayoutConfig('update_layout_config', ...$2); $$=$2;}
;
attributes
: attribute { $$ = [$1]; }
| attribute attributes { $2.unshift($1); $$=$2;}
;
attribute
: STR { $$ = $1.trim(); }
| STR_KEY STR_VALUE { let kv={}; kv[$1.trim()]=$2.trim(); $$=kv; }
| ATTRIBUTE { $$ = $1.trim(); }
| ATTRIBUTE_EMPTY { $$ = ""; }
;