private string GetVariableValueString(UnderlyingVariableValuePair variableValuePair) { // Determine how to format our value string. switch (variableValuePair.Variable.GenericType) { case VarGenericType.Array: return($"{variableValuePair.Variable.BaseType} (size: {((object[])variableValuePair.Value).Length})"); case VarGenericType.ByteArrayDynamic: return($"{variableValuePair.Variable.BaseType} (size: {((Memory<byte>)variableValuePair.Value).Length})"); case VarGenericType.ByteArrayFixed: return(variableValuePair.Variable.BaseType); case VarGenericType.Mapping: return("<unsupported>"); case VarGenericType.String: return($"\"{variableValuePair.Value}\""); case VarGenericType.Struct: return(variableValuePair.Variable.BaseType); default: // As a fallback, try to turn the object into a string. return(variableValuePair.Value?.ToString() ?? "null"); } }
protected override void HandleVariablesRequestAsync(IRequestResponder <VariablesArguments, VariablesResponse> responder) { // Obtain relevant variable resolving information. int threadId = 0; int traceIndex = 0; bool isLocalVariableScope = false; bool isStateVariableScope = false; bool isParentVariableScope = false; UnderlyingVariableValuePair parentVariableValuePair = new UnderlyingVariableValuePair(null, null); // Try to obtain the variable reference as a local variable scope. isLocalVariableScope = ReferenceContainer.ResolveLocalVariable(responder.Arguments.VariablesReference, out threadId, out traceIndex); if (!isLocalVariableScope) { // Try to obtain the variable reference as a state variable scope. isStateVariableScope = ReferenceContainer.ResolveStateVariable(responder.Arguments.VariablesReference, out threadId, out traceIndex); if (!isStateVariableScope) { // Try to obtain the variable reference as a sub-variable scope. isParentVariableScope = ReferenceContainer.ResolveParentVariable(responder.Arguments.VariablesReference, out threadId, out parentVariableValuePair); } } // Using our thread id, obtain our thread state ThreadStates.TryGetValue(threadId, out var threadState); // Verify the thread state is valid if (threadState == null) { responder.SetResponse(new VariablesResponse()); return; } // Obtain the trace index for this scope. List <Variable> variableList = new List <Variable>(); try { ResolveVariables( variableList, responder.Arguments.VariablesReference, isLocalVariableScope, isStateVariableScope, isParentVariableScope, traceIndex, parentVariableValuePair, threadState); } catch (Exception ex) { LogException(ex, threadState); } // Respond with our variable list. responder.SetResponse(new VariablesResponse(variableList)); }
protected override void HandleVariablesRequestAsync(IRequestResponder <VariablesArguments, VariablesResponse> responder) { // Obtain relevant variable resolving information. int threadId = 0; int traceIndex = 0; bool isLocalVariableScope = false; bool isStateVariableScope = false; bool isParentVariableScope = false; UnderlyingVariableValuePair parentVariableValuePair = new UnderlyingVariableValuePair(null, null); // Try to obtain the variable reference as a local variable scope. isLocalVariableScope = ReferenceContainer.ResolveLocalVariable(responder.Arguments.VariablesReference, out threadId, out traceIndex); if (!isLocalVariableScope) { // Try to obtain the variable reference as a state variable scope. isStateVariableScope = ReferenceContainer.ResolveStateVariable(responder.Arguments.VariablesReference, out threadId, out traceIndex); if (!isStateVariableScope) { // Try to obtain the variable reference as a sub-variable scope. isParentVariableScope = ReferenceContainer.ResolveParentVariable(responder.Arguments.VariablesReference, out threadId, out parentVariableValuePair); } } // Using our thread id, obtain our thread state ThreadStates.TryGetValue(threadId, out var threadState); // Verify the thread state is valid if (threadState == null) { responder.SetResponse(new VariablesResponse()); return; } // Obtain the trace index for this scope. List <Variable> variableList = new List <Variable>(); // Obtain our local variables at this point in execution VariableValuePair[] variablePairs = Array.Empty <VariableValuePair>(); if (isLocalVariableScope) { variablePairs = threadState.ExecutionTraceAnalysis.GetLocalVariables(traceIndex); } else if (isStateVariableScope) { variablePairs = threadState.ExecutionTraceAnalysis.GetStateVariables(traceIndex); } else if (isParentVariableScope) { // We're loading sub-variables for a variable. switch (parentVariableValuePair.Variable.GenericType) { case VarGenericType.Struct: { // Cast our to an enumerable type. variablePairs = ((IEnumerable <VariableValuePair>)parentVariableValuePair.Value).ToArray(); break; } case VarGenericType.Array: { // Cast our variable var arrayVariable = ((VarArray)parentVariableValuePair.Variable); // Cast to an object array. var arrayValue = (object[])parentVariableValuePair.Value; // Loop for each element for (int i = 0; i < arrayValue.Length; i++) { // Create an underlying variable value pair for this element var underlyingVariableValuePair = new UnderlyingVariableValuePair(arrayVariable.ElementObject, arrayValue[i]); // Check if this is a nested variable type bool nestedType = IsNestedVariableType(arrayVariable.ElementObject.GenericType); int variablePairReferenceId = 0; if (nestedType) { // Create a new reference id for this variable if it's a nested type. variablePairReferenceId = ReferenceContainer.GetUniqueId(); // Link our reference for any nested types. ReferenceContainer.LinkSubVariableReference(responder.Arguments.VariablesReference, variablePairReferenceId, threadId, underlyingVariableValuePair); } // Obtain the value string for this variable and add it to our list. string variableValueString = GetVariableValueString(underlyingVariableValuePair); variableList.Add(new Variable($"[{i}]", variableValueString, variablePairReferenceId)); } break; } case VarGenericType.ByteArrayDynamic: case VarGenericType.ByteArrayFixed: { // Cast our to an enumerable type. var bytes = (Memory <byte>)parentVariableValuePair.Value; for (int i = 0; i < bytes.Length; i++) { variableList.Add(new Variable($"[{i}]", bytes.Span[i].ToString(CultureInfo.InvariantCulture), 0)); } break; } } } // Loop for each local variables foreach (VariableValuePair variablePair in variablePairs) { // Create an underlying variable value pair for this pair. var underlyingVariableValuePair = new UnderlyingVariableValuePair(variablePair); // Check if this is a nested variable type bool nestedType = IsNestedVariableType(variablePair.Variable.GenericType); int variablePairReferenceId = 0; if (nestedType) { // Create a new reference id for this variable if it's a nested type. variablePairReferenceId = ReferenceContainer.GetUniqueId(); // Link our reference for any nested types. ReferenceContainer.LinkSubVariableReference(responder.Arguments.VariablesReference, variablePairReferenceId, threadId, underlyingVariableValuePair); } // Obtain the value string for this variable and add it to our list. string variableValueString = GetVariableValueString(underlyingVariableValuePair); variableList.Add(new Variable(variablePair.Variable.Name, variableValueString, variablePairReferenceId)); } // Respond with our variable list. responder.SetResponse(new VariablesResponse(variableList)); }
void ResolveVariables( List <Variable> variableList, int variablesReference, bool isLocalVariableScope, bool isStateVariableScope, bool isParentVariableScope, int traceIndex, UnderlyingVariableValuePair parentVariableValuePair, MeadowDebugAdapterThreadState threadState) { // Obtain our local variables at this point in execution VariableValuePair[] variablePairs = Array.Empty <VariableValuePair>(); if (isLocalVariableScope) { variablePairs = threadState.ExecutionTraceAnalysis.GetLocalVariables(traceIndex, threadState.RpcClient); } else if (isStateVariableScope) { variablePairs = threadState.ExecutionTraceAnalysis.GetStateVariables(traceIndex, threadState.RpcClient); } else if (isParentVariableScope) { // We're loading sub-variables for a variable. switch (parentVariableValuePair.Variable.GenericType) { case VarGenericType.Struct: { // Cast our to an enumerable type. variablePairs = ((IEnumerable <VariableValuePair>)parentVariableValuePair.Value).ToArray(); break; } case VarGenericType.Array: { // Cast our variable var arrayVariable = ((VarArray)parentVariableValuePair.Variable); // Cast to an object array. var arrayValue = (object[])parentVariableValuePair.Value; // Loop for each element for (int i = 0; i < arrayValue.Length; i++) { // Create an underlying variable value pair for this element var underlyingVariableValuePair = new UnderlyingVariableValuePair(arrayVariable.ElementObject, arrayValue[i]); // Check if this is a nested variable type bool nestedType = IsNestedVariableType(arrayVariable.ElementObject.GenericType); int variablePairReferenceId = 0; if (nestedType) { // Create a new reference id for this variable if it's a nested type. variablePairReferenceId = ReferenceContainer.GetUniqueId(); // Link our reference for any nested types. ReferenceContainer.LinkSubVariableReference(variablesReference, variablePairReferenceId, threadState.ThreadId, underlyingVariableValuePair); } // Obtain the value string for this variable and add it to our list. string variableValueString = GetVariableValueString(underlyingVariableValuePair); variableList.Add(CreateVariable($"[{i}]", variableValueString, variablePairReferenceId, underlyingVariableValuePair.Variable.BaseType)); } break; } case VarGenericType.ByteArrayDynamic: case VarGenericType.ByteArrayFixed: { // Cast our to an enumerable type. var bytes = (Memory <byte>)parentVariableValuePair.Value; for (int i = 0; i < bytes.Length; i++) { variableList.Add(CreateVariable($"[{i}]", bytes.Span[i].ToString(CultureInfo.InvariantCulture), 0, "byte")); } break; } case VarGenericType.Mapping: { // Obtain our mapping's key-value pairs. var mappingKeyValuePairs = (MappingKeyValuePair[])parentVariableValuePair.Value; variablePairs = new VariableValuePair[mappingKeyValuePairs.Length * 2]; // Loop for each key and value pair to add. int variableIndex = 0; for (int i = 0; i < mappingKeyValuePairs.Length; i++) { // Set our key and value in our variable value pair enumeration. variablePairs[variableIndex++] = mappingKeyValuePairs[i].Key; variablePairs[variableIndex++] = mappingKeyValuePairs[i].Value; } break; } } } // Loop for each local variables foreach (VariableValuePair variablePair in variablePairs) { // Create an underlying variable value pair for this pair. var underlyingVariableValuePair = new UnderlyingVariableValuePair(variablePair); // Check if this is a nested variable type bool nestedType = IsNestedVariableType(variablePair.Variable.GenericType); int variablePairReferenceId = 0; if (nestedType) { // Create a new reference id for this variable if it's a nested type. variablePairReferenceId = ReferenceContainer.GetUniqueId(); // Link our reference for any nested types. ReferenceContainer.LinkSubVariableReference(variablesReference, variablePairReferenceId, threadState.ThreadId, underlyingVariableValuePair); } // Obtain the value string for this variable and add it to our list. string variableValueString = GetVariableValueString(underlyingVariableValuePair); variableList.Add(CreateVariable(variablePair.Variable.Name, variableValueString, variablePairReferenceId, variablePair.Variable.BaseType)); } }