Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Trying to add flowchart Langium parser #5892

Draft
wants to merge 14 commits into
base: develop
Choose a base branch
from
5 changes: 5 additions & 0 deletions packages/parser/langium-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
"id": "gitGraph",
"grammar": "src/language/gitGraph/gitGraph.langium",
"fileExtensions": [".mmd", ".mermaid"]
},
{
"id": "flowchart",
"grammar": "src/language/flowchart/flowchart.langium",
"fileExtensions": [".mmd", ".mermaid"]
}
],
"mode": "production",
Expand Down
2 changes: 1 addition & 1 deletion packages/parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"ast"
],
"dependencies": {
"langium": "3.0.0"
"langium": "3.2.0"
},
"devDependencies": {
"chevrotain": "^11.0.3"
Expand Down
16 changes: 5 additions & 11 deletions packages/parser/src/language/common/common.langium
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
interface Common {
accDescr?: string;
accTitle?: string;
title?: string;
}

fragment TitleAndAccessibilities:
((accDescr=ACC_DESCR | accTitle=ACC_TITLE | title=TITLE) EOL)+
;
Expand All @@ -13,11 +7,11 @@ fragment EOL returns string:
;

terminal NEWLINE: /\r?\n/;
terminal ACC_DESCR: /[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/;
terminal ACC_TITLE: /[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/;
terminal TITLE: /[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/;
terminal ACC_DESCR: /accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/;
terminal ACC_TITLE: /accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/;
terminal TITLE: /title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/;

hidden terminal WHITESPACE: /[\t ]+/;
hidden terminal YAML: /---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/;
hidden terminal DIRECTIVE: /[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/;
hidden terminal SINGLE_LINE_COMMENT: /[\t ]*%%[^\n\r]*/;
hidden terminal DIRECTIVE: /%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/;
hidden terminal SINGLE_LINE_COMMENT: /%%[^\n\r]*/;
173 changes: 173 additions & 0 deletions packages/parser/src/language/flowchart/flowchart.langium
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
grammar Flowchart

// from common
// fragment EOL returns string:
// NEWLINE+ | EOF
// ;
// terminal NEWLINE: /\r?\n/;
// hidden terminal WHITESPACE: /[\t ]+/;
import "../common/common";

entry Flowchart:
NEWLINE*
FlowchartType FlowchartDirection?
DELIMITER
((nodes+=FlowchartNode | edges+=(FlowchartEdge) | subgraphs+=FlowchartSubgraph | styles+=FlowchartStyle | interactions+=FlowchartInteraction) DELIMITER)*
;

fragment FlowchartDirection:
dir=("TD" | "TB"| "v" | "BT" | "^" | "LR" | ">" | "RL" | "<");

fragment FlowchartType:
type=("flowchart-elk" | "graph" | "flowchart");

FlowchartSubgraph:
"subgraph" id=ID DELIMITER
("direction" FlowchartDirection DELIMITER)?
((nodes+=FlowchartNode | edges+=(FlowchartEdge) | subgraphs+=FlowchartSubgraph) DELIMITER)*
"end";

terminal EllipseLabel: "(-" -> "-)";
FlowchartNodeEllipse:
id=ID label=EllipseLabel (":::" class=ID)?;

terminal StadiumLabel: "([" -> "])";
FlowchartNodeStadium:
id=ID label=StadiumLabel (":::" class=ID)?;

terminal OddLabel: ">" -> "]";
FlowchartNodeOdd:
id=ID label=OddLabel (":::" class=ID)?;

terminal CylinderLabel: "[(" -> ")]";
FlowchartNodeCylinder:
id=ID label=CylinderLabel (":::" class=ID)?;

terminal DoublecircleLabel: "(((" -> ")))";
FlowchartNodeDoublecircle:
id=ID label=DoublecircleLabel (":::" class=ID)?;

terminal TrapezoidLabel: "[/" -> "\\]";
FlowchartNodeTrapezoid:
id=ID label=TrapezoidLabel (":::" class=ID)?;

terminal InvTrapezoidLabel: "[\\" -> "/]";
FlowchartNodeInvTrapezoid:
id=ID label=InvTrapezoidLabel (":::" class=ID)?;

terminal LeanRightLabel: "[/" -> "/]";
FlowchartNodeLeanRight:
id=ID label=LeanRightLabel (":::" class=ID)?;

terminal LeanLeftLabel: "[\\" -> "\\]";
FlowchartNodeLeanLeft:
id=ID label=LeanLeftLabel (":::" class=ID)?;

terminal SubroutineLabel: "[[" -> "]]";
FlowchartNodeSubroutine:
id=ID label=SubroutineLabel (":::" class=ID)?;

terminal HexagonLabel: "{{" -> "}}";
FlowchartNodeHexagon:
id=ID label=HexagonLabel (":::" class=ID)?;

terminal SquareLabel: "[" -> "]";
FlowchartNodeSquare:
id=ID (label=SquareLabel)? (":::" class=ID)?;

terminal RoundLabel: "(" -> ")";
FlowchartNodeRound:
id=ID label=RoundLabel (":::" class=ID)?;

terminal DiamondLabel: "{" -> "}";
FlowchartNodeDiamond:
id=ID label=DiamondLabel (":::" class=ID)?;

FlowchartNode:
FlowchartNodeSquare |
FlowchartNodeRound |
FlowchartNodeDiamond |
FlowchartNodeEllipse |
FlowchartNodeStadium |
FlowchartNodeOdd |
FlowchartNodeCylinder |
FlowchartNodeDoublecircle |
FlowchartNodeTrapezoid |
FlowchartNodeInvTrapezoid |
FlowchartNodeLeanRight |
FlowchartNodeLeanLeft |
FlowchartNodeSubroutine |
FlowchartNodeHexagon;

terminal AMP: "&";

FlowchartNodeConjunction:
nodes+=FlowchartNode (AMP nodes+=FlowchartNode)+;

terminal fragment ArrowStart: "<" | "x" | "o";
terminal fragment ArrowEnd: ">" | "x" | "o";
terminal fragment DottedArrowEnd: "."* ".-" ArrowEnd?;

terminal DottedArrowWithLabel: ArrowStart? "-." -> DottedArrowEnd;
terminal DottedArrow: ArrowStart? "-"? DottedArrowEnd;

terminal RegularArrowWithLabel: /[<xo]?--(?![>xo])[\s\S]*?--+[->xo]/ ;
// terminal RegularArrowWithLabel: ArrowStart? "--" -> "-" "-"+ ('-' |ArrowEnd);
terminal RegularArrow: (ArrowStart "-" "-"+ ArrowEnd?) | ("-" "-"+ ('-' |ArrowEnd));

terminal ThickArrowWithLabel: /[<xo]?==(?![>xo])[\s\S]*?==+[=>xo]/ ;
// terminal ThickArrowWithLabel: ArrowStart? "==" -> "=" "="+ ("=" | ArrowEnd);
terminal ThickArrow: (ArrowStart "=" "="+ ArrowEnd?) | ("=" "="+ ("=" | ArrowEnd));

terminal InvisibleArrow: "~~" "~"+;

terminal EdgeLabel: "|" -> "|";

FlowchartEdge:
start=(FlowchartNode|FlowchartNodeConjunction) ends+=(FlowchartEdgeRegular | FlowchartEdgeDotted | FlowchartEdgeThick | FlowchartEdgeInvisible)+;

// FlowchartEdgeConjunction:
// edges+=FlowchartEdge (AMP edges+=FlowchartEdge)+;

FlowchartEdgeDotted:
(arrow=DottedArrow (label=EdgeLabel)? end=(FlowchartNode|FlowchartNodeConjunction)) |
(arrow=DottedArrowWithLabel end=(FlowchartNode|FlowchartNodeConjunction));

FlowchartEdgeRegular:
(arrow=RegularArrow (label=EdgeLabel)? end=(FlowchartNode|FlowchartNodeConjunction)) |
(arrow=RegularArrowWithLabel end=(FlowchartNode|FlowchartNodeConjunction));

FlowchartEdgeThick:
(arrow=ThickArrow (label=EdgeLabel)? end=(FlowchartNode|FlowchartNodeConjunction)) |
(arrow=ThickArrowWithLabel end=(FlowchartNode|FlowchartNodeConjunction));

FlowchartEdgeInvisible:
arrow=(InvisibleArrow) (label=EdgeLabel)? end=(FlowchartNode|FlowchartNodeConjunction);

FlowchartStyle:
"style" id=ID items+=FlowchartStylePair ("," items+=FlowchartStylePair)*;

FlowchartStylePair:
key=ID ":" (value+=ID)+;

terminal Target: "_self" | "_blank" | "_parent" | "_top";
terminal String: "\"" -> "\"";

fragment FlowchartInteractionLink:
"href"? href=String (tooltip=String)? (targe=Target)?;

fragment FlowchartInteractionFunction:
callback=ID (tooltip=String)?;

fragment FlowchartInteractionCall:
// RoundLabel is a temp solution
"call" callback=ID arguments=RoundLabel (tooltip=String)?;

FlowchartInteraction:
"click" id=ID (FlowchartInteractionLink | FlowchartInteractionFunction | FlowchartInteractionCall);

terminal ID: /[_\-\w#]+/;

fragment DELIMITER returns string:
";" NEWLINE* | EOL
;
1 change: 1 addition & 0 deletions packages/parser/src/language/flowchart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './module.js';
54 changes: 54 additions & 0 deletions packages/parser/src/language/flowchart/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type {
DefaultSharedCoreModuleContext,
LangiumCoreServices,
LangiumSharedCoreServices,
Module,
PartialLangiumCoreServices,
} from 'langium';
import {
inject,
createDefaultCoreModule,
createDefaultSharedCoreModule,
EmptyFileSystem,
} from 'langium';
import { FlowchartValueConverter } from './valueConverter.js';
import { MermaidGeneratedSharedModule, FlowchartGeneratedModule } from '../generated/module.js';
import { FlowchartTokenBuilder } from './tokenBuilder.js';

interface FlowchartAddedServices {
parser: {
TokenBuilder: FlowchartTokenBuilder;
ValueConverter: FlowchartValueConverter;
};
}

export type FlowchartServices = LangiumCoreServices & FlowchartAddedServices;

export const FlowchartModule: Module<
FlowchartServices,
PartialLangiumCoreServices & FlowchartAddedServices
> = {
parser: {
TokenBuilder: () => new FlowchartTokenBuilder(),
ValueConverter: () => new FlowchartValueConverter(),
},
};

export function createFlowchartServices(
context: DefaultSharedCoreModuleContext = EmptyFileSystem
): {
shared: LangiumSharedCoreServices;
Flowchart: FlowchartServices;
} {
const shared: LangiumSharedCoreServices = inject(
createDefaultSharedCoreModule(context),
MermaidGeneratedSharedModule
);
const Flowchart: FlowchartServices = inject(
createDefaultCoreModule({ shared }),
FlowchartGeneratedModule,
FlowchartModule
);
shared.ServiceRegistry.register(Flowchart);
return { shared, Flowchart };
}
3 changes: 3 additions & 0 deletions packages/parser/src/language/flowchart/tokenBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { DefaultTokenBuilder } from 'langium';

export class FlowchartTokenBuilder extends DefaultTokenBuilder {}
51 changes: 51 additions & 0 deletions packages/parser/src/language/flowchart/valueConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { type GrammarAST, type CstNode, DefaultValueConverter, type ValueType } from 'langium';
// import { CommonValueConverter } from '../common/valueConverter.js';

export class FlowchartValueConverter extends DefaultValueConverter {
protected override runConverter(
rule: GrammarAST.AbstractRule,
input: string,
cstNode: CstNode
): ValueType {
switch (rule.name) {
case 'String':
return input.substring(1, input.length - 1); //.replace(/\\(.)/g, '$1');
case 'EdgeLabel':
case 'OddLabel':
case 'SquareLabel':
case 'RoundLabel':
case 'DiamondLabel':
return input.substring(1, input.length - 1);
case 'EllipseLabel':
case 'StadiumLabel':
case 'CylinderLabel':
case 'TrapezoidLabel':
case 'InvTrapezoidLabel':
case 'LeanRightLabel':
case 'LeanLeftLabel':
case 'SubroutineLabel':
case 'HexagonLabel':
return input.substring(2, input.length - 2);
case 'DoublecircleLabel':
return input.substring(3, input.length - 3);
// case 'FlowchartDirection':
// switch (input) {
// case 'TD':
// case 'TB':
// case 'v':
// return 'TB';
// case 'BT':
// case '^':
// return 'BT';
// case 'LR':
// case '>':
// return 'LR';
// case 'RL':
// case '<':
// return 'RL';
// }
}

return super.runConverter(rule, input, cstNode);
}
}
3 changes: 3 additions & 0 deletions packages/parser/src/language/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export {
isBranch,
isCommit,
isMerge,
Flowchart,
} from './generated/ast.js';

export {
Expand All @@ -31,6 +32,7 @@ export {
PieGeneratedModule,
ArchitectureGeneratedModule,
GitGraphGeneratedModule,
FlowchartGeneratedModule,
} from './generated/module.js';

export * from './gitGraph/index.js';
Expand All @@ -39,3 +41,4 @@ export * from './info/index.js';
export * from './packet/index.js';
export * from './pie/index.js';
export * from './architecture/index.js';
export * from './flowchart/index.js';
Loading
Loading