private MsgTuple ParamsToTuple(IEnumerable <RValue> args, CoalescedFrame frame) { var tuple = new MsgTuple(); foreach (var arg in args) { if (arg is ConstantValue) { tuple.Column.Add(ConstantToTypedValue(arg as ConstantValue)); } else { if (frame != null) { tuple.Column.Add(VariableToTypedValue(arg as LocalVar, frame)); } else { throw new RequestFailedException("Local variables cannot be referenced without a stack frame"); } } } return(tuple); }
public void Evaluate(DAPRequest request, string expression, CoalescedFrame frame, bool allowMutation) { var stmt = Parse(expression); if (stmt == null) { DAP.SendReply(request, "Syntax error. Type \"help\" for usage."); return; } if (stmt.Params == null) { EvaluateName(request, stmt.Name, allowMutation); } else { EvaluateCall(request, stmt, frame, allowMutation); } }
private MsgTypedValue VariableToTypedValue(LocalVar lvar, CoalescedFrame frame) { // TODO - lvar.Type? if (lvar.Name == "_") { var tv = new MsgTypedValue(); tv.TypeId = (UInt32)Value.Type.None; return(tv); } else { var frameVar = frame.Variables.FirstOrDefault(v => v.Name == lvar.Name); if (frameVar == null) { throw new RequestFailedException($"Variable does not exist: \"{lvar.Name}\""); } return(frameVar.TypedValue); } }
private CoalescedFrame MsgFrameToLocal(MsgFrame frame) { var outFrame = new CoalescedFrame(); outFrame.Name = Formatter.GetFrameDebugName(frame); if (frame.Type == MsgFrame.Types.FrameType.GoalInitAction || frame.Type == MsgFrame.Types.FrameType.GoalExitAction) { var goal = DebugInfo.Goals[frame.GoalId]; outFrame.File = goal.Path; if (frame.Type == MsgFrame.Types.FrameType.GoalInitAction) { outFrame.Line = (int)goal.InitActions[(int)frame.ActionIndex].Line; } else { outFrame.Line = (int)goal.ExitActions[(int)frame.ActionIndex].Line; } } else if (frame.NodeId != 0) { var node = DebugInfo.Nodes[frame.NodeId]; if (node.RuleId != 0) { var rule = DebugInfo.Rules[node.RuleId]; var goal = DebugInfo.Goals[rule.GoalId]; outFrame.File = goal.Path; if (frame.Type == MsgFrame.Types.FrameType.Pushdown && node.Type == Node.Type.Rule) { outFrame.Line = (int)rule.ActionsStartLine; } else if (frame.Type == MsgFrame.Types.FrameType.RuleAction) { outFrame.Line = (int)rule.Actions[(int)frame.ActionIndex].Line; } else { outFrame.Line = node.Line; } } } outFrame.Variables = TupleToVariables(frame); outFrame.Frame = frame; if (outFrame.File != null && ModUuid != null) { var modRe = new Regex(".*\\.pak:/Mods/.*/Story/RawFiles/Goals/(.*)\\.txt"); var match = modRe.Match(outFrame.File); if (match.Success) { outFrame.File = "divinity:/" + ModUuid + "/" + match.Groups[1].Value + ".divgoal"; } } return(outFrame); }
/// <summary> /// Merges a node call range into an output stack frame. /// </summary> private CoalescedFrame MergeFrame(List <CoalescedFrame> range) { var frame = new CoalescedFrame(); frame.Frame = range[0].Frame; foreach (var node in range) { // Use last available location/variable data in the range if (node.Line != 0) { frame.File = node.File; frame.Line = node.Line; } if (frame.Rule == null && node.Frame.NodeId != 0) { var storyNode = DebugInfo.Nodes[node.Frame.NodeId]; if (storyNode.RuleId != 0) { var rule = DebugInfo.Rules[storyNode.RuleId]; frame.Rule = rule; } } if (node.Frame.Type == MsgFrame.Types.FrameType.Pushdown || node.Frame.Type == MsgFrame.Types.FrameType.Insert || node.Frame.Type == MsgFrame.Types.FrameType.Delete) { // Rule variable info is only propagated through Pushdown nodes. // All other nodes either have no variable info at all, or contain // local tuples used for DB insert/delete/query. // We'll keep the variables from Insert/Delete nodes if there are // no better rule candidates, as they show the PROC/DB input tuple. frame.Variables = node.Variables; } if (node.Frame.Type == MsgFrame.Types.FrameType.Insert || node.Frame.Type == MsgFrame.Types.FrameType.Delete) { // We'll keep the initial argument list that was passed to the PROC/QRY/DB // (from the initial Insert/Delete frame) to display in the call frame name frame.CallArguments = node.Frame.Tuple; } } if (frame.Variables == null) { frame.Variables = new List <DebugVariable>(); } frame.Name = Formatter.GetFrameName(frame.Frame, frame.CallArguments); // Special indicator for backward propagation of database inserts/deletes if (range.Count >= 2 && (range[0].Frame.Type == MsgFrame.Types.FrameType.Insert || range[0].Frame.Type == MsgFrame.Types.FrameType.Delete) && (range[1].Frame.Type == MsgFrame.Types.FrameType.Pushdown || range[1].Frame.Type == MsgFrame.Types.FrameType.PushdownDelete)) { var pushdownNode = DebugInfo.Nodes[range[1].Frame.NodeId]; if (range[0].Frame.NodeId != pushdownNode.ParentNodeId) { frame.Name = "(Database Propagation) " + frame.Name; } } return(frame); }
public void EvaluateCall(DAPRequest request, Statement stmt, CoalescedFrame frame, bool allowMutation) { NodeDebugInfo node; var func = new FunctionNameAndArity(stmt.Name, stmt.Params.Count); if (!NameToNodeMap.TryGetValue(func, out node)) { DAP.SendReply(request, "Name not found: " + func); return; } var function = DebugInfo.Functions[node.FunctionName]; var args = ParamsToTuple(stmt.Params, frame); DbgEvaluate.Types.EvalType evalType; switch (node.Type) { case Node.Type.Database: if (stmt.Not) { evalType = DbgEvaluate.Types.EvalType.Insert; } else { evalType = DbgEvaluate.Types.EvalType.Delete; } break; case Node.Type.Proc: if (stmt.Not) { throw new RequestFailedException("\"NOT\" statements not supported for PROCs"); } evalType = DbgEvaluate.Types.EvalType.Insert; break; case Node.Type.DivQuery: case Node.Type.InternalQuery: case Node.Type.UserQuery: if (stmt.Not) { throw new RequestFailedException("\"NOT\" statements not supported for QRYs"); } evalType = DbgEvaluate.Types.EvalType.IsValid; break; default: throw new RequestFailedException($"Eval node type not supported: {node.Type}"); } if ((evalType != DbgEvaluate.Types.EvalType.IsValid || node.Type == Node.Type.UserQuery) && !allowMutation) { throw new RequestFailedException($"Evaluation could cause game state change"); } UInt32 seq = DbgClient.SendEvaluate(evalType, node.Id, args); var argNames = function.Params.Select(arg => arg.Name).ToList(); var eval = new PendingExpressionEvaluation { Request = request, Results = EvalResults.MakeResults(function.Params.Count, argNames), Node = node, Function = function }; PendingEvaluations.Add(seq, eval); }