上一次封装了 vga 的部分操作,但是调用起来有点麻烦。Rust 提供了 macro 机制。定义 macro 需要使用 macro_rules!,貌似这也是个 macro,不过我没查到定义
macro 定义了一系列的规则,如果匹配到相应的 matcher 则会执行对应的处理逻辑
macro_rules! test {
(x => $e:expr) => (println!("mode X: {}", $e));
(y => $e:expr) => (println!("mode Y: {}", $e));
}
fn main() {
test!(y => 3);
}
// output:
// mode Y: 3
还可以利用 *,+ 等进行重复匹配
macro_rules! test {
(x => ($( $e:expr ),*)) => ($( println!("mode X: {}", $e);)*);
(y => ($( $e:expr ),*)) => ($( println!("mode Y: {}", $e);)*);
}
fn main() {
test!(x => (3, 4, 5));
}
// output:
// mode X: 3
// mode X: 4
// mode X: 5
其中 matcher 中可以使用
ident: an identifier. Examples:x;foo.path: a qualified name. Example:T::SpecialA.expr: an expression. Examples:2 + 2;if true { 1 } else { 2 }; f(42).ty: a type. Examples:i32;Vec<(char, String)>;&T.pat: a pattern. Examples:Some(t);(17, 'a');_.stmt: a single statement. Example:let x = 3.block: a brace-delimited sequence of statements and optionally an expression. Example:{ log(error, "hi"); return 12; }.item: an item. Examples:fn foo() { };struct Bar;.meta: a “meta item”, as found in attributes. Example:cfg(target_os = "windows").tt: a single token tree.
token tree 可以为
- a sequence of token trees surrounded by matching
(),[], or{}, or - any other single token.
在 vga/src/lib.rs 中添加如下 macro
pub fn kprint(args: fmt::Arguments) {
WRITER.lock().write_fmt(args).unwrap();
}
#[macro_export]
macro_rules! kprint {
($($arg:tt)*) => ({
$crate::kprint(format_args!($($arg)*));
});
}
#[macro_export]
macro_rules! kprintln {
($fmt:expr) => (kprint!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (kprint!(concat!($fmt, "\n"), $($arg)*));
}
src/lib.rs 中添加如下代码
#[macro_use]
extern crate vga;
我们便可以在 kmain 中使用 kprintln! 了
#[no_mangle]
pub extern fn kmain() -> ! {
kprintln!("Welcome to Japari Park")j;
loop {}
}