compile method

TreeSitterQuery compile(
  1. String source, {
  2. Map<String, String> fallbackCaptures = const {},
  3. TreeSitterLanguageTable? language,
  4. bool preserveAnonymousLiterals = false,
  5. bool validateLanguage = true,
})

Implementation

TreeSitterQuery compile(
  String source, {
  Map<String, String> fallbackCaptures = const {},
  TreeSitterLanguageTable? language,
  bool preserveAnonymousLiterals = false,
  bool validateLanguage = true,
}) {
  final captures = <String, String>{...fallbackCaptures};
  final capturePatternIndices = <String, int>{
    for (final kind in fallbackCaptures.keys) kind: -1,
  };
  final contextual = <TreeSitterQueryPattern>[];
  final structural = <TreeSitterStructuralQueryPattern>[];
  final matchPatterns = <TreeSitterStructuralQueryPattern>[];
  final patternStartBytes = <int>[];
  final patternRooted = <bool>[];
  final captureQuantifiersByPattern =
      <Map<String, TreeSitterCaptureQuantifier>>[];
  final patternNonLocal = <bool>[];
  final generalPredicatesByPattern =
      <List<TreeSitterQueryGeneralPredicate>>[];
  final propertyPredicatesByPattern =
      <List<(TreeSitterQueryProperty, bool)>>[];
  final propertySettingsByPattern = <List<TreeSitterQueryProperty>>[];
  final predicateStrings = <String>[];
  final predicateStepsByPattern = <List<TreeSitterQueryPredicateStep>>[];
  late final List<TreeSitterScmExpression> expressions;
  try {
    expressions = TreeSitterScmParser(source).parse();
  } on FormatException {
    if (language != null && validateLanguage) {
      // Tree-sitter validates a completed node-name token before it reaches
      // the missing closing delimiter. Recover only unterminated lists for
      // that validation pass, then preserve the original syntax error when
      // every recovered symbol is valid.
      final recovered = TreeSitterScmParser(
        source,
      ).parse(recoverUnterminatedLists: true);
      _validateLanguageSymbols(recovered, source, language);
    }
    rethrow;
  }
  final declaredCaptureNames = <String>[];
  final seenCaptureNames = <String>{};
  void collectCaptureNames(TreeSitterScmExpression expression) {
    if (expression case TreeSitterScmAtom(
      :final value,
    ) when value.startsWith('@')) {
      final name = value.substring(1);
      if (seenCaptureNames.add(name)) declaredCaptureNames.add(name);
    } else if (expression is TreeSitterScmList) {
      for (final child in expression.children) {
        collectCaptureNames(child);
      }
    }
  }

  for (final expression in expressions) {
    collectCaptureNames(expression);
  }
  if (language != null && validateLanguage) {
    _validateLanguageSymbols(expressions, source, language);
    _validatePossiblePatterns(expressions, source, language);
  }
  _validatePredicates(expressions, source);
  final patternCount = _compileSequence(
    expressions,
    captures,
    capturePatternIndices,
    contextual,
    structural: structural,
    matchPatterns: matchPatterns,
    querySource: source,
    patternStartBytes: patternStartBytes,
    patternRooted: patternRooted,
    parentKind: null,
    preserveAnonymousLiterals: preserveAnonymousLiterals || language != null,
  );
  for (var index = 0; index < expressions.length; index++) {
    final expression = expressions[index];
    if (!_isPattern(expression)) continue;
    final suffix = <TreeSitterScmAtom>[];
    var cursor = index + 1;
    while (cursor < expressions.length) {
      final atom = expressions[cursor];
      if (atom is! TreeSitterScmAtom || !_isSuffix(atom.value)) break;
      suffix.add(atom);
      cursor++;
    }
    final cardinalities = _scmDecoratedCaptureCardinalities(
      expression,
      suffix,
    );
    captureQuantifiersByPattern.add(
      Map.unmodifiable({
        for (final name in declaredCaptureNames)
          name: (cardinalities[name] ?? const _ScmCaptureCardinality(0, 0))
              .quantifier,
      }),
    );
    patternNonLocal.add(
      language != null && _scmPatternIsNonLocal(expression, suffix, language),
    );
    final metadata = _queryPredicateMetadata(
      expression,
      declaredCaptureNames,
      source,
    );
    generalPredicatesByPattern.add(metadata.general);
    propertyPredicatesByPattern.add(metadata.properties);
    propertySettingsByPattern.add(metadata.settings);
    predicateStepsByPattern.add(
      _queryPredicateSteps(
        expression,
        declaredCaptureNames,
        predicateStrings,
      ),
    );
    index = cursor - 1;
  }
  final sourceByteLength = utf8.encode(source).length;
  final patternEndBytes = <int>[
    for (var index = 0; index < patternStartBytes.length; index++)
      index + 1 < patternStartBytes.length
          ? patternStartBytes[index + 1]
          : sourceByteLength,
  ];
  final guaranteedSteps = language == null
      ? const <({int offset, bool value})>[]
      : _guaranteedSteps(expressions, source, language);
  return TreeSitterQuery(
    Map.unmodifiable(captures),
    capturePatternIndicesByKind: Map.unmodifiable(capturePatternIndices),
    contextualCaptures: List.unmodifiable(contextual),
    structuralPatterns: List.unmodifiable(structural),
    matchPatterns: List.unmodifiable(matchPatterns),
    patternStartBytes: List.unmodifiable(patternStartBytes),
    patternEndBytes: List.unmodifiable(patternEndBytes),
    patternRooted: List.unmodifiable(patternRooted),
    declaredCaptureNames: List.unmodifiable(declaredCaptureNames),
    captureQuantifiersByPattern: List.unmodifiable(
      captureQuantifiersByPattern,
    ),
    patternNonLocal: List.unmodifiable(patternNonLocal),
    guaranteedStepOffsets: List.unmodifiable([
      for (final step in guaranteedSteps) step.offset,
    ]),
    guaranteedStepValues: List.unmodifiable([
      for (final step in guaranteedSteps) step.value,
    ]),
    generalPredicatesByPattern: List.unmodifiable(generalPredicatesByPattern),
    propertyPredicatesByPattern: List.unmodifiable(
      propertyPredicatesByPattern,
    ),
    propertySettingsByPattern: List.unmodifiable(propertySettingsByPattern),
    predicateStrings: List.unmodifiable(predicateStrings),
    predicateStepsByPattern: List.unmodifiable(predicateStepsByPattern),
    patternCount: patternCount,
  );
}