I'm trying to implement a Lisp version of Processing, and to that end I'm employing the macro_lisp
crate to turn Lisp code into Rust at compile time.
It works when I structure my code like so:
main.rs
fn main() {
include!("hello.lisp");
}
hello.lisp
lisp!(println "hello")
Note that I have to wrap the content of hello.lisp
in lisp!()
, in hello.lisp
itself.
I want it to be structured like so:
main.rs
fn main() {
lisp!(include!("hello.lisp"));
}
hello.lisp
println "hello"
But this gives me the following error:
error: expected expression, found `<eof>`
--> src/main.rs:47:18
|
47 | lisp!(include!("draw.lisp"));
| ^ expected expression
There should not be an EOF there, there should be hello "list"
.
What am I doing wrong? Do I need to patch macro_lisp
?
Open Excel Workbook, Run Macro, Then Close Self explanatory by reading the comments, but just make sure you change the File path and Macro name. Pushing the green run button up the top, should now load your Excel File, run the macro, wait for it finish, close Excel and display a popup box, finally close PowerShell.
Function-like macros can take arguments, just like true functions. To define a macro that uses arguments, you insert parameters between the pair of parentheses in the macro definition that make the macro function-like. The parameters must be valid C identifiers, separated by commas and optionally whitespace.
There are two types of arguments: keyword and positional. Keyword arguments are assigned names in the macro definition; in the macro call, they are identified by name. Positional arguments are defined after the keyword !
Record a macroOn the Developer tab, click Record Macro. Optionally, enter a name for the macro in the Macro name box, enter a shortcut key in the Shortcut key box, and a description in the Description box, and then click OK to start recording.
Unfortunately, what you want is not easy to achieve.
Macros work significantly different than functions. The important part for this question is that "nested macro calls" are evaluated from "outside to inside" (unlike functions, where arguments are evaluated first, so "inside to outside"). We can see that in effect with this tiny program:
macro_rules! foo {
($x:literal) => { "literal" };
($x:ident ! ()) => { "ident ! ()" };
}
macro_rules! bar {
() => { 3 };
}
fn main() {
let s = foo!(bar!());
println!("{}", s);
}
As you can see on the Playground, it prints ident ! ()
. That means the bar!()
macro was not evaluated before foo!
was evaluated. (Furthermore, the compiler even warns about the unused macro definition bar
.)
include!
is no exception to this, so we can't use it as an argument to other macros. So how can you do it? I can think of two ways, neither of which is particularly easy or elegant:
Write a procedural macro that loads the file and emits the token stream lisp! { ... }
where ...
is the file content. It could be tricky to get all the paths right (and to make sure everything is correctly recompiled when the lisp file changes), but it should in theory work.
Use a build script to manually replace include!("*.lisp")
strings in your source code with the file content. Obviously, you don't actually want to modify your real source code (that is checked into git), but have to be a bit clever about it. A few crates use such a tactic, but only for very special reasons. I wouldn't advise to do this in your case.
In your case, I would think twice whether using a lot of LISP code in Rust is a good idea, because there aren't any nice ways to make it work (as far as I can see).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With