Files @ d3fc4f54e2ee
Branch filter:

Location: Diana/src/sgfParser/property.py

Laman
fixed crash on unknown SGF property
import re

from .propValues import choose, singleton, listOf, compose, number, real, double, color, text, empty, anything, point, move, stone
from . import skipWhitespace, ParserError

GAME_INFO=1
UNKNOWN=99


class Property:
	identRegexp=re.compile(r"[A-Z]+")

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

	@staticmethod
	def fits(s,i):
		return i<len(s) and s[i].isupper()

	@staticmethod
	def create(s,start):
		assert Property.fits(s,start)
		res=Property()
		i,res.name=Property.ident(s,start)
		i=skipWhitespace(s,i)
		i,x=Property.createValue(s,i,res.name)
		res.value=x
		i=skipWhitespace(s,i)
		return (i,res)

	@staticmethod
	def ident(s,start):
		m=Property.identRegexp.match(s,start)
		if m is None: raise ParserError("expected a property identifier matching '[A-Z]+'",s,start)
		return (m.end(),m.group())

	@staticmethod
	def createValue(s,start,name):
		if name in Property.patterns:
			return Property.patterns[name](s,start)
		else:
			# !! raise or log or ignore
			# print('warning, unknown property "{0}" at position {1}'.format(name,start))
			return choose(listOf(anything), singleton(anything))(s,start)

	@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 copy(self):
		res=Property()
		res.name=self.name
		res.value=self.value if not isinstance(self.value,list) else self.value[:]
		return res

	def __str__(self):
		val="[{0}]".format(self.value) if not isinstance(self.value,list) else "".join("[{0}]".format(x) for x in self.value)
		return "{0}{1}".format(self.name,val)

	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