Lenses are working, implemented addition of an operator to the parser.
This commit is contained in:
parent
b517d4f032
commit
fce4e7f53c
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
/tests_results
|
/tests_results
|
||||||
/main.exe
|
/main.exe
|
||||||
|
/main.exe.mdb
|
||||||
/*Generated.cs
|
/*Generated.cs
|
||||||
/*Generator.exe
|
/*Generator.exe
|
|
@ -18,10 +18,10 @@ public static class LexerGenerator {
|
||||||
Case("StringOpen"),
|
Case("StringOpen"),
|
||||||
Case("StringClose")),
|
Case("StringClose")),
|
||||||
Record("Rule",
|
Record("Rule",
|
||||||
Field("S", "oldState"),
|
Field("Lexer.S", "oldState"),
|
||||||
Field("string", "description"),
|
Field("string", "description"),
|
||||||
Field("Func<GraphemeCluster, bool>", "test"),
|
Field("Func<GraphemeCluster, bool>", "test"),
|
||||||
Field("S", "throughState"),
|
Field("Lexer.S", "throughState"),
|
||||||
Field("S", "newState"))));
|
Field("Lexer.S", "newState"))));
|
||||||
}
|
}
|
||||||
}
|
}
|
52
Parser.cs
52
Parser.cs
|
@ -8,32 +8,44 @@ using S = Lexer.S;
|
||||||
using Lexeme = Lexer.Lexeme;
|
using Lexeme = Lexer.Lexeme;
|
||||||
using static Global;
|
using static Global;
|
||||||
|
|
||||||
using PrecedenceDAG = System.Collections.Immutable.ImmutableDictionary<string, Parser.DAGNode>;
|
using PrecedenceDAG = ImmutableDefaultDictionary<string, Parser.DAGNode>;
|
||||||
|
|
||||||
public static partial class Parser {
|
public static partial class Parser {
|
||||||
public static PrecedenceDAG DefaultPrecedenceDAG = new PrecedenceDAG();
|
public static DAGNode EmptyDAGNode = new DAGNode(
|
||||||
|
infixLeftAssociative: ImmutableList<Operator>.Empty,
|
||||||
|
prefix: ImmutableList<Operator>.Empty,
|
||||||
|
closed: ImmutableList<Operator>.Empty,
|
||||||
|
terminal: ImmutableList<Operator>.Empty,
|
||||||
|
infixRightAssociative: ImmutableList<Operator>.Empty,
|
||||||
|
infixNonAssociative: ImmutableList<Operator>.Empty,
|
||||||
|
postfix: ImmutableList<Operator>.Empty,
|
||||||
|
successorNodes: ImmutableList<string>.Empty
|
||||||
|
);
|
||||||
|
|
||||||
public static DAGNode With(DAGNode node, Operator @operator) {
|
public static PrecedenceDAG DefaultPrecedenceDAG
|
||||||
var newNode = @operator.fixity.Match(
|
= new PrecedenceDAG(EmptyDAGNode);
|
||||||
Closed: () => node.lens.closed.Cons(@operator),
|
|
||||||
InfixLeftAssociative: () => node.lens.infixLeftAssociative.Cons(@operator),
|
public static Whole With<Whole>(this ILens<DAGNode, Whole> node, Operator @operator) {
|
||||||
InfixRightAssociative: () => node.lens.infixRightAssociative.Cons(@operator),
|
return @operator.fixity.Match(
|
||||||
InfixNonAssociative: () => node.lens.infixNonAssociative.Cons(@operator),
|
Closed:
|
||||||
Prefix: () => node.lens.prefix.Cons(@operator),
|
() => node.Closed().Cons(@operator),
|
||||||
Postfix: () => node.lens.postfix.Cons(@operator),
|
InfixLeftAssociative:
|
||||||
Terminal: () => node.lens.terminal.Cons(@operator)
|
() => node.InfixLeftAssociative().Cons(@operator),
|
||||||
|
InfixRightAssociative:
|
||||||
|
() => node.InfixRightAssociative().Cons(@operator),
|
||||||
|
InfixNonAssociative:
|
||||||
|
() => node.InfixNonAssociative().Cons(@operator),
|
||||||
|
Prefix:
|
||||||
|
() => node.Prefix().Cons(@operator),
|
||||||
|
Postfix:
|
||||||
|
() => node.Postfix().Cons(@operator),
|
||||||
|
Terminal:
|
||||||
|
() => node.Terminal().Cons(@operator)
|
||||||
);
|
);
|
||||||
// op.fixity, parts, holes
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PrecedenceDAG With(PrecedenceDAG precedenceDAG, Operator @operator) {
|
public static PrecedenceDAG With(PrecedenceDAG precedenceDAG, Operator @operator)
|
||||||
precedenceDAG.lens(@operator.precedenceGroup);
|
=> precedenceDAG.lens()[@operator.precedenceGroup].With(@operator);
|
||||||
/*precedenceDAG.update(
|
|
||||||
dagNode => dagNode.Add(@operator)
|
|
||||||
);*/
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DagToGrammar(DAGNode precedenceDAG) {
|
public static void DagToGrammar(DAGNode precedenceDAG) {
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,19 @@ public static class Generator {
|
||||||
|
|
||||||
w("using System;");
|
w("using System;");
|
||||||
w($"{singleHeader}");
|
w($"{singleHeader}");
|
||||||
|
foreach (var type in types) {
|
||||||
|
var name = type.Key;
|
||||||
|
var kind = type.Value.Item1;
|
||||||
|
var components = type.Value.Item2;
|
||||||
|
switch (kind) {
|
||||||
|
case Kind.Record:
|
||||||
|
w.RecordUsing(header, footer, qualifier, name, @components);
|
||||||
|
break;
|
||||||
|
case Kind.Variant:
|
||||||
|
w.VariantUsing(header, footer, qualifier, name, @components);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
w("");
|
w("");
|
||||||
foreach (var type in types) {
|
foreach (var type in types) {
|
||||||
var name = type.Key;
|
var name = type.Key;
|
||||||
|
|
|
@ -6,6 +6,15 @@ using System.Linq;
|
||||||
using Record = System.Collections.Immutable.ImmutableDictionary<string, string>;
|
using Record = System.Collections.Immutable.ImmutableDictionary<string, string>;
|
||||||
|
|
||||||
public static class RecordGenerator {
|
public static class RecordGenerator {
|
||||||
|
private static void NewExampleComment(this Action<string> w, string qualifier, string name, Record record) {
|
||||||
|
w($" /* To create an instance of {name}, write:");
|
||||||
|
w($" new {name}(");
|
||||||
|
w(String.Join(",\n", record.Select(@field =>
|
||||||
|
$" {@field.Key}: new {@field.Value}(…)")));
|
||||||
|
w($" )");
|
||||||
|
w($" */");
|
||||||
|
}
|
||||||
|
|
||||||
private static void Fields(this Action<string> w, string qualifier, string name, Record record) {
|
private static void Fields(this Action<string> w, string qualifier, string name, Record record) {
|
||||||
foreach (var @field in record) {
|
foreach (var @field in record) {
|
||||||
var F = @field.Key;
|
var F = @field.Key;
|
||||||
|
@ -69,7 +78,9 @@ public static class RecordGenerator {
|
||||||
private static void Lenses(this Action<string> w, string qualifier, string name, Record record) {
|
private static void Lenses(this Action<string> w, string qualifier, string name, Record record) {
|
||||||
w($" public sealed class Lens<Whole> : ILens<{name}, Whole> {{");
|
w($" public sealed class Lens<Whole> : ILens<{name}, Whole> {{");
|
||||||
w($" public readonly System.Func<{name}, Whole> wrap;");
|
w($" public readonly System.Func<{name}, Whole> wrap;");
|
||||||
w($" public readonly {name} oldHole;");
|
w($" private readonly {name} oldHole;");
|
||||||
|
w($"");
|
||||||
|
w($" public {name} value {{ get => oldHole; }}");
|
||||||
w($"");
|
w($"");
|
||||||
w($" public Lens(System.Func<{name}, Whole> wrap, {name} oldHole) {{");
|
w($" public Lens(System.Func<{name}, Whole> wrap, {name} oldHole) {{");
|
||||||
w($" this.wrap = wrap;");
|
w($" this.wrap = wrap;");
|
||||||
|
@ -84,7 +95,8 @@ public static class RecordGenerator {
|
||||||
w($" => oldHole.{F}.ChainLens(");
|
w($" => oldHole.{F}.ChainLens(");
|
||||||
w($" value => wrap(oldHole.With{caseF}(value)));");
|
w($" value => wrap(oldHole.With{caseF}(value)));");
|
||||||
}
|
}
|
||||||
w($" public Whole Update(Func<{name}, {name}> update) => wrap(update(oldHole));");
|
w($" public Whole Update(Func<{name}, {name}> update)");
|
||||||
|
w($" => wrap(update(oldHole));");
|
||||||
w($" }}");
|
w($" }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,10 +118,42 @@ public static class RecordGenerator {
|
||||||
w($" }}");
|
w($" }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void LensExtensionMethods(this Action<string> w, string qualifier, string name, Record record) {
|
||||||
|
w($" public static class {name}LensExtensionMethods {{");
|
||||||
|
foreach (var @field in record) {
|
||||||
|
var F = @field.Key;
|
||||||
|
var noAtF = F.StartsWith("@") ? F.Substring(1) : F;
|
||||||
|
var caseF = Char.ToUpper(noAtF[0]) + noAtF.Substring(1);
|
||||||
|
var Ty = @field.Value;
|
||||||
|
// same as {name}.Lens but as extension mehtods (should
|
||||||
|
// be extension properties once C# supports those) to
|
||||||
|
// be applied to instances of ILens<{name}, Whole>
|
||||||
|
w($" public static ILens<{Ty}, Whole>");
|
||||||
|
w($" {caseF}<Whole>(");
|
||||||
|
w($" this ILens<{qualifier}{name}, Whole> self)");
|
||||||
|
w($" => self.value.{F}.ChainLens(");
|
||||||
|
w($" value => self.Update(oldHole => oldHole.With{caseF}(value)));");
|
||||||
|
}
|
||||||
|
w($" }}");
|
||||||
|
}
|
||||||
|
|
||||||
public static void Record(this Action<string> w, string header, string footer, string qualifier, string name, Record record) {
|
public static void Record(this Action<string> w, string header, string footer, string qualifier, string name, Record record) {
|
||||||
w($"{header}");
|
w($"{header}");
|
||||||
w("");
|
w("");
|
||||||
|
w.NewExampleComment(qualifier, name, record);
|
||||||
|
w("");
|
||||||
w.RecordClass(qualifier, name, record);
|
w.RecordClass(qualifier, name, record);
|
||||||
w($"{footer}");
|
w($"{footer}");
|
||||||
|
w.LensExtensionMethods(qualifier, name, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void QualifierAliases(this Action<string> w, string qualifier, string name, Record record) {
|
||||||
|
if (qualifier != "") {
|
||||||
|
w($"using {name} = {qualifier}{name};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RecordUsing(this Action<string> w, string header, string footer, string qualifier, string name, Record record) {
|
||||||
|
w.QualifierAliases(qualifier, name, record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,8 +185,20 @@ public static class VariantGenerator {
|
||||||
w($"{header}");
|
w($"{header}");
|
||||||
w($"");
|
w($"");
|
||||||
w.MatchExampleComment(qualifier, name, variant);
|
w.MatchExampleComment(qualifier, name, variant);
|
||||||
|
w($"");
|
||||||
w.VariantClass(qualifier, name, variant);
|
w.VariantClass(qualifier, name, variant);
|
||||||
|
w($"");
|
||||||
w.ExtensionMethods(qualifier, name, variant);
|
w.ExtensionMethods(qualifier, name, variant);
|
||||||
w($"{footer}");
|
w($"{footer}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void QualifierAliases(this Action<string> w, string qualifier, string name, Variant variant) {
|
||||||
|
if (qualifier != "") {
|
||||||
|
w($"using {name} = {qualifier}{name};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void VariantUsing(this Action<string> w, string header, string footer, string qualifier, string name, Variant variant) {
|
||||||
|
w.QualifierAliases(qualifier, name, variant);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,11 @@ public class ImmutableDefaultDictionary<TKey, TValue> : IEnumerable<KeyValuePair
|
||||||
public readonly TValue defaultValue;
|
public readonly TValue defaultValue;
|
||||||
public readonly ImmutableDictionary<TKey, TValue> dictionary;
|
public readonly ImmutableDictionary<TKey, TValue> dictionary;
|
||||||
|
|
||||||
|
public ImmutableDefaultDictionary(TValue defaultValue) {
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
this.dictionary = ImmutableDictionary<TKey, TValue>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
public ImmutableDefaultDictionary(TValue defaultValue, ImmutableDictionary<TKey, TValue> dictionary) {
|
public ImmutableDefaultDictionary(TValue defaultValue, ImmutableDictionary<TKey, TValue> dictionary) {
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
this.dictionary = dictionary;
|
this.dictionary = dictionary;
|
||||||
|
@ -16,9 +21,15 @@ public class ImmutableDefaultDictionary<TKey, TValue> : IEnumerable<KeyValuePair
|
||||||
get => dictionary.GetOrDefault(key, defaultValue);
|
get => dictionary.GetOrDefault(key, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableDefaultDictionary<TKey, TValue> With(TKey key, TValue value)
|
public ImmutableDefaultDictionary<TKey, TValue> Add(TKey key, TValue value)
|
||||||
=> new ImmutableDefaultDictionary<TKey, TValue>(defaultValue, dictionary.Add(key, value));
|
=> new ImmutableDefaultDictionary<TKey, TValue>(defaultValue, dictionary.Add(key, value));
|
||||||
|
|
||||||
|
public ImmutableDefaultDictionary<TKey, TValue> SetItem(TKey key, TValue value)
|
||||||
|
=> new ImmutableDefaultDictionary<TKey, TValue>(defaultValue, dictionary.SetItem(key, value));
|
||||||
|
|
||||||
|
public ImmutableDefaultDictionary<TKey, TValue> Remove(TKey key)
|
||||||
|
=> new ImmutableDefaultDictionary<TKey, TValue>(defaultValue, dictionary.Remove(key));
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => dictionary.GetEnumerator();
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => dictionary.GetEnumerator();
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => dictionary.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => dictionary.GetEnumerator();
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Code quality of this file: low.
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
public interface ILens<Hole, Whole> {
|
public interface ILens<Hole, Whole> {
|
||||||
|
Hole value { get; }
|
||||||
Whole Update(Func<Hole, Hole> update);
|
Whole Update(Func<Hole, Hole> update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,12 +13,6 @@ public static class LensExtensionMethods {
|
||||||
public static Whole Cons<T, Whole>(this ILens<ImmutableList<T>, Whole> lens, T value)
|
public static Whole Cons<T, Whole>(this ILens<ImmutableList<T>, Whole> lens, T value)
|
||||||
=> lens.Update(oldHole => oldHole.Cons(value));
|
=> lens.Update(oldHole => oldHole.Cons(value));
|
||||||
|
|
||||||
public static ImmutableListLens<T, Whole>
|
|
||||||
ChainLens<T, Whole>(
|
|
||||||
this ImmutableList<T> hole,
|
|
||||||
System.Func<ImmutableList<T>, Whole> wrap)
|
|
||||||
=> new ImmutableListLens<T, Whole>(wrap: wrap, oldHole: hole);
|
|
||||||
|
|
||||||
public static ILens<string, Whole> ChainLens<Whole>(this string hole, System.Func<string, Whole> wrap) => new LeafLens<string, Whole>(wrap: wrap, oldHole: hole);
|
public static ILens<string, Whole> ChainLens<Whole>(this string hole, System.Func<string, Whole> wrap) => new LeafLens<string, Whole>(wrap: wrap, oldHole: hole);
|
||||||
|
|
||||||
public static ILens<Func<GraphemeCluster,bool>, Whole> ChainLens<Whole>(this Func<GraphemeCluster,bool> hole, System.Func<Func<GraphemeCluster,bool>, Whole> wrap) => new LeafLens<Func<GraphemeCluster,bool>, Whole>(wrap: wrap, oldHole: hole);
|
public static ILens<Func<GraphemeCluster,bool>, Whole> ChainLens<Whole>(this Func<GraphemeCluster,bool> hole, System.Func<Func<GraphemeCluster,bool>, Whole> wrap) => new LeafLens<Func<GraphemeCluster,bool>, Whole>(wrap: wrap, oldHole: hole);
|
||||||
|
|
86
Utils/Lens/ImmutableDefaultDictionaryLens.cs
Normal file
86
Utils/Lens/ImmutableDefaultDictionaryLens.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
// Code quality of this file: medium.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
public sealed class ImmutableDefaultDictionaryValueLens<TKey, TValue, Whole> : ILens<TValue, Whole> {
|
||||||
|
public readonly Func<ImmutableDefaultDictionary<TKey, TValue>, Whole> wrap;
|
||||||
|
|
||||||
|
private readonly ImmutableDefaultDictionary<TKey, TValue> oldDictionary;
|
||||||
|
|
||||||
|
private readonly TKey oldKey;
|
||||||
|
|
||||||
|
public TValue value { get => oldDictionary[oldKey]; }
|
||||||
|
|
||||||
|
public ImmutableDefaultDictionaryValueLens(Func<ImmutableDefaultDictionary<TKey, TValue>, Whole> wrap, ImmutableDefaultDictionary<TKey, TValue> oldDictionary, TKey oldKey) {
|
||||||
|
// TODO: check that key exists.
|
||||||
|
this.wrap = wrap;
|
||||||
|
this.oldDictionary = oldDictionary;
|
||||||
|
this.oldKey = oldKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put methods with the following signature here to focus on sub-parts of the list as needed.
|
||||||
|
// public ILens<ImmutableDefaultDictionary<T>,Whole> sub-part => oldHole.sub-part.ChainLens(value => oldHole.with-sub-part(value));
|
||||||
|
|
||||||
|
public Whole Update(Func<TValue, TValue> update) {
|
||||||
|
var oldValue = oldDictionary[oldKey];
|
||||||
|
return wrap(oldDictionary.SetItem(oldKey, update(oldValue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableDefaultDictionaryValueLens<TKey, TValue, Whole> UpdateKey(Func<TKey, TKey> update) {
|
||||||
|
var newKey = update(oldKey);
|
||||||
|
return new ImmutableDefaultDictionaryValueLens<TKey, TValue, Whole>(
|
||||||
|
wrap,
|
||||||
|
oldDictionary.Remove(oldKey).Add(newKey, oldDictionary[oldKey]),
|
||||||
|
newKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ImmutableDefaultDictionaryLens<TKey, TValue, Whole> : ILens<ImmutableDefaultDictionary<TKey, TValue>, Whole> {
|
||||||
|
public readonly Func<ImmutableDefaultDictionary<TKey, TValue>, Whole> wrap;
|
||||||
|
private readonly ImmutableDefaultDictionary<TKey, TValue> oldHole;
|
||||||
|
|
||||||
|
public ImmutableDefaultDictionary<TKey, TValue> value { get => oldHole; }
|
||||||
|
|
||||||
|
public ImmutableDefaultDictionaryLens(Func<ImmutableDefaultDictionary<TKey, TValue>, Whole> wrap, ImmutableDefaultDictionary<TKey, TValue> oldHole) {
|
||||||
|
// TODO: check that key exists.
|
||||||
|
this.wrap = wrap;
|
||||||
|
this.oldHole = oldHole;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put methods with the following signature here to focus on sub-parts of the list as needed.
|
||||||
|
public ImmutableDefaultDictionaryValueLens<TKey, TValue, Whole> this[TKey key] {
|
||||||
|
get => new ImmutableDefaultDictionaryValueLens<TKey, TValue, Whole>(wrap, oldHole, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Whole Update(Func<ImmutableDefaultDictionary<TKey, TValue>, ImmutableDefaultDictionary<TKey, TValue>> update) {
|
||||||
|
return wrap(update(oldHole));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ImmutableDefaultDictionaryLensExtensionMethods {
|
||||||
|
public static ImmutableDefaultDictionaryLens<TKey, TValue, Whole>
|
||||||
|
ChainLens<TKey, TValue, Whole>(
|
||||||
|
this ImmutableDefaultDictionary<TKey, TValue> hole,
|
||||||
|
System.Func<ImmutableDefaultDictionary<TKey, TValue>, Whole> wrap)
|
||||||
|
=> new ImmutableDefaultDictionaryLens<TKey, TValue, Whole>(wrap: wrap, oldHole: hole);
|
||||||
|
|
||||||
|
// TODO: this should be an extension property (once C# supports them)
|
||||||
|
public static ImmutableDefaultDictionaryLens<TKey, TValue, ImmutableDefaultDictionary<TKey, TValue>>
|
||||||
|
lens<TKey, TValue>(
|
||||||
|
this ImmutableDefaultDictionary<TKey, TValue> d)
|
||||||
|
=> d.ChainLens(x => x);
|
||||||
|
|
||||||
|
// this is a shorthand since we don't have extension properties
|
||||||
|
public static ImmutableDefaultDictionaryValueLens<TKey, TValue, ImmutableDefaultDictionary<TKey, TValue>>
|
||||||
|
lens<TKey, TValue>(
|
||||||
|
this ImmutableDefaultDictionary<TKey, TValue> d,
|
||||||
|
TKey key)
|
||||||
|
=> d.lens()[key];
|
||||||
|
|
||||||
|
public static ImmutableDefaultDictionaryValueLens<TKey, TValue, Whole>
|
||||||
|
UpdateKey<TKey, TValue, Whole>(
|
||||||
|
this ImmutableDefaultDictionaryValueLens<TKey, TValue, Whole> lens,
|
||||||
|
TKey newKey)
|
||||||
|
=> lens.UpdateKey(oldKey => newKey);
|
||||||
|
}
|
|
@ -1,63 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Immutable;
|
|
||||||
|
|
||||||
public sealed class ImmutableDictionaryValueLens<TKey, TValue, Whole> : ILens<TValue, Whole> {
|
|
||||||
public readonly Func<ImmutableDictionary<TKey, TValue>, Whole> wrap;
|
|
||||||
public readonly ImmutableDictionary<TKey, TValue> oldDictionary;
|
|
||||||
public readonly TKey oldKey;
|
|
||||||
|
|
||||||
public ImmutableDictionaryValueLens(Func<ImmutableDictionary<TKey, TValue>, Whole> wrap, ImmutableDictionary<TKey, TValue> oldDictionary, TKey oldKey) {
|
|
||||||
// TODO: check that key exists.
|
|
||||||
this.wrap = wrap;
|
|
||||||
this.oldDictionary = oldDictionary;
|
|
||||||
this.oldKey = oldKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put methods with the following signature here to focus on sub-parts of the list as needed.
|
|
||||||
// public ILens<ImmutableList<T>,Whole> sub-part => oldHole.sub-part.ChainLens(value => oldHole.with-sub-part(value));
|
|
||||||
|
|
||||||
public Whole Update(Func<TValue, TValue> update) {
|
|
||||||
var oldValue = oldDictionary[oldKey];
|
|
||||||
return wrap(oldDictionary.SetItem(oldKey, update(oldValue)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImmutableDictionaryValueLens<TKey, TValue, Whole> UpdateKey(Func<TKey, TKey> update) {
|
|
||||||
var newKey = update(oldKey);
|
|
||||||
return new ImmutableDictionaryValueLens<TKey, TValue, Whole>(
|
|
||||||
wrap,
|
|
||||||
oldDictionary.Remove(oldKey).Add(newKey, oldDictionary[oldKey]),
|
|
||||||
newKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ImmutableDictionaryLens<TKey, TValue, Whole> : ILens<ImmutableDictionary<TKey, TValue>, Whole> {
|
|
||||||
public readonly Func<ImmutableDictionary<TKey, TValue>, Whole> wrap;
|
|
||||||
public readonly ImmutableDictionary<TKey, TValue> oldHole;
|
|
||||||
|
|
||||||
public ImmutableDictionaryLens(Func<ImmutableDictionary<TKey, TValue>, Whole> wrap, ImmutableDictionary<TKey, TValue> oldHole) {
|
|
||||||
// TODO: check that key exists.
|
|
||||||
this.wrap = wrap;
|
|
||||||
this.oldHole = oldHole;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put methods with the following signature here to focus on sub-parts of the list as needed.
|
|
||||||
public ImmutableDictionaryValueLens<TKey, TValue, Whole> this[TKey key] {
|
|
||||||
get => new ImmutableDictionaryValueLens<TKey, TValue, Whole>(wrap, oldHole, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Whole Update(Func<ImmutableDictionary<TKey, TValue>, ImmutableDictionary<TKey, TValue>> update) {
|
|
||||||
return wrap(update(oldHole));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ImmutableDictionaryLensExtensionMethods {
|
|
||||||
public static ImmutableDictionaryLens<TKey, TValue, ImmutableDictionary<TKey, TValue>> lens<TKey, TValue>(this ImmutableDictionary<TKey, TValue> d)
|
|
||||||
=> new ImmutableDictionaryLens<TKey, TValue, ImmutableDictionary<TKey, TValue>>(x => x, d);
|
|
||||||
|
|
||||||
public static ImmutableDictionaryValueLens<TKey, TValue, Whole> UpdateKey<TKey, TValue, Whole, Whole>(this ImmutableDictionaryValueLens<TKey, TValue, Whole> lens, TKey newKey)
|
|
||||||
=> lens.UpdateKey(oldKey => newKey);
|
|
||||||
|
|
||||||
// This would need an IFocusable<TValue> constraint which is hard to get
|
|
||||||
//public static ILens<ImmutableDictionary<TKey, ?>, Whole> ChainLens<TKey, Whole>(this ImmutableDictionary<TKey, ?> hole, System.Func<ImmutableDictionary<TKey, ?>, Whole> wrap)
|
|
||||||
// => new ImmutableDictionaryLens<TKey, ?, Whole>(wrap: wrap, oldHole: hole);
|
|
||||||
}
|
|
|
@ -3,7 +3,9 @@ using System.Collections.Immutable;
|
||||||
|
|
||||||
public sealed class ImmutableListLens<T, Whole> : ILens<ImmutableList<T>, Whole> {
|
public sealed class ImmutableListLens<T, Whole> : ILens<ImmutableList<T>, Whole> {
|
||||||
public readonly Func<ImmutableList<T>, Whole> wrap;
|
public readonly Func<ImmutableList<T>, Whole> wrap;
|
||||||
public readonly ImmutableList<T> oldHole;
|
private readonly ImmutableList<T> oldHole;
|
||||||
|
|
||||||
|
public ImmutableList<T> value { get => oldHole; }
|
||||||
|
|
||||||
public ImmutableListLens(Func<ImmutableList<T>, Whole> wrap, ImmutableList<T> oldHole) {
|
public ImmutableListLens(Func<ImmutableList<T>, Whole> wrap, ImmutableList<T> oldHole) {
|
||||||
this.wrap = wrap;
|
this.wrap = wrap;
|
||||||
|
@ -11,12 +13,21 @@ public sealed class ImmutableListLens<T, Whole> : ILens<ImmutableList<T>, Whole>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put methods with the following signature here to focus on sub-parts of the list as needed.
|
// Put methods with the following signature here to focus on sub-parts of the list as needed.
|
||||||
// public ILens<ImmutableList<T>,Whole> sub-part => oldHole.sub-part.ChainLens(value => oldHole.with-sub-part(value));
|
// public ILens<ImmutableList<T>,Whole> sub-part
|
||||||
|
// => oldHole.sub-part.ChainLens(value => oldHole.with-sub-part(value));
|
||||||
|
|
||||||
public Whole Update(Func<ImmutableList<T>, ImmutableList<T>> update) => wrap(update(oldHole));
|
public Whole Update(Func<ImmutableList<T>, ImmutableList<T>> update) => wrap(update(oldHole));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ImmutableListLensExtensionMethods {
|
public static class ImmutableListLensExtensionMethods {
|
||||||
public static ILens<ImmutableList<string>, Whole> ChainLens<Whole>(this ImmutableList<string> hole, System.Func<ImmutableList<string>, Whole> wrap)
|
public static ImmutableListLens<T, Whole>
|
||||||
=> new ImmutableListLens<string, Whole>(wrap: wrap, oldHole: hole);
|
ChainLens<T, Whole>(
|
||||||
}
|
this ImmutableList<T> hole,
|
||||||
|
System.Func<ImmutableList<T>, Whole> wrap)
|
||||||
|
=> new ImmutableListLens<T, Whole>(wrap: wrap, oldHole: hole);
|
||||||
|
|
||||||
|
public static ImmutableListLens<T, ImmutableList<T>>
|
||||||
|
lens<T>(
|
||||||
|
this ImmutableList<T> d)
|
||||||
|
=> d.ChainLens(x => x);
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@ using System.Collections.Immutable;
|
||||||
// interesting to further focus.
|
// interesting to further focus.
|
||||||
public sealed class LeafLens<T, Whole> : ILens<T, Whole> {
|
public sealed class LeafLens<T, Whole> : ILens<T, Whole> {
|
||||||
public readonly System.Func<T, Whole> wrap;
|
public readonly System.Func<T, Whole> wrap;
|
||||||
public readonly T oldHole;
|
private readonly T oldHole;
|
||||||
|
|
||||||
|
public T value { get => oldHole; }
|
||||||
|
|
||||||
public LeafLens(System.Func<T, Whole> wrap, T oldHole) {
|
public LeafLens(System.Func<T, Whole> wrap, T oldHole) {
|
||||||
this.wrap = wrap;
|
this.wrap = wrap;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user