The updated compiler:
class Compiler:
@ staticmethod
def fixedlimit (spec, limit):
what = spec.kind ()
fun = getattr (Compiler, "fixedlimit_" + what)
# after
if limit < 1:
return {
"group": EmptyGroup (),
"count": 0,
}
ret = fun (spec, limit)
return ret
@ staticmethod
def fixedlimit_fixed (spec, limit):
fs = spec.fixedstr
fslen = len (fs)
if fslen < 1:
return {
"group": EmptyGroup (),
"count": 0,
}
if fslen <= limit:
return {
"group": spec,
"count": fslen,
}
return {
"group": FixedGroup (fs [:limit]),
"count": limit,
}
@ staticmethod
def fixedlimit_expo (spec, limit):
base = spec.base
baselen = base.fixedlength ()
expo = spec.expo
have = expo * baselen
if have < 1:
return {
"group": EmptyGroup (),
"count": 0,
}
if have <= limit:
return {
"group": spec,
"count": have,
}
div, mod = divmod (limit, baselen)
if mod:
ret = Compiler.fixedlimit (base, mod)
gmod = ret ["group"]
if ret ["count"] != mod:
raise Wrong (mod, ret ["count"])
if div:
if div > 1:
h = ListGroup ([ExpoGroup (base, div), gmod])
else:
h = ListGroup ([base, gmod])
else:
h = gmod
else:
if div > 1:
h = ExpoGroup (base, div)
else:
h = base
return {
"group": h,
"count": limit,
}
@ staticmethod
def fixedlimit_list (spec, limit):
gs = spec.groups
gslen = len (gs)
if gslen < 1:
return {
"group": EmptyGroup (),
"count": 0,
}
take = []
left = limit
used = 0
flim = Compiler.fixedlimit
while (left > 0) and (used < gslen):
ret = flim (gs [used], left)
used += 1
now = ret ["count"]
if now > 0:
take.append (ret ["group"])
left -= now
taken = len (take)
if taken < 1:
return {
"group": EmptyGroup (),
"count": 0,
}
return {
"group": take [0] if taken == 1 else ListGroup (take),
"count": limit - left,
}
@ staticmethod
def fixedlimit_star (spec, limit):
g = spec.group
if not g.isfixed ():
raise Wrong (g.kind ())
have = g.fixedlength ()
if have < 1:
raise Wrong
div, mod = divmod (limit, have)
if mod:
ret = Compiler.fixedlimit (g, mod)
gmod = ret ["group"]
if ret ["count"] != mod:
raise Wrong (mod, ret ["count"])
if div:
if div > 1:
h = ListGroup ([ExpoGroup (g, div), gmod])
else:
h = ListGroup ([g, gmod])
else:
h = gmod
else:
if div > 1:
h = ExpoGroup (g, div)
else:
h = g
return {
"group": h,
"count": limit,
}
@ staticmethod
def fixedlimit_stamploop (spec, limit):
more = True
index = 0
left = limit
stal = spec.stamplength
while more:
now = stal (index)
if now <= left:
index += 1
left -= now
more = (left > 0)
else:
more = False
out = []
if index > 1:
out.append (LoopGroup (index, spec.stamp))
elif index == 1:
out.append (spec.stamp)
if left > 0:
g = spec.tailgroup (index)
ret = Compiler.fixedlimit (g, left)
gmod = ret ["group"]
if ret ["count"] != left:
raise Wrong (left, ret ["count"])
out.append (gmod)
outlen = len (out)
if outlen < 1:
raise Wrong
return {
"group": out [0] if outlen == 1 else ListGroup (out),
"count": limit,
}