Search code examples
rascal

Pattern with action for two statements


I'm am trying to match and delete two statements with rascals visit statement. Of course I would also need to check if they are used but in this case, I don't have to worry about that. In the example below, you can see two tmp variabels which are created but not used (this is semi-pseudo Rust code). They are only created as temporary variables and freed. (I have tried to create equivelant in Java but it lost some context in translation like for example the redeclaration of the tmp)

{
    let tmp : c_void = repository as c_void;
    repository = MArray();
    free(tmp);

    let tmp : c_void = where_ as c_void;
    where_ = MArray();
    free(tmp);
}

This is an example of the simplified version of the pattern with action which I have been playing with. With this pattern, I would think that the first free statement would be matched but it apparently is the last one within the scope. I have tried to do this in all kind of ways like statement counters and various different patterns to no success.

visit(crate){
    case (Statements) `let tmp : c_void = <Identifier _> as c_void;
                      '<Statement* stmts>
                      'free(tmp);` =>
         (Statements) `<Statement* stmts>`
}

The final product should look like following:

{
    repository = MArray();

    where_ = MArray();
}

Edit: Progress

I have managed to do what I wanted with the following code (this is still just the semi-pseudo Rust):

crate = innermost visit(crate){
    case (Statements) `let tmp : c_void = <Identifier _> as c_void;
                      '<Statement* stmts>
                      'free(tmp);
                      '<Statement* post_stmts>` =>
         (Statements) `<Statement* stmts>
                      '<Statement* post_stmts>`

    case (Statements) `<Statement* pre_stmts>
                      'let tmp : c_void = <Identifier _> as c_void;
                      '<Statement* stmts>
                      'free(tmp);` =>
         (Statements) `<Statement* pre_stmts>
                      '<Statement* stmts>`
}

This now works for a single scope matching of both tmp instances but it does not expand into other scopes. I'm not sure why it doesn't just continue to match in other scopes despite it using the innermost matching. An example of an if else would be fitting for this. It matches and changes the tmp instances in the if branch but it does not continue into the else branch to also match them there.

Edit: Final

This seems to be solved now. I was wondering if adding another case would help and yes it did. Apparentaly it was not the problem of not reaching the scope but a problem of not matching the contents of the scope. Here is the modified code which works (I had to change the statements names because Rascal complaining about redeclared Statement* names accros cases):

crate = innermost visit(crate){
    case (Statements) `let mut tmp : *mut ::std::os::raw::c_void = <Identifier _> as (*mut ::std::os::raw::c_void);
                      '<Statement* stmts1>
                      'free(tmp);
                      '<Statement* stmts2>` =>
         (Statements) `<Statement* stmts1>
                      '<Statement* stmts2>`

    case (Statements) `<Statement* stmts3>
                      'let mut tmp : *mut ::std::os::raw::c_void = <Identifier _> as (*mut ::std::os::raw::c_void);
                      '<Statement* stmts4>
                      'free(tmp);` =>
         (Statements) `<Statement* stmts3>
                      '<Statement* stmts4>`

    case (Statements) `<Statement* stmts5>
                      'let mut tmp : *mut ::std::os::raw::c_void = <Identifier _> as (*mut ::std::os::raw::c_void);
                      '<Statement* stmts6>
                      'free(tmp);
                      '<Statement* stmts7>` =>
         (Statements) `<Statement* stmts5>
                      '<Statement* stmts6>
                      '<Statement* stmts7>`
}

^ (This example is the actual code an not a semi-pseudo code anymore.)


Solution

  • There is no place holder after the last free(tmp); so the last free(tmp) has to match. May be use a pattern like this:

    `let tmp : c_void = <Identifier _> as c_void;
    '<Statement* stmts1>
    'free(tmp); 
    '<Statement* stmts2>`
    

    I don't know the precise details of your example, but you could give this a try.