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
9pub struct Interpreter {
11 node: ast::Seq,
12 sep: Regex,
13 implicit_print: bool,
14}
15
16pub struct Builder {
18 filename: Option<String>,
19 expression: Option<String>,
20 sep: Option<Regex>,
21 print: Option<bool>,
22}
23
24impl Interpreter {
25 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 pub fn lint(&self) -> Vec<lint::LintMessage> {
62 lint::lint(&self.node)
63 }
64
65 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 pub fn filename(&mut self, filename: String) -> &mut Self {
79 self.filename = Some(filename);
80 self
81 }
82
83 pub fn expression(&mut self, expression: String) -> &mut Self {
85 self.expression = Some(expression);
86 self
87 }
88
89 pub fn sep(&mut self, sep: Regex) -> &mut Self {
91 self.sep = Some(sep);
92 self
93 }
94
95 pub fn print(&mut self, print: bool) -> &mut Self {
97 self.print = Some(print);
98 self
99 }
100
101 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}