using System.Collections; namespace Jint.Runtime.Debugger; /// /// Collection of breakpoints. /// /// /// Only allows a single breakpoint at the same location (source, column and line). /// Adding a new breakpoint at the same location replaces the old one - this allows replacing e.g. a /// conditional breakpoint with a new condition (or remove the condition). /// public sealed class BreakPointCollection : IEnumerable { private readonly Dictionary _breakPoints = new(new OptionalSourceBreakLocationEqualityComparer()); public BreakPointCollection() { } /// /// Gets or sets whether breakpoints are activated. When false, all breakpoints will fail to match (and be skipped by the debugger). /// public bool Active { get; set; } = true; public int Count => _breakPoints.Count; /// /// Sets a new breakpoint. Note that this will replace any breakpoint at the same location (source/column/line). /// public void Set(BreakPoint breakPoint) { _breakPoints[breakPoint.Location] = breakPoint; } /// /// Removes breakpoint with the given location (source/column/line). /// Note that a null source matches any source. /// public bool RemoveAt(BreakLocation location) { return _breakPoints.Remove(location); } /// /// Checks whether collection contains a breakpoint at the given location (source/column/line). /// Note that a null source matches any source. /// public bool Contains(BreakLocation location) { return _breakPoints.ContainsKey(location); } /// /// Removes all breakpoints. /// public void Clear() { _breakPoints.Clear(); } internal BreakPoint? FindMatch(DebugHandler debugger, BreakLocation location) { if (!Active) { return null; } if (!_breakPoints.TryGetValue(location, out var breakPoint)) { return null; } if (!string.IsNullOrEmpty(breakPoint.Condition)) { try { var completionValue = debugger.Evaluate(breakPoint.Condition!); // Truthiness check: if (!TypeConverter.ToBoolean(completionValue)) { return null; } } catch (Exception ex) when (ex is JavaScriptException || ex is DebugEvaluationException) { // Error in the condition means it doesn't match - shouldn't actually throw. return null; } } return breakPoint; } public IEnumerator GetEnumerator() { return _breakPoints.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _breakPoints.GetEnumerator(); } }