lexer function

List<LexToken> lexer(
  1. String str
)

Implementation

List<LexToken> lexer(String str) {
  final List<LexToken> tokens = [];
  int i = 0;

  while (i < str.length) {
    final char = str[i];

    if (char == '*' || char == '+' || char == '?') {
      tokens.add(
          LexToken(type: LexTokenType.MODIFIER, index: i, value: str[i++]));
      continue;
    }

    if (char == '\\') {
      tokens.add(
          LexToken(type: LexTokenType.ESCAPED_CHAR, index: i, value: str[i++]));
      continue;
    }

    if (char == '{') {
      tokens.add(LexToken(type: LexTokenType.OPEN, index: i, value: str[i++]));
      continue;
    }

    if (char == '}') {
      tokens.add(LexToken(type: LexTokenType.CLOSE, index: i, value: str[i++]));
      continue;
    }

    if (char == ':') {
      String name = '';
      int j = i + 1;

      while (j < str.length) {
        final code = str.codeUnitAt(j);

        if (
            // '0-9'
            (code >= 48 && code <= 57) ||
                // 'A-Z'
                (code >= 65 && code <= 90) ||
                // 'a-z'
                (code >= 97 && code <= 122) ||
                // '_'
                code == 95) {
          name += str[j++];
          continue;
        }

        break;
      }

      if (['', null].contains(name)) {
        // 'Missing parameter name at $i')
        throw TypeError();
      }

      tokens.add(LexToken(type: LexTokenType.NAME, index: i, value: name));
      i = j;
      continue;
    }

    if (char == '(') {
      int count = 1;
      String pattern = '';
      int j = i + 1;

      if (str[j] == '?') {
        // 'Pattern cannot start with "?" at ${j}'
        throw TypeError();
      }

      while (j < str.length) {
        if (str[j] == '\\') {
          pattern += str[j++] + str[j++];
          continue;
        }

        if (str[j] == ')') {
          count--;
          if (count == 0) {
            j++;
            break;
          }
        } else if (str[j] == '(') {
          count++;
          if (str[j + 1] != '?') {
            // 'Capturing groups are not allowed at ${j}'
            throw TypeError();
          }
        }

        pattern += str[j++];
      }

      if (count != 0) {
        // 'Unbalanced pattern at ${i}'
        throw TypeError();
      }
      // 'Missing pattern at ${i}'
      if ([null, ''].contains(pattern)) {
        throw TypeError();
      }

      tokens
          .add(LexToken(type: LexTokenType.PATTERN, index: i, value: pattern));
      i = j;
      continue;
    }

    tokens.add(LexToken(type: LexTokenType.CHAR, index: i, value: str[i++]));
  }

  tokens.add(LexToken(type: LexTokenType.END, index: i, value: ''));

  return tokens;
}