diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..9e32b48 --- /dev/null +++ b/.hgignore @@ -0,0 +1,2 @@ +syntax: glob +*.pyc diff --git a/language_tools.py b/language_tools.py new file mode 100644 index 0000000..514b7df --- /dev/null +++ b/language_tools.py @@ -0,0 +1,75 @@ +import sys +import traceback +import bisect +from pyparsing import ParseException + +def tokenparser(func): + def newfunc(s, loc, tokens): + try: + rv = func(tokens) + pos = lineno(s, loc) + if isinstance(rv, VMBaseObject): + rv.pos = pos + return rv + assert not False in [isinstance(x, (VMBaseObject, list)) for x in rv] + for x in rv: + if isinstance(x, VMBaseObject) and x.pos == None: + x.pos = pos + except: + e = sys.exc_info() + if e[0] == ParseException: + raise + gd = globals() + funcobj = None + for x in gd: + if hasattr(gd[x], "parse") and gd[x].parse == newfunc: + funcobj = x + print "Error with %s.parse tokens: %s" % (funcobj, tokens) + traceback.print_exc(e) + raise + + return [rv] + + return newfunc + + +def lineno(s, loc): + if hash(s) in lineno.cache: + cache = lineno.cache[hash(s)] + else: + cache = [] + + i = 0 + while True: + n = s[i:].find("\n") + i + if n < i: + break + cache.append(n) + i = n + 1 + + cache.append(len(s)) + + lineno.cache[hash(s)] = cache + + cachepos = bisect.bisect_left(cache, loc) + line = cachepos + 1 + if cachepos == 0: + char = loc + 1 + else: + char = loc - cache[cachepos-1] + + + return (line, char) + +lineno.cache = {} + + +class VMBaseObject(object): + def __init__(self): + self.pos = None + + def bytecode(self): + return [self] + + def __repr__(self): + return "<%s>" % (self.__class__.__name__,)