124 lines
3 KiB
C#
124 lines
3 KiB
C#
|
using System.Reflection;
|
|||
|
using meowlang.parser;
|
|||
|
|
|||
|
|
|||
|
var className = args[0];
|
|||
|
var destinatinDir = args[1] ?? ".";
|
|||
|
var destinationPath = Path.Join(destinatinDir, $"{className}.cs");
|
|||
|
|
|||
|
|
|||
|
var parserType = typeof(Parser);
|
|||
|
var nameSpace = parserType.Namespace;
|
|||
|
var modelTypes = parserType.Assembly.DefinedTypes.Where(t => t.IsAssignableTo(typeof(ModelBase))).Where(t => !t.IsAbstract);
|
|||
|
|
|||
|
string UnModelifyName(string name)
|
|||
|
{
|
|||
|
var nameWithoutModel = name;
|
|||
|
var modelIndex = nameWithoutModel.LastIndexOf("Model", StringComparison.Ordinal);
|
|||
|
if (modelIndex > -1)
|
|||
|
{
|
|||
|
nameWithoutModel = nameWithoutModel.Remove(modelIndex);
|
|||
|
}
|
|||
|
|
|||
|
return nameWithoutModel;
|
|||
|
}
|
|||
|
|
|||
|
string MakeVisitorMethod(TypeInfo model, bool isVoid)
|
|||
|
{
|
|||
|
if (model == null) throw new ArgumentNullException(nameof(model));
|
|||
|
var typeName = model.Name;
|
|||
|
var visitorName = $"Visit{UnModelifyName(typeName)}";
|
|||
|
return isVoid ? @$"
|
|||
|
public virtual void {visitorName}({typeName} m)
|
|||
|
{{
|
|||
|
foreach (var modelBase in m.GetChildren())
|
|||
|
{{
|
|||
|
Visit(modelBase);
|
|||
|
}}
|
|||
|
}}
|
|||
|
" : @$"
|
|||
|
public virtual T {visitorName}({typeName} m)
|
|||
|
{{
|
|||
|
T result = default;
|
|||
|
foreach (var modelBase in m.GetChildren())
|
|||
|
{{
|
|||
|
result = Visit(modelBase);
|
|||
|
}}
|
|||
|
|
|||
|
return result;
|
|||
|
}}
|
|||
|
";
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
string MakeSwitchArm(TypeInfo model, bool isVoid)
|
|||
|
{
|
|||
|
if (model == null) throw new ArgumentNullException(nameof(model));
|
|||
|
var typeName = model.Name;
|
|||
|
var visitorName = $"Visit{UnModelifyName(typeName)}";
|
|||
|
return isVoid ? $@"
|
|||
|
case {typeName} x: {visitorName}(x); break;" : $@"
|
|||
|
case {typeName} x: return {visitorName}(x);";
|
|||
|
}
|
|||
|
|
|||
|
var arms = new List<string>();
|
|||
|
var voidArms = new List<string>();
|
|||
|
var methods = new List<string>();
|
|||
|
var voidMethods = new List<string>();
|
|||
|
|
|||
|
foreach (var modelType in modelTypes)
|
|||
|
{
|
|||
|
arms.Add(MakeSwitchArm(modelType, false));
|
|||
|
voidArms.Add(MakeSwitchArm(modelType, true));
|
|||
|
methods.Add(MakeVisitorMethod(modelType, false));
|
|||
|
voidMethods.Add(MakeVisitorMethod(modelType, true));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
var sourceCode = $@"// automatically generated
|
|||
|
|
|||
|
// ReSharper disable MemberCanBeProtected.Global
|
|||
|
// ReSharper disable MemberCanBePrivate.Global
|
|||
|
#pragma warning disable CS8603
|
|||
|
#pragma warning disable CS8600
|
|||
|
#pragma warning disable CS8509
|
|||
|
|
|||
|
using System.CodeDom.Compiler;
|
|||
|
namespace {nameSpace};
|
|||
|
|
|||
|
[GeneratedCode(""meow-visitorgenerator"", ""1"")]
|
|||
|
public class {className}<T>
|
|||
|
{{
|
|||
|
|
|||
|
public T? TryVisit(ModelBase? m)
|
|||
|
{{
|
|||
|
return m == null ? default : Visit(m);
|
|||
|
}}
|
|||
|
|
|||
|
public T Visit(ModelBase m)
|
|||
|
{{
|
|||
|
switch(m)
|
|||
|
{{
|
|||
|
{string.Join("", arms)}
|
|||
|
}}
|
|||
|
return default;
|
|||
|
}}
|
|||
|
{string.Join("", methods)}
|
|||
|
}}
|
|||
|
|
|||
|
[GeneratedCode(""meow-visitorgenerator"", ""1"")]
|
|||
|
public class {className}
|
|||
|
{{
|
|||
|
public void Visit(ModelBase m)
|
|||
|
{{
|
|||
|
switch(m)
|
|||
|
{{
|
|||
|
{string.Join("", voidArms)}
|
|||
|
}}
|
|||
|
}}
|
|||
|
{string.Join("", voidMethods)}
|
|||
|
}}
|
|||
|
";
|
|||
|
|
|||
|
File.WriteAllText(destinationPath, sourceCode);
|
|||
|
Console.WriteLine($"output written to {destinationPath}");
|