Skip to content

Instantly share code, notes, and snippets.

@kurtbrose
Last active July 19, 2018 16:03
Show Gist options
  • Save kurtbrose/05f2dd879eba6a88a3dc7c13e36ce772 to your computer and use it in GitHub Desktop.
Save kurtbrose/05f2dd879eba6a88a3dc7c13e36ce772 to your computer and use it in GitHub Desktop.
little parsley examples
# 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