К сожалению, достичь того, чего вы хотите, нелегко.
Макросы работают значительно иначе, чем функции.Важной частью этого вопроса является то, что «вложенные вызовы макросов» оцениваются «снаружи внутрь» (в отличие от функций, где аргументы оцениваются первыми, поэтому «снаружи внутрь»).Мы видим, что в действительности с этой крошечной программой:
macro_rules! foo {
($x:literal) => { "literal" };
($x:ident ! ()) => { "ident ! ()" };
}
macro_rules! bar {
() => { 3 };
}
fn main() {
let s = foo!(bar!());
println!("{}", s);
}
Как вы можете видеть на игровой площадке , она печатает ident ! ()
.Это означает, что макрос bar!()
не был оценен до foo!
.(Более того, компилятор даже предупреждает о неиспользованном определении макроса bar
.)
include!
не является исключением, поэтому мы не можем использовать его в качестве аргумента для других макросов.Так как же может сделать это?Я могу придумать два способа, ни один из которых не является особенно простым или элегантным:
Написать процедурный макрос, который загружает файл и генерирует поток токенов lisp! { ... }
, где ...
- этосодержимое файла.Может быть сложно получить правильные пути (и убедиться, что все правильно перекомпилируется при изменении файла lisp), но теоретически это должно работать.
Использовать скрипт сборки длявручную замените строки include!("*.lisp")
в исходном коде содержимым файла.Очевидно, что вы на самом деле не хотите изменять свой реальный исходный код (который проверен в git), но должны быть немного хитрыми в этом.Несколько ящиков используют такую тактику, но только по очень особым причинам.Я бы не советовал делать это в вашем случае.
В вашем случае я бы дважды подумал, является ли использование большого количества кода LISP в Rust хорошей идеей, потому что нет 'Есть хорошие способы заставить его работать (насколько я вижу).