From 07713b63dcf83bfd9283bb84e15eb77bf0975fe7 Mon Sep 17 00:00:00 2001 From: HPT-I Date: Fri, 12 Apr 2024 10:38:20 +0200 Subject: [PATCH 01/12] Added multifile support --- .../Compiler/CompilerError.cs | 23 ++++ .../Compiler/Typechecker/SctTableVisitor.cs | 18 +-- SocietalConstructionTool/SctRunner.cs | 113 ++++++++++++++---- 3 files changed, 118 insertions(+), 36 deletions(-) diff --git a/SocietalConstructionTool/Compiler/CompilerError.cs b/SocietalConstructionTool/Compiler/CompilerError.cs index 576cadf2..5369ebf7 100644 --- a/SocietalConstructionTool/Compiler/CompilerError.cs +++ b/SocietalConstructionTool/Compiler/CompilerError.cs @@ -5,6 +5,7 @@ public class CompilerError public string Message { get; } public int? Line { get; } public int? Column { get; } + public string? Filename { get; set; } public CompilerError(string message) { @@ -24,8 +25,30 @@ public CompilerError(string message, int line, int column) Column = column; } + public CompilerError(string message, string fileName, int line, int column) + { + Message = message; + Filename = fileName; + Line = line; + Column = column; + } + public override string ToString() { + + if (Filename is not null) + { + if (Line is null) + { + return $"{Filename}: {Message}"; + } + if (Column is null) + { + return $"{Filename}, Line {Line}: {Message}"; + } + return $"{Filename}, Line {Line}, Column {Column}: {Message}"; + } + if (Line is null) { return Message; diff --git a/SocietalConstructionTool/Compiler/Typechecker/SctTableVisitor.cs b/SocietalConstructionTool/Compiler/Typechecker/SctTableVisitor.cs index a879f526..55482de8 100644 --- a/SocietalConstructionTool/Compiler/Typechecker/SctTableVisitor.cs +++ b/SocietalConstructionTool/Compiler/Typechecker/SctTableVisitor.cs @@ -2,29 +2,23 @@ namespace Sct.Compiler.Typechecker { - public class SctTableVisitor : SctBaseVisitor, IErrorReporter + public class SctTableVisitor(CTableBuilder cTableBuilder) : SctBaseVisitor, IErrorReporter { public CTable? Ctable { get; private set; } private readonly List _errors = new(); public IEnumerable Errors => _errors; - private readonly CTableBuilder _ctableBuilder = new(); + private readonly CTableBuilder _ctableBuilder = cTableBuilder; public override SctType VisitStart([NotNull] SctParser.StartContext context) { _ = base.VisitStart(context); - Ctable = _ctableBuilder.BuildCtable(); + // This spot used to check if there was a setup function and if it was of the correct type. + // This can no longer be done here, as the setup function can be defined in any file. + // And the TableVisitor is run on each file separately. + // TODO: Find another way to check this. - var setupType = Ctable.GlobalClass.LookupFunctionType("Setup"); - if (setupType is null) - { - _errors.Add(new CompilerError("No setup function found")); - } - else if (setupType.ReturnType != TypeTable.Void || setupType.ParameterTypes.Count != 0) - { - _errors.Add(new CompilerError("Setup function must return void and take no arguments")); - } return TypeTable.None; } diff --git a/SocietalConstructionTool/SctRunner.cs b/SocietalConstructionTool/SctRunner.cs index 439d78f6..cf774033 100644 --- a/SocietalConstructionTool/SctRunner.cs +++ b/SocietalConstructionTool/SctRunner.cs @@ -20,35 +20,88 @@ public static class SctRunner * * Reads an SCT source file, statically chekcs it and translates it into C# code * - * The path of the SCT source file + * The path of the SCT source file * The resulting C# source, or null if compilation failed */ - public static (string? outputText, IEnumerable errors) CompileSct(string filename) + public static (string? outputText, IEnumerable errors) CompileSct(string[] filenames) { - // TODO: Add error handling - string input = File.ReadAllText(filename); - ICharStream stream = CharStreams.fromString(input); - ITokenSource lexer = new SctLexer(stream); - ITokenStream tokens = new CommonTokenStream(lexer); - SctParser parser = new(tokens); - var startNode = parser.start(); - KeywordContextCheckVisitor keywordChecker = new(); - var errors = startNode.Accept(keywordChecker).ToList(); + // 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. + + // Create a CTableBuilder that is used for all files. + CTableBuilder cTableBuilder = new(); + var errors = new List(); + // Run static analysis on each file separately. + foreach (var file in filenames) + { + string input = File.ReadAllText(file); + ICharStream fileStream = CharStreams.fromString(input); + ITokenSource fileLexer = new SctLexer(fileStream); + ITokenStream fileTokens = new CommonTokenStream(fileLexer); + SctParser fileParser = new(fileTokens); + var startNode = fileParser.start(); + + KeywordContextCheckVisitor keywordChecker = new(); + + // Annotate each error with the filename. + var keywordErrors = startNode.Accept(keywordChecker).ToList(); + foreach (var error in keywordErrors) + { + error.Filename = file; + } + errors.AddRange(keywordErrors); + + // Run visitor that populates the tables using the CTableBuilder. + var sctTableVisitor = new SctTableVisitor(cTableBuilder); + _ = startNode.Accept(sctTableVisitor); + + foreach (var error in sctTableVisitor.Errors) + { + error.Filename = file; + } + + errors.AddRange(sctTableVisitor.Errors); + } - // Run visitor that populates the tables. - var sctTableVisitor = new SctTableVisitor(); - _ = startNode.Accept(sctTableVisitor); - var ctable = sctTableVisitor.Ctable; - errors.AddRange(sctTableVisitor.Errors); + // Build the CTable after all files have been visited. + // The CTable is used for type checking. + CTable cTable = cTableBuilder.BuildCtable(); - // Run visitor that checks the types. - var sctTypeChecker = new SctTypeChecker(ctable!); - _ = startNode.Accept(sctTypeChecker); - parser.Reset(); + // Typecheck each file separately. + // Identifiers from other files are known because the CTable is built from all files. + foreach (var file in filenames) + { + string input = File.ReadAllText(file); + ICharStream fileStream = CharStreams.fromString(input); + ITokenSource fileLexer = new SctLexer(fileStream); + ITokenStream fileTokens = new CommonTokenStream(fileLexer); + SctParser fileParser = new(fileTokens); + var startNode = fileParser.start(); + + // Run visitor that checks the types. + var sctTypeChecker = new SctTypeChecker(cTable); + _ = startNode.Accept(sctTypeChecker); + fileParser.Reset(); + + foreach (var error in sctTypeChecker.Errors) + { + error.Filename = file; + } + + errors.AddRange(sctTypeChecker.Errors); + } - errors.AddRange(sctTypeChecker.Errors); + // Concatenate all files into one string and run the translator on it. + string fullInput = ConcatenateFiles(filenames); + ICharStream stream = CharStreams.fromString(fullInput); + ITokenSource lexer = new SctLexer(stream); + ITokenStream tokens = new CommonTokenStream(lexer); + SctParser parser = new(tokens); var translator = new SctTranslator(); parser.AddParseListener(translator); @@ -144,10 +197,10 @@ public static void Run(Assembly assembly, IRuntimeContext initialContext) */ public static void CompileAndRun(string[] filenames, IOutputLogger logger) { - // TODO: Actually concatenate the files. Isak is working on this. - var filename = filenames[0]; - var (outputText, errors) = CompileSct(filename); + var (outputText, errors) = CompileSct(filenames); + + // TODO: Handle errors from ANTLR. They are not currently being passed to the errors list. if (errors.Any() || outputText is null) { Console.Error.WriteLine("Compilation failed:"); @@ -169,5 +222,17 @@ public static void CompileAndRun(string[] filenames, IOutputLogger logger) Run(assembly, logger); } + + private static string ConcatenateFiles(string[] filenames) + { + + string result = string.Empty; + foreach (var file in filenames) + { + result += File.ReadAllText(file); + } + + return result; + } } } From a948f78f8516d86e403d6d2d7bea7bf95a161a36 Mon Sep 17 00:00:00 2001 From: HPT-I Date: Fri, 12 Apr 2024 12:51:16 +0200 Subject: [PATCH 02/12] check setup in CompileSct and run returnvisitor --- SocietalConstructionTool/SctRunner.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/SocietalConstructionTool/SctRunner.cs b/SocietalConstructionTool/SctRunner.cs index cf774033..d337c96a 100644 --- a/SocietalConstructionTool/SctRunner.cs +++ b/SocietalConstructionTool/SctRunner.cs @@ -56,6 +56,14 @@ public static (string? outputText, IEnumerable errors) CompileSct } errors.AddRange(keywordErrors); + SctReturnCheckVisitor returnChecker = new(); + _ = startNode.Accept(returnChecker); + foreach (var error in returnChecker.Errors) + { + error.Filename = file; + } + errors.AddRange(returnChecker.Errors); + // Run visitor that populates the tables using the CTableBuilder. var sctTableVisitor = new SctTableVisitor(cTableBuilder); _ = startNode.Accept(sctTableVisitor); @@ -72,6 +80,15 @@ public static (string? outputText, IEnumerable errors) CompileSct // The CTable is used for type checking. CTable cTable = cTableBuilder.BuildCtable(); + var setupType = cTable.GlobalClass.LookupFunctionType("Setup"); + if (setupType is null) + { + errors.Add(new CompilerError("No Setup function found.")); + } else if (setupType.ReturnType != TypeTable.Void || setupType.ParameterTypes.Count != 0) + { + errors.Add(new CompilerError("Setup function must return void and take no arguments")); + } + // Typecheck each file separately. // Identifiers from other files are known because the CTable is built from all files. foreach (var file in filenames) From 000d4f1269602c9108a2968ae161caf7ef4e8e3b Mon Sep 17 00:00:00 2001 From: HPT-I Date: Fri, 12 Apr 2024 12:51:46 +0200 Subject: [PATCH 03/12] removed comment --- .../Compiler/Typechecker/SctTableVisitor.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/SocietalConstructionTool/Compiler/Typechecker/SctTableVisitor.cs b/SocietalConstructionTool/Compiler/Typechecker/SctTableVisitor.cs index 55482de8..2e2f1dcf 100644 --- a/SocietalConstructionTool/Compiler/Typechecker/SctTableVisitor.cs +++ b/SocietalConstructionTool/Compiler/Typechecker/SctTableVisitor.cs @@ -14,11 +14,6 @@ public override SctType VisitStart([NotNull] SctParser.StartContext context) { _ = base.VisitStart(context); - // This spot used to check if there was a setup function and if it was of the correct type. - // This can no longer be done here, as the setup function can be defined in any file. - // And the TableVisitor is run on each file separately. - // TODO: Find another way to check this. - return TypeTable.None; } From eb98d2ed50f15b816c383c0cf21ebc819a6e1580 Mon Sep 17 00:00:00 2001 From: HPT-I Date: Fri, 12 Apr 2024 13:00:10 +0200 Subject: [PATCH 04/12] Fixed tests not passing --- SocietalConstructionTool/SctRunner.cs | 2 +- .../TypecheckerTests.cs | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/SocietalConstructionTool/SctRunner.cs b/SocietalConstructionTool/SctRunner.cs index d337c96a..329f6762 100644 --- a/SocietalConstructionTool/SctRunner.cs +++ b/SocietalConstructionTool/SctRunner.cs @@ -83,7 +83,7 @@ public static (string? outputText, IEnumerable errors) CompileSct var setupType = cTable.GlobalClass.LookupFunctionType("Setup"); if (setupType is null) { - errors.Add(new CompilerError("No Setup function found.")); + errors.Add(new CompilerError("No setup function found")); } else if (setupType.ReturnType != TypeTable.Void || setupType.ParameterTypes.Count != 0) { errors.Add(new CompilerError("Setup function must return void and take no arguments")); diff --git a/SocietalConstructionToolTests/TypecheckerTests.cs b/SocietalConstructionToolTests/TypecheckerTests.cs index f2723244..7704efce 100644 --- a/SocietalConstructionToolTests/TypecheckerTests.cs +++ b/SocietalConstructionToolTests/TypecheckerTests.cs @@ -37,9 +37,21 @@ public async Task TypecheckFile(string testFile) _ = startNode.Accept(returnChecker); errors.AddRange(returnChecker.Errors); - var sctTableVisitor = new SctTableVisitor(); + var cTableBuilder = new CTableBuilder(); + + var sctTableVisitor = new SctTableVisitor(cTableBuilder); _ = sctTableVisitor.Visit(startNode); - var ctable = sctTableVisitor.Ctable; + var ctable = cTableBuilder.BuildCtable(); + + var setupType = ctable.GlobalClass.LookupFunctionType("Setup"); + if (setupType is null) + { + errors.Add(new CompilerError("No setup function found")); + } else if (setupType.ReturnType != TypeTable.Void || setupType.ParameterTypes.Count != 0) + { + errors.Add(new CompilerError("Setup function must return void and take no arguments")); + } + errors.AddRange(sctTableVisitor.Errors); var sctTypeChecker = new SctTypeChecker(ctable!); From 5fd831cc6205a28932604cb5236d91d37a3b306e Mon Sep 17 00:00:00 2001 From: HPT-I Date: Fri, 12 Apr 2024 13:10:32 +0200 Subject: [PATCH 05/12] Reused parser for type checking. --- SocietalConstructionTool/SctRunner.cs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/SocietalConstructionTool/SctRunner.cs b/SocietalConstructionTool/SctRunner.cs index 329f6762..3b7a5239 100644 --- a/SocietalConstructionTool/SctRunner.cs +++ b/SocietalConstructionTool/SctRunner.cs @@ -36,6 +36,9 @@ public static (string? outputText, IEnumerable errors) CompileSct CTableBuilder cTableBuilder = new(); var errors = new List(); + // Store parses for each file to avoid having to recreate them for type checking. + Dictionary parsers = new(); + // Run static analysis on each file separately. foreach (var file in filenames) { @@ -43,8 +46,10 @@ public static (string? outputText, IEnumerable errors) CompileSct ICharStream fileStream = CharStreams.fromString(input); ITokenSource fileLexer = new SctLexer(fileStream); ITokenStream fileTokens = new CommonTokenStream(fileLexer); - SctParser fileParser = new(fileTokens); - var startNode = fileParser.start(); + + // Save parser for later use. + parsers[file] = new SctParser(fileTokens); + var startNode = parsers[file].start(); KeywordContextCheckVisitor keywordChecker = new(); @@ -74,6 +79,9 @@ public static (string? outputText, IEnumerable errors) CompileSct } errors.AddRange(sctTableVisitor.Errors); + + // Reset the parser to be able to type check the file later. + parsers[file].Reset(); } // Build the CTable after all files have been visited. @@ -93,17 +101,11 @@ public static (string? outputText, IEnumerable errors) CompileSct // Identifiers from other files are known because the CTable is built from all files. foreach (var file in filenames) { - string input = File.ReadAllText(file); - ICharStream fileStream = CharStreams.fromString(input); - ITokenSource fileLexer = new SctLexer(fileStream); - ITokenStream fileTokens = new CommonTokenStream(fileLexer); - SctParser fileParser = new(fileTokens); - var startNode = fileParser.start(); + var startNode = parsers[file].start(); // Run visitor that checks the types. var sctTypeChecker = new SctTypeChecker(cTable); _ = startNode.Accept(sctTypeChecker); - fileParser.Reset(); foreach (var error in sctTypeChecker.Errors) { @@ -111,6 +113,9 @@ public static (string? outputText, IEnumerable errors) CompileSct } errors.AddRange(sctTypeChecker.Errors); + + // Reset the parser because its good practice. + parsers[file].Reset(); } // Concatenate all files into one string and run the translator on it. From cfa3e5705a0f03d11f4972a7f529e87a5965d307 Mon Sep 17 00:00:00 2001 From: HPT-I Date: Fri, 12 Apr 2024 13:12:36 +0200 Subject: [PATCH 06/12] Ran formatter --- SocietalConstructionTool/SctRunner.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SocietalConstructionTool/SctRunner.cs b/SocietalConstructionTool/SctRunner.cs index 3b7a5239..1f47e373 100644 --- a/SocietalConstructionTool/SctRunner.cs +++ b/SocietalConstructionTool/SctRunner.cs @@ -92,7 +92,8 @@ public static (string? outputText, IEnumerable errors) CompileSct if (setupType is null) { errors.Add(new CompilerError("No setup function found")); - } else if (setupType.ReturnType != TypeTable.Void || setupType.ParameterTypes.Count != 0) + } + else if (setupType.ReturnType != TypeTable.Void || setupType.ParameterTypes.Count != 0) { errors.Add(new CompilerError("Setup function must return void and take no arguments")); } From 9688d36a12bcd19e72890e59a8ce2ddc2efdba10 Mon Sep 17 00:00:00 2001 From: HPT-I Date: Fri, 12 Apr 2024 13:14:07 +0200 Subject: [PATCH 07/12] ran formatter in test project --- SocietalConstructionToolTests/TypecheckerTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SocietalConstructionToolTests/TypecheckerTests.cs b/SocietalConstructionToolTests/TypecheckerTests.cs index 7704efce..b8d4247c 100644 --- a/SocietalConstructionToolTests/TypecheckerTests.cs +++ b/SocietalConstructionToolTests/TypecheckerTests.cs @@ -47,7 +47,8 @@ public async Task TypecheckFile(string testFile) if (setupType is null) { errors.Add(new CompilerError("No setup function found")); - } else if (setupType.ReturnType != TypeTable.Void || setupType.ParameterTypes.Count != 0) + } + else if (setupType.ReturnType != TypeTable.Void || setupType.ParameterTypes.Count != 0) { errors.Add(new CompilerError("Setup function must return void and take no arguments")); } From a9d66428294fe340f505b829fef4c2db1a36f474 Mon Sep 17 00:00:00 2001 From: HPT-I Date: Mon, 15 Apr 2024 13:05:59 +0200 Subject: [PATCH 08/12] Added tests --- .../SplitFileTests/MultiFileOne.verified.txt | 71 +++++++++++++++++++ .../SplitFileTests/MultiFileTwo.verified.txt | 71 +++++++++++++++++++ .../SplitFileTests.cs | 35 +++++++++ .../TestFiles/SplitFileTests/MultiFileOne.sct | 17 +++++ .../TestFiles/SplitFileTests/MultiFileTwo.sct | 7 ++ 5 files changed, 201 insertions(+) create mode 100644 SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt create mode 100644 SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt create mode 100644 SocietalConstructionToolTests/SplitFileTests.cs create mode 100644 SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileOne.sct create mode 100644 SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileTwo.sct diff --git a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt new file mode 100644 index 00000000..d16a6a96 --- /dev/null +++ b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt @@ -0,0 +1,71 @@ +namespace SctGenerated +{ + using Sct.Runtime; + using System; + using System.Collections.Generic; + + public class GlobalClass + { + public static long __sct_endCheck(IRuntimeContext ctx) + { + if ((2 > 3 ? 1 : 0) != 0) + { + return 0; + } + else + { + return 1; + } + } + + public static void __sct_Setup(IRuntimeContext ctx) + { + ctx.AgentHandler.CreateAgent(new __sct_Town("__sct_Growing", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_id", 1), new KeyValuePair("__sct_space", 50) }))); + } + + public class __sct_Town : BaseAgent + { + private int __sct_id { get => Fields["__sct_id"]; set => Fields["__sct_id"] = value; } + private int __sct_space { get => Fields["__sct_space"]; set => Fields["__sct_space"] = value; } + + public __sct_Town(String state, IDictionary fields) : base(state, fields) + { + } + + private bool __sct_Growing(IRuntimeContext ctx) + { + if (__sct_endCheck(ctx) != 0) + { + Enter(ctx, "__sct_End"); + return true; + } + + Enter(ctx, "__sct_Growing"); + return true; + return false; + } + + private bool __sct_End(IRuntimeContext ctx) + { + ctx.ExitRuntime(); + return true; + return false; + } + + public override void Update(IRuntimeContext ctx) + { + _ = State switch + { + "__sct_Growing" => __sct_Growing(ctx), + "__sct_End" => __sct_End(ctx)}; + } + } + + public static void RunSimulation(IRuntimeContext ctx) + { + Runtime runtime = new Runtime(); + __sct_Setup(ctx); + runtime.Run(ctx); + } + } +} diff --git a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt new file mode 100644 index 00000000..7ee7e885 --- /dev/null +++ b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt @@ -0,0 +1,71 @@ +namespace SctGenerated +{ + using Sct.Runtime; + using System; + using System.Collections.Generic; + + public class GlobalClass + { + public static long __sct_endCheck(IRuntimeContext ctx) + { + if ((2 > 3 ? 1 : 0) != 0) + { + return 0; + } + else + { + return 1; + } + } + + public static void __sct_Setup(IRuntimeContext ctx) + { + ctx.AgentHandler.CreateAgent(new __sct_Town("__sct_Growing", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_id", 1), new KeyValuePair("__sct_space", 50) }))); + } + + public class __sct_Town : BaseAgent + { + private int __sct_id { get => Fields["__sct_id"]; set => Fields["__sct_id"] = value; } + private int __sct_space { get => Fields["__sct_space"]; set => Fields["__sct_space"] = value; } + + public __sct_Town(String state, IDictionary fields) : base(state, fields) + { + } + + private bool __sct_Growing(IRuntimeContext ctx) + { + if (__sct_endCheck(ctx) != 0) + { + Enter(ctx, "__sct_End"); + return true; + } + + Enter(ctx, "__sct_Growing"); + return true; + return false; + } + + private bool __sct_End(IRuntimeContext ctx) + { + ctx.ExitRuntime(); + return true; + return false; + } + + public override void Update(IRuntimeContext ctx) + { + _ = State switch + { + "__sct_Growing" => __sct_Growing(ctx), + "__sct_End" => __sct_End(ctx)}; + } + } + + public static void RunSimulation(IRuntimeContext ctx) + { + Runtime runtime = new Runtime(); + __sct_Setup(ctx); + runtime.Run(ctx); + } + } +} \ No newline at end of file diff --git a/SocietalConstructionToolTests/SplitFileTests.cs b/SocietalConstructionToolTests/SplitFileTests.cs new file mode 100644 index 00000000..062ca98e --- /dev/null +++ b/SocietalConstructionToolTests/SplitFileTests.cs @@ -0,0 +1,35 @@ +using Microsoft.CodeAnalysis; + +using Sct; + +namespace SocietalConstructionToolTests +{ + [TestClass] + public class SplitFileTests : AbstractSnapshotTests + { + private static new IEnumerable Files => + Directory.GetFiles(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "SplitFileTests")) + .Select(f => new[] { f }); + + + [DataTestMethod] + [DynamicData(nameof(Files), DynamicDataSourceType.Property)] + public async Task RunFiles(params string[] files) + { + UseProjectRelativeDirectory("Snapshots/SplitFileTests"); // save snapshots here + + var (outputText, errors) = SctRunner.CompileSct(GetFiles()); + + Assert.IsTrue(errors.Count() == 0, string.Join("\n", errors)); + _ = await Verify(outputText) + .UseFileName(Path.GetFileNameWithoutExtension(files[0])); + } + + // RunFiles is run for each file, and passing files to CompileSct only passes the file that triggered the test. + // This method is used to get all files to pass to CompileSct. + private static string[] GetFiles() + { + return Files.SelectMany(f => f).ToArray(); + } + } +} diff --git a/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileOne.sct b/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileOne.sct new file mode 100644 index 00000000..d30cca72 --- /dev/null +++ b/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileOne.sct @@ -0,0 +1,17 @@ +class Town(int id, int space) { + state Growing { + if (endCheck()) { + enter End; + } + enter Growing; + } + state End { + exit; + } +} + +function Setup() -> void { + // Create a town in the state growing with the id of 1 and space for 50 people + create Town::Growing(id: 1, space: 50); + +} diff --git a/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileTwo.sct b/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileTwo.sct new file mode 100644 index 00000000..20bc176d --- /dev/null +++ b/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileTwo.sct @@ -0,0 +1,7 @@ +function endCheck() -> int { + if (2 > 3) { + return 0; + } else { + return 1; + } +} From bf5a391cc868223d6f148031eb53d544e5aadb5c Mon Sep 17 00:00:00 2001 From: HPT-I Date: Mon, 15 Apr 2024 13:16:05 +0200 Subject: [PATCH 09/12] Simplified test files --- .../SplitFileTests/MultiFileOne.verified.txt | 26 +++++-------------- .../SplitFileTests/MultiFileTwo.verified.txt | 24 +++++------------ .../TestFiles/SplitFileTests/MultiFileOne.sct | 12 --------- .../TestFiles/SplitFileTests/MultiFileTwo.sct | 14 ++++++---- 4 files changed, 22 insertions(+), 54 deletions(-) diff --git a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt index d16a6a96..02220488 100644 --- a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt +++ b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileOne.verified.txt @@ -6,23 +6,6 @@ public class GlobalClass { - public static long __sct_endCheck(IRuntimeContext ctx) - { - if ((2 > 3 ? 1 : 0) != 0) - { - return 0; - } - else - { - return 1; - } - } - - public static void __sct_Setup(IRuntimeContext ctx) - { - ctx.AgentHandler.CreateAgent(new __sct_Town("__sct_Growing", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_id", 1), new KeyValuePair("__sct_space", 50) }))); - } - public class __sct_Town : BaseAgent { private int __sct_id { get => Fields["__sct_id"]; set => Fields["__sct_id"] = value; } @@ -34,7 +17,7 @@ private bool __sct_Growing(IRuntimeContext ctx) { - if (__sct_endCheck(ctx) != 0) + if (1 != 0) { Enter(ctx, "__sct_End"); return true; @@ -61,6 +44,11 @@ } } + public static void __sct_Setup(IRuntimeContext ctx) + { + ctx.AgentHandler.CreateAgent(new __sct_Town("__sct_Growing", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_id", 1), new KeyValuePair("__sct_space", 50) }))); + } + public static void RunSimulation(IRuntimeContext ctx) { Runtime runtime = new Runtime(); @@ -68,4 +56,4 @@ runtime.Run(ctx); } } -} +} \ No newline at end of file diff --git a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt index 7ee7e885..02220488 100644 --- a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt +++ b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt @@ -6,23 +6,6 @@ public class GlobalClass { - public static long __sct_endCheck(IRuntimeContext ctx) - { - if ((2 > 3 ? 1 : 0) != 0) - { - return 0; - } - else - { - return 1; - } - } - - public static void __sct_Setup(IRuntimeContext ctx) - { - ctx.AgentHandler.CreateAgent(new __sct_Town("__sct_Growing", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_id", 1), new KeyValuePair("__sct_space", 50) }))); - } - public class __sct_Town : BaseAgent { private int __sct_id { get => Fields["__sct_id"]; set => Fields["__sct_id"] = value; } @@ -34,7 +17,7 @@ private bool __sct_Growing(IRuntimeContext ctx) { - if (__sct_endCheck(ctx) != 0) + if (1 != 0) { Enter(ctx, "__sct_End"); return true; @@ -61,6 +44,11 @@ } } + public static void __sct_Setup(IRuntimeContext ctx) + { + ctx.AgentHandler.CreateAgent(new __sct_Town("__sct_Growing", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_id", 1), new KeyValuePair("__sct_space", 50) }))); + } + public static void RunSimulation(IRuntimeContext ctx) { Runtime runtime = new Runtime(); diff --git a/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileOne.sct b/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileOne.sct index d30cca72..ad0dd09d 100644 --- a/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileOne.sct +++ b/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileOne.sct @@ -1,15 +1,3 @@ -class Town(int id, int space) { - state Growing { - if (endCheck()) { - enter End; - } - enter Growing; - } - state End { - exit; - } -} - function Setup() -> void { // Create a town in the state growing with the id of 1 and space for 50 people create Town::Growing(id: 1, space: 50); diff --git a/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileTwo.sct b/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileTwo.sct index 20bc176d..b7576ae1 100644 --- a/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileTwo.sct +++ b/SocietalConstructionToolTests/TestFiles/SplitFileTests/MultiFileTwo.sct @@ -1,7 +1,11 @@ -function endCheck() -> int { - if (2 > 3) { - return 0; - } else { - return 1; +class Town(int id, int space) { + state Growing { + if (1) { + enter End; + } + enter Growing; + } + state End { + exit; } } From 6d7ac80e54e61e72f1d5c88418d4a9e58c922bbf Mon Sep 17 00:00:00 2001 From: HPT-I Date: Mon, 15 Apr 2024 13:19:56 +0200 Subject: [PATCH 10/12] hack attempt --- SocietalConstructionToolTests/SplitFileTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SocietalConstructionToolTests/SplitFileTests.cs b/SocietalConstructionToolTests/SplitFileTests.cs index 062ca98e..e602fce4 100644 --- a/SocietalConstructionToolTests/SplitFileTests.cs +++ b/SocietalConstructionToolTests/SplitFileTests.cs @@ -14,14 +14,14 @@ public class SplitFileTests : AbstractSnapshotTests [DataTestMethod] [DynamicData(nameof(Files), DynamicDataSourceType.Property)] - public async Task RunFiles(params string[] files) + public void RunFiles(params string[] files) { UseProjectRelativeDirectory("Snapshots/SplitFileTests"); // save snapshots here var (outputText, errors) = SctRunner.CompileSct(GetFiles()); Assert.IsTrue(errors.Count() == 0, string.Join("\n", errors)); - _ = await Verify(outputText) + _ = Verify(outputText) .UseFileName(Path.GetFileNameWithoutExtension(files[0])); } From b54b51d44352cb1779b58a65bf6506b364206bc2 Mon Sep 17 00:00:00 2001 From: HPT-I Date: Wed, 17 Apr 2024 12:56:10 +0200 Subject: [PATCH 11/12] addressed comments --- SocietalConstructionTool/SctRunner.cs | 24 ++++---- .../SplitFileTests/MultiFileTwo.verified.txt | 59 ------------------- .../SplitFileTests.cs | 10 ++-- 3 files changed, 17 insertions(+), 76 deletions(-) delete mode 100644 SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt diff --git a/SocietalConstructionTool/SctRunner.cs b/SocietalConstructionTool/SctRunner.cs index 1f47e373..4931d784 100644 --- a/SocietalConstructionTool/SctRunner.cs +++ b/SocietalConstructionTool/SctRunner.cs @@ -37,7 +37,7 @@ public static (string? outputText, IEnumerable errors) CompileSct var errors = new List(); // Store parses for each file to avoid having to recreate them for type checking. - Dictionary parsers = new(); + Dictionary startNodes = new(); // Run static analysis on each file separately. foreach (var file in filenames) @@ -47,9 +47,10 @@ public static (string? outputText, IEnumerable errors) CompileSct ITokenSource fileLexer = new SctLexer(fileStream); ITokenStream fileTokens = new CommonTokenStream(fileLexer); + var fileParser = new SctParser(fileTokens); // Save parser for later use. - parsers[file] = new SctParser(fileTokens); - var startNode = parsers[file].start(); + startNodes[file] = fileParser.start(); + var startNode = startNodes[file]; KeywordContextCheckVisitor keywordChecker = new(); @@ -79,9 +80,6 @@ public static (string? outputText, IEnumerable errors) CompileSct } errors.AddRange(sctTableVisitor.Errors); - - // Reset the parser to be able to type check the file later. - parsers[file].Reset(); } // Build the CTable after all files have been visited. @@ -102,7 +100,7 @@ public static (string? outputText, IEnumerable errors) CompileSct // Identifiers from other files are known because the CTable is built from all files. foreach (var file in filenames) { - var startNode = parsers[file].start(); + var startNode = startNodes[file]; // Run visitor that checks the types. var sctTypeChecker = new SctTypeChecker(cTable); @@ -116,7 +114,12 @@ public static (string? outputText, IEnumerable errors) CompileSct errors.AddRange(sctTypeChecker.Errors); // Reset the parser because its good practice. - parsers[file].Reset(); + // startNodes[file].Reset(); + } + + if (errors.Count > 0) + { + return (null, errors); } // Concatenate all files into one string and run the translator on it. @@ -130,11 +133,6 @@ public static (string? outputText, IEnumerable errors) CompileSct parser.AddParseListener(translator); _ = parser.start(); - if (errors.Count > 0) - { - return (null, errors); - } - if (translator.Root is null) { throw new InvalidOperationException("Translation failed"); diff --git a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt b/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt deleted file mode 100644 index 02220488..00000000 --- a/SocietalConstructionToolTests/Snapshots/SplitFileTests/MultiFileTwo.verified.txt +++ /dev/null @@ -1,59 +0,0 @@ -namespace SctGenerated -{ - using Sct.Runtime; - using System; - using System.Collections.Generic; - - public class GlobalClass - { - public class __sct_Town : BaseAgent - { - private int __sct_id { get => Fields["__sct_id"]; set => Fields["__sct_id"] = value; } - private int __sct_space { get => Fields["__sct_space"]; set => Fields["__sct_space"] = value; } - - public __sct_Town(String state, IDictionary fields) : base(state, fields) - { - } - - private bool __sct_Growing(IRuntimeContext ctx) - { - if (1 != 0) - { - Enter(ctx, "__sct_End"); - return true; - } - - Enter(ctx, "__sct_Growing"); - return true; - return false; - } - - private bool __sct_End(IRuntimeContext ctx) - { - ctx.ExitRuntime(); - return true; - return false; - } - - public override void Update(IRuntimeContext ctx) - { - _ = State switch - { - "__sct_Growing" => __sct_Growing(ctx), - "__sct_End" => __sct_End(ctx)}; - } - } - - public static void __sct_Setup(IRuntimeContext ctx) - { - ctx.AgentHandler.CreateAgent(new __sct_Town("__sct_Growing", new Dictionary(new KeyValuePair[] { new KeyValuePair("__sct_id", 1), new KeyValuePair("__sct_space", 50) }))); - } - - public static void RunSimulation(IRuntimeContext ctx) - { - Runtime runtime = new Runtime(); - __sct_Setup(ctx); - runtime.Run(ctx); - } - } -} \ No newline at end of file diff --git a/SocietalConstructionToolTests/SplitFileTests.cs b/SocietalConstructionToolTests/SplitFileTests.cs index e602fce4..0ae07963 100644 --- a/SocietalConstructionToolTests/SplitFileTests.cs +++ b/SocietalConstructionToolTests/SplitFileTests.cs @@ -13,15 +13,17 @@ public class SplitFileTests : AbstractSnapshotTests [DataTestMethod] - [DynamicData(nameof(Files), DynamicDataSourceType.Property)] - public void RunFiles(params string[] files) + public async Task RunFiles() { UseProjectRelativeDirectory("Snapshots/SplitFileTests"); // save snapshots here - var (outputText, errors) = SctRunner.CompileSct(GetFiles()); + var files = GetFiles(); + + var (outputText, errors) = SctRunner.CompileSct(files); Assert.IsTrue(errors.Count() == 0, string.Join("\n", errors)); - _ = Verify(outputText) + Assert.IsNotNull(outputText); + _ = await Verify(outputText) .UseFileName(Path.GetFileNameWithoutExtension(files[0])); } From 716d2239f17ec47e000d8b6a41121be9bf76dbdc Mon Sep 17 00:00:00 2001 From: HPT-I Date: Wed, 17 Apr 2024 14:16:41 +0200 Subject: [PATCH 12/12] removed commented code --- SocietalConstructionTool/SctRunner.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/SocietalConstructionTool/SctRunner.cs b/SocietalConstructionTool/SctRunner.cs index 84a58661..00375905 100644 --- a/SocietalConstructionTool/SctRunner.cs +++ b/SocietalConstructionTool/SctRunner.cs @@ -112,9 +112,6 @@ public static (string? outputText, IEnumerable errors) CompileSct } errors.AddRange(sctTypeChecker.Errors); - - // Reset the parser because its good practice. - // startNodes[file].Reset(); } if (errors.Count > 0)