Skip to main content

rl_lang/repl/
depth_checker.rs

1//! Determines whether a multiline input block is complete and ready to evaluate.
2use crate::{
3    lexer::{tokenizer::Tokenizer, tokentypes::TokenType},
4    utils::source::SourceFile,
5};
6
7/// Returns `true` if `input` is a syntactically complete expression or statement.
8///
9/// Lexes `input` and counts bracket/brace/paren depth. The input is considered
10/// incomplete (returns `false`) when:
11/// - any parentheses or brackets are unclosed
12/// - braces are unclosed and the input does not end with `{` (a block opener)
13///
14/// On lex error, returns `true` so the evaluator can surface the error to the user.
15pub fn is_complete(input: &str) -> bool {
16    let source = SourceFile::new("<check>", input.to_string());
17    let tokens = match Tokenizer::lex(source) {
18        Ok(t) => t,
19        Err(_) => return true,
20    };
21    let mut brace_depth: i32 = 0;
22    let mut paren_depth: i32 = 0;
23    let mut bracket_depth: i32 = 0;
24    for tok in &tokens {
25        match tok.token {
26            TokenType::LeftBrace => brace_depth += 1,
27            TokenType::RightBrace => brace_depth -= 1,
28            TokenType::LeftParen => paren_depth += 1,
29            TokenType::RightParen => paren_depth -= 1,
30            TokenType::LeftBracket => bracket_depth += 1,
31            TokenType::RightBracket => bracket_depth -= 1,
32            _ => {}
33        }
34    }
35
36    if paren_depth > 0 || bracket_depth > 0 {
37        return false;
38    }
39
40    if brace_depth > 0 {
41        return input.trim_end().ends_with('{');
42    }
43    true
44}