docs: def gen_tokens(self):
          """
          >>> list(Program("ls").gen_tokens())
          ['ls']
          >>> list(Program("ls -a").gen_tokens())
          ['ls', '-a']
          >>> list(Program("cd /; pwd").gen_tokens())
          ['cd', '/', None, 'pwd']
          >>> list(Program("'cd /; pwd'").gen_tokens())
          ['cd /; pwd']
          """
          current_token = []
          escape = False
          quote = None
          skip = 0
          for char, peek in zip(self.text, self.text[1:] + " "):
              if skip > 0:
                  skip -= 1
                  continue
              if quote is None:
                  if escape:
                      current_token.append(char)
                      escape = False
                  elif char in self.escape_chars:
                      escape = True
                  elif char in QUOTES:
                      quote = char
                  elif char in self.metacharacters:
                      if current_token:
                          yield token.Word(''.join(current_token))
                      current_token = []
                      if char == "(":
                          yield token.LParen()
                      elif char == ")":
                          yield token.RParen()
                      elif char in "|&;":
                          if peek == char:
                              yield token.Word(char + peek)
                              skip += 1
                          else:
                              yield token.Word(char)
                  else:
                      current_token.append(char)
              elif char == quote:
                  if current_token:
                      yield token.DoubleQuote(''.join(current_token))
                  current_token = []
                  quote = None
              else:
                  current_token.append(char)
          if quote is not None:
              raise ValueError("No closing quotation")
          if escape:
              raise ValueError("No escaped character")
          if current_token:
              yield token.Word(''.join(current_token))