Skip to content

Instantly share code, notes, and snippets.

@mrange
Last active June 11, 2022 05:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrange/ec69b55cbdaf9af29e4c8d0792cb8781 to your computer and use it in GitHub Desktop.
Save mrange/ec69b55cbdaf9af29e4c8d0792cb8781 to your computer and use it in GitHub Desktop.
GenAll T4
<#@ assembly name ="System.Core" #>
<#@ import namespace ="System.Linq" #>
<#
var model = new []
{
Union(
"BooleanValue"
, Case("False")
, Case("True")
)
, Union(
"NumberValue"
, Case("Zero")
, Case("One")
, Case("PI")
)
, Union(
"StringValue"
, Case("Empty")
, Case("Hello")
, Case("Escaped")
)
, Union(
"ArrayValue"
, Case("Empty")
, Case("One", ("JsonValue", "V0"))
, Case("Two", ("JsonValue", "V0"), ("JsonValue", "V1"))
)
, Record("MemberValue", ("StringValue", "Key"), ("JsonValue", "Value"))
, Union(
"ObjectValue"
, Case("Empty")
, Case("One", ("MemberValue", "V0"))
, Case("Two", ("MemberValue", "V0"), ("MemberValue", "V1"))
)
, Union(
"JsonValue"
, Case("Null" )
, Case("String" , ("StringValue" , "Value"))
, Case("Number" , ("NumberValue" , "Value"))
, Case("Boolean", ("BooleanValue" , "Value"))
, Case("Array" , ("ArrayValue" , "Value"))
, Case("Object" , ("ObjectValue" , "Value"))
)
};
#>
namespace CsGenAll
{
<#
var prefix = "";
#>
<# foreach (var td in model) { #>
<#
var kind = WhatKind(td);
var (bnm, cs) = td;
#>
// <#=bnm#> - BEGIN
// Kind: <#=kind#>
<#
switch(kind)
{
default:
case Kind.IsEmpty: { #>
sealed partial record <#=bnm#>();
<# }
break;
case Kind.IsRecord: { #>
<#
var (_, args) = cs[0];
#>
sealed partial record <#=bnm#>(
<# prefix = " "; #>
<# foreach (var (tp, nm) in args) { #>
<#=prefix#><#=RightPad(tp, Pad)#> <#=nm#>
<# prefix = ", "; #>
<# } #>
);
<# }
break;
case Kind.IsEnum: { #>
enum <#=bnm#>
{
<# prefix = " "; #>
<# foreach (var (cnm, _) in cs) { #>
<#=prefix#><#=cnm#>
<# prefix = ", "; #>
<# } #>
}
<# }
break;
case Kind.IsUnion: { #>
abstract partial record <#=bnm#>();
<# foreach (var (cnm, args) in cs) { #>
sealed partial record <#=bnm#>_<#=cnm#>(
<# prefix = " "; #>
<# foreach (var (tp, nm) in args) { #>
<#=prefix#><#=RightPad(tp, Pad)#> <#=nm#>
<# prefix = ", "; #>
<# } #>
) : <#=bnm#>();
<# } #>
<# }
break;
}
#>
// <#=bnm#> - END
<# } #>
static partial class Generators
{
const int InitSize = 16;
<# foreach (var td in model) { #>
<#
var kind = WhatKind(td);
var (bnm, cs) = td;
#>
// <#=bnm#> - BEGIN
// Kind: <#=kind#>
public static void Generate(int rem, out List<<#=bnm#>> values)
{
if (rem <= 0)
{
values = new();
return;
}
<#
switch(kind)
{
default:
case Kind.IsEmpty: { #>
values = new(1);
values.Add(new());
<# }
break;
case Kind.IsRecord: { #>
<#
var (_, args) = cs[0];
#>
values = new(InitSize);
<# foreach (var (tp, nm) in args) { #>
Generate(rem - 1, out List<<#=tp#>> vs_<#=nm#>);
<# } #>
<# foreach (var (tp, nm) in args) { #>
for (var i_<#=nm#> = 0; i_<#=nm#> < vs_<#=nm#>.Count; ++i_<#=nm#>)
{
var v_<#=nm#> = vs_<#=nm#>[i_<#=nm#>];
<# } #>
values.Add(new (
<# prefix = " "; #>
<# foreach (var (tp, nm) in args) { #>
<#=prefix#>v_<#=nm#>
<# prefix = ", "; #>
<# } #>
));
<# foreach (var (tp, nm) in args) { #>
} // i_<#=nm#>
<# } #>
<# }
break;
case Kind.IsEnum: { #>
values = new(<#=cs.Length#>);
<# foreach (var (cnm, _) in cs) { #>
values.Add(<#=bnm#>.<#=cnm#>);
<# } #>
<# }
break;
case Kind.IsUnion: { #>
values = new(InitSize);
<# foreach (var (cnm, args) in cs) { #>
{
// Case: <#=bnm#>.<#=cnm#> - BEGIN
<# foreach (var (tp, nm) in args) { #>
Generate(rem - 1, out List<<#=tp#>> vs_<#=nm#>);
<# } #>
<# foreach (var (tp, nm) in args) { #>
for (var i_<#=nm#> = 0; i_<#=nm#> < vs_<#=nm#>.Count; ++i_<#=nm#>)
{
var v_<#=nm#> = vs_<#=nm#>[i_<#=nm#>];
<# } #>
values.Add(new <#=bnm#>_<#=cnm#>(
<# prefix = " "; #>
<# foreach (var (tp, nm) in args) { #>
<#=prefix#>v_<#=nm#>
<# prefix = ", "; #>
<# } #>
));
<# foreach (var (tp, nm) in args) { #>
} // i_<#=nm#>
<# } #>
// Case: <#=bnm#>.<#=cnm#> - END
}
<# } #>
<# }
break;
}
#>
}
// <#=bnm#> - END
<# } #>
}
}
<#+
const int Pad = 30;
enum Kind
{
IsEnum ,
IsRecord ,
IsUnion ,
IsEmpty ,
}
static Kind WhatKind((string, (string, (string, string)[])[]) i)
{
var (bnm, cs) = i;
if (cs.Length == 0)
{
return Kind.IsEmpty;
}
else if (cs.Length == 1 && cs[0].Item1 == bnm)
{
return Kind.IsRecord;
}
else
{
var isEnum = cs.All(c => c.Item2.Length == 0);
if (isEnum)
{
return Kind.IsEnum;
}
else
{
return Kind.IsUnion;
}
}
}
static string RightPad(string s, int n)
{
s ??= "";
n = System.Math.Max(n, 0);
if (s.Length < n)
{
return s + new string(' ', n - s.Length);
}
else
{
return s;
}
}
(string, (string, (string, string)[])[]) Record(string name, params (string, string)[] attributes)
{
return (name, new [] { (name, attributes) });
}
(string, (string, (string, string)[])[]) Union(string name, params (string, (string, string)[])[] cases)
{
return (name, cases);
}
(string, (string, string)[]) Case(string name, params (string, string)[] attributes)
{
return (name, attributes);
}
#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment