better analytics, worked on golike syntax
This commit is contained in:
@@ -1,22 +1,56 @@
|
|||||||
import gll
|
import gll
|
||||||
|
|
||||||
ws = gll.skipmany(gll.whitespace())
|
@gll.parser("expression")
|
||||||
skipped = lambda pat: gll.skip(gll.string(pat))
|
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,
|
ws = gll.skipmany(gll.string(" "))
|
||||||
gll.regex("\w+", tag="type"), gll.skip(gll.regex("[\s,]*")))
|
skipped = lambda pat: gll.skip(gll.string(pat), tag="skip_{}".format(pat))
|
||||||
arguments_list = gll.seq(skipped("("), gll.many(argument), skipped(")"), tag="arguments")
|
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"),
|
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"),
|
gll.skipmany(gll.string(" ")), skipped("\n"),
|
||||||
tag="package_name")
|
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")
|
tag="package")
|
||||||
|
|
||||||
parser = gll.all(package)
|
parser = gll.all(package)
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
from gll.parser import string, digit, many, many1, whitespace, skip, skipmany,\
|
from gll.parser import string, digit, many, many1, whitespace, skip, skipmany,\
|
||||||
opt, regex, seq, all
|
opt, regex, seq, all, sep_by, parser
|
||||||
|
@@ -11,8 +11,12 @@ class Parser:
|
|||||||
def __call__(self, string):
|
def __call__(self, string):
|
||||||
return self.fun(string)
|
return self.fun(string)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.fun.__name__
|
||||||
|
|
||||||
def __or__(self, other):
|
def __or__(self, other):
|
||||||
@rename("{}_alt_{}".format(self.tag, other.tag))
|
@rename("{}_alt_{}".format(self.name, other.name))
|
||||||
def internal(string):
|
def internal(string):
|
||||||
res = self(string)
|
res = self(string)
|
||||||
|
|
||||||
@@ -22,14 +26,14 @@ class Parser:
|
|||||||
return Parser(internal)
|
return Parser(internal)
|
||||||
|
|
||||||
def __rshift__(self, into):
|
def __rshift__(self, into):
|
||||||
@rename("{}_into_{}".format(self.tag, self.into))
|
@rename("{}_into_{}".format(self.name, into))
|
||||||
def internal(string):
|
def internal(string):
|
||||||
res = self(string)
|
res = self(string)
|
||||||
return Success(into(res.value), res.rest, self.tag)
|
return Success(into(res.value), res.rest, self.tag)
|
||||||
return Parser(internal)
|
return Parser(internal)
|
||||||
|
|
||||||
|
|
||||||
def string(match, tag=None):
|
def string(match, tag="string"):
|
||||||
@rename("string_{}".format(match))
|
@rename("string_{}".format(match))
|
||||||
def internal(string):
|
def internal(string):
|
||||||
ln = len(match)
|
ln = len(match)
|
||||||
@@ -44,7 +48,7 @@ def string(match, tag=None):
|
|||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
|
||||||
def regex(match, tag=None, reopts=None):
|
def regex(match, tag="regex", reopts=None):
|
||||||
if not reopts:
|
if not reopts:
|
||||||
reopts = []
|
reopts = []
|
||||||
rx = re.compile(match, *reopts)
|
rx = re.compile(match, *reopts)
|
||||||
@@ -59,7 +63,7 @@ def regex(match, tag=None, reopts=None):
|
|||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
|
||||||
def digit(tag=None):
|
def digit(tag="digit"):
|
||||||
@rename("digit")
|
@rename("digit")
|
||||||
def internal(string):
|
def internal(string):
|
||||||
if not string:
|
if not string:
|
||||||
@@ -72,8 +76,8 @@ def digit(tag=None):
|
|||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
|
||||||
def many(parser, tag=None):
|
def many(parser, tag="many"):
|
||||||
@rename("many_{}".format(parser.tag))
|
@rename("many_{}".format(parser.name))
|
||||||
def internal(string):
|
def internal(string):
|
||||||
res = parser(string)
|
res = parser(string)
|
||||||
|
|
||||||
@@ -89,8 +93,8 @@ def many(parser, tag=None):
|
|||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
|
||||||
def many1(parser, tag=None):
|
def many1(parser, tag="many1"):
|
||||||
@rename("many1_{}".format(parser.tag))
|
@rename("many1_{}".format(parser.name))
|
||||||
def internal(string):
|
def internal(string):
|
||||||
res = parser(string)
|
res = parser(string)
|
||||||
|
|
||||||
@@ -106,7 +110,7 @@ def many1(parser, tag=None):
|
|||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
|
||||||
def whitespace(tag=None):
|
def whitespace(tag="whitespace"):
|
||||||
@rename("whitespace")
|
@rename("whitespace")
|
||||||
def internal(string):
|
def internal(string):
|
||||||
if not string:
|
if not string:
|
||||||
@@ -119,8 +123,8 @@ def whitespace(tag=None):
|
|||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
|
||||||
def skip(parser, tag=None):
|
def skip(parser, tag="skip"):
|
||||||
@rename("skip_{}".format(parser.tag))
|
@rename("skip_{}".format(parser.name))
|
||||||
def internal(string):
|
def internal(string):
|
||||||
res = parser(string)
|
res = parser(string)
|
||||||
|
|
||||||
@@ -130,12 +134,35 @@ def skip(parser, tag=None):
|
|||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
|
||||||
def skipmany(parser, tag=None):
|
def skipmany(parser, tag="skipmany"):
|
||||||
return many(skip(parser), tag)
|
return many(skip(parser), tag)
|
||||||
|
|
||||||
|
|
||||||
def opt(parser, tag=None):
|
def sep_by(separator, parser, tag="sep_by"):
|
||||||
@rename("opt_{}".format(parser.tag))
|
@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):
|
def internal(string):
|
||||||
res = parser(string)
|
res = parser(string)
|
||||||
if res.valid:
|
if res.valid:
|
||||||
@@ -144,8 +171,8 @@ def opt(parser, tag=None):
|
|||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
|
||||||
def seq(*parsers, tag=None):
|
def seq(*parsers, tag="seq"):
|
||||||
@rename("seq_{}".format("_".join(str(parser.tag) for parser in parsers)))
|
@rename("seq_{}".format("_".join(str(parser.name) for parser in parsers)))
|
||||||
def internal(string):
|
def internal(string):
|
||||||
resl = []
|
resl = []
|
||||||
rest = string
|
rest = string
|
||||||
@@ -158,8 +185,9 @@ def seq(*parsers, tag=None):
|
|||||||
return Success(resl, rest, tag)
|
return Success(resl, rest, tag)
|
||||||
return Parser(internal, 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):
|
def internal(string):
|
||||||
res = parser(string)
|
res = parser(string)
|
||||||
|
|
||||||
@@ -167,3 +195,8 @@ def all(parser, tag=None):
|
|||||||
return res
|
return res
|
||||||
return Failure(res.rest)
|
return Failure(res.rest)
|
||||||
return Parser(internal, tag)
|
return Parser(internal, tag)
|
||||||
|
|
||||||
|
def parser(tag=None):
|
||||||
|
def internal(f):
|
||||||
|
return Parser(f, tag)
|
||||||
|
return internal
|
||||||
|
Reference in New Issue
Block a user