From 819ab10281c9bd6c000364c3a243959edd18abf7 Mon Sep 17 00:00:00 2001 From: Timotej Lazar Date: Thu, 15 Jan 2015 12:10:22 +0100 Subject: Move pymonkey stuff to monkey/ Importing pymonkey into webmonkey, let's see how this works. --- monkey/util.py | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 monkey/util.py (limited to 'monkey/util.py') diff --git a/monkey/util.py b/monkey/util.py new file mode 100644 index 0000000..b8be2bb --- /dev/null +++ b/monkey/util.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 + +from collections import namedtuple +from heapq import heappush, heappop +import itertools + +# A simple priority queue based on the heapq class. +class PQueue(object): + REMOVED = '' # placeholder for a removed task + + def __init__(self): + self.pq = [] # list of entries arranged in a heap + self.entry_finder = {} # mapping of tasks to entries + self.counter = itertools.count() # unique sequence count + self.size = 0 + + def push(self, task, priority=0): + 'Add a new task or update the priority of an existing task' + if task in self.entry_finder: + self.remove(task) + else: + self.size += 1 + entry = [priority, next(self.counter), task] + self.entry_finder[task] = entry + heappush(self.pq, entry) + + def remove(self, task): + 'Mark an existing task as REMOVED. Raise KeyError if not found.' + entry = self.entry_finder.pop(task) + entry[-1] = self.REMOVED + self.size -= 1 + + def pop(self): + 'Remove and return the lowest priority task. Raise KeyError if empty.' + while self.pq: + priority, count, task = heappop(self.pq) + if task is not self.REMOVED: + del self.entry_finder[task] + self.size -= 1 + return task + return None + + def __len__(self): + return self.size + +# Stores a token's type and value, and optionally the position of the first +# character in the lexed stream. +class Token(namedtuple('Token', ['type', 'val', 'pos'])): + __slots__ = () + + # Custom constructor to support default parameters. + def __new__(cls, type, val='', pos=None): + return super(Token, cls).__new__(cls, type, val, pos) + + def __str__(self): + return self.val + + # Ignore position when comparing tokens. There is probably a cleaner way of + # doing these. + __eq__ = lambda x, y: x[0] == y[0] and x[1] == y[1] + __ne__ = lambda x, y: x[0] != y[0] or x[1] != y[1] + __lt__ = lambda x, y: tuple.__lt__(x[0:2], y[0:2]) + __le__ = lambda x, y: tuple.__le__(x[0:2], y[0:2]) + __ge__ = lambda x, y: tuple.__ge__(x[0:2], y[0:2]) + __gt__ = lambda x, y: tuple.__gt__(x[0:2], y[0:2]) + + # Only hash token's value (we don't care about position, and types are + # determined by values). + def __hash__(self): + return hash(self[1]) + +# Return [n]th line in [text]. +def get_line(text, n): + lines = text.split('\n') + if n >= 0 and n < len(lines): + return lines[n] + return None + +# Indent each line in [text] by [indent] spaces. +def indent(text, indent=2): + return '\n'.join([' '*indent+line for line in text.split('\n')]) -- cgit v1.2.1