from . import skipWhitespace, ParserWarning
from .property import Property, GAME_INFO
class Node:
def __init__(self):
self.properties=dict()
self.parent=None
self.children=[]
@staticmethod
def fits(s,i):
return i<len(s) and s[i]==";"
@staticmethod
def create(s,start):
assert Node.fits(s,start)
res=Node()
i=skipWhitespace(s,start+1)
while Property.fits(s,i):
i,x=Property.create(s,i)
if x.name in res.properties:
# !! raise or log or ignore
raise ParserWarning('duplicate "{0}" property in a node. second value ignored'.format(x.name),s,i)
else:
res.properties[x.name]=x
i=skipWhitespace(s,i)
return (i,res)
def isGINode(self):
return any(prop.type==GAME_INFO for prop in self.properties.values())
def setProperty(self,name,value):
self.properties[name]=value
# zkontrolovat typ value
def setParent(self,node):
self.parent=node
def setChildren(self,children):
self.children=children
def addChild(self,node):
if node in self.children: return node
self.children.append(node)
return node
def removeChild(self,node):
if node not in self.children:
return None
del self.children[self.children.index(node)]
return node
def removeChildAt(self,i):
if -len(self.children)<i<len(self.children):
res=self.children[i]
del self.children[i]
return res
return None
## Create a copy of the Node, with deep copied propeties and shallow copied parent and children.
def copy(self):
res=Node()
res.properties={k: v.copy() for (k,v) in self.properties.items()}
res.parent=self.parent
res.setChildren(self.children[:])
return res
def getProperty(self,name):
if name in self.properties: return self.properties[name]
else: return None
## Returns textual representation of the Node itself, but disregards its children.
def __str__(self):
return ";" + "".join(str(p) for p in self.properties.values())
def export(self):
# there is a beatiful recursive solution, which this stack is too narrow to contain
stack=[(self,1,1)]
output=[]
while len(stack)>0:
node,left,right=stack.pop()
if left>0: output.append("("*left)
output.append(str(node))
childCount=len(node.children)
if childCount==0: # a leaf
output.append(")"*right)
elif childCount==1: # a line
stack.append((node.children[0],0,right))
else: # a branching node
# first child pops first, last child closes parent's parentheses
children=zip(node.children,[1]*childCount,[1]*(childCount-1)+[1+right])
stack.extend(reversed(children))
return "".join(output)