docs: def isValid(self) -> bool:
          '''Determine if the statement, expression or directive is valid. Otherwise
          the parser will continue until a valid multi-line expression or statement
          can be found.'''
          if not self.values:
              return True
          try:
              if self.category() == 'directive':
                  # we add func() because the expression can be multi-line and
                  # can have keyword-argument like options
                  #
                  # However, python considers
                  #
                  #     func('value', )
                  #
                  # a valid syntax but we do want , to continue to the next line
                  if self.values[-1].strip().endswith(','):
                      self.error_msg = 'Trailing ,'
                      return False
                  # to allow type trait, we will have to test the expression as if in a function
                  # definition, with something like "def func(a : str, b : list=[])"
                  try:
                      compile(
                          'func(' + ''.join(self.values) + ')',
                          filename='<string>',
                          mode='eval')
                  except:
                      compile(
                          'def func(' + ''.join(self.values) + '):\n  pass',
                          filename='<string>',
                          mode='exec')
              elif self.category() == 'statements':
                  compile((''.join(self.values)),
                          filename='<string>',
                          mode='exec')
              elif self.category() == 'script':
                  #
                  # A valid script has an identation defined at the first line. That is to say
                  #
                  # line 1
                  # line 2
                  #
                  # is allowed
                  #
                  #     line 1
                  #     line 2
                  #
                  # line 3
                  #
                  # is not so the addition of line 3 would fail. However, the last line
                  # will be tested before inserted so this function will always return True
                  return True
              else:
                  raise RuntimeError(
                      f'Unrecognized expression type {self.category()}')
              return True
          except Exception as e:
              self.error_msg = repr(e)
              return False