From 27adfa2af1bd2b045c434419bf1401fb32d19f76 Mon Sep 17 00:00:00 2001 From: James Hughes Date: Thu, 15 Jun 2023 18:32:07 +0100 Subject: [PATCH] Removed demo project, it's probably better off just using PgfPlotsSdk as the demo --- src/DemoProject/DemoProject.csproj | 18 -- src/DemoProject/Program.cs | 62 ------ .../DemoApiDefinition.fluid.yml | 8 + .../Parsers/FluidApiDefinitionParserTests.cs | 203 ++++++++++-------- .../FluidGeneratorServiceTests.cs | 71 ++++++ src/SuperFluid.Tests/SuperFluid.Tests.csproj | 1 + src/SuperFluid.sln | 6 - .../Definitions/FluidApiArgumentDefinition.cs | 10 + .../Definitions/FluidApiMethodDefinition.cs | 5 +- .../Internal/Model/FluidApiArgument.cs | 16 ++ .../Internal/Model/FluidApiMethod.cs | 6 +- .../Parsers/FluidApiDefinitionParser.cs | 5 +- .../Services/FluidGeneratorService.cs | 4 +- src/SuperFluid/SuperFluid.csproj | 2 +- 14 files changed, 229 insertions(+), 188 deletions(-) delete mode 100644 src/DemoProject/DemoProject.csproj delete mode 100644 src/DemoProject/Program.cs rename src/{DemoProject => SuperFluid.Tests}/DemoApiDefinition.fluid.yml (78%) create mode 100644 src/SuperFluid.Tests/SourceGenerators/FluidGeneratorServiceTests.cs create mode 100644 src/SuperFluid/Internal/Definitions/FluidApiArgumentDefinition.cs create mode 100644 src/SuperFluid/Internal/Model/FluidApiArgument.cs diff --git a/src/DemoProject/DemoProject.csproj b/src/DemoProject/DemoProject.csproj deleted file mode 100644 index 72fb391..0000000 --- a/src/DemoProject/DemoProject.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - net7.0 - enable - enable - - - - - - - - - - - diff --git a/src/DemoProject/Program.cs b/src/DemoProject/Program.cs deleted file mode 100644 index a73d17d..0000000 --- a/src/DemoProject/Program.cs +++ /dev/null @@ -1,62 +0,0 @@ -using SuperFluid.Tests.Cars; - -string builtString = Test.Initialize() - .Unlock() - .Enter() - .Start() - .Stop() - .Exit() - .Lock() - .Unlock() - .Enter() - .Start() - .Build(); - -Console.WriteLine(builtString); - -public class Test : ICarActor -{ - - private readonly List _calls = new(); - - public ICanUnlock Lock() - { - _calls.Add("Lock!"); - return this; - } - - public ICanStartOrExit Enter() - { - _calls.Add("Enter!"); - return this; - } - - - public ICanLockOrEnter Unlock() - { - _calls.Add("Unlock!"); - return this; - } - - public ICanStopOrBuild Start() - { - _calls.Add("Start!"); - return this; - } - - public ICanLockOrEnter Exit() - { - _calls.Add("Exit!"); - return this; - } - - public ICanStartOrExit Stop() - { - _calls.Add("Stop!"); - return this; - } - - public string Build() => string.Join('\n', _calls); - - public static ICanUnlock Initialize() => new Test(); -} diff --git a/src/DemoProject/DemoApiDefinition.fluid.yml b/src/SuperFluid.Tests/DemoApiDefinition.fluid.yml similarity index 78% rename from src/DemoProject/DemoApiDefinition.fluid.yml rename to src/SuperFluid.Tests/DemoApiDefinition.fluid.yml index 977b32d..b79cf40 100644 --- a/src/DemoProject/DemoApiDefinition.fluid.yml +++ b/src/SuperFluid.Tests/DemoApiDefinition.fluid.yml @@ -21,6 +21,11 @@ Methods: - "Lock" - "Enter" - Name: "Start" + Arguments: + - Name: "speed" + Type: "int" + - Name: "direction" + Type: "string" CanTransitionTo: - "Stop" - "Build" @@ -29,5 +34,8 @@ Methods: - "Start" - "Exit" - Name: "Build" + Arguments: + - Name: "color" + Type: "string" CanTransitionTo: [] ReturnType: "string" diff --git a/src/SuperFluid.Tests/Parsers/FluidApiDefinitionParserTests.cs b/src/SuperFluid.Tests/Parsers/FluidApiDefinitionParserTests.cs index 9942ee6..11490c2 100644 --- a/src/SuperFluid.Tests/Parsers/FluidApiDefinitionParserTests.cs +++ b/src/SuperFluid.Tests/Parsers/FluidApiDefinitionParserTests.cs @@ -6,86 +6,97 @@ namespace SuperFluid.Tests.Parsers; public class FluidApiDefinitionParserTests { - private readonly FluidApiMethodDefinition _init = new() - { - Name = "Initialize", - CanTransitionTo = new() - { - "Unlock" - } - }; - private readonly FluidApiMethodDefinition _initSimple = new() - { - Name = "Initialize", - CanTransitionTo = new() - { - "DropDead" - } - }; - - private readonly FluidApiMethodDefinition _unlock = new() - { - Name = "Unlock", - CanTransitionTo = new() + private static readonly FluidApiArgumentDefinition Speed = new() + { + Name = "speed", + Type = "int" + }; + + private static readonly FluidApiMethodDefinition Init = new() + { + Name = "Initialize", + CanTransitionTo = new() + { + "Unlock" + } + }; + + private static readonly FluidApiMethodDefinition InitSimple = new() + { + Name = "Initialize", + CanTransitionTo = new() + { + "DropDead" + } + }; + + private static readonly FluidApiMethodDefinition Unlock = new() + { + Name = "Unlock", + CanTransitionTo = new() + { + "Enter", + "Lock" + } + }; + + private static readonly FluidApiMethodDefinition Lock = new() + { + Name = "Lock", + CanTransitionTo = new() + { + "Unlock" + } + }; + + private static readonly FluidApiMethodDefinition Enter = new() + { + Name = "Enter", + CanTransitionTo = new() + { + "Start", + "Exit" + } + }; + + private static readonly FluidApiMethodDefinition Exit = new() + { + Name = "Exit", + CanTransitionTo = new() + { + "Lock", + "Enter" + } + }; + + private static readonly FluidApiMethodDefinition Start = new() + { + Name = "Start", + CanTransitionTo = new() + { + "Stop" + }, + Arguments = new() { - "Enter", - "Lock" + Speed } - }; - - private readonly FluidApiMethodDefinition _lock = new() - { - Name = "Lock", - CanTransitionTo = new() - { - "Unlock" - } - }; - - private readonly FluidApiMethodDefinition _enter = new() - { - Name = "Enter", - CanTransitionTo = new() - { - "Start", - "Exit" - } - }; - - private readonly FluidApiMethodDefinition _exit = new() - { - Name = "Exit", - CanTransitionTo = new() - { - "Lock", - "Enter" - } - }; - - private readonly FluidApiMethodDefinition _start = new() - { - Name = "Start", - CanTransitionTo = new() - { - "Stop" - } - }; - - private readonly FluidApiMethodDefinition _stop = new() - { - Name = "Stop", - CanTransitionTo = new() - { - "Start", - "Exit" - } - }; - - private readonly FluidApiMethodDefinition _dropDead = new() - { - Name = "DropDead", - CanTransitionTo = new() - }; + }; + + private static readonly FluidApiMethodDefinition Stop = new() + { + Name = "Stop", + CanTransitionTo = new() + { + "Start", + "Exit" + } + }; + + private static readonly FluidApiMethodDefinition DropDead = new() + { + Name = "DropDead", + CanTransitionTo = new() + }; [Fact] public void CanDeserializeSimpleCase() @@ -94,10 +105,10 @@ public void CanDeserializeSimpleCase() { Name = "Simple", Namespace = "Simple.Test", - InitialState = _initSimple, + InitialState = InitSimple, Methods = new() { - _dropDead + DropDead } }; @@ -122,30 +133,30 @@ public void CanDeserializeComplexCase() { Name = "Simple", Namespace = "Simple.Test", - InitialState = _init, + InitialState = Init, Methods = new() { - _lock, - _unlock, - _enter, - _exit, - _start, - _stop + Lock, + Unlock, + Enter, + Exit, + Start, + Stop } }; FluidApiDefinitionParser parser = new(); FluidApiModel model = parser.Parse(definition); - FluidApiMethod lockMethod = model.Methods.Single(s => s.Name == _lock.Name); - FluidApiMethod unlockMethod = model.Methods.Single(s => s.Name == _unlock.Name); - FluidApiMethod enterMethod = model.Methods.Single(s => s.Name == _enter.Name); - FluidApiMethod exitMethod = model.Methods.Single(s => s.Name == _exit.Name); - FluidApiMethod startMethod = model.Methods.Single(s => s.Name == _start.Name); - FluidApiMethod stopMethod = model.Methods.Single(s => s.Name == _stop.Name); + FluidApiMethod lockMethod = model.Methods.Single(s => s.Name == Lock.Name); + FluidApiMethod unlockMethod = model.Methods.Single(s => s.Name == Unlock.Name); + FluidApiMethod enterMethod = model.Methods.Single(s => s.Name == Enter.Name); + FluidApiMethod exitMethod = model.Methods.Single(s => s.Name == Exit.Name); + FluidApiMethod startMethod = model.Methods.Single(s => s.Name == Start.Name); + FluidApiMethod stopMethod = model.Methods.Single(s => s.Name == Stop.Name); FluidApiMethod initMethod = model.InitialMethod; - initMethod.Name.ShouldBe(_init.Name); + initMethod.Name.ShouldBe(Init.Name); model.Methods.ShouldContain(initMethod); initMethod.CanTransitionTo.ShouldBeEquivalentTo(new HashSet {unlockMethod}); @@ -155,6 +166,8 @@ public void CanDeserializeComplexCase() exitMethod.CanTransitionTo.ShouldBeEquivalentTo(new HashSet {enterMethod, lockMethod}); startMethod.CanTransitionTo.ShouldBeEquivalentTo(new HashSet {stopMethod}); stopMethod.CanTransitionTo.ShouldBeEquivalentTo(new HashSet {startMethod, exitMethod}); - } + startMethod.Arguments.First().Name.ShouldBe("speed"); + startMethod.Arguments.First().Type.ShouldBe("int"); + } } diff --git a/src/SuperFluid.Tests/SourceGenerators/FluidGeneratorServiceTests.cs b/src/SuperFluid.Tests/SourceGenerators/FluidGeneratorServiceTests.cs new file mode 100644 index 0000000..bdc0949 --- /dev/null +++ b/src/SuperFluid.Tests/SourceGenerators/FluidGeneratorServiceTests.cs @@ -0,0 +1,71 @@ +using SuperFluid.Internal.Services; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace SuperFluid.Tests.SourceGenerators; + +public class FluidGeneratorServiceTests +{ + private readonly string _rawYml = File.ReadAllText("../../../DemoApiDefinition.fluid.yml"); + + [Fact] + public void CanGenerateDemoApi() + { + IDeserializer deserializer = new DeserializerBuilder().WithNamingConvention(NullNamingConvention.Instance).Build(); + FluidGeneratorService service = new(deserializer, new()); + Dictionary result = service.Generate(_rawYml); + result["ICanLockOrEnter.fluid.g.cs"].ShouldBe(CanLockOrEnterSource); + result["ICanUnlock.fluid.g.cs"].ShouldBe(CanUnlockSource); + result["ICanStartOrExit.fluid.g.cs"].ShouldBe(CanStartOrExitSource); + result["ICanStopOrBuild.fluid.g.cs"].ShouldBe(CanStopOrBuildSource); + result["ICarActor.fluid.g.cs"].ShouldBe(CarActorSource); + } + + private const string CanLockOrEnterSource = """ + namespace SuperFluid.Tests.Cars; + + public interface ICanLockOrEnter + { + public ICanUnlock Lock(); + public ICanStartOrExit Enter(); + } + """; + + private const string CanUnlockSource = """ + namespace SuperFluid.Tests.Cars; + + public interface ICanUnlock + { + public ICanLockOrEnter Unlock(); + } + """; + + private const string CanStartOrExitSource = """ + namespace SuperFluid.Tests.Cars; + + public interface ICanStartOrExit + { + public ICanStopOrBuild Start(int speed, string direction); + public ICanLockOrEnter Exit(); + } + """; + + private const string CanStopOrBuildSource = """ + namespace SuperFluid.Tests.Cars; + + public interface ICanStopOrBuild + { + public ICanStartOrExit Stop(); + public string Build(string color); + } + """; + + private const string CarActorSource = """ + namespace SuperFluid.Tests.Cars; + + public interface ICarActor: ICanLockOrEnter,ICanUnlock,ICanStartOrExit,ICanStopOrBuild + { + public static abstract ICanUnlock Initialize(); + } + """; +} diff --git a/src/SuperFluid.Tests/SuperFluid.Tests.csproj b/src/SuperFluid.Tests/SuperFluid.Tests.csproj index 9fd9d11..c57d433 100644 --- a/src/SuperFluid.Tests/SuperFluid.Tests.csproj +++ b/src/SuperFluid.Tests/SuperFluid.Tests.csproj @@ -25,6 +25,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + diff --git a/src/SuperFluid.sln b/src/SuperFluid.sln index 58691e4..26f2556 100644 --- a/src/SuperFluid.sln +++ b/src/SuperFluid.sln @@ -4,8 +4,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperFluid", "SuperFluid\Su EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperFluid.Tests", "SuperFluid.Tests\SuperFluid.Tests.csproj", "{6C2B21F8-301C-4062-9C12-608DAF4C0E16}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoProject", "DemoProject\DemoProject.csproj", "{FA0C7E98-6910-4226-A706-B9B0A0D529A2}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,9 +22,5 @@ Global {F49EE144-4D5A-4C5A-93ED-1BE64AFF5D7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {F49EE144-4D5A-4C5A-93ED-1BE64AFF5D7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F49EE144-4D5A-4C5A-93ED-1BE64AFF5D7D}.Release|Any CPU.Build.0 = Release|Any CPU - {FA0C7E98-6910-4226-A706-B9B0A0D529A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FA0C7E98-6910-4226-A706-B9B0A0D529A2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FA0C7E98-6910-4226-A706-B9B0A0D529A2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FA0C7E98-6910-4226-A706-B9B0A0D529A2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/SuperFluid/Internal/Definitions/FluidApiArgumentDefinition.cs b/src/SuperFluid/Internal/Definitions/FluidApiArgumentDefinition.cs new file mode 100644 index 0000000..ab8812e --- /dev/null +++ b/src/SuperFluid/Internal/Definitions/FluidApiArgumentDefinition.cs @@ -0,0 +1,10 @@ +using System.Diagnostics; + +namespace SuperFluid.Internal.Definitions; + +[DebuggerDisplay("{Type} {Name}")] +internal record FluidApiArgumentDefinition +{ + public required string Type { get; init; } + public required string Name { get; init; } +} diff --git a/src/SuperFluid/Internal/Definitions/FluidApiMethodDefinition.cs b/src/SuperFluid/Internal/Definitions/FluidApiMethodDefinition.cs index dd4df3a..459701d 100644 --- a/src/SuperFluid/Internal/Definitions/FluidApiMethodDefinition.cs +++ b/src/SuperFluid/Internal/Definitions/FluidApiMethodDefinition.cs @@ -6,7 +6,8 @@ namespace SuperFluid.Internal.Definitions; internal record FluidApiMethodDefinition { public required string Name { get; init; } - public string? ReturnType { get; init; } - public required List CanTransitionTo { get; init; } = new(); + public List CanTransitionTo { get; init; } = new(); + + public List Arguments { get; init; } = new(); } diff --git a/src/SuperFluid/Internal/Model/FluidApiArgument.cs b/src/SuperFluid/Internal/Model/FluidApiArgument.cs new file mode 100644 index 0000000..4c24fc4 --- /dev/null +++ b/src/SuperFluid/Internal/Model/FluidApiArgument.cs @@ -0,0 +1,16 @@ +using System.Diagnostics; + +namespace SuperFluid.Internal.Model; + +[DebuggerDisplay("{Type} {Name}")] +internal class FluidApiArgument +{ + public FluidApiArgument(string argName, string argType) + { + Name = argName; + Type = argType; + } + + public string Type { get; init; } + public string Name { get; init; } +} diff --git a/src/SuperFluid/Internal/Model/FluidApiMethod.cs b/src/SuperFluid/Internal/Model/FluidApiMethod.cs index db516d1..7602c3a 100644 --- a/src/SuperFluid/Internal/Model/FluidApiMethod.cs +++ b/src/SuperFluid/Internal/Model/FluidApiMethod.cs @@ -5,10 +5,11 @@ namespace SuperFluid.Internal.Model; [DebuggerDisplay("{Name}")] internal record FluidApiMethod { - public FluidApiMethod(string name, string? returnType, IEnumerable transitions) + public FluidApiMethod(string name, string? returnType, IEnumerable transitions, IEnumerable args) { Name = name; ReturnType = returnType; + Arguments = args.ToHashSet(); CanTransitionTo = transitions.ToHashSet(); } @@ -16,4 +17,7 @@ public FluidApiMethod(string name, string? returnType, IEnumerable CanTransitionTo { get; init; } = new(); + + internal HashSet Arguments { get; init; } = new(); } + diff --git a/src/SuperFluid/Internal/Parsers/FluidApiDefinitionParser.cs b/src/SuperFluid/Internal/Parsers/FluidApiDefinitionParser.cs index 7622b84..b0ef793 100644 --- a/src/SuperFluid/Internal/Parsers/FluidApiDefinitionParser.cs +++ b/src/SuperFluid/Internal/Parsers/FluidApiDefinitionParser.cs @@ -84,7 +84,10 @@ private FluidApiMethod FindOrCreateMethod(FluidApiDefinition definition, FluidAp { return state; } - FluidApiMethod newMethod = new(method.Name, method.ReturnType, ArraySegment.Empty); + + List args = method.Arguments.Select(a => new FluidApiArgument(a.Name, a.Type)).ToList(); + + FluidApiMethod newMethod = new(method.Name, method.ReturnType, ArraySegment.Empty, args); stateDict.Add(method, newMethod); List transitionDefinitions = method.CanTransitionTo.Select(m => definition.Methods.Single(d => d.Name == m)).ToList(); diff --git a/src/SuperFluid/Internal/Services/FluidGeneratorService.cs b/src/SuperFluid/Internal/Services/FluidGeneratorService.cs index 3988b60..0626ba4 100644 --- a/src/SuperFluid/Internal/Services/FluidGeneratorService.cs +++ b/src/SuperFluid/Internal/Services/FluidGeneratorService.cs @@ -36,7 +36,7 @@ namespace {{model.Namespace}}; public interface {{model.Name}}: {{string.Join(',', model.States.Select(s => s.Name))}} { - public static abstract {{model.InitializerMethodReturnState.Name}} {{model.InitialMethod.Name}}(); + public static abstract {{model.InitializerMethodReturnState.Name}} {{model.InitialMethod.Name}}({{string.Join(", ", model.InitialMethod.Arguments.Select(a =>$"{a.Type} {a.Name}"))}}); } """; return source; @@ -46,7 +46,7 @@ private string GenerateStateSource(FluidApiState fluidApiState, FluidApiModel mo { IEnumerable methodDeclarations = fluidApiState.MethodTransitions.Select(kvp => $""" - public {kvp.Key.ReturnType ?? kvp.Value.Name} {kvp.Key.Name}(); + public {kvp.Key.ReturnType ?? kvp.Value.Name} {kvp.Key.Name}({string.Join(", ", kvp.Key.Arguments.Select(a =>$"{a.Type} {a.Name}"))}); """); string source = $$""" diff --git a/src/SuperFluid/SuperFluid.csproj b/src/SuperFluid/SuperFluid.csproj index 13b439a..89eab9d 100644 --- a/src/SuperFluid/SuperFluid.csproj +++ b/src/SuperFluid/SuperFluid.csproj @@ -6,7 +6,7 @@ enable default true - 0.0.1 + 0.0.1-alpha SuperFluid James Hughes An incremental source generator for fluent APIs with grammar