Rascal AST visit access annotation - rascal

Ok, so I would like to access a node's annotations when I visit it. To give an example:
visit (myAST) {
case someNode(str name): {
// How do I now access the #src annotation of someNode here?
}
};
I have already tried the following but this does not work:
visit (myAST) {
case someNode(str name): {
parents = getTraversalContext();
iprintln(parents[0]); // This print shows someNode with the #src annotation.
iprintln(parents[0]#src); // This gives the error: get-annotation not supported on value at...
}
};
What am I doing wrong here? Is my approach wrong?

Good question, the best way to do this is to introduce a variable, say sn in the pattern and to use that to fetch the annotation
visit (myAST) {
case sn:someNode(str name): {
// Access the #src annotation of someNode here by sn#src
}
};
As a side note: you use the function getTraversalContext but I strongly advice you to avoid it since it is experimental and will very likely change in the future. Admitted: we should have marked it as such.

Related

Analyzer package - How to recursively search in the results of parseDartFile()

Currently trying to understand 'analyzer' package, because I need to analyze and edit .dart file from another file (maybe it's a terrible idea).
I think I understand how to go deep into the childEntities tree.
But can't understand how to search in it.
I mean, theoretically I can write a recursive search that will find me a class named "FindABetterSolution". But is there a built in method for that?
What I'm trying to do:
var file = parseDartFile("test.dart");
file.childEntities.forEach((SyntacticEntity entity) {
if(entity is AstNode) {
//then it has its own child nodes which can be AstNode-s or Tokens.
} else if(entity is Token) {
Token token = entity;
print("${token.lexeme} ${token.type} ${token.runtimeType} ${token.keyword}");
//this will output "class KEYWORD KeywordToken CLASS" for "class" in "class MyClass {"
}
});
//I need a way to find certain functions/classes/variables/methods e.t.c.
var myClassNode = file.searchClass("MyClass", abstract: false);
var myMethod = myClassNode.searchMethod("myMethod", static: true);
var globalFunction = file.searchFunction("myFunc", returns: "bool");
UPD: Ok, I think I found a way to search and replace nodes. But how to insert new node after/before another?
You can call file.accept() or file.visitChildren() with a RecursiveAstVisitor that implements visitClassDeclaration, visitMethodDeclaration, or visitFunctionDeclaration.

Display template not called if TypeConverter exists

As soon as I register a TypeConverter for a complex type, it fails to load the correct (base type) display template for properties of a derived type, i.e., #Html.DisplayFor(m => m.My_Derived_ComplexTypeProp) fails to load the MyComplexType display template.
I've debugged the display template selection logic a little bit, and the problem seems to be very obvious:
// From TemplateHelpers:
internal static IEnumerable<string> GetViewNames(ModelMetadata metadata, params string[] templateHints)
{
[...]
yield return fieldType.Name; // TRY 1: Type, but no base type walking
if (!(fieldType == typeof (string))) // YEP ...
{
if (!metadata.IsComplexType) // Unfortunately YEP (see below...)
{
if (fieldType.IsEnum) // NOPE
yield return "Enum";
else if (fieldType == typeof (DateTimeOffset)) // NOPE
yield return "DateTime";
yield return "String"; // TRY 2: string => uh oh, string will be found, and we do not use the correct display template.
}
[...]
else
{
[...] // only in here we would have the base type walk
}
[...]
// From ModelMetadata:
public virtual bool IsComplexType
{
get
{
// !!! !!! WTF !!! !!!:
// Why is IsComplexType returning false if we cannot convert from string?
return !TypeDescriptor.GetConverter(this.ModelType).CanConvertFrom(typeof (string));
}
}
As soon as the logic detects "no complex type" it simply checks for enumerations, DateTimes and returns the template for string otherwise! But look at the implementation of IsComplexType -> if convertible to string it is treated like a simple type!
So, of course, as soon as you register a type converter for a complex type, the display template resolution fails to use the correct template.
Is there a known workaround? I cannot believe, I'm one of the few people running into this until now...
I have found Cannot use TypeConverter and custom display/editor template together?, however, the "solution" which is marked as answer, is not really a solution. It just hackarounds the problem...

Factory in Swift using Generic Types

I'm trying to achieve the following in Swift - I want to pass in a type to a generic "get" function, and based on that type and the parameter, use different repositories to get back a class.
I recognize this is a bit strange to do in this way, but it would save me a lot of time and allow me to more properly refactor something later.
Here is the code but it compile errors on the Foo1Repository and Foo2Repository lines "Cannot convert the type of Foo1Repository to T".
Basically Foo1Repository should return a Foo1, which inherits from BaseEntity of course (and the same is true for Foo2)
class func Get<T: BaseEntity>(id: Int) -> T
{
if (T is Foo1) {
return Foo1Repository.Get(id)
}
else if (T == Foo2) {
return Foo2Repository.Get(id)
}
return T()
}
I was hoping to invoke this function by doing:
let foo = FactoryClass.Get<Foo1>(1)
I understand immediately you would ask "why not just call the appropriate repository, i.e."
let foo = Foo1Repository.Get(1)
and you're all set! No need for some weird factory pattern here.
Let's just say at the moment I need to try to do it above without a lot of refactoring of some code I inherited. I'll get back to planning a proper refactor later.
So I've tried a combination of things but still can't seem to get past the compiler errors. Is something like this possible, or do I need to just bite the bullet and go a different route? Thanks so much!
So I figured it out! I wanted to share the answer so others can see how to do this. Hopefully it will help.
func Get<T: BaseEntity>(id: Int) -> T
{
if (T.self == Foo1.self) {
return Foo1Repository.Get() as! T
}
else if (T.self == Foo2.self) {
return Foo2Repository.Get() as! T
}
...
return T()
}
So you can see, the whole as! T at the end was key. Also == instead of is for type checks.

Is there a way to dynamically call a method or set an instance variable in a class in Dart?

I would want to be able to do something like this with a Dart class constructor:
class Model {
// ... setting instance variables
Model(Map fields) {
fields.forEach((k,v) => this[k] = v);
}
}
Obviously, this doesn't work, because this doesn't have a []= method.
Is there a way to make it work or is it simply not "the dart way" of doing things? If it's not, could you show me what would be the right way to tackle this?
You can use Mirrors:
InstanceMirror im = reflect(theClassInstance);
im.invoke('methodName', ['param 1', 2, 'foo']).then((InstanceMirror value) {
print(value.reflectee); // This is the return value of the method invocation.
});
So, in your case you could do this (since you have setters):
import 'dart:mirrors';
class Model {
Model(Map fields) {
InstanceMirror im = reflect(this);
fields.forEach((k, v) => im.setField(k, v)); // or just fields.forEach(im.setField);
}
}
The documentation for InstanceMirror might come in handy.
Currently no. You will have to wait for reflection to arrive in Dart before something like this (hopefully) becomes possible. Until then your best bet is probably to do it in a constructor. Alternatively you could try to use something like JsonObject which allows you to directly initialize it from a Map (for an explanation on how this works, check this blog post).

Grails Property Expression instead of Domain Object in Web Flow?

We are currently trying to build some stuff with Grails Web Flows.
We are setting an object in the Flow (using flow.objectName = objectInstance), but when we try to access it in the next step of the Flow (using flow.objectName), the Object is not set, but instead there is a org.codehaus.groovy..... .PropertyExpression, that has none of the methods we want to use.
The Code we used to set and get works in other cases, and we cannot find any differences.
What is a Property Expression?
What are we doing wrong, any clues or Problems that happen often with Webflows?
Thank you in advance for your time.
Make sure your Webflow DSL syntax is correct.
For example
def someFlow = {
eventAction {
flow.value = someValue // This is incorrect
action {
flow.value = someValue // This is correct
}
on("success").to "eventDisplay"
}
eventDisplay {
on("finish").to "end"
flow.anotherValue = somethingElse // This usually causes the behavior you are seeing.
// Proper way of setting flow.anotherValue
on("finish2") {
flow.anotherValue = somethingElse
}.to "end"
}
end{}
}

Resources