Some initial work for debugging
This commit is contained in:
parent
590614c34d
commit
a4cdaa5b05
|
@ -7,5 +7,7 @@ namespace Upsilon.Binder
|
|||
protected BoundStatement(TextSpan span) : base(span)
|
||||
{
|
||||
}
|
||||
|
||||
internal bool HasBreakpoint { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Upsilon.Evaluator.Debugging
|
||||
{
|
||||
public class BreakpointInfo
|
||||
{
|
||||
private Dictionary<string, object> _variables;
|
||||
public BreakpointInfo(EvaluationScope scope)
|
||||
{
|
||||
_variables = new Dictionary<string, object>();
|
||||
while (scope != null)
|
||||
{
|
||||
foreach (var v in scope.Variables)
|
||||
{
|
||||
_variables.Add(v.Key, v.Value);
|
||||
}
|
||||
|
||||
scope = scope.ParentScope;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Upsilon.Evaluator.Debugging
|
||||
{
|
||||
public class DebugFile
|
||||
{
|
||||
public List<Breakpoint> Breakpoints = new List<Breakpoint>();
|
||||
}
|
||||
|
||||
public class Breakpoint
|
||||
{
|
||||
public int Line { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Upsilon.Evaluator.Debugging
|
||||
{
|
||||
public static class DebugSession
|
||||
{
|
||||
public static bool DebuggerAttached { get; set; }
|
||||
internal static bool Debugging { get; set; }
|
||||
private static Dictionary<string, DebugFile> Files { get; set; }
|
||||
|
||||
public static void AttachDebugger()
|
||||
{
|
||||
DebuggerAttached = true;
|
||||
}
|
||||
|
||||
public static DebugFile GetFileInfo(string file)
|
||||
{
|
||||
return Files.TryGetValue(file, out var info) ? info : null;
|
||||
}
|
||||
|
||||
public static void SetBreakpoint(string file, int line)
|
||||
{
|
||||
if (!Files.TryGetValue(file, out var fileObj))
|
||||
{
|
||||
fileObj = new DebugFile();
|
||||
Files.Add(file, fileObj);
|
||||
}
|
||||
fileObj.Breakpoints.Add(new Breakpoint()
|
||||
{
|
||||
Line = line
|
||||
});
|
||||
}
|
||||
|
||||
public static void RemoveBreakpoint(string file, int line)
|
||||
{
|
||||
if (Files.TryGetValue(file, out var fileObj))
|
||||
{
|
||||
fileObj = new DebugFile();
|
||||
fileObj.Breakpoints.RemoveAll(x => x.Line == line);
|
||||
if (fileObj.Breakpoints.Count <= 0)
|
||||
Files.Remove(file);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void TriggerBreakpoint(EvaluationScope scope)
|
||||
{
|
||||
OnBreakpoint?.Invoke(new BreakpointInfo(scope));
|
||||
}
|
||||
|
||||
public delegate void BreakpointEvent(BreakpointInfo info);
|
||||
public static event BreakpointEvent OnBreakpoint;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
public class EvaluationScope : IDisposable
|
||||
{
|
||||
private EvaluationScope _parentScope;
|
||||
public EvaluationScope ParentScope { get; private set; }
|
||||
private EvaluationScope _getOnlyParentScope;
|
||||
|
||||
public readonly Dictionary<string, ScriptType> Variables;
|
||||
|
@ -16,7 +16,7 @@ namespace Upsilon.Evaluator
|
|||
|
||||
internal EvaluationScope(EvaluationScope parentScope)
|
||||
{
|
||||
_parentScope = parentScope;
|
||||
ParentScope = parentScope;
|
||||
Variables = new Dictionary<string, ScriptType>();
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@ namespace Upsilon.Evaluator
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
_parentScope?.Dispose();
|
||||
_parentScope = null;
|
||||
ParentScope?.Dispose();
|
||||
ParentScope = null;
|
||||
Variables.Clear();
|
||||
}
|
||||
|
||||
|
@ -44,9 +44,9 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
Variables[symbol.Name] = value;
|
||||
}
|
||||
else if (_parentScope != null)
|
||||
else if (ParentScope != null)
|
||||
{
|
||||
_parentScope.AssignToNearest(symbol, value);
|
||||
ParentScope.AssignToNearest(symbol, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -74,8 +74,8 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
if (Variables.TryGetValue(symbol.Name, out obj))
|
||||
return true;
|
||||
if (_parentScope != null)
|
||||
if (_parentScope.TryGet(symbol, out obj))
|
||||
if (ParentScope != null)
|
||||
if (ParentScope.TryGet(symbol, out obj))
|
||||
return true;
|
||||
if (_getOnlyParentScope != null)
|
||||
if (_getOnlyParentScope.TryGet(symbol, out obj))
|
||||
|
@ -87,8 +87,8 @@ namespace Upsilon.Evaluator
|
|||
{
|
||||
if (Variables.TryGetValue(variable, out obj))
|
||||
return true;
|
||||
if (_parentScope != null)
|
||||
if (_parentScope.TryGet(variable, out obj))
|
||||
if (ParentScope != null)
|
||||
if (ParentScope.TryGet(variable, out obj))
|
||||
return true;
|
||||
if (_getOnlyParentScope != null)
|
||||
if (_getOnlyParentScope.TryGet(variable, out obj))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Upsilon.BaseTypes;
|
||||
using Upsilon.BaseTypes.Number;
|
||||
using Upsilon.BaseTypes.ScriptFunction;
|
||||
|
@ -8,8 +9,10 @@ using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
|||
using Upsilon.BaseTypes.UserData;
|
||||
using Upsilon.Binder;
|
||||
using Upsilon.Binder.VariableSymbols;
|
||||
using Upsilon.Evaluator.Debugging;
|
||||
using Upsilon.Exceptions;
|
||||
using Upsilon.Text;
|
||||
using Upsilon.Utilities;
|
||||
using Type = Upsilon.BaseTypes.Type;
|
||||
|
||||
namespace Upsilon.Evaluator
|
||||
|
@ -57,6 +60,19 @@ namespace Upsilon.Evaluator
|
|||
|
||||
public ScriptType Evaluate(BoundScript e)
|
||||
{
|
||||
if (DebugSession.DebuggerAttached && !string.IsNullOrWhiteSpace(e.FileName))
|
||||
{
|
||||
var file = DebugSession.GetFileInfo(e.FileName);
|
||||
if (file != null)
|
||||
{
|
||||
foreach (var breakpoint in file.Breakpoints)
|
||||
{
|
||||
var lineStart = _script.ScriptString.GetLineInfo(breakpoint.Line).Start;
|
||||
var debugStatement = e.GetBottomStatementAtPosition(lineStart);
|
||||
debugStatement.HasBreakpoint = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
EvaluateNode(e.Statement);
|
||||
if (_returnValue == null)
|
||||
return _lastValue;
|
||||
|
@ -474,14 +490,30 @@ namespace Upsilon.Evaluator
|
|||
throw new Exception($"Cannot find variable: '{e.Variable.VariableSymbol.Name}'");
|
||||
}
|
||||
|
||||
private Queue<BoundStatement> _todoStatements;
|
||||
|
||||
private void EvaluateBoundBlockStatement(BoundBlockStatement boundBlockStatement)
|
||||
{
|
||||
foreach (var boundStatement in boundBlockStatement.Statements)
|
||||
_todoStatements = new Queue<BoundStatement>(boundBlockStatement.Statements);
|
||||
while (true)
|
||||
{
|
||||
if (DebugSession.Debugging)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
continue;
|
||||
}
|
||||
if (HasReturned)
|
||||
return;
|
||||
if (HasBroken)
|
||||
return;
|
||||
if (_todoStatements.Count == 0)
|
||||
return;
|
||||
var boundStatement = _todoStatements.Dequeue();
|
||||
if (DebugSession.DebuggerAttached && boundStatement.HasBreakpoint)
|
||||
{
|
||||
DebugSession.TriggerBreakpoint(Scope);
|
||||
continue;
|
||||
}
|
||||
EvaluateStatement(boundStatement);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,11 @@ namespace Upsilon.Utilities
|
|||
{
|
||||
return node.GetNodeAtPosition(characterPosition).First();
|
||||
}
|
||||
|
||||
public static BoundStatement GetBottomStatementAtPosition(this BoundNode node, int characterPosition)
|
||||
{
|
||||
return (BoundStatement) node.GetNodeAtPosition(characterPosition).First(x => x is BoundStatement);
|
||||
}
|
||||
|
||||
public static Dictionary<string, VariableSymbol> GetBoundScopeVisibleVariables(this BoundScope scope)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue