use paste::paste;
use super::{Field, Token, Value};
#[macro_export]
macro_rules! command {
($commandName: ident {
$($arg: ident : $value: expr),* $(,)?
}) => {
{
paste::expr!{
g_code::emit::command::[<$commandName:snake:lower>](
vec![$(
g_code::emit::Field {
letters: std::borrow::Cow::Borrowed(stringify!([<$arg:upper>])),
value: g_code::emit::Value::Float($value),
}
,)*].into_iter()
)
}
}
};
}
macro_rules! impl_commands {
($($(#[$outer:meta])* $commandName: ident {$letters: expr, $value: literal, {$($(#[$inner:meta])* $arg: ident), *} } )*) => {
paste! {
$(
$(#[$outer])*
pub fn [<$commandName:snake:lower>]<'a, I: Iterator<Item = Field<'a>>>(args: I) -> Command<'a> {
Command {
name: [<$commandName:snake:upper _FIELD>].clone(),
args: args.filter(|arg| {
match arg.letters.to_ascii_uppercase().as_str() {
$(stringify!($arg) => true,)*
_ => false
}
}).collect(),
}
}
pub const [<$commandName:snake:upper _FIELD>]: Field<'static> = Field {
letters: std::borrow::Cow::Borrowed($letters),
value: crate::emit::Value::Integer($value),
};
)*
}
#[derive(Clone, PartialEq, Debug)]
pub struct Command<'a> {
name: Field<'a>,
args: Vec<Field<'a>>,
}
impl<'a> Command<'a> {
pub fn push(&mut self, arg: Field<'a>) -> Result<(), &'static str> {
paste!{
match &self.name {
$(x if *x == [<$commandName:snake:upper _FIELD>] => {
if match arg.letters.as_ref() {
$(stringify!([<$arg:upper>]) => {true},)*
$(stringify!([<$arg:lower>]) => {true},)*
_ => false,
} {
self.args.push(arg);
Ok(())
} else {
Err(concat!($(stringify!([<$arg:lower>]), " ", stringify!([<$arg:upper>]), " ", )*))
}
},)*
_ => {
unreachable!("a command's name cannot change");
}
}
}
}
pub fn iter(&self) -> impl Iterator<Item = &Field<'_>> {
std::iter::once(&self.name).chain(self.args.iter())
}
pub fn into_token_vec(mut self) -> Vec<Token<'a>> {
std::iter::once(self.name).chain(self.args.drain(..)).map(|f| f.into()).collect()
}
pub fn iter_args(&self) -> impl Iterator<Item = &Field<'_>> {
self.iter().skip(1)
}
pub fn iter_mut_args(&mut self) -> impl Iterator<Item = &mut Field<'a>> {
self.args.iter_mut()
}
pub fn get(&'_ self, letters: &str) -> Option<&'_ Field<'_>> {
let letters = letters.to_ascii_uppercase();
self.iter_args().find(|arg| arg.letters == letters)
}
pub fn set(&mut self, letters: &str, value: Value<'a>) {
let letters = letters.to_ascii_uppercase();
for i in 0..self.args.len() {
if self.args[i].letters == letters {
self.args[i].value = value;
break;
}
}
}
}
};
}
impl_commands!(
RapidPositioning {
"G", 0, {
X,
Y,
Z,
E,
F,
H,
R,
S,
A,
B,
C
}
}
LinearInterpolation {
"G", 1, {
X,
Y,
Z,
E,
F,
H,
R,
S,
A,
B,
C
}
}
ClockwiseCircularInterpolation {
"G", 2, {
X,
Y,
Z,
I,
J,
K,
E,
F,
R
}
}
CounterclockwiseCircularInterpolation {
"G", 3, {
X,
Y,
Z,
I,
J,
K,
E,
F,
R
}
}
Dwell {
"G", 4, {
P
}
}
UnitsInches {
"G", 20, {}
}
UnitsMillimeters {
"G", 21, {}
}
AbsoluteDistanceMode {
"G", 90, {}
}
RelativeDistanceMode {
"G", 91, {}
}
FeedRateUnitsPerMinute {
"G", 94, {}
}
StartSpindleClockwise {
"M", 3, {
P
}
}
StartSpindleCounterclockwise {
"M", 4, {
P
}
}
StopSpindle {
"M", 5, {}
}
ProgramEnd {
"M", 2, {}
}
);