/// <inheritdoc/> public void StackTrace(IStackTraceCommand cmd) { var threadState = m_state.GetThreadState(cmd.ThreadId); int startFrame = cmd.StartFrame ?? 0; int maxNumberOfFrames = cmd.Levels ?? int.MaxValue; var frames = threadState.StackTrace.Skip(startFrame).Take(maxNumberOfFrames).Select((entry, idx) => { var functionName = entry.FunctionName; var source = new Source(TranslateBuildXLPath(entry.File)); var id = m_scopeHandles.Create(new FrameContext(cmd.ThreadId, startFrame + idx, threadState)); return((IStackFrame) new StackFrame(id, functionName, source, entry.Line, entry.Position)); }).ToList(); cmd.SendResult(new StackTraceResult(frames)); }
/// <summary> /// Evaluates an expression in the current debugger state context /// </summary> internal Possible <ObjectContext, EvaluateFailure> EvaluateExpression(FrameContext frameContext, string expressionString) { var evalState = (EvaluationState)m_state.GetThreadState(frameContext.ThreadId); var context = evalState.Context; var moduleLiteral = evalState.GetEnvForFrame(frameContext.FrameIndex); var frontEnd = new DScriptFrontEnd(new FrontEndStatistics()); frontEnd.InitializeFrontEnd(context.FrontEndHost, context.FrontEndContext, s_configuration); // We clear the logger before using it. var isClear = m_logger.TryClearCapturedDiagnostics(); // This logger should only be used in the context of one thread, so it should always be possible to clear it Contract.Assert(isClear); RuntimeModelContext runtimeModelContext = new RuntimeModelContext( context.FrontEndHost, context.FrontEndContext, m_logger, context.Package); // We recreate the local scope so the expression is parsed using the same local variables indexes // than the context where it is going to be evaluated var localScope = BuildLocalScopeForLocalVars(context, evalState.GetStackEntryForFrame(frameContext.FrameIndex)); var expression = s_parser.ParseExpression(runtimeModelContext, context.Package.Path, expressionString, localScope, useSemanticNameResolution: false); // If parsing failed, we report it and return // VS code only displays the first error that is sent. So we only send the first one. // An alternative would be to concatenate all errors and send them as a single message, but new lines are not respected by VS Code, // so the concatenation is not very legible. // Anyway, the first error should be good enough for almost all cases if (expression == null) { Contract.Assert(runtimeModelContext.Logger.CapturedDiagnostics.Count > 0); var diagnostic = runtimeModelContext.Logger.CapturedDiagnostics[0]; return(new EvaluateFailure(diagnostic)); } // We clear the logger again since it may contain warnings that didn't prevent the parser from finishing successfully isClear = m_logger.TryClearCapturedDiagnostics(); Contract.Assert(isClear); object expressionResult; // We temporary override the context logger so it doesn't affect the normal evaluation using (var expressionContext = new SnippetEvaluationContext(context, m_logger)) { expressionResult = expression.Eval(expressionContext.GetContextForSnippetEvaluation(), moduleLiteral, evalState.GetArgsForFrame(frameContext.FrameIndex)).Value; // If evaluation failed, we report it and return if (expressionResult.IsErrorValue()) { Contract.Assert(context.Logger.CapturedDiagnostics.Count > 0); var diagnostic = context.Logger.CapturedDiagnostics[0]; return(new EvaluateFailure(diagnostic)); } } return(new ObjectContext(context, expressionResult)); }