bryan-stearns
commited on
Commit
•
786340e
1
Parent(s):
c3d5c44
Initial app commit
Browse files- .gitignore +30 -0
- Inspect_Logic.py +101 -0
- README.md +1 -1
- smem_obj.py +276 -0
- smem_token_parser.py +140 -0
.gitignore
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Compiled class file
|
2 |
+
*.class
|
3 |
+
|
4 |
+
# Log file
|
5 |
+
*.log
|
6 |
+
|
7 |
+
# BlueJ files
|
8 |
+
*.ctxt
|
9 |
+
|
10 |
+
# Mobile Tools for Java (J2ME)
|
11 |
+
.mtj.tmp/
|
12 |
+
|
13 |
+
# Package Files #
|
14 |
+
*.jar
|
15 |
+
*.war
|
16 |
+
*.nar
|
17 |
+
*.ear
|
18 |
+
*.zip
|
19 |
+
*.tar.gz
|
20 |
+
*.rar
|
21 |
+
|
22 |
+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
23 |
+
hs_err_pid*
|
24 |
+
|
25 |
+
# VSCode files
|
26 |
+
*.code-workspace
|
27 |
+
.editorconfig
|
28 |
+
|
29 |
+
# Macintosh filesystem
|
30 |
+
.DS_Store
|
Inspect_Logic.py
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from io import StringIO
|
2 |
+
import streamlit as st
|
3 |
+
|
4 |
+
from smem_token_parser import SMEM_Parser, read_tokens_from_lines
|
5 |
+
from smem_obj import SMEM_Obj, ObjType
|
6 |
+
|
7 |
+
MIN_COLS = 4
|
8 |
+
|
9 |
+
# Set up page config before any other streamlit commands
|
10 |
+
st.set_page_config(page_title="Soar Agent Memory Inspector", layout="wide")
|
11 |
+
st.title("Logic Inspector")
|
12 |
+
|
13 |
+
|
14 |
+
def get_smem_root_from_file(smem_file):
|
15 |
+
# tokens = get_smem_tokens_from_local_file(smem_filename)
|
16 |
+
tokens = read_tokens_from_lines(smem_file)
|
17 |
+
if tokens == None:
|
18 |
+
st.error("Error reading file: '"+str(smem_file)+"'")
|
19 |
+
return None
|
20 |
+
parser = SMEM_Parser()
|
21 |
+
parser.parse_file(tokens)
|
22 |
+
return parser.get_context_root()
|
23 |
+
|
24 |
+
if "col_obj_list" not in st.session_state:
|
25 |
+
st.session_state["col_obj_list"] = None
|
26 |
+
|
27 |
+
file_upload_expander = st.expander(label="Select a file to inspect", expanded=(st.session_state.col_obj_list == None))
|
28 |
+
file = file_upload_expander.file_uploader(" ")
|
29 |
+
|
30 |
+
if file is not None:
|
31 |
+
if st.session_state.col_obj_list is None:
|
32 |
+
root = get_smem_root_from_file(StringIO(file.getvalue().decode("utf-8")))
|
33 |
+
if root:
|
34 |
+
st.session_state["col_obj_list"] = [None]*MIN_COLS
|
35 |
+
st.session_state.col_obj_list[0] = root
|
36 |
+
st.experimental_rerun()
|
37 |
+
else:
|
38 |
+
st.session_state["col_obj_list"] = None
|
39 |
+
|
40 |
+
# inpath = "/Users/bstearn1/Documents/Projects/OptumGitHub/Intelligent-Solutions/AICarePlan/agent/D-RULES_082222_smem.soar"
|
41 |
+
# inpath = "SMEM Generator/test_pim_smem.soar"
|
42 |
+
# st.session_state.col_obj_list[0] = get_smem_root_from_file(inpath)
|
43 |
+
|
44 |
+
if st.session_state.col_obj_list is None:
|
45 |
+
st.stop()
|
46 |
+
|
47 |
+
def add_col(index, obj):
|
48 |
+
st.session_state.col_obj_list = st.session_state.col_obj_list[:index+1]
|
49 |
+
st.session_state.col_obj_list.append(obj)
|
50 |
+
# st.session_state.current_tab_index = index+1
|
51 |
+
st.experimental_rerun()
|
52 |
+
|
53 |
+
def get_header_str(obj_type):
|
54 |
+
if obj_type == ObjType.CONTEXT:
|
55 |
+
return "START"
|
56 |
+
elif obj_type == ObjType.COND_CONJ:
|
57 |
+
return "CONDITION"
|
58 |
+
elif obj_type == ObjType.OP:
|
59 |
+
return "CHOICE"
|
60 |
+
elif obj_type == ObjType.ACT_GROUP:
|
61 |
+
return "RESULT"
|
62 |
+
else:
|
63 |
+
return " "
|
64 |
+
|
65 |
+
st.subheader("Click the buttons below to select conditions and to inspect resulting actions.")
|
66 |
+
|
67 |
+
cols = st.columns(max(MIN_COLS,len(st.session_state.col_obj_list)))
|
68 |
+
|
69 |
+
for i,col in enumerate(cols):
|
70 |
+
try:
|
71 |
+
if st.session_state.col_obj_list[i] == None:
|
72 |
+
break
|
73 |
+
except Exception as e:
|
74 |
+
# print("ERROR checking column "+str(i+1)+" of "+str(len(st.session_state.col_obj_list))+": "+str(e))
|
75 |
+
break
|
76 |
+
# Build the available objects to navigate under this col's object
|
77 |
+
obj = st.session_state.col_obj_list[i]
|
78 |
+
obj_str,obj_label,obj_desc = obj.to_string()
|
79 |
+
sub_objs = list(obj.get_child_objects(compact=True))
|
80 |
+
# print(obj.obj_type)
|
81 |
+
if len(sub_objs) > 0:
|
82 |
+
col.markdown("**"+get_header_str(sub_objs[0].obj_type)+"**",)
|
83 |
+
col.markdown("---")
|
84 |
+
# Show the object's main title and description
|
85 |
+
col.text(obj_str)
|
86 |
+
if obj_desc != None:
|
87 |
+
col.markdown("*"+obj_desc+"*")
|
88 |
+
for j,sub in enumerate(sub_objs):
|
89 |
+
sub_str,sub_label,sub_desc = sub.to_string()
|
90 |
+
if sub.obj_type == ObjType.OP:
|
91 |
+
subsub = list(sub.get_child_objects(compact=True))[0]
|
92 |
+
_,group_string,_ = subsub.to_string()
|
93 |
+
group_string = "\n * "+str(group_string).replace("AND", "\n * ")
|
94 |
+
col.markdown(group_string)
|
95 |
+
if col.button(sub_label, key="button"+str(i)+"-"+str(j)):
|
96 |
+
add_col(i,sub)
|
97 |
+
elif sub.obj_type == ObjType.ACT_GROUP:
|
98 |
+
col.markdown("*Output Details:* ")
|
99 |
+
col.markdown("\n * "+str(sub_str).replace(") AND", ")\n * "))
|
100 |
+
elif col.button(sub_label, key="button"+str(i)+"-"+str(j)):
|
101 |
+
add_col(i,sub)
|
README.md
CHANGED
@@ -5,7 +5,7 @@ colorFrom: indigo
|
|
5 |
colorTo: yellow
|
6 |
sdk: streamlit
|
7 |
sdk_version: 1.15.2
|
8 |
-
app_file:
|
9 |
pinned: false
|
10 |
---
|
11 |
|
|
|
5 |
colorTo: yellow
|
6 |
sdk: streamlit
|
7 |
sdk_version: 1.15.2
|
8 |
+
app_file: Inspect_Logic.py
|
9 |
pinned: false
|
10 |
---
|
11 |
|
smem_obj.py
ADDED
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from enum import Enum
|
2 |
+
|
3 |
+
class SMEM_Obj():
|
4 |
+
def __init__(self):
|
5 |
+
self.processed = False
|
6 |
+
self.obj_type = None
|
7 |
+
self.id_var = None
|
8 |
+
self.class_str = None
|
9 |
+
self.wme_list = []
|
10 |
+
self.description = None
|
11 |
+
|
12 |
+
def set_id_var(self, var):
|
13 |
+
self.id_var = var
|
14 |
+
|
15 |
+
def add_wme(self, attr, val):
|
16 |
+
self.wme_list.append((attr,val))
|
17 |
+
|
18 |
+
def get_class(self):
|
19 |
+
for (attr,val) in self.wme_list:
|
20 |
+
if attr == "^class":
|
21 |
+
self.class_str = val
|
22 |
+
break
|
23 |
+
return self.class_str
|
24 |
+
|
25 |
+
def get_description(self):
|
26 |
+
if self.description != None:
|
27 |
+
return self.description
|
28 |
+
# Search for the description
|
29 |
+
for (attr,val) in self.wme_list:
|
30 |
+
if attr == "^description":
|
31 |
+
self.description = val
|
32 |
+
break
|
33 |
+
return self.description
|
34 |
+
|
35 |
+
def get_compact_printable_object(self):
|
36 |
+
""" Return this object if printable in compact mode, else return the set of next printable descendants.
|
37 |
+
"""
|
38 |
+
if self.obj_type == None:
|
39 |
+
print("Warning: No obj_type for obj '"+self.id_var+"' in get_compact_printable_object().")
|
40 |
+
return None
|
41 |
+
retval = set()
|
42 |
+
returnSelf = False
|
43 |
+
|
44 |
+
if self.obj_type == ObjType.COND_PRIM:
|
45 |
+
for (attr,val) in self.wme_list:
|
46 |
+
if attr == "^supplies-condition":
|
47 |
+
val.obj_type = ObjType.COND_CONJ
|
48 |
+
retval.update(val.get_compact_printable_object())
|
49 |
+
elif self.obj_type == ObjType.COND_CONJ:
|
50 |
+
for (attr,val) in self.wme_list:
|
51 |
+
if attr == "^satisfies-op":
|
52 |
+
val.obj_type = ObjType.OP
|
53 |
+
returnSelf = True
|
54 |
+
break
|
55 |
+
elif attr == "^activates-context":
|
56 |
+
val.obj_type = ObjType.CONTEXT
|
57 |
+
returnSelf = True
|
58 |
+
break
|
59 |
+
elif attr == "^supplies-condition":
|
60 |
+
val.obj_type = ObjType.COND_CONJ
|
61 |
+
retval.update(val.get_compact_printable_object())
|
62 |
+
elif self.obj_type == ObjType.CONTEXT:
|
63 |
+
for (attr,val) in self.wme_list:
|
64 |
+
if attr == "^primes-condition":
|
65 |
+
val.obj_type = ObjType.COND_PRIM
|
66 |
+
retval.update(val.get_compact_printable_object())
|
67 |
+
else:
|
68 |
+
returnSelf = True
|
69 |
+
|
70 |
+
if returnSelf:
|
71 |
+
retval = set()
|
72 |
+
retval.add(self)
|
73 |
+
|
74 |
+
return retval
|
75 |
+
|
76 |
+
def get_child_objects(self, compact=True):
|
77 |
+
""" If compact=True, skip condition prims and contexts, only get conjunctions and action groups
|
78 |
+
"""
|
79 |
+
if self.obj_type == None:
|
80 |
+
print("Warning: No obj_type for obj '"+self.id_var+"'")
|
81 |
+
return None
|
82 |
+
retval = set()
|
83 |
+
for (attr,val) in self.wme_list:
|
84 |
+
if self.obj_type == ObjType.CONTEXT:
|
85 |
+
if attr == "^primes-condition":
|
86 |
+
val.obj_type = ObjType.COND_PRIM
|
87 |
+
if compact:
|
88 |
+
retval.update(val.get_compact_printable_object())
|
89 |
+
else:
|
90 |
+
retval.add(val)
|
91 |
+
elif self.obj_type == ObjType.COND_PRIM:
|
92 |
+
if attr == "^supplies-condition":
|
93 |
+
val.obj_type = ObjType.COND_CONJ
|
94 |
+
if compact:
|
95 |
+
retval.update(val.get_compact_printable_object())
|
96 |
+
else:
|
97 |
+
retval.add(val)
|
98 |
+
elif self.obj_type == ObjType.COND_CONJ:
|
99 |
+
if attr == "^satisfies-op":
|
100 |
+
val.obj_type = ObjType.OP
|
101 |
+
retval.add(val)
|
102 |
+
elif attr == "^activates-context":
|
103 |
+
val.obj_type = ObjType.CONTEXT
|
104 |
+
if compact:
|
105 |
+
retval.update(val.get_compact_printable_object())
|
106 |
+
else:
|
107 |
+
retval.add(val)
|
108 |
+
elif attr == "^supplies-condition":
|
109 |
+
val.obj_type = ObjType.COND_CONJ
|
110 |
+
if compact:
|
111 |
+
retval.update(val.get_compact_printable_object())
|
112 |
+
else:
|
113 |
+
retval.add(val)
|
114 |
+
elif self.obj_type == ObjType.OP:
|
115 |
+
if attr == "^activates-action":
|
116 |
+
val.obj_type = ObjType.ACT_GROUP
|
117 |
+
retval.add(val)
|
118 |
+
elif self.obj_type == ObjType.ACT_GROUP:
|
119 |
+
if attr == "^action":
|
120 |
+
val.obj_type = ObjType.ACT_PRIM
|
121 |
+
retval.add(val)
|
122 |
+
return retval
|
123 |
+
|
124 |
+
def get_prim_cond_string(self, negate=False):
|
125 |
+
if len(self.wme_list) == 0:
|
126 |
+
return "", ""
|
127 |
+
if negate:
|
128 |
+
op_join_str = " is not "
|
129 |
+
else:
|
130 |
+
op_join_str = " is "
|
131 |
+
if self.class_str == None:
|
132 |
+
self.get_class()
|
133 |
+
|
134 |
+
retval_long, retval_short, retval_desc = ["(", "(", None]
|
135 |
+
if self.class_str == "prim":
|
136 |
+
group_str, attr_str, val_str = ["","",""]
|
137 |
+
for (attr,val) in self.wme_list:
|
138 |
+
if attr == "^group":
|
139 |
+
group_str = val
|
140 |
+
elif attr == "^attribute":
|
141 |
+
attr_str = val
|
142 |
+
elif attr == "^value":
|
143 |
+
val_str = val
|
144 |
+
elif attr == "^description":
|
145 |
+
self.description = val
|
146 |
+
retval_desc = val
|
147 |
+
retval_long += group_str+"."+attr_str+op_join_str+val_str
|
148 |
+
retval_short += attr_str+op_join_str+val_str
|
149 |
+
return retval_long+")", retval_short+")", retval_desc
|
150 |
+
|
151 |
+
def get_cond_string(self):
|
152 |
+
retval_long, retval_short, retval_desc = ["","",None]
|
153 |
+
# Compile the parent prim descriptions
|
154 |
+
parent_conds = []
|
155 |
+
# child_conjs = []
|
156 |
+
is_negation = (self.get_class() == "negation")
|
157 |
+
for (attr,val) in self.wme_list:
|
158 |
+
if attr == "^receives-condition":
|
159 |
+
parent_conds.append(val)
|
160 |
+
if attr == "^description":
|
161 |
+
self.description = val
|
162 |
+
retval_desc = val
|
163 |
+
# if attr == "^supplies-condition":
|
164 |
+
# child_conjs.append(val)
|
165 |
+
|
166 |
+
for i,cond in enumerate(parent_conds):
|
167 |
+
if i > 0:
|
168 |
+
retval_long += " \nAND "
|
169 |
+
retval_short += " AND "
|
170 |
+
if cond.obj_type == ObjType.COND_CONJ:
|
171 |
+
long, short, _ = cond.get_cond_string()
|
172 |
+
else:
|
173 |
+
long, short, _ = cond.get_prim_cond_string(negate=is_negation)
|
174 |
+
retval_long += long
|
175 |
+
retval_short += short
|
176 |
+
return retval_long, retval_short, retval_desc
|
177 |
+
|
178 |
+
def get_op_string(self):
|
179 |
+
retval_long, retval_short, retval_desc = ["", "", None]
|
180 |
+
numeric_pref = None
|
181 |
+
for (attr,val) in self.wme_list:
|
182 |
+
if attr == "^name":
|
183 |
+
retval_long = val
|
184 |
+
retval_short = val
|
185 |
+
elif attr == "^numeric-preference":
|
186 |
+
try:
|
187 |
+
numeric_pref = str(float(val)*100)+"%"
|
188 |
+
except Exception as e:
|
189 |
+
print("ERROR in get_op_string() converting numeric_pref to string: "+str(e))
|
190 |
+
numeric_pref = None
|
191 |
+
elif attr == "^description":
|
192 |
+
self.description = val
|
193 |
+
retval_desc = val
|
194 |
+
if numeric_pref:
|
195 |
+
retval_long += "\nPercentage: "+numeric_pref
|
196 |
+
# print(self.id_var+": "+retval)
|
197 |
+
return retval_long, retval_short, retval_desc
|
198 |
+
|
199 |
+
def get_prim_act_string(self):
|
200 |
+
if len(self.wme_list) == 0:
|
201 |
+
return ""
|
202 |
+
if self.class_str == None:
|
203 |
+
self.get_class()
|
204 |
+
retval_long = "("
|
205 |
+
retval_short = "("
|
206 |
+
if self.class_str == "prim":
|
207 |
+
type_str, attr_str, val_str = ["","",""]
|
208 |
+
for (attr,val) in self.wme_list:
|
209 |
+
if attr == "^type":
|
210 |
+
type_str = val
|
211 |
+
elif attr == "^attribute":
|
212 |
+
attr_str = val
|
213 |
+
elif attr == "^value":
|
214 |
+
val_str = val
|
215 |
+
retval_long += type_str+"."+attr_str+" = "+val_str
|
216 |
+
retval_short += attr_str+" = "+val_str
|
217 |
+
elif self.class_str == "prim-message":
|
218 |
+
type_str, flag_str, msg_str = ["","",""]
|
219 |
+
for (attr,val) in self.wme_list:
|
220 |
+
if attr == "^type":
|
221 |
+
type_str = val
|
222 |
+
elif attr == "^flag":
|
223 |
+
flag_str = val
|
224 |
+
elif attr == "^message":
|
225 |
+
msg_str = val
|
226 |
+
retval_long += type_str+".flag = "+flag_str+" AND "+type_str+'.message = "'+msg_str+'"'
|
227 |
+
retval_short += 'message: "'+msg_str+'"'
|
228 |
+
return retval_long+")", retval_short+")"
|
229 |
+
|
230 |
+
def get_act_group_string(self):
|
231 |
+
retval_long, retval_short, retval_desc = ["", "", None]
|
232 |
+
# Compile the child prim action descriptions
|
233 |
+
child_prims = []
|
234 |
+
for (attr,val) in self.wme_list:
|
235 |
+
if attr == "^action":
|
236 |
+
child_prims.append(val)
|
237 |
+
elif attr == "^description":
|
238 |
+
self.description = val
|
239 |
+
retval_desc = val
|
240 |
+
for i,prim in enumerate(child_prims):
|
241 |
+
if i > 0:
|
242 |
+
retval_long += " AND "
|
243 |
+
retval_short += " AND "
|
244 |
+
long, short = prim.get_prim_act_string()
|
245 |
+
retval_long += long
|
246 |
+
retval_short += short
|
247 |
+
return retval_long, retval_short, retval_desc
|
248 |
+
|
249 |
+
def to_string(self):
|
250 |
+
long = self.id_var
|
251 |
+
short = self.id_var
|
252 |
+
description = None
|
253 |
+
|
254 |
+
if self.obj_type == ObjType.CONTEXT:
|
255 |
+
return "", "", self.get_description()
|
256 |
+
if self.obj_type == ObjType.COND_PRIM:
|
257 |
+
long, short, description = self.get_prim_cond_string()
|
258 |
+
# long = "IF "+long
|
259 |
+
# short = "IF "+short
|
260 |
+
if self.obj_type == ObjType.COND_CONJ:
|
261 |
+
long, short, description = self.get_cond_string()
|
262 |
+
if self.obj_type == ObjType.OP:
|
263 |
+
long, short, description = self.get_op_string()
|
264 |
+
if self.obj_type == ObjType.ACT_GROUP:
|
265 |
+
long, short, description = self.get_act_group_string()
|
266 |
+
if self.obj_type == ObjType.ACT_PRIM:
|
267 |
+
long, short = self.get_prim_act_string()
|
268 |
+
return long, short, description
|
269 |
+
|
270 |
+
class ObjType(Enum):
|
271 |
+
CONTEXT = 0
|
272 |
+
COND_PRIM = 1
|
273 |
+
COND_CONJ = 2
|
274 |
+
OP = 3
|
275 |
+
ACT_GROUP = 4
|
276 |
+
ACT_PRIM = 5
|
smem_token_parser.py
ADDED
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
from os import access, R_OK
|
3 |
+
from os.path import isfile
|
4 |
+
from collections import defaultdict
|
5 |
+
import re
|
6 |
+
|
7 |
+
from smem_obj import SMEM_Obj, ObjType
|
8 |
+
|
9 |
+
|
10 |
+
def clean_smem_string_token(s):
|
11 |
+
return str(s).replace("|","")
|
12 |
+
|
13 |
+
def removeComments(s):
|
14 |
+
""" Trim any '#' content from the given string
|
15 |
+
"""
|
16 |
+
ind = str(s).find('#')
|
17 |
+
if (ind == -1):
|
18 |
+
return s
|
19 |
+
return s[:ind]
|
20 |
+
|
21 |
+
def read_tokens_from_lines(file):
|
22 |
+
retval = [] # A list of all tokens from the "smem --add {}" contents.
|
23 |
+
inSmemAdd = False # Whether the read is inside an "smem --add {}" command
|
24 |
+
|
25 |
+
try:
|
26 |
+
for line in file:
|
27 |
+
sline = line.lstrip()
|
28 |
+
# Don't use comments
|
29 |
+
if sline.startswith('#'):
|
30 |
+
continue
|
31 |
+
# Check if we're in an smem --add command
|
32 |
+
if not inSmemAdd:
|
33 |
+
if sline.startswith("smem --add {"):
|
34 |
+
inSmemAdd = True
|
35 |
+
# Only add from this line any content after the opening '{'
|
36 |
+
sline = sline[12:]
|
37 |
+
else:
|
38 |
+
continue
|
39 |
+
|
40 |
+
# Get the tokens: split on whitespace, pipe quotes, parentheses, and brackets, but only exclude whitespace delimiters and pipe quotes
|
41 |
+
regex_pattern = '[\s+]|\\|(.+?)\\||(?<=\\))|(?<=\\()|(?<=\\{)|(?<=\\})'
|
42 |
+
tokens = re.split(regex_pattern, removeComments(sline).rstrip())
|
43 |
+
|
44 |
+
while None in tokens:
|
45 |
+
tokens.remove(None)
|
46 |
+
while '' in tokens:
|
47 |
+
tokens.remove('')
|
48 |
+
|
49 |
+
# Check for the closing character
|
50 |
+
try:
|
51 |
+
ind = tokens.index('}')
|
52 |
+
# If no exception, it was found
|
53 |
+
tokens = tokens[:ind]
|
54 |
+
inSmemAdd = False
|
55 |
+
except:
|
56 |
+
pass
|
57 |
+
|
58 |
+
# Add this line to the return list
|
59 |
+
if len(tokens) > 0:
|
60 |
+
retval.extend(tokens)
|
61 |
+
except Exception as e:
|
62 |
+
print("ERROR extracting tokens from the given file: "+str(e), file=sys.stderr)
|
63 |
+
return None
|
64 |
+
|
65 |
+
return retval
|
66 |
+
|
67 |
+
"""
|
68 |
+
This method scans a file that holds an 'smem --add{}' command and returns the relevant tokens from that file
|
69 |
+
"""
|
70 |
+
def get_smem_tokens_from_local_file(filename):
|
71 |
+
# Error check for reading the file
|
72 |
+
if not isfile(filename):
|
73 |
+
print("ERROR in get_smem_tokens_from_local_file(): File does not exist: '"+str(filename)+"'.", file=sys.stderr)
|
74 |
+
return None
|
75 |
+
if not access(filename, R_OK):
|
76 |
+
print("ERROR in get_smem_tokens_from_local_file(): File is not readable: '"+str(filename)+"'.", file=sys.stderr)
|
77 |
+
return None
|
78 |
+
|
79 |
+
# Get the file content
|
80 |
+
with open(filename) as file:
|
81 |
+
retval = read_tokens_from_lines(file)
|
82 |
+
|
83 |
+
# All done
|
84 |
+
return retval
|
85 |
+
|
86 |
+
|
87 |
+
class SMEM_Parser():
|
88 |
+
|
89 |
+
def __init__(self):
|
90 |
+
# Init the data structured needed to parse the smem file
|
91 |
+
self.smem_var_obj_map = defaultdict(SMEM_Obj)
|
92 |
+
|
93 |
+
def parse_file(self, smem_tokens):
|
94 |
+
# Iterate through the tokens
|
95 |
+
current_obj = None
|
96 |
+
current_attr = None
|
97 |
+
isNextWMEId = False
|
98 |
+
for token in smem_tokens:
|
99 |
+
# Skip empty tokens
|
100 |
+
if len(token) == 0:
|
101 |
+
continue
|
102 |
+
# Get WME ID
|
103 |
+
if isNextWMEId:
|
104 |
+
current_obj = self.smem_var_obj_map[token]
|
105 |
+
current_obj.set_id_var(token)
|
106 |
+
isNextWMEId = False
|
107 |
+
continue
|
108 |
+
# Get start of obj
|
109 |
+
if token == '(':
|
110 |
+
isNextWMEId = True
|
111 |
+
continue
|
112 |
+
# Get end of obj
|
113 |
+
if token == ')':
|
114 |
+
current_obj = None
|
115 |
+
current_attr = None
|
116 |
+
continue
|
117 |
+
# Get attributes
|
118 |
+
if token.startswith('^'):
|
119 |
+
current_attr = token
|
120 |
+
continue
|
121 |
+
# Get values
|
122 |
+
if current_obj != None and current_attr != None:
|
123 |
+
# Add the WME to the current object
|
124 |
+
if token.startswith('<'):
|
125 |
+
token_val = self.smem_var_obj_map[token]
|
126 |
+
token_val.set_id_var(token)
|
127 |
+
else:
|
128 |
+
token_val = clean_smem_string_token(token)
|
129 |
+
current_obj.add_wme(current_attr, token_val)
|
130 |
+
else:
|
131 |
+
print("ERROR: Unexpected token '"+token+"'.")
|
132 |
+
return
|
133 |
+
|
134 |
+
def get_context_root(self):
|
135 |
+
for var,obj in self.smem_var_obj_map.items():
|
136 |
+
for (attr,val) in obj.wme_list:
|
137 |
+
if attr == "^context-root":
|
138 |
+
obj.obj_type = ObjType.CONTEXT
|
139 |
+
return obj
|
140 |
+
return None
|