hyeong 0.1.0-beta

Hyeo-ung Programming Language Compiler
Documentation
use crate::code::{State, UnOptCode};
use crate::{code, execute, io};
use colored::Colorize;
use std::collections::HashSet;
use std::io::{stdin, stdout, Write};
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

pub fn run(code: Vec<UnOptCode>, from: usize) -> ! {
    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    let mut state = code::UnOptState::new();

    ctrlc::set_handler(move || {
        if r.load(Ordering::SeqCst) {
            r.store(false, Ordering::SeqCst);
            print!("\ntype \"exit\" to exit\n");
            print!("{} ", ">".bright_red());
            io::handle_error(stdout().flush());
            r.store(true, Ordering::SeqCst);
        }
    })
    .expect("Error setting Ctrl-C handler");

    io::print_log("running in debug mode");

    for c in &code {
        state.push_code(c.clone());
    }

    let mut is_running = false;
    let mut break_points = HashSet::new();
    break_points.insert(from);

    let mut out = io::CustomWriter::new(|x| {
        if !x.is_empty() {
            println!("[{}] {}", "stdout".bold(), x);
        }

        Result::Ok(())
    });

    let mut err = io::CustomWriter::new(|x| {
        if !x.is_empty() {
            println!("[{}] {}", "stderr".bold().bright_red(), x);
        }

        Result::Ok(())
    });

    let mut state_stack = vec![(state, 0)];

    while state_stack.last().unwrap().1 < code.len() {
        if is_running {
            if break_points.contains(&state_stack.last().unwrap().1) {
                out.flush().unwrap();
                err.flush().unwrap();
                is_running = false;
            } else {
                state_stack.push(execute::execute_one(
                    &mut stdin(),
                    &mut out,
                    &mut err,
                    state_stack.last().unwrap().0.clone(),
                    state_stack.last().unwrap().1,
                ));
            }
        } else {
            loop {
                print!("{} ", ">".bright_red());
                io::handle_error(stdout().flush());
                running.store(true, Ordering::SeqCst);
                let input = io::read_line();
                running.store(false, Ordering::SeqCst);

                if input == "" {
                    process::exit(0);
                }

                let parsed = input.trim().split(" ").collect::<Vec<_>>();

                match parsed[0] {
                    "next" | "n" => {
                        let c = &code[state_stack.last().unwrap().1];

                        println!(
                            "{}:{}|{} {}",
                            c.get_location().0,
                            c.get_location().1,
                            state_stack.last().unwrap().1,
                            c.get_raw().bright_blue()
                        );

                        state_stack.push(execute::execute_one(
                            &mut stdin(),
                            &mut out,
                            &mut err,
                            state_stack.last().unwrap().0.clone(),
                            state_stack.last().unwrap().1,
                        ));

                        out.flush().unwrap();
                        err.flush().unwrap();

                        break;
                    }

                    "previous" | "p" => {
                        if state_stack.len() > 1 {
                            state_stack.pop();
                            io::print_log("moved back");
                        } else {
                            io::print_error_str_no_exit("cannot go back");
                        }
                    }

                    "run" | "r" => {
                        state_stack.push(execute::execute_one(
                            &mut stdin(),
                            &mut out,
                            &mut err,
                            state_stack.last().unwrap().0.clone(),
                            state_stack.last().unwrap().1,
                        ));

                        is_running = true;
                        break;
                    }

                    "state" | "s" => {
                        print!("{:?}", state_stack.last().unwrap().0);
                    }

                    "break" | "b" => {
                        if parsed.len() < 2 {
                            let mut v = break_points.iter().collect::<Vec<_>>();
                            v.sort();
                            for i in v {
                                println!("{}: {}", i, code[*i].get_raw());
                            }
                            continue;
                        }
                        let num = match parsed[1].parse::<usize>() {
                            Ok(t) => t,
                            Err(e) => {
                                io::print_error_no_exit(e);
                                continue;
                            }
                        };
                        if num > code.len() {
                            io::print_error_str_no_exit("number exceeds the range");
                            continue;
                        }

                        if !break_points.contains(&num) {
                            break_points.insert(num);
                            io::print_log(&*format!("set breakpoint on line {}", num));
                        } else {
                            break_points.remove(&num);
                            io::print_log(&*format!("unset breakpoint on line {}", num));
                        }
                    }

                    "help" | "h" => {
                        println!("break(b)       show breakpoints");
                        println!("break(b) NUM   set/unset breakpoint on NUM");
                        println!("exit           Exit debugger");
                        println!("help(h)        Print this");
                        println!("next(n)        goto next command");
                        println!("state(s)       print state status");
                        println!("previous(p)    move to previous state");
                        println!("run(r)         run until breakpoint");
                        continue;
                    }

                    "exit" => {
                        process::exit(0);
                    }

                    "" => {
                        continue;
                    }

                    t => {
                        println!("command \"{}\" not found", t);
                    }
                }
            }
        }
    }

    out.flush().unwrap();
    err.flush().unwrap();

    process::exit(0);
}