build(rust): vendor rnix parser crate

This commit was merged in pull request #57.
This commit is contained in:
alexion committed 2026-09-16 15:51:43 -04:00
1 parent cbdf482422
commit 82ad65a3a4
492 files changed
+67785 -1

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
use std::{env, fs};
fn main() {
let mut iter = env::args().skip(1).peekable();
if iter.peek().is_none() {
eprintln!("Usage: dump-ast <file>");
return;
}
for file in iter {
let content = match fs::read_to_string(file) {
Ok(content) => content,
Err(err) => {
eprintln!("error reading file: {}", err);
return;
}
};
let parse = rnix::Root::parse(&content);
for error in parse.errors() {
println!("error: {}", error);
}
println!("{:#?}", parse.tree());
}
}
+67
View File
@@ -0,0 +1,67 @@
use rnix::ParseError;
use std::{env, fs};
fn main() {
let file = match env::args().nth(1) {
Some(file) => file,
None => {
eprintln!("Usage: error-report <file>");
return;
}
};
let content = match fs::read_to_string(&file) {
Ok(content) => content,
Err(err) => {
eprintln!("error reading file: {}", err);
return;
}
};
let ast = rnix::Root::parse(&content);
for error in ast.errors() {
let range = match error {
ParseError::Unexpected(range) => range,
ParseError::UnexpectedExtra(range) => range,
ParseError::UnexpectedWanted(_, range, _) => range,
ParseError::UnexpectedDoubleBind(range) => range,
ParseError::DuplicatedArgs(range, _) => range,
err => {
eprintln!("error: {}", err);
continue;
}
};
eprintln!("----- ERROR -----");
eprintln!("{}", error);
let start = usize::from(range.start());
let start_row = content[..start].lines().count() - 1;
let start_line = content[..start].rfind('\n').map(|i| i + 1).unwrap_or(0);
let start_col = content[start_line..start].chars().count();
let end = usize::from(range.end());
let end_row = content[..end].lines().count() - 1;
let end_line = content[..end].rfind('\n').map(|i| i + 1).unwrap_or(0);
let end_col = content[end_line..end].chars().count();
let mut line_len = 1;
let mut line = end_row;
while line >= 10 {
line /= 10;
line_len += 1;
}
let i = start_row.saturating_sub(1);
for (i, line) in content.lines().enumerate().skip(i).take(end_row - i + 1) {
println!("{:line_len$} {}", i + 1, line, line_len = line_len);
if i >= start_row && i <= end_row {
print!("{:line_len$} ", "", line_len = line_len);
let mut end_col = if i == end_row { end_col } else { line.chars().count() };
if i == start_row {
print!("{:indent$}", "", indent = start_col);
end_col -= start_col;
}
for _ in 0..end_col {
print!("^");
}
println!();
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
use std::{io, io::Read};
fn main() {
let mut content = String::new();
io::stdin().read_to_string(&mut content).expect("could not read nix from stdin");
let ast = rnix::Root::parse(&content);
for error in ast.errors() {
println!("error: {}", error);
}
println!("{:#?}", ast.tree());
}
+95
View File
@@ -0,0 +1,95 @@
use std::{env, error::Error, fs};
use rnix::{
ast::{self, AstToken, HasEntry},
match_ast, NodeOrToken, SyntaxNode,
};
use rowan::ast::AstNode;
macro_rules! single_match {
($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? => $captured:expr) => {
match $expression {
$( $pattern )|+ $( if $guard )? => Some($captured),
_ => None
}
};
}
fn main() -> Result<(), Box<dyn Error>> {
let file = match env::args().nth(1) {
Some(file) => file,
None => {
eprintln!("Usage: list-fns <file>");
return Ok(());
}
};
let content = fs::read_to_string(&file)?;
let ast = rnix::Root::parse(&content).ok()?;
let expr = ast.expr().unwrap();
let set = match expr {
ast::Expr::AttrSet(set) => set,
_ => return Err("root isn't a set".into()),
};
for entry in set.entries() {
if let ast::Entry::AttrpathValue(attrpath_value) = entry {
if let Some(ast::Expr::Lambda(lambda)) = attrpath_value.value() {
let attrpath = attrpath_value.attrpath().unwrap();
let ident = attrpath.attrs().last().and_then(|attr| match attr {
ast::Attr::Ident(ident) => Some(ident),
_ => None,
});
let s = ident.as_ref().map_or_else(
|| "error".to_string(),
|ident| ident.ident_token().unwrap().text().to_string(),
);
println!("Function name: {}", s);
{
let comments = comments_before(attrpath_value.syntax());
if !comments.is_empty() {
println!("--> Doc: {comments}");
}
}
let mut value = Some(lambda);
while let Some(lambda) = value {
let s = lambda
.param()
.as_ref()
.map_or_else(|| "error".to_string(), |param| param.to_string());
println!("-> Param: {}", s);
{
let comments = comments_before(lambda.syntax());
if !comments.is_empty() {
println!("--> Doc: {comments}");
}
}
value =
single_match!(lambda.body().unwrap(), ast::Expr::Lambda(lambda) => lambda);
}
println!();
}
}
}
Ok(())
}
fn comments_before(node: &SyntaxNode) -> String {
node.siblings_with_tokens(rowan::Direction::Prev)
// rowan always returns the first node for some reason
.skip(1)
.map_while(|element| match element {
NodeOrToken::Token(token) => match_ast! {
match token {
ast::Comment(it) => Some(Some(it)),
ast::Whitespace(_) => Some(None),
_ => None,
}
},
_ => None,
})
.flatten()
.map(|s| s.text().trim().to_string())
.collect::<Vec<_>>()
.join("\n ")
}
+19
View File
@@ -0,0 +1,19 @@
use std::{env, fs};
fn main() {
let mut iter = env::args().skip(1).peekable();
if iter.peek().is_none() {
eprintln!("Usage: preserve <file>");
return;
}
for file in iter {
let content = match fs::read_to_string(file) {
Ok(content) => content,
Err(err) => {
eprintln!("error reading file: {}", err);
return;
}
};
print!("{}", rnix::Root::parse(&content).tree());
}
}
+48
View File
@@ -0,0 +1,48 @@
use std::{env, error::Error, fs, path::Path};
fn main() -> Result<(), Box<dyn Error>> {
let path = env::var("NIX_PATH")?;
let nixpkgs =
path.split(':').find(|s| s.starts_with("nixpkgs=")).ok_or("no store path found")?;
println!("Nix store path: {}", nixpkgs);
recurse(Path::new(&nixpkgs["nixpkgs=".len()..]))
}
fn recurse(path: &Path) -> Result<(), Box<dyn Error>> {
if path.metadata()?.is_file() {
if path.extension().and_then(|s| s.to_str()) != Some("nix") {
return Ok(());
}
println!("Checking {}", path.display());
let original = fs::read_to_string(path)?;
if original.trim().is_empty() {
return Ok(());
}
let parsed = rnix::Root::parse(&original).tree().to_string();
if original != parsed {
eprintln!("Original input does not match parsed output!");
println!("Input:");
println!("----------");
println!("{}", original);
println!("----------");
println!("Output:");
println!("----------");
println!("{}", parsed);
println!("----------");
return Err("parsing error".into());
}
return Ok(());
} else {
for entry in path.read_dir()? {
let entry = entry?;
if entry.file_type()?.is_symlink() {
continue;
}
recurse(&entry.path())?;
}
}
Ok(())
}