from collections import OrderedDict from jwutils.log import * def quote(s): if is_quoted(s): return s s = s.strip() if len(s) > 0: if s[0] == '"': return "'" + s + "'" return '"' + s + '"' def is_quoted(s): if isinstance(s, StringTree): return False s = s.strip() if len(s) < 2: return False d = s[0] if d == s[-1] and d in [ '"', "'" ]: return True return False def cleanup_string(s): if isinstance(s, StringTree): return s s = s.strip() if is_quoted(s): return s[1:-1].replace('\\' + s[0], s[0]) return s class StringTree: # export def __init__(self, path, content): slog(DEBUG, "ctor, path =", path, "content =", content) self.children = OrderedDict() self.content = None self.__set(path, content) assert(hasattr(self, "content")) #assert self.content is not None # root (content = [ symbols ]) # symbols (content = [ regex ]) # regex ( content ='[ \n\t\r]+' ) # root (content = root, children = [ symbols ]) # symbols (content = symbols, children = [ regex ]) # regex ( content = regex, children = [ '[ \n\t\r]+' ] ) # '[ \n\t\r]+)' ( content = '\n\t\r]+)', children = [] ) def __set(self, path_, content, split=True): logcontent = "not-yet" if hasattr(self, "content"): logcontent = self.content slog(DEBUG, "+ setting >" + str(content) + "< at path \"" + str(path_) + "\" to", logcontent) if path_ is None: self.content = cleanup_string(content) slog(DEBUG, " -- content = >" + str(content) + "<, self.content = >" + str(self.content) + "<") return self path = cleanup_string(path_) components = path.split('.') if split else [ path ] l = len(components) if len(path) == 0 or l == 0: assert self.content is None #self.content = cleanup_string(content) self.content = content slog(DEBUG, " -- content = >" + str(content) + "<, self.content = >" + str(self.content) + "<") #assert(content != "'antlr_doesnt_understand_vertical_tab'") assert(content != '"[a-zA-Z0-9+_*/-]"') #self.children[content] = StringTree(None, content) return self assert self.content is not None nibble = components[0] rest = '.'.join(components[1:]) if nibble not in self.children: self.children[nibble] = StringTree('', content=nibble) if l > 1: assert len(rest) > 0 return self.children[nibble].__set(rest, content=content) if content is not None: self.children[nibble].children[content] = StringTree('', content=content) return self.children[nibble] def __str__(self): return 'st:"{}"'.format(self.content) def __getitem__(self, path): r = self.get(path) if r is None: raise KeyError(path) return r def __setitem__(self, key, value): return self.__set(key, value) def __dump(self, prio, indent=0, **kwargs): caller = kwargs['caller'] if 'caller' in kwargs.keys() else get_caller_pos(1) slog(prio, '|' + (' ' * indent) + str(self.content), caller=caller) indent += 2 for name, child in self.children.items(): child.__dump(prio, indent=indent, caller=caller) def keys(self): return self.children.keys() def items(self): return self.children.items() def set_content(self, content): if content is None: raise Exception("Tried to set none content") content = cleanup_string(content) if len(content) == 0: raise Exception("Tried to set empty content") self.content = content def add(self, path, content = None, split = True): slog(DEBUG, "adding >{}< at >{}< to >{}<".format(content, path, self.content)) return self.__set(path, content, split) def get(self, path_): slog(DEBUG, "looking for", path_, "in", self.content) path = cleanup_string(path_) if len(path) == 0: slog(DEBUG, "returning myself") return self if is_quoted(path_): if not path in self.children.keys(): return None return self.children[path] components = path.split('.') if len(components) == 0: return self name = cleanup_string(components[0]) if not hasattr(self, "children"): return None if not name in self.children.keys(): slog(DEBUG, "Name \"" + name + "\" is not in children of", self.content) for child in self.children: slog(DEBUG, "child = ", child) return None relpath = '.'.join(components[1:]) return self.children[name].get(relpath) def value(self): if len(self.children) == 0: return None return self.children[next(reversed(self.children))].content def dump(self, prio, *args, **kwargs): caller = kwargs['caller'] if 'caller' in kwargs.keys() else get_caller_pos(1) msg = '' if args is not None: msg = ' ' + ' '.join(args) + ' ' slog(prio, ",------------" + msg + "----------- >", caller=caller) self.__dump(prio, indent=0, caller=caller) slog(prio, "`------------" + msg + "----------- <", caller=caller)