split method

Iterable<String> split()

Implementation

Iterable<String> split() sync* {
  var i = 0;
  var lastDollar = -2; // position of last dollar sign we saw
  String? inDollarQuote;
  String? inQuote;
  String? escaped;
  String? token;

  if (debug) {
    print('full input: >$str<');
  }

  while (true) {
    final pos = i;
    final char = i < str.length ? str[i++] : null;

    if (debug) {
      print([
        'position: $pos',
        'input: >$char<',
        'accumulated: $token',
        'inQuote: $inQuote',
        'inDollarQuote: $inDollarQuote',
        'lastDollar: $lastDollar',
        'escaped: $escaped'
      ].join('\n'));
    }

    // Ran out of characters, we're done
    if (char == null) {
      if (inQuote != null) {
        throw ('Got EOF while in a quoted string');
      }
      if (escaped != null) {
        throw ('Got EOF while in an escape sequence');
      }
      if (token != null) {
        yield token;
      }
      return;
    }

    // We were in an escape sequence, complete it
    if (escaped != null) {
      if (char == '\n') {
        // An escaped newline just means to continue the command on the next
        // line. We just need to ignore it.
      } else if (inQuote != null) {
        // If we are in a quote, just accumulate the whole escape sequence,
        // as we will interpret escape sequences later.
        token = (token ?? '') + escaped + char;
      } else {
        // Just use the literal character
        token = (token ?? '') + char;
      }

      escaped = null;
      continue;
    }

    if (escapes.contains(char)) {
      if (inQuote == null ||
          inDollarQuote != null ||
          escapedQuotes.contains(inQuote)) {
        // We encountered an escape character, which is going to affect how
        // we treat the next character.
        escaped = char;
        continue;
      } else {
        // This string type doesn't use escape characters. Ignore for now.
      }
    }

    // We were in a string
    if (inQuote != null) {
      // String is finished. Don't grab the quote character.
      if (char == inQuote) {
        token = processEscapes(token ?? '', inQuote, inDollarQuote == '\'');
        inQuote = null;
        inDollarQuote = null;
        continue;
      }

      // String isn't finished yet, accumulate the character
      token = (token ?? '') + char;
      continue;
    }

    // This is the start of a new string, don't accumulate the quotation mark
    if (quotes.contains(char)) {
      inQuote = char;
      if (lastDollar == pos - 1) {
        if (char == '\'' && !ansiCQuotes) {
          // Feature not enabled
        } else if (char == '"' && !localeQuotes) {
          // Feature not enabled
        } else {
          inDollarQuote = char;
        }
      }

      token = (token ?? ''); // fixes blank string

      if (inDollarQuote != null) {
        // Drop the opening $ we captured before
        token = token.substring(0, token.length - 1);
      }

      continue;
    }

    // This is a dollar sign, record that we saw it in case it's the start of
    // an ANSI C or localized string
    if (inQuote == null && char == '\$') {
      lastDollar = pos;
    }

    // This is whitespace, so yield the token if we have one
    if (whitespace.contains(char)) {
      if (token != null) {
        yield token;
      }
      token = null;
      continue;
    }

    // Otherwise, accumulate the character
    token = (token ?? '') + char;
  }
}