diff --git a/SocietalConstructionTool/Program.cs b/SocietalConstructionTool/Program.cs index 52c912e3..c71c1819 100644 --- a/SocietalConstructionTool/Program.cs +++ b/SocietalConstructionTool/Program.cs @@ -43,7 +43,7 @@ { Console.WriteLine("Warning: No output specified"); } - _ = SctRunner.CompileAndRun(sourceFiles.Select(f => f.FullName).ToArray(), logger); + _ = SctRunner.CompileAndRun(sourceFiles.Select(f => f.FullName), logger); }, sourceFilesArgument, outputToConsoleOption, outputFileOption); diff --git a/SocietalConstructionTool/Resources/Stdlib.sct b/SocietalConstructionTool/Resources/Stdlib.sct new file mode 100644 index 00000000..a651e807 --- /dev/null +++ b/SocietalConstructionTool/Resources/Stdlib.sct @@ -0,0 +1,68 @@ +class stdCounter(int x) { + state Counting { + if (x <= 0) { + exit; + } + x = x - 1; + enter Counting; + } +} + +class stdPredicateExists(Predicate p) { + state ExitWhen { + if (exists(p)) { + exit; + } + enter ExitWhen; + } + + state ExitWhenNo { + if (!exists(p)) { + exit; + } + enter ExitWhenNo; + } +} + +class stdPredicateAmount(Predicate p, int x) { + state ExitLessThan { + if (count(p) < x) { + exit; + } + enter ExitLessThan; + } + + state ExitMoreThan { + if (count(p) > x) { + exit; + } + enter ExitMoreThan; + } +} + + + +// exit the simulation after the specified amount of ticks +function ExitAfterTicks(int ticks) -> void { + create stdCounter::Counting(x: ticks); +} + +// exit the simulation when there exists an agent fulfilling `pred` +function ExitWhenExists(Predicate pred) -> void { + create stdPredicateExists::ExitWhen(p: pred); +} + +// exit the simulation when there no longer exists any agents fulfilling `pred` +function ExitWhenNoLongerExists(Predicate pred) -> void { + create stdPredicateExists::ExitWhenNo(p: pred); +} + +// exit the simulation when there exists `amount` agents fulfilling `pred` +function ExitWhenMoreThan(Predicate pred, int amount) -> void { + create stdPredicateAmount::ExitMoreThan(p: pred, x: amount); +} + +// exit the simulation when there are less than `amount` agents fulfilling `pred` +function ExitWhenLessThan(Predicate pred, int amount) -> void { + create stdPredicateAmount::ExitLessThan(p: pred, x: amount); +} diff --git a/SocietalConstructionTool/SctRunner.cs b/SocietalConstructionTool/SctRunner.cs index 653548ff..3a579579 100644 --- a/SocietalConstructionTool/SctRunner.cs +++ b/SocietalConstructionTool/SctRunner.cs @@ -42,6 +42,9 @@ private static SctParser GetSctParser(string input) return parser; } + private static IEnumerable StdLibFilename => + Directory.GetFiles(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Resources")); + /** * * Reads an SCT source file, statically chekcs it and translates it into C# code @@ -49,13 +52,10 @@ private static SctParser GetSctParser(string input) * The path of the SCT source file * The resulting C# source, or null if compilation failed */ - public static (string? outputText, IEnumerable errors) CompileSct(string[] filenames) + public static (string? outputText, IEnumerable errors) CompileSct(IEnumerable filenames) { - // Make SctTableVisitor take a CTableBuilder as a parameter - // Analyse each file separately - // Add file name to each found error. - // Call CTabelBuilder.BuildCtable() after all files have been visited - // Run the translator on all files concatenated. + // Add stdlib to the list of files to compile + filenames = filenames.Concat(StdLibFilename); var errors = RunStaticChecks(filenames); @@ -115,7 +115,7 @@ private static List RunSecondPassChecks(ParserRuleContext startNo return typeChecker.Errors.ToList(); } - public static List RunStaticChecks(string[] filenames) + public static List RunStaticChecks(IEnumerable filenames) { // Create a CTableBuilder that is used for all files. CTableBuilder cTableBuilder = new(); @@ -243,9 +243,8 @@ private static void Run(Assembly assembly, IRuntimeContext initialContext) * The path of the SCT source file * The logger to use to output the result of the simulation */ - public static IEnumerable CompileAndRun(string[] filenames, IOutputLogger? logger) + public static IEnumerable CompileAndRun(IEnumerable filenames, IOutputLogger? logger) { - var (outputText, errors) = CompileSct(filenames); // TODO: Handle errors from ANTLR. They are not currently being passed to the errors list. @@ -273,16 +272,7 @@ public static IEnumerable CompileAndRun(string[] filenames, IOutp return []; } - private static string ConcatenateFiles(string[] filenames) - { - - string result = string.Empty; - foreach (var file in filenames) - { - result += File.ReadAllText(file); - } - - return result; - } + private static string ConcatenateFiles(IEnumerable filenames) + => filenames.Select(File.ReadAllText).Aggregate((acc, next) => acc + next); } } diff --git a/SocietalConstructionTool/SocietalConstructionTool.csproj b/SocietalConstructionTool/SocietalConstructionTool.csproj index c9d4673e..f4f430f8 100644 --- a/SocietalConstructionTool/SocietalConstructionTool.csproj +++ b/SocietalConstructionTool/SocietalConstructionTool.csproj @@ -19,6 +19,11 @@ + + + PreserveNewest + + diff --git a/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitAfter.verified.txt b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitAfter.verified.txt new file mode 100644 index 00000000..b61e6131 --- /dev/null +++ b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitAfter.verified.txt @@ -0,0 +1,33 @@ +[ + { + "State": "Counting", + "Fields": { + "x": 3 + }, + "ClassName": "stdCounter" + } +][ + { + "State": "Counting", + "Fields": { + "x": 2 + }, + "ClassName": "stdCounter" + } +][ + { + "State": "Counting", + "Fields": { + "x": 1 + }, + "ClassName": "stdCounter" + } +][ + { + "State": "Counting", + "Fields": { + "x": 0 + }, + "ClassName": "stdCounter" + } +][] \ No newline at end of file diff --git a/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenExists.verified.txt b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenExists.verified.txt new file mode 100644 index 00000000..897308d0 --- /dev/null +++ b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenExists.verified.txt @@ -0,0 +1,41 @@ +[ + { + "State": "Bar", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitWhen", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": "__sct_Baz", + "Fields": {} + } + }, + "ClassName": "stdPredicateExists" + } +][ + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitWhen", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": "__sct_Baz", + "Fields": {} + } + }, + "ClassName": "stdPredicateExists" + } +][ + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + } +] \ No newline at end of file diff --git a/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenLessThan.verified.txt b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenLessThan.verified.txt new file mode 100644 index 00000000..596a706b --- /dev/null +++ b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenLessThan.verified.txt @@ -0,0 +1,47 @@ +[ + { + "State": "Bar", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitLessThan", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": null, + "Fields": {} + }, + "x": 2 + }, + "ClassName": "stdPredicateAmount" + } +][ + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitLessThan", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": null, + "Fields": {} + }, + "x": 2 + }, + "ClassName": "stdPredicateAmount" + } +][] \ No newline at end of file diff --git a/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenMoreThan.verified.txt b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenMoreThan.verified.txt new file mode 100644 index 00000000..fb1389e6 --- /dev/null +++ b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenMoreThan.verified.txt @@ -0,0 +1,114 @@ +[ + { + "State": "Bar", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitMoreThan", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": "__sct_Baz", + "Fields": {} + }, + "x": 1 + }, + "ClassName": "stdPredicateAmount" + } +][ + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitMoreThan", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": "__sct_Baz", + "Fields": {} + }, + "x": 1 + }, + "ClassName": "stdPredicateAmount" + } +][ + { + "State": "Bar", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitMoreThan", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": "__sct_Baz", + "Fields": {} + }, + "x": 1 + }, + "ClassName": "stdPredicateAmount" + } +][ + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Bar", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitMoreThan", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": "__sct_Baz", + "Fields": {} + }, + "x": 1 + }, + "ClassName": "stdPredicateAmount" + } +][ + { + "State": "Bar", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Bar", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + } +] \ No newline at end of file diff --git a/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenNoLongerExists.verified.txt b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenNoLongerExists.verified.txt new file mode 100644 index 00000000..d52d8b5e --- /dev/null +++ b/SocietalConstructionToolTests/Snapshots/BehaviourTests/StdlibExitWhenNoLongerExists.verified.txt @@ -0,0 +1,41 @@ +[ + { + "State": "Bar", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitWhenNo", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": "__sct_Bar", + "Fields": {} + } + }, + "ClassName": "stdPredicateExists" + } +][ + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + }, + { + "State": "ExitWhenNo", + "Fields": { + "p": { + "ClassName": "__sct_Foo", + "State": "__sct_Bar", + "Fields": {} + } + }, + "ClassName": "stdPredicateExists" + } +][ + { + "State": "Baz", + "Fields": {}, + "ClassName": "Foo" + } +] \ No newline at end of file diff --git a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt index 123f6d8b..068b0be4 100644 --- a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt +++ b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt @@ -6,6 +6,148 @@ public class GlobalClass { + public static void __sct_ExitWhenLessThan(IRuntimeContext ctx, QueryPredicate __sct_pred, long __sct_amount) + { + ctx.AgentHandler.CreateAgent(new __sct_stdPredicateAmount("__sct_ExitLessThan", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_p", __sct_pred), new KeyValuePair("__sct_x", __sct_amount) }))); + } + + public static void __sct_ExitWhenMoreThan(IRuntimeContext ctx, QueryPredicate __sct_pred, long __sct_amount) + { + ctx.AgentHandler.CreateAgent(new __sct_stdPredicateAmount("__sct_ExitMoreThan", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_p", __sct_pred), new KeyValuePair("__sct_x", __sct_amount) }))); + } + + public static void __sct_ExitWhenNoLongerExists(IRuntimeContext ctx, QueryPredicate __sct_pred) + { + ctx.AgentHandler.CreateAgent(new __sct_stdPredicateExists("__sct_ExitWhenNo", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_p", __sct_pred) }))); + } + + public static void __sct_ExitWhenExists(IRuntimeContext ctx, QueryPredicate __sct_pred) + { + ctx.AgentHandler.CreateAgent(new __sct_stdPredicateExists("__sct_ExitWhen", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_p", __sct_pred) }))); + } + + public static void __sct_ExitAfterTicks(IRuntimeContext ctx, long __sct_ticks) + { + ctx.AgentHandler.CreateAgent(new __sct_stdCounter("__sct_Counting", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_x", __sct_ticks) }))); + } + + public class __sct_stdPredicateAmount : BaseAgent + { + private QueryPredicate __sct_p { get => Fields["__sct_p"]; set => Fields["__sct_p"] = value; } + private long __sct_x { get => Fields["__sct_x"]; set => Fields["__sct_x"] = value; } + + public __sct_stdPredicateAmount(String state, IDictionary fields) : base(state, fields) + { + } + + private bool __sct_ExitLessThan(IRuntimeContext ctx) + { + if (((((ctx.QueryHandler.Count(ctx, __sct_p) < __sct_x) ? 1 : 0))) != 0) + { + ctx.ExitRuntime(); + return true; + } + + Enter(ctx, "__sct_ExitLessThan"); + return true; + return false; + } + + private bool __sct_ExitMoreThan(IRuntimeContext ctx) + { + if (((((ctx.QueryHandler.Count(ctx, __sct_p) > __sct_x) ? 1 : 0))) != 0) + { + ctx.ExitRuntime(); + return true; + } + + Enter(ctx, "__sct_ExitMoreThan"); + return true; + return false; + } + + public override void Update(IRuntimeContext ctx) + { + _ = State switch + { + "__sct_ExitLessThan" => __sct_ExitLessThan(ctx), + "__sct_ExitMoreThan" => __sct_ExitMoreThan(ctx)}; + } + } + + public class __sct_stdPredicateExists : BaseAgent + { + private QueryPredicate __sct_p { get => Fields["__sct_p"]; set => Fields["__sct_p"] = value; } + + public __sct_stdPredicateExists(String state, IDictionary fields) : base(state, fields) + { + } + + private bool __sct_ExitWhen(IRuntimeContext ctx) + { + if (((ctx.QueryHandler.Exists(ctx, __sct_p))) != 0) + { + ctx.ExitRuntime(); + return true; + } + + Enter(ctx, "__sct_ExitWhen"); + return true; + return false; + } + + private bool __sct_ExitWhenNo(IRuntimeContext ctx) + { + if (((ctx.QueryHandler.Exists(ctx, __sct_p) == 0 ? 1 : 0)) != 0) + { + ctx.ExitRuntime(); + return true; + } + + Enter(ctx, "__sct_ExitWhenNo"); + return true; + return false; + } + + public override void Update(IRuntimeContext ctx) + { + _ = State switch + { + "__sct_ExitWhen" => __sct_ExitWhen(ctx), + "__sct_ExitWhenNo" => __sct_ExitWhenNo(ctx)}; + } + } + + public class __sct_stdCounter : BaseAgent + { + private long __sct_x { get => Fields["__sct_x"]; set => Fields["__sct_x"] = value; } + + public __sct_stdCounter(String state, IDictionary fields) : base(state, fields) + { + } + + private bool __sct_Counting(IRuntimeContext ctx) + { + if (((((__sct_x <= 0) ? 1 : 0))) != 0) + { + ctx.ExitRuntime(); + return true; + } + + __sct_x = (__sct_x - 1); + Enter(ctx, "__sct_Counting"); + return true; + return false; + } + + public override void Update(IRuntimeContext ctx) + { + _ = State switch + { + "__sct_Counting" => __sct_Counting(ctx)}; + } + } + public class __sct_Town : BaseAgent { private long __sct_id { get => Fields["__sct_id"]; set => Fields["__sct_id"] = value; } diff --git a/SocietalConstructionToolTests/Snapshots/StaticCheckTests/WrongExpressionIf.verified.txt b/SocietalConstructionToolTests/Snapshots/StaticCheckTests/WrongExpressionIf.verified.txt index 22a41bb4..ccb25cfa 100644 --- a/SocietalConstructionToolTests/Snapshots/StaticCheckTests/WrongExpressionIf.verified.txt +++ b/SocietalConstructionToolTests/Snapshots/StaticCheckTests/WrongExpressionIf.verified.txt @@ -35,4 +35,4 @@ Column: 13, Filename: {CurrentDirectory}TestFiles/StaticCheckTests/WrongExpressionIf.sct } -] \ No newline at end of file +] diff --git a/SocietalConstructionToolTests/Snapshots/StaticCheckTests/WrongExpressionWhile.verified.txt b/SocietalConstructionToolTests/Snapshots/StaticCheckTests/WrongExpressionWhile.verified.txt index 28a7b46a..5061c1bf 100644 --- a/SocietalConstructionToolTests/Snapshots/StaticCheckTests/WrongExpressionWhile.verified.txt +++ b/SocietalConstructionToolTests/Snapshots/StaticCheckTests/WrongExpressionWhile.verified.txt @@ -17,4 +17,4 @@ Column: 11, Filename: {CurrentDirectory}TestFiles/StaticCheckTests/WrongExpressionWhile.sct } -] \ No newline at end of file +] diff --git a/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitAfter.sct b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitAfter.sct new file mode 100644 index 00000000..f6b7646f --- /dev/null +++ b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitAfter.sct @@ -0,0 +1,3 @@ +function Setup() -> void { + ExitAfterTicks(3); +} diff --git a/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenExists.sct b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenExists.sct new file mode 100644 index 00000000..08a21ae6 --- /dev/null +++ b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenExists.sct @@ -0,0 +1,13 @@ +class Foo() { + state Bar { + enter Baz; + } + state Baz { + enter Baz; + } +} + +function Setup() -> void { + create Foo::Bar(); + ExitWhenExists(Foo::Baz()); +} diff --git a/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenLessThan.sct b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenLessThan.sct new file mode 100644 index 00000000..1359ccd2 --- /dev/null +++ b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenLessThan.sct @@ -0,0 +1,16 @@ +class Foo() { + state Bar { + enter Baz; + } + state Baz { + destroy; + } +} + +function Setup() -> void { + create Foo::Bar(); + create Foo::Baz(); + create Foo::Baz(); + ExitWhenLessThan(Foo::?(), 2); +} + diff --git a/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenMoreThan.sct b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenMoreThan.sct new file mode 100644 index 00000000..20a371df --- /dev/null +++ b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenMoreThan.sct @@ -0,0 +1,14 @@ +class Foo() { + state Bar { + enter Baz; + } + state Baz { + create Foo::Bar(); + enter Baz; + } +} + +function Setup() -> void { + create Foo::Bar(); + ExitWhenMoreThan(Foo::Baz(), 1); +} diff --git a/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenNoLongerExists.sct b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenNoLongerExists.sct new file mode 100644 index 00000000..4104e9b8 --- /dev/null +++ b/SocietalConstructionToolTests/TestFiles/BehaviourTests/StdlibExitWhenNoLongerExists.sct @@ -0,0 +1,13 @@ +class Foo() { + state Bar { + enter Baz; + } + state Baz { + enter Baz; + } +} + +function Setup() -> void { + create Foo::Bar(); + ExitWhenNoLongerExists(Foo::Bar()); +}