Skip to content

Instantly share code, notes, and snippets.

@xmonader
Created May 14, 2018 22:17
Show Gist options
  • Save xmonader/8e60b3311d0f4a2b460444c3f6a45da8 to your computer and use it in GitHub Desktop.
Save xmonader/8e60b3311d0f4a2b460444c3f6a45da8 to your computer and use it in GitHub Desktop.
from functools import reduce
import string
class Maybe:
pass
class Just(Maybe):
def __init__(self, val):
self.val = val
def __str__(self):
return "<Just %s>"%str(self.val)
class Nothing(Maybe):
def __str__(self):
return "<Nothing>"
class Either:
pass
class Left:
def __init__(self, errmsg):
self.errmsg = errmsg
def __str__(self):
return "(Left %s)"%self.errmsg
def map(self, f):
return self
class Right:
def __init__(self, val):
self.val = val
def __str__(self):
return "(Right %s)"% str(self.val)
def map(self, f):
print("SELF.VAL IN RIGHT: ", self.val)
return Right( (f("".join(self.val[0])), self.val[1]) )
class Parser:
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
return self.f(*args, **kwargs)
def __rshift__(self, rparser):
return andThen(self, rparser)
def __or__(self, rparser):
return orElse(self, rparser)
def map(self, transformer):
return Parser(lambda *args, **kwargs: self.f(*args, **kwargs).map(transformer))
def compose(p1, p2):
def newf(*args, **kwargs):
return p2(p1(*args, **kwargs))
return newf
def runParser(p, inp):
print("P: ", p)
print("INP: ", inp)
return p(inp)
# print(parseChar("a")("abc"))
# print(parseChar("a")("zbc"))
def andThen(p1, p2):
print("P1: ", p1, " P2: ", p2)
def curried(s):
res1 = p1(s)
if isinstance(res1, Left):
return res1
else:
res2 = p2(res1.val[1]) # parse remaining chars.
if isinstance(res2, Right):
return Right( ([res1.val[0], res2.val[0]], res2.val[1]))
return res2
return Parser(curried)
def orElse(p1, p2):
def curried(s):
res = p1(s)
if isinstance(res, Right):
return res
else:
res = p2(s)
if isinstance(res, Right):
return res
else:
return Left("Failed at both")
return Parser(curried)
def parseChar(c):
def curried(s):
if not s:
msg = "S is empty"
return Left(msg)
else:
if s[0] == c:
return Right((c, s[1:]) )
else:
return Left("Expecting '%s' and found '%s'"%(c, s[0]))
return Parser(curried)
foldl = reduce
def choice(parsers):
return foldl(orElse, parsers)
def anyOf(chars):
return choice(list(map(parseChar, chars)))
def parseString(s):
return foldl(andThen, list(map(parseChar, list(s))))
def parseDigit():
return anyOf(list(string.digits))
aparser = parseChar("a")
bparser = parseChar("b")
# print(runParser(aparser, "abc"))
# print(runParser(bparser, "bcd"))
# abparser = andThen(aparser, bparser)
# print(runParser(abparser, "abc"))
# aorbparser = orElse(aparser, bparser)
# print(runParser(aorbparser, "akcd"))
# print(runParser(aorbparser, "bkcd"))
# p = compose(aparser, bparser)
# p("abc")
abparser = aparser >> bparser
print(runParser(abparser, "abc"))
aorbparser = aparser| bparser
print(runParser(aorbparser, "akcd"))
print(runParser(aorbparser, "bkcd"))
abcdeparser = anyOf(list("abcde"))
print(runParser(abcdeparser, "abcde"))
print(runParser(abcdeparser, "ello"))
abcparser = parseString("abc")
print(runParser(abcparser, "abcd"))
lowerparser = anyOf(string.ascii_lowercase)
print(runParser(lowerparser, "abcd"))
digitparser = anyOf(string.digits)
print(runParser(digitparser, "12abc"))
twodigitparser = digitparser >> digitparser
print(runParser(twodigitparser, "12abcd"))
twodigitparserAsInt = twodigitparser.map(int)
print(runParser(twodigitparserAsInt, "12abcd"))
def parseZeroOrMore(parser, inp): #zero or more
res = parser(inp)
if isinstance(res, Left):
return "", inp
else:
firstval, restinpafterfirst = res.val
subseqvals, remaining = parseZeroOrMore(parser, restinpafterfirst)
values = firstval+subseqvals
return values, remaining
def many(parser):
def curried(s):
return Right(parseZeroOrMore(parser,s))
return Parser(curried)
manyAparser = many(parseChar("a"))
print(runParser(manyAparser, "aaab"))
print(runParser(manyAparser, "bbc")) # zero or more
def many1(parser):
def curried(s):
res = runParser(parser, s)
if isinstance(res, Left):
return res
else:
return runParser(many(parser), s)
return Parser(curried)
whitespaceParser = anyOf(string.whitespace)
print(runParser(whitespaceParser, "\thello"))
whitespaceGreeting = whitespaceParser >> many(lowerparser)
print(runParser(whitespaceGreeting, "\thello"))
many1aParser = many1(parseChar("a"))
print(runParser(many1aParser, "aaab"))
print(runParser(many1aParser, "bbc")) # zero or more
manyDigits = many1(digitparser)
manyDigitsAsInt = manyDigits.map(int)
print(runParser(manyDigitsAsInt, "12345bcd"))
def optionally(parser):
noneparser = Parser(lambda x: Right( (Nothing, "")))
return orElse(parser, noneparser)
aquestionparser = parseChar("a") >> optionally(parseChar("?"))
print(runParser(aquestionparser, "a?"))
print(runParser(aquestionparser, "a"))
pint = optionally(parseChar("-")) >> manyDigits
def convertToNum(args):
sign = args[0]
num = "".join(args[1:])
num = int(num)
if sign == "-":
return num*-1
return num
parsesignedint = pint.map(convertToNum)
print(runParser(parsesignedint, "-10"))
ab_space_cd_parser = parseString("ab") >> many1(whitespaceParser) >> parseString("cd")
print(ab_space_cd_parser("ab cd"))
ab_space_cd_ef_parser = parseString("ab") >> many1(whitespaceParser) >> parseString("cd") >> parseString("ef")
print(ab_space_cd_ef_parser("ab cdef"))
between = lambda p1, p2 , p3 : p1 >> p2 >> p3
singlequote = parseChar('"')
wordinquotes = None
def oninnerword(x):
global wordinquotes
wordinquotes = x
return x
quotedword = between(singlequote, many1(lowerparser).map(oninnerword), singlequote)
print(quotedword('"a"'))
print(wordinquotes)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment