use std::fmt::{self, Display, Formatter};
#[derive(Debug, Default)]
pub struct Program {
pub filename: String,
pub blocks: Vec<Block>,
}
#[derive(Debug, Default)]
pub struct Block {
pub lineno: usize,
pub blockdel: bool,
pub words: Vec<Word>,
pub assignments: Vec<ParAssign>,
}
#[derive(Debug)]
pub struct ParAssign {
pub id: ParId,
pub value: Expr,
}
#[derive(Debug)]
pub enum ParId {
Named(String),
Numeric(u16),
Indirect(Box<Expr>),
}
#[derive(Debug)]
pub enum Expr {
Num(f64),
Par(ParId),
Call(Call),
BinOp(Op, Box<Expr>, Box<Expr>),
UnOp(UnOp, Box<Expr>),
}
#[derive(Debug)]
pub enum Word {
Gcode(Expr),
Mcode(Expr),
Feed(Expr),
Spindle(Expr),
Tool(Expr),
Arg(Arg, Expr),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Op {
Exp,
Mul,
Div,
Mod,
Add,
Sub,
Eq,
Ne,
Gt,
Ge,
Lt,
Le,
And,
Or,
Xor,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnOp {
Plus,
Minus,
}
#[derive(Debug)]
pub enum Call {
Exists(ParId),
Atan(Box<Expr>, Box<Expr>),
Abs(Box<Expr>),
Acos(Box<Expr>),
Asin(Box<Expr>),
Cos(Box<Expr>),
Exp(Box<Expr>),
Fix(Box<Expr>),
Fup(Box<Expr>),
Round(Box<Expr>),
Ln(Box<Expr>),
Sin(Box<Expr>),
Sqrt(Box<Expr>),
Tan(Box<Expr>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Arg {
AxisA,
AxisB,
AxisC,
AxisU,
AxisV,
AxisW,
AxisX,
AxisY,
AxisZ,
OffsetI,
OffsetJ,
OffsetK,
ParamD,
ParamE,
ParamH,
ParamL,
ParamP,
ParamQ,
ParamR,
}
fn wrap_op(f: &mut Formatter, ex: &Expr) -> fmt::Result {
if let Expr::BinOp(..) = ex {
write!(f, "[{}]", ex)
} else {
Display::fmt(&ex, f)
}
}
impl Display for Program {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
for block in &self.blocks {
write!(f, "{}\n", block)?;
}
Ok(())
}
}
impl Display for Block {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.blockdel {
write!(f, "/ ")?;
}
for ass in &self.assignments {
write!(f, "{} ", ass)?;
}
for word in &self.words {
write!(f, "{} ", word)?;
}
Ok(())
}
}
impl Display for ParAssign {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if let ParId::Indirect(id) = &self.id {
if let Expr::Call(..) = **id {
write!(f, "#[{}]=", self.id)?;
return wrap_op(f, &self.value);
}
}
write!(f, "#{}=", self.id)?;
wrap_op(f, &self.value)
}
}
impl Display for ParId {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
ParId::Numeric(n) => Display::fmt(n, f),
ParId::Named(n) => write!(f, "<{}>", n),
ParId::Indirect(ex) => wrap_op(f, ex),
}
}
}
impl Display for Expr {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Expr::Num(n) => Display::fmt(n, f),
Expr::Par(id) => write!(f, "#{}", id),
Expr::Call(func) => Display::fmt(func, f),
Expr::BinOp(op, lhs, rhs) => {
wrap_op(f, lhs)?;
write!(f, " {} ", op)?;
wrap_op(f, rhs)
}
Expr::UnOp(op, rhs) => {
Display::fmt(op, f)?;
wrap_op(f, rhs)
}
}
}
}
impl Display for Op {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(match self {
Op::Exp => "**",
Op::Mul => "*",
Op::Div => "/",
Op::Mod => "MOD",
Op::Add => "+",
Op::Sub => "-",
Op::Eq => "EQ",
Op::Ne => "NE",
Op::Gt => "GT",
Op::Ge => "GE",
Op::Lt => "LT",
Op::Le => "LE",
Op::And => "AND",
Op::Or => "OR",
Op::Xor => "XOR",
})
}
}
impl Display for UnOp {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(match self {
UnOp::Plus => "+",
UnOp::Minus => "-",
})
}
}
impl Display for Word {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Word::Gcode(n) => { f.write_str("G")?; wrap_op(f, n) },
Word::Mcode(n) => { f.write_str("M")?; wrap_op(f, n) },
Word::Feed(n) => { f.write_str("F")?; wrap_op(f, n) },
Word::Spindle(n) => { f.write_str("S")?; wrap_op(f, n) },
Word::Tool(n) => { f.write_str("T")?; wrap_op(f, n) },
Word::Arg(a, n) => { Display::fmt(a, f)?; wrap_op(f, n) },
}
}
}
impl Display for Arg {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(match self {
Arg::AxisA => "A",
Arg::AxisB => "B",
Arg::AxisC => "C",
Arg::AxisU => "U",
Arg::AxisV => "V",
Arg::AxisW => "W",
Arg::AxisX => "X",
Arg::AxisY => "Y",
Arg::AxisZ => "Z",
Arg::OffsetI => "I",
Arg::OffsetJ => "J",
Arg::OffsetK => "K",
Arg::ParamD => "D",
Arg::ParamE => "E",
Arg::ParamH => "H",
Arg::ParamL => "L",
Arg::ParamP => "P",
Arg::ParamQ => "Q",
Arg::ParamR => "R",
})
}
}
impl Display for Call {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Call::Atan(arg1, arg2) => write!(f, "ATAN[{}]/[{}]", arg1, arg2),
Call::Exists(par) => write!(f, "EXISTS[#{}]", par),
Call::Abs(arg) => write!(f, "ABS[{}]", arg),
Call::Acos(arg) => write!(f, "ACOS[{}]", arg),
Call::Asin(arg) => write!(f, "ASIN[{}]", arg),
Call::Cos(arg) => write!(f, "COS[{}]", arg),
Call::Exp(arg) => write!(f, "EXP[{}]", arg),
Call::Fix(arg) => write!(f, "FIX[{}]", arg),
Call::Fup(arg) => write!(f, "FUP[{}]", arg),
Call::Round(arg) => write!(f, "ROUND[{}]", arg),
Call::Ln(arg) => write!(f, "LN[{}]", arg),
Call::Sin(arg) => write!(f, "SIN[{}]", arg),
Call::Sqrt(arg) => write!(f, "SQRT[{}]", arg),
Call::Tan(arg) => write!(f, "TAN[{}]", arg),
}
}
}