pub fn parse(source: &str, extglob: bool) -> Result<Vec<Node>>Expand description
Parses a bash source string into a list of top-level AST nodes.
Each top-level command separated by newlines becomes a separate node.
Commands separated by ; on the same line are grouped into a single
NodeKind::List.
Set extglob to true to enable extended glob patterns (@(), ?(),
*(), +(), !()).
§Examples
let nodes = rable::parse("echo hello", false).unwrap();
assert_eq!(nodes[0].to_string(), "(command (word \"echo\") (word \"hello\"))");// Multiple top-level commands
let nodes = rable::parse("echo a\necho b", false).unwrap();
assert_eq!(nodes.len(), 2);§Errors
Returns RableError::Parse for syntax errors and
RableError::MatchedPair for unclosed delimiters.
Examples found in repository?
examples/basic.rs (line 12)
9fn main() {
10 // Parse a simple pipeline
11 let source = "echo $USER | grep root";
12 let nodes = parse(source, false).expect("valid bash");
13
14 println!("Source: {source}");
15 println!("S-expression: {}", nodes[0]);
16 println!();
17
18 // Inspect the AST
19 if let NodeKind::Pipeline { commands, .. } = &nodes[0].kind {
20 println!("Pipeline with {} commands:", commands.len());
21 for (i, cmd) in commands.iter().enumerate() {
22 if let NodeKind::Command {
23 words, redirects, ..
24 } = &cmd.kind
25 {
26 let word_values: Vec<_> = words
27 .iter()
28 .filter_map(|w| {
29 if let NodeKind::Word { value, .. } = &w.kind {
30 Some(value.as_str())
31 } else {
32 None
33 }
34 })
35 .collect();
36 println!(
37 " Command {}: {:?} ({} redirects)",
38 i,
39 word_values,
40 redirects.len()
41 );
42 }
43 }
44 }
45
46 println!();
47
48 // Parse a compound command
49 let source = r#"if [ -f /etc/passwd ]; then echo "exists"; fi"#;
50 let nodes = parse(source, false).expect("valid bash");
51 println!("Source: {source}");
52 println!("S-expression: {}", nodes[0]);
53 println!();
54
55 // Error handling
56 match parse("if", false) {
57 Ok(_) => println!("Unexpectedly parsed"),
58 Err(e) => {
59 println!(
60 "Parse error at line {}, pos {}: {}",
61 e.line(),
62 e.pos(),
63 e.message()
64 );
65 }
66 }
67}