异步编程设计模式 - IronPythonDebugger

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
using System.Threading;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel;

namespace IronPythonDebugger
{
    public class IronPythonDebugger : IIronPythonDebugger
    {
        private ScriptEngine _engine;

        private ScriptScope _scope;

        private string _source;

        private string _debugSource;

        private ScriptSource _debugScriptSource;

        private Dictionary<int, bool> _breakpoints;

        private Thread _debugThread;

        private int _currentLine = 0;//从1开始计算

        private int _logicStartLine;//从1开始计算

        private ScriptBackgroundExecute _backgroundExecute;

        private bool _debugging = false;

        private int _sourceLineCount;

        private const string BACKGROUND_BREAK_CODE = "_backgroundExecute.Break()";

        private Action<int> _breakCallback;

        private int _nextBreakLine;

        private bool _debugThreadSleep = false;

        private AsyncOperation _asyncOp;

        private Action _exec;

        private SendOrPostCallback _onBreakCallback;

        private void Execute()
        {
            try
            {
                _debugScriptSource.Execute(_scope);
            }
            catch (DebugStopException)
            {
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
            finally
            {
                Stop();
            }
        }

        private void BackgroundBreakCallback()
        {
            if (!_debugging)
            {
                throw new DebugStopException();
            }
            _currentLine++;
            if (_currentLine == _nextBreakLine)
            {
                _debugThreadSleep = true;
                //if (_breakCallback != null)
                //{
                //    _breakCallback(_currentLine);
                //}
                _asyncOp.Post(_onBreakCallback, _currentLine);
                WaitDebugThreadContinue();
            }
        }

        private void OnBreakCallback(object lineNumber)
        {
            if (Break != null)
            {
                Break(this, new BreakEventArgs((int)lineNumber));
            }
            else if (_breakCallback != null)
            {
                _breakCallback((int)lineNumber);
            }
        }

        private void WaitDebugThreadContinue()
        {
            while (_debugThreadSleep)
            {
                Thread.Sleep(100);
            }
        }

        private void AddBackgroundBreakCode()
        {
            string[] lines = _source.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
            _sourceLineCount = lines.Length;
            _logicStartLine = GetLogicStartLine(lines);//获取第一行逻辑代码的行号
            _debugSource = string.Empty;
            for (int i = 0; i < _sourceLineCount; i++)
            {
                if (!string.IsNullOrEmpty(_debugSource))
                {
                    _debugSource += Environment.NewLine;
                }
                if (i >= _logicStartLine - 1)
                {
                    _debugSource += BACKGROUND_BREAK_CODE + Environment.NewLine;
                }
                _debugSource += lines[i];
            }
        }

        ////import clr,sys
        ////clr.AddReference('TestClass')
        ////clr.AddReference('System.Windows.Forms')
        ////from TestClass import *
        ////from System.Windows.Forms import *

        ////c1 = Class1()
        ////c1.Name = "c1"
        ////MessageBox.Show(c1.Name)
        ////child = Class1()
        ////child.Name = "child1"
        ////c1.Child = child
        ////MessageBox.Show(c1.Child.Name)
        private int GetLogicStartLine(string[] lines)
        {
            int startLine = 1;
            for (int i = 0; i < lines.Length;i++ )
            {
                string line = lines[i].ToLower();
                if (line.IndexOf("import") < 0
                    && line.IndexOf("clr") < 0
                    && line.IndexOf("from") < 0)
                {
                    startLine = i + 1;
                    break;
                }
            }
            return startLine;
        }

        private int GetNextBreakLine(int currentLine)
        {
            int next = -1;
            _breakpoints.OrderBy(breakpoint => breakpoint.Key);
            foreach (KeyValuePair<int, bool> breakpoint in _breakpoints)
            {
                if (breakpoint.Value && breakpoint.Key > currentLine)
                {
                    next = breakpoint.Key;
                    break;
                }
            }
            return next;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        public event Action<object, BreakEventArgs> Break;

        public ScriptEngine Engine
        {
            get
            {
                return _engine;
            }
        }

        public ScriptScope Scope
        {
            get
            {
                return _scope;
            }
        }

        public string Source
        {
            get
            {
                return _source;
            }
        }

        public Action<int> BreakCallback
        {
            get
            {
                return _breakCallback;
            }

            set
            {
                _breakCallback = value;
            }
        }

        public IronPythonDebugger()
        {
            _engine = Python.CreateEngine();
            _scope = _engine.CreateScope();
            _scope.SetVariable("_backgroundExecute", _backgroundExecute);
            _breakpoints = new Dictionary<int, bool>();
            _backgroundExecute = new ScriptBackgroundExecute(BackgroundBreakCallback);
            _exec = new Action(Execute);
            _onBreakCallback = new SendOrPostCallback(OnBreakCallback);
        }

        public void InitialDebugger()
        {
            if (_debugging)
            {
                throw new Exception("调试器正在调试中!");
            }
            _scope = _engine.CreateScope();
            _scope.SetVariable("_backgroundExecute", _backgroundExecute);
            _breakpoints.Clear();
        }

        public void InitialDebugger(List<int> breakpoints)
        {
            InitialDebugger();
            foreach (int breakpoint in breakpoints)
            {
                _breakpoints[breakpoint] = true;
            }
        }

        public void ClearBreakpoints()
        {
            _breakpoints.Clear();
        }

        public void Start(string source)
        {
            if (_debugging)
            {
                throw new Exception("调试器正在调试中!");
            }
            _source = source;
            AddBackgroundBreakCode();
            _debugScriptSource = _engine.CreateScriptSourceFromString(_debugSource);
            _currentLine = _logicStartLine - 1;
            _debugThreadSleep = false;
            _nextBreakLine = GetNextBreakLine(0);
            //_debugThread = new Thread(Execute);
            //_debugThread.Start();
            _asyncOp = AsyncOperationManager.CreateOperation(1);
            _exec.BeginInvoke(null, null);
            _debugging = true;
        }

        public void Stop()
        {
            if (_debugging)
            {
                _debugging = false;
                _debugThreadSleep = false;
                //if (_debugThread != null && _debugThread.IsAlive)
                //{
                //    _debugThread.Abort();
                //}
            }
        }

        public void AddBreakpoint(int line)
        {
            _breakpoints[line] = true;
        }

        public void AddBreakpoints(List<int> lines)
        {
            foreach (int line in lines)
            {
                AddBreakpoint(line);
            }
        }

        public void DeleteBreakpoint(int line)
        {
            _breakpoints[line] = false;
        }

        public void DeleteBreakpoints(List<int> lines)
        {
            foreach (int line in lines)
            {
                DeleteBreakpoint(line);
            }
        }

        public void StepOver()
        {
            if (!_debugging)
            {
                throw new Exception("调试器未开始调试!");
            }
            _nextBreakLine++;
            _debugThreadSleep = false;
        }

        public void StepInto()
        {
            MessageBox.Show("暂不支持逐语句调试!");
        }

        public void StepOut()
        {
            MessageBox.Show("暂不支持跳出调试!");
        }

        public void Continue()
        {
            if (!_debugging)
            {
                throw new Exception("调试器未开始调试!");
            }
            _nextBreakLine = GetNextBreakLine(_currentLine);
            _debugThreadSleep = false;
        }

        public string GetValueAsString(string variable)
        {
            string value = string.Empty;
            try
            {
                string[] names = variable.Split('.');
                object obj = _scope.GetVariable(names[0]);
                for (int i = 1; i < names.Length; i++)
                {
                    Type type = obj.GetType();
                    PropertyInfo pi = type.GetProperty(names[i]);
                    obj = pi.GetValue(obj, null);
                }
                value = obj.ToString();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
            return value;
        }

        public bool IsDebugging()
        {
            return _debugging;
        }
    }

    public class BreakEventArgs : EventArgs
    {
        public int LineNumber;

        public BreakEventArgs(int lineNumber)
        {
            this.LineNumber = lineNumber;
        }
    }

    public class DebugStopException : Exception
    {
    }
}

 

posted on 2015-05-05 14:33  Admin_csq  阅读(329)  评论(1编辑  收藏  举报