chrriis / rrdiagram Goto Github PK
View Code? Open in Web Editor NEWGenerate railroad diagrams from code or BNF, generate BNF from code
License: Apache License 2.0
Generate railroad diagrams from code or BNF, generate BNF from code
License: Apache License 2.0
This type of library lends itself to be published as a maven plugin, which can take BNF grammars as input and produce SVG content as output as part of a Maven build (e.g. to enrich Javadocs, etc.)
I'm considering adding support for labels to rule references (see jOOQ/jOOQ#10251). For example, I'd like to be able to define this grammar:
function = 'DATEDIFF' '(' (! field "fromDate" !) ',' (! field "toDate" !) ')';
field = ...;
The output should be this:
But the link anchors should point to field
.
Any thoughts? Preferences on syntax? My suggestion uses a (! ... !)
syntax similar to comments (* ... *)
and expects the name of the expression and an optional label. (! expression !)
is the same as expression
An alternative way to implement this would be to have label definitions in addition to rule definitions, such as:
function = 'DATEDIFF' '(' fromDate ',' toDate ')';
"fromDate" = field;
"toDate" = field;
field = ...;
Syntax again debatable. These labels would not appear in the output, just like before, but they would now be global. I personally prefer local labels.
On certain parse errors, there is a null pointer exception being thrown. For instance, when parsing this:
abc = x [
The following exception is thrown:
java.lang.NullPointerException
at chrriis.grammar.model.BNFToGrammar$Chunk.prune(BNFToGrammar.java:70)
at chrriis.grammar.model.BNFToGrammar$Chunk.prune(BNFToGrammar.java:147)
at chrriis.grammar.model.BNFToGrammar$Chunk.access$1(BNFToGrammar.java:68)
at chrriis.grammar.model.BNFToGrammar.createRule(BNFToGrammar.java:330)
at chrriis.grammar.model.BNFToGrammar.convert(BNFToGrammar.java:300)
at chrriis.grammar.rrdiagram.RRDiagramTests.grammar(RRDiagramTests.java:95)
at chrriis.grammar.rrdiagram.RRDiagramTests.testParseError(RRDiagramTests.java:78)
This can be rather cumbersome if the grammar is large, as there is no indication whatsoever about what went wrong.
It would be nice if grammars, rules, etc. would print their own BNF representation when debugging.
Should the link be http://www.bottlecaps.de/rr/ui
instead of
http://railroad.my28msec.com/rr/ui
or is the site just dead?
It would be really good if the library did not have a dependency on awt. This would mean that there would be another library awt-rrdiagram that has a font factory that uses awt classes to measure text length etc.
I did a first pass here -> https://github.com/billy1380/RRDiagram.
Please let me know if there is any interest.
The reason I thought this might be useful is because I would like to use it with gwt. The result can be found here:
https://www.willshex.com/#!e_bnf
I found the idl spec and changed it a little to make it parsable and used it for testing (listing below).
Was a little disappointed that I had to add semi colons to mark the end of the lines
specification ::= definition+;
definition ::= type_dcl ";"|const_dcl ";"|except_dcl ";"|interface ";"|module ";";
module ::= "module" identifier "{" definition+ "}";
interface ::= interface_dcl | forward_dcl;
interface_dcl ::= interface_header "{" interface_body "}";
forward_dcl ::= "interface" identifier;
interface_header ::= "interface" identifier (inheritance_spec);
interface_body ::= export*;
export ::= type_dcl ";"|const_dcl ";"|except_dcl ";"|attr_dcl ";"|op_dcl ";";
inheritance_spec ::= ":" scoped_name ("," scoped_name)*;
scoped_name ::= identifier|"::" identifier|scoped_name "::" identifier;
const_dcl ::= "const" const_type identifier "=" const_exp;
const_type ::= integer_type|char_type|boolean_type|floating_pt_type|string_type|scoped_name;
const_exp ::= or_expr;
or_expr ::= xor_expr|or_expr "|" xor_expr;
xor_expr ::= and_expr|xor_expr "^" and_expr;
and_expr ::= shift_expr|and_expr "&" shift_expr;
shift_expr ::= add_expr|shift_expr ">>"add_expr|shift_expr "<<" add_expr;
add_expr ::= mult_expr|add_expr "+" mult_expr|add_expr "-" mult_expr;
mult_expr ::= unary_expr|mult_expr "*" unary_expr|mult_expr "/" unary_expr|mult_expr "%" unary_expr;
unary_expr ::= unary_operator primary_expr|primary_expr;
unary_operator ::= "-"|"+"|"~";
primary_expr ::= scoped_name|literal|"(" const_exp ")";
literal ::= integer_literal|string_literal|character_literal|floating_pt_literal|boolean_literal;
boolean_literal ::= "TRUE"|"FALSE";
positive_int_const ::= const_exp;
type_dcl ::= "typedef" type_declarator|struct_type|union_type|enum_type;
type_declarator ::= type_spec declarators;
type_spec ::= simple_type_spec|constr_type_spec;
simple_type_spec ::= base_type_spec|template_type_spec|scoped_name;
base_type_spec ::= floating_pt_type|integer_type|char_type|boolean_type|octet_type|any_type;
template_type_spec ::= sequence_type|string_type;
constr_type_spec ::= struct_type|union_type|enum_type;
declarators ::= declarator ( "," declarator )*;
declarator ::= simple_declarator|complex_declarator;
simple_declarator ::= identifier;
complex_declarator ::= array_declarator;
floating_pt_type ::= "float"|"double";
integer_type ::= signed_int|unsigned_int;
signed_int ::= signed_long_int|signed_short_int;
signed_long_int ::= "long";
signed_short_int ::= "short";
unsigned_int ::= unsigned_long_int|unsigned_short_int;
unsigned_long_int ::= "unsigned" "long";
unsigned_short_int ::= "unsigned" "short";
char_type ::= "char";
boolean_type ::= "boolean";
octet_type ::= "octet";
any_type ::= "any";
struct_type ::= "struct" identifier "{" member_list "}";
member_list ::= member+;
member ::= type_spec declarators ";";
union_type ::= "union" identifier "switch" "(" switch_type_spec ")" "{" switch_body "}";
switch_type_spec ::= integer_type|char_type|boolean_type|enum_type|scoped_name;
switch_body ::= case+;
case ::= case_label+ element_spec ";";
case_label ::= "case" const_exp ":"|"default" ":";
element_spec ::= type_spec declarator;
enum_type ::= "enum" identifier "{" enumerator ( "," enumerator )* "}";
enumerator ::= identifier;
sequence_type ::= "sequence" "<" simple_type_spec "," positive_int_const ">"|"sequence" "<" simple_type_spec ">";
string_type ::= "string" "<" positive_int_const ">"|"string";
array_declarator ::= identifier fixed_array_size+;
fixed_array_size ::= "[" positive_int_const "]";
attr_dcl ::= "readonly"? "attribute" param_type_spec simple_declarator (","simple_declarator)*;
except_dcl ::= "exception" identifier "{" member* "}";
op_dcl ::= op_attribute? op_type_spec identifier parameter_dcls raises_expr? context_expr?;
op_attribute ::= "oneway";
op_type_spec ::= param_type_spec|"void";
parameter_dcls ::= "(" param_dcl ("," param_dcl)* ")"|"(" ")";
param_dcl ::= param_attribute param_type_spec simple_declarator;
param_attribute ::= "in"|"out"|"inout";
raises_expr ::= "raises" "(" scoped_name ("," scoped_name)* ")";
context_expr ::= "context" "(" string_literal ( "," string_literal)* ")";
param_type_spec ::= base_type_spec string_type scoped_name;
I get this in my bugs file;
Failed to load Main-Class manifest attribute from
RRDiagram.jar
I use this to run the program;
java -Duser.home=I:\PROGRAMS\RRDiagram -jar RRDiagram.jar 2>RRDiagram-bugs.txt
Of course java can be found.
Question: How to start the program?
This rule causes a parsing error:
func_mods ::= func_mod+ ('private' func_mod*)?
java.lang.IllegalStateException: Expecting start of a comment after '(' but could not find '*'!
at net.nextencia.rrdiagram.grammar.model.BNFToGrammar.convert(BNFToGrammar.java:320)
at net.nextencia.rrdiagram.grammar.model.BNFToGrammar.convert(BNFToGrammar.java:285)
It can be reproduced with this test:
@Test
public void testRepeatedOptional() {
svg("func_mod+ ('private' func_mod*)?");
}
The existing method accepts a Reader
, which is a reasonable default:
But in many cases, a String
argument might be more convenient, specifically in unit tests. We should overload this method with the usual variants that are available when a Reader
is available, including String
, InputStream
(together with encoding), File
, etc.
In order to facilitate both contributions and distribution, I suggest the license be changed to ASL 2.0. In particular the legal impact any modification may have on the distribution of the library is not very clear in the LGPL.
Besides, the ASL is understood not to require and CLA to make sure that all contributions are made under the terms of the ASL as well.
@Chrriis: Do you confirm this license change or do you prefer RRDiagram to stay under the terms of the LGPL?
The diagrams of some rules may become quite wide. Of course, we can use GrammarToRRDiagram.setRuleConsideredAsLineBreak()
to insert explicit line breaks into grammars, but sometimes, we don't want to put UI information into a grammar for cleaner separation of concerns. So it would be interesting if we could produce automatic line breaks at a certain width. There are different possible strategies which could be discussed in this issue.
The current implementation hard-codes a variety of purely stylistic elements. It should be possible to:
The exact specification of this change will follow.
Instructions here:
http://central.sonatype.org/pages/ossrh-guide.html
This change depends on #15 (renaming of Maven groupId)
The above rule causes an exception:
Caused by: java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 1
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:374)
at java.base/java.util.ArrayList.get(ArrayList.java:459)
at net.nextencia.rrdiagram.grammar.model.BNFToGrammar$Chunk.prune(BNFToGrammar.java:116)
at net.nextencia.rrdiagram.grammar.model.BNFToGrammar$Chunk.prune(BNFToGrammar.java:148)
at net.nextencia.rrdiagram.grammar.model.BNFToGrammar$Chunk.access$100(BNFToGrammar.java:35)
at net.nextencia.rrdiagram.grammar.model.BNFToGrammar.createRule(BNFToGrammar.java:344)
at net.nextencia.rrdiagram.grammar.model.BNFToGrammar.convert(BNFToGrammar.java:313)
whereas SIGN ::= [xy]
is successfully parsed. Are you supposed to use some special escaping?
The word "Java" does not appear at all in the README.md
This project should be distributed on Maven Central. The first step is to transform the directory layout to Maven style, and add a pom.xml
The source code makes use of quite a few @FunctionalInterfaces
, which would be really nice to use with lambda syntax.
@Chrriis: Do you agree if the source and target language level is upgraded to 1.8?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.