Last active
July 19, 2018 16:03
-
-
Save kurtbrose/05f2dd879eba6a88a3dc7c13e36ce772 to your computer and use it in GitHub Desktop.
little parsley examples
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
# how to separate items in a list from separators | |
parsley.makeGrammar(''' | |
a_list = ('a':it ','? -> it)* | |
''', {})('a,a,a').a_list() | |
# result is ['a', 'a', 'a'] | |
# strict comma-delimeted items (at least one item) | |
parsley.makeGrammar(''' | |
a_list = 'a':first (',' 'a')*:rest -> [first] + rest | |
''', {})('a,a,a').a_list() | |
''' | |
# parsing a list of 'a's | |
parsley.makeGrammar(''' | |
a_list = '[' ('a':it ','? -> it)*:li ']' -> li | |
''', {})('[a,a,a,]').a_list() | |
# result is ['a', 'a', 'a'] | |
# parsing anything between quotes | |
parsley.makeGrammar(''' | |
string = '"' <(~'"' anything)*>:val '"' -> val | |
''', {})('"abc"').string() | |
# result is 'abc' | |
# dropping optional whitespace delimeters | |
parsley.makeGrammar(''' | |
skip_ws = (ws 'a')* | |
''', {})('aa a a').skip_ws() | |
# result is ['a', 'a', 'a', 'a'] | |
# embedding a python literal into an expression | |
parsley.makeGrammar(''' | |
one = !(1) | |
''', {})('').one() | |
# result is 1 | |
# default argument with python expression | |
parsley.makeGrammar(''' | |
orone = 'a' | !(1) | |
''', {})('').orone() | |
# result is 1 | |
parsley.makeGrammar(''' | |
orone = 'a' | !(1) | |
''', {})('a').orone() | |
# result is 'a' | |
# to round out how this might be used | |
parsley.makeGrammar(''' | |
a_b_def_c = 'a' | 'b' | !('c') | |
''', {})('').a_b_def_c() | |
# match and return 'a' or 'b' as the next character; if neither is present, return 'c' as a default | |
# also, None as a default is a special case -- ? expression evals to None | |
parsley.makeGrammar(''' | |
ornone = 'a'? | |
''', {})('').ornone() == None | |
# True | |
# matching string tokens to constants from a python data structure | |
# e.g. a dict or enum | |
parsley.makeGrammar(''' | |
result = ('a' !(const['a'])) | ('b' !(const['b'])) | |
''', {'const': {'a': 'AAA', 'b': 'BBB'}})('b').result() | |
# result is 'BBB' | |
# match anything as long as it isn't in a list of reserved words | |
parsley.makeGrammar(''' | |
forbidden = 'int' | 'float' | |
identifier = ~forbidden <anything*> | |
''', {})('int').identifier() | |
# parse error | |
parsley.makeGrammar(''' | |
forbidden = 'int' | 'float' | |
identifier = ~forbidden <anything*> | |
''', {})('cat').identifier() | |
# returns 'cat' | |
# parse the bodies of C and C++ style comments | |
COMMENTS = ''' | |
// hello /* <- nested | |
/* world // <- nested */ | |
''' | |
parsley.makeGrammar(''' | |
c_comment = '//' <('\\\n' | (~'\n' anything))*> | |
cpp_comment = '/*' <(~'*/' anything)*>:body '*/' -> body | |
ws_char = ' ' | '\t' | '\n' | |
comments_only = (ws_char | c_comment | cpp_comment)* | |
''', {})(COMMENTS).comments_only() | |
# returns ['\n', ' hello /* <- nested', '\n', ' world // <- nested ', '\n'] | |
# pass a match string in parent rule as argument to child rule | |
parsley.makeGrammar(''' | |
a = <digit+>:n b(n) | |
b :n = 'plus_one' -> int(n) + 1 | |
''', {})('1plus_one').a() | |
# returns 2 | |
# simple self-recursive tree | |
parsley.makeGrammar(''' | |
matched_trees = tree:first matching(first) | |
tree = 'a'?:val ('b' tree)?:left ('c' tree)?:right -> val, left, right | |
''', {})('ababa').tree() | |
# returns ('a', ('a', ('a', None, None), None), None) | |
# unpacking earlier value as part of recursive descent | |
parsley.makeGrammar(''' | |
stuff = 'a' -> 1, 2 | |
parent = stuff:arg child(arg) | |
child :param = grandchild(param[0]) | |
grandchild :n = -> n | |
''', {})('a').parent() | |
# returns 1 aka stuff[0] | |
# pattern-matching? not sure if this is a real feature | |
parsley.makeGrammar(''' | |
match 'a' = 'a' | |
match 'b' = 'b' | |
match2 :c = <match(c) match(c)> | |
''', {})('bb').match2('b') | |
# returns 'bb' | |
parsley.makeGrammar(''' | |
match 'a' = 'a' | |
match 'b' = 'b' | |
match2 :c = <match(c) match(c)> | |
''', {})('bb').match2('a') | |
# raises ParseError: expected one of 'a', or 'b'. trail: [] | |
# rule for matching the rest of the line; extremely useful for comments | |
parsley.makeGrammar(''' | |
rest_of_line = <('\\\n' | (~'\n' anything))*> | |
bash_comment = '#' rest_of_line | |
script = (('\n'*)? bash_comment)* | |
''', {})('# this is\n#some comments\n###the end.###').script() | |
# returns [' this is', 'some comments', '##the end.###'] | |
# match a repeated string of the same character; reject / stop at the first different character | |
# this demonstrates: | |
# 1- capture a match into a python variable for processing | |
# 2- abstracting out a python-code to do arbitrary processing as a rule | |
parsley.makeGrammar(''' | |
arg_eq :a :b = ?(a == b) | |
repeating = <anything:first (anything:nxt arg_eq(first nxt))+> | |
''', {})('aaa').repeating() | |
# returns 'aaa' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment