Exemple #1
0
        public async Task Build(TaskScheduler taskScheduler, bool verbose)
        {
            var taskFactory   = new TaskFactory(taskScheduler);
            var projectBuilds = new Dictionary <Project, Task <Package> >();

            var projectBuildsSource = new TaskCompletionSource <FixedDictionary <Project, Task <Package> > >();
            var projectBuildsTask   = projectBuildsSource.Task;

            // Sort projects to detect cycles and so we can assume the tasks already exist
            var sortedProjects = TopologicalSort();
            var compiler       = new AdamantCompiler();
            var consoleLock    = new object();

            foreach (var project in sortedProjects)
            {
                var buildTask = taskFactory.StartNew(() =>
                                                     Build(compiler, project, projectBuildsTask, consoleLock))
                                .Unwrap(); // Needed because StartNew doesn't work intuitively with Async methods
                if (!projectBuilds.TryAdd(project, buildTask))
                {
                    throw new Exception("Project added to build set twice");
                }
            }
            projectBuildsSource.SetResult(projectBuilds.ToFixedDictionary());

            await Task.WhenAll(projectBuilds.Values);
        }
Exemple #2
0
        public async Task Build(TaskScheduler taskScheduler, bool verbose)
        {
            _ = verbose; // verbose parameter will be needed in the future
            var taskFactory   = new TaskFactory(taskScheduler);
            var projectBuilds = new Dictionary <Project, Task <PackageIL?> >();

            var projectBuildsSource = new TaskCompletionSource <FixedDictionary <Project, Task <PackageIL?> > >();
            var projectBuildsTask   = projectBuildsSource.Task;

            // Sort projects to detect cycles and so we can assume the tasks already exist
            var sortedProjects = TopologicalSort();
            var compiler       = new AdamantCompiler();
            var consoleLock    = new object();

            foreach (var project in sortedProjects)
            {
#pragma warning disable CA2008 // Do not create tasks without passing a TaskScheduler (created with task factory built with task scheduler)
                var buildTask = taskFactory.StartNew(() =>
                                                     Build(compiler, project, projectBuildsTask, consoleLock))
#pragma warning restore CA2008             // Do not create tasks without passing a TaskScheduler
                                .Unwrap(); // Needed because StartNew doesn't work intuitively with Async methods
                if (!projectBuilds.TryAdd(project, buildTask))
                {
                    throw new Exception("Project added to build set twice");
                }
            }
            projectBuildsSource.SetResult(projectBuilds.ToFixedDictionary());

            await Task.WhenAll(projectBuilds.Values).ConfigureAwait(false);
        }
Exemple #3
0
 private PackageIL CompileStdLib(AdamantCompiler compiler)
 {
     try
     {
         var sourceDir   = Path.Combine(SolutionDirectory.Get(), @"stdlib\src");
         var sourcePaths =
             Directory.EnumerateFiles(sourceDir, "*.ad", SearchOption.AllDirectories);
         var rootNamespace = FixedList <string> .Empty;
         var codeFiles     = sourcePaths.Select(p => LoadCode(p, sourceDir, rootNamespace))
                             .ToList();
         return(compiler.CompilePackage("adamant.stdlib", codeFiles,
                                        FixedDictionary <Name, PackageIL> .Empty));
     }
     catch (FatalCompilationErrorException ex)
     {
         testOutput.WriteLine("Std Lib Compiler Errors:");
         foreach (var diagnostic in ex.Diagnostics)
         {
             testOutput.WriteLine(
                 $"{diagnostic.File.Reference}:{diagnostic.StartPosition.Line}:{diagnostic.StartPosition.Column} {diagnostic.Level} {diagnostic.ErrorCode}");
             testOutput.WriteLine(diagnostic.Message);
         }
         Assert.True(false, "Compilation errors in standard library");
         throw new UnreachableCodeException();
     }
 }
Exemple #4
0
        private static Package CompileStdLib(AdamantCompiler compiler)
        {
            var sourceDir     = Path.Combine(SolutionDirectory.Get(), @"stdlib\src");
            var sourcePaths   = Directory.EnumerateFiles(sourceDir, "*.ad", SearchOption.AllDirectories);
            var rootNamespace = FixedList <string> .Empty;
            var codeFiles     = sourcePaths.Select(p => LoadCode(p, sourceDir, rootNamespace)).ToList();

            return(compiler.CompilePackage("adamant.stdlib",
                                           codeFiles,
                                           FixedDictionary <string, Package> .Empty));
        }
Exemple #5
0
        private static async Task <Package> Build(
            AdamantCompiler compiler,
            Project project,
            Task <FixedDictionary <Project, Task <Package> > > projectBuildsTask,
            object consoleLock)
        {
            var projectBuilds = await projectBuildsTask;
            var sourceDir     = Path.Combine(project.Path, "src");
            var sourcePaths   = Directory.EnumerateFiles(sourceDir, "*.ad", SearchOption.AllDirectories);
            // Wait for the references, unfortunately, this requires an ugly loop.
            var referenceTasks = project.References.ToDictionary(r => r.Name, r => projectBuilds[r.Project]);
            var references     = new Dictionary <string, Package>();

            foreach (var referenceTask in referenceTasks)
            {
                references.Add(referenceTask.Key, await referenceTask.Value);
            }

            lock (consoleLock)
            {
                Console.WriteLine($"Compiling {project.Name} ({project.Path})...");
            }
            var codeFiles = sourcePaths.Select(p => LoadCode(p, sourceDir, project.RootNamespace)).ToList();
            var package   = compiler.CompilePackage(project.Name, codeFiles, references.ToFixedDictionary());

            // TODO switch to the async version of the compiler
            //var codeFiles = sourcePaths.Select(p => new CodePath(p)).ToList();
            //var references = project.References.ToDictionary(r => r.Name, r => projectBuilds[r.Project]);
            //var package = await compiler.CompilePackageAsync(project.Name, codeFiles, references);
            if (OutputDiagnostics(project, package, consoleLock))
            {
                return(package);
            }

            var cacheDir = PrepareCacheDir(project);
            var codePath = EmitCode(project, package, cacheDir);
            var success  = CompileCode(project, cacheDir, codePath, consoleLock);

            lock (consoleLock)
            {
                Console.WriteLine(success
                    ? $"Build SUCCEEDED {project.Name} ({project.Path})"
                    : $"Build FAILED {project.Name} ({project.Path})");
            }

            return(package);
        }
Exemple #6
0
        public void Test_cases(TestCase testCase)
        {
            // Setup
            var codeFile   = CodeFile.Load(testCase.FullCodePath);
            var code       = codeFile.Code.Text;
            var compiler   = new AdamantCompiler();
            var references = new Dictionary <string, Package>();

            // Reference Standard Library
            var stdLibPackage = CompileStdLib(compiler);

            references.Add("adamant.stdlib", stdLibPackage);

            // Analyze
            var package = compiler.CompilePackage("testPackage", codeFile.Yield(), references.ToFixedDictionary());

            // Check for compiler errors
            var expectedCompileErrorLines = ExpectedCompileErrorLines(codeFile, code);

            Assert.NotNull(package.Diagnostics);
            var diagnostics = package.Diagnostics;

            if (diagnostics.Any())
            {
                testOutput.WriteLine("Compiler Errors:");
                foreach (var diagnostic in diagnostics)
                {
                    testOutput.WriteLine($"{testCase.RelativeCodePath}:{diagnostic.StartPosition.Line}:{diagnostic.StartPosition.Column} {diagnostic.Level} {diagnostic.ErrorCode}");
                    testOutput.WriteLine(diagnostic.Message);
                }
            }

            var errorDiagnostics = diagnostics
                                   .Where(d => d.Level >= DiagnosticLevel.CompilationError).ToList();

            if (expectedCompileErrorLines.Any())
            {
                foreach (var expectedCompileErrorLine in expectedCompileErrorLines)
                {
                    // Assert a single error on the given line
                    var errorsOnLine = errorDiagnostics.Count(e =>
                                                              e.StartPosition.Line == expectedCompileErrorLine);
                    Assert.True(errorsOnLine == 1,
                                $"Expected single error on line {expectedCompileErrorLine}, found {errorsOnLine}");
                }
            }

            foreach (var error in errorDiagnostics)
            {
                var errorLine = error.StartPosition.Line;
                if (expectedCompileErrorLines.All(line => line != errorLine))
                {
                    Assert.True(false, $"Unexpected error on line {error.StartPosition.Line}");
                }
            }

            // We got only expected errors, but need to not go one to emit code
            if (errorDiagnostics.Any())
            {
                return;
            }

            // Emit Code
            var codePath = Path.ChangeExtension(testCase.FullCodePath, "c");

            EmitCode(package, stdLibPackage, codePath);

            // Compile Code to Executable
            var exePath = CompileToExecutable(codePath);

            // Execute and check results
            var process = Execute(exePath);

            process.WaitForExit();
            var stdout = process.StandardOutput.ReadToEnd();

            testOutput.WriteLine("stdout:");
            testOutput.WriteLine(stdout);
            Assert.Equal(ExpectedOutput(code, "stdout"), stdout);
            var stderr = process.StandardError.ReadToEnd();

            testOutput.WriteLine("stderr:");
            testOutput.WriteLine(stderr);
            Assert.Equal(ExpectedOutput(code, "stderr"), stderr);
            Assert.Equal(ExpectedExitCode(code), process.ExitCode);
        }
Exemple #7
0
        public void Test_cases(TestCase testCase)
        {
            // Setup
            var codeFile = CodeFile.Load(testCase.FullCodePath);
            var code     = codeFile.Code.Text;
            var compiler = new AdamantCompiler()
            {
                SaveLivenessAnalysis   = true,
                SaveReachabilityGraphs = true,
            };
            var references = new Dictionary <Name, PackageIL>();

            // Reference Standard Library
            var stdLibPackage = CompileStdLib(compiler);

            references.Add("adamant.stdlib", stdLibPackage);

            try
            {
                // Analyze
                var package = compiler.CompilePackage("testPackage", codeFile.Yield(),
                                                      references.ToFixedDictionary());

                // Check for compiler errors
                Assert.NotNull(package.Diagnostics);
                var diagnostics      = package.Diagnostics;
                var errorDiagnostics = CheckErrorsExpected(testCase, codeFile, code, diagnostics);

                // Disassemble
                var ilAssembler = new ILAssembler();
                testOutput.WriteLine(ilAssembler.Disassemble(package));

                // We got only expected errors, but need to not go on to emit code
                if (errorDiagnostics.Any())
                {
                    return;
                }

                // Emit Code
                var codePath = Path.ChangeExtension(testCase.FullCodePath, "c");
                EmitCode(package, stdLibPackage, codePath);

                // Compile Code to Executable
                var exePath = CompileToExecutable(codePath);

                // Execute and check results
                var process = Execute(exePath);

                process.WaitForExit();
                var stdout = process.StandardOutput.ReadToEnd();
                testOutput.WriteLine("stdout:");
                testOutput.WriteLine(stdout);
                Assert.Equal(ExpectedOutput(code, "stdout", testCase.FullCodePath), stdout);
                var stderr = process.StandardError.ReadToEnd();
                testOutput.WriteLine("stderr:");
                testOutput.WriteLine(stderr);
                Assert.Equal(ExpectedOutput(code, "stderr", testCase.FullCodePath), stderr);
                Assert.Equal(ExpectedExitCode(code), process.ExitCode);
            }
            catch (FatalCompilationErrorException ex)
            {
                var diagnostics = ex.Diagnostics;
                CheckErrorsExpected(testCase, codeFile, code, diagnostics);
            }
        }