How to process expanded macros from within procedural macros? - plugins

For overflower, I'm trying to replace all arithmetic operations (binary +, -, *, /, %, <<, >> and unary -) with corresponding trait method calls. However, I'm hitting a wall with macros. Ideally, I'd work on the already expanded macro, but this does not appear to work.
I've followed the suggestion in syntax::fold::Folder::fold_mac(..) and called noop_fold_mac(mac, self), but that does not appear to do anything to stuff inside a macro, like assert_eq!(2, 1 + 1). I don't care about the code pre-expansion, so how do I have my macro work on the expanded code?
I could probably work on the TokenTrees directly, but that's cumbersome.
I'm using rustc 1.11.0-nightly (915b003e3 2016-06-02)

You can use the expand_expr function to do a full expansion (if let, macros, etc...). You need a MacroExpander, which you can get by passing a mutable reference to the ExtCtxt to the MacroExpander::new method or call the ExtCtxt's expander() method.
The actual code is:
fn fold_expr(&mut self, expr: P<Expr>) -> P<Expr> {
..
if let ExprKind::Mac(_) = expr.node {
let expanded = expand_expr(expr.unwrap(), &mut self.cx.expander());
return self.fold_expr(expanded);
}
..
}
Edit: For completeness, one should also expand Items with ItemKind::Mac; there's an syntax::ext::expand::expand_item(..) method working similarly to expand_expr(..).

Related

Is it possible for a macro to turn an identifier lowercase? [duplicate]

This question already has answers here:
Is it possible to modify the case of a token inside of a macro?
(2 answers)
Closed 2 years ago.
Is it possible to generate a symbol or identifier in a Rust macro
from a string? Or to perform string-like operations on a identifier?
I wanted to generate a method given a symbol, but need to downcase it to
obtain the method name.
get!(B);
// should expand to
fn b() -> B {
// method body
}
It's easy to get close...
macro_rules! get {
($kind:ident, $method:ident)
=>
{
fn $method() -> $kind {
// method body
}
}
}
get!(B, b)
But dissatisfying.
I just wrote a procedural macro (casey) to do this.
#![feature(proc_macro_hygiene)]
use casey::lower;
lower!(B); // would render as `b`
Update
proc_macro_hygiene is stable as of rust 1.45.0, so no longer requires nightly.
The previous answers are all correct; standard declarative macros can't do this, and you can drop to procedural macros instead. However, a simpler alternative to procedural macros (especially if, like myself, that's an area of the language you haven't delved into yet) is dtolnay's paste crate.
An example from those docs:
use paste::paste;
paste! {
// Defines a const called `QRST`.
const [<Q R S T>]: &str = "success!";
}
fn main() {
assert_eq!(
paste! { [<Q R S T>].len() },
8,
);
}
Case conversion is also supported, e.g. [<ld_ $reg:lower _expr>]
No, there isn't a macro that can perform this sort of string manipulation on identifiers.
It is possible to create such a macro in the compiler, but it doesn't seem to be a popular need; today only the experimental concat_idents! comes anything close to this (i.e. string-like operations for identifiers).
Your workaround is currently the only available solution.

Adding classes to micropython module

In reference to adding module in micropython, I was trying to create a class which has a local method. In the documentation it is given how to add local methods and that the first argument should be of mp_obj_t type which is the data struct itself. However, I was asking how can I pass extra parameters like other methods? I tried using mp_obj_t * args as second argument but STATIC MP_DEFINE_CONST_FUN_OBJ_1 gives error. I tried the same with STATIC MP_DEFINE_CONST_FUN_OBJ_VAR but it does not support passing mp_obt_t as first argument as STATIC MP_DEFINE_CONST_FUN_OBJ_VAR needs an int. I am quite new, so I was asking how to add methods to classes which can accept arguments?
You need MP_DEFINE_CONST_FUN_OBJ_2, since you have 2 arguments.
Something like
STATIC mp_obj_t my_class_func(mp_obj_t self, mp_obj_t arg) {
if (MP_OBJ_IS_SMALL_INT(lhs)) {
const mp_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(arg);
//...
} else {
//oops, not an int
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(my_class_func_obj, my_class_func);
The best source of samples like this is the source code btw.
To eleaborate on #stijn answer ~ when creating a class, all the MP_DEFINE_CONST_FUN_OBJ_XXXXXX defines work the exact same as they would if you weren't creating a class. The only difference is the first argument of ACTUAL arguments will always refer to self
Here's an example:
mp_obj_t Class_method(mp_uint_t n_args, const mp_obj_t *args) { ... }
That is the standard candidate for:
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(Class_method_obj, 1, 3, Class_method);
However, in this case args[0] will be self.
Let's have another example.
mp_obj_t Class_method(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { ... }
That's a prime candidate for this define
MP_DEFINE_CONST_FUN_OBJ_KW(Class_method_obj, 2, Class_method);
The only difference in this case is that the first index of allowed_args needs to automatically be handled as self. Nothing about how you do these things changes, except now the first ACTUAL argument (ie not including n_args or any other "helper" argument) needs to automatically be considered as self. That being said, you will NEVER use MP_DEFINE_CONST_FUN_OBJ_0 with a class method. '_0' means "zero arguments" and a class method will never have zero arguments because it will ALWAYS at least have self. This also means that you have to add one to however many expected arguments you have on the python end. If your python version accepts 3 arguments ~
(red, green, blue)
then your C_MODULE define has to start at 4 because it's going to get
(self, red, green, blue)

Can macros expand array/vector into multiple indexed arguments?

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.

Xtext, Xbase: infer questions

I'm going to write an inferrer for my dsl and I have some questions that I could not solve with only the help of documentation.
First one:
I need to create static void main() from a feature: how can I add static with .toMethod()?
Second one:
Suppose I have a rule in my dsl like this:
Sequence:
'SEQ' name=ID '{'
statements+=Statement*
'}'
;
Where Statement:
Statement:
Sequence | others...
;
Sequence must be mapped to a void method and the body of that method is composed from the traslation of statements.
But the problem is this: when inside a Sequence I'll find another Sequence I have to create a method for the new sequence and add a call in super sequence.
For example:
SEQ first {
instructions...
SEQ second {
other instructions....
}
instructions...
}
Must generate:
void first(){
instructions(translated)...
second();
instructions(translated)...
}
void second(){
other instructions(translated)...
}
Is it possible to realize it?
First question:
ctx.toMethod('main', ctx.newTypeRef(Void.Type)) [
static = true
….
]
Second question:
Implying that with 'instructions' you mean instances of 'XExpression', you need to trick a bit, as it is currently not possible to compose new expressions during inference.
What you coudl basically do is to make your Sequence a subtype of XExpression. Then during JvmModelInference you need to walk over your expression tree (Statement) and create methods for Sequences. you need to override the XbaseTypeComputer as well as the XbaseCompiler and add type computation and compile strategies for your expressions. The latter would be a call to the method created during inference.

; expected but <place your favourite keyword here> found

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
}