using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using HeuristicLab.Core.Views; using HeuristicLab.MainForm; namespace HeuristicLab.Problems.ProgramSynthesis.Views { public partial class PushDebuggerView : ItemView { private readonly IDictionary debugListDict = new Dictionary(); private readonly IDictionary debugPushProgramDict = new Dictionary(); private PooledPushInterpreter interpreter; private PushInterpreterPool pool; private const string GROUP_BOX_TEXT_STRING_FORMAT = "{0}[{1}]"; private const string EXEC_COUNT_LABEL_FORMAT = "{0}/{1} max. expressions evaluated"; public event EventHandler OnReset; public PushDebuggerView() { InitializeComponent(); InitEvents(); } ~PushDebuggerView() { interpreter.Dispose(); } public new PushSolution Content { get { return (PushSolution)base.Content; } set { base.Content = value; } } protected override void OnContentChanged() { if (Content == null) return; Name = "Push Debugger"; pool = new PushInterpreterPool(Content.Config); if (interpreter != null) { interpreter.Dispose(); } var random = Content.GetRandom(); interpreter = pool.Create(random); InitDebugLists(Content.Config); ClearDebugLists(); UpdateExecList(); UpdateDebugLists(); ResetDebugging(); } private void UpdateExecCountLabel() { execCountLabel.Text = string.Format( EXEC_COUNT_LABEL_FORMAT, interpreter.ExecCounter, Content.Config.EvalPushLimit); } private void InitEvents() { runButton.Click += RunButtonClick; resetButton.Click += ResetButtonClick; stepButton.Click += StepButtonClick; simplifyButton.Click += SimplifyButtonClick; } private void RunButtonClick(object sender, EventArgs e) { if (interpreter == null) return; interpreter.Resume(); UpdateStep(); } private void StepButtonClick(object sender, EventArgs e) { if (interpreter == null || stepWidthBox.Value <= 0) return; var count = Math.Min(stepWidthBox.Value, interpreter.ExecStack.Count); for (var i = 0; i < count; i++) { SkipNoops(); // run next none noop expression interpreter.Step(); } // skip trailing noops so next expression is a none noop in debugger SkipNoops(); stepWidthBox.Maximum = Math.Max(1, interpreter.ExecStack.Count); UpdateStep(); } private void UpdateStep() { UpdateExecList(); UpdateDebugLists(); UpdateExecCountLabel(); CheckIfButtonsCanBeEnabled(); } private void SkipNoops() { // skip noops if (skipNoopsCheckBox.Checked) { while (interpreter.CanStep && interpreter.ExecStack.Top.IsNoop(interpreter)) { interpreter.Step(); } } } private void CheckIfButtonsCanBeEnabled() { runButton.Enabled = interpreter != null && interpreter.CanStep; stepButton.Enabled = interpreter != null && interpreter.CanStep; stepWidthBox.Enabled = interpreter != null && interpreter.CanStep; } private void ResetButtonClick(object sender, EventArgs e) { ResetDebugging(); } private void SimplifyButtonClick(object sender, EventArgs e) { var newContent = Content.Simplify(); MainFormManager.MainForm.ShowContent(newContent, GetType()); } public void ResetDebugging() { if (Content == null || pool == null || Content.Program == null) return; if (interpreter != null) { interpreter.Reset(); } if (OnReset != null) { OnReset(this, interpreter); } interpreter.Run(Content.Program, true); stepWidthBox.Maximum = interpreter.ExecStack.Count; UpdateStep(); } private void ClearDebugLists() { foreach (var list in debugListDict.Values) { list.Items.Clear(); } foreach (var treeView in debugPushProgramDict.Values) { treeView.Nodes.Clear(); } } private void UpdateExecList() { execTreeView.LoadExpressions(interpreter.ExecStack.Reverse()); exec2GroupBox.Text = string.Format(GROUP_BOX_TEXT_STRING_FORMAT, Enum.GetName(typeof(StackTypes), StackTypes.Exec), interpreter.ExecStack.Count); } private void InitDebugLists(IReadOnlyPushConfiguration config) { debugListDict.Clear(); debugPushProgramDict.Clear(); // 2 = ExecList + EmptyColumn which is required to fill empty space while (debugTableLayout.ColumnCount > 2) { debugTableLayout.Controls.RemoveAt(1); debugTableLayout.ColumnCount--; } foreach (StackTypes stackType in Enum.GetValues(typeof(StackTypes))) { if (stackType == StackTypes.Exec || !config.IsStackEnabled(stackType)) continue; switch (stackType) { case StackTypes.Code: var treeView = CreatePushProgramTreeView(stackType); debugPushProgramDict.Add(stackType, treeView); break; default: var list = CreateDebugList(stackType); debugListDict.Add(stackType, list); break; } } } private PushProgramTreeView CreatePushProgramTreeView(StackTypes type) { var treeView = new PushProgramTreeView { Dock = DockStyle.Fill }; AddStackControlToTableLayout(type, treeView, 400); return treeView; } private void AddStackControlToTableLayout(StackTypes type, Control control, int width) { var groupBox = CreateStackGroupBox(type); groupBox.Controls.Add(control); debugTableLayout.ColumnCount++; debugTableLayout.ColumnStyles.Insert(1, new ColumnStyle(SizeType.Absolute, width)); debugTableLayout.Controls.Add(groupBox); debugTableLayout.Controls.SetChildIndex(groupBox, 1); } private ListBox CreateDebugList(StackTypes type) { var list = new ListBox { Dock = DockStyle.Fill }; // align numbers right if (type == StackTypes.Integer || type == StackTypes.Float) { list.DrawMode = DrawMode.OwnerDrawFixed; list.DrawItem += (sender, e) => { if (e.Index <= -1) return; var item = list.Items[e.Index]; e.DrawBackground(); e.DrawFocusRectangle(); var brush = new SolidBrush(e.ForeColor); var size = e.Graphics.MeasureString(item.ToString(), e.Font); e.Graphics.DrawString( item.ToString(), e.Font, brush, e.Bounds.Right - size.Width, e.Bounds.Top + (e.Bounds.Height / 2 - size.Height / 2)); }; } AddStackControlToTableLayout(type, list, 150); return list; } private static GroupBox CreateStackGroupBox(StackTypes type) { return new GroupBox { Anchor = AnchorStyles.Bottom | AnchorStyles.Right | AnchorStyles.Left | AnchorStyles.Top, AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, Text = Enum.GetName(typeof(StackTypes), type) }; } private void UpdateDebugLists() { ClearDebugLists(); if (Content == null || interpreter == null) return; foreach (var pair in debugPushProgramDict) { var name = Enum.GetName(typeof(StackTypes), pair.Key); var stack = (IPushStack)interpreter.Stacks[pair.Key]; pair.Value.AddExpressions(stack); ((GroupBox)pair.Value.Parent).Text = string.Format(GROUP_BOX_TEXT_STRING_FORMAT, name, pair.Value.Nodes.Count); } foreach (var pair in debugListDict) { var name = Enum.GetName(typeof(StackTypes), pair.Key); var items = interpreter.StringifyStack(pair.Key).ToArray(); pair.Value.Items.AddRange(items); ((GroupBox)pair.Value.Parent).Text = string.Format(GROUP_BOX_TEXT_STRING_FORMAT, name, pair.Value.Items.Count); } } } }