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