Created
September 15, 2016 13:27
-
-
Save tkruse/e07d9c5af6d3caad945f4715b130d407 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
# PoC Ros2Names parsing using EBNF and Grako (install from pypi) | |
# Tested with grako 3.14.0 | |
# | |
import grako | |
POSITIVES = "foo", "abc123", "_foo", "Foo", "BAR", "~", "foo/bar", "~/foo", "{foo}_bar", "foo/{ping}/bar", "foo/_/bar", "rosservice:///foo", "rostopic://foo/bar" | |
NEGATIVES = "123abc", "123", "__foo", "foo__bar", "foo bar", "foo__", "foo_", "foo//bar", "foo/", "~foo", "foo~", "foo~/bar", "foo/~bar", "/_/bar", "_", "_/_bar", "/~", "foo/~/bar", "{", "}", "}{" | |
TODO = "foo{x1}bar{x2}baz", "foo_/bar" | |
## Short EBNF Grako introduction | |
# [] optional element | |
# {} repetition | |
# (* *) comment | |
# | alternative (order matters, first are tried first) | |
# '' token | |
# / / regex? | |
grammar = """ | |
uriname | |
= | |
[ urischeme ] pathname $ | |
; | |
urischeme | |
= | |
namecharp '://' | |
; | |
pathname | |
= | |
['/' | '~/'] startpathsegment '/' { pathsegment '/' } endpathsegment | |
| | |
['/' | '~/'] singlename | |
| | |
'~' | |
; | |
(* must not start with digit *) | |
startpathsegment | |
= | |
/[_A-Za-z][_A-Za-z0-9]+/ | |
| | |
/[_A-Za-z][_A-Za-z0-9]*/ '{' namecharx '}' namecharx | |
; | |
pathsegment | |
= | |
namecharp | |
| | |
namecharx '{' namecharx '}' namecharx | |
; | |
(* must not finish with _ *) | |
endpathsegment | |
= | |
/[_A-Za-z0-9]*[A-Za-z0-9]/ | |
| | |
namecharx '{' /[_A-Za-z0-9]*/ '}' { /[_A-Za-z0-9]*[A-Za-z0-9]/ } | |
; | |
(* must not start with digit, nor finish with _ *) | |
singlename | |
= | |
/[_A-Za-z][_A-Za-z0-9]*[A-Za-z0-9]/ | |
| | |
[ /[_A-Za-z][_A-Za-z0-9]*/ ] '{' namecharx '}' { /[_A-Za-z0-9]*[A-Za-z0-9]/ } | |
| | |
/[A-Za-z]/ | |
; | |
namecharp | |
= | |
/[_A-Za-z0-9]+/ | |
; | |
namecharx | |
= | |
/[_A-Za-z0-9]*/ | |
; | |
""" | |
def test_main(): | |
for s in POSITIVES: | |
print("ACCEPTED: %s \t as %s " % (s, parse(s))) | |
print('=' * 40) | |
for s in NEGATIVES: | |
thrown = False | |
try: | |
print("ERROR, SHOULD REFUSE: %s \t\t as %s" % (s, parse(s))) | |
except Exception: | |
print("REJECTED: " + s) | |
thrown = True | |
assert thrown | |
def parse(s): | |
model = grako.genmodel("model", grammar) | |
if ('__' in s): | |
raise Exception("Must not cointain consecutive slashes") | |
ast = model.parse(s, "uriname") | |
return ast | |
if __name__ == '__main__': | |
test_main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment