compile method
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,
);
}