Как я могу включить содержимое файла в качестве аргумента макроса? - PullRequest
0 голосов
/ 30 января 2019

Я пытаюсь реализовать Lisp-версию Обработка , и для этого я использую ящик macro_lisp, чтобы превратить код Lisp в Rust во время компиляции.

Это работает, когда я структурирую свой код следующим образом:

main.rs

fn main() {
    include!("hello.lisp");
}

hello.lisp

lisp!(println "hello")

Обратите внимание, что мне нужно обернуть содержимое hello.lisp в lisp!(), в hello.lisp.

Я хочу, чтобы оно было структурировано так:

main.rs

fn main() {
    lisp!(include!("hello.lisp"));
}

hello.lisp

println "hello"

Но это дает мне следующую ошибку:

error: expected expression, found `<eof>`
  --> src/main.rs:47:18
   |
47 |     lisp!(include!("draw.lisp"));
   |                  ^ expected expression

Там не должно быть EOF, должно быть hello "list".

Что я делаю не так?Нужно ли исправлять macro_lisp?

1 Ответ

0 голосов
/ 30 января 2019

К сожалению, достичь того, чего вы хотите, нелегко.

Макросы работают значительно иначе, чем функции.Важной частью этого вопроса является то, что «вложенные вызовы макросов» оцениваются «снаружи внутрь» (в отличие от функций, где аргументы оцениваются первыми, поэтому «снаружи внутрь»).Мы видим, что в действительности с этой крошечной программой:

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 хорошей идеей, потому что нет 'Есть хорошие способы заставить его работать (насколько я вижу).

...