#[macro_export]
macro_rules! tokay {
( { $( $items:tt ),+ } ) => {
{
let mut compiler = Compiler::new();
compiler.debug = 0;
compiler.push_parselet(); compiler.mark_consuming();
let main = tokay!(compiler, { $( $items ),* });
let parselet = compiler.pop_parselet(
Some("__main__".to_string()),
Vec::new(),
main.unwrap_or(ImlOp::Nop)
);
compiler.define_value(parselet.into());
match compiler.to_program() {
Ok(program) => {
if compiler.debug > 0 {
program.dump();
}
program
},
Err(errors) => {
for error in errors {
println!("{}", error);
}
panic!("Errors in compile!");
}
}
}
};
( $compiler:expr, ( $name:ident = $value:literal ) ) => {
{
let name = stringify!($name).to_string();
let value = Value::Str($value.to_string()).into();
$compiler.set_constant(&name, value);
None
}
};
( $compiler:expr, ( _ = { $( $item:tt ),* } ) ) => {
{
$compiler.push_parselet();
$compiler.mark_consuming();
let items = vec![
$(
tokay!($compiler, $item)
),*
];
let body = ImlAlternation::new(
items.into_iter()
.filter(|item| item.is_some())
.map(|item| item.unwrap())
.collect()
);
let mut parselet = $compiler.pop_parselet(
Some("_".to_string()),
Vec::new(),
body
);
parselet.severity = 0; $compiler.set_constant("_", parselet.into());
None
}
};
( $compiler:expr, ( $name:ident = { $( $item:tt ),* } ) ) => {
{
let name = stringify!($name).to_string();
if !crate::utils::identifier_is_consumable(&name) {
panic!("Parselet identifier must begin with an upper-case letter or underscore!");
}
$compiler.push_parselet();
$compiler.mark_consuming();
let items = vec![
$(
tokay!($compiler, $item)
),*
];
let body = ImlAlternation::new(
items.into_iter()
.filter(|item| item.is_some())
.map(|item| item.unwrap())
.collect()
);
let parselet = $compiler.pop_parselet(
Some(stringify!($name).to_string()),
Vec::new(),
body
);
$compiler.set_constant(&name, parselet.into());
None
}
};
( $compiler:expr, [ $( $item:tt ),* ] ) => {
{
let items = vec![
$(
tokay!($compiler, $item)
),*
];
Some(
ImlSequence::new(
items.into_iter()
.filter(|item| item.is_some())
.map(|item| item.unwrap())
.collect()
)
)
}
};
( $compiler:expr, { $( $item:tt ),* } ) => {
{
let items = vec![
$(
tokay!($compiler, $item)
),*
];
Some(
ImlAlternation::new(
items.into_iter()
.filter(|item| item.is_some())
.map(|item| item.unwrap())
.collect()
)
)
}
};
( $compiler:expr, (kle $item:tt) ) => {
Some(tokay!($compiler, $item).unwrap().into_kleene())
};
( $compiler:expr, (pos $item:tt) ) => {
Some(tokay!($compiler, $item).unwrap().into_positive())
};
( $compiler:expr, (opt $item:tt) ) => {
Some(tokay!($compiler, $item).unwrap().into_optional())
};
( $compiler:expr, (not $item:tt) ) => {
Some(ImlNot::new(tokay!($compiler, $item).unwrap()))
};
( $compiler:expr, (peek $item:tt) ) => {
Some(ImlPeek::new(tokay!($compiler, $item).unwrap()))
};
( $compiler:expr, (expect $item:tt) ) => {
Some(
ImlExpect::new(
tokay!($compiler, $item).unwrap(),
Some(format!("Expecting {}", stringify!($item)))
)
)
};
( $compiler:expr, (expect $item:tt, $msg:literal) ) => {
Some(ImlExpect::new(tokay!($compiler, $item).unwrap(), Some($msg.to_string())))
};
( $compiler:expr, (value $value:tt) ) => {
Some(ImlOp::from(Op::LoadStatic($compiler.define_value($crate::value!($value).into()))))
};
( $compiler:expr, (token $token:tt) ) => {
{
Some(ImlOp::from(Op::CallStatic($compiler.define_value(RefValue::from($token).into()))))
}
};
( $compiler:expr, (call $ident:ident [ $( $param:tt ),* ] ) ) => {
{
let mut items = vec![
$(
tokay!($compiler, $param).unwrap()
),*
];
let name = stringify!($ident).to_string();
let item = Usage::Call{
name,
args: items.len(),
nargs: 0,
offset: None
}.resolve_or_dispose(&mut $compiler);
items.extend(item);
Some(ImlOp::from_vec(items))
}
};
( $compiler:expr, $ident:ident ) => {
{
let name = stringify!($ident);
let item = Usage::CallOrCopy{
name: name.to_string(),
offset: None
}.resolve_or_dispose(&mut $compiler);
Some(ImlOp::from_vec(item))
}
};
( $compiler:expr, _ ) => {
{
let item = Usage::CallOrCopy{
name: "_".to_string(),
offset: None
}.resolve_or_dispose(&mut $compiler);
assert!(item.len() == 1); Some(item.into_iter().next().unwrap())
}
};
( $compiler:expr, (MATCH $literal:literal) ) => {
{
let token = RefValue::from(Token::Match($literal.to_string()));
Some(ImlOp::from(Op::CallStatic($compiler.define_value(token.into()))))
}
};
( $compiler:expr, $literal:literal ) => {
{
let token = RefValue::from(Token::Touch($literal.to_string()));
Some(ImlOp::from(Op::CallStatic($compiler.define_value(token.into()))))
}
};
( $compiler:expr, $expr:tt ) => {
{
Some(ImlOp::from($expr))
}
};
}