import re from . import skipWhitespace, ParserError GAME_INFO=1 UNKNOWN=99 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) 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): r=re.compile(r"(\+|-|)\d+") m=r.match(s,start) if m is None: raise ParserError("expected a number matching '(\+|-|)\d+'",s,start) 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: raise ParserError("expected a real number matching '(\+|-|)\d+(\.\d+)?'",s,start) 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: raise ParserError("expected a double value, either '1' or '2'",s,start) 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: raise ParserError("expected a color value, either 'B' or 'W'",s,start) return (m.end(),m.group(0)) def text(simple=True,composed=False): def f(s,start): res="" esc=False lastC="" i=start 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: raise ParserError("expected a point value matching '[a-zA-Z]{2}|'",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 class Property: identRegexp=re.compile(r"[A-Z]+") def __init__(self): self.name="" self.value="" @staticmethod def fits(s,i): return i