[pyrepl-checkins] r5437 - in pyrepl/branch/pyrepl-rework-n: pyrepl/dfa test test/unit

mwh at codespeak.net mwh at codespeak.net
Mon Jul 5 16:08:00 MEST 2004


Author: mwh
Date: Mon Jul  5 16:08:00 2004
New Revision: 5437

Added:
   pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/   (props changed)
   pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/__init__.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/base.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/commandsm.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/compile.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/keystrokesm.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/statemachine.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/unicodesm.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/test/
   pyrepl/branch/pyrepl-rework-n/test/unit/   (props changed)
   pyrepl/branch/pyrepl-rework-n/test/unit/test_commandsm.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/test/unit/test_keystrokesm.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/test/unit/test_makematch.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/test/unit/test_statemachines.py   (contents, props changed)
   pyrepl/branch/pyrepl-rework-n/test/unit/test_unicodesm.py   (contents, props changed)
Log:
add some files on the branch


Added: pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/__init__.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/__init__.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1 @@
+# foo

Added: pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/base.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/base.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,24 @@
+
+class StateMachine(object):
+    def __init__(self, parent):
+        self.parent = parent
+        self.output = []
+
+    def push_and_go(self, evt):
+        self.push(evt)
+        if self.parent is not None:
+            while 1:
+                e = self.get()
+                if e is None:
+                    return
+                self.parent.push_and_go(e)
+    
+    def push(self, evt):
+        pass
+
+    def get(self):
+        if self.output:
+            return self.output.pop(0)
+        else:
+            return None
+

Added: pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/commandsm.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/commandsm.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,61 @@
+from pyrepl.dfa.base import StateMachine
+from pyrepl.dfa.compile import make_match
+from pyrepl.keymap import parse_keys
+
+import unicodedata
+
+class Command(object):
+    def __init__(self, cmd, keystrokes):
+        self.cmd = cmd
+        self.keystrokes = keystrokes
+    def __eq__(self, other):
+        if isinstance(other, Command):
+            return self.cmd == other.cmd \
+                   and self.keystrokes == other.keystrokes
+        else:
+            return False
+    def __repr__(self):
+        return "%s(%r, %r)"%(self.__class__.__name__,
+                             self.cmd, self.keystrokes)
+        
+
+
+class CommandSM(StateMachine):
+    def __init__(self, parent, keys, keymap, invalid_cls, character_cls):
+        super(CommandSM, self).__init__(parent)
+        
+        self.keymap = keymap
+        self.invalid_cls = invalid_cls
+        self.character_cls = character_cls
+        
+        d = []
+        for keyspec, command in keymap:
+            keyseq = tuple(parse_keys(keyspec, keys))
+            d.append((keyseq, command))
+
+        self.k = self.ck = make_match(d, ())
+        self.buf = []
+
+    def push(self, keystroke):
+        n = keystroke.name
+        self.buf.append(keystroke)
+        if n in self.k:
+            k = self.k[n]
+            if not isinstance(k, dict):
+                self.output.append(Command(k, self.buf))
+                self.buf = []
+                self.k = self.ck
+        else:
+            if (len(self.buf) > 1
+                or len(keystroke.raw) > 1
+                or unicodedata.category(keystroke.raw)[0] == 'C'):
+                self.output.append(
+                    Command(self.invalid_cls, self.buf))
+            else:
+                self.k[n] = self.character_cls
+                self.output.append(
+                    Command(self.character_cls, self.buf))
+            self.buf = []
+            self.k = self.ck
+            
+                

Added: pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/compile.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/compile.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,16 @@
+def make_match(seq, empty=''):
+    """make_match([('key', 'value'), ...]) -> nested dictionaries"""
+    r = {}
+    for key, value in seq:
+        r.setdefault(key[0], {})[key[1:]] = value
+    for key, value in r.items():
+        if empty in value:
+            if len(value) <> 1:
+                raise ValueError, \
+                      "key definitions for %s clash"%(value.values(),)
+            else:
+                r[key] = value[empty]
+        else:
+            r[key] = make_match(value.items(), empty)
+    return r
+

Added: pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/keystrokesm.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/keystrokesm.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,71 @@
+from pyrepl.dfa.base import StateMachine
+from pyrepl.dfa.compile import make_match
+
+class Keystroke(object):
+    def __init__(self, name, raw):
+        self.name = name
+        self.raw = raw
+    def __eq__(self, other):
+        if isinstance(other, Keystroke):
+            return self.name == other.name and self.raw == other.raw
+        else:
+            return False
+    def __repr__(self):
+        return "%s(%r, %r)"%(self.__class__.__name__,
+                             self.name, self.raw)
+
+class CursesKeys(object):
+    _keynames = {
+        "delete" : "kdch1",
+        "down" : "kcud1",
+        "end" : "kend",
+        "enter" : "kent",
+        "f1"  : "kf1",   "f2"  : "kf2",   "f3"  : "kf3",   "f4"  : "kf4",
+        "f5"  : "kf5",   "f6"  : "kf6",   "f7"  : "kf7",   "f8"  : "kf8",
+        "f9"  : "kf9",   "f10" : "kf10",  "f11" : "kf11",  "f12" : "kf12",
+        "f13" : "kf13",  "f14" : "kf14",  "f15" : "kf15",  "f16" : "kf16",
+        "f17" : "kf17",  "f18" : "kf18",  "f19" : "kf19",  "f20" : "kf20",
+        "home" : "khome",
+        "insert" : "kich1",
+        "left" : "kcub1",
+        "page down" : "knp",
+        "page up"   : "kpp",
+        "right" : "kcuf1",
+        "up" : "kcuu1",
+        }    
+    def translate(self, key):
+        from curses import tigetstr
+        return tigetstr(self._keynames[key])
+    def all_keys(self):
+        r = []
+        for k in _keynames:
+            v = self.translate(k)
+            if v is not None:
+                r.append((v, k))
+        r.append((tcgetattr(fd)[6][VERASE], 'backspace'))
+        return r
+    def keynames(self):
+        return self._keynames.keys()
+
+class KeystrokeSM(StateMachine):
+    def __init__(self, parent, keys):
+        super(KeystrokeSM, self).__init__(parent)
+        self.k = self.ck = make_match(keys.all_keys())
+        self.chars = ''
+    def push(self, evt):
+        if evt in self.k:
+            self.chars += evt
+            k = self.k[evt]
+            if isinstance(k, dict):
+                self.k = k
+            else:
+                self.output.append(Keystroke(k, self.chars))
+                self.k = self.ck
+                self.chars = ''
+        elif self.chars:
+            self.output.extend([Keystroke(c, c) for c in self.chars])
+            self.k = self.ck
+            self.chars = ''
+            self.push(evt)
+        else:
+            self.output.append(Keystroke(evt, evt))

Added: pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/statemachine.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/statemachine.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,104 @@
+# --------------------------------------------------------------------
+# base class
+# --------------------------------------------------------------------
+
+class StateMachine(object):
+    def __init__(self, parent):
+        self.parent = parent
+        self.output = []
+    def push_and_go(self, evt):
+        self.push(evt)
+        e = self.get()
+        if e is not None:
+            self.parent.push_and_go(e)
+    
+    def push(self, evt):
+        pass
+    def get(self):
+        if self.output:
+            return self.output.pop(0)
+        else:
+            return None
+    # anything else?
+
+# --------------------------------------------------------------------
+# character data -> unicode
+# --------------------------------------------------------------------
+
+class FixedWidthUnicodeSM(StateMachine):
+    def __init__(self, parent, encoding):
+        super(FixedWidthUnicodeSM, self).__init__(parent)
+        self.encoding = encoding
+        self.width = len(u' '.encode(encoding))
+        self.chars = ''
+        self.output = []
+    def push(self, evt):
+        self.chars += evt
+        while len(self.chars) >= self.width:
+            self.output.append(self.chars[:self.width].decode(self.encoding))
+            self.chars = self.chars[self.width:]
+
+# nicked from unicodeobject.c:
+utf8prefix_lengths = [
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0]
+
+
+class UTF8UnicodeSM(StateMachine):
+    def __init__(self, parent):
+        super(UTF8UnicodeSM, self).__init__(parent)
+        self.chars = ''
+        self.l = 0
+    def push(self, evt):
+        if self.l:
+            self.chars += evt
+            self.l -= 1
+        else:
+            self.chars = evt
+            self.l = utf8prefix_lengths[ord(evt)] - 1
+            if self.l < 0:
+                raise UnicodeError, "invalid utf-8 data"
+        if not self.l:
+            c = self.chars
+            self.chars = ''
+            self.output.append(c.decode('utf-8'))
+
+if 0: # dreaming of coroutines....
+ while 1:
+  c = getchar()
+  l = lengths[c] - 1
+  for i in range(l):
+   c += getchar()
+  yield c.decode('utf-8')
+ while 1:
+  yield None
+  l = lengths[self.c]
+  for i in range(l):
+   yield None
+  c = self.c
+  self.c = ''
+  yield c.decode('utf-8')
+
+# --------------------------------------------------------------------
+# unicode -> keystrokes
+# --------------------------------------------------------------------
+
+
+
+# --------------------------------------------------------------------
+# keystrokes -> commands
+# --------------------------------------------------------------------

Added: pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/unicodesm.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/pyrepl/dfa/unicodesm.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,53 @@
+from pyrepl.dfa.base import StateMachine
+
+class FixedWidthUnicodeSM(StateMachine):
+    def __init__(self, parent, encoding):
+        super(FixedWidthUnicodeSM, self).__init__(parent)
+        self.encoding = encoding
+        self.width = len(u' '.encode(encoding))
+        self.chars = ''
+        self.output = []
+    def push(self, evt):
+        self.chars += evt
+        while len(self.chars) >= self.width:
+            self.output.append(self.chars[:self.width].decode(self.encoding))
+            self.chars = self.chars[self.width:]
+
+# nicked from unicodeobject.c:
+utf8prefix_lengths = [
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0]
+
+
+class UTF8UnicodeSM(StateMachine):
+    def __init__(self, parent):
+        super(UTF8UnicodeSM, self).__init__(parent)
+        self.chars = ''
+        self.l = 0
+    def push(self, evt):
+        if self.l:
+            self.chars += evt
+            self.l -= 1
+        else:
+            self.chars = evt
+            self.l = utf8prefix_lengths[ord(evt)] - 1
+            if self.l < 0:
+                raise UnicodeError, "invalid utf-8 data"
+        if not self.l:
+            c = self.chars
+            self.chars = ''
+            self.output.append(c.decode('utf-8'))

Added: pyrepl/branch/pyrepl-rework-n/test/unit/test_commandsm.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/test/unit/test_commandsm.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,21 @@
+from pyrepl.dfa.keystrokesm import Keystroke
+from pyrepl.dfa.commandsm import Command, CommandSM
+
+def do_feed(m, data, results):
+    for c in data:
+        m.push(c)
+    for r in results:
+        v = m.get()
+        assert v == r
+
+test_keymap = [('a', 'cmd'),
+               ('\C-a', 'bol')]
+
+def test_basic():
+    m = CommandSM(None, None, test_keymap, None, None)
+    a = Keystroke('a', 'a')
+    do_feed(m, [a], [Command('cmd', [a])])
+    a = Keystroke('\001', '')
+    do_feed(m, [a], [Command('bol', [a])])
+    
+

Added: pyrepl/branch/pyrepl-rework-n/test/unit/test_keystrokesm.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/test/unit/test_keystrokesm.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,26 @@
+from pyrepl.dfa.keystrokesm import KeystrokeSM, Keystroke
+
+class TestKeys(object):
+    def translate(self, key):
+        return key
+    def all_keys(self):
+        return [('abc', 'a'),
+                ('abd', 'b')]
+
+def do_feed(m, data, results):
+    for c in data:
+        m.push(c)
+    for r in results:
+        v = m.get()
+        assert v == r
+
+def test_keystrokesm():
+    m = KeystrokeSM(None, TestKeys())
+    do_feed(m, 'ab',  [None])
+    do_feed(m, 'c',   [Keystroke('a', 'abc')])
+    do_feed(m, 'abd', [Keystroke('b', 'abd')])
+    do_feed(m, 'ab',  [None])
+    do_feed(m, 'e',   [Keystroke('a', 'a'),
+                       Keystroke('b', 'b'),
+                       Keystroke('e', 'e')])
+    do_feed(m, 'f',   [Keystroke('f', 'f')])

Added: pyrepl/branch/pyrepl-rework-n/test/unit/test_makematch.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/test/unit/test_makematch.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,7 @@
+from pyrepl.dfa.compile import make_match
+
+def test_make_match():
+    s = [('abc', 'a'),
+         ('abd', 'b')]
+    d = make_match(s)
+    assert d == {'a': {'b': {'c': 'a', 'd': 'b'}}}

Added: pyrepl/branch/pyrepl-rework-n/test/unit/test_statemachines.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/test/unit/test_statemachines.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,42 @@
+from pyrepl.dfa.unicodesm import UTF8UnicodeSM
+from pyrepl.dfa.keystrokesm import KeystrokeSM, Keystroke
+from pyrepl.dfa.commandsm import CommandSM, Command
+
+class TestKeys(object):
+    def translate(self, key):
+        return key
+    def all_keys(self):
+        return [('abc', 'a'),
+                ('abd', 'b')]
+    def keynames(self):
+        return ['abc', 'abd']
+
+test_keymap = [('q', 'cmd'),
+               ('\C-a', 'bol'),
+               ('\<abc>', 'keynamed-a'),
+               ('\<abd>', 'keynamed-b'),
+               ]
+
+def test_it():
+    tk = TestKeys()
+    c = CommandSM(None, tk, test_keymap, 'invalid', 'character')
+    k = KeystrokeSM(c, tk)
+    u = UTF8UnicodeSM(k)
+
+    egrave = u'\N{latin small letter e with grave}'
+
+    for char in egrave.encode('utf-8'):
+        u.push_and_go(char)
+
+    v = c.get()
+
+    assert v == Command('character', [Keystroke(egrave, egrave)])
+
+    u.push_and_go('a')
+    u.push_and_go('b')
+    u.push_and_go('c')
+
+    v = c.get()
+    print v
+    assert v == Command('keynamed-a', [Keystroke('abc', 'a')])
+    

Added: pyrepl/branch/pyrepl-rework-n/test/unit/test_unicodesm.py
==============================================================================
--- (empty file)
+++ pyrepl/branch/pyrepl-rework-n/test/unit/test_unicodesm.py	Mon Jul  5 16:08:00 2004
@@ -0,0 +1,31 @@
+
+def run_test_fixedwidthsm(encoding):
+    from pyrepl.statemachine import FixedWidthUnicodeSM
+    m = FixedWidthUnicodeSM(None, encoding)
+    inpu = u'abc\N{latin small letter i with diaeresis}de'
+    inp = inpu.encode(encoding)
+    for c in inp:
+        m.push(c)
+    for u in inpu:
+        assert u == m.get()
+    assert m.get() is None
+
+def test_utf8sm():
+    from pyrepl.statemachine import UTF8UnicodeSM
+    m = UTF8UnicodeSM(None)
+    inpu = u'abc\N{latin small letter i with diaeresis}de'
+    inp = inpu.encode('utf-8')
+    for c in inp:
+        m.push(c)
+    for u in inpu:
+        assert u == m.get()
+    assert m.get() is None
+
+def test_fixedwidthsm_latin1():
+    run_test_fixedwidthsm('latin1')
+
+def test_fixedwidthsm_utf_16_le():
+    run_test_fixedwidthsm('utf-16-le')
+    
+if __name__ == '__main__':
+    test_fixedwidthsm_latin1()


More information about the pyrepl-checkins mailing list