From 980188d90cc8ff8f211d82919f4482f7aaa5b567 Mon Sep 17 00:00:00 2001 From: hellerve Date: Mon, 27 Feb 2017 18:08:11 +0100 Subject: [PATCH] added memoization for a factor 100 speed improvement --- examples/golike.py | 4 ++-- gll/parser.py | 15 ++++++++++++++- gll/util.py | 12 ++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/examples/golike.py b/examples/golike.py index f9f8ebd..61b5a34 100644 --- a/examples/golike.py +++ b/examples/golike.py @@ -48,8 +48,8 @@ package_name = gll.seq(skipped("package"), ws, variable, gll.skipmany(gll.string(" ")), skipped("\n"), tag="package_name") -package = gll.seq(package_name, gll.sep_by(gll.string("\n"), function, - tag="package_body"), +package = gll.seq(package_name, gll.many(skipped("\n")), + gll.sep_by(gll.string("\n"), function, tag="package_body"), gll.many(skipped("\n")), tag="package") diff --git a/gll/parser.py b/gll/parser.py index 6128e1d..0e8686a 100644 --- a/gll/parser.py +++ b/gll/parser.py @@ -1,6 +1,6 @@ import re -from gll.util import rename +from gll.util import rename, memoize from gll.result import Success, Failure class Parser: @@ -16,6 +16,7 @@ class Parser: return self.fun.__name__ def __or__(self, other): + @memoize @rename("{}_alt_{}".format(self.name, other.name)) def internal(string): res = self(string) @@ -26,6 +27,7 @@ class Parser: return Parser(internal) def __rshift__(self, into): + @memoize @rename("{}_into_{}".format(self.name, into)) def internal(string): res = self(string) @@ -34,6 +36,7 @@ class Parser: def string(match, tag="string"): + @memoize @rename("string_{}".format(match)) def internal(string): ln = len(match) @@ -53,6 +56,7 @@ def regex(match, tag="regex", reopts=None): reopts = [] rx = re.compile(match, *reopts) + @memoize @rename("regex_{}".format(match)) def internal(string): res = rx.match(string) @@ -64,6 +68,7 @@ def regex(match, tag="regex", reopts=None): def digit(tag="digit"): + @memoize @rename("digit") def internal(string): if not string: @@ -77,6 +82,7 @@ def digit(tag="digit"): def many(parser, tag="many"): + @memoize @rename("many_{}".format(parser.name)) def internal(string): res = parser(string) @@ -94,6 +100,7 @@ def many(parser, tag="many"): def many1(parser, tag="many1"): + @memoize @rename("many1_{}".format(parser.name)) def internal(string): res = parser(string) @@ -111,6 +118,7 @@ def many1(parser, tag="many1"): def whitespace(tag="whitespace"): + @memoize @rename("whitespace") def internal(string): if not string: @@ -124,6 +132,7 @@ def whitespace(tag="whitespace"): def skip(parser, tag="skip"): + @memoize @rename("skip_{}".format(parser.name)) def internal(string): res = parser(string) @@ -139,6 +148,7 @@ def skipmany(parser, tag="skipmany"): def sep_by(separator, parser, tag="sep_by"): + @memoize @rename("{}_sep_by_{}".format(parser.name, separator.name)) def internal(string): if not string: @@ -162,6 +172,7 @@ def sep_by(separator, parser, tag="sep_by"): def opt(parser, tag="opt"): + @memoize @rename("opt_{}".format(parser.name)) def internal(string): res = parser(string) @@ -172,6 +183,7 @@ def opt(parser, tag="opt"): def seq(*parsers, tag="seq"): + @memoize @rename("seq_{}".format("_".join(str(parser.name) for parser in parsers))) def internal(string): resl = [] @@ -187,6 +199,7 @@ def seq(*parsers, tag="seq"): def all(parser, tag="all"): + @memoize @rename("all_{}".format(parser.name)) def internal(string): res = parser(string) diff --git a/gll/util.py b/gll/util.py index 7e3413d..063c991 100644 --- a/gll/util.py +++ b/gll/util.py @@ -1,5 +1,17 @@ +from functools import wraps + def rename(name): def wrapped(f): f.__name__ = name return f return wrapped + + +def memoize(f): + d = {} + @wraps(f) + def internal(arg): + if arg not in d: + d[arg] = f(arg) + return d[arg] + return internal