Referencing value assigned to variable in statement builder within another statement

Given a statement that does something like:
var expr = new ExpressionBuilder();
expr.AppendVerbatim("var propertyValue = (");
expr.AppendType(field.Type);
expr.AppendVerbatim(")valueType?.GetValue(");
//And so on
var expr = new ExpressionBuilder();
expr.AppendVerbatim("var propertyValue = (");
expr.AppendType(field.Type);
expr.AppendVerbatim(")valueType?.GetValue(");
//And so on
I would like to use the value assigned to propertyValue elsewhere, but of course, I cannot use AppendExpression with it since the context isn't aware it's been assigned. How might I go about referencing this variable value as an expression? Thanks!
Petr Onderka
Petr Onderka291d ago
I think that ExpressionFactory.Parse("propertyValue") should work for you. (It's effectively the same as using ExpressionBuilder and then calling ToExpression() on it.)
Xaniff
Xaniff290d ago
Well, let me put it another way. Say I use the statement builder with the following:
var sampleBuilder = new StatementBuilder();
sampleBuilder.AppendVerbatim("var abc = ");
sampleBuilder.AppendLiteral(123);
sampleBuilder.AppendVerbatim(";");
meta.InsertStatement(sampleBuilder.ToStatement());
var abc = ExpressionFactory.Parse("abc").Value;
var sampleBuilder = new StatementBuilder();
sampleBuilder.AppendVerbatim("var abc = ");
sampleBuilder.AppendLiteral(123);
sampleBuilder.AppendVerbatim(";");
meta.InsertStatement(sampleBuilder.ToStatement());
var abc = ExpressionFactory.Parse("abc").Value;
When I insert the statement via meta.InsertStatement, this doesn't give me a variable I can reference in other parts of the template. The use of ExpressionFactory.Parse on the next line does give me abc to use in the template, but this suddenly can't be used in a compile-time loop as it outputs the following:
var abc = 123;
var abc = abc;

var abc = 123;
var abc_1 = abc;

var abc = 123;
var abc_2 = abc;
var abc = 123;
var abc = abc;

var abc = 123;
var abc_1 = abc;

var abc = 123;
var abc_2 = abc;
I suppose I could do something like:
//Out of the loop
var ii = meta.CompileTime(0);

//In the loop
var sampleBuilder = new StatementBuilder();
sampleBuilder.AppendVerbatim($"var abc{ii} = ");
sampleBuilder.AppendLiteral(123);
sampleBuilder.AppendVerbatim(";");
meta.InsertStatement(sampleBuilder.ToStatement());
var abc = ExpressionFactory.Parse($"abc{ii}").Value;
//Out of the loop
var ii = meta.CompileTime(0);

//In the loop
var sampleBuilder = new StatementBuilder();
sampleBuilder.AppendVerbatim($"var abc{ii} = ");
sampleBuilder.AppendLiteral(123);
sampleBuilder.AppendVerbatim(";");
meta.InsertStatement(sampleBuilder.ToStatement());
var abc = ExpressionFactory.Parse($"abc{ii}").Value;
And then this yields (outside of the apparently bug reported at https://github.com/postsharp/Metalama/issues/202):
var abc0 = 123;
var abc = abc0;

var abc1 = 123;
var abc_1 = abc1;

var abc2 = 123;
var abc_2 = abc2;
var abc0 = 123;
var abc = abc0;

var abc1 = 123;
var abc_1 = abc1;

var abc2 = 123;
var abc_2 = abc2;
Again, since the first variable is more than sufficient for my purposes but is simply inaccessible since it's created by string, might you consider updating the StatementBuilder to include an out variable or the like that I can use to reference the variable on the class instead of this hacky approach resulting in two lines in the output for each assignment (especially since the ExpressionFactory.Parse().Value approach itself yields a unique variable name each time? Thanks!
GitHub
Issues · postsharp/Metalama
Metalama is a Roslyn-based meta-programming framework. Use this repo to report bugs or ask questions. - Issues · postsharp/Metalama
Gael Fraiteur
Gael Fraiteur289d ago
OK I got it. Didn't read your first request properly it seems However generally we want to keep StatementBuilder and ExpressionBuilder as minimalistic as possible. So you want an API that defines a local variable and takes care of the unique naming?
Petr Onderka
Petr Onderka289d ago
If you want to reference the variable you declared, you can do it by declaring var abc = ExpressionFactory.Parse("abc"); and then using abc.Value where you used just abc previously. Alternatively, I wonder if using Builder just for the expression and letting Metalama manage the variable would work better. Let me check. Yeah, I think that would work better for you. For example, this code:
foreach (var i in meta.CompileTime(Enumerable.Range(0, 3)))
{
var sampleBuilder = new ExpressionBuilder();
sampleBuilder.AppendLiteral(123);
var abc = sampleBuilder.ToValue();
Console.WriteLine(abc);
}
foreach (var i in meta.CompileTime(Enumerable.Range(0, 3)))
{
var sampleBuilder = new ExpressionBuilder();
sampleBuilder.AppendLiteral(123);
var abc = sampleBuilder.ToValue();
Console.WriteLine(abc);
}
generates:
var abc = 123;
Console.WriteLine(abc);
var abc_1 = 123;
Console.WriteLine(abc_1);
var abc_2 = 123;
Console.WriteLine(abc_2);
var abc = 123;
Console.WriteLine(abc);
var abc_1 = 123;
Console.WriteLine(abc_1);
var abc_2 = 123;
Console.WriteLine(abc_2);
Xaniff
Xaniff289d ago
I'll see if I can't use that - I suspect I'm going to run into issues along the lines of https://github.com/postsharp/Metalama/issues/202 since this is within several if and foreach loops both run-time and compile-time
GitHub
Bug: Metalama not incrementing in compile-time loop as expected · I...
I'm trying to solve a variable reference issue. Put simply, I have a loop inside a template that enumerates several compile-time values to write several run-time statements. As these are writte...
Petr Onderka
Petr Onderka289d ago
I think you shouldn't, since you wouldn't be modifying any compile-time variables.
Xaniff
Xaniff289d ago
Yeah, unfortunately I think my toy sample there doesn't quite work with what I actually have in place - can't see how to fit that in there. I've got a foreach going through a compile-time dictionary, a foreach inside that going through the values of that kv pair, then a null check on each of those values (compile-time), then a run-time null check (per issue #202 up there) and then inside all that I've got one more equality check and the statement builder. Right now I'm incrementing the meta.CompileTime after the run-time null check but at the bottom of the inner foreach. If not for all my loops already there, I think that'd be a clever fix To your question @the.metalama.guy Yes, that'd be great - an API that lets me simply provide the right side of a statement after the "=" and places its own unique variable name in there so I might trivially reference it anywhere else. Like what I get with expression builder - don't much care what the auto-generated variable name is, so long as it's unique and I can trivially reference it in the rest of the template
Gael Fraiteur
Gael Fraiteur289d ago
I think it's rather going to be a method like: IExpression DefineLocalVariable( string nameHint, IType type, IExpression? assignedValue ); Please file a feature request on GitHub because we don't track tickets here -- just for ephemeral discussions
Xaniff
Xaniff289d ago
Absolutely - I've been thinking about what I'd like it to do, but I'll file a ticket about it in a few Filed under #205
Want results from more Discord servers?
Add your server
More Posts
Specifying generic constraints of compile-time introduced typeI have a TypeAspect that has three attribute arguments when applied to a type. One of these is a `TyStep-through aspect-debuggingI'm sure I've asked this before, but I cannot find the thread in which it was answered (if I actuallCodeLens HelpMetalama is configured in CodeLens, and I have an aspect that has been applied. I am able to right-How to apply an attribute to a method introduced by another aspect?I have an aspect that has a dependency on another aspect. However, I'd like for downstream projects Advising the addition of code commentsUsing Metalama Is there a way to advise adding code comments? For example, when I advise a method Set eligibility to not run against (built-in) methods of record classes or structsI've figured out how to set up an `If` statement for the record types, but I cannot figure out how tHow to specify an IMethod as the callback for an event?I'd like to specify an introduced method on a TypeAspect as the callback for an event handler. 1) WCreate NuGet with MetalamaWith source generators I have to add some MSBuild configuration, but with Metalama it seems I don't Override property with BuildAspectI create exceptions inheriting from Exception and putting the `[BusinessException]` attribute. I waView diff in RiderI don't use Visual Studio, and overall, I don't have Windows. Is there any way to see the source genOverride constructorIs it possible to override a constructor? I want to take my code: ``` public class BusinessExceptiDoes Metalama only support attributes?I navigated in all Metalama documentation, but I want to override a method for all types that inheriCan Metalama suppress compiler errors?Hello! I want to know if I can use Metalama in my library. The users of my library have to declare Eligibility rule based on target method not returning voidTypically eligibility rules I've put together are based on a specifically typed return or paramters.Follow up question from yesterday's meetupNow that I've had time to review what was discussed I think I can now ask the question I'd wanted toPlease cache licensing key rather than check every buildEvery time I attempt to build an aspect today, I'm getting an error that I've got an invalid licenseDocumentation: Bad linkAt https://doc.metalama.net/conceptual/using/fabrics there's a link at the bottom titled "ConfigurinCan one pass state between aspects?One can trivially pass arbitrary data between the aspect class and a template via the 'args' parametOrdering AspectsIn the documentation it states: 'Aspects must be ordered using the AspectOrderAttribute assembly-levThis error has me foxedIt's our old friend LAMA0001 Can't work out where it is getting Net Framework reference from. Pr