This repository has been archived on 2025-10-23. You can view files and clone it, but cannot push or open issues or pull requests.
Files
nub-lang-archive/src/CLI/Program.cs
nub31 16768beea6 ...
2025-06-14 23:33:09 +02:00

143 lines
3.7 KiB
C#

using System.Diagnostics;
using System.Reflection;
using CLI;
using Generation.QBE;
using Syntax;
using Syntax.Parsing;
using Syntax.Tokenization;
using Syntax.Typing;
const string BIN_DIR = "bin";
const string BIN_INT_DIR = "bin-int";
if (Directory.Exists(BIN_DIR))
{
Directory.Delete(BIN_DIR, true);
}
if (Directory.Exists(BIN_INT_DIR))
{
Directory.Delete(BIN_INT_DIR, true);
}
Directory.CreateDirectory(BIN_DIR);
Directory.CreateDirectory(BIN_INT_DIR);
var error = false;
var compilationUnits = new List<CompilationUnit>();
var sourceTexts = new Dictionary<CompilationUnit, SourceText>();
foreach (var file in args)
{
if (!File.Exists(file))
{
Console.Error.WriteLine($"File '{file}' does not exist");
return 1;
}
var content = File.ReadAllText(file);
var sourceText = new SourceText(file, content);
var tokenizeResult = Tokenizer.Tokenize(sourceText);
tokenizeResult.PrintAllDiagnostics();
error = error || tokenizeResult.HasErrors;
var parseResult = Parser.ParseFile(tokenizeResult.Value);
parseResult.PrintAllDiagnostics();
error = error || parseResult.HasErrors;
if (parseResult.Value != null)
{
compilationUnits.Add(parseResult.Value);
sourceTexts[parseResult.Value] = sourceText;
}
}
if (error)
{
return 1;
}
var definitionTable = new DefinitionTable(compilationUnits);
foreach (var compilationUnit in compilationUnits)
{
var typeCheckResult = TypeChecker.Check(compilationUnit, definitionTable);
typeCheckResult.PrintAllDiagnostics();
error = error || typeCheckResult.HasErrors;
}
if (error)
{
return 1;
}
var objectFiles = new List<string>();
foreach (var compilationUnit in compilationUnits)
{
var relativeFilePath = Path.GetRelativePath(Environment.CurrentDirectory, sourceTexts[compilationUnit].Path);
var outputPath = Path.Combine(BIN_INT_DIR, "program", relativeFilePath);
var outputDirectory = Path.GetDirectoryName(outputPath);
Debug.Assert(!string.IsNullOrWhiteSpace(outputDirectory));
Directory.CreateDirectory(outputDirectory);
var ssa = QBEGenerator.Generate(compilationUnit, definitionTable);
var ssaPath = Path.ChangeExtension(outputPath, "ssa");
File.WriteAllText(ssaPath, ssa);
var asm = await QBE.Invoke(ssa);
var asmPath = Path.ChangeExtension(outputPath, "s");
await File.WriteAllTextAsync(asmPath, asm);
var objPath = Path.ChangeExtension(outputPath, "o");
var asmSuccess = await GCC.Assemble(asmPath, objPath);
if (!asmSuccess)
{
return 1;
}
objectFiles.Add(objPath);
}
var assembly = Assembly.GetExecutingAssembly();
var runtimeResources = assembly
.GetManifestResourceNames()
.Where(name => name.EndsWith(".s", StringComparison.OrdinalIgnoreCase));
foreach (var resourceName in runtimeResources)
{
await using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream == null)
{
Console.Error.WriteLine($"Could not load embedded resource {resourceName}");
return 1;
}
using var reader = new StreamReader(stream);
var asm = await reader.ReadToEndAsync();
var outputDirectory = Path.Combine(BIN_INT_DIR, "runtime");
Directory.CreateDirectory(outputDirectory);
var fileName = resourceName.Split('.').Reverse().Skip(1).First();
var asmPath = Path.Combine(outputDirectory, fileName + ".s");
await File.WriteAllTextAsync(asmPath, asm);
var objPath = Path.Combine(outputDirectory, fileName + ".o");
var asmSuccess = await GCC.Assemble(asmPath, objPath);
if (!asmSuccess)
{
return 1;
}
objectFiles.Add(objPath);
}
var linkSuccess = await GCC.Link(objectFiles, Path.Combine(BIN_DIR, "out"));
return linkSuccess ? 0 : 1;