Files @ ef10e626e192
Branch filter:

Location: Diana/src/sgfParser/propValues.py - annotation

Laman
exporting game info, added GameRecord wrapper
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
70d01e8dc839
70d01e8dc839
70d01e8dc839
70d01e8dc839
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
70d01e8dc839
70d01e8dc839
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
70d01e8dc839
70d01e8dc839
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
70d01e8dc839
70d01e8dc839
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
70d01e8dc839
70d01e8dc839
70d01e8dc839
70d01e8dc839
7a9194696648
7a9194696648
7a9194696648
70d01e8dc839
70d01e8dc839
70d01e8dc839
70d01e8dc839
7a9194696648
7a9194696648
7a9194696648
7a9194696648
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
5982aac96259
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
5982aac96259
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
70d01e8dc839
70d01e8dc839
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
7a9194696648
import re

from . import ParserError, skipWhitespace


class Regexp:
	number=re.compile(r"(\+|-|)\d+")
	real=re.compile(r"(\+|-|)\d+(\.\d+)?")
	point=re.compile(r"[a-zA-Z]{2}|")
	text=re.compile(r"(?:.*?[^\\])??(?:\\\\)*(?=])", re.DOTALL)
	composedText=re.compile(r"(?:.*?[^\\])??(?:\\\\)*(?=]|:)", re.DOTALL)

	class Text:
		softBreaks=re.compile(r"(^|[^\\])((\\\\)*)\\((\n\r)|(\r\n)|\r|\n)")
		whitespace=re.compile(r"[\t\f\v]")
		simpleWhitespace=re.compile(r"[\t\f\v\n\r]")
		removeSlashes=re.compile(r"(^|[^\\])((\\\\)*)\\($|[^\\])")
		unescapeSlashes=re.compile(r"\\\\")


class Composed:
	def __init__(self,a=None,b=None):
		self.a=a
		self.b=b

	def __str__(self):
		return "{0}:{1}".format(self.a,self.b)


class Point:
	def __init__(self,c,r):
		self.r=r
		self.c=c

	def __iter__(self):
		yield self.c
		yield self.r

	def __str__(self):
		a=ord("a")
		return chr(a+self.c)+chr(a+self.r)


## Metatype matching one of the provided types.
#
# Returns the first match, so the order is important.
def choose(*vTypes):
	def f(s,start):
		for vType in vTypes:
			try:
				i,x=vType(s,start)
				return (i,x)
			except ParserError: pass
		raise ParserError("no variant of a 'choose' property value matched",s,start)
	return f


def singletonFits(s,i):
	return i<len(s) and s[i]=="["


def singletonEnds(s,i):
	return i<len(s) and s[i]=="]"


def singleton(vType):
	def f(s,start):
		if not singletonFits(s,start):
			raise ParserError("expected a property value starting with '['",s,start)
		i,x=vType(s,start+1)
		if not singletonEnds(s,i):
			raise ParserError("expected a property value ending with ']'",s,i)
		i=skipWhitespace(s,i+1)
		return (i,x)
	return f


def listOf(vType,allowEmpty=False):
	def f(s,start):
		i=start
		if not singletonFits(s,i):
			raise ParserError("expected a property value starting with '['",s,i)
		if singletonEnds(s,i+1) and allowEmpty:
			i=skipWhitespace(s,i+2)
			return (i,[])
		single=singleton(vType)
		i,x=single(s,i)
		res=[x]
		while singletonFits(s,i):
			i,x=single(s,i)
			res.append(x)
		return (i,res)
	return f


def compose(vTypeA,vTypeB):
	def f(s,start):
		i,a=vTypeA(s,start)
		if i>=len(s) or s[i]!=":":
			raise ParserError("expected a composed property value separated by ':'",s,i)
		i,b=vTypeB(s,i+1)
		return (i,Composed(a,b))
	return f


def number(s,start):
	m=Regexp.number.match(s,start)
	if m is None: raise ParserError("expected a number matching '{0}'".format(Regexp.number.pattern),s,start)
	res=int(m.group(0))
	return (m.end(),res)


def real(s,start):
	m=Regexp.real.match(s,start)
	if m is None: raise ParserError("expected a real number matching '{0}'".format(Regexp.real.pattern),s,start)
	res=float(m.group(0))
	return (m.end(),res)


def double(s,start):
	c=s[start]
	if c not in ("1", "2"):
		raise ParserError("expected a double value, either '1' or '2'",s,start)
	return (start+1,c)


def color(s,start):
	c=s[start]
	if c not in ("B", "W"):
		raise ParserError("expected a color value, either 'B' or 'W'",s,start)
	return (start+1,c)


def text(simple=True,composed=False):
	def f(s,start):
		regexps=Regexp.Text
		m=Regexp.composedText.match(s,start) if composed else Regexp.text.match(s,start)
		res=m.group(0)
		res=regexps.softBreaks.sub(r"\1\2",res) # remove soft line breaks
		if simple:
			res=regexps.simpleWhitespace.sub(" ",res) # convert whitespace to spaces, no escapes
		else:
			res=regexps.whitespace.sub(" ",res) # convert whitespace to spaces, no escapes
		res=regexps.removeSlashes.sub(r"\1\2\4",res)
		res=regexps.unescapeSlashes.sub(r"\\",res) # unescape slashes

		return (m.end(),res)
	return f


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


def anything(s,start):
	esc=False
	i=start
	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):
	m=Regexp.point.match(s,start) # !! limit to board size
	if m is None: raise ParserError("expected a point value matching '{0}'".format(Regexp.point.pattern),s,start)
	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(),Point(col,row))


move=point
stone=point