Steven Fackler / sfackler
This stuff:
let count = try!(r.read(buf)); let foo = bytes!("hello"); include_file!("some_file.rs"); println!("Hello, {}", "world"); #[deriving(Show, Eq)] struct Foo { i: int }
C's preprocessor operates on a lexical level.
Think find and replace - like sed.
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define struct union #define DO_A_THING(t) do { \ do_blah(t); \ do_foo(t); \ } while(0)
pub enum Expr_ { ExprCall(@Expr, ~[@Expr]), ExprMatch(@Expr, ~[Arm]), ExprForLoop(@Pat, @Expr, P<Block>, Option<Ident>), ... } pub enum Item_ { ItemFn(P<FnDecl>, Purity, AbiSet, Generics, P<Block>), ItemTrait(Generics, ~[TraitDef], ~[TraitMethod]), ... } ...
Macros can do things that normal code simply can't.
Return from the invoking function
macro_rules! try( ($e:expr) => ( match $e { Ok(e) => e, Err(e) => return Err(e) } ) ) fn read_foo(r: &mut Reader) -> Result<Foo, IoError> { let bar = try!(r.read_be_i32()); let baz = try!(r.read_bytes(10)); Ok(Foo { bar: bar, baz: baz }) }
(Almost) freeform syntax
let map = make_map!(Start with collections::HashMap::new() and add "foo" => 1, "bar" => 2, "baz" => 3);
Do work at compile time instead of run time!
test.rs:2:35: 2:37 error: argument never used test.rs:2 println!("hello {}", "world", 10); ^~
Syntax extensions don't have to be defined in the compiler anymore! (#11151)
They can be implemented in libraries that the compiler can load into itself.
It's simple for macro_rules!.
#[macro_export] macro_rules! my_macro(() => (1))
It's a bit more complicated for procedural macros. Libraries define a macro_registrar function to register procedural macros with the compiler.
#[macro_registrar] pub fn registrar(cb: |ast::Name, ext::base::SyntaxExtension|) { ... }
pub enum SyntaxExtension { // e.g. #[deriving(...)] ItemDecorator(...), // e.g. try!(...) NormalTT(...), // e.g. macro_rules! foo(...) IdentTT(...), }
Client code annotates the crate import to tell the compiler to load syntax extensions from it.
#[feature(phase)]; #[phase(syntax)] extern crate my_macros; fn main() { let _x = my_macro!(); }
Let's write a syntax extension that creates sorted arrays of strings:
#[feature(phase)]; #[phase(syntax)] extern crate sort; fn main() { assert_eq!(sort!("z", "", "hello", "a"), ["", "a", "hello", "z"]); }
External syntax extensions are feature gated for a reason! The API can and will change.