263 lines
12 KiB
Rust
263 lines
12 KiB
Rust
use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType}, Args, lerror, warn};
|
|
use color_eyre::Result;
|
|
use eyre::eyre;
|
|
|
|
|
|
pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
|
|
if args.unsaf {
|
|
if !args.quiet {
|
|
warn!("Unsafe mode enabled, disabling typechecker, goodluck");
|
|
}
|
|
return Ok(ops.to_vec());
|
|
}
|
|
|
|
let mut stack: Vec<Types> = Vec::new();
|
|
|
|
for op in ops {
|
|
match op.typ.clone() {
|
|
OpType::Keyword(keyword) => {
|
|
match keyword {
|
|
KeywordType::If => {
|
|
stack_pop(&mut stack, &op, &[Types::Bool])?;
|
|
},
|
|
KeywordType::Do => {
|
|
stack_pop(&mut stack, &op, &[Types::Bool])?;
|
|
},
|
|
|
|
KeywordType::Else |
|
|
KeywordType::End |
|
|
KeywordType::While |
|
|
KeywordType::Macro |
|
|
KeywordType::Include |
|
|
KeywordType::Memory => (),
|
|
}
|
|
},
|
|
OpType::Instruction(instruction) => {
|
|
match instruction {
|
|
InstructionType::PushInt => {
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::PushStr => {
|
|
stack.push(Types::Int);
|
|
stack.push(Types::Ptr);
|
|
|
|
},
|
|
InstructionType::Drop => {
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
},
|
|
InstructionType::Print => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
},
|
|
InstructionType::Dup => {
|
|
let a = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(a);
|
|
},
|
|
InstructionType::Rot => {
|
|
let a = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
let b = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
let c = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(b);
|
|
stack.push(a);
|
|
stack.push(c);
|
|
},
|
|
InstructionType::Over => {
|
|
let a = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
let b = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(b.clone());
|
|
stack.push(a);
|
|
stack.push(b);
|
|
},
|
|
InstructionType::Swap => {
|
|
let a = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
let b = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(a);
|
|
stack.push(b);
|
|
},
|
|
InstructionType::Minus => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Plus => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Equals => {
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack.push(Types::Bool);
|
|
},
|
|
InstructionType::Gt => {
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack.push(Types::Bool);
|
|
},
|
|
InstructionType::Lt => {
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack.push(Types::Bool);
|
|
},
|
|
InstructionType::Ge => {
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack.push(Types::Bool);
|
|
},
|
|
InstructionType::Le => {
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack.push(Types::Bool);
|
|
},
|
|
InstructionType::NotEquals => {
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
|
|
stack.push(Types::Bool);
|
|
},
|
|
InstructionType::Band => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Bor => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Shr => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Shl => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::DivMod => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack.push(Types::Int);
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Mul => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Mem => {
|
|
stack.push(Types::Ptr);
|
|
},
|
|
InstructionType::Load8 => {
|
|
stack_pop(&mut stack, &op, &[Types::Ptr])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Store8 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Ptr])?;
|
|
},
|
|
InstructionType::Load32 => {
|
|
stack_pop(&mut stack, &op, &[Types::Ptr])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Store32 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Ptr])?;
|
|
},
|
|
InstructionType::Load64 => {
|
|
stack_pop(&mut stack, &op, &[Types::Ptr])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Store64 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Ptr])?;
|
|
},
|
|
InstructionType::Syscall0 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Syscall1 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Syscall2 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Syscall3 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Syscall4 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Syscall5 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::Syscall6 => {
|
|
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::CastBool => {
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Bool);
|
|
},
|
|
InstructionType::CastPtr => {
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Ptr);
|
|
},
|
|
InstructionType::CastInt => {
|
|
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
stack.push(Types::Int);
|
|
},
|
|
InstructionType::MemUse => {
|
|
stack.push(Types::Ptr);
|
|
},
|
|
InstructionType::None => {},
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
Ok(ops.to_vec())
|
|
}
|
|
|
|
|
|
|
|
fn stack_pop(v: &mut Vec<Types>, op: &Operator, t: &[Types]) -> Result<Types> {
|
|
if v.is_empty() {
|
|
lerror!(&op.loc, "Expected {:?}, but got nothing", t);
|
|
return Err(eyre!(""));
|
|
}
|
|
let r = v.pop().unwrap();
|
|
|
|
if !t.contains(&r) && t[0] != Types::Any {
|
|
lerror!(&op.loc, "Expected {:?}, but got {:?}", t, r);
|
|
return Err(eyre!(""));
|
|
}
|
|
|
|
Ok(r)
|
|
}
|