Skip to main content

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}