Skip to content

Instantly share code, notes, and snippets.

@justinfay
Created January 19, 2017 11:36
Show Gist options
  • Save justinfay/e082cdb4f8fc00cd96c63960277df270 to your computer and use it in GitHub Desktop.
Save justinfay/e082cdb4f8fc00cd96c63960277df270 to your computer and use it in GitHub Desktop.
# http://theorangeduck.com/page/you-could-have-invented-parser-combinators
stream = list('abcdefghijklmnopqrstuvwxyz')
def literal(char):
"""
Parser which matches a character.
"""
def parser(stream):
if stream[0] == char:
return stream.pop(0)
raise Exception()
return parser
def or_(parser1, parser2):
"""
Boolean or statement.
"""
def parser(stream):
try:
return parser1(stream)
except:
return parser2(stream)
return parser
def and_(parser1, parser2):
"""
Boolean and statement.
"""
def parser(stream):
return [parser1(stream), parser2(stream)]
return parser
def apply_(func, parser):
"""
Parser which applies a func to the result
of another parser.
"""
def _parser(stream):
return func(parser(stream))
return _parser
def literal_to_int(char):
"""
Parser which converts characters to ints.
"""
return apply_(ord, literal(char))
if __name__ == "__main__":
# We want to match tokens that begin with either 'ab'
# or 'cd'.
parser = or_(
and_(literal_to_int('a'), literal_to_int('b')),
and_(literal_to_int('c'), literal_to_int('d')))
print parser(stream)
print stream
print parser(stream)
print stream
print parser(['c', 'd'])
try:
parser(stream)
except Exception:
# All good.
pass
next_parser = literal_to_int('e')
print next_parser(stream)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment