changeset 39:aa05cc7ccd0d

Serious implementation for parsing predicates in structpath.py
author Thinker K.F. Li <thinker@codemud.net>
date Thu, 16 Jun 2011 08:03:50 +0800
parents 0766bd54c9d3
children 0c0a659187c2
files paraspace/structpath.py
diffstat 1 files changed, 94 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/structpath.py	Wed Jun 15 22:16:00 2011 +0800
+++ b/paraspace/structpath.py	Thu Jun 16 08:03:50 2011 +0800
@@ -53,6 +53,7 @@
 STATE_STR_SQ = 2
 STATE_STR_DQ = 3
 STATE_BKSP = 4
+STATE_STOP = 5
 
 def _path_split(path):
     stk = []
@@ -128,6 +129,91 @@
     return parts
 
 
+def _path_parse_preds(path):
+    stk = []
+    idx = 0
+    state = STATE_START
+    name = None
+    preds = []
+    while True:
+        mo = _reo_nest_chars.search(path, idx)
+        
+        if mo == None:
+            break
+        
+        ch = mo.group()
+        idx = mo.end()
+        if state in (STATE_START, STATE_STOP):
+            if ch == '[':
+                name = path[:idx - 1]
+                left = idx
+                stk.append(STATE_STOP)
+                state = STATE_PRED
+            elif ch == '\'':
+                stk.append(state)
+                state = STATE_STR_SQ
+            elif ch == '"':
+                stk.append(state)
+                state = STATE_STR_DQ
+                pass
+            else:
+                raise ValueError, 'invalid structpath string'
+            pass
+        elif state == STATE_STR_SQ:
+            if ch == '\'':
+                state = stk.pop()
+                pass
+            elif ch == '\\':
+                stk.append(state)
+                state = STATE_BKSP
+                bksp_idx = idx
+                pass
+            pass
+        elif state == STATE_STR_DQ:
+            if ch == '"':
+                state = stk.pop()
+            elif ch == '\\':
+                stk.append(state)
+                state = STATE_BKSP
+                bksp_idx = idx
+                pass
+            pass
+        elif state == STATE_PRED:
+            if ch == '[':
+                stk.append(state)
+                state = STATE_PRED
+            elif ch == '\'':
+                stk.append(state)
+                state = STATE_STR_SQ
+            elif ch == '"':
+                stk.append(state)
+                state = STATE_STR_DQ
+            elif ch == ']':
+                state = stk.pop()
+                if state == STATE_STOP:
+                    preds.append(path[left:idx - 1])
+                    pass
+                pass
+            pass
+        elif state == STATE_BKSP:
+            if idx != (bksp_idx + 1):
+                idx = mo.start()
+                pass
+            state = stk.pop()
+            pass
+        pass
+
+    if state not in (STATE_START, STATE_STOP):
+        raise ValueError, 'invalid structpath string'
+    if state == STATE_STOP and idx != len(path):
+        raise ValueError, 'invalid structpath string'
+    if state == STATE_START:
+        name = path
+        pass
+    
+    return name, preds
+
+
 def _is_abs(path_parts):
     if len(path_parts) == 0:
         return False
@@ -150,15 +236,7 @@
     return part == '..'
 
 
-def _split_attr_pred(part):
-    try:
-        lq_idx = part.index('[')
-    except:
-        return part, ''
-    return part[:lq_idx].strip(), part[lq_idx:].strip()
-
-
-def _eval_obj_sub_pred(ctx, obj, sub_pred):
+def _eval_obj_pred(ctx, obj, pred):
     ns_global = {}
     for attr in dir(obj):
         if attr.startswith('_'):
@@ -167,24 +245,16 @@
         ns_global[attr] = v
         pass
 
-    truth_v = eval(sub_pred, ns_global)
+    truth_v = eval(pred, ns_global)
     return truth_v
 
 
-def _split_pred_into_subs(pred):
-    striped_pred = pred.strip(' []\n\r')
-    subs = striped_pred.split('][')
-    return subs
-
-
-def _eval_obj_pred(ctx, obj, pred):
-    subs = _split_pred_into_subs(pred)
-    
-    for sub in subs:
-        if not sub:
+def _eval_obj_preds(ctx, obj, preds):
+    for pred in preds:
+        if not pred:
             continue
         
-        if not _eval_obj_sub_pred(ctx, obj, sub):
+        if not _eval_obj_pred(ctx, obj, pred):
             return False
         pass
     return True
@@ -213,7 +283,7 @@
 
 
 def _handle_path_part_obj(ctx, part, obj):
-    attr, pred = _split_attr_pred(part)
+    attr, preds = _path_parse_preds(part)
     
     if _is_parent_name(attr):
         new_objs = [ctx.get_parent(obj)]
@@ -227,7 +297,7 @@
             return []
         pass
 
-    new_objs = filter((lambda x: _eval_obj_pred(ctx, x, pred)), new_objs)
+    new_objs = filter((lambda x: _eval_obj_preds(ctx, x, preds)), new_objs)
                    
     return new_objs