Skip to content

Commit

Permalink
Merge pull request #5 from thinker227/updated-tree-model
Browse files Browse the repository at this point in the history
Pass and tree model have been updated, and some functionality has been implemented. Tests still need to be written.
  • Loading branch information
thinker227 authored Aug 20, 2022
2 parents 3752f75 + 4f93f3b commit 020b487
Show file tree
Hide file tree
Showing 12 changed files with 373 additions and 21 deletions.
53 changes: 52 additions & 1 deletion src/NanopassSharp/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;

namespace NanopassSharp;

public static class Extensions
{

public static IEnumerable<(T first, T second)> WithNext<T>(this IEnumerable<T> source)
{
T? prev = default;
Expand Down Expand Up @@ -53,4 +54,54 @@ public static async ValueTask<U> Then<T, U>(this ValueTask<T> task, Func<T, Task
return await f(result);
}

public static bool DictionaryEquals<TKey, TValue>(this IDictionary<TKey, TValue> source, IDictionary<TKey, TValue> other) =>
source.DictionaryEquals(other, EqualityComparer<TValue>.Default);
public static bool DictionaryEquals<TKey, TValue>(this IDictionary<TKey, TValue> source, IDictionary<TKey, TValue> other, IEqualityComparer<TValue> valueComparer) =>
DictionaryEquals(new ReadOnlyDictionaryAdapter<TKey, TValue>(source), new ReadOnlyDictionaryAdapter<TKey, TValue>(other), valueComparer);
public static bool DictionaryEquals<TKey, TValue>(this IDictionary<TKey, TValue> source, IReadOnlyDictionary<TKey, TValue> other) =>
source.DictionaryEquals(other, EqualityComparer<TValue>.Default);
public static bool DictionaryEquals<TKey, TValue>(this IDictionary<TKey, TValue> source, IReadOnlyDictionary<TKey, TValue> other, IEqualityComparer<TValue> valueComparer) =>
DictionaryEquals(new ReadOnlyDictionaryAdapter<TKey, TValue>(source), other, valueComparer);
public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source, IDictionary<TKey, TValue> other) =>
source.DictionaryEquals(other, EqualityComparer<TValue>.Default);
public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source, IDictionary<TKey, TValue> other, IEqualityComparer<TValue> valueComparer) =>
DictionaryEquals(source, new ReadOnlyDictionaryAdapter<TKey, TValue>(other), valueComparer);
public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source, IReadOnlyDictionary<TKey, TValue> other) =>
source.DictionaryEquals(other, EqualityComparer<TValue>.Default);
public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source, IReadOnlyDictionary<TKey, TValue> other, IEqualityComparer<TValue> valueComparer)
{
if (source.Count != other.Count) return false;

foreach (var (key, sourceValue) in source)
{
if (!other.ContainsKey(key)) return false;

var otherValue = other[key];
if (!valueComparer.Equals(sourceValue, otherValue)) return false;
}

return true;
}
private sealed class ReadOnlyDictionaryAdapter<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
{
private readonly IDictionary<TKey, TValue> dictionary;

public TValue this[TKey key] => dictionary[key];
public IEnumerable<TKey> Keys => dictionary.Keys;
public IEnumerable<TValue> Values => dictionary.Values;
public int Count => dictionary.Count;

public ReadOnlyDictionaryAdapter(IDictionary<TKey, TValue> dictionary)
{
this.dictionary = dictionary;
}

public bool ContainsKey(TKey key) => dictionary.ContainsKey(key);
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => dictionary.GetEnumerator();
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) => dictionary.TryGetValue(key, out value);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

public static bool SetEquals<T>(this ISet<T> source, ISet<T> other) =>
source.Count == other.Count && source.Overlaps(other);
}
4 changes: 0 additions & 4 deletions src/NanopassSharp/Functional/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ namespace NanopassSharp.Functional;
/// <typeparam name="T">The type of the success value.</typeparam>
public readonly struct Result<T> : IEquatable<Result<T>>, IEquatable<T>
{

/// <summary>
/// The result value.
/// </summary>
Expand Down Expand Up @@ -203,12 +202,10 @@ public static explicit operator T(Result<T> result) =>
result.Equals(value);
public static bool operator !=(Result<T> result, T value) =>
!result.Equals(value);

}

public static class Result
{

/// <summary>
/// Creates a <see cref="Result{T}"/> with a successful state.
/// </summary>
Expand Down Expand Up @@ -249,5 +246,4 @@ public static Result<T> CreateNotNull<T>(T? value, string? error = null, [Caller
value is not null
? new(value.Value)
: new(error ?? $"{callerExpression} was null");

}
2 changes: 0 additions & 2 deletions src/NanopassSharp/Functional/ResultExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace NanopassSharp.Functional;
public static class ResultExtensions
{

/// <summary>
/// Returns the inner value as either itself or the type's default value.
/// </summary>
Expand Down Expand Up @@ -40,5 +39,4 @@ public static Result<U> Apply<T, U>(this Result<Func<T, U>> source, Result<T> re
new Result<U>(f(x))
)
);

}
2 changes: 0 additions & 2 deletions src/NanopassSharp/Functional/TaskResultExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ namespace NanopassSharp.Functional;

public static class TaskResultExtensions
{

public static async Task<TResult> SwitchResultAsync<T, TResult>(this Task<Result<T>> source, Func<T, Task<TResult>> ifSuccess, Func<string, Task<TResult>> ifFailure) =>
await (await source).SwitchAsync(ifSuccess, ifFailure);
public static async Task<TResult> SwitchResultAsync<T, TResult>(this Task<Result<T>> source, Func<T, TResult> ifSuccess, Func<string, TResult> ifFailure) =>
Expand Down Expand Up @@ -89,5 +88,4 @@ public static async Task<Result<T>> NotNullResultAsync<T>(this Task<Result<T?>>
public static async Task<Result<T>> NotNullResultAsync<T>(this Task<Result<T?>> result, string? error = null)
where T : struct =>
(await result).Bind(v => v is not null ? new Result<T>(v.Value) : error ?? "Inner result value was null");

}
61 changes: 61 additions & 0 deletions src/NanopassSharp/ITransformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
namespace NanopassSharp;

/// <summary>
/// A description of a transformation and pattern.
/// </summary>
public interface ITransformationDescription
{
/// <summary>
/// The pattern the transformation is triggered by.
/// </summary>
ITransformationPattern? Pattern { get; }
/// <summary>
/// The transformation to apply.
/// </summary>
ITransformation Transformation { get; }
}

/// <summary>
/// A transformation on a node or node member.
/// </summary>
public interface ITransformation
{
/// <summary>
/// Applies the transformation to a node tree.
/// </summary>
/// <param name="tree">The tree the node is a part of.</param>
/// <param name="node">The node to apply the transformation to.</param>
/// <returns>A new node with the applied transformation.</returns>
AstNode ApplyToNode(AstNodeHierarchy tree, AstNode node);
/// <summary>
/// Applies the transformation to a node member.
/// </summary>
/// <param name="tree">The tree the node of the member is a part of.</param>
/// <param name="node">The node the member is a part of.</param>
/// <param name="member">The member to apply the transformation to.</param>
/// <returns>A new member with the applied transformation.</returns>
AstNodeMember ApplyToMember(AstNodeHierarchy tree, AstNode node, AstNodeMember member);
}

/// <summary>
/// A pattern for a transformation.
/// </summary>
public interface ITransformationPattern
{
/// <summary>
/// Whether the pattern is recursive.
/// </summary>
bool IsRecursive { get; }

/// <summary>
/// Returns whether a node matches the pattern.
/// </summary>
/// <param name="node">The node to check.</param>
bool IsMatch(AstNode node);
/// <summary>
/// Returns whether a member of a node matches the pattern.
/// </summary>
/// <param name="node">The node the member is a part of.</param>
/// <param name="member">The node member to check.</param>
bool IsMatch(AstNode node, AstNodeMember member);
}
6 changes: 0 additions & 6 deletions src/NanopassSharp/Models/PassModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,22 @@ namespace NanopassSharp.Models;

public sealed class PassModel
{

public string Name { get; set; } = "";
public ModificationPassModel? Mod { get; set; }
public string? Type { get; set; }

}

public sealed class ModificationPassModel
{

public string? TypeName { get; set; }
public List<ModificationModel> Add { get; set; } = new();
public List<ModificationModel> Remove { get; set; } = new();

}

public sealed class ModificationModel
{

public string Target { get; set; } = "";
public string? Parameter { get; set; }
public string? Property { get; set; }
public string? Type { get; set; }

}
157 changes: 157 additions & 0 deletions src/NanopassSharp/Pass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace NanopassSharp;

/// <summary>
/// A single compiler pass.
/// </summary>
/// <param name="Name">The name of the pass.</param>
/// <param name="Documentation">The pass' corresponding documentation.</param>
/// <param name="Transformations">The transformations the pass applies to its nodes.</param>
/// <param name="Previous">The previous pass which this pass is based on.</param>
public sealed record class CompilerPass
(
string Name,
string? Documentation,
PassTransformations Transformations,
CompilerPass Previous
)
{
/// <summary>
/// The next pass immediately based on this pass.
/// </summary>
public CompilerPass? Next { get; set; }

private AstNodeHierarchy? tree;
/// <summary>
/// The transformed tree of this pass.
/// </summary>
public AstNodeHierarchy Tree =>
tree ??= PassTransformer.ApplyTransformations(Previous.Tree, Transformations);
}

/// <summary>
/// The transformations applied by a <see cref="CompilerPass"/>.
/// </summary>
/// <param name="Transformations">A list of transformations.</param>
public sealed record class PassTransformations
(
IList<ITransformationDescription> Transformations
);

/// <summary>
/// A tree of nodes representing types which are the input and output of a pass.
/// </summary>
/// <param name="Roots">The root nodes.
/// May be multiple if the language does not support nested types.</param>
/// <param name="Nodes">The nodes of the tree.</param>
public sealed record class AstNodeHierarchy
(
IList<AstNode> Roots
)
{
public bool Equals(AstNodeHierarchy? other)
{
if (other is null) return false;

if (!other.Roots.SequenceEqual(Roots)) return false;

return true;
}
public override int GetHashCode()
{
HashCode hashCode = new();

foreach (var root in Roots) hashCode.Add(root);

return hashCode.ToHashCode();
}
}

/// <summary>
/// A node representing a type in a compiler pass.
/// </summary>
/// <param name="Name">The name of the type.</param>
/// <param name="Documentation">The type's corresponding documentation.</param>
/// <param name="Parent">The parent type node.
/// <see langword="null"/> if the node is a root node.</param>
/// <param name="Children">The children of the node (typically nested types).</param>
/// <param name="Members">The members of the type.</param>
/// <param name="Attributes">The language-specific attributes of the type.</param>
public sealed record class AstNode
(
string Name,
string? Documentation,
AstNode? Parent,
IDictionary<string, AstNode> Children,
IDictionary<string, AstNodeMember> Members,
ISet<object> Attributes
)
{
public bool Equals(AstNode? other)
{
if (other is null) return false;

if (other.Name != Name) return false;
if (other.Documentation != Documentation) return false;
if (!other.Children.DictionaryEquals(Children)) return false;
if (!other.Members.DictionaryEquals(Members)) return false;
if (!other.Attributes.SetEquals(Attributes)) return false;
return true;
}
public override int GetHashCode()
{
HashCode hashCode = new();

hashCode.Add(Name);
hashCode.Add(Documentation);
foreach (var child in Children.Values) hashCode.Add(child);
foreach (var member in Members.Values) hashCode.Add(member);
foreach (object attribute in Attributes) hashCode.Add(attribute);

return hashCode.ToHashCode();
}
}

/// <summary>
/// A member of a <see cref="AstNode"/>.
/// </summary>
/// <param name="Name">The name of the member.</param>
/// <param name="Documentation">The member's corresponding documentation.</param>
/// <param name="Type">The type of the member.
/// May be <see langword="null"/> in dynamically typed languages
/// or languages without explicitly typed members.</param>
/// <param name="Attributes">The language-specific attributes of the member.</param>
public sealed record class AstNodeMember
(
string Name,
string? Documentation,
string? Type,
ISet<object> Attributes
)
{
public bool Equals(AstNodeMember? other)
{
if (other is null) return false;

if (other.Name != Name) return false;
if (other.Documentation != Documentation) return false;
if (other.Type != Type) return false;
if (!other.Attributes.SetEquals(Attributes)) return false;

return true;
}
public override int GetHashCode()
{
HashCode hashCode = new();

hashCode.Add(Name);
hashCode.Add(Documentation);
hashCode.Add(Type);
foreach (object attribute in Attributes) hashCode.Add(attribute);

return hashCode.ToHashCode();
}
}
Loading

0 comments on commit 020b487

Please sign in to comment.