def __init__(self, line, line_num=-1, var_map=None):
    """Initialise a new rule object.

    Args:
      line: (str), a template rule line to parse.
      line_num: (int), Optional line reference included in error reporting.
      var_map: Map for template (${var}) substitutions.

    Raises:
      TextFSMTemplateError: If 'line' is not a valid format for a Value entry.
    """
    self.match = ''
    self.regex = ''
    self.regex_obj = None
    self.line_op = ''              # Equivalent to 'Next'.
    self.record_op = ''            # Equivalent to 'NoRecord'.
    self.new_state = ''            # Equivalent to current state.
    self.line_num = line_num

    line = line.strip()
    if not line:
      raise TextFSMTemplateError('Null data in FSMRule. Line: %s'
                                 % self.line_num)

    # Is there '->' action present.
    match_action = self.MATCH_ACTION.match(line)
    if match_action:
      self.match = match_action.group('match')
    else:
      self.match = line

    # Replace ${varname} entries.
    self.regex = self.match
    if var_map:
      try:
        self.regex = string.Template(self.match).substitute(var_map)
      except (ValueError, KeyError):
        raise TextFSMTemplateError(
            "Duplicate or invalid variable substitution: '%s'. Line: %s." %
            (self.match, self.line_num))

    try:
      # Work around a regression in Python 2.6 that makes RE Objects uncopyable.
      self.regex_obj = CopyableRegexObject(self.regex)
    except re.error:
      raise TextFSMTemplateError(
          "Invalid regular expression: '%s'. Line: %s." %
          (self.regex, self.line_num))

    # No '->' present, so done.
    if not match_action:
      return

    # Attempt to match line.record operation.
    action_re = self.ACTION_RE.match(match_action.group('action'))
    if not action_re:
      # Attempt to match record operation.
      action_re = self.ACTION2_RE.match(match_action.group('action'))
      if not action_re:
        # Math implicit defaults with an optional new state.
        action_re = self.ACTION3_RE.match(match_action.group('action'))
        if not action_re:
          # Last attempt, match an optional new state only.
          raise TextFSMTemplateError("Badly formatted rule '%s'. Line: %s." %
                                     (line, self.line_num))

    # We have an Line operator.
    if 'ln_op' in action_re.groupdict() and action_re.group('ln_op'):
      self.line_op = action_re.group('ln_op')

    # We have a record operator.
    if 'rec_op' in action_re.groupdict() and action_re.group('rec_op'):
      self.record_op = action_re.group('rec_op')

    # A new state was specified.
    if 'new_state' in action_re.groupdict() and action_re.group('new_state'):
      self.new_state = action_re.group('new_state')

    # Only 'Next' (or implicit 'Next') line operator can have a new_state.
    # But we allow error to have one as a warning message so we are left
    # checking that Continue does not.
    if (self.line_op == 'Continue' and self.new_state):
      raise TextFSMTemplateError(
          "Action '%s' with new state %s specified. Line: %s."
          % (self.line_op, self.new_state, self.line_num))

    # Check that an error message is present only with the 'Error' operator.
    if self.line_op != 'Error' and self.new_state:
      if not re.match('\w+', self.new_state):
        raise TextFSMTemplateError(
            'Alphanumeric characters only in state names. Line: %s.'
            % (self.line_num))
dataset/ETHPy150Open google/textfsm/textfsm.py/TextFSMRule.__init__/original