-
Notifications
You must be signed in to change notification settings - Fork 3
Note: Quoting and Unquoting
The quote
expression is used to turn a piece of code into an AST value of type @core::macro::Expr
:
let expr = quote {
if foo(@"...") {
42;
"asdf";
} else {
bar;
};
};
// expr is of type @core::macro::Expr. It looks like this:
assert expr == @new Block {
exprs = @[@new If {
condition = @new FunctionCall {
function = @new QualIdent {
idents = @[@new Ident {
value = "foo"
}
]
},
arguments = @[@new Box {
operand = @new StringLiteral {
value = "..."
}
}
]
},
true_branch = @new Block {
exprs = @[@new IntLiteral {
value = 42
},
@new StringLiteral {
value = "asdf"
}
]
},
false_branch = @new Block {
exprs = @[@new Ident {
value = "bar"
}
]
}
}]
};
// Note that quoted expressions are actually stored in the data segment.
// The operand to quote doesn't have to be a block:
let expr2 = quote 42;
assert expr2 == @new IntLiteral {
value = 42
};
Quoting happens after parsing, so invalid input to quote
cannot occur (because it would have been flagged by the parser already). Of course, semantic errors can occur after quoted code is unquoted.
Note that quote
can only be invoked inside a macro
declaration.
A value of type @core::macro::Expr
can be unquoted with unquote
, effectively turning it into 'real' code:
let expr = quote 42;
// Quote a block with a result value of 42.
quote {
unquote expr;
};
Note that unquote
can only be invoked inside a quote
expression.
So we could write a macro like this:
pub macro unless(cond, act) {
quote {
if !unquote cond {
unquote act;
};
();
};
}
This could be invoked as:
unless!(2 + 2 != 4, {
assert false, "well, that's not good";
});
Arguments to macros are passed literally as $core::macro::Expr
AST values. So when unless
is invoked, e.g. the unquote cond
expression turns the 2 + 2 != 4
expression (represented as AST nodes) into actual code.
A macro's body is evaluated sequentially at compile time. The last value in a macro body is expected to be of type @core::macro::Expr
and will be expanded into the macro call site. A macro's body is only semantically checked once invoked (since the inputs aren't available until then).
Within a macro's body, macro
followed by a string literal can be used to query information about the environment the macro is being expanded in. In particular, we could say:
pub macro get_line() {
let line = macro "line";
quote unquote line;
}
We could then do:
assert get_line() == 42; // Assuming we're expanding get_line at line 42.
A list of the things that can be queried:
-
"file"
(str
): The absolute path to the file the macro is being expanded in. -
"line"
(u32
): The line the macro is being expanded on. Starts at 1. -
"column"
(u32
): The column the macro is being expanded at. Starts at 1. -
"module"
(str
): The name of the module the macro is being expanded in, e.g."foo::bar"
. -
"function"
(str
): The name of the function the macro is being expanded in, e.g."my_function"
.
- Home
- Introduction
- Motivation
- Features
- Tutorial
- Library
- FAQ
- General
- Interoperability
- Syntax
- Type System
- Macros and CTE
- Specification
- Introduction
- Lexical
- Common Grammar Elements
- Modules and Bundles
- Type System
- Declarations
- Expressions
- Macros
- Compile-Time Evaluation
- Memory Management
- Application Binary Interface
- Foreign Function Interface
- Unit Testing
- Documentation Comments
- Style
- Indentation
- Braces
- Spacing
- Naming