pascalabcnet/VisualPascalABCNETLinux/MonoDebugging/Evaluation/LambdaBodyOutputVisitor.cs
2023-04-10 21:04:27 +02:00

261 lines
7.5 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Mono.Debugging.Client;
namespace Mono.Debugging.Evaluation
{
// Outputs lambda expression inputted on Immediate Pad. Also
// this class works for followings.
// - Check if body of lambda has not-supported expression
// - Output reserved words like `this` or `base` with generated
// identifer.
// - Collect variable references for outside the lambda
// (local variables/properties...)
/*public class LambdaBodyOutputVisitor : CSharpSyntaxWalker
{
readonly Dictionary<string, ValueReference> userVariables;
readonly EvaluationContext ctx;
Dictionary<string, Tuple<string, object>> localValues;
List<string> definedIdentifier;
int gensymCount;
public LambdaBodyOutputVisitor (EvaluationContext ctx, Dictionary<string, ValueReference> userVariables)
{
this.ctx = ctx;
this.userVariables = userVariables;
this.localValues = new Dictionary<string, Tuple<string, object>> ();
this.definedIdentifier = new List<string> ();
}
public Tuple<string, object>[] GetLocalValues ()
{
var locals = new Tuple<string, object>[localValues.Count];
int n = 0;
foreach (var localv in localValues.Values) {
locals[n] = localv;
n++;
}
return locals;
}
static Exception NotSupported ()
{
return new NotSupportedExpressionException ();
}
static Exception EvaluationError (string message, params object[] args)
{
return new EvaluatorException (message, args);
}
bool IsPublicValueFlag (ObjectValueFlags flags)
{
var isField = (flags & ObjectValueFlags.Field) != 0;
var isProperty = (flags & ObjectValueFlags.Property) != 0;
var isPublic = (flags & ObjectValueFlags.Public) != 0;
return !(isField || isProperty) || isPublic;
}
void AssertPublicType (object type)
{
if (!ctx.Adapter.IsPublic (ctx, type)) {
var typeName = ctx.Adapter.GetDisplayTypeName (ctx, type);
throw EvaluationError ("Not Support to reference non-public type: `{0}'", typeName);
}
}
void AssertPublicValueReference (ValueReference vr)
{
if (!(vr is NamespaceValueReference)) {
var typ = vr.Type;
AssertPublicType (typ);
}
if (!IsPublicValueFlag (vr.Flags)) {
throw EvaluationError ("Not Support to reference non-public thing: `{0}'", vr.Name);
}
}
ValueReference Evaluate (IdentifierNameSyntax t)
{
var visitor = new NRefactoryExpressionEvaluatorVisitor (ctx, t.Identifier.ValueText, null, userVariables);
return visitor.Visit (t);
}
ValueReference Evaluate (BaseExpressionSyntax t)
{
var visitor = new NRefactoryExpressionEvaluatorVisitor (ctx, "base", null, userVariables);
return visitor.Visit (t);
}
ValueReference Evaluate (ThisExpressionSyntax t)
{
var visitor = new NRefactoryExpressionEvaluatorVisitor (ctx, "this", null, userVariables);
return visitor.Visit (t);
}
string GenerateSymbol (string s)
{
var prefix = "__" + s;
var sym = prefix;
while (ExistsLocalName (sym)) {
sym = prefix + gensymCount++;
}
return sym;
}
string AddToLocals (string name, ValueReference vr, bool shouldRename = false)
{
if (localValues.ContainsKey (name))
return GetLocalName (name);
string localName;
if (shouldRename) {
localName = GenerateSymbol (name);
} else if (!ExistsLocalName (name)) {
localName = name;
} else {
throw EvaluationError ("Cannot use a variable named {0} inside lambda", name);
}
AssertPublicValueReference (vr);
if (!(vr is NamespaceValueReference)) {
var valu = vr?.Value;
var pair = Tuple.Create(localName, valu);
localValues.Add(name, pair);
}
return localName;
}
string GetLocalName (string name)
{
Tuple<string, object> pair;
if (localValues.TryGetValue (name, out pair))
return pair.Item1;
return null;
}
bool ExistsLocalName (string localName)
{
foreach (var pair in localValues.Values) {
if (pair.Item1 == localName)
return true;
}
return definedIdentifier.Contains (localName);
}
#region IAstVisitor implementation
public override void VisitAssignmentExpression (AssignmentExpressionSyntax node)
{
throw EvaluationError ("Not support assignment expression inside lambda");
}
public override void VisitBaseExpression (BaseExpressionSyntax node)
{
var basee = "base";
var localbase = GetLocalName (basee);
if (localbase == null) {
var vr = Evaluate (node);
localbase = AddToLocals (basee, vr, true);
}
}
public override void VisitIdentifierName (IdentifierNameSyntax node)
{
var identifier = node.Identifier.ValueText;
var localIdentifier = "";
if (definedIdentifier.Contains (identifier)) {
localIdentifier = identifier;
} else {
localIdentifier = GetLocalName (identifier);
if (localIdentifier == null) {
var vr = Evaluate (node);
localIdentifier = AddToLocals (identifier, vr);
}
}
}
public override void VisitGenericName (GenericNameSyntax node)
{
foreach (var arg in node.TypeArgumentList.Arguments) {
Visit (arg);
}
}
public override void VisitInvocationExpression (InvocationExpressionSyntax node)
{
var invocationTarget = node.Expression;
if (!(invocationTarget is IdentifierNameSyntax method)) {
Visit(invocationTarget);
return;
}
var argc = node.ArgumentList.Arguments.Count;
var methodName = method.Identifier.ValueText;
var vref = ctx.Adapter.GetThisReference (ctx);
var vtype = ctx.Adapter.GetEnclosingType (ctx);
string accessor = null;
var hasInstanceMethod = ctx.Adapter.HasMethodWithParamLength (ctx, vtype, methodName, BindingFlags.Instance, argc);
var hasStaticMethod = ctx.Adapter.HasMethodWithParamLength (ctx, vtype, methodName, BindingFlags.Static, argc);
var publicFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
var hasPublicMethod = ctx.Adapter.HasMethodWithParamLength (ctx, vtype, methodName, publicFlags, argc);
if ((hasInstanceMethod || hasStaticMethod) && !hasPublicMethod)
throw EvaluationError ("Only support public method invocation inside lambda");
if (vref == null && hasStaticMethod) {
AssertPublicType (vtype);
var typeName = ctx.Adapter.GetTypeName (ctx, vtype);
accessor = ctx.Adapter.GetDisplayTypeName (typeName);
} else if (vref != null) {
AssertPublicValueReference (vref);
if (hasInstanceMethod) {
if (hasStaticMethod) {
// It's hard to determine which one is expected because
// we don't have any information of parameter types now.
throw EvaluationError ("Not supported invocation of static/instance overloaded method");
}
accessor = GetLocalName ("this");
if (accessor == null)
accessor = AddToLocals ("this", vref, true);
} else if (hasStaticMethod) {
var typeName = ctx.Adapter.GetTypeName (ctx, vtype);
accessor = ctx.Adapter.GetDisplayTypeName (typeName);
}
}
for (int i = 0; i < node.ArgumentList.Arguments.Count; i++) {
Visit (node.ArgumentList.Arguments[i]);
}
}
public override void VisitSimpleLambdaExpression (SimpleLambdaExpressionSyntax node)
{
if (node.Parameter.Modifiers.Count > 0)
throw NotSupported ();
definedIdentifier.Add (node.Parameter.Identifier.ValueText);
Visit (node.Body);
}
public override void VisitThisExpression (ThisExpressionSyntax node)
{
var thiss = "this";
var localthis = GetLocalName (thiss);
if (localthis == null) {
var vr = Evaluate (node);
localthis = AddToLocals (thiss, vr, true);
}
}
#endregion
}*/
}