use super::{
ast::{BinaryOperator, UnaryOperator},
value::Value,
};
use crate::luna_impl::position::Located;
use std::{cell::RefCell, fmt::Display, rc::Rc};
pub type Register = u16;
pub type Address = u32;
pub type VectorSize = u16;
pub type ObjectSize = u16;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ByteCode {
#[default]
None,
Jump {
addr: Address,
},
JumpIf {
negative: bool,
cond: Source,
addr: Address,
},
JumpNull {
negative: bool,
cond: Source,
addr: Address,
},
CallZero {
dst: Option<Location>,
func: Source,
},
CallSingle {
dst: Option<Location>,
func: Source,
arg: Source,
},
Call {
dst: Option<Location>,
func: Source,
offset: Register,
amount: u8,
},
Return {
src: Option<Source>,
},
Move {
dst: Location,
src: Source,
},
Field {
dst: Location,
head: Source,
field: Source,
},
SetField {
head: Source,
field: Source,
src: Source,
},
Vector {
dst: Location,
start: Register,
amount: VectorSize,
},
Object {
dst: Location,
start: Register,
amount: ObjectSize,
},
Function {
dst: Location,
addr: Address,
},
Binary {
op: BinaryOperation,
dst: Location,
left: Source,
right: Source,
},
Unary {
op: UnaryOperation,
dst: Location,
src: Source,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Source {
Register(Register),
Upvalue(Address),
Global(Address),
Constant(Address),
#[default]
Null,
Bool(bool),
Char(char),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Location {
Register(Register),
Upvalue(Address),
Global(Address),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOperation {
Add,
Sub,
Mul,
Div,
Pow,
Mod,
EQ,
NE,
LT,
GT,
LE,
GE,
And,
Or,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOperation {
Neg,
Not,
}
#[derive(Debug, Clone, Default)]
pub struct Closure {
pub code: Vec<Located<ByteCode>>,
pub registers: Register,
pub closures: Vec<Rc<RefCell<Self>>>,
pub upvalues: Vec<Upvalue>,
pub consts: Vec<Value>,
pub path: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Upvalue {
pub register: Register,
pub depth: u8,
}
impl Display for Source {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Register(reg) => write!(f, "@{reg}"),
Self::Upvalue(addr) => write!(f, "@u{addr}"),
Self::Global(addr) => write!(f, "@g{addr}"),
Self::Constant(addr) => write!(f, "#{addr}"),
Self::Null => write!(f, "null"),
Self::Bool(v) => write!(f, "{v:?}"),
Self::Char(v) => write!(f, "{v:?}"),
}
}
}
impl Display for Location {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Register(reg) => write!(f, "!{reg}"),
Self::Upvalue(addr) => write!(f, "!u{addr}"),
Self::Global(addr) => write!(f, "!g{addr}"),
}
}
}
impl Display for ByteCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::None => write!(f, "none"),
Self::Jump { addr } => write!(f, "jump *{addr:?}"),
Self::JumpIf {
negative,
cond,
addr,
} => {
if *negative {
write!(f, "jumpifnot {cond} *{addr:?}")
} else {
write!(f, "jumpif {cond} *{addr:?}")
}
}
Self::JumpNull { negative, cond, addr } => {
if *negative {
write!(f, "jumpnotnull {cond} *{addr:?}")
} else {
write!(f, "jumpnull {cond} *{addr:?}")
}
}
Self::CallZero {
dst,
func,
} => {
if let Some(dst) = dst {
write!(f, "call {func} -> {dst}")
} else {
write!(f, "call {func}")
}
}
Self::CallSingle {
dst,
func,
arg,
} => {
if let Some(dst) = dst {
write!(f, "call {func} {arg} -> {dst}")
} else {
write!(f, "call {func} {arg}")
}
}
Self::Call {
dst,
func,
offset,
amount,
} => {
if let Some(dst) = dst {
write!(f, "call {func} @{offset}..+{amount} -> {dst}")
} else {
write!(f, "call {func} @{offset}..+{amount}")
}
}
Self::Return { src } => {
if let Some(src) = src {
write!(f, "return {src}")
} else {
write!(f, "return")
}
}
Self::Move { dst, src } => write!(f, "move {dst} = {src}"),
Self::Field { dst, head, field } => write!(f, "field {dst} = {head} . {field}"),
Self::SetField { head, field, src } => write!(f, "setfield {head} . {field} = {src}"),
Self::Vector { dst, start, amount } => write!(f, "vector {dst} = @{start}..+{amount}"),
Self::Object { dst, start, amount } => write!(f, "object {dst} = @{start}..+{amount}"),
Self::Function { dst, addr } => write!(f, "func {dst} = #f{addr:?}"),
Self::Binary {
op,
dst,
left,
right,
} => write!(
f,
"binary {dst} = {left} {} {right}",
format!("{op:?}").to_lowercase()
),
Self::Unary { op, dst, src } => write!(
f,
"unary {dst} = {} {src}",
format!("{op:?}").to_lowercase()
),
}
}
}
impl Display for Closure {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "closure {:08x?}", self as *const Closure)?;
writeln!(f, "registers: {}", self.registers)?;
writeln!(f, "code, #{} instructions:", self.code.len())?;
for (addr, bytecode) in self.code.iter().enumerate() {
writeln!(f, "\t[{addr:04}] {bytecode}")?;
}
writeln!(f, "upvalues:")?;
for (addr, upvalue) in self.upvalues.iter().enumerate() {
writeln!(
f,
"\t[{addr}] register: {}, depth: {}",
upvalue.register, upvalue.depth
)?;
}
writeln!(f, "constants:")?;
for (addr, value) in self.consts.iter().enumerate() {
writeln!(f, "\t[{addr}] {}: {:?}", value.typ(), value)?;
}
writeln!(f, "closures:")?;
for (addr, closure) in self.closures.iter().enumerate() {
writeln!(f, "\t[{addr}] {:08x?}", closure.as_ptr())?;
}
writeln!(f)?;
for closure in self.closures.iter() {
write!(f, "{}", closure.borrow())?;
}
Ok(())
}
}
impl From<Location> for Source {
fn from(value: Location) -> Self {
match value {
Location::Register(register) => Self::Register(register),
Location::Upvalue(addr) => Self::Upvalue(addr),
Location::Global(addr) => Self::Global(addr),
}
}
}
impl From<BinaryOperator> for BinaryOperation {
fn from(value: BinaryOperator) -> Self {
match value {
BinaryOperator::Plus => Self::Add,
BinaryOperator::Minus => Self::Sub,
BinaryOperator::Star => Self::Mul,
BinaryOperator::Slash => Self::Div,
BinaryOperator::Exponent => Self::Pow,
BinaryOperator::Percent => Self::Mod,
BinaryOperator::EqualEqual => Self::EQ,
BinaryOperator::ExclamationEqual => Self::NE,
BinaryOperator::Less => Self::LT,
BinaryOperator::Greater => Self::GT,
BinaryOperator::LessEqual => Self::LE,
BinaryOperator::GreaterEqual => Self::GE,
BinaryOperator::Ampersand => Self::And,
BinaryOperator::Pipe => Self::Or,
}
}
}
impl From<UnaryOperator> for UnaryOperation {
fn from(value: UnaryOperator) -> Self {
match value {
UnaryOperator::Minus => Self::Neg,
UnaryOperator::Exclamation => Self::Not,
}
}
}
impl Display for BinaryOperation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Add => write!(f, "add"),
Self::Sub => write!(f, "sub"),
Self::Mul => write!(f, "mul"),
Self::Div => write!(f, "div"),
Self::Pow => write!(f, "pow"),
Self::Mod => write!(f, "mod"),
Self::EQ => write!(f, "eq"),
Self::NE => write!(f, "ne"),
Self::LT => write!(f, "lt"),
Self::GT => write!(f, "gt"),
Self::LE => write!(f, "le"),
Self::GE => write!(f, "ge"),
Self::And => write!(f, "and"),
Self::Or => write!(f, "or"),
}
}
}
impl Display for UnaryOperation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UnaryOperation::Neg => write!(f, "neg"),
UnaryOperation::Not => write!(f, "not"),
}
}
}