Removing CST branch during visit - rascal

I have a syntax containing this expression: {Binding ","}+
At some points, I would like to remove Binding based on their value. Is there a simple way of doing this inside a visit expression?

Yes, if you use concrete syntax matching, it will be something like the following:
In this case we are removing the last binding:
visit (myProgram) {
case (Expression) `let <{Binding ","}+ otherBindings>, <Binding myBinding> in <Expression e>`
=> (Expression) `let <{Binding ","}+ otherBindings> in <Expression e>`
}
You could also remove the first binding:
visit (myProgram) {
case (Expression) `let <Binding myBinding>, <{Binding ","}+ otherBindings> in <Expression e>`
=> (Expression) `let <{Binding ","}+ otherBindings> in <Expression e>`
}
I expect the pattern match for myBinding to have more details, or you have a when clause or something to decide if and when to remove the binding.
Or one in the middle:
visit (myProgram) {
case (Expression) `let <{Binding ","}+ firstThese>, <Binding myBinding>, <{Binding ","}+ thenOthers> in <Expression e>`
=> (Expression) `let <{Binding ","}+ firstThese>, <{Binding ","}+ theOthers> in <Expression e>`
}
Rascal takes care of removing the additional separator commas where necessary.
Note that all the types in the patterns will become optional in the near future, and you'd write:
{Binding ","}+ bs1, bs2;
Binding myBinding;
visit (myProgram) {
case (Expression) `let <bs1>, <myBinding>, <bs2> in <Expression e>`
=> (Expression) `let <bs1>, <bs2> in <Expression e>`
}

Related

FParsec Not Recognizing a Type’s Constructor

The following top-level XML parser definition returns the error The value or constructor ‘TOP_LEVEL_RECORD’ is not defined. …
let xTop_Level, xTop_Level_Ref = createParserForwardedToRef<TOP_LEVEL_RECORD, unit>()
do xTop_Level_Ref :=
pipe4
(opt xDeclaration)
(opt (many xComment_or_CData))
xElement
(opt (many xComment_or_CData))
(fun decl before_root root after_root
-> {Declaration = decl
Before_Root = before_root
Root = root
After_Root = after_root}) |>> TOP_LEVEL_RECORD
// This returns the error -------------------→^^^^^^^^^^^^^^^^
TOP_LEVEL_RECORD is defined as …
type TOP_LEVEL_RECORD = {Declaration : XDECLARATION option
Before_Root : COMMENTS_OR_CDATA list option
Root : XELEMENT
After_Root : COMMENTS_OR_CDATA list option
}
The parsers xDeclaration, xCommentor_Cdata, and xElement are all correctly defined and return the corresponding types in the TOP_LEVEL_RECORD.
The let xTop_Level, xTop_Level_Ref = createParserForwardedToRef<TOP_LEVEL_RECORD, unit>() is Fparsec’s syntax for recursive parser calls documented here: http://www.quanttec.com/fparsec/tutorial.html#parsing-json.createParserForwardedToRef-example.
If I define the type type TOP_LEVEL = TOP_LEVEL_TYPE of TOP_LEVEL_RECORD and replace TOP_LEVEL_RECORD with TOP_LEVEL and TOP_LEVEL_TYPE as follows …
let xTop_Level, xTop_Level_Ref = createParserForwardedToRef<TOP_LEVEL, unit>()
// Replaced this text ------------------------------------->^^^^^^^^^
do xTop_Level_Ref :=
pipe4
(opt xDeclaration)
(opt (many xComment_or_CData))
xElement
(opt (many xComment_or_CData))
(fun decl before_root root after_root
-> {Declaration = decl
Before_Root = before_root
Root = root
After_Root = after_root}) |>> TOP_LEVEL_TYPE
// Replaced this text ----------------------->^^^^^^^^^^^^^^
... the code compiles without any errors or warnings.
Why does TOP_LEVEL_TYPE have a constructor here and not TOP_LEVEL_RECORD?
Can you point me to the relevant part of the F# or FParsec documentation?
TOP_LEVEL_RECORD (a record type) and TOP_LEVEL (a union type) are type names and cannot be used as constructors.
To construct a TOP_LEVEL_RECORD you use the syntax as in your code
{ Declaration = decl
Before_Root = before_root
Root = root
After_Root = after_root }
To construct an instance of a union type, you use one of the case names as a constructor function; TOP_LEVEL_TYPE in your case, since there's only one union case.
Note that in your type definition
type TOP_LEVEL = TOP_LEVEL_TYPE of TOP_LEVEL_RECORD
TOP_LEVEL is a type, but TOP_LEVEL_TYPE (despite its name) is not a type, but a constructor function for the TOP_LEVEL type.
So record types do not have named constructor functions, but union types do.
For your code, you can just skip the |>> TOP_LEVEL_RECORD part.
You can read about record types and union types in F# language spec, sections 8.4 and 8.5.

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.)
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.

Pattern matching on Parsers Success In Scala

I'm new to Scala, and have been trying to use its excellent combinator parser library. I've been trying to get this code to compile:
import scala.util.parsing.combinator._
...
val r:Parsers#ParseResult[Node] = parser.parseAll(parser.suite,reader)
r match {
case Success(r, n) => println(r)
case Failure(msg, n) => println(msg)
case Error(msg, n) => println(msg)
}
...
But I keep getting these errors:
TowelParser.scala:97: error: not found: value Success
case Success(r, n) => println(r)
^
TowelParser.scala:98: error: not found: value Failure
case Failure(msg, n) => println(msg)
TowelParser.scala:99: error: object Error is not a case class constructor, nor does it have an unapply/unapplySeq method
case Error(msg, n) => println(msg)
I've tried lots of different things like:
case Parsers#Success(r, n) => println(r)
and
case Parsers.Success(r, n) => println(r)
and
import scala.util.parsing.combinator.Parsers.Success
But I can't seem to get this to compile. I'm sure there's probably something obvious I'm missing, but I've been at it for a while, and google doesn't seem to have any good examples of this.
Thanks!
You need to specify the full path for the ParseResult, which includes your Parsers instance. For example:
import scala.util.parsing.combinator._
object parser extends RegexParsers { def digits = "\\d+".r ^^ (_.toInt) }
val res = parser.parseAll(parser.digits, "42")
res match {
case parser.Success(r, n) => println(r)
case parser.Failure(msg, n) => println(msg)
case parser.Error(msg, n) => println(msg)
}
Note that you could also import these if you want a little extra syntactic convenience:
import parser.{ Error, Failure, Success }
Now your original version will work as expected.

Erlang: join two tables not on equality pattern

Is there a way to implement
SELECT *
FROM pattern p
JOIN tag t ON t.tag LIKE CONCAT(p.pattern, '%') AND t.type = p.type
in terms of erlang qlc on top of two ets:
[{{Pattern, Type}, Id}]
[{{Tag, Type}, Id}]
?
I. e. inequality pattern meaning Tag begins with Pattern and Type = Type.
Thanks in advance.
Pretty simple:
1> ets:new(a,[named_table]),[ets:insert(a,X) || X<-[{{"foo", bar},12},{{"baz", quux},11}]].
[true,true]
2> ets:new(b,[named_table]),[ets:insert(b,X) || X<-[{{"foobar", bar},12},{{"bazquux", quux},11},{{"fooxxx", bar},1},{{"bazbaz", baz},11}]].
[true,true,true,true]
3> qlc:e(qlc:q([{Pattern, Type1, Tag, Id1, Id2} || {{Pattern, Type1}, Id1} <- ets:table(a), {{Tag, Type2}, Id2} <- ets:table(b), Type1 =:= Type2, lists:prefix(Pattern, Tag)])).
[{"baz",quux,"bazquux",11,11},
{"foo",bar,"foobar",12,12},
{"foo",bar,"fooxxx",12,1}]

Case issue in erlang

Working with Erlang's case, I'm facing a problem. The problem is the following:
other languages:
switch(A)
{
case "A" : case "B" :
//do something
break;
}
So, how to achieve the same thing using Erlang? Because sometimes it is very important to put conditions like these, to avoid overhead.
May be guards are what you want.
the_answer_is(N) when A == "A"; A == "B";
; - is OR
, - is AND
You can use case expressions in Erlang. The syntax is:
case Expression of
Pattern1 [when Guard1] -> Expr_seq1;
Pattern2 [when Guard2] -> Expr_seq2;
...
end
To quote Pragmatic Erlang:
case is evaluated as follows. First,
Expression is evaluated; assume this
evaluates to Value. Thereafter, Value
is matched in turn against Pattern1
(with the optional guard Guard1),
Pattern2, and so on, until a match is
found. As soon as a match is found,
then the corresponding expression
sequence is evaluated—the result of
evaluating the expression sequence is
the value of the case expression. If
none of the patterns match, then an
exception is raised.
An example:
filter(P, [H|T]) ->
case P(H) of
true -> [H|filter(P, T)];
false -> filter(P, T)
end;
filter(P, []) ->
[].
filter(P , L); returns a list of all those elements X in L for which P(X) is true. This can be written using pattern matching, but the case construct makes the code cleaner. Note that choosing between pattern matching and case expressions is a matter of taste, style and experience.
Not my favorite style, but you can do something like:
case A of
_ when A == "A";
A == "B" -> do_ab();
_ when A == "C";
_ when A == "D" -> do_cd();
_ -> do_default()
end.

Resources