diff --git a/src/sgfParser/property.py b/src/sgfParser/property.py --- a/src/sgfParser/property.py +++ b/src/sgfParser/property.py @@ -1,4 +1,5 @@ import re +from . import skipWhitespace, ParserError GAME_INFO=1 @@ -28,36 +29,54 @@ class Point: 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: - i,x=vType(s,start) - if x is not None: return (i,x) - return (start,None) + 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("a composed property value separated by ':' expected",s,i) i,b=vTypeB(s,i+1) - if b==None: return start,None return (i,Composed(a,b)) return f @@ -75,7 +94,7 @@ def compose(vTypeA,vTypeB): def number(s,start): r=re.compile(r"(\+|-|)\d+") m=r.match(s,start) - if m is None: return (start,None) + if m is None: raise ParserError("expected a number matching '(\+|-|)\d+'",s,start) res=int(m.group(0)) return (m.end(),res) @@ -83,7 +102,7 @@ def number(s,start): def real(s,start): r=re.compile(r"(\+|-|)\d+(\.\d+)?") m=r.match(s,start) - if m is None: return (start,None) + if m is None: raise ParserError("expected a real number matching '(\+|-|)\d+(\.\d+)?'",s,start) res=float(m.group(0)) return (m.end(),res) @@ -91,7 +110,7 @@ def real(s,start): def double(s,start): r=re.compile(r"1|2") m=r.match(s,start) - if m is None: return (start,None) + 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) @@ -99,7 +118,7 @@ def double(s,start): def color(s,start): r=re.compile(r"B|W") m=r.match(s,start) - if m is None: return (start,None) + if m is None: raise ParserError("expected a color value, either 'B' or 'W'",s,start) return (m.end(),m.group(0)) @@ -108,6 +127,7 @@ def text(simple=True,composed=False): res="" esc=False lastC="" + i=start for i,c in enumerate(s[start:],start): if esc: if c!="\n" and c!="\r": res+=c @@ -144,7 +164,7 @@ def anything(s,start): 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 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] @@ -158,29 +178,31 @@ stone=point class Property: + identRegexp=re.compile(r"[A-Z]+") + def __init__(self): self.name="" self.value="" @staticmethod + def fits(s,i): + return i