add tool/sexp.py
authorNIIBE Yutaka <gniibe@fsij.org>
Mon, 21 Jan 2013 01:31:18 +0000 (10:31 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Mon, 21 Jan 2013 03:05:06 +0000 (12:05 +0900)
ChangeLog
tool/sexp.py [new file with mode: 0644]

index 7f91840..ecb14f5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-01-21  Niibe Yutaka  <gniibe@fsij.org>
+
+       * tool/sexp.py: New.
+
 2013-01-20  Niibe Yutaka  <gniibe@fsij.org>
 
        * tool/gpg_agent.py: New.
diff --git a/tool/sexp.py b/tool/sexp.py
new file mode 100644 (file)
index 0000000..a705054
--- /dev/null
@@ -0,0 +1,65 @@
+# SEXP (S-expressions) Basic Transport Support
+#
+# See: http://people.csail.mit.edu/rivest/sexp.html
+#
+
+import re
+
+WHITESPACE='[ \n\t\v\r\f]+'
+re_ws = re.compile(WHITESPACE)
+DIGITS='[0-9]+'
+re_digit = re.compile(DIGITS)
+
+def skip_whitespace(string, pos):
+    m = re_ws.match(string, pos)
+    if m:
+        return m.start()
+    else:
+        return pos
+
+def sexp_match(string, ch, pos):
+    pos = skip_whitespace(string,pos)
+    if string[pos] == ch:
+        return pos+1
+    else:
+        raise ValueError("expect '%s'" % ch)
+
+def sexp_parse_simple_string(string, pos):
+    pos = skip_whitespace(string,pos)
+    m = re_digit.match(string, pos)
+    if m:
+        length = int(string[m.start():m.end()],10)
+        pos = sexp_match(string, ':', m.end())
+        return (string[pos:pos+length], pos+length)
+    else:
+        raise ValueError('expect digit')
+
+def sexp_parse_list(string,pos):
+    l = []
+    while True:
+        pos = skip_whitespace(string,pos)
+        if string[pos] == ')':
+            return (l, pos)
+        else:
+            (sexp, pos) = sexp_parse(string,pos)
+            l.append(sexp)
+
+def sexp_parse(string, pos=0):
+    pos = skip_whitespace(string,pos)
+    if string[pos] == '(':
+        (l, pos) = sexp_parse_list(string,pos+1)
+        pos = sexp_match(string, ')', pos)
+        return (l, pos)
+    elif string[pos] == '[':
+        pos = skip_whitespace(string,pos)
+        (dsp, pos) = sexp_parse_simple_string(string,pos+1)
+        pos = sexp_match(string, ']', pos)
+        pos = skip_whitespace(string,pos)
+        (ss, pos) = sexp_parse_simple_string(string, pos)
+        return ((dsp, ss), pos)
+    else:
+        return sexp_parse_simple_string(string, pos)
+
+def sexp(string):
+    (sexp, pos) = sexp_parse(string)
+    return sexp