rawk_core/awk.rs
1use crate::{Evaluator, Lexer, ParseError, Parser, Program};
2
3/// High-level wrapper for compiling and running an AWK script.
4///
5/// This type parses the script once and can be run with different input.
6///
7/// # Example
8/// ```
9/// use rawk_core::awk::Awk;
10///
11/// let awk = Awk::new("{ print }").unwrap();
12/// let output = awk.run(vec!["hello world".into()], None);
13/// assert_eq!(output, vec!["hello world".to_string()]);
14/// ```
15pub struct Awk {
16 program: Program<'static>,
17}
18
19impl Awk {
20 /// Parse an AWK script into an executable program.
21 ///
22 /// The script is stored with a static lifetime to keep the AST valid.
23 /// Returns a parse error if the script is not valid AWK according to this parser.
24 pub fn new(script: impl Into<String>) -> Result<Self, ParseError<'static>> {
25 let script: String = script.into();
26 let script: &'static str = Box::leak(script.into_boxed_str());
27
28 let lexer = Lexer::new(script);
29 let parser: &'static mut Parser<'static> = Box::leak(Box::new(Parser::new(lexer)));
30 let program = parser.try_parse_program()?;
31
32 Ok(Self { program })
33 }
34
35 /// Execute the compiled program against the given input lines.
36 ///
37 /// When `filename` is `None`, `FILENAME` defaults to `"-"`.
38 pub fn run(&self, input: Vec<String>, filename: Option<String>) -> Vec<String> {
39 let filename = filename.unwrap_or_else(|| "-".to_string());
40 let mut evaluator = Evaluator::new(self.program.clone(), input, filename);
41
42 evaluator.eval()
43 }
44}