romulus/
interpreter.rs

1use crate::runtime::op::{Operation, ScopePersister, SigStatement};
2use crate::runtime::{Environment, Event, Scope};
3use crate::{ast, lex, lint};
4
5use regex::Regex;
6use std::fs::File;
7use std::io::{BufRead, Read, Write};
8
9/// The interpreter which processes lines with a romulus program
10pub struct Interpreter {
11    node: ast::Seq,
12    sep: Regex,
13    implicit_print: bool,
14}
15
16/// Builds an interpreter
17pub struct Builder {
18    filename: Option<String>,
19    expression: Option<String>,
20    sep: Option<Regex>,
21    print: Option<bool>,
22}
23
24impl Interpreter {
25    /// Process an input stream and writes the results for it's romulus program to
26    /// the output stream
27    pub fn process<R: BufRead, W: Write>(&self, sin: &mut R, sout: &mut W) {
28        let mut iter = sin.lines();
29        let mut env = Environment::new(sout, &self.node, self.sep.clone());
30
31        if cfg!(feature = "envvar") {
32            env.push(Scope::env());
33        }
34
35        let implicit_print = !self.node.significant();
36
37        env.event = Event::Begin;
38        self.node.perform(&mut env);
39
40        while let Some(Ok(line)) = iter.next() {
41            env.lineno += 1;
42            env.event = Event::Line(line);
43
44            self.node.persist_scope(&mut env);
45            self.node.perform(&mut env);
46
47            if env.finished() {
48                return;
49            }
50
51            if implicit_print && self.implicit_print {
52                env.print_event();
53            }
54        }
55
56        env.event = Event::End;
57        self.node.perform(&mut env);
58    }
59
60    /// Lint the current program
61    pub fn lint(&self) -> Vec<lint::LintMessage> {
62        lint::lint(&self.node)
63    }
64
65    /// Create a new interpreter builder
66    pub fn builder() -> Builder {
67        Builder {
68            filename: None,
69            expression: None,
70            sep: None,
71            print: None,
72        }
73    }
74}
75
76impl Builder {
77    /// Sets a filename to be read
78    pub fn filename(&mut self, filename: String) -> &mut Self {
79        self.filename = Some(filename);
80        self
81    }
82
83    /// Sets an expression
84    pub fn expression(&mut self, expression: String) -> &mut Self {
85        self.expression = Some(expression);
86        self
87    }
88
89    /// sets the seperator
90    pub fn sep(&mut self, sep: Regex) -> &mut Self {
91        self.sep = Some(sep);
92        self
93    }
94
95    /// sets the implicit printing
96    pub fn print(&mut self, print: bool) -> &mut Self {
97        self.print = Some(print);
98        self
99    }
100
101    /// Builds the interpreter
102    pub fn build(&mut self) -> Result<Interpreter, String> {
103        let node = match (&self.filename, &self.expression) {
104            (None, None) => return Err(String::from("Neither an expression or a file was given")),
105            (Some(_), Some(_)) => {
106                return Err(String::from(
107                    "Both expression and file should not be given at the same time",
108                ))
109            }
110
111            (Some(ref file), None) => {
112                let mut file = match File::open(file) {
113                    Ok(f) => f,
114                    Err(err) => {
115                        return Err(format!(
116                            "unable to open file romulus file '{}': {}",
117                            file, err
118                        ))
119                    }
120                };
121
122                let mut buf = String::new();
123                if let Err(err) = file.read_to_string(&mut buf) {
124                    return Err(format!("unable to read romulus file: {}", err));
125                }
126
127                let tokens = lex::lex(buf.as_ref())?;
128                ast::parse(tokens)?
129            }
130            (None, Some(expr)) => {
131                let tokens = lex::lex(expr.as_ref())?;
132                ast::parse(tokens)?
133            }
134        };
135
136        let sep = self
137            .sep
138            .clone()
139            .unwrap_or_else(|| Regex::new(" +").unwrap());
140
141        let implicit_print = self.print.unwrap_or(true);
142
143        Ok(Interpreter {
144            node,
145            sep,
146            implicit_print,
147        })
148    }
149}