hyeong 0.1.0-beta

Hyeo-ung Programming Language Compiler
Documentation
use std::io::Write;
use std::process;

use crate::code::Code;
use crate::io::ReadLine;
use crate::number::Num;
use crate::{code, io};

pub fn push_stack_wrap<T>(
    out: &mut impl Write,
    err: &mut impl Write,
    state: &mut T,
    idx: usize,
    num: Num,
) where
    T: code::State,
{
    match idx {
        1 => {
            if num.is_pos() {
                io::write(out, &*format!("{}", num.floor().to_int() as u8 as char));
            } else {
                io::write(out, &*format!("{}", -&num));
            }
        }
        2 => {
            if num.is_pos() {
                io::write(err, &*format!("{}", num.floor().to_int() as u8 as char));
            } else {
                io::write(err, &*format!("{}", -&num));
            }
        }
        _ => {
            state.push_stack(idx, num);
        }
    }
}

pub fn pop_stack_wrap<T>(
    ipt: &mut impl ReadLine,
    out: &mut impl Write,
    err: &mut impl Write,
    state: &mut T,
    idx: usize,
) -> Num
where
    T: code::State,
{
    match idx {
        0 => {
            if state.get_stack(0).is_empty() {
                let s = io::read_line_from(ipt);
                for c in s.chars().rev() {
                    state.push_stack(0, Num::from_num(c as isize));
                }
            }
            state.pop_stack(0)
        }
        1 => {
            out.flush().unwrap();
            err.flush().unwrap();
            process::exit(0);
        }
        2 => {
            out.flush().unwrap();
            err.flush().unwrap();
            process::exit(1);
        }
        _ => state.pop_stack(idx),
    }
}

pub fn execute_one<T>(
    ipt: &mut impl ReadLine,
    out: &mut impl Write,
    err: &mut impl Write,
    mut state: T,
    cur_loc: usize,
) -> (T, usize)
where
    T: code::State,
{
    let code = (*state.get_code(cur_loc)).clone();
    let mut cur_stack = state.current_stack();

    match code.get_type() {
        0 => {
            push_stack_wrap(
                out,
                err,
                &mut state,
                cur_stack,
                &Num::from_num(code.get_hangul_count() as isize)
                    * &Num::from_num(code.get_dot_count() as isize),
            );
        }
        1 => {
            let mut n = Num::zero();
            for _ in 0..code.get_hangul_count() {
                n += &pop_stack_wrap(ipt, out, err, &mut state, cur_stack);
            }
            push_stack_wrap(out, err, &mut state, code.get_dot_count(), n);
        }
        2 => {
            let mut n = Num::one();
            for _ in 0..code.get_hangul_count() {
                n *= &pop_stack_wrap(ipt, out, err, &mut state, cur_stack);
            }
            push_stack_wrap(out, err, &mut state, code.get_dot_count(), n);
        }
        3 => {
            let mut n = Num::zero();
            let mut v = Vec::with_capacity(code.get_hangul_count());

            for _ in 0..code.get_hangul_count() {
                v.push(pop_stack_wrap(ipt, out, err, &mut state, cur_stack));
            }

            for mut x in v {
                x.minus();
                n += &x;
                push_stack_wrap(out, err, &mut state, cur_stack, x);
            }

            push_stack_wrap(out, err, &mut state, code.get_dot_count(), n);
        }
        4 => {
            let mut n = Num::one();
            let mut v = Vec::with_capacity(code.get_hangul_count());

            for _ in 0..code.get_hangul_count() {
                v.push(pop_stack_wrap(ipt, out, err, &mut state, cur_stack));
            }

            for mut x in v {
                x.flip();
                n *= &x;
                push_stack_wrap(out, err, &mut state, cur_stack, x);
            }

            push_stack_wrap(out, err, &mut state, code.get_dot_count(), n);
        }
        // 5
        _ => {
            let n = pop_stack_wrap(ipt, out, err, &mut state, cur_stack);
            for _ in 0..code.get_hangul_count() {
                push_stack_wrap(out, err, &mut state, code.get_dot_count(), n.clone());
            }
            push_stack_wrap(out, err, &mut state, cur_stack, n);
            state.set_current_stack(code.get_dot_count());
        }
    }

    cur_stack = state.current_stack();
    let area_type = code::calc(code.get_area(), code.get_area_count(), || {
        Option::Some(pop_stack_wrap(ipt, out, err, &mut state, cur_stack))
    })
    .unwrap();

    if area_type != 0 {
        if area_type != 13 {
            let id = ((code.get_area_count() as u128) << 4) + area_type as u128;
            match state.get_point(id) {
                Some(value) => {
                    if cur_loc != value {
                        state.set_latest_loc(cur_loc);
                        return (state, value);
                    }
                }
                None => state.set_point(id, cur_loc),
            }
        } else {
            if let Some(loc) = state.get_latest_loc() {
                return (state, loc);
            }
        }
    }

    (state, cur_loc + 1)
}

pub fn execute<T>(
    ipt: &mut impl ReadLine,
    out: &mut impl Write,
    err: &mut impl Write,
    mut state: T,
    code: &T::CodeType,
) -> T
where
    T: code::State,
{
    let mut cur_loc = state.push_code((*code).clone());
    let length = cur_loc + 1;

    while cur_loc < length {
        let (new_state, new_loc) = execute_one(ipt, out, err, state, cur_loc);
        state = new_state;
        cur_loc = new_loc;
    }

    state
}