Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions Sources/SynKit/Libraries/Parser/ParseErrorElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Source repository: https://github.com/LanguageDev/Yoakke

using System.Collections.Generic;
using System.Collections.Generic.Polyfill;

namespace Yoakke.SynKit.Parser;

Expand All @@ -11,10 +12,12 @@ namespace Yoakke.SynKit.Parser;
/// </summary>
public class ParseErrorElement
{
private readonly ParseErrorExpectationSet expected;

/// <summary>
/// The expected possible inputs.
/// </summary>
public ISet<object> Expected { get; }
public ISet<object> Expected => this.expected;

/// <summary>
/// The context in which the error occurred.
Expand All @@ -27,8 +30,9 @@ public class ParseErrorElement
/// <param name="expected">The expected input.</param>
/// <param name="context">The context in which the error occurred.</param>
public ParseErrorElement(object expected, string context)
: this(new HashSet<object> { expected }, context)
{
this.expected = new ParseErrorExpectationSet(expected);
this.Context = context;
}

/// <summary>
Expand All @@ -38,7 +42,13 @@ public ParseErrorElement(object expected, string context)
/// <param name="context">The context in which the error occurred.</param>
public ParseErrorElement(ISet<object> expected, string context)
{
this.Expected = expected;
this.expected = new ParseErrorExpectationSet(expected);
this.Context = context;
}

internal ParseErrorElement CreateMergedElement(ParseErrorElement parseErrorElement)
{
var newExpected = parseErrorElement.expected.Merge(this.expected);
return new(newExpected, parseErrorElement.Context);
}
}
139 changes: 114 additions & 25 deletions Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic.Polyfill;
using System.Linq;

namespace Yoakke.SynKit.Parser;
Expand All @@ -14,6 +13,8 @@
{
private string? firstKey;
private ParseErrorElement? firstItem;
private string? secondKey;
private ParseErrorElement? secondItem;
private Dictionary<string, ParseErrorElement>? elements;

private ParseErrorElementDictionary()
Expand All @@ -31,35 +32,76 @@
this.firstItem = value;
}

public ParseErrorElementDictionary(string firstKey, ParseErrorElement firstValue, string secondKey, ParseErrorElement secondValue)
{
this.firstKey = firstKey;
this.firstItem = firstValue;
this.secondKey = secondKey;
this.secondItem = secondValue;
}

public ParseErrorElement this[string key] => this.firstKey is null
? this.elements is null
? throw new KeyNotFoundException($"The key {key} was not found in the dictionary")
: this.elements[key]
: this.firstKey == key
? this.firstItem!
: this.secondKey == key
? this.secondItem!
: throw new KeyNotFoundException($"The key {key} was not found in the dictionary");

public IEnumerable<string> Keys => this.firstKey is null ? this.elements!.Keys : new[] { this.firstKey };
public IEnumerable<string> Keys =>
this.elements is not null
? this.elements.Keys
: (this.secondKey is null) ? [this.firstKey!] : [this.firstKey!, this.secondKey];

public IEnumerable<ParseErrorElement> Values => this.firstKey is null ? this.elements!.Values : new[] { this.firstItem! };
public IEnumerable<ParseErrorElement> Values =>
this.elements is not null
? this.elements.Values
: (this.secondKey is null) ? [this.firstItem!] : [this.firstItem!, this.secondItem!];

public int Count => this.firstKey is null ? this.elements is null ? 0 : this.elements.Count : 1;
public int Count => this.elements is null
? this.firstKey is null ? 0
: this.secondKey is null ? 1 : 2
: this.elements.Count;

public bool ContainsKey(string key)
{
if (this.elements is not null)
{
return this.elements.ContainsKey(key);
}
else if (this.firstKey is null)
{
return false;
}
else
{
return this.firstKey == key || (this.secondKey is null ? false : this.firstKey == key);
}
}

public bool ContainsKey(string key) => this.firstKey is null ? this.elements is null ? false : this.elements.ContainsKey(key) : this.firstKey == key;
public IEnumerator<KeyValuePair<string, ParseErrorElement>> GetEnumerator() =>
this.elements is null
? new Enumerator(this.firstKey!, this.firstItem!)
: this.elements.GetEnumerator();
? (secondKey is null)
? new Enumerator(this.firstKey!, this.firstItem!) : new TwoElementEnumerator(this.firstKey!, this.firstItem!, this.secondKey, this.secondItem)

Check warning on line 87 in Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs

View workflow job for this annotation

GitHub Actions / Solution (ubuntu-latest)

Possible null reference argument for parameter 'secondValue' in 'TwoElementEnumerator.TwoElementEnumerator(string firstKey, ParseErrorElement firstValue, string secondKey, ParseErrorElement secondValue)'.

Check warning on line 87 in Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs

View workflow job for this annotation

GitHub Actions / Solution (macos-latest)

Possible null reference argument for parameter 'secondValue' in 'TwoElementEnumerator.TwoElementEnumerator(string firstKey, ParseErrorElement firstValue, string secondKey, ParseErrorElement secondValue)'.
: this.elements.GetEnumerator();
public bool TryGetValue(string key, out ParseErrorElement value)
{
if (this.elements is null)
{
if (this.firstKey == key)
{
value = firstItem;

Check warning on line 95 in Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs

View workflow job for this annotation

GitHub Actions / Solution (ubuntu-latest)

Possible null reference assignment.
return true;
}

if (this.secondKey == key)
{
value = secondItem;

Check warning on line 101 in Sources/SynKit/Libraries/Parser/ParseErrorElementDictionary.cs

View workflow job for this annotation

GitHub Actions / Solution (ubuntu-latest)

Possible null reference assignment.
return true;
}

value = default;
return false;
}
Expand All @@ -73,30 +115,31 @@
{
if (this.elements is null)
{
if (other.elements is null)
if (other.elements is not null)
{
if (this.firstKey == other.firstKey)
{
var newExpected = other.firstItem!.Expected.ToHashSet();
newExpected.UnionWith(this.firstItem!.Expected);
return new(other.firstKey!, new (newExpected, this.firstItem.Context));
}
else
{
return new(new Dictionary<string, ParseErrorElement>
{
{ this.firstKey!, this.firstItem! },
{ other.firstKey!, other.firstItem! },
});
}
return new(new(other.elements));
}

if (this.firstKey == other.firstKey)
{
return new(other.firstKey!, other.firstItem!.CreateMergedElement(this.firstItem!));
}
else
{
return new(new (other.elements));
if (this.secondKey is null)
{
return new(this.firstKey!, this.firstItem!, other.firstKey!, other.firstItem!);
}
return new(new Dictionary<string, ParseErrorElement>
{
{ this.firstKey!, this.firstItem! },
{ this.secondKey!, this.secondItem! },
{ other.firstKey!, other.firstItem! },
});
}
}

var elements = this.elements.Values.ToDictionary(e => e.Context, e => new ParseErrorElement(e.Expected.ToHashSet(), e.Context));
var elements = this.elements.Values.ToDictionary(e => e.Context, e => new ParseErrorElement(e.Expected, e.Context));
foreach (var element in other.Values)
{
if (elements.TryGetValue(element.Context, out var part))
Expand All @@ -105,7 +148,7 @@
}
else
{
part = new(element.Expected.ToHashSet(), element.Context);
part = new(element.Expected, element.Context);
elements.Add(element.Context, part);
}
}
Expand Down Expand Up @@ -156,4 +199,50 @@
this.valid = false;
}
}

private struct TwoElementEnumerator : IEnumerator<KeyValuePair<string, ParseErrorElement>>
{
private int consumed;
private KeyValuePair<string, ParseErrorElement> _firstPair;
private KeyValuePair<string, ParseErrorElement> _secondPair;
public TwoElementEnumerator(string firstKey, ParseErrorElement firstValue, string secondKey, ParseErrorElement secondValue)
{
this._firstPair = new KeyValuePair<string, ParseErrorElement>(firstKey, firstValue);
this._secondPair = new KeyValuePair<string, ParseErrorElement>(secondKey, secondValue);
}

public KeyValuePair<string, ParseErrorElement> Current
{
get
{
if (consumed > 2)
{
throw new InvalidOperationException("The enumerator is not valid.");
}

return consumed == 1 ? _firstPair : _secondPair;
}
}

object IEnumerator.Current => this.Current;

public void Dispose() { }
public bool MoveNext()
{
if (this.consumed >= 2)
{
this.consumed++;
return false;
}
else
{
this.consumed++;
return true;
}
}
public void Reset()
{
this.consumed = 0;
}
}
}
Loading
Loading