def expression(self, text):
    """expression = number , op_mult , expression
                  | expression_terminal , op_mult , number , [operator , expression]
                  | expression_terminal , op_add , [operator , expression]
                  | expression_terminal , [operator , expression] ;
    """
    self._attempting(text)
    return alternation([
      # number , op_mult , expression
      concatenation([
        self.number,
        self.op_mult,
        self.expression
      ], ignore_whitespace=True),
      # expression_terminal , op_mult , number , [operator , expression]
      concatenation([
        self.expression_terminal,
        self.op_mult,
        self.number,
        option(
          concatenation([
            self.operator,
            self.expression
          ], ignore_whitespace=True)
        )
      ], ignore_whitespace=True),
      # expression_terminal , op_add , [operator , expression]
      concatenation([
        self.expression_terminal,
        self.op_add,
        option(
          concatenation([
            self.operator,
            self.expression
          ], ignore_whitespace=True)
        )
      ], ignore_whitespace=True),
      # expression_terminal , [operator , expression]
      concatenation([
        self.expression_terminal,
        option(
          concatenation([
            self.operator,
            self.expression
          ], ignore_whitespace=True)
        )
      ], ignore_whitespace=True)
    ])(text).retyped(TokenType.expression)