-
-
Save xmonader/8e60b3311d0f4a2b460444c3f6a45da8 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| 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