def toplabel(): return Choice( 0, ALPHA(), Sequence( ALPHA(), ZeroOrMore(Choice(0, alphanum(), "-")), alphanum() ) )
def generate_sequence(name, *modifiers): if len(modifiers) == 1: return Sequence( name, Optional(Sequence(copy(whitespace), Choice(0, *modifiers)), skip=SKIP)) return Sequence( name, ZeroOrMore(Sequence( copy(whitespace), Choice(0, *modifiers), ), skip=SKIP), )
def paramchar(): return Choice( 0, Group(param_unreserved(), "param_unreserved"), Group(unreserved(), "unreserved"), Group(pct_encoded(), "pct-encoded") )
def uric(): return Choice( 0, Group(reserved(), "reserved"), Group(unreserved(), "unreserved"), Group(pct_encoded(), "pct-encoded") )
def dec_octet(): return Choice( 0, DIGIT(), Sequence(HorizontalChoice("1", "2", "3", "4", "5", "6", "7", "8", "9"), DIGIT()), Sequence("1", DIGIT(), DIGIT()), Sequence("2", HorizontalChoice("0", "1", "2", "3", "4"), DIGIT()), Sequence("25", HorizontalChoice("0", "1", "2", "3", "4", "5")))
def par(): return Choice( 0, Group(parameter(), "parameter"), Group(extension(), "extension"), Group(isdn_subaddress(), "isdn-subaddress") )
def recurse(p: Parser) -> Union[DiagramItem, str, None]: # Transform parsers are just ignored if isinstance(p, _Transform): return recurse(p.children[0]) elif isinstance(p, Opt): # Opt parsers are straightforwardly wrapped into an Optional return Optional(recurse(p.parser)) elif isinstance(p, _Extract): # Extract is ignored return recurse(p.parser) # For list parsers, we create a sequence with the right separator # and sub-parser. elif isinstance(p, List): sep = recurse(p.sep) if p.sep else None child = recurse(p.parser) if p.empty_valid: return ZeroOrMore(child, repeat=sep) else: return OneOrMore(child, repeat=sep) # For defers, we just return the rule name elif isinstance(p, Defer): return p.rule_name # For tokens, we return either the quoted original string, or the DSL # name. elif isinstance(p, _Token): if p._original_string: return repr(p._original_string) else: return p.val.dsl_name children = [] for c in p.children: res = recurse(c) if res is not None: children.append(res) if isinstance(p, Or): if len(children) == 0: return None children = sorted(children, key=lambda c: isinstance(c, Skip)) return Choice(0, *children) elif isinstance(p, _Row): if len(children) == 0: return Skip() return Sequence(*children) else: return None
def phonedigit(): return Choice( 0, DIGIT(), Optional( Group(visual_separator(), "visual-separator") ) )
def hier_part(): return Optional( Choice( 0, Sequence("//", Group(Sequence(*authority()), "authority"), Group(path_abempty(), "path-abempty")), Group(path_absolute(), "path-absolute"), Group(path_rootless(), "path-rootless")))
def domainlabel(): return Choice(0, alphanum(), Sequence( alphanum(), ZeroOrMore(Sequence(alphanum(), "-")), alphanum() ) )
def phonedigit_hex(): return Choice( 0, HEXDIG(), "*", "#", Optional( Group(visual_separator(), "visual-separator") ) )
def generate_diagram(name, *modifiers): return NamedDiagram( name, Diagram( Sequence( name, ZeroOrMore( Sequence( copy(whitespace), Choice(0, *modifiers), ), skip=SKIP, ))))
def x_token(): return Sequence(Choice(0, "X-", "x-"), NonTerminal("token"))
def extension_token(): return Choice(0, ietf_token(), x_token())
def composite_type(): return Choice(0, "message", "multipart", extension_token())
def discrete_type(): return Choice(0, "text", "image", "audio", "video", "application", extension_token())
def type_(): return Choice(0, discrete_type(), composite_type())
def tspecials(): return Choice(0, "(", ")", "<", ">", "@", ",", ";", ":", "\\", "/", "[", "]", "?", "=")
def subtype(): return Choice(0, extension_token(), iana_token())
import sys from railroad import Diagram, Choice, OneOrMore d = Diagram("A", Choice(0, "B", "C"), OneOrMore("D")) with open('diagram.html', 'w') as f: d.writeSvg(f.write)
def local_number_digits(): return Sequence( ZeroOrMore(NonTerminal("phonedigit_hex")), Choice(0, HEXDIG(), "*", "#"), ZeroOrMore(NonTerminal("phonedigit_hex")) )
def pname(): return OneOrMore(Choice(0, alphanum(), "-"))
def descriptor(): return Choice( 0, Group(domainname(), "domainname"), Group(global_number_digits(), "global-number-digits") )
def unreserved(): return Choice(0, alphanum(), mark())
stroke:#000; fill:transparent; }} rect.group-box {{ stroke:gray; stroke-dasharray:10 5; fill:none; }} """ railroad.DIAGRAM_CLASS = '' railroad.DEFAULT_STYLE = css railroad.STROKE_ODD_PIXEL_LENGTH = STROKE_WIDTH % 2 == 1 railroad.CHAR_WIDTH = 7.5 padding = Sequence('padding:', Choice(0, 'zero', 'space', 'none')) case_sensitive = Sequence('case_sensitive:', Choice(0, 'true', 'false')) hour_repr = Sequence('repr:', Choice(0, '24', '12')) month_repr = Sequence('repr:', Choice(0, 'numerical', 'long', 'short')) period_case = Sequence('case:', Choice(0, 'lower', 'upper')) sign = Sequence('sign:', Choice(0, 'automatic', 'mandatory')) subsecond_digits = Sequence( 'digits:', Choice(0, '1+', '1', '2', '3', '4', '5', '6', '7', '8', '9')) weekday_repr = Sequence('repr:', Choice(0, 'long', 'short', 'sunday', 'monday')) weekday_one_indexed = Sequence('one_indexed:', Choice(0, 'false', 'true')) week_number_repr = Sequence('repr:', Choice(0, 'iso', 'sunday', 'monday')) year_repr = Sequence('repr:', Choice(0, 'full', 'last_two')) year_base = Sequence('base:', Choice(0, 'calendar', 'iso_week')) whitespace = Comment('whitespace')
def value(): return Choice(0, token(), quoted_string())
def token(): return OneOrMore(Choice(0, alphanum(), tspecials()))
def telephone_subscriber(): return Choice( 0, Group(global_number(), "global-number"), Group(local_number(), "local-number") )
#!/usr/bin/env python3 import sys from railroad import Diagram, Choice d = Diagram("foo", Choice(0, "bar", "baz")) d.writeSvg(sys.stdout.write)
def unreserved(): return Choice(0, HorizontalChoice(ALPHA(), DIGIT()), HorizontalChoice("-", ".", "_", "~"))