Skip to content

Commit

Permalink
Merge pull request #114 from Jcparkyn/dev
Browse files Browse the repository at this point in the history
Add Experimental Nodes
  • Loading branch information
Jcparkyn authored Oct 24, 2020
2 parents 22c5155 + 31209d1 commit 2138c47
Show file tree
Hide file tree
Showing 48 changed files with 1,009 additions and 189 deletions.
32 changes: 16 additions & 16 deletions Nodexr.Tests/QuantifierTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public string Greedy_ReturnsOutput(string contents, Reps repetitions)
public string GetOutput_GroupedContents_ReturnsContentsWithAsterisk(string contents)
{
var node = CreateDefaultQuantifier(contents);
node.InputCount.Value = Reps.ZeroOrMore;
return node.CachedOutput.Expression;
}

Expand All @@ -40,9 +41,10 @@ public string GetOutput_GroupedContents_ReturnsContentsWithAsterisk(string conte
public string GetOutput_UngroupedContents_ReturnsContentsGroupedWithAsterisk(string contents)
{
var node = new QuantifierNode();
node.InputCount.Value = Reps.ZeroOrMore;
var input = new TextNode();
input.Input.Contents = contents;
input.InputEscapeSpecials.IsChecked = false;
input.Input.Value = contents;
input.InputEscapeSpecials.Checked = false;

node.InputContents.ConnectedNode = input;
node.InputSearchType.Value = QuantifierNode.SearchMode.Greedy;
Expand All @@ -55,7 +57,9 @@ public string GetOutput_UngroupedContents_ReturnsContentsGroupedWithAsterisk(str
[TestCase(Reps.ZeroOrOne, ExpectedResult = @"?")]
public string GetSuffix_BasicModes_ReturnsSuffix(Reps mode)
{
return IQuantifiableNode.GetSuffix(mode);
var node = new QuantifierNode();
node.InputCount.Value = mode;
return IQuantifiableNode.GetSuffix(node);
}

[TestCase(0, ExpectedResult = @"{0}")]
Expand All @@ -64,29 +68,25 @@ public string GetSuffix_BasicModes_ReturnsSuffix(Reps mode)
[TestCase(null, ExpectedResult = @"{0}")]
public string GetSuffix_Number_ReturnsSuffix(int? number)
{
return IQuantifiableNode.GetSuffix(Reps.Number, number: number);
var node = new QuantifierNode();
node.InputCount.Value = Reps.Number;
node.InputNumber.Value = number;
return IQuantifiableNode.GetSuffix(node);
}

[TestCase(0, 0, ExpectedResult = @"{0,0}")]
[TestCase(0, 0, ExpectedResult = @"{0,}")]
[TestCase(0, 1, ExpectedResult = @"{0,1}")]
[TestCase(0, 99, ExpectedResult = @"{0,99}")]
[TestCase(null, 1, ExpectedResult = @"{0,1}")]
[TestCase(1, 99, ExpectedResult = @"{1,99}")]
[TestCase(1, null, ExpectedResult = @"{1,}")]
public string GetSuffix_Range_ReturnsSuffix(int? min, int? max)
{
return IQuantifiableNode.GetSuffix(Reps.Range, min: min, max: max);
}

private QuantifierNode CreateQuantifierWithRange(string contents, int min, int max)
{
var node = CreateDefaultQuantifier(contents);

var node = new QuantifierNode();
node.InputCount.Value = Reps.Range;
node.InputMin.InputContents = min;
node.InputMax.InputContents = max;

return node;
node.InputRange.Min = min;
node.InputRange.Max = max;
return IQuantifiableNode.GetSuffix(node);
}

private QuantifierNode CreateDefaultQuantifier(string contents)
Expand Down
8 changes: 4 additions & 4 deletions Nodexr.Tests/RegexParserTests/CharSetParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,24 @@ class CharSetParserTests
public void CharSetNode_NoSpecials_ReturnsContents(string input, string expectedContents)
{
CharSetNode result = ParseCharSet.ParseOrThrow(input);
Assert.AreEqual(expectedContents, result.InputCharacters.Contents);
Assert.AreEqual(expectedContents, result.InputCharacters.Value);
}

[TestCase(@"[\]]", @"\]")]
[TestCase(@"[abc\]def]", @"abc\]def")]
public void CharSetNode_EscapedBracket_ReturnsContents(string input, string expectedContents)
{
var result = ParseCharSet.ParseOrThrow(input);
Assert.AreEqual(expectedContents, result.InputCharacters.Contents);
Assert.AreEqual(expectedContents, result.InputCharacters.Value);
}

[TestCase(@"[^a]", @"a")]
[TestCase(@"[^abc]", @"abc")]
public void Inverted_ReturnsContents(string input, string expectedContents)
{
var result = ParseCharSet.ParseOrThrow(input);
Assert.That(result.InputDoInvert.IsChecked, Is.True);
Assert.AreEqual(expectedContents, result.InputCharacters.Contents);
Assert.That(result.InputDoInvert.Checked, Is.True);
Assert.AreEqual(expectedContents, result.InputCharacters.Value);
}
}
}
2 changes: 1 addition & 1 deletion Nodexr.Tests/TextNodeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class TextNodeTests
public void VariousStrings_MatchesString(string contents, string shouldMatch)
{
var node = new TextNode();
node.Input.Contents = contents;
node.Input.Value = contents;

string nodeVal = node.CachedOutput.Expression;

Expand Down
10 changes: 10 additions & 0 deletions Nodexr/Shared/Components/NodeList.razor
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,15 @@
new CommentNode(),
new FlagNode(),
}),

("Experimental",
new Node[]
{
new DecimalNode(),
new IntegerNode(),
new OptionalNode(),
new ListNode(),
new RecursionNode(),
}),
};
}
2 changes: 1 addition & 1 deletion Nodexr/Shared/Components/NoodleCollection.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{
var inputsWithNoodles = node.GetAllInputs()
.OfType<InputProcedural>()
.Where(input => input.Enabled);
.Where(input => input.Connected);

@foreach (var input in inputsWithNoodles)
{
Expand Down
2 changes: 1 addition & 1 deletion Nodexr/Shared/Components/NoodleSvg.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@implements IDisposable

<path id="@DomId" class="noodle" d="@PathInstructions"
style="@(Noodle.Enabled ? "" : "display:none;") @CssStrokeStyle"/>
style="@(Noodle.Connected ? "" : "display:none;") @CssStrokeStyle"/>


@functions{
Expand Down
11 changes: 11 additions & 0 deletions Nodexr/Shared/ExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,16 @@ public static string EscapeCharacters(this string input, IEnumerable<char> chars
}
return result;
}

public static string EscapeSpecialCharacters(this string input, bool escapeBackslashes = true)
{
const string specialCharacters = "()[]{}$^?.+*|";

string charsToEscape = escapeBackslashes ?
specialCharacters + "\\" :
specialCharacters;

return EscapeCharacters(input, charsToEscape);
}
}
}
176 changes: 176 additions & 0 deletions Nodexr/Shared/IntegerRangeGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Algorithm based on answers in https://stackoverflow.com/questions/33512037/a-regular-expression-generator-for-number-ranges

namespace Nodexr.Shared
{
public class IntegerRangeGenerator
{
private readonly struct Pair
{
public readonly int min;
public readonly int max;

public Pair(int min, int max)
{
this.min = min;
this.max = max;
}

public Pair Flipped()
{
return new Pair(max, min);
}
}

public List<string> GenerateRegexRange(int start, int end)
{
if (start < 0)
throw new ArgumentOutOfRangeException(nameof(start), "Must be non-negative");
if (end < 0)
throw new ArgumentOutOfRangeException(nameof(end), "Must be non-negative");

//order inputs so start <= end
if (start > end)
(start, end) = (end, start);

return GenerateRegexRanges(start, end);
}

private List<string> GenerateRegexRanges(int start, int end)
{
var pairs = GetRegexPairsRecursion(start, end);
return FormatPairsToRegEx(pairs);
}

/**
* return the regular expressions that match the ranges in the given
* list of integers. The list is in the form firstRangeStart, firstRangeEnd,
* secondRangeStart, secondRangeEnd, etc. Each regular expression is 0-left-padded,
* if necessary, to match strings of the given width.
*/
private List<string> FormatPairsToRegEx(List<Pair> pairs)
{
List<string> list = new List<string>();
for (int i = 0; i < pairs.Count; i ++)
{
string start = pairs[i].min.ToString();
string end = pairs[i].max.ToString();

StringBuilder result = new StringBuilder();

for (int pos = 0; pos < start.Length; pos++)
{
if (start[pos] == end[pos])
{
result.Append(start[pos]);
}
else if(start[pos] == '0' && end[pos] == '9')
{
result.Append("\\d");
}
else
{
result.Append('[').Append(start[pos]).Append('-')
.Append(end[pos]).Append(']');
}
}

list.Add(result.ToString());
}
return list;
}

/**
* return the list of integers that are the paired integers
* used to generate the regular expressions for the given
* range. Each pair of integers in the list -- 0,1, then 2,3,
* etc., represents a range for which a single regular expression
* is generated.
*/
private List<Pair> GetRegexPairsRecursion(int start, int end)
{
var pairs = new List<Pair>();

if (start == 0)
{
if (end <= 9)
{
pairs.Add(new Pair(0, end));
return pairs;
}
else
{
pairs.Add(new Pair(0, 9));
start = 10;
}
}

if (start > end)
{
return pairs;
}

/*
* Calculate first number ending with 0, which is greater than the start value.
* This will tell us whether or not start and end values differ only at last digit.
*/
int firstEndingWith0 = 10 * ((start + 9) / 10);

/*
* Start and end values differ only at the last digit.
*/
if (firstEndingWith0 > end) // not in range?
{
pairs.Add(new Pair(start, end));
return pairs;
}

/*
* start is not ending in 0.
*/
if (start < firstEndingWith0)
{
pairs.Add(new Pair(start, firstEndingWith0 - 1));
}

//Largest number ending with 9, which is <= the Range end.
int lastEndingWith9 = ((end + 1) / 10 * 10) - 1;

/*
* All RegEx for the range [firstEndingWith0,lastEndingWith9] end with [0-9],
* hence, remove the rightmost 0 from new working range start and remove the rightmost
* 9 from new working range end.
*/
var pairsMiddle = GetRegexPairsRecursion(firstEndingWith0 / 10, lastEndingWith9 / 10);

/*
* Append digits to start and end of each pair. 0 will be appended to the low value of
* the pair and 9 will be appended to the high value of the pair.
* This is equivalent of multiplying low value by 10, and multiplying high value by 10
* and adding 9 to it.
*/
foreach (Pair pair in pairsMiddle)
{
pairs.Add(new Pair(
(pair.min * 10) + 0,
(pair.max * 10) + 9
));
}

if (lastEndingWith9 < end) // end is not ending in 9
{
pairs.Add(new Pair(
lastEndingWith9 + 1,
end
));
}

return pairs;
}
}
}
10 changes: 5 additions & 5 deletions Nodexr/Shared/NodeInputs/InputCheckbox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
{
public class InputCheckbox : NodeInput
{
private bool isChecked;
private bool _checked;

public bool IsChecked
public bool Checked
{
get => isChecked;
get => _checked;
set
{
isChecked = value;
_checked = value;
OnValueChanged();
}
}
Expand All @@ -18,7 +18,7 @@ public bool IsChecked

public InputCheckbox(bool isChecked = false)
{
this.isChecked = isChecked;
this._checked = isChecked;
}
}
}
4 changes: 1 addition & 3 deletions Nodexr/Shared/NodeInputs/InputDropdown.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;


namespace Nodexr.Shared.NodeInputs
{
public abstract class InputDropdown : NodeInput
Expand All @@ -16,7 +15,7 @@ public class InputDropdown<TValue> : InputDropdown
where TValue : struct, Enum
{
//private string dropdownValue;
private Dictionary<TValue, string> displayNames;
private readonly Dictionary<TValue, string> displayNames;

private TValue value = default;

Expand Down Expand Up @@ -53,7 +52,6 @@ public override IEnumerable<string> Options
get
{
if (displayNames != null) return displayNames.Values;

else return Enum.GetNames(typeof(TValue));
}
}
Expand Down
Loading

0 comments on commit 2138c47

Please sign in to comment.