use std::collections::HashMap;
use purua::{parser::ast::*, TokenType};
use super::lunarir::*;
#[derive(Debug)]
pub struct Walker {
pub msg_stack: Vec<LunarIR>,
pub idx_of_irep: usize,
pub current_irep: usize,
pub idx_of_ireps: HashMap<usize, IrepIndices>,
}
#[derive(Debug, Clone)]
pub struct IrepIndices {
pub locals: usize,
pub syms: usize,
pub pool: usize,
}
impl Walker {
pub fn new() -> Self {
Walker {
msg_stack: Vec::new(),
idx_of_irep: 0,
current_irep: 0,
idx_of_ireps: HashMap::from([(
0,
IrepIndices {
locals: 0,
syms: 0,
pool: 0,
},
)]),
}
}
pub fn push_msg(&mut self, msg: LunarIR) {
self.msg_stack.push(msg);
}
pub fn walk(&mut self, root: &Block) {
self.walk_block(root);
}
pub fn walk_block(&mut self, block: &Block) {
let chunk = &block.0;
self.walk_chunk(chunk);
}
pub fn walk_chunk(&mut self, chunk: &Chunk) {
self.push_msg(LunarIR::ChunkStart(self.idx_of_irep));
let before_irep = self.current_irep;
self.current_irep = self.idx_of_irep;
self.idx_of_irep += 1;
self.idx_of_ireps.insert(
self.idx_of_irep,
IrepIndices {
locals: 0,
syms: 0,
pool: 0,
},
);
if self.current_irep != 0 {
self.push_msg(LunarIR::Enter(0x40000));
self.idx_of_ireps.get_mut(&self.current_irep).unwrap().locals += 1;
}
let statements = &chunk.0;
for statement in statements {
self.walk_stat(statement);
}
if let Some(last_stat) = &chunk.1 {
self.walk_laststat(last_stat);
} else {
self.push_msg(LunarIR::NoReturn);
}
if self.current_irep == 0 {
self.push_msg(LunarIR::Stop);
} else {
self.current_irep = before_irep;
}
self.push_msg(LunarIR::ChunkEnd);
}
pub fn walk_stat(&mut self, stat: &Stat) {
match stat {
Stat::FunctionCall(function_call) => {
let func_name = &function_call.0;
let args = &function_call.2;
self.walk_prefixexpr(func_name);
self.push_msg(LunarIR::FunctionCallStart(
self.idx_of_ireps[&self.current_irep].syms - 1,
));
self.walk_args(args);
self.push_msg(LunarIR::FunctionCallEnd);
},
Stat::For(_token, expr, expr1, expr2, block) => {
let begin = self.ensure_expr_as_number(expr) as usize;
let end = self.ensure_expr_as_number(expr1) as usize;
let step = match expr2 {
Some(expr) => self.ensure_expr_as_number(expr),
None => 1.0,
} as usize;
self.push_msg(LunarIR::StoreSym(
self.idx_of_ireps[&self.current_irep].syms,
"each".to_string(),
));
self.push_msg(LunarIR::ForStart(self.idx_of_ireps[&self.current_irep].syms));
self.idx_of_ireps.get_mut(&self.current_irep).unwrap().syms += 1;
self.push_msg(LunarIR::ForParam(
begin,
end,
step,
));
self.push_msg(LunarIR::Block(self.idx_of_irep - 1));
self.walk_block(block);
self.push_msg(LunarIR::ForEnd);
},
_ => {
panic!("Unsupported statement: {:?}", stat);
}
}
}
pub fn walk_args(&mut self, args: &Args) {
match args {
Args::ArgsString(string) => {
self.push_msg(LunarIR::PoolString(
self.idx_of_ireps[&self.current_irep].pool,
string.to_owned(),
));
self.push_msg(LunarIR::FunctionCallArg(
0,
LunarValue::String(self.idx_of_ireps[&self.current_irep].pool),
));
self.idx_of_ireps.get_mut(&self.current_irep).unwrap().pool += 1;
},
_ => {
panic!("Unsupported argument: {:?}", args);
}
}
}
pub fn ensure_expr_as_number(&mut self, expr: &Expr) -> f64 {
match expr {
Expr::Number(f) => *f,
_ => {
panic!("Unsupported expression: {:?}", expr);
}
}
}
pub fn walk_prefixexpr(&mut self, prefix_expr: &PrefixExp) {
match prefix_expr {
PrefixExp::PrefixVar(var) => {
let var = var.as_ref();
self.walk_var(var);
},
_ => {
panic!("Unsupported prefix expression: {:?}", prefix_expr);
}
}
}
pub fn walk_var(&mut self, var: &Var) {
match var {
Var::VarName(name) => {
let name = match name.token_type {
TokenType::Name => {
name.lexeme.clone()
},
_ => {
panic!("Unsupported variable name: {:?}", name);
}
};
self.push_msg(LunarIR::StoreSym(
self.idx_of_ireps[&self.current_irep].syms,
name.clone().try_into().unwrap(),
));
self.idx_of_ireps.get_mut(&self.current_irep).unwrap().syms += 1;
},
_ => {
panic!("Unsupported variable: {:?}", var);
}
}
}
pub fn walk_laststat(&mut self, last_stat: &LastStat) {
match last_stat {
LastStat::Return(_ret) => todo!(),
LastStat::Break => todo!(),
}
}
}