From 6a8d39fc88aae2143249a45ad5321d816471032f Mon Sep 17 00:00:00 2001 From: hellerve Date: Mon, 27 Feb 2017 14:18:45 +0100 Subject: [PATCH] better analytics, worked on golike syntax --- examples/golike.py | 52 +++++++++++++++++++++++++++------ gll/__init__.py | 2 +- gll/parser.py | 71 +++++++++++++++++++++++++++++++++------------- 3 files changed, 96 insertions(+), 29 deletions(-) diff --git a/examples/golike.py b/examples/golike.py index 3199557..f9f8ebd 100644 --- a/examples/golike.py +++ b/examples/golike.py @@ -1,22 +1,56 @@ import gll -ws = gll.skipmany(gll.whitespace()) -skipped = lambda pat: gll.skip(gll.string(pat)) +@gll.parser("expression") +def expression(string): + parser = gll.seq(ws, func_call | literal, ws, tag="expression") -body = gll.seq(skipped("{"), skipped("}")) + return parser(string) -argument = gll.seq(gll.regex("\w+", tag="argument"), ws, - gll.regex("\w+", tag="type"), gll.skip(gll.regex("[\s,]*"))) -arguments_list = gll.seq(skipped("("), gll.many(argument), skipped(")"), tag="arguments") +ws = gll.skipmany(gll.string(" ")) +skipped = lambda pat: gll.skip(gll.string(pat), tag="skip_{}".format(pat)) +variable = gll.regex("\w+", tag="variable_name") +type_decl = gll.regex("\w+", tag="type") +comma = gll.skip(gll.regex(r"\s*,\s*")) + +number = gll.many1(gll.digit(), tag="number") +string = gll.seq(skipped("\""), gll.regex(r'[^"\\]+'), skipped("\""), tag="string") +lst = gll.seq(skipped("["), gll.sep_by(comma, expression | variable), + skipped("]"), tag="list") + +declaration = gll.seq(skipped("var"), ws, variable, ws, type_decl, tag="declaration") + +assignment = gll.seq(variable, ws, skipped("="), ws, expression, tag="assignment") + +return_statement = gll.seq(skipped("return"), ws, expression, + tag="return") + +func_call = gll.seq(variable, skipped("("), + gll.sep_by(comma, expression | variable, tag="arguments"), + skipped(")"), tag="call") + +literal = number | string | lst + +special = gll.seq(ws, return_statement | declaration | assignment, ws) + +body = gll.seq(skipped("{"), skipped("\n"), + gll.sep_by(gll.regex(r"\s*\n+\s*"), expression | special, tag="body"), + gll.opt(skipped("\n")), skipped("}")) + +argument = gll.seq(variable, ws, type_decl, tag="parameter") +arguments_list = gll.seq(skipped("("), gll.sep_by(comma, argument), + skipped(")"), tag="parameters") function = gll.seq(skipped("func"), ws, gll.regex("\w+", tag="function_name"), - ws, arguments_list, ws, body, ws, tag="function") + ws, arguments_list, ws, type_decl, ws, body, ws, + tag="function") -package_name = gll.seq(skipped("package"), ws, gll.regex("\w+", tag="name"), +package_name = gll.seq(skipped("package"), ws, variable, gll.skipmany(gll.string(" ")), skipped("\n"), tag="package_name") -package = gll.seq(package_name, gll.many(function, tag="package_body"), +package = gll.seq(package_name, gll.sep_by(gll.string("\n"), function, + tag="package_body"), + gll.many(skipped("\n")), tag="package") parser = gll.all(package) diff --git a/gll/__init__.py b/gll/__init__.py index 5ef271d..6973fb0 100644 --- a/gll/__init__.py +++ b/gll/__init__.py @@ -1,2 +1,2 @@ from gll.parser import string, digit, many, many1, whitespace, skip, skipmany,\ - opt, regex, seq, all + opt, regex, seq, all, sep_by, parser diff --git a/gll/parser.py b/gll/parser.py index 2e5cf89..6128e1d 100644 --- a/gll/parser.py +++ b/gll/parser.py @@ -11,8 +11,12 @@ class Parser: def __call__(self, string): return self.fun(string) + @property + def name(self): + return self.fun.__name__ + def __or__(self, other): - @rename("{}_alt_{}".format(self.tag, other.tag)) + @rename("{}_alt_{}".format(self.name, other.name)) def internal(string): res = self(string) @@ -22,14 +26,14 @@ class Parser: return Parser(internal) def __rshift__(self, into): - @rename("{}_into_{}".format(self.tag, self.into)) + @rename("{}_into_{}".format(self.name, into)) def internal(string): res = self(string) return Success(into(res.value), res.rest, self.tag) return Parser(internal) -def string(match, tag=None): +def string(match, tag="string"): @rename("string_{}".format(match)) def internal(string): ln = len(match) @@ -44,7 +48,7 @@ def string(match, tag=None): return Parser(internal, tag) -def regex(match, tag=None, reopts=None): +def regex(match, tag="regex", reopts=None): if not reopts: reopts = [] rx = re.compile(match, *reopts) @@ -59,7 +63,7 @@ def regex(match, tag=None, reopts=None): return Parser(internal, tag) -def digit(tag=None): +def digit(tag="digit"): @rename("digit") def internal(string): if not string: @@ -72,8 +76,8 @@ def digit(tag=None): return Parser(internal, tag) -def many(parser, tag=None): - @rename("many_{}".format(parser.tag)) +def many(parser, tag="many"): + @rename("many_{}".format(parser.name)) def internal(string): res = parser(string) @@ -89,8 +93,8 @@ def many(parser, tag=None): return Parser(internal, tag) -def many1(parser, tag=None): - @rename("many1_{}".format(parser.tag)) +def many1(parser, tag="many1"): + @rename("many1_{}".format(parser.name)) def internal(string): res = parser(string) @@ -106,7 +110,7 @@ def many1(parser, tag=None): return Parser(internal, tag) -def whitespace(tag=None): +def whitespace(tag="whitespace"): @rename("whitespace") def internal(string): if not string: @@ -119,8 +123,8 @@ def whitespace(tag=None): return Parser(internal, tag) -def skip(parser, tag=None): - @rename("skip_{}".format(parser.tag)) +def skip(parser, tag="skip"): + @rename("skip_{}".format(parser.name)) def internal(string): res = parser(string) @@ -130,12 +134,35 @@ def skip(parser, tag=None): return Parser(internal, tag) -def skipmany(parser, tag=None): +def skipmany(parser, tag="skipmany"): return many(skip(parser), tag) -def opt(parser, tag=None): - @rename("opt_{}".format(parser.tag)) +def sep_by(separator, parser, tag="sep_by"): + @rename("{}_sep_by_{}".format(parser.name, separator.name)) + def internal(string): + if not string: + return Success("", "", tag) + + res = parser(string) + + if not res.valid: + return Success("", string, tag) + + resl = [] + while res.valid: + resl.append(res) + rest = res.rest + res = separator(rest) + if not res.valid: + continue + res = parser(res.rest) + return Success(resl, rest, tag=tag) + return Parser(internal, tag) + + +def opt(parser, tag="opt"): + @rename("opt_{}".format(parser.name)) def internal(string): res = parser(string) if res.valid: @@ -144,8 +171,8 @@ def opt(parser, tag=None): return Parser(internal, tag) -def seq(*parsers, tag=None): - @rename("seq_{}".format("_".join(str(parser.tag) for parser in parsers))) +def seq(*parsers, tag="seq"): + @rename("seq_{}".format("_".join(str(parser.name) for parser in parsers))) def internal(string): resl = [] rest = string @@ -158,8 +185,9 @@ def seq(*parsers, tag=None): return Success(resl, rest, tag) return Parser(internal, tag) -def all(parser, tag=None): - @rename("all_{}".format(parser.tag)) + +def all(parser, tag="all"): + @rename("all_{}".format(parser.name)) def internal(string): res = parser(string) @@ -167,3 +195,8 @@ def all(parser, tag=None): return res return Failure(res.rest) return Parser(internal, tag) + +def parser(tag=None): + def internal(f): + return Parser(f, tag) + return internal