def test_simple_ml(): _test_simple_ml() ze_exp.lang.as_fixed() _test_simple_ml() parse = build_parser(ze_exp.lang, opt=True) print(parse("let x = 1 in x"))
engine ::= 'engine' '{' kvs=(kv (',' kv)*) '}' -> Engine(dict(kvs)) id ::= name=Name -> name.value python ::= mark='python' codes=(_{is_indented})+ -> Python(recover_codes([mark, *codes])[len('python'):]) field ::= id=id ':' type=expr ops=option* ['=' value=expr] -> Field(id, type, ops, value) fields ::= fields<<field (',' fields<<field)* [','] -> fields repr ::= '{' names=(id (',' id)*) '}' -> names[::2] table ::= id=id '{' [fields=fields] ['repr' repr=repr] '}' -> Table(id, fields or [], repr) option ::= ch=('~' | '!' | '?') -> ch.value relation ::= left=id w1=['^'] 'with' w2=['^'] right=id '{' field_lst=(field (',' field)*) '}' -> Relation(left, right, (bool(w1), bool(w2)), field_lst[::2]) expr ::= | [is_enum='enum'] tks=(~('=' | '{' | '}' | '!' | '?' | '~' | ',' | 'repr' | 'with'))+ -> (EnumValue if is_enum else Value)(recover_codes(tks)) lexer_helper := R'.' stmts ::= stmts=(engine | relation | table | python)+ -> list(stmts) """ dbg = Language('dbg') dbg.namespace.update(dbg_ast.__dict__) build_language(source_code, dbg, 'dbg-lang.rbnf') parse = build_parser(dbg)
import re from rbnf.easy import Language, build_language, build_parser from ast import fix_missing_locations from astpretty import pprint from rbnfrbnf import constructs with open('rbnf-bootstrap.rbnf') as f: code = f.read() rbnf2 = Language('rbnf') rbnf2.namespace.update(constructs.__dict__) build_language(code, rbnf2, "rbnf-bootstrap.rbnf") test_line_start = re.compile('\S') parse = build_parser(rbnf2) def add_semi_comma(text: str): def _add_semi_comma(text_formal: str): for each in text_formal.split('\n'): if test_line_start.match(each): yield ';' yield each return '\n'.join(_add_semi_comma(text)) result = parse( add_semi_comma(""" X := 'a' A ::= ('b' | 'c' ('c' | 'a')) Z ::= 'b' recur F ::=
keyword cast := 'commit' 'Author:' sig := R'[0-9a-f]+' space := R'\n|\s+' head ::= 'commit' as mark space sig as sig (~'\n')* '\n' (~'Author:')* 'Author:' (~'<')+ as author '<' (~'>')+ as email '>' with mark.colno <= 1 rewrite sig.value, ''.join(e.value for e in author).strip(), ''.join(e.value for e in email).strip() section ::= head as sig (~head)+ rewrite sig lexer_helper := R'.' partial_text ::= (~section)* section as it rewrite it text ::= (section to [it] | ~section)+ rewrite it """ lang = Language("git-log") build_language(grammar, lang, '<python-internal>') parse = build_parser(lang, use_parser='text') partial_parse = build_parser(lang, use_parser='partial_text')
from rbnfrbnf.core import constructs import re import os cfg = Language('cfg-rbnf') test_line_start = re.compile('\S') def add_semi_comma(text: str): def _add_semi_comma(text_formal: str): for each in text_formal.split('\n'): if test_line_start.match(each): yield ';' yield each yield ';' return '\n'.join(_add_semi_comma(text)) directory = os.path.split(__file__)[0] with open(f'{directory}/context_free.rbnf') as f: source = f.read() cfg.namespace = {**constructs.__dict__} build_language(source, cfg, 'context_free.rbnf') _parse = build_parser(cfg) def parse(grammar): return _parse(add_semi_comma(grammar))
def run(filename: 'python file generated by `rbnf` command, or rbnf sour file', opt: 'optimize switch' = False): """ You can apply immediate tests on your parser. P.S: use `--opt` option takes longer starting time. """ from rbnf.easy import build_parser import importlib.util import traceback full_path = Path(filename) base, ext = os.path.splitext(str(full_path)) full_path_str = str(full_path) if not ext: if full_path.into('.py').exists(): full_path_str = base + '.py' elif Path(base).into('.rbnf'): full_path_str = base + '.rbnf' if full_path_str[-3:].lower() != '.py': with Path(full_path_str).open('r') as fr: ze_exp = ze.compile(fr.read(), filename=full_path_str) lang = ze_exp.lang else: spec = importlib.util.spec_from_file_location("runbnf", full_path_str) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) try: lang = next(each for each in mod.__dict__.values() if isinstance(each, Language)) except StopIteration: raise NameError("Found no language in {}".format(full_path_str)) parse = build_parser(lang, opt=bool(opt)) namespace = {} print(Purple('type `:i` to switch between python mode and parsing mode.')) print(Purple('The last result of parsing is stored as symbol `res`.')) while True: inp = input('runbnf> ') if not inp.strip(): continue elif inp.strip() == 'exit': break if inp.strip() == ':i': while True: inp = input('python> ') if inp.strip() == ':i': break try: try: res = eval(inp, namespace) if res is not None: print(res) namespace['_'] = res except SyntaxError: exec(inp, namespace) except Exception: traceback.print_exc() else: res = namespace['res'] = parse(inp) print( LightBlue( 'parsed result = res: ResultDescription{result, tokens, state}' )) print(res.result)