Files @ cfcff53c74e6
Branch filter:

Location: Diana/src/sgfParser/property.py

Laman
little property refactoring
import re


GAME_INFO=1
UNKNOWN=99


class Property:
	def __init__(self):
		self.name=""
		self.value=""

	@staticmethod
	def create(s,start):
		res=Property()
		i,x=Property.ident(s,start)
		if x is None:
			return (start,None)
		res.name=x
		i,x=PropValue.create(s,i,res.name)
		if x is None:
			print('error when parsing property "{0}" at position {1}'.format(res.name,i))
			return (start,None)
		res.value=x
		return (i,res)

	@staticmethod
	def ident(s,start):
		r=re.compile(r"[A-Z]+")
		m=r.match(s,start)
		if m is None: return (start,None)
		return (m.end(),m.group())

	@property
	def type(self):
		gameInfo={"AN","BR","BT","CP","DT","EV","GN","GC","ON","OT","PB","PC","PW","RE","RO","RU","SO","TM","US","WR","WT"}
		if self.name in gameInfo: return GAME_INFO
		else: return UNKNOWN


def choose(*vTypes):
	def f(s,start):
		for vType in vTypes:
			i,x=vType(s,start)
			if x is not None: return (i,x)
		return (start,None)
	return f


def singleton(vType):
	def f(s,start):
		if s[start]!="[":
			return (start,None)
		i,x=vType(s,start+1)
		if x is None: return (start,None)
		if s[i]!="]":
			return (start,None)
		return (i+1,x)
	return f


def listOf(vType,allowEmpty=False):
	def f(s,start):
		res=[]
		single=singleton(vType)
		i,x=single(s,start)
		while x!=None:
			res.append(x)
			i,x=single(s,i)
		if len(res)==0 and not allowEmpty: return (start,None)
		return (i,res)
	return f


def compose(vTypeA,vTypeB):
	def f(s,start):
		i,a=vTypeA(s,start)
		if a==None or s[i]!=":": return (start,None)
		i,b=vTypeB(s,i+1)
		if b==None: return start,None
		return (i,(a,b))
	return f


def number(s,start):
	r=re.compile(r"(\+|-|)\d+")
	m=r.match(s,start)
	if m is None: return (start,None)
	res=int(m.group(0))
	return (m.end(),res)


def real(s,start):
	r=re.compile(r"(\+|-|)\d+(\.\d+)?")
	m=r.match(s,start)
	if m is None: return (start,None)
	res=float(m.group(0))
	return (m.end(),res)


def double(s,start):
	r=re.compile(r"1|2")
	m=r.match(s,start)
	if m is None: return (start,None)
	res=int(m.group(0))
	return (m.end(),res)


def color(s,start):
	r=re.compile(r"B|W")
	m=r.match(s,start)
	if m is None: return (start,None)
	return (m.end(),m.group(0))


def text(simple=True,composed=False):
	def f(s,start):
		res=""
		esc=False
		lastC=""
		for i,c in enumerate(s[start:],start):
			if esc:
				if c!="\n" and c!="\r": res+=c
				esc=False
			elif (c=="\n" and lastC=="\r") or (c=="\r" and lastC=="\n"): pass
			elif c=="\r" or c=="\n" and not simple:
				res+="\n"
			elif c.isspace():
				res+=" "
			elif c=="\\":
				esc=True
			elif c=="]" or (c==":" and composed):
				break
			else:
				res+=c
			lastC=c
		return (i,res)
	return f


def empty(s,start): return (start,"")


def anything(s,start):
	esc=False
	for i,c in enumerate(s[start:],start):
		if esc: esc=False
		elif c=="\\": esc=True
		elif c=="]": break
	return (i,s[start:i])

# go specific
def point(s,start):
	r=re.compile(r"[a-zA-Z]{2}|") # !! limit to board size
	m=r.match(s,start)
	if m is None: return (start,None)
	if m.group(0)=="": # pass, !! tt
		return (m.end(),tuple())
	col=m.group(0)[0]
	row=m.group(0)[1]
	col=ord(col) - (ord("a") if "a"<=col<="z" else ord("A")-26)
	row=ord(row) - (ord("a") if "a"<=row<="z" else ord("A")-26)
	return (m.end(),(col,row))

move=point
stone=point


class PropValue:
	def __init__(self):
		self.type=""
		self.value=None

	@staticmethod
	def create(s,start,name):
		if name in PropValue.patterns:
			return PropValue.patterns[name](s,start)
		else:
			print('warning, unknown property "{0}" at position {1}'.format(name,start))
			return singleton(anything)(s,start)

	patterns={
		"B":singleton(move),
		"KO":singleton(empty),
		"MN":singleton(number),
		"W":singleton(move),
		"AB":listOf(stone), #
		"AE":listOf(point), #
		"AW":listOf(stone), #
		"PL":singleton(color),
		"C":singleton(text(simple=False)),
		"DM":singleton(double),
		"GB":singleton(double),
		"GW":singleton(double),
		"HO":singleton(double),
		"N":singleton(text()),
		"UC":singleton(double),
		"V":singleton(real),
		"BM":singleton(double),
		"DO":singleton(empty),
		"IT":singleton(empty),
		"TE":singleton(double),
		"AR":listOf(compose(point,point)), #
		"CR":listOf(point), #
		"DD":listOf(point,allowEmpty=True), #
		"LB":listOf(compose(point,text())), #
		"LN":listOf(compose(point,point)), #
		"MA":listOf(point), #
		"SL":listOf(point), #
		"SQ":listOf(point), #
		"TR":listOf(point), #
		"AP":singleton(compose(text(composed=True),text())), #
		"CA":singleton(text()),
		"FF":singleton(number),
		"GM":singleton(number),
		"ST":singleton(number),
		"SZ":choose(singleton(number),singleton(compose(number,number))), #
		"AN":singleton(text()),
		"BR":singleton(text()),
		"BT":singleton(text()),
		"CP":singleton(text()),
		"DT":singleton(text()),
		"EV":singleton(text()),
		"GN":singleton(text()),
		"GC":singleton(text(simple=False)),
		"ON":singleton(text()),
		"OT":singleton(text()),
		"PB":singleton(text()),
		"PC":singleton(text()),
		"PW":singleton(text()),
		"RE":singleton(text()),
		"RO":singleton(text()),
		"RU":singleton(text()),
		"SO":singleton(text()),
		"TM":singleton(real),
		"US":singleton(text()),
		"WR":singleton(text()),
		"WT":singleton(text()),
		"BL":singleton(real),
		"OB":singleton(number),
		"OW":singleton(number),
		"WL":singleton(real),
		"FG":choose(singleton(empty),singleton(compose(number,text()))), #
		"PM":singleton(number),
		"VW":listOf(point,allowEmpty=True), #

		# go specific
		"HA":singleton(number),
		"KM":singleton(real),
		"TB":listOf(point,allowEmpty=True),
		"TW":listOf(point,allowEmpty=True)
	}


# TODO:
# date