Files
codeql/shared/yeast/src/tree_builder.rs
Taus 04f587190e yeast: AST desugaring framework with proc-macro DSL
YEAST (YEAST Elaborates Abstract Syntax Trees) is a framework for
transforming tree-sitter parse trees before CodeQL extraction.

Core components:
- shared/yeast/ — Ast, Node, Schema, query matching engine, captures,
  FreshScope, BuildCtx
- shared/yeast-macros/ — proc macros: query!, tree!, trees!, rule!

The query language is inspired by tree-sitter queries:
  (assignment left: (_) @lhs right: (_) @rhs)

Templates support embedded Rust ({expr}), splicing ({..expr}),
computed literals (#{expr}), and fresh identifiers ($name).

The rule! macro combines query and transform:
  rule!((for pattern: (_) @pat ...) => (call receiver: {val} ...))

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 11:34:09 +00:00

44 lines
1.2 KiB
Rust

use std::cell::Cell;
use std::collections::BTreeMap;
/// Tracks fresh identifier generation during a single tree-building operation.
/// All occurrences of the same `$name` within one build share the same generated value.
pub struct FreshScope {
counter: Cell<u32>,
resolved: std::cell::RefCell<BTreeMap<String, String>>,
}
impl Default for FreshScope {
fn default() -> Self {
Self::new()
}
}
impl FreshScope {
pub fn new() -> Self {
Self {
counter: Cell::new(0),
resolved: std::cell::RefCell::new(BTreeMap::new()),
}
}
pub fn resolve(&self, name: &str) -> String {
self.resolved
.borrow_mut()
.entry(name.to_string())
.or_insert_with(|| {
let id = self.counter.get();
self.counter.set(id + 1);
format!("${name}-{id}")
})
.clone()
}
/// Clear resolved names but keep the counter. Called between rule
/// applications so that `$tmp` in different rules gets different values
/// while the counter increases monotonically.
pub fn next_scope(&self) {
self.resolved.borrow_mut().clear();
}
}