[ prog / sol / mona ]

prog


e and the Stern-Brocot tree

37 2021-02-26 10:43

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,
      }
54


VIP:

do not edit these