Skip to main content

rl_lang/repl/
input_eval.rs

1//! Evaluates a complete input string and appends results to the output buffer.
2use crate::{
3    interpreter::evaluator::Evaluator,
4    lexer::tokenizer::Tokenizer,
5    parser::parser_logic::Parser,
6    repl::{lines_types::OutputLine, syntax_highlighting::highlight},
7    utils::source::SourceFile,
8};
9
10/// Lexes, parses, and evaluates `input`, appending results to `output`.
11///
12/// Expression statements have their return value rendered directly with syntax
13/// highlighting (unless the value is `null`). Non-expression statements
14/// (declarations, loops, etc.) are evaluated for their side effects only.
15///
16/// Any `println` / `print` output captured in [`Evaluator::output_buffer`]
17/// is flushed into `output` as [`OutputLine::Result`] lines after evaluation.
18///
19/// Returns `true` if all statements evaluated without error.
20pub fn eval_input(input: &str, evaluator: &mut Evaluator, output: &mut Vec<OutputLine>) -> bool {
21    let source = SourceFile::new("<repl>", input.to_string());
22
23    let tokens = match Tokenizer::lex(source.clone()) {
24        Ok(t) => t,
25        Err(e) => {
26            output.push(OutputLine::Error(format!("error: {}", e.message())));
27            return false;
28        }
29    };
30
31    let (_file_ast, statements) = match Parser::parse(tokens, source.clone()) {
32        Ok(s) => s,
33        Err(e) => {
34            output.push(OutputLine::Error(format!("error: {}", e.message())));
35            return false;
36        }
37    };
38
39    evaluator.set_source_file(source);
40    evaluator.output_buffer = Some(String::new());
41
42    let mut success = true;
43
44    for statement in &statements {
45        if let crate::ast::statements::StatementKind::Expression(expr) = &statement.kind {
46            match evaluator.evaluate(*expr) {
47                Ok(val) => {
48                    if !matches!(val, crate::interpreter::values::Value::Null) {
49                        let val_str = format!("{}", val);
50                        let spans = highlight(&val_str);
51                        output.push(OutputLine::Styled(
52                            spans
53                                .into_iter()
54                                .map(|sp| (sp.content.into_owned(), sp.style))
55                                .collect(),
56                        ));
57                    }
58                }
59                Err(e) => {
60                    output.push(OutputLine::Error(format!("error: {}", e.message())));
61                    success = false;
62                    break;
63                }
64            }
65        } else if let Err(e) = evaluator.evaluate_statement(statement) {
66            output.push(OutputLine::Error(format!("error: {}", e.message())));
67            success = false;
68            break;
69        }
70    }
71
72    if let Some(captured) = evaluator.output_buffer.take() {
73        for line in captured.split('\n') {
74            if !line.is_empty() {
75                output.push(OutputLine::Result(line.to_string()));
76            }
77        }
78    }
79
80    success
81}