diff --git a/shared/tree-sitter-extractor/src/extractor/mod.rs b/shared/tree-sitter-extractor/src/extractor/mod.rs index 3eab0144bc1..bdd23ad7301 100644 --- a/shared/tree-sitter-extractor/src/extractor/mod.rs +++ b/shared/tree-sitter-extractor/src/extractor/mod.rs @@ -837,7 +837,12 @@ pub fn extract_and_desugar( schema, ); let runner = yeast::Runner::new(language.clone(), rules); - let ast = runner.run_from_tree(&tree); + let ast = runner.run_from_tree(&tree) + .unwrap_or_else(|e| { + tracing::error!("Desugaring failed: {e}"); + // Fall back to the un-desugared AST + yeast::Ast::from_tree(language.clone(), &tree) + }); traverse_yeast(&ast, &mut visitor); diff --git a/shared/yeast/src/bin/main.rs b/shared/yeast/src/bin/main.rs index 92c1530982d..e9ee1f38078 100644 --- a/shared/yeast/src/bin/main.rs +++ b/shared/yeast/src/bin/main.rs @@ -21,6 +21,6 @@ fn main() { let language = get_language(&args.language); let source = std::fs::read_to_string(&args.file).unwrap(); let runner = yeast::Runner::new(language, vec![]); - let ast = runner.run(&source); + let ast = runner.run(&source).unwrap(); println!("{}", ast.print(&source, ast.get_root())); } diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index 59a21f6a37c..ef38d446dc9 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -539,52 +539,49 @@ impl Rule { Self { query, transform } } - fn try_rule(&self, ast: &mut Ast, node: Id, fresh: &tree_builder::FreshScope) -> Option> { + fn try_rule(&self, ast: &mut Ast, node: Id, fresh: &tree_builder::FreshScope) -> Result>, String> { let mut captures = Captures::new(); - if self.query.do_match(ast, node, &mut captures).unwrap() { + if self.query.do_match(ast, node, &mut captures)? { fresh.next_scope(); - // Get the source range of the matched node for location info let source_range = ast.get_node(node).and_then(|n| { match n.content { NodeContent::Range(r) => Some(r), _ => n.source_range, } }); - Some((self.transform)(ast, captures, fresh, source_range)) + Ok(Some((self.transform)(ast, captures, fresh, source_range))) } else { - None + Ok(None) } } } -fn apply_rules(rules: &Vec, ast: &mut Ast, id: Id, fresh: &tree_builder::FreshScope) -> Vec { - // apply the transformation rules on this node +fn apply_rules(rules: &Vec, ast: &mut Ast, id: Id, fresh: &tree_builder::FreshScope) -> Result, String> { for rule in rules { - if let Some(result_node) = rule.try_rule(ast, id, fresh) { - // We transformed it so now recurse into the result - return result_node - .iter() - .flat_map(|node| apply_rules(rules, ast, *node, fresh)) - .collect(); + if let Some(result_node) = rule.try_rule(ast, id, fresh)? { + let mut results = Vec::new(); + for node in result_node { + results.extend(apply_rules(rules, ast, node, fresh)?); + } + return Ok(results); } } - // copy the current node let mut node = ast.nodes[id].clone(); // recursively descend into all the fields for vec in node.fields.values_mut() { - let mut old = Vec::new(); - mem::swap(vec, &mut old); - *vec = old - .iter() - .flat_map(|node| apply_rules(rules, ast, *node, fresh)) - .collect(); + let old = std::mem::take(vec); + let mut new = Vec::new(); + for child_id in old { + new.extend(apply_rules(rules, ast, child_id, fresh)?); + } + *vec = new; } node.id = ast.nodes.len(); ast.nodes.push(node); - vec![ast.nodes.len() - 1] + Ok(vec![ast.nodes.len() - 1]) } pub struct Runner { @@ -597,28 +594,30 @@ impl Runner { Self { language, rules } } - pub fn run_from_tree(&self, tree: &tree_sitter::Tree) -> Ast { + pub fn run_from_tree(&self, tree: &tree_sitter::Tree) -> Result { let fresh = tree_builder::FreshScope::new(); let mut ast = Ast::from_tree(self.language.clone(), tree); - let res = apply_rules(&self.rules, &mut ast, 0, &fresh); + let res = apply_rules(&self.rules, &mut ast, 0, &fresh)?; if res.len() != 1 { - panic!("Expected at exactly one result node, got {}", res.len()); + return Err(format!("Expected exactly one result node, got {}", res.len())); } ast.set_root(res[0]); - ast + Ok(ast) } - pub fn run(&self, input: &str) -> Ast { + pub fn run(&self, input: &str) -> Result { let fresh = tree_builder::FreshScope::new(); let mut parser = tree_sitter::Parser::new(); - parser.set_language(&self.language).unwrap(); - let tree = parser.parse(input, None).unwrap(); + parser.set_language(&self.language) + .map_err(|e| format!("Failed to set language: {e}"))?; + let tree = parser.parse(input, None) + .ok_or_else(|| "Failed to parse input".to_string())?; let mut ast = Ast::from_tree(self.language.clone(), &tree); - let res = apply_rules(&self.rules, &mut ast, 0, &fresh); + let res = apply_rules(&self.rules, &mut ast, 0, &fresh)?; if res.len() != 1 { - panic!("Expected at exactly one result node, got {}", res.len()); + return Err(format!("Expected exactly one result node, got {}", res.len())); } ast.set_root(res[0]); - ast + Ok(ast) } } diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index 9df89c8c3d4..9cc9df72945 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -6,7 +6,7 @@ use yeast::*; /// Helper: parse Ruby source, apply rules, return dump of result. fn run_and_dump(input: &str, rules: Vec) -> String { let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), rules); - let ast = runner.run(input); + let ast = runner.run(input).unwrap(); dump_ast(&ast, ast.get_root(), input) } @@ -64,7 +64,7 @@ program #[test] fn test_query_match() { let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), vec![]); - let ast = runner.run("x = 1"); + let ast = runner.run("x = 1").unwrap(); let query = yeast::query!( (program @@ -85,7 +85,7 @@ fn test_query_match() { #[test] fn test_query_no_match() { let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), vec![]); - let ast = runner.run("x = 1"); + let ast = runner.run("x = 1").unwrap(); let query = yeast::query!( (program @@ -103,7 +103,7 @@ fn test_query_no_match() { #[test] fn test_query_repeated_capture() { let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), vec![]); - let ast = runner.run("x, y, z = 1"); + let ast = runner.run("x, y, z = 1").unwrap(); let query = yeast::query!( (assignment @@ -129,7 +129,7 @@ fn test_query_repeated_capture() { #[test] fn test_tree_builder() { let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), vec![]); - let mut ast = runner.run("x = 1"); + let mut ast = runner.run("x = 1").unwrap(); let input = "x = 1"; let query = yeast::query!( @@ -286,7 +286,7 @@ program #[test] fn test_cursor_navigation() { let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), vec![]); - let ast = runner.run("x = 1"); + let ast = runner.run("x = 1").unwrap(); let mut cursor = AstCursor::new(&ast); // Start at root