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)
|
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
|
public class EvaluationScope : IDisposable
|
||||||
{
|
{
|
||||||
private EvaluationScope _parentScope;
|
public EvaluationScope ParentScope { get; private set; }
|
||||||
private EvaluationScope _getOnlyParentScope;
|
private EvaluationScope _getOnlyParentScope;
|
||||||
|
|
||||||
public readonly Dictionary<string, ScriptType> Variables;
|
public readonly Dictionary<string, ScriptType> Variables;
|
||||||
|
@ -16,7 +16,7 @@ namespace Upsilon.Evaluator
|
||||||
|
|
||||||
internal EvaluationScope(EvaluationScope parentScope)
|
internal EvaluationScope(EvaluationScope parentScope)
|
||||||
{
|
{
|
||||||
_parentScope = parentScope;
|
ParentScope = parentScope;
|
||||||
Variables = new Dictionary<string, ScriptType>();
|
Variables = new Dictionary<string, ScriptType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ namespace Upsilon.Evaluator
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_parentScope?.Dispose();
|
ParentScope?.Dispose();
|
||||||
_parentScope = null;
|
ParentScope = null;
|
||||||
Variables.Clear();
|
Variables.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,9 +44,9 @@ namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
Variables[symbol.Name] = value;
|
Variables[symbol.Name] = value;
|
||||||
}
|
}
|
||||||
else if (_parentScope != null)
|
else if (ParentScope != null)
|
||||||
{
|
{
|
||||||
_parentScope.AssignToNearest(symbol, value);
|
ParentScope.AssignToNearest(symbol, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -74,8 +74,8 @@ namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
if (Variables.TryGetValue(symbol.Name, out obj))
|
if (Variables.TryGetValue(symbol.Name, out obj))
|
||||||
return true;
|
return true;
|
||||||
if (_parentScope != null)
|
if (ParentScope != null)
|
||||||
if (_parentScope.TryGet(symbol, out obj))
|
if (ParentScope.TryGet(symbol, out obj))
|
||||||
return true;
|
return true;
|
||||||
if (_getOnlyParentScope != null)
|
if (_getOnlyParentScope != null)
|
||||||
if (_getOnlyParentScope.TryGet(symbol, out obj))
|
if (_getOnlyParentScope.TryGet(symbol, out obj))
|
||||||
|
@ -87,8 +87,8 @@ namespace Upsilon.Evaluator
|
||||||
{
|
{
|
||||||
if (Variables.TryGetValue(variable, out obj))
|
if (Variables.TryGetValue(variable, out obj))
|
||||||
return true;
|
return true;
|
||||||
if (_parentScope != null)
|
if (ParentScope != null)
|
||||||
if (_parentScope.TryGet(variable, out obj))
|
if (ParentScope.TryGet(variable, out obj))
|
||||||
return true;
|
return true;
|
||||||
if (_getOnlyParentScope != null)
|
if (_getOnlyParentScope != null)
|
||||||
if (_getOnlyParentScope.TryGet(variable, out obj))
|
if (_getOnlyParentScope.TryGet(variable, out obj))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.BaseTypes.Number;
|
using Upsilon.BaseTypes.Number;
|
||||||
using Upsilon.BaseTypes.ScriptFunction;
|
using Upsilon.BaseTypes.ScriptFunction;
|
||||||
|
@ -8,8 +9,10 @@ using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
using Upsilon.BaseTypes.UserData;
|
using Upsilon.BaseTypes.UserData;
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.Binder.VariableSymbols;
|
||||||
|
using Upsilon.Evaluator.Debugging;
|
||||||
using Upsilon.Exceptions;
|
using Upsilon.Exceptions;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
|
using Upsilon.Utilities;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
namespace Upsilon.Evaluator
|
namespace Upsilon.Evaluator
|
||||||
|
@ -57,6 +60,19 @@ namespace Upsilon.Evaluator
|
||||||
|
|
||||||
public ScriptType Evaluate(BoundScript e)
|
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);
|
EvaluateNode(e.Statement);
|
||||||
if (_returnValue == null)
|
if (_returnValue == null)
|
||||||
return _lastValue;
|
return _lastValue;
|
||||||
|
@ -474,14 +490,30 @@ namespace Upsilon.Evaluator
|
||||||
throw new Exception($"Cannot find variable: '{e.Variable.VariableSymbol.Name}'");
|
throw new Exception($"Cannot find variable: '{e.Variable.VariableSymbol.Name}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Queue<BoundStatement> _todoStatements;
|
||||||
|
|
||||||
private void EvaluateBoundBlockStatement(BoundBlockStatement boundBlockStatement)
|
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)
|
if (HasReturned)
|
||||||
return;
|
return;
|
||||||
if (HasBroken)
|
if (HasBroken)
|
||||||
return;
|
return;
|
||||||
|
if (_todoStatements.Count == 0)
|
||||||
|
return;
|
||||||
|
var boundStatement = _todoStatements.Dequeue();
|
||||||
|
if (DebugSession.DebuggerAttached && boundStatement.HasBreakpoint)
|
||||||
|
{
|
||||||
|
DebugSession.TriggerBreakpoint(Scope);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
EvaluateStatement(boundStatement);
|
EvaluateStatement(boundStatement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,11 @@ namespace Upsilon.Utilities
|
||||||
return node.GetNodeAtPosition(characterPosition).First();
|
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)
|
public static Dictionary<string, VariableSymbol> GetBoundScopeVisibleVariables(this BoundScope scope)
|
||||||
{
|
{
|
||||||
IEnumerable<KeyValuePair<string, VariableSymbol>> dictionary = scope.Variables;
|
IEnumerable<KeyValuePair<string, VariableSymbol>> dictionary = scope.Variables;
|
||||||
|
|
Loading…
Reference in New Issue