airlang_bin 0.0.8

The Air Programming Language
use {
    crate::repl::{
        cmd::repl::title,
        eval::{
            ConstCtx,
            DynCtx,
            Output,
        },
        ui::Ui,
    },
    airlang::semantics::{
        parse,
        Interpreter,
        Val,
    },
};

pub(crate) fn repl(ui: &mut impl Ui) -> std::io::Result<()> {
    let const_ctx = cmd::const_ctx();
    let mut dyn_ctx = dyn_ctx();
    let mut input_buffer = String::new();

    print_title(ui, &const_ctx, &mut dyn_ctx)?;

    loop {
        ui.print(PROMPT_PREFIX)?;

        let len = input_buffer.len();
        ui.read_line(&mut input_buffer)?;

        let input = input_buffer.trim();
        if input.is_empty() {
            input_buffer.clear();
            continue;
        }

        if input == "((" {
            dyn_ctx.multiline_mode = true;
        } else {
            let newline = input_buffer[len..].trim();
            if newline == "))" {
                dyn_ctx.multiline_mode = false;
            }
        }
        if dyn_ctx.multiline_mode {
            continue;
        }

        match eval(&const_ctx, &mut dyn_ctx, input) {
            Output::Ok(output) => {
                ui.println(&output)?;
            }
            Output::Err(error) => {
                ui.eprintln(&*error)?;
            }
            Output::Break => break,
        }
        input_buffer.clear();
    }
    Ok(())
}

pub(crate) fn dyn_ctx() -> DynCtx {
    DynCtx {
        interpreter: Interpreter::new(),
        meta_interpreter: Interpreter::new(),
        multiline_mode: false,
    }
}

fn eval(const_ctx: &ConstCtx, dyn_ctx: &mut DynCtx, input: &str) -> Output {
    match parse(input) {
        Ok(input) => const_ctx.eval(dyn_ctx, input),
        Err(err) => Output::Err(Box::new(err)),
    }
}

fn print_title(
    ui: &mut impl Ui,
    const_ctx: &ConstCtx,
    dyn_ctx: &mut DynCtx,
) -> std::io::Result<()> {
    match title(const_ctx, dyn_ctx, Val::default()) {
        Output::Ok(output) => {
            ui.println(&output)?;
        }
        Output::Err(error) => {
            ui.eprintln(&*error)?;
        }
        _ => {}
    }
    Ok(())
}

const PROMPT_PREFIX: &str = "> ";

pub(crate) mod cmd;

pub(crate) mod eval;

pub(crate) mod ui;