Using a macro that breaks out of a loop works, but I want to pass in a label to be able to define which outer loop to break out of.
Passing the argument in as an expression gave a syntax error, the only way I managed to get this to work was to pass in a block however this isn't very elegant, e.g.:
my_macro({ break 'outer; });
Is there a way to pass:
my_macro('outer);
... that can be written in the macro as break $my_label; that expands into break 'outer; ?
Passing it as the versatile tt (token tree) works:
macro_rules! my_break {
($label:tt) => { break $label; }
}
fn main() {
'outer: loop {
println!("Start of outer");
loop {
println!("Start of inner");
my_break!('outer);
println!("Not reachable");
}
println!("End of outer");
}
println!("End of main");
}
Playground
To future readers, there's an accepted RFC adding a lifetime specifier for macro parameters.
Related
What is the reason for wrapping all this code in a UI: do { } block and where can I get clear instructions about it?
UI: do {
backgroundButton.setImage(UIImage.init(named: "search"), for: .normal)
backgroundButton.backgroundColor = Colors.backgroundButtonBackgroundColor
backgroundButton.tintColor = Colors.backgroundButtonTintColor
}
Other than labels being used to break loops (change control flow), in your particular example it's probably being used to organize the code.
So, in:
UI: do {
//...
}
UI: is a Labelled Statement where UI is a user defined label name that should be descriptive enough to indicate or hint to the reader of it's purpose
Labeled Statement
You can prefix a loop statement, an if statement, a switch statement,
or a do statement with a statement label, which consists of the name
of the label followed immediately by a colon (:). Use statement labels
with break and continue statements to be explicit about how you want
to change control flow in a loop statement or a switch statement
Ref: https://docs.swift.org/swift-book/ReferenceManual/Statements.html#ID439
do { } is a Do Statement
Do Statement
The do statement is used to introduce a new scope and can optionally
contain one or more catch clauses, which contain patterns that match
against defined error conditions. Variables and constants declared in
the scope of a do statement can be accessed only within that scope.
Ref: https://docs.swift.org/swift-book/ReferenceManual/Statements.html#ID533
//... is all the code within the scope of do
Usage Example:
In a monolithic function, in order to improve code readability and segregate the internal logics, a labeled do statement can be used.
So, if this is a monolithic function:
func update() {
var hasUpdatedDatasource = false
print("setting datasource")
//N lines of code related to datasource
let strings = ["update", "Datasource"]
print(strings.joined())
hasUpdatedDatasource = strings.count > 2
print("setting something")
//N lines of code related to something
if hasUpdatedDatasource {
print("setting some more stuff")
//N lines of code related to something more
}
print("setting UI")
//N lines of code related to UI
}
Here we see multiple lines of code in which you may be creating/modifying variables. Basically alot of soup code that would make it hard to figure out which set of code lines is handling which feature or part of the function.
Using a labeled do statement, as in your case, will make the code a bit more readable like so:
func update() {
var hasUpdatedDatasource = false
updateDatasource: do {
//do datasource related modification
//N lines of code go here
let datasource = ["update", "Datasource"]
print(datasource.joined())
hasUpdatedDatasource = strings.count > 2
}
doSomething: do {
print("doSomething")
//N lines of code go here
guard hasUpdatedDatasource else { break doSomething }
print("doSomething: More")
//N lines of code go here
}
updateUI: do {
print("updateUI")
//N lines of code go here
}
}
This allows you to make a set of code lines into block of codes with a descriptive label name and shows the logic flow more clearly.
You can access and modify variables from above it's do scope, and since it has it's own scope, variables created inside are only accessible here.
This can prevent variables from lingering unnecessarily till the end of the function.
NOTES:
updateDatasource created a local variable datasource which won't be available outside it's scope, AND... modified a variable hasUpdatedDatasource which is local to the entire function
doSomething has a break statement that can break itself anytime by referring to it's label name
It does make the code more readable but not necessarily more maintainable as it's statefull.
Personally, I prefer splitting large functions into smaller or nested functions. But this does not mean that labeled do statements don't have their place.
If it makes your code better, go for it.
It's a labeled statement:
A labeled statement is indicated by placing a label on the same line
as the statement’s introducer keyword, followed by a colon.
and it can be used to break away from outsider scopes. An illustrative example is given here.
The UI in your code is a labeled statement which is useful in cases where you want to escape from an outer scope(or block) while you're inside an inner scope(or block)
Consider an example where you want to break out of the outer loop when a certain condition arises while you're inside another loop(or, innerLoop in our case)
outerLoop: for outerCount in 1...5 {
innerLoop: for innerCount in 1...5 {
// Condition for breaking out of outer loop
if outerCount == 3 {
break outerLoop
}
print("Outer Count: \(outerCount) Inner Count: \(innerCount)")
}
}
If we had used break instead of break outerLoop in above case, we
would just be able to break innerLoop and would still be inside
outerLoop scope
The do clause in your case , as #Rob suggested , can also be used to simply encapsulate a series of statements within their own scope . What it does is, it provides a scope for some variables that are initialised inside do and will be deallocated once the do scope ends
Consider the following case for do scope which will automatically deinit the object as soon as the do scope ends
class Demo {
init() {
print("Instance initialised")
}
deinit {
print("Instance Deinitalised")
}
}
do {
let demoObject = Demo()
}
Output of above code will be
Instance initialised
Instance Deinitalised
Is it possible to write a macro that expands an expression into multiple indexed arguments, which can be passed to a function or another macro?
See this simple self contained example.The aim is to have unpack3 expand v into v[0], v[1], v[2].
macro_rules! elem {
($val:expr, $($var:expr), *) => {
$($val == $var) || *
}
}
// attempt to expand an array.
macro_rules! unpack3 {
($v:expr) => {
$v[0], $v[1], $v[2]
}
}
fn main() {
let a = 2;
let vars = [0, 1, 3];
// works!
if elem!(a, vars[0], vars[1], vars[2]) {
println!("Found!");
}
// fails!
if elem!(a, unpack3!(vars)) {
println!("Found!");
}
}
The second example fails, is it possible to make this work?
Possible solutions could include:
Changing use of macro grammar.
Using tuples, then expanding into arguments after.
Re-arranging the expressions to workaround macro constraints.
Note, this may be related to Escaping commas in macro output but don't think its a duplicate.
This is impossible in two different ways.
First, to quote the answer to the question you yourself linked: "No; the result of a macro must be a complete grammar construct like an expression or an item. You absolutely cannot have random bits of syntax like a comma or a closing brace." Just because it isn't exactly a comma doesn't change matters: a collection of function arguments are not a complete grammar construct.
Secondly, macros cannot parse the output of other macros. This requires eager expansion, which Rust doesn't have. You can only do this using recursion.
Is it possible to build an enum inside a Rust macro using fields that are defined as macro parameters? I've tried this:
macro_rules! build {
($($case:ty),*) => { enum Test { $($case),* } };
}
fn main() {
build!{ Foo(i32), Bar(i32, i32) };
}
But it fails with error: expected ident, found 'Foo(i32)'
Note that if the fields are defined inside the enum, there is no problem:
macro_rules! build {
($($case:ty),*) => { enum Test { Foo(i32), Bar(i32, i32) } };
}
fn main() {
build!{ Foo(i32), Bar(i32, i32) };
}
It also works if my macro only accepts simple fields:
macro_rules! build {
($($case:ident),*) => { enum Test { $($case),* } };
}
fn main() {
build!{ Foo, Bar };
}
But I've been unable to get it to work in the general case.
It's absolutely possible, but you're conflating totally unrelated concepts.
Something like $case:ty does not mean $case is something which looks like a type, it means $case is literally a type. Enums are not made up of a sequence of types; they're made up of a sequence of variants which are an identifier followed (optionally) by a tuple structure body, a record structure body, or a tag value.
The parser doesn't care if the type you give it happens to coincidentally look like a valid variant, it's simply not expecting a type, and will refuse to parse one in that position.
What you need is to use something like $case:variant. Unfortunately for you, no such matcher exists. The only way to do something like this is to manually parse it using a recursive incremental parser and that is so out of scope of an SO question it's not funny. If you want to learn more, try the chapter on incremental TT munchers in the Little Book of Rust Macros as a starting point.
However, you don't appear to actually do anything with the cases. You're just blindly substituting them. In that case, you can just cheat and not bother with trying to match anything coherent:
macro_rules! build {
($($body:tt)*) => {
as_item! {
enum Test { $($body)* }
}
};
}
macro_rules! as_item {
($i:item) => { $i };
}
fn main() {
build!{ Foo, Bar };
}
(Incidentally, that as_item! thing is explained in the section on AST coercion (a.k.a. "the reparse trick").)
This just grabs everything provided as input to build!, and shoves it into the body of an enum without caring what it looks like.
If you were trying to do something meaningful with the variants, well, you're going to have to be more specific about what you're actually trying to accomplish, as the best advice of how to proceed varies wildly depending on the answer.
I am trying to make a wrapper for a macro. The trouble is that I don't want to repeat the same rules in both macro. Is there a way to do that?
Here is what I tried:
macro_rules! inner {
($test:ident) => { stringify!($test) };
($test:ident.run()) => { format!("{}.run()", stringify!($test)) };
}
macro_rules! outer {
($expression:expr) => {
println!("{}", inner!($expression));
}
}
fn main() {
println!("{}", inner!(test));
println!("{}", inner!(test.run()));
outer!(test);
outer!(test.run());
}
but I get the following error:
src/main.rs:8:31: 8:42 error: expected ident, found test
src/main.rs:8 println!("{}", inner!($expression));
^~~~~~~~~~~
If I change the outer macro for this, the code compile:
macro_rules! outer {
($expression:expr) => {
println!("{}", stringify!($expression));
}
}
What am I doing wrong?
macro_rules! is both cleverer and dumber than you might realise.
Initially, all input to a macro begins life as undifferentiated token soup. An Ident here, StrLit there, etc. However, when you match and capture a bit of the input, generally the input will be parsed in an Abstract Syntax Tree node; this is the case with expr.
The "clever" bit is that when you substitute this capture (for example, $expression), you don't just substitute the tokens that were originally matched: you substitute the entire AST node as a single token. So there's now this weird not-really-a-token in the output that's an entire syntax element.
The "dumb" bit is that this process is basically irreversible and mostly totally invisible. So let's take your example:
outer!(test);
We run this through one level of expansion, and it becomes this:
println!("{}", inner!(test));
Except, that's not what it looks like. To make things clearer, I'm going to invent some non-standard syntax:
println!("{}", inner!( $(test):expr ));
Pretend that $(test):expr is a single token: it's an expression which can be represented by the token sequence test. It is not simply the token sequence test. This is important, because when the macro interpreter goes to expand that inner! macro, it checks the first rule:
($test:ident) => { stringify!($test) };
The problem is that $(test):expr is an expression, not an identifier. Yes, it contains an identifier, but the macro interpreter doesn't look that deep. It sees an expression and just gives up.
It fails to match the second rule for the same reason.
So what do you do? ... Well, that depends. If outer! doesn't do any sort of processing on its input, you can use a tt matcher instead:
macro_rules! outer {
($($tts:tt)*) => {
println!("{}", inner!($($tts)*));
}
}
tt will match any token tree (see the Macros chapter of the Rust Book). $($tts:tt)* will match any sequence of tokens, without changing them. This of this as a way to safely forward a bunch of tokens to another macro.
If you need to do processing on the input and forward it on to the inner! macro... you're probably going to have to repeat the rules.
I had some success with the $($stuff: expr),+ syntax.
macro_rules! println {
( $($stuff: expr),+) => {
avr_device::interrupt::free(|cs| {
uwriteln!(unsafe { &SERIAL_STATIC}.borrow(cs).borrow_mut().as_mut().unwrap(),
$($stuff),+)
})
}
}
I'm trying to write a class for a scala project and I get this error in multiple places with keywords such as class, def, while.
It happens in places like this:
var continue = true
while (continue) {
[..]
}
And I'm sure the error is not there since when I isolate that code in another class it doesn't give me any error.
Could you please give me a rule of thumb for such errors? Where should I find them? are there some common syntactic errors elsewhere when this happens?
It sounds like you're using reserved keywords as variable names. "Continue", for instance, is a Java keyword.
You probably don't have parentheses or braces matched somewhere, and the compiler can't tell until it hits a structure that looks like the one you showed.
The other possibility is that Scala sometimes has trouble distinguishing between the end of a statement with a new one on the next line, and a multi-line statement. In that case, just drop the ; at the end of the first line and see if the compiler's happy. (This doesn't seem like it fits your case, as Scala should be able to tell that nothing should come after true, and that you're done assigning a variable.)
Can you let us know what this code is inside? Scala expects "expressions" i.e. things that resolve to a particular value/type. In the case of "var continue = true", this does not evaluate to a value, so it cannot be at the end of an expression (i.e. inside an if-expression or match-expression or function block).
i.e.
def foo() = {
var continue = true
while (continue) {
[..]
}
}
This is a problem, as the function block is an expression and needs to have an (ignored?) return value, i.e.
def foo() = {
var continue = true
while (continue) {
[..]
}
()
}
() => a value representing the "Unit" type.
I get this error when I forget to put an = sign after a function definition:
def function(val: String):Boolean {
// Some stuff
}