Interpolation in Concrete Syntax Matching - rascal

I'm working with a Java 8 grammar and I want to find occurrences of a method invocation, more specifically it.hasNext(), when it is an Iterator.
This works:
visit(unit) {
case (MethodInvocation)`it . <TypeArguments? ta> hasNext()`: {
println("found");
}
}
Ideally I would like to match with any identifier, not just it.
So I tried using String interpolation, which compiles but doesn't match:
str iteratorId = "it";
visit(unit) {
case (MethodInvocation)`$iteratorId$ . <TypeArguments? ta> hasNext()`: {
println("achei");
}
}
I also tried several other ways, including pattern variable uses (as seen in the docs) but I can't get this to work.
Is this kind of matching possible in rascal? If yes, how can it be done?

The answer specifically depends on the grammar you are using, which I did not look up, but in general in concrete syntax fragments this notation is used for placeholders: <NonTerminal variableName>
So your pattern should look something like the following:
str iteratorId = "it";
visit(unit) {
case (MethodInvocation)`<MethodName name>.<TypeArguments? ta>hasNext()`:
if (iteratorId == "<name>") println("bingo!");
}
That is assuming that MethodName is indeed a non-terminal in your Java8 grammar and part of the syntax rule for method invocations.

Related

Writing a parser for a Scheme EBNF Grammar

I'm currently writing my own compiler for a scheme subset and have issues with my own recursive descent parser for the grammar. I'm using the chez scheme grammar found here: https://www.scheme.com/tspl2d/grammar.html. The issues come from the asterisks und plus signs. Since asterisks basically mean epsilon rules, I would either need to check if the following token is legal or allow the called non-terminal method to fail and return nothing. I took the second approach and use a vector to save tokens that possibly need to be restored.
Example:
Note: The code to build the AST is still missing
bool Parser::definition() {
if (variableDefinition()){
consumeTT(); // consumeTemporaryTokens
return true;
}
if (derivedDefinition()){
consumeTT();
return true;
}
if (checkNext(Tag::LPAR)) {
if (checkNext(Tag::BEGIN)) {
while (definition())
;
consumeTT();
return true;
}
}
restoreTT(); //restoreTemporaryTokens
return false;
}
Is this the right approach? And how am I supposed to handle Errors now, since basically any rule can fail?

Swift `in` keyword meaning?

I am trying to implement some code from parse.com and I notice a keyword in after the void.
I am stumped what is this ? The second line you see the Void in
PFUser.logInWithUsernameInBackground("myname", password:"mypass") {
(user: PFUser?, error: NSError?) -> Void in
if user != nil {
// Do stuff after successful login.
} else {
// The login failed. Check error to see why.
}
}
The docs don't document this. I know the in keyword is used in for loops.
Anyone confirm?
In a named function, we declare the parameters and return type in the func declaration line.
func say(s:String)->() {
// body
}
In an anonymous function, there is no func declaration line - it's anonymous! So we do it with an in line at the start of the body instead.
{
(s:String)->() in
// body
}
(That is the full form of an anonymous function. But then Swift has a series of rules allowing the return type, the parameter types, and even the parameter names and the whole in line to be omitted under certain circumstances.)
Closure expression syntax has the following general form:
The question of what purpose in serves has been well-answered by other users here; in summary: in is a keyword defined in the Swift closure syntax as a separator between the function type and the function body in a closure:
{ /parameters and type/ in /function body/ }
But for those who might be wondering "but why specifically the keyword in?", here's a bit of history shared by Joe Groff, Senior Swift Compiler Engineer at Apple, on the Swift forums:
It's my fault, sorry. In the early days of Swift, we had a closure
syntax that was very similar to traditional Javascript:
func (arg: -> Type, arg: Type) -> Return { ... }
While this is nice and regular syntax, it is of course also very bulky
and awkward if you're trying to support expressive functional APIs,
such as map/filter on collections, or if you want libraries to be able
to provide closure-based APIs that feel like extensions of the
language.
Our earliest adopters at Apple complained about this, and mandated
that we support Ruby-style trailing closure syntax. This is tricky to
fit into a C-style syntax like Swift's, and we tried many different
iterations, including literally Ruby's {|args| } syntax, but many of
them suffered from ambiguities or simply distaste and revolt from our
early adopters. We wanted something that still looked like other parts
of the language, but which could be parsed unambiguously and could
span the breadth of use cases from a fully explicit function signature
to extremely compact.
We had already taken in as a keyword, we couldn't use -> like Java
does because it's already used to denote the return type, and we were
concerned that using => like C# would be too visually confusing. in
made xs.map { x in f(x) } look vaguely like for x in xs { f(x) },
and people hated it less than the alternatives.
*Formatting and emphasis mine. And thanks to Nikita Belov's post on the Swift forums for helping my own understanding.

How to access the methods for a higher rule?

During writing validation rules a came across the problem that I need some content from a rule in my grammar which is hierarchically higher than the one I pass to my validationMethod.
I know that I can refer to a "higher" rule with .eContainer but then I don't have a clue how to access the values I want to.
For example I have the following grammar snippet:
rule1:
name=ID content=rule2
;
rule2:
<<whatever content>>
;
If I have a normal validationMethod with the argument rule1 then I can access the name via .name but when I give rule2 as an argument and then referring to rule via .eConatiner the .name method does not exist.
Greetings Krzmbrzl
EObject is the root class of all AST node classes. It comes from the EMF Ecore framework which is used by Xtext to generate the AST implementation. Therefore, the EObject class contains a lot of the tree structure features, e.g., iterating through a tree. The EObject.eContainer() method returns an element of type EObject which actually is the super type of the type of the actual returned object. To get access to methods of the next higher element, you have to cast the eContainers methods result like this:
#Check
public void check(rule2 r2) {
EObject o = r2.eContainer();
rule1 r1 = (rule1) o;
String r1Name = r1.getName();
}
If the type of the parent object is ambigous, you should test whether the actual type is the expected with an instanceof expression:
#Check
public void check(rule2 r2) {
EObject o = r2.eContainer();
if (o instanceof rule1) {
rule1 r1 = (rule1) o;
String r1Name = r1.getName();
}
}
Xtend provide the same instanceof-expression like Java. But if the object to be checked definetly can have more then a few types, you can use Xtends really powerful switch expression. It supports so called type guards. You can switch over any object and instead of case value: guards simply write the a concrete type:
switch (anyAbstractTypeObject) {
ConcreteSubtypeA: {...}
ConcreteSubtypeB: {...}
}
This is an elegant shorthand if-instanceof-eleseif-... in Xtend.

writing a function to do type cast

I'm trying to write a function that does type casting, which seems to be a frequently occurring activity in Rascal code. But I can't seem to get it right. The following and several variations on it fail.
public &T cast(type[&T] tp, value v) throws str {
if (tp tv := v)
return tv;
else
throw "cast failed";
}
Can someone help me out?
Some more info: I frequently use pattern matching against a pattern of the form "Type Var" (i.e. against a variable declaration) in order to tell Rascal that an expression has a certain type, e.g.
map[str,value] m := myexp
This is usually in cases where I know that myexp has type map[str,value], but omitting the matching would make Rascal's type checking mechanism complain.
In order to be a bit more defensive against mistakes, I usually wrap the matching construct in an if-then-else where an exception is raised if the match fails:
if (map[str,value] m := myexp) {
// use m
} else {
throw "cast failed";
}
I would like to shorten all such similar pieces of code using a single function that does the job generically, so that I can write instead
cast(#map[str,value], myexp)
PS. Also see How to cast a value type to Map in Rascal?
It seems that the best way to write this, if you truly need to do this, is the following:
public map[str,value] cast(map[str,value] v) = v;
public default map[str,value] cast(value v) { throw "cast failed!"; }
Then you could just say
m = cast(myexp);
and it would do what you want to do -- the actual pattern matching is moved into the function signature for cast, with a case specific to the type you are wanting to use and a case that handles everything that doesn't otherwise match.
However, I'm still not sure why you are using type value, either here (inside the map) or in the linked question. The "standard" Rascal way of handling cases where you could have one of multiple choices is to define these with a user-defined data type and constructors. You could then use pattern matching to match the constructors, or use the is and has keywords to interrogate a value to check to see if it was created using a specific constructor or if it has a specific field, respectively. The rule for fields is that all occurrences of a field in the constructor definitions for a given ADT have the same type. So, it may help to know more about your usage scenario to see if this definition of cast is the best option or if there is a better solution to your problem.
EDITED
If you are reading JSON, an alternate way to do it is to use the JSON grammar and AST that also live in that part of the library (I think the one you are using is more of a stream reader, like our current text readers and writers, but I would need to look at the code more to be sure). You can then do something like this (long output included to give an idea of the results):
rascal>import lang::json::\syntax::JSON;
ok
rascal>import lang::json::ast::JSON;
ok
rascal>import lang::json::ast::Implode;
ok
ascal>js = buildAST(parse(#JSONText, |project://rascal/src/org/rascalmpl/library/lang/json/examples/twitter01.json|));
Value: object((
"since_id":integer(0),
"refresh_url":string("?since_id=202744362520678400&q=amsterdam&lang=en"),
"page":integer(1),
"since_id_str":string("0"),
"completed_in":float(0.058),
"results_per_page":integer(25),
"next_page":string("?page=2&max_id=202744362520678400&q=amsterdam&lang=en&rpp=25"),
"max_id_str":string("202744362520678400"),
"query":string("amsterdam"),
"max_id":integer(202744362520678400),
"results":array([
object((
"from_user":string("adekamel"),
"profile_image_url_https":string("https:\\/\\/si0.twimg.com\\/profile_images\\/2206104506\\/339515338_normal.jpg"),
"in_reply_to_status_id_str":string("202730522013728768"),
"to_user_id":integer(215350297),
"from_user_id_str":string("366868475"),
"geo":null(),
"in_reply_to_status_id":integer(202730522013728768),
"profile_image_url":string("http:\\/\\/a0.twimg.com\\/profile_images\\/2206104506\\/339515338_normal.jpg"),
"to_user_id_str":string("215350297"),
"from_user_name":string("nurul amalya \\u1d54\\u1d25\\u1d54"),
"created_at":string("Wed, 16 May 2012 12:56:37 +0000"),
"id_str":string("202744362520678400"),
"text":string("#Donnalita122 #NaishahS #fatihahmS #oishiihotchoc #yummy_DDG #zaimar93 #syedames I\'m here at Amsterdam :O"),
"to_user":string("Donnalita122"),
"metadata":object(("result_type":string("recent"))),
"iso_language_code":string("en"),
"from_user_id":integer(366868475),
"source":string("<a href="http:\\/\\/blackberry.com\\/twitter" rel="nofollow">Twitter for BlackBerry\\u00ae<\\/a>"),
"id":integer(202744362520678400),
"to_user_name":string("Rahmadini Hairuddin")
)),
object((
"from_user":string("kelashby"),
"profile_image_url_https":string("https:\\/\\/si0.twimg.com\\/profile_images\\/1861086809\\/me_beach_normal.JPG"),
"to_user_id":integer(0),
"from_user_id_str":string("291446599"),
"geo":null(),
"profile_image_url":string("http:\\/\\/a0.twimg.com\\/profile_images\\/1861086809\\/me_beach_normal.JPG"),
"to_user_id_str":string("0"),
"from_user_name":string("Kelly Ashby"),
"created_at":string("Wed, 16 May 2012 12:56:25 +0000"),
"id_str":string("202744310872018945"),
"text":string("45 days til freedom! Cannot wait! After Paris: London, maybe Amsterdam, then southern France, then CANADA!!!!"),
"to_user":null(),
"metadata":object(("result_type":string("recent"))),
"iso_language_code":string("en"),
"from_user_id":integer(291446599),
"source":string("<a href="http:\\/\\/mobile.twitter.com" rel="nofollow">Mobile Web<\\/a>"),
"id":integer(202744310872018945),
"to_user_name":null()
)),
object((
"from_user":string("johantolsma"),
"profile_image_url_https":string("https:\\/\\/si0.twimg.com\\/profile_images\\/1961917557\\/image_normal.jpg"),
"to_user_id":integer(0),
"from_user_id_str":string("23632499"),
"geo":null(),
"profile_image_url":string("http:\\/\\/a0.twimg.com\\/profile_images\\/1961917557\\/image_normal.jpg"),
"to_user_id_str":string("0"),
"from_user_name":string("Johan Tolsma"),
"created_at":string("Wed, 16 May 2012 12:56:16 +0000"),
"id_str":string("202744274050236416"),
"text":string("RT #agerolemou: Office space for freelancers in Amsterdam http:\\/\\/t.co\\/6VfHuLeK"),
"to_user":null(),
"metadata":object(("result_type":string("recent"))),
"iso_language_code":string("en"),
"from_user_id":integer(23632499),
"source":string("<a href="http:\\/\\/itunes.apple.com\\/us\\/app\\/twitter\\/id409789998?mt=12" rel="nofollow">Twitter for Mac<\\/a>"),
"id":integer(202744274050236416),
"to_user_name":null()
)),
object((
"from_user":string("hellosophieg"),
"profile_image_url_https":string("https:\\/\\/si0.twimg.com\\/profile_images\\/2213055219\\/image_normal.jpg"),
"to_user_id":integer(0),
"from_user_id_str":string("41153106"),
"geo":null(),
"profile_image_url":string("http:\\/\\/a0.twimg.com\\/profile_images\\/2213055219\\/image_normal.jp...
rascal>js is object;
bool: true
rascal>js.members<0>;
set[str]: {"since_id","refresh_url","page","since_id_str","completed_in","results_per_page","next_page","max_id_str","query","max_id","results"}
rascal>js.members["results_per_page"];
Value: integer(25)
You can then use pattern matching, over the types defined in lang::json::ast::json, to extract the information you need.
The code has a bug. This is the fixed code:
public &T cast(type[&T] tp, value v) throws str {
if (&T tv := v)
return tv;
else
throw "cast failed";
}
Note that we do not wish to include this in the standard library. Rather lets collect cases where we need it and find out how to fix it in another way.
If you find you need this casting often, then you might be avoiding the better parts of Rascal, such as pattern based dispatch. See also the answer by Mark Hills.

f# keyword use and using

I am trying to use System.Data.Sqlite with F#. In C#, I have code like
using (DbTransaction dbTrans = con.BeginTransaction()) {
using (SQLiteCommand cmd = con.CreateCommand()) {
//blahblah
}
dbTrans.Commit();
}
But in F#, when I use the similiar two using above I got error of the type bool is not compatible with the type IDisposable...
EDIT I am really sorry for my question. use would work in F# case. I just dont know how to close/delete my quesetions.
To add some details - if you need to explicitly mark the scope where command is valid (to get exactly the same behavior as in your C# example, where cmd id disposed of before calling Commit) you can write:
use dbTrans = con.BeginTransaction()
( use cmd = con.CreateCommand()
cmd.BlahBlahBlah() )
dbTrans.Commit()
The scope is just a part of expression where the symbol is defined, so you can make it explicit using parentheses.
using is just an F# function that you could use before special syntax using use was added. Just FYI, the syntax looks like this:
using (con.BeginTransaction()) (fun dbTrans ->
using (con.CreateCommand()) (fun cmd ->
cmd.BlahBlahBlah() )
dbTrans.Commit() )
Writing the code using use is definitely a better idea (but you can define your functions like using to encapsulate more interesting behavior - e.g. transaction).
in f# it's
use dbTrans = new con.BeginTransaction ()
and
use cmd = con.CreateCommand()
these will dispose when your function ends

Resources