Last active
May 24, 2016 21:16
-
-
Save mrange/34341f15612e0799a67d50b7350f478d to your computer and use it in GitHub Desktop.
Reusable ADT generator for C#/T4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
var model = new Model () | |
{ | |
Namespace = "MyNameSpace" , | |
Unions = new [] | |
{ | |
U ( "CustomerKind" | |
, UC ("Person" , F ("string", "FullName"), F ("string", "SocialNo" ), F ("DateTime", "BirthDate" )) | |
, UC ("Company", F ("string", "Name" ), F ("string", "CompanyNo"), F ("string" , "TaxNo" )) | |
), | |
}, | |
Tuples = new [] | |
{ | |
T ("Address", F ("string", "Street"), F ("string", "Zip"), F ("string", "City"), F ("string", "State")) , | |
}, | |
}; | |
#> | |
namespace <#=model.Namespace#> | |
{ | |
using System; | |
using System.Text; | |
<# | |
foreach (var tuple in model.Tuples) | |
{ | |
#> | |
// Tuple: <#=tuple.Name#> | |
partial struct <#=tuple.Name#> | |
: IEquatable<<#=tuple.Name#>> | |
, IComparable<<#=tuple.Name#>> | |
, IComparable | |
{ | |
<# | |
TupleMembers (4, false, "tuple", tuple.Name, tuple.Fields); | |
#> | |
public int CompareTo (object other) | |
{ | |
return other is <#=tuple.Name#> | |
? CompareTo ((<#=tuple.Name#>) other) | |
: 1 | |
; | |
} | |
} | |
// Tuple: <#=tuple.Name#> | |
<# | |
} | |
#> | |
<# | |
foreach (var union in model.Unions) | |
{ | |
var tag = 0; | |
#> | |
// Union: <#=union.Name#> | |
abstract partial class <#=union.Name#> | |
: IEquatable<<#=union.Name#>> | |
, IComparable<<#=union.Name#>> | |
, IComparable | |
{ | |
public abstract int Tag { get; } | |
public abstract bool Equals (<#=union.Name#> other); | |
public abstract int CompareTo (<#=union.Name#> other); | |
public abstract int CompareTo (object other); | |
public TResult Match<TResult> ( | |
TResult defaultValue | |
<# | |
foreach (var unionCase in union.UnionCases) | |
{ | |
#> | |
, Func<<#=unionCase.Name#>, TResult> <#=LowerCaseFirst (unionCase.Name)#> = null | |
<# | |
} | |
#> | |
) | |
{ | |
switch (Tag) | |
{ | |
<# | |
tag = 0; | |
foreach (var unionCase in union.UnionCases) | |
{ | |
++tag; | |
var lucn = LowerCaseFirst (unionCase.Name); | |
#> | |
case <#=tag#>: | |
return <#=lucn#> != null | |
? <#=lucn#> ((<#=unionCase.Name#>)this) | |
: defaultValue | |
; | |
<# | |
} | |
#> | |
default: | |
throw new Exception ("union/<#=union.Name#>: Invalid union case"); | |
} | |
} | |
<# | |
tag = 0; | |
foreach (var unionCase in union.UnionCases) | |
{ | |
++tag; | |
#> | |
// UnionCase: <#=unionCase.Name#> | |
public partial class <#=unionCase.Name#> | |
: <#=union.Name#> | |
, IEquatable<<#=unionCase.Name#>> | |
, IComparable<<#=unionCase.Name#>>, IComparable | |
{ | |
<# | |
TupleMembers (6, true, "union/" + union.Name, unionCase.Name, unionCase.Fields); | |
#> | |
public override int Tag | |
{ | |
get | |
{ | |
return <#=tag#>; | |
} | |
} | |
public override bool Equals (<#=union.Name#> other) | |
{ | |
return other is <#=unionCase.Name#> | |
? Equals ((<#=unionCase.Name#>) other) | |
: false | |
; | |
} | |
public override int CompareTo (<#=union.Name#> other) | |
{ | |
return other is <#=unionCase.Name#> | |
? CompareTo ((<#=unionCase.Name#>) other) | |
: <#=tag#> < ((<#=union.Name#>)other).Tag ? -1 : 1 | |
; | |
} | |
public override int CompareTo (object other) | |
{ | |
if (other is <#=unionCase.Name#>) | |
{ | |
return CompareTo ((<#=unionCase.Name#>) other); | |
} | |
else if (other is <#=union.Name#>) | |
{ | |
return <#=tag#> < ((<#=union.Name#>)other).Tag ? -1 : 1; | |
} | |
else | |
{ | |
return 1; | |
} | |
} | |
} | |
// UnionCase: <#=unionCase.Name#> | |
<# | |
} | |
#> | |
} | |
// Union: <#=union.Name#> | |
<# | |
} | |
#> | |
} | |
<#+ | |
static FieldDefinition F (string type, string name) | |
{ | |
return new FieldDefinition | |
{ | |
Type = type ?? NoType , | |
Name = name ?? NoName , | |
}; | |
} | |
static UnionDefinition U (string name, params UnionCaseDefinition[] unionCases) | |
{ | |
return new UnionDefinition | |
{ | |
Name = name ?? NoName , | |
UnionCases = unionCases ?? new UnionCaseDefinition[0], | |
}; | |
} | |
static UnionCaseDefinition UC (string name, params FieldDefinition[] fields) | |
{ | |
return new UnionCaseDefinition | |
{ | |
Name = name ?? NoName , | |
Fields = fields ?? new FieldDefinition[0], | |
}; | |
} | |
static TupleDefinition T (string name, params FieldDefinition[] fields) | |
{ | |
return new TupleDefinition | |
{ | |
Name = name ?? NoName , | |
Fields = fields ?? new FieldDefinition[0], | |
}; | |
} | |
class Model | |
{ | |
public string Namespace = NoName ; | |
public UnionDefinition[] Unions = new UnionDefinition[0] ; | |
public TupleDefinition[] Tuples = new TupleDefinition[0] ; | |
} | |
class FieldDefinition | |
{ | |
public string Type = NoType ; | |
public string Name = NoName ; | |
} | |
class UnionCaseDefinition | |
{ | |
public string Name = NoName ; | |
public FieldDefinition[] Fields = new FieldDefinition[0] ; | |
} | |
class UnionDefinition | |
{ | |
public string Name = NoName ; | |
public UnionCaseDefinition[] UnionCases = new UnionCaseDefinition[0]; | |
} | |
class TupleDefinition | |
{ | |
public string Name = NoName ; | |
public FieldDefinition[] Fields = new FieldDefinition[0] ; | |
} | |
const string NoName = "<NoName>"; | |
const string NoType = "<NoType>"; | |
static string LowerCaseFirst (string name) | |
{ | |
return string.IsNullOrEmpty (name) | |
? "" | |
: char.ToLowerInvariant (name[0]) + name.Substring (1) | |
; | |
} | |
void PushIndent (int i) | |
{ | |
PushIndent (new string (' ', i)); | |
} | |
void ApplyTo<T> (Action<bool, T> transform, params T[] vs) | |
{ | |
var first = true; | |
foreach (var v in vs) | |
{ | |
transform (first, v); | |
first = false; | |
} | |
} | |
void FormatArgument (bool first, FieldDefinition field) | |
{ | |
#> | |
<#=first ? " " : ","#> <#=LowerCaseFirst (field.Name)#> | |
<#+ | |
} | |
void FormatParameter (bool first, FieldDefinition field) | |
{ | |
#> | |
<#=first ? " " : ","#> <#=field.Type#> <#=LowerCaseFirst (field.Name)#> | |
<#+ | |
} | |
void TupleMembers (int indent, bool refType, string prelude, string name, FieldDefinition[] fields) | |
{ | |
PushIndent (indent); | |
foreach (var field in fields) | |
{ | |
#> | |
public <#=field.Type#> <#=field.Name#>; | |
<#+ | |
} | |
#> | |
public <#=name#> ( | |
<#+ | |
ApplyTo (FormatParameter, fields); | |
#> | |
) | |
{ | |
<#+ | |
foreach (var field in fields) | |
{ | |
#> | |
<#=field.Name#> = <#=LowerCaseFirst (field.Name)#>; | |
<#+ | |
} | |
#> | |
} | |
public static <#=name#> Create ( | |
<#+ | |
ApplyTo (FormatParameter, fields); | |
#> | |
) | |
{ | |
return new <#=name#> ( | |
<#+ | |
ApplyTo (FormatArgument, fields); | |
#> | |
); | |
} | |
public override string ToString () | |
{ | |
var sb = new StringBuilder (16); | |
sb.Append ("(<#=prelude#>/<#=name#>"); | |
<#+ | |
foreach (var field in fields) | |
{ | |
#> | |
sb.AppendFormat (", {0}", <#=field.Name#>); | |
<#+ | |
} | |
#> | |
sb.Append (")"); | |
return sb.ToString (); | |
} | |
public bool Equals (<#=name#> other) | |
{ | |
<#+ | |
if (refType) | |
{ | |
#> | |
if (other == null) | |
{ | |
return false; | |
} | |
<#+ | |
} | |
#> | |
return | |
true | |
<#+ | |
foreach (var field in fields) | |
{ | |
#> | |
&& (<#=field.Name#> == default (<#=field.Type#>) ? other.<#=field.Name#> == default (<#=field.Type#>) : <#=field.Name#>.Equals (other.<#=field.Name#>)) | |
<#+ | |
} | |
#> | |
; | |
} | |
public override bool Equals (object other) | |
{ | |
return other is <#=name#> | |
? Equals ((<#=name#>) other) | |
: false | |
; | |
} | |
public override int GetHashCode () | |
{ | |
var hashCode = 17; | |
<#+ | |
foreach (var field in fields) | |
{ | |
#> | |
hashCode = hashCode * 23 + (<#=field.Name#> != default (<#=field.Type#>) ? <#=field.Name#>.GetHashCode () : 17); | |
<#+ | |
} | |
#> | |
return hashCode; | |
} | |
public int CompareTo (<#=name#> other) | |
{ | |
<#+ | |
if (refType) | |
{ | |
#> | |
if (other == null) | |
{ | |
return 1; | |
} | |
<#+ | |
} | |
#> | |
<#+ | |
foreach (var field in fields) | |
{ | |
#> | |
{ | |
var c = <#=field.Name#> == default (<#=field.Type#>) | |
? (other.<#=field.Name#> == default (<#=field.Type#>) ? 0 : -1) | |
: <#=field.Name#>.CompareTo (other.<#=field.Name#>) | |
; | |
if (c != 0) | |
{ | |
return c; | |
} | |
} | |
<#+ | |
} | |
#> | |
return 0; | |
} | |
<#+ | |
PopIndent (); | |
} | |
#> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment