Skip to main content

rl_lang/
logic_loops.rs

1//! Pipeline driver functions.
2//!
3//! Thin wrappers around each pipeline stage that handle errors uniformly:
4//! print to stderr and exit with code 1. Used by both `main.rs` and any
5//! other binary entry points that need to run the full pipeline without
6//! boilerplate error handling at the call site.
7//!
8//! | Function | Stage |
9//! |---|---|
10//! | [`lexing_loop`] | source -> [`Vec<Token>`] |
11//! | [`parsing_loop`] | tokens -> [`Vec<Statement>`] |
12//! | [`eval_loop`] | statements -> execution (`eval` feature only) |
13//!
14//! [`Vec<Token>`]: crate::lexer::tokentypes::Token
15//! [`Vec<Statement>`]: crate::ast::statements::Statement
16#[cfg(feature = "debug")]
17use log::info;
18
19use crate::ast::Ast;
20
21#[cfg(feature = "eval")]
22use super::interpreter::evaluator::Evaluator;
23
24use super::{
25    ast::statements::Statement,
26    lexer::{tokenizer::Tokenizer, tokentypes::Token},
27    parser::parser_logic::Parser,
28    utils::source::SourceFile,
29};
30
31/// Lexes `source` into a token stream, or prints the error and exits.
32pub fn lexing_loop(source: SourceFile) -> Vec<Token> {
33    #[cfg(feature = "debug")]
34    info!("lexing the source file...");
35    match Tokenizer::lex(source.clone()) {
36        Ok(t) => t,
37        Err(e) => {
38            e.report_to_stderr();
39            std::process::exit(1);
40        }
41    }
42}
43
44/// Parses `tokens` into an AST statement list, or prints the error and exits.
45pub fn parsing_loop(source: SourceFile, tokens: Vec<Token>) -> (Ast, Vec<Statement>) {
46    #[cfg(feature = "debug")]
47    info!("parsing the tokens into ast tree...");
48    match Parser::parse(tokens, source.clone()) {
49        Ok(s) => s,
50        Err(e) => {
51            e.report_to_stderr();
52            std::process::exit(1);
53        }
54    }
55}
56
57/// Resolves and evaluates `statements`, or prints the error and exits.
58///
59/// Only available with the `eval` feature. Constructs a fresh [`Evaluator`]
60/// with the stdlib loaded, runs the [`Resolver`] pass, then evaluates the program.
61///
62/// [`Resolver`]: crate::resolver
63#[cfg(feature = "eval")]
64pub fn eval_loop(
65    source: SourceFile,
66    ast: Ast,
67    statements: Vec<Statement>,
68    user_args_offset: usize,
69) {
70    #[cfg(feature = "debug")]
71    info!("evaluating the ast tree...");
72    let mut evaluator = Evaluator::default()
73        .with_stdlib()
74        .with_source_file(source.clone())
75        .with_user_args_offset(user_args_offset);
76
77    evaluator.resolver.current_dir = std::path::Path::new(source.name.as_ref())
78        .parent()
79        .unwrap_or(std::path::Path::new(""))
80        .to_path_buf();
81
82    let statements = evaluator.resolver.resolve_program(ast, statements);
83    if let Err(e) = evaluator.evaluate_program(&statements) {
84        e.report_to_stderr();
85        std::process::exit(1);
86    }
87
88    #[cfg(feature = "debug")]
89    info!("evaluation done");
90}