Can't access LambdaResolveResult.BodyExpression #40

Closed
opened 2012-04-15 06:33:13 -05:00 by danelkhen · 6 comments
danelkhen commented 2012-04-15 06:33:13 -05:00 (Migrated from github.com)

Marked internal, can't find a different way to access the body of a lambda function. Am I missing something?
Currently, I'm hacking it using reflection, and all data looks ok.

Please help

Marked internal, can't find a different way to access the body of a lambda function. Am I missing something? Currently, I'm hacking it using reflection, and all data looks ok. Please help
dgrunwald commented 2012-04-15 11:11:40 -05:00 (Migrated from github.com)

This is intentional, semantic trees don't have references back to the AST. There is LambdaResolveResult.Body which holds the resolved body.

Most resolve results are not language-specific, but each language has its own AST.
That the class derived from LambdaResolveResult currently does maintain a reference back to the AST is an implementation and may change at any time in the future. In fact it's probably a good idea to null out the reference back to the AST once the resolver is done, so that maintaining a reference to the semantic tree (as we might do in the debugger's interpreter) doesn't keep the whole AST in memory.

This is intentional, semantic trees don't have references back to the AST. There is `LambdaResolveResult.Body` which holds the resolved body. Most resolve results are not language-specific, but each language has its own AST. That the class derived from LambdaResolveResult currently does maintain a reference back to the AST is an implementation and may change at any time in the future. In fact it's probably a good idea to null out the reference back to the AST once the resolver is done, so that maintaining a reference to the semantic tree (as we might do in the debugger's interpreter) doesn't keep the whole AST in memory.
danelkhen commented 2012-04-15 11:15:44 -05:00 (Migrated from github.com)

Hi Daniel, thanks for your reply!

I wanted to use the "Body" property, but as it also documented:
/// Body Returns a resolve result for 'void' for statement lambdas.

So I can't find a way to go deeper in the resolve tree when I reach this
kind of lambda. I also tried using GetDefinitionRegion() to find the
expression ast node back, but it returns an empty region as well.

Dan-el

On Sun, Apr 15, 2012 at 7:11 PM, Daniel Grunwald <
reply@reply.github.com

wrote:

This is intentional, semantic trees don't have references back to the AST.
There is LambdaResolveResult.Body which holds the resolved body.

Most resolve results are not language-specific, but each language has its
own AST.
That the class derived from LambdaResolveResult currently does maintain a
reference back to the AST is an implementation and may change at any time
in the future. In fact it's probably a good idea to null out the reference
back to the AST once the resolver is done, so that maintaining a reference
to the semantic tree (as we might do in the debugger's interpreter) doesn't
keep the whole AST in memory.


Reply to this email directly or view it on GitHub:
https://github.com/icsharpcode/NRefactory/issues/40#issuecomment-5140191

Hi Daniel, thanks for your reply! I wanted to use the "Body" property, but as it also documented: /// Body Returns a resolve result for 'void' for statement lambdas. So I can't find a way to go deeper in the resolve tree when I reach this kind of lambda. I also tried using GetDefinitionRegion() to find the expression ast node back, but it returns an empty region as well. Dan-el On Sun, Apr 15, 2012 at 7:11 PM, Daniel Grunwald < reply@reply.github.com > wrote: > > This is intentional, semantic trees don't have references back to the AST. > There is `LambdaResolveResult.Body` which holds the resolved body. > > Most resolve results are not language-specific, but each language has its > own AST. > That the class derived from LambdaResolveResult currently does maintain a > reference back to the AST is an implementation and may change at any time > in the future. In fact it's probably a good idea to null out the reference > back to the AST once the resolver is done, so that maintaining a reference > to the semantic tree (as we might do in the debugger's interpreter) doesn't > keep the whole AST in memory. > > --- > > Reply to this email directly or view it on GitHub: > https://github.com/icsharpcode/NRefactory/issues/40#issuecomment-5140191
dgrunwald commented 2012-04-15 11:48:11 -05:00 (Migrated from github.com)

You have to look at the original AST for that. For example, you could try building a Dictionary<LambdaResolveResult, LambdaExpression> and fill it by resolving every lambda expression.
Note however that this trick doesn't work in general for mapping ResolveResults to AstNodes, because different AstNodes may resolve to the same ResolveResult instance due to lookup caches.

You have to look at the original AST for that. For example, you could try building a `Dictionary<LambdaResolveResult, LambdaExpression>` and fill it by resolving every lambda expression. Note however that this trick doesn't work in general for mapping ResolveResults to AstNodes, because different AstNodes may resolve to the same ResolveResult instance due to lookup caches.
danelkhen commented 2012-04-15 12:16:31 -05:00 (Migrated from github.com)

Thanks, I understood this concept. The problem is, that sometimes, in
complex statements, the resolve() returns a full hierarchy of results, that
relate to inner AstNodes, and once I start scanning my way in the result
tree, I lose the connection to a certain result. I need a way to resolve
the original AstNode back from a ResolveResult. I mean, this relationship
may not be maintained as a reference, but I'm sure that there is a point in
time in which you have references to both objects (ResolveResult and
AstNode), is there a way for me to store this relationship myself as it
occurs?

The NRefactory library is really an amazing piece of software engineering,
and it works really great, the only problem I found is in the
LambdaExpressions vs. ResolveResults, I'm quite certain that there's a tiny
missing API somewhere that would allow me to use ResolveResult for all
expression nodes recursively, without trying to map back in which AstNode I
actually am.

Any ideas?

Thanks again for your help.

Dan-el

On Sun, Apr 15, 2012 at 7:48 PM, Daniel Grunwald <
reply@reply.github.com

wrote:

You have to look at the original AST for that. For example, you could try
building a Dictionary<LambdaResolveResult, LambdaExpression> and fill it
by resolving every lambda expression.
Note however that this trick doesn't work in general for mapping
ResolveResults to AstNodes, because different AstNodes may resolve to the
same ResolveResult instance due to lookup caches.


Reply to this email directly or view it on GitHub:
https://github.com/icsharpcode/NRefactory/issues/40#issuecomment-5140458

Thanks, I understood this concept. The problem is, that sometimes, in complex statements, the resolve() returns a full hierarchy of results, that relate to inner AstNodes, and once I start scanning my way in the result tree, I lose the connection to a certain result. I need a way to resolve the original AstNode back from a ResolveResult. I mean, this relationship may not be maintained as a reference, but I'm sure that there is a point in time in which you have references to both objects (ResolveResult and AstNode), is there a way for me to store this relationship myself as it occurs? The NRefactory library is really an amazing piece of software engineering, and it works really great, the only problem I found is in the LambdaExpressions vs. ResolveResults, I'm quite certain that there's a tiny missing API somewhere that would allow me to use ResolveResult for all expression nodes recursively, without trying to map back in which AstNode I actually am. Any ideas? Thanks again for your help. Dan-el On Sun, Apr 15, 2012 at 7:48 PM, Daniel Grunwald < reply@reply.github.com > wrote: > > You have to look at the original AST for that. For example, you could try > building a `Dictionary<LambdaResolveResult, LambdaExpression>` and fill it > by resolving every lambda expression. > Note however that this trick doesn't work in general for mapping > ResolveResults to AstNodes, because different AstNodes may resolve to the > same ResolveResult instance due to lookup caches. > > --- > > Reply to this email directly or view it on GitHub: > https://github.com/icsharpcode/NRefactory/issues/40#issuecomment-5140458
dgrunwald commented 2012-04-16 10:27:35 -05:00 (Migrated from github.com)

I'm sure that there is a point in time in which you have references to both objects (ResolveResult and AstNode)

Of course there is: at the end of the Resolve() call. Just call Resolve() for all AstNodes and store the relation yourself. You could also use a custom IResolveVisitorNavigator for that. Just be careful - the relation isn't 1-to-1; there may be resolve results without any AstNode (conversions, intermediate results, etc.), and multiple AstNodes may share the same resolve result (due to member lookup caching, or due to ParenthesizedExpressions having the same result as the contained expression).
However in your special case of LambdaExpressions and LambdaResolveResults, the relation should be 1-to-1. So you could just resolve all LambdaExpressions and AnonymousMethodExpressions and store the result in a Dictionary<ResolveResult, Expression>.

I'm quite certain that there's a tiny missing API somewhere that would allow me to use ResolveResult for all expression nodes recursively

We only have resolve results on the expression level. If we wanted to produce a full tree even for statement lambdas, we would need to add resolve results for all kinds of expressions - about 25 new kinds of resolve results.

> I'm sure that there is a point in time in which you have references to both objects (ResolveResult and AstNode) Of course there is: at the end of the `Resolve()` call. Just call `Resolve()` for all AstNodes and store the relation yourself. You could also use a custom `IResolveVisitorNavigator` for that. Just be careful - the relation isn't 1-to-1; there may be resolve results without any AstNode (conversions, intermediate results, etc.), and multiple AstNodes may share the same resolve result (due to member lookup caching, or due to `ParenthesizedExpression`s having the same result as the contained expression). However in your special case of `LambdaExpression`s and `LambdaResolveResult`s, the relation should be 1-to-1. So you could just resolve all `LambdaExpression`s and `AnonymousMethodExpression`s and store the result in a `Dictionary<ResolveResult, Expression>`. > I'm quite certain that there's a tiny missing API somewhere that would allow me to use ResolveResult for all expression nodes recursively We only have resolve results on the expression level. If we wanted to produce a full tree even for statement lambdas, we would need to add resolve results for all kinds of expressions - about 25 new kinds of resolve results.
danelkhen commented 2012-04-16 15:59:11 -05:00 (Migrated from github.com)

Hi Daniel,

Thank you very much for the info. I think I got it now, although I can't
store the mapping in a dictionary after calling Resolve() - since resolve
returns a tree, but navigator did the trick, it gave me a decision point in
which I can store the mapping myself. There's a bit of overhead in storing
it all in a single dictionary, but since it's open-source, I guess I can
add a 'public object Tag' property on ResolveResult and on AstNode, and
avoid the need for a global dictionary.

Thanks again, this project is truly amazing.

Dan-el

On Mon, Apr 16, 2012 at 6:27 PM, Daniel Grunwald <
reply@reply.github.com

wrote:

I'm sure that there is a point in time in which you have references to
both objects (ResolveResult and AstNode)

Of course there is: at the end of the Resolve() call. Just call
Resolve() for all AstNodes and store the relation yourself. You could
also use a custom IResolveVisitorNavigator for that. Just be careful -
the relation isn't 1-to-1; there may be resolve results without any AstNode
(conversions, intermediate results, etc.), and multiple AstNodes may share
the same resolve result (due to member lookup caching, or due to
ParenthesizedExpressions having the same result as the contained
expression).
However in your special case of LambdaExpressions and
LambdaResolveResults, the relation should be 1-to-1. So you could just
resolve all LambdaExpressions and AnonymousMethodExpressions and store
the result in a Dictionary<ResolveResult, Expression>.

I'm quite certain that there's a tiny missing API somewhere that would
allow me to use ResolveResult for all expression nodes recursively

We only have resolve results on the expression level. If we wanted to
produce a full tree even for statement lambdas, we would need to add
resolve results for all kinds of expressions - about 25 new kinds of
resolve results.


Reply to this email directly or view it on GitHub:
https://github.com/icsharpcode/NRefactory/issues/40#issuecomment-5154767

Hi Daniel, Thank you very much for the info. I think I got it now, although I can't store the mapping in a dictionary after calling Resolve() - since resolve returns a tree, but navigator did the trick, it gave me a decision point in which I can store the mapping myself. There's a bit of overhead in storing it all in a single dictionary, but since it's open-source, I guess I can add a 'public object Tag' property on ResolveResult and on AstNode, and avoid the need for a global dictionary. Thanks again, this project is truly amazing. Dan-el On Mon, Apr 16, 2012 at 6:27 PM, Daniel Grunwald < reply@reply.github.com > wrote: > > > I'm sure that there is a point in time in which you have references to > > both objects (ResolveResult and AstNode) > > Of course there is: at the end of the `Resolve()` call. Just call > `Resolve()` for all AstNodes and store the relation yourself. You could > also use a custom `IResolveVisitorNavigator` for that. Just be careful - > the relation isn't 1-to-1; there may be resolve results without any AstNode > (conversions, intermediate results, etc.), and multiple AstNodes may share > the same resolve result (due to member lookup caching, or due to > `ParenthesizedExpression`s having the same result as the contained > expression). > However in your special case of `LambdaExpression`s and > `LambdaResolveResult`s, the relation should be 1-to-1. So you could just > resolve all `LambdaExpression`s and `AnonymousMethodExpression`s and store > the result in a `Dictionary<ResolveResult, Expression>`. > > > I'm quite certain that there's a tiny missing API somewhere that would > > allow me to use ResolveResult for all expression nodes recursively > > We only have resolve results on the expression level. If we wanted to > produce a full tree even for statement lambdas, we would need to add > resolve results for all kinds of expressions - about 25 new kinds of > resolve results. > > --- > > Reply to this email directly or view it on GitHub: > https://github.com/icsharpcode/NRefactory/issues/40#issuecomment-5154767
This discussion has been locked. Commenting is limited to contributors.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-icsharpcode/NRefactory#40
No description provided.