eclipse-langium / langium

Next-gen language engineering / DSL framework
https://langium.org/
MIT License
754 stars 68 forks source link

Grammar railroad diagram #1062

Closed mingodad closed 1 year ago

mingodad commented 1 year ago

I manually converted the langium-grammar.langium to an EBNF understood by https://www.bottlecaps.de/rr/ui , would be nice if langium could generate it automatically like I did for bison/byacc/lemon here https://github.com/mingodad/lalr-parser-test .

Copy and paste the EBNF shown bellow on https://www.bottlecaps.de/rr/ui on the tab Edit Grammar the click on the tab View Diagram to see/download a navigable railroad diagram.

EBNF diagram ``` /****************************************************************************** * Copyright 2021 TypeFox GmbH * This program and the accompanying materials are made available under the * terms of the MIT License, which is available in the project root. ******************************************************************************/ grammar LangiumGrammar entry Grammar : ( /*isDeclared?=*/'grammar' /*name=*/ID ('with' /*usedGrammars+=[Grammar:*/ID/*]*/ (',' /*usedGrammars+=[Grammar:*/ID/*]*/)*)? (/*definesHiddenTokens?=*/'hidden' '(' (/*hiddenTokens+=[AbstractRule:*/ID/*]*/ (',' /*hiddenTokens+=[AbstractRule:*/ID/*]*/)*)? ')')? )? /*imports+=*/GrammarImport* (/*rules+=*/AbstractRule | /*interfaces+=*/Interface | /*types+=*/Type)+ ; Interface : 'interface' /*name=*/ID ('extends' /*superTypes+=[AbstractType:*/ID/*]*/ (',' /*superTypes+=[AbstractType:*/ID/*]*/)*)? SchemaType ; /*fragment*/ SchemaType : '{' /*attributes+=*/TypeAttribute* '}' ';'? ; TypeAttribute : /*name=*/FeatureName (/*isOptional?=*/'?')? ':' /*type=*/TypeDefinition ';'? ; TypeDefinition : UnionType ; UnionType /*infers TypeDefinition*/ : ArrayType (/*{infer UnionType.types+=current}*/ ('|' /*types+=*/ArrayType)+)? ; ArrayType /*infers TypeDefinition*/ : ReferenceType (/*{infer ArrayType.elementType=current}*/ '[' ']')? ; ReferenceType /*infers TypeDefinition*/ : SimpleType | /*{infer ReferenceType}*/ '@' /*referenceType=*/SimpleType ; SimpleType /*infers TypeDefinition*/ : '(' TypeDefinition ')' | /*{infer SimpleType}*/ (/*typeRef=[AbstractType:*/ID/*]*/ | /*primitiveType=*/PrimitiveType | /*stringType=*/STRING) ; PrimitiveType returns string : 'string' | 'number' | 'boolean' | 'Date' | 'bigint' ; /*type*/ AbstractType : Interface | Type | Action | ParserRule ; Type : 'type' /*name=*/ID '=' /*type=*/TypeDefinition ';'? ; AbstractRule : ParserRule | TerminalRule ; GrammarImport : 'import' /*path=*/STRING ';'? ; ParserRule : (/*entry?=*/'entry' | /*fragment?=*/'fragment')? RuleNameAndParams (/*wildcard?=*/'*' | ('returns' (/*returnType=[AbstractType:*/ID/*]*/ | /*dataType=*/PrimitiveType)) | /*inferredType=*/InferredType/**/)? (/*definesHiddenTokens?=*/'hidden' '(' (/*hiddenTokens+=[AbstractRule:*/ID/*]*/ (',' /*hiddenTokens+=[AbstractRule:*/ID/*]*/)*)? ')')? ':' /*definition=*/Alternatives ';' ; InferredType/**/ : (/**/ 'infer' | /**/ 'infers') /*name=*/ID ; /*fragment*/ RuleNameAndParams : /*name=*/ID ('<' (/*parameters+=*/Parameter (',' /*parameters+=*/Parameter)*)? '>')? ; Parameter : /*name=*/ID ; Alternatives infers AbstractElement : ConditionalBranch (/*{infer Alternatives.elements+=current}*/ ('|' /*elements+=*/ConditionalBranch)+)? ; ConditionalBranch infers AbstractElement : UnorderedGroup | /*{infer Group}*/ '<' /*guardCondition=*/Disjunction '>' (/*elements+=*/AbstractToken)+ ; UnorderedGroup /*infers AbstractElement*/ : Group (/*{infer UnorderedGroup.elements+=current}*/ ('&' /*elements+=*/Group)+)? ; Group /*infers AbstractElement*/ : AbstractToken (/*{infer Group.elements+=current}*/ /*elements+=*/AbstractToken+)? ; AbstractToken /*infers AbstractElement*/ : AbstractTokenWithCardinality | Action ; AbstractTokenWithCardinality /*infers AbstractElement*/ : (Assignment | AbstractTerminal) /*cardinality=*/('?'|'*'|'+')? ; Action /*infers AbstractElement*/ : /*{infer Action}*/ '{' (/*type=[AbstractType:*/ID/*]*/ | /*inferredType=*/InferredType/**/) ('.' /*feature=*/FeatureName /*operator=*/('='|'+=') 'current')? '}' ; AbstractTerminal /*infers AbstractElement*/ : Keyword | RuleCall | ParenthesizedElement | PredicatedKeyword | PredicatedRuleCall | PredicatedGroup ; Keyword : /*value=*/STRING ; RuleCall : /*rule=[AbstractRule:*/ID/*]*/ ('<' /*arguments+=*/NamedArgument (',' /*arguments+=*/NamedArgument)* '>')? ; NamedArgument : ( /*parameter=[Parameter:*/ID/*]*/ /*calledByName?=*/'=')? ( /*value=*/Disjunction ) ; LiteralCondition : /*true?=*/'true' | 'false' ; Disjunction /*infers Condition*/ : Conjunction (/*{infer Disjunction.left=current}*/ '|' /*right=*/Conjunction)* ; Conjunction /*infers Condition*/ : Negation (/*{infer Conjunction.left=current}*/ '&' /*right=*/Negation)* ; Negation /*infers Condition*/ : Atom | /*{infer Negation}*/ '!' /*value=*/Negation ; Atom /*infers Condition*/ : ParameterReference | ParenthesizedCondition | LiteralCondition ; ParenthesizedCondition /*infers Condition*/ : '(' Disjunction ')' ; ParameterReference : /*parameter=[Parameter:*/ID/*]*/ ; PredicatedKeyword /*infers Keyword*/ : ('=>' | '->') /*value=*/STRING ; PredicatedRuleCall /*infers RuleCall*/ : ('=>' | '->') /*rule=[AbstractRule:*/ID/*]*/ ('<' /*arguments+=*/NamedArgument (',' /*arguments+=*/NamedArgument)* '>')? ; Assignment /*infers AbstractElement*/ : /*{infer Assignment}*/ ('=>' | '->')? /*feature=*/FeatureName /*operator=*/('+='|'='|'?=') /*terminal=*/AssignableTerminal ; AssignableTerminal /*infers AbstractElement*/ : Keyword | RuleCall | ParenthesizedAssignableElement | CrossReference ; ParenthesizedAssignableElement /*infers AbstractElement*/ : '(' AssignableAlternatives ')' ; AssignableAlternatives /*infers AbstractElement*/ : AssignableTerminal (/*{infer Alternatives.elements+=current}*/ ('|' /*elements+=*/AssignableTerminal)+)? ; CrossReference /*infers AbstractElement*/ : /*{infer CrossReference}*/ '[' /*type=[AbstractType]*/ ((/*deprecatedSyntax?=*/'|' | ':') /*terminal=*/CrossReferenceableTerminal )? ']' ; CrossReferenceableTerminal /*infers AbstractElement*/ : Keyword | RuleCall ; ParenthesizedElement /*infers AbstractElement*/ : '(' Alternatives ')' ; PredicatedGroup /*infers Group*/ : ('=>' | '->') '(' /*elements+=*/Alternatives ')' ; ReturnType : /*name=*/(PrimitiveType | ID) ; TerminalRule : /*hidden?=*/'hidden'? 'terminal' (/*fragment?=*/'fragment' /*name=*/ID | /*name=*/ID ('returns' /*type=*/ReturnType)?) ':' /*definition=*/TerminalAlternatives ';' ; TerminalAlternatives /*infers AbstractElement*/ : TerminalGroup (/*{infer TerminalAlternatives.elements+=current}*/ '|' /*elements+=*/TerminalGroup)* ; TerminalGroup /*infers AbstractElement*/ : TerminalToken (/*{infer TerminalGroup.elements+=current}*/ /*elements+=*/TerminalToken+)? ; TerminalToken /*infers AbstractElement*/ : TerminalTokenElement /*cardinality=*/('?'|'*'|'+')? ; TerminalTokenElement /*infers AbstractElement*/ : CharacterRange | TerminalRuleCall | ParenthesizedTerminalElement | NegatedToken | UntilToken | RegexToken | Wildcard ; ParenthesizedTerminalElement /*infers AbstractElement*/ : '(' (/*lookahead=*/('?='|'?!'))? TerminalAlternatives ')' ; TerminalRuleCall /*infers AbstractElement*/ : /*{infer TerminalRuleCall}*/ /*rule=[TerminalRule:*/ID/*]*/ ; NegatedToken /*infers AbstractElement*/ : /*{infer NegatedToken}*/ '!' /*terminal=*/TerminalTokenElement ; UntilToken infers AbstractElement : /*{infer UntilToken}*/ '->' /*terminal=*/TerminalTokenElement ; RegexToken /*infers AbstractElement*/ : /*{infer RegexToken}*/ /*regex=*/RegexLiteral ; Wildcard /*infers AbstractElement*/ : /*{infer Wildcard}*/ '.' ; CharacterRange /*infers AbstractElement*/ : /*{infer CharacterRange}*/ /*left=*/Keyword ('..' /*right=*/Keyword)? ; FeatureName /*returns string*/ : 'current' | 'entry' | 'extends' | 'false' | 'fragment' | 'grammar' | 'hidden' | 'import' | 'interface' | 'returns' | 'terminal' | 'true' | 'type' | 'infer' | 'infers' | 'with' | PrimitiveType | ID ; //terminal ID: /\^?[_a-zA-Z][\w_]*/; //terminal STRING: /"(\\.|[^"\\])*"|'(\\.|[^'\\])*'/; //terminal RegexLiteral /*returns string*/: /\/(?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+\//; //hidden terminal WS: /\s+/; //hidden terminal ML_COMMENT: /\/\*[\s\S]*?\*\//; //hidden terminal SL_COMMENT: /\/\/[^\n\r]*/; ```
msujew commented 1 year ago

@spoenemann Is this similar enough to https://github.com/langium/langium/issues/827 to warrant this being a duplicate?

mingodad commented 1 year ago

It's similar but using a different tool that in my opnion is superior to the one chevotrain produces, I didn't knew that issue before (I searched for railroad before creating this issue).

mingodad commented 1 year ago

Also I'm including an actual usable EBNF of langium-grammar.langium.

msujew commented 1 year ago

It's not necessarily about about the diagram chevrotain produces, but about syntax diagrams in general. We would use the solution best suited to get the job done. The discussion just was inspired by what Chevrotain does.

spoenemann commented 1 year ago

Let's keep it separate, we might even support both at some point.