diff --git a/run.sh b/run.sh
index 58dfd46..8ee553e 100755
--- a/run.sh
+++ b/run.sh
@@ -1,4 +1,4 @@
#!/bin/bash
set -e
-dotnet run --project src/CLI/CLI.csproj example/main.nub example/c.nub
+dotnet run --project src/compilation/CLI/CLI.csproj example/main.nub example/c.nub
./bin/out
\ No newline at end of file
diff --git a/src/.gitignore b/src/.gitignore
deleted file mode 100644
index c6cc67a..0000000
--- a/src/.gitignore
+++ /dev/null
@@ -1,34 +0,0 @@
-# Common IntelliJ Platform excludes
-
-# User specific
-**/.idea/**/workspace.xml
-**/.idea/**/tasks.xml
-**/.idea/shelf/*
-**/.idea/dictionaries
-**/.idea/httpRequests/
-
-# Sensitive or high-churn files
-**/.idea/**/dataSources/
-**/.idea/**/dataSources.ids
-**/.idea/**/dataSources.xml
-**/.idea/**/dataSources.local.xml
-**/.idea/**/sqlDataSources.xml
-**/.idea/**/dynamic.xml
-
-# Rider
-# Rider auto-generates .iml files, and contentModel.xml
-**/.idea/**/*.iml
-**/.idea/**/contentModel.xml
-**/.idea/**/modules.xml
-
-*.suo
-*.user
-.vs/
-[Bb]in/
-[Oo]bj/
-_UpgradeReport_Files/
-[Pp]ackages/
-
-Thumbs.db
-Desktop.ini
-.DS_Store
\ No newline at end of file
diff --git a/src/.idea/.idea.Compiler/.idea/.gitignore b/src/.idea/.idea.Compiler/.idea/.gitignore
deleted file mode 100644
index cda1cf4..0000000
--- a/src/.idea/.idea.Compiler/.idea/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Rider ignored files
-/modules.xml
-/projectSettingsUpdater.xml
-/contentModel.xml
-/.idea.Compiler.iml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/src/.idea/.idea.Compiler/.idea/.name b/src/.idea/.idea.Compiler/.idea/.name
deleted file mode 100644
index b92b7a3..0000000
--- a/src/.idea/.idea.Compiler/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-Compiler
\ No newline at end of file
diff --git a/src/.idea/.idea.Compiler/.idea/encodings.xml b/src/.idea/.idea.Compiler/.idea/encodings.xml
deleted file mode 100644
index df87cf9..0000000
--- a/src/.idea/.idea.Compiler/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/.idea/.idea.Compiler/.idea/indexLayout.xml b/src/.idea/.idea.Compiler/.idea/indexLayout.xml
deleted file mode 100644
index 7b08163..0000000
--- a/src/.idea/.idea.Compiler/.idea/indexLayout.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/.idea/.idea.Compiler/.idea/vcs.xml b/src/.idea/.idea.Compiler/.idea/vcs.xml
deleted file mode 100644
index 6c0b863..0000000
--- a/src/.idea/.idea.Compiler/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/CLI/CLI.csproj b/src/CLI/CLI.csproj
deleted file mode 100644
index c8dff8b..0000000
--- a/src/CLI/CLI.csproj
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- nub
- Exe
- net9.0
- enable
- enable
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/CLI/GCC.cs b/src/CLI/GCC.cs
deleted file mode 100644
index 445814c..0000000
--- a/src/CLI/GCC.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System.Diagnostics;
-
-namespace CLI;
-
-public static class GCC
-{
- public static async Task Assemble(string asmPath, string objPath)
- {
- using var gccProcess = new Process();
- gccProcess.StartInfo = new ProcessStartInfo("gcc", ["-g", "-c", asmPath, "-o", objPath])
- {
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
-
- gccProcess.Start();
- await gccProcess.WaitForExitAsync();
-
- var gccErrors = await gccProcess.StandardError.ReadToEndAsync();
- if (!string.IsNullOrWhiteSpace(gccErrors))
- {
- await Console.Error.WriteLineAsync("gcc error when assembling:\n" + gccErrors);
- }
-
- return gccProcess.ExitCode == 0;
- }
-
- public static async Task Link(List objectFiles, string outputPath)
- {
- using var gccProcess = new Process();
- gccProcess.StartInfo = new ProcessStartInfo("gcc", ["-g", "-nostartfiles", "-o", outputPath, ..objectFiles])
- {
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
-
- gccProcess.Start();
- await gccProcess.WaitForExitAsync();
-
- var gccErrors = await gccProcess.StandardError.ReadToEndAsync();
- if (!string.IsNullOrWhiteSpace(gccErrors))
- {
- await Console.Error.WriteLineAsync("gcc error when linking:\n" + gccErrors);
- }
-
- return gccProcess.ExitCode == 0;
- }
-}
diff --git a/src/CLI/Program.cs b/src/CLI/Program.cs
deleted file mode 100644
index f62895f..0000000
--- a/src/CLI/Program.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-using System.Diagnostics;
-using System.Reflection;
-using CLI;
-using Generation.QBE;
-using Syntax;
-using Syntax.Diagnostics;
-using Syntax.Parsing;
-using Syntax.Tokenization;
-using Syntax.Typing;
-using Binder = Syntax.Typing.Binder;
-
-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 diagnostics = new List();
-var syntaxTrees = new List();
-
-foreach (var file in args)
-{
- if (!File.Exists(file))
- {
- Console.Error.WriteLine($"File '{file}' does not exist");
- return 1;
- }
-}
-
-foreach (var file in args)
-{
- var content = File.ReadAllText(file);
- var sourceText = new SourceText(file, content);
-
- var tokenizeResult = Tokenizer.Tokenize(sourceText, out var tokenizerDiagnostics);
- diagnostics.AddRange(tokenizerDiagnostics);
-
- var syntaxTree = Parser.ParseFile(tokenizeResult, file, out var parseDiagnostics);
- diagnostics.AddRange(parseDiagnostics);
-
- if (syntaxTree != null)
- {
- syntaxTrees.Add(syntaxTree);
- }
- else
- {
- throw new Exception();
- }
-}
-
-var definitionTable = new DefinitionTable(syntaxTrees);
-
-var boundSyntaxTrees = new List();
-
-foreach (var syntaxTree in syntaxTrees)
-{
- boundSyntaxTrees.Add(Binder.Bind(syntaxTree, definitionTable));
-}
-
-var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees);
-
-foreach (var diagnostic in diagnostics)
-{
- Console.Error.WriteLine(diagnostic.FormatANSI());
-}
-
-if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error))
-{
- return 1;
-}
-
-var objectFiles = new List();
-
-foreach (var boundSyntaxTree in boundSyntaxTrees)
-{
- var relativeFilePath = Path.GetRelativePath(Environment.CurrentDirectory, boundSyntaxTree.FilePath);
- 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.Emit(boundSyntaxTree, boundDefinitionTable);
- var ssaPath = Path.ChangeExtension(outputPath, "ssa");
- File.WriteAllText(ssaPath, ssa);
-
- var asm = await QBE.Invoke(ssa);
- if (asm == null)
- {
- return 1;
- }
-
- 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;
\ No newline at end of file
diff --git a/src/CLI/QBE.cs b/src/CLI/QBE.cs
deleted file mode 100644
index c592e12..0000000
--- a/src/CLI/QBE.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Diagnostics;
-
-namespace CLI;
-
-public static class QBE
-{
- public static async Task Invoke(string ssa)
- {
- using var qbeProcess = new Process();
- qbeProcess.StartInfo = new ProcessStartInfo
- {
- FileName = "qbe",
- UseShellExecute = false,
- RedirectStandardInput = true,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
-
- qbeProcess.Start();
-
- await qbeProcess.StandardInput.WriteAsync(ssa);
- qbeProcess.StandardInput.Close();
-
- await qbeProcess.WaitForExitAsync();
-
- var qbeErrors = await qbeProcess.StandardError.ReadToEndAsync();
- if (!string.IsNullOrWhiteSpace(qbeErrors))
- {
- await Console.Error.WriteLineAsync("qbe error:\n" + qbeErrors);
- }
-
- var asm = await qbeProcess.StandardOutput.ReadToEndAsync();
-
- return qbeProcess.ExitCode == 0 ? asm : null;
- }
-}
diff --git a/src/CLI/Runtime/entry.s b/src/CLI/Runtime/entry.s
deleted file mode 100644
index 5ea2a6a..0000000
--- a/src/CLI/Runtime/entry.s
+++ /dev/null
@@ -1,12 +0,0 @@
-.intel_syntax noprefix
-
-.equ SYS_EXIT, 60
-
-.text
-.globl _start
-_start:
- mov rdi, rsp
- call main
- mov rdi, rax
- mov rax, SYS_EXIT
- syscall
diff --git a/src/CLI/Runtime/nub_cstring.s b/src/CLI/Runtime/nub_cstring.s
deleted file mode 100644
index 8acef4f..0000000
--- a/src/CLI/Runtime/nub_cstring.s
+++ /dev/null
@@ -1,17 +0,0 @@
-.intel_syntax noprefix
-
-.text
-.globl nub_cstring_length
-# func nub_cstring_length(string: cstring): u64
-nub_cstring_length:
- xor rax, rax
-
-count_loop:
- cmp byte ptr [rdi + rax], 0
- je done
-
- inc rax
- jmp count_loop
-
-done:
- ret
diff --git a/src/CLI/Runtime/nub_mem.s b/src/CLI/Runtime/nub_mem.s
deleted file mode 100644
index 27cf71c..0000000
--- a/src/CLI/Runtime/nub_mem.s
+++ /dev/null
@@ -1,27 +0,0 @@
-.intel_syntax noprefix
-
-.text
-.globl nub_memcpy
-# func nub_memcpy(destination: ^u8, source: ^u8, count: u64): ^u8
-nub_memcpy:
- mov rcx, rdx
- rep movsb
- ret
-
-.text
-.globl nub_memset
-# func nub_memset(destination: ^u8, value: i8, count: u64): ^u8
-nub_memset:
- push rdi
- mov rcx, rdx
- mov al, sil
- test rcx, rcx
- jz memset_done
-memset_loop:
- mov BYTE PTR [rdi], al
- inc rdi
- dec rcx
- jnz memset_loop
-memset_done:
- pop rax
- ret
diff --git a/src/CLI/Runtime/nub_panic.s b/src/CLI/Runtime/nub_panic.s
deleted file mode 100644
index 51332e2..0000000
--- a/src/CLI/Runtime/nub_panic.s
+++ /dev/null
@@ -1,47 +0,0 @@
-.intel_syntax noprefix
-
-.equ NUB_PANIC_ERROR_CODE, 101
-
-.equ SYS_WRITE, 1
-.equ SYS_EXIT, 60
-
-.equ FD_STDIN, 0
-.equ FD_STDOUT, 1
-.equ FD_STDERR, 2
-
-.data
-.align 8
-array_oob_msg:
- .ascii "Index is out of bounds of array\n"
-
-.data
-.align 8
-oom_msg:
- .ascii "Out of memory\n"
-
-.text
-.globl nub_panic
-nub_panic:
- mov rax, SYS_EXIT
- mov rdi, NUB_PANIC_ERROR_CODE
- syscall
-
-.text
-.globl nub_panic_array_oob
-nub_panic_array_oob:
- mov rax, SYS_WRITE
- mov rdi, FD_STDERR
- lea rsi, [rip + array_oob_msg]
- mov rdx, 32
- syscall
- call nub_panic
-
-.text
-.globl nub_panic_oom
-nub_panic_oom:
- mov rax, SYS_WRITE
- mov rdi, FD_STDERR
- lea rsi, [rip + oom_msg]
- mov rdx, 14
- syscall
- call nub_panic
diff --git a/src/CLI/Runtime/nub_string.s b/src/CLI/Runtime/nub_string.s
deleted file mode 100644
index dccbd5d..0000000
--- a/src/CLI/Runtime/nub_string.s
+++ /dev/null
@@ -1,32 +0,0 @@
-.intel_syntax noprefix
-
-.text
-.globl nub_string_length
-# func nub_string_length(string: string): u64
-nub_string_length:
- mov rsi, [rdi] # Length of string in bytes
-
- add rdi, 8 # Start of bytes
- xor rax, rax # Character count
- xor rdx, rdx # Current byte position
-
- test rsi, rsi
- jz _done
-
-_count_loop:
- cmp rdx, rsi
- jge _done
-
- mov dl, [rdi + rdx]
- and dl, 0b11000000
- cmp dl, 0b10000000
- je _skip_byte
-
- inc rax
-
-_skip_byte:
- inc rdx
- jmp _count_loop
-
-_done:
- ret
diff --git a/src/Common/Common.csproj b/src/Common/Common.csproj
deleted file mode 100644
index b682a68..0000000
--- a/src/Common/Common.csproj
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- net9.0
- enable
- enable
- true
-
-
-
diff --git a/src/Common/Optional.cs b/src/Common/Optional.cs
deleted file mode 100644
index 5cd9f29..0000000
--- a/src/Common/Optional.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-
-namespace Common;
-
-public readonly struct Optional
-{
- public static Optional Empty() => new();
-
- ///
- /// Alias for creating an Optional<TValue> which allows for implicit types
- ///
- ///
- ///
- ///
- public static Optional OfNullable(TValue? value)
- {
- return value ?? Optional.Empty();
- }
-}
-
-public readonly struct Optional
-{
- public static Optional Empty() => new();
-
- public static Optional OfNullable(TValue? value)
- {
- return value ?? Empty();
- }
-
- public Optional()
- {
- Value = default;
- HasValue = false;
- }
-
- public Optional(TValue value)
- {
- Value = value;
- HasValue = true;
- }
-
- public TValue? Value { get; }
-
- [MemberNotNullWhen(true, nameof(Value))]
- public bool HasValue { get; }
-
-
- [MemberNotNullWhen(true, nameof(Value))]
- public bool TryGetValue([NotNullWhen(true)] out TValue? value)
- {
- if (HasValue)
- {
- value = Value;
- return true;
- }
-
- value = default;
- return false;
- }
-
- public TValue GetValue()
- {
- return Value ?? throw new InvalidOperationException("Value is not set");
- }
-
- public static implicit operator Optional(TValue value) => new(value);
-
- public TValue Or(TValue other)
- {
- if (HasValue)
- {
- return Value;
- }
-
- return other;
- }
-}
\ No newline at end of file
diff --git a/src/Common/Variant.cs b/src/Common/Variant.cs
deleted file mode 100644
index 541b111..0000000
--- a/src/Common/Variant.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-namespace Common;
-
-public readonly struct Variant where T1 : notnull where T2 : notnull
-{
- public Variant()
- {
- throw new InvalidOperationException("Variant must be initialized with a value");
- }
-
- public Variant(T1 value)
- {
- _value = value;
- }
-
- public Variant(T2 value)
- {
- _value = value;
- }
-
- private readonly object _value;
-
- public void Match(Action on1, Action on2)
- {
- switch (_value)
- {
- case T1 v1:
- on1(v1);
- break;
- case T2 v2:
- on2(v2);
- break;
- default:
- throw new InvalidCastException();
- }
- }
-
- public T Match(Func on1, Func on2)
- {
- return _value switch
- {
- T1 v1 => on1(v1),
- T2 v2 => on2(v2),
- _ => throw new InvalidCastException()
- };
- }
-
- public static implicit operator Variant(T1 value) => new(value);
- public static implicit operator Variant(T2 value) => new(value);
-}
\ No newline at end of file
diff --git a/src/Compiler.sln b/src/Compiler.sln
deleted file mode 100644
index 702f726..0000000
--- a/src/Compiler.sln
+++ /dev/null
@@ -1,34 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syntax", "Syntax\Syntax.csproj", "{5047E21F-590D-4CB3-AFF3-064316485009}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLI", "CLI\CLI.csproj", "{A22F17ED-FA17-45AB-92BA-CD02C28B3524}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generation", "Generation\Generation.csproj", "{F903F1B9-69A6-4522-B483-81A4B072C8B1}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{91ECE034-32D4-48E6-A905-5F95DB95A3D4}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {5047E21F-590D-4CB3-AFF3-064316485009}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5047E21F-590D-4CB3-AFF3-064316485009}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5047E21F-590D-4CB3-AFF3-064316485009}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5047E21F-590D-4CB3-AFF3-064316485009}.Release|Any CPU.Build.0 = Release|Any CPU
- {A22F17ED-FA17-45AB-92BA-CD02C28B3524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A22F17ED-FA17-45AB-92BA-CD02C28B3524}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A22F17ED-FA17-45AB-92BA-CD02C28B3524}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A22F17ED-FA17-45AB-92BA-CD02C28B3524}.Release|Any CPU.Build.0 = Release|Any CPU
- {F903F1B9-69A6-4522-B483-81A4B072C8B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F903F1B9-69A6-4522-B483-81A4B072C8B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F903F1B9-69A6-4522-B483-81A4B072C8B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F903F1B9-69A6-4522-B483-81A4B072C8B1}.Release|Any CPU.Build.0 = Release|Any CPU
- {91ECE034-32D4-48E6-A905-5F95DB95A3D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {91ECE034-32D4-48E6-A905-5F95DB95A3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {91ECE034-32D4-48E6-A905-5F95DB95A3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {91ECE034-32D4-48E6-A905-5F95DB95A3D4}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/src/Generation/Generation.csproj b/src/Generation/Generation.csproj
deleted file mode 100644
index fbe4e73..0000000
--- a/src/Generation/Generation.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- net9.0
- enable
- enable
- true
-
-
-
-
-
-
-
-
diff --git a/src/Generation/QBE/QBEGenerator.cs b/src/Generation/QBE/QBEGenerator.cs
deleted file mode 100644
index d8850c6..0000000
--- a/src/Generation/QBE/QBEGenerator.cs
+++ /dev/null
@@ -1,1433 +0,0 @@
-using System.Diagnostics;
-using System.Globalization;
-using System.Text;
-using Syntax;
-using Syntax.Parsing.Node;
-using Syntax.Tokenization;
-using Syntax.Typing;
-using Syntax.Typing.BoundNode;
-
-namespace Generation.QBE;
-
-public static class QBEGenerator
-{
- private static BoundSyntaxTree _syntaxTree = null!;
- private static BoundDefinitionTable _definitionTable = null!;
-
- private static StringBuilder _builder = new();
- private static List _cStringLiterals = [];
- private static List _stringLiterals = [];
- private static Stack _breakLabels = [];
- private static Stack _continueLabels = [];
- private static Queue<(BoundAnonymousFuncNode Func, string Name)> _anonymousFunctions = [];
- private static Stack _variables = [];
- private static Stack _variableScopes = [];
- private static int _variableIndex;
- private static int _labelIndex;
- private static int _anonymousFuncIndex;
- private static int _cStringLiteralIndex;
- private static int _stringLiteralIndex;
- private static bool _codeIsReachable = true;
-
- public static string Emit(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable)
- {
- _syntaxTree = syntaxTree;
- _definitionTable = definitionTable;
-
- _builder = new StringBuilder();
- _cStringLiterals = [];
- _stringLiterals = [];
- _breakLabels = [];
- _continueLabels = [];
- _anonymousFunctions = [];
- _variables = [];
- _variableScopes = [];
- _variableIndex = 0;
- _labelIndex = 0;
- _anonymousFuncIndex = 0;
- _cStringLiteralIndex = 0;
- _stringLiteralIndex = 0;
- _codeIsReachable = true;
-
- foreach (var structDef in _definitionTable.GetStructs())
- {
- EmitStructDefinition(structDef);
- _builder.AppendLine();
- }
-
- foreach (var funcDef in _syntaxTree.Definitions.OfType())
- {
- EmitFuncDefinition(FuncName(funcDef), funcDef.Parameters, funcDef.ReturnType, funcDef.Body, funcDef.Exported);
- _builder.AppendLine();
- }
-
- while (_anonymousFunctions.TryDequeue(out var anon))
- {
- EmitFuncDefinition(anon.Name, anon.Func.Parameters, anon.Func.ReturnType, anon.Func.Body, false);
- _builder.AppendLine();
- }
-
- foreach (var cStringLiteral in _cStringLiterals)
- {
- _builder.AppendLine($"data {cStringLiteral.Name} = {{ b \"{cStringLiteral.Value}\", b 0 }}");
- }
-
- foreach (var stringLiteral in _stringLiterals)
- {
- var bytes = Encoding.UTF8.GetBytes(stringLiteral.Value).Select(b => $"b {b}");
- _builder.AppendLine($"data {stringLiteral.Name} = {{ l {stringLiteral.Value.Length}, {string.Join(", ", bytes)} }}");
- }
-
- return _builder.ToString();
- }
-
- private static string VarName()
- {
- return $"%v{++_variableIndex}";
- }
-
- private static string LabelName()
- {
- return $"@l{++_labelIndex}";
- }
-
- private static string CStringName()
- {
- return $"$cstring{++_cStringLiteralIndex}";
- }
-
- private static string StringName()
- {
- return $"$string{++_stringLiteralIndex}";
- }
-
- private static string FuncName(BoundFuncDefinition funcDef)
- {
- return funcDef switch
- {
- BoundExternFuncDefinitionNode externFuncDefinition => $"${externFuncDefinition.CallName}",
- BoundLocalFuncDefinitionNode localFuncDefinition => localFuncDefinition.Exported
- ? $"${localFuncDefinition.Name}"
- : $"${localFuncDefinition.Namespace}_{localFuncDefinition.Name}",
- _ => throw new ArgumentOutOfRangeException(nameof(funcDef))
- };
- }
-
- private static string StructName(BoundStructDefinitionNode structDef)
- {
- return $":{structDef.Namespace}_{structDef.Name}";
- }
-
- private static string QBEStore(NubType type)
- {
- return type switch
- {
- NubArrayType => "storel",
- NubPointerType => "storel",
- NubPrimitiveType primitiveType => primitiveType.Kind switch
- {
- PrimitiveTypeKind.I64 => "storel",
- PrimitiveTypeKind.I32 => "storew",
- PrimitiveTypeKind.I16 => "storeh",
- PrimitiveTypeKind.I8 => "storeb",
- PrimitiveTypeKind.U64 => "storel",
- PrimitiveTypeKind.U32 => "storew",
- PrimitiveTypeKind.U16 => "storeh",
- PrimitiveTypeKind.U8 => "storeb",
- PrimitiveTypeKind.F64 => "stored",
- PrimitiveTypeKind.F32 => "stores",
- PrimitiveTypeKind.Bool => "storew",
- _ => throw new ArgumentOutOfRangeException()
- },
- NubStructType => "storel",
- NubFixedArrayType => "storel",
- NubFuncType => "storel",
- NubCStringType => "storel",
- NubStringType => "storel",
- _ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions")
- };
- }
-
- private static string QBELoad(NubType type)
- {
- return type switch
- {
- NubArrayType => "loadl",
- NubPointerType => "loadl",
- NubPrimitiveType primitiveType => primitiveType.Kind switch
- {
- PrimitiveTypeKind.I64 => "loadl",
- PrimitiveTypeKind.I32 => "loadw",
- PrimitiveTypeKind.I16 => "loadsh",
- PrimitiveTypeKind.I8 => "loadsb",
- PrimitiveTypeKind.U64 => "loadl",
- PrimitiveTypeKind.U32 => "loadw",
- PrimitiveTypeKind.U16 => "loaduh",
- PrimitiveTypeKind.U8 => "loadub",
- PrimitiveTypeKind.F64 => "loadd",
- PrimitiveTypeKind.F32 => "loads",
- PrimitiveTypeKind.Bool => "loadw",
- _ => throw new ArgumentOutOfRangeException()
- },
- NubStructType => "loadl",
- NubFixedArrayType => "loadl",
- NubFuncType => "loadl",
- NubCStringType => "loadl",
- NubStringType => "loadl",
- _ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions")
- };
- }
-
- private static string QBEAssign(NubType type)
- {
- return type switch
- {
- NubArrayType => "=l",
- NubPointerType => "=l",
- NubPrimitiveType primitiveType => primitiveType.Kind switch
- {
- PrimitiveTypeKind.I64 => "=l",
- PrimitiveTypeKind.I32 => "=w",
- PrimitiveTypeKind.I16 => "=w",
- PrimitiveTypeKind.I8 => "=w",
- PrimitiveTypeKind.U64 => "=l",
- PrimitiveTypeKind.U32 => "=w",
- PrimitiveTypeKind.U16 => "=w",
- PrimitiveTypeKind.U8 => "=w",
- PrimitiveTypeKind.F64 => "=d",
- PrimitiveTypeKind.F32 => "=s",
- PrimitiveTypeKind.Bool => "=w",
- _ => throw new ArgumentOutOfRangeException()
- },
- NubStructType => "=l",
- NubFixedArrayType => "=l",
- NubFuncType => "=l",
- NubCStringType => "=l",
- NubStringType => "=l",
- _ => throw new NotSupportedException($"'{type}' type cannot be used in variables")
- };
- }
-
- private static int AlignmentOf(NubType type)
- {
- switch (type)
- {
- case NubPrimitiveType primitiveType:
- {
- return primitiveType.Kind switch
- {
- PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 or PrimitiveTypeKind.F64 => 8,
- PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.F32 or PrimitiveTypeKind.Bool => 4,
- PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => 2,
- PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 => 1,
- _ => throw new ArgumentOutOfRangeException()
- };
- }
- case NubStructType nubStructType:
- {
- var definition = _definitionTable.LookupStruct(nubStructType.Namespace, nubStructType.Name).GetValue();
- return definition.Fields.Max(f => AlignmentOf(f.Type));
- }
- case NubPointerType:
- case NubArrayType:
- case NubCStringType:
- case NubStringType:
- case NubFuncType:
- {
- return 8;
- }
- case NubFixedArrayType nubFixedArrayType:
- {
- return AlignmentOf(nubFixedArrayType.ElementType);
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
- }
-
- private static int AlignTo(int offset, int alignment)
- {
- return (offset + alignment - 1) & ~(alignment - 1);
- }
-
- private static int SizeOf(NubType type)
- {
- switch (type)
- {
- case NubPrimitiveType primitiveType:
- {
- return primitiveType.Kind switch
- {
- PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 or PrimitiveTypeKind.F64 => 8,
- PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.F32 or PrimitiveTypeKind.Bool => 4,
- PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => 2,
- PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 => 1,
- _ => throw new ArgumentOutOfRangeException()
- };
- }
- case NubStructType nubStructType:
- {
- var definition = _definitionTable.LookupStruct(nubStructType.Namespace, nubStructType.Name).GetValue();
-
- var size = 0;
- var maxAlignment = 1;
-
- foreach (var field in definition.Fields)
- {
- var fieldAlignment = AlignmentOf(field.Type);
- maxAlignment = Math.Max(maxAlignment, fieldAlignment);
-
- size = AlignTo(size, fieldAlignment);
- size += SizeOf(field.Type);
- }
-
- size = AlignTo(size, maxAlignment);
-
- return size;
- }
- case NubPointerType:
- case NubArrayType:
- case NubCStringType:
- case NubStringType:
- case NubFuncType:
- {
- return 8;
- }
- case NubFixedArrayType nubFixedArrayType:
- {
- return SizeOf(nubFixedArrayType.ElementType) * nubFixedArrayType.Capacity + 8;
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
- }
-
- private static int OffsetOf(BoundStructDefinitionNode structDefinition, string member)
- {
- var offset = 0;
-
- foreach (var field in structDefinition.Fields)
- {
- if (field.Name == member)
- {
- return offset;
- }
-
- var fieldAlignment = AlignmentOf(field.Type);
-
- offset = AlignTo(offset, fieldAlignment);
- offset += SizeOf(field.Type);
- }
-
- throw new UnreachableException($"Member '{member}' not found in struct");
- }
-
- private static bool IsPointerType(NubType type)
- {
- if (type.IsVoid)
- {
- throw new InvalidOperationException($"{nameof(IsPointerType)} should not be called on void types");
- }
-
- return type is NubStructType or NubFixedArrayType;
- }
-
- private static void EmitFuncDefinition(string name, List parameters, NubType returnType, BoundBlockNode body, bool exported)
- {
- _variables.Clear();
- _variableScopes.Clear();
-
- if (exported)
- {
- _builder.Append("export ");
- }
-
- _builder.Append("function ");
- if (returnType is not NubVoidType)
- {
- _builder.Append(returnType switch
- {
- NubArrayType => "l",
- NubPointerType => "l",
- NubPrimitiveType primitiveType => primitiveType.Kind switch
- {
- PrimitiveTypeKind.I64 => "l",
- PrimitiveTypeKind.I32 => "w",
- PrimitiveTypeKind.I16 => "sh",
- PrimitiveTypeKind.I8 => "sb",
- PrimitiveTypeKind.U64 => "l",
- PrimitiveTypeKind.U32 => "w",
- PrimitiveTypeKind.U16 => "uh",
- PrimitiveTypeKind.U8 => "ub",
- PrimitiveTypeKind.F64 => "d",
- PrimitiveTypeKind.F32 => "s",
- PrimitiveTypeKind.Bool => "w",
- _ => throw new ArgumentOutOfRangeException()
- },
- NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
- NubFixedArrayType => "l",
- NubFuncType => "l",
- NubCStringType => "l",
- NubStringType => "l",
- _ => throw new NotSupportedException($"'{returnType}' type cannot be used as a function return type")
- });
- _builder.Append(' ');
- }
-
- _builder.Append(name);
-
- var parameterStrings = parameters.Select(parameter =>
- {
- var qbeType = parameter.Type switch
- {
- NubArrayType => "l",
- NubPointerType => "l",
- NubPrimitiveType primitiveType => primitiveType.Kind switch
- {
- PrimitiveTypeKind.I64 => "l",
- PrimitiveTypeKind.I32 => "w",
- PrimitiveTypeKind.I16 => "sh",
- PrimitiveTypeKind.I8 => "sb",
- PrimitiveTypeKind.U64 => "l",
- PrimitiveTypeKind.U32 => "w",
- PrimitiveTypeKind.U16 => "uh",
- PrimitiveTypeKind.U8 => "ub",
- PrimitiveTypeKind.F64 => "d",
- PrimitiveTypeKind.F32 => "s",
- PrimitiveTypeKind.Bool => "w",
- _ => throw new ArgumentOutOfRangeException()
- },
- NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
- NubFixedArrayType => "l",
- NubFuncType => "l",
- NubCStringType => "l",
- NubStringType => "l",
- _ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used as a function parameter type")
- };
-
- return $"{qbeType} %{parameter.Name}";
- });
-
- _builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{");
- _builder.AppendLine("@start");
-
- List parameterVars = [];
-
- foreach (var parameter in parameters)
- {
- var parameterName = "%" + parameter.Name;
-
- if (parameter.Type is NubPrimitiveType primitiveType)
- {
- switch (primitiveType.Kind)
- {
- case PrimitiveTypeKind.I16:
- parameterName = VarName();
- _builder.AppendLine($" {parameterName} =w extsh %{parameter.Name}");
- break;
- case PrimitiveTypeKind.I8:
- parameterName = VarName();
- _builder.AppendLine($" {parameterName} =w extsb %{parameter.Name}");
- break;
- case PrimitiveTypeKind.U16:
- parameterName = VarName();
- _builder.AppendLine($" {parameterName} =w extuh %{parameter.Name}");
- break;
- case PrimitiveTypeKind.U8:
- parameterName = VarName();
- _builder.AppendLine($" {parameterName} =w extub %{parameter.Name}");
- break;
- }
- }
-
- parameterVars.Add(new Variable(parameter.Name, new Val(parameterName, parameter.Type, ValKind.Immediate)));
- }
-
- EmitBlock(body, parameterVars);
-
- if (body.Statements.LastOrDefault() is not BoundReturnNode)
- {
- if (returnType is NubVoidType)
- {
- _builder.AppendLine(" ret");
- }
- }
-
- _builder.AppendLine("}");
- }
-
- private static void EmitStructDefinition(BoundStructDefinitionNode structDefinition)
- {
- _builder.Append($"type {StructName(structDefinition)} = {{ ");
- foreach (var structDefinitionField in structDefinition.Fields)
- {
- var qbeType = structDefinitionField.Type switch
- {
- NubArrayType => "l",
- NubPointerType => "l",
- NubPrimitiveType primitiveType => primitiveType.Kind switch
- {
- PrimitiveTypeKind.I64 => "l",
- PrimitiveTypeKind.I32 => "w",
- PrimitiveTypeKind.I16 => "h",
- PrimitiveTypeKind.I8 => "b",
- PrimitiveTypeKind.U64 => "l",
- PrimitiveTypeKind.U32 => "w",
- PrimitiveTypeKind.U16 => "h",
- PrimitiveTypeKind.U8 => "b",
- PrimitiveTypeKind.F64 => "d",
- PrimitiveTypeKind.F32 => "s",
- PrimitiveTypeKind.Bool => "w",
- _ => throw new ArgumentOutOfRangeException()
- },
- NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
- NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
- NubFuncType => "l",
- NubCStringType => "l",
- NubStringType => "l",
- _ => throw new NotSupportedException($"'{structDefinitionField.Type}' type cannot be used in structs")
- };
- _builder.Append(qbeType + ", ");
- }
-
- _builder.AppendLine("}");
- }
-
- private static void EmitStatement(BoundStatementNode statement)
- {
- switch (statement)
- {
- case BoundArrayIndexAssignmentNode arrayIndexAssignment:
- EmitArrayIndexAssignment(arrayIndexAssignment);
- break;
- case BoundBreakNode:
- EmitBreak();
- break;
- case BoundContinueNode:
- EmitContinue();
- break;
- case BoundDereferenceAssignmentNode dereferenceAssignment:
- EmitDereferenceAssignment(dereferenceAssignment);
- break;
- case BoundIfNode ifStatement:
- EmitIf(ifStatement);
- break;
- case BoundMemberAssignmentNode memberAssignment:
- EmitMemberAssignment(memberAssignment);
- break;
- case BoundReturnNode @return:
- EmitReturn(@return);
- break;
- case BoundStatementExpressionNode statementExpression:
- EmitExpression(statementExpression.Expression);
- break;
- case BoundVariableDeclarationNode variableDeclaration:
- EmitVariableDeclaration(variableDeclaration);
- break;
- case BoundVariableAssignmentNode variableAssignment:
- EmitVariableAssignment(variableAssignment);
- break;
- case BoundWhileNode whileStatement:
- EmitWhile(whileStatement);
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(statement));
- }
- }
-
- private static void EmitArrayIndexAssignment(BoundArrayIndexAssignmentNode arrayIndexAssignment)
- {
- var array = EmitUnwrap(EmitExpression(arrayIndexAssignment.ArrayIndexAccess.Array));
- var index = EmitUnwrap(EmitExpression(arrayIndexAssignment.ArrayIndexAccess.Index));
- EmitArrayBoundsCheck(array, index);
- var value = EmitUnwrap(EmitExpression(arrayIndexAssignment.Value));
-
- switch (arrayIndexAssignment.ArrayIndexAccess.Array.Type)
- {
- case NubArrayType arrayType:
- {
- var pointer = VarName();
- _builder.AppendLine($" {pointer} =l mul {index}, {SizeOf(arrayType.ElementType)}");
- _builder.AppendLine($" {pointer} =l add {pointer}, 8");
- _builder.AppendLine($" {pointer} =l add {array}, {pointer}");
-
- EmitCopy(arrayType.ElementType, value, pointer);
- break;
- }
- case NubFixedArrayType fixedArrayType:
- {
- var pointer = VarName();
- _builder.AppendLine($" {pointer} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
- _builder.AppendLine($" {pointer} =l add {pointer}, 8");
- _builder.AppendLine($" {pointer} =l add {array}, {pointer}");
-
- EmitCopy(fixedArrayType.ElementType, value, pointer);
- break;
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
- }
-
- private static void EmitBlock(BoundBlockNode block, List? variables = null)
- {
- _variableScopes.Push(_variables.Count);
- if (variables != null)
- {
- foreach (var variable in variables)
- {
- _variables.Push(variable);
- }
- }
-
- foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
- {
- EmitStatement(statement);
- }
-
- var count = _variableScopes.Pop();
- while (_variableScopes.Count > count)
- {
- _variableScopes.Pop();
- }
-
- _codeIsReachable = true;
- }
-
- private static void EmitBreak()
- {
- _builder.AppendLine($" jmp {_breakLabels.Peek()}");
- _codeIsReachable = false;
- }
-
- private static void EmitContinue()
- {
- _builder.AppendLine($" jmp {_continueLabels.Peek()}");
- _codeIsReachable = false;
- }
-
- private static void EmitDereferenceAssignment(BoundDereferenceAssignmentNode dereferenceAssignment)
- {
- var pointer = EmitUnwrap(EmitExpression(dereferenceAssignment.Dereference.Expression));
- var value = EmitUnwrap(EmitExpression(dereferenceAssignment.Value));
- EmitCopy(dereferenceAssignment.Value.Type, value, pointer);
- }
-
- private static void EmitIf(BoundIfNode ifStatement)
- {
- var trueLabel = LabelName();
- var falseLabel = LabelName();
- var endLabel = LabelName();
-
- var result = EmitUnwrap(EmitExpression(ifStatement.Condition));
- _builder.AppendLine($" jnz {result}, {trueLabel}, {falseLabel}");
- _builder.AppendLine(trueLabel);
- EmitBlock(ifStatement.Body);
- _builder.AppendLine($" jmp {endLabel}");
- _builder.AppendLine(falseLabel);
- if (ifStatement.Else.HasValue)
- {
- ifStatement.Else.Value.Match
- (
- elseIfNode => EmitIf(elseIfNode),
- elseNode => EmitBlock(elseNode)
- );
- }
-
- _builder.AppendLine(endLabel);
- }
-
- private static void EmitMemberAssignment(BoundMemberAssignmentNode memberAssignment)
- {
- var structType = memberAssignment.MemberAccess.Expression.Type as NubStructType;
- Debug.Assert(structType != null);
-
- var structDefinition = _definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue();
- var offset = OffsetOf(structDefinition, memberAssignment.MemberAccess.Member);
-
- var item = EmitUnwrap(EmitExpression(memberAssignment.MemberAccess.Expression));
- var pointer = VarName();
-
- _builder.AppendLine($" {pointer} =l add {item}, {offset}");
-
- var value = EmitUnwrap(EmitExpression(memberAssignment.Value));
-
- EmitCopy(memberAssignment.Value.Type, value, pointer);
- }
-
- private static void EmitReturn(BoundReturnNode @return)
- {
- if (@return.Value.HasValue)
- {
- var result = EmitUnwrap(EmitExpression(@return.Value.Value));
- _builder.AppendLine($" ret {result}");
- }
- else
- {
- _builder.AppendLine(" ret");
- }
- }
-
- private static void EmitVariableDeclaration(BoundVariableDeclarationNode variableDeclaration)
- {
- var tmp = VarName();
- _builder.AppendLine($" {tmp} =l alloc8 {SizeOf(variableDeclaration.Type)}");
- _variables.Push(new Variable(variableDeclaration.Name, new Val(tmp, variableDeclaration.Type, ValKind.Pointer)));
- }
-
- private static void EmitVariableAssignment(BoundVariableAssignmentNode variableAssignment)
- {
- var value = EmitUnwrap(EmitExpression(variableAssignment.Value));
- var variable = _variables.Single(x => x.Name == variableAssignment.Identifier.Name);
- EmitCopy(variableAssignment.Value.Type, value, variable.Val.Name);
- }
-
- private static void EmitWhile(BoundWhileNode whileStatement)
- {
- var conditionLabel = LabelName();
- var iterationLabel = LabelName();
- var endLabel = LabelName();
-
- _breakLabels.Push(endLabel);
- _continueLabels.Push(conditionLabel);
-
- _builder.AppendLine($" jmp {conditionLabel}");
- _builder.AppendLine(iterationLabel);
- EmitBlock(whileStatement.Body);
- _builder.AppendLine(conditionLabel);
- var result = EmitUnwrap(EmitExpression(whileStatement.Condition));
- _builder.AppendLine($" jnz {result}, {iterationLabel}, {endLabel}");
- _builder.AppendLine(endLabel);
-
- _continueLabels.Pop();
- _breakLabels.Pop();
- }
-
- private static Val EmitExpression(BoundExpressionNode expression)
- {
- return expression switch
- {
- BoundAddressOfNode addressOf => EmitAddressOf(addressOf),
- BoundAnonymousFuncNode anonymousFunc => EmitAnonymousFunc(anonymousFunc),
- BoundArrayIndexAccessNode arrayIndex => EmitArrayIndexAccess(arrayIndex),
- BoundArrayInitializerNode arrayInitializer => EmitArrayInitializer(arrayInitializer),
- BoundBinaryExpressionNode binaryExpression => EmitBinaryExpression(binaryExpression),
- BoundDereferenceNode dereference => EmitDereference(dereference),
- BoundFixedArrayInitializerNode fixedArrayInitializer => EmitFixedArrayInitializer(fixedArrayInitializer),
- BoundFuncCallNode funcCallExpression => EmitFuncCall(funcCallExpression),
- BoundIdentifierNode identifier => EmitIdentifier(identifier),
- BoundLiteralNode literal => EmitLiteral(literal),
- BoundStructInitializerNode structInitializer => EmitStructInitializer(structInitializer),
- BoundUnaryExpressionNode unaryExpression => EmitUnaryExpression(unaryExpression),
- BoundMemberAccessNode memberAccess => EmitMemberAccess(memberAccess),
- _ => throw new ArgumentOutOfRangeException(nameof(expression))
- };
- }
-
- private static Val EmitAnonymousFunc(BoundAnonymousFuncNode anonymousFunc)
- {
- var name = $"$anon_func{++_anonymousFuncIndex}";
- _anonymousFunctions.Enqueue((anonymousFunc, name));
- return new Val(name, anonymousFunc.Type, ValKind.Func);
- }
-
- private static string EmitArrayIndexPointer(BoundArrayIndexAccessNode arrayIndexAccess)
- {
- var array = EmitUnwrap(EmitExpression(arrayIndexAccess.Array));
- var index = EmitUnwrap(EmitExpression(arrayIndexAccess.Index));
- EmitArrayBoundsCheck(array, index);
-
- var elementType = arrayIndexAccess.Array.Type switch
- {
- NubArrayType arrayType => arrayType.ElementType,
- NubFixedArrayType fixedArrayType => fixedArrayType.ElementType,
- _ => throw new ArgumentOutOfRangeException()
- };
-
- var pointer = VarName();
- _builder.AppendLine($" {pointer} =l mul {index}, {SizeOf(elementType)}");
- _builder.AppendLine($" {pointer} =l add {pointer}, 8");
- _builder.AppendLine($" {pointer} =l add {array}, {pointer}");
- return pointer;
- }
-
- private static Val EmitArrayIndexAccess(BoundArrayIndexAccessNode arrayIndexAccess)
- {
- var pointer = EmitArrayIndexPointer(arrayIndexAccess);
- var outputName = VarName();
- _builder.AppendLine($" {outputName} {QBEAssign(arrayIndexAccess.Type)} {QBELoad(arrayIndexAccess.Type)} {pointer}");
- return new Val(outputName, arrayIndexAccess.Type, ValKind.Immediate);
- }
-
- private static void EmitArrayBoundsCheck(string array, string index)
- {
- var count = VarName();
- _builder.AppendLine($" {count} =l loadl {array}");
-
- var isNegative = VarName();
- _builder.AppendLine($" {isNegative} =w csltl {index}, 0");
-
- var isOob = VarName();
- _builder.AppendLine($" {isOob} =w csgel {index}, {count}");
-
- var anyOob = VarName();
- _builder.AppendLine($" {anyOob} =w or {isNegative}, {isOob}");
-
- var oobLabel = LabelName();
- var notOobLabel = LabelName();
- _builder.AppendLine($" jnz {anyOob}, {oobLabel}, {notOobLabel}");
-
- _builder.AppendLine(oobLabel);
- _builder.AppendLine($" call $nub_panic_array_oob()");
-
- _builder.AppendLine(notOobLabel);
- }
-
- private static Val EmitArrayInitializer(BoundArrayInitializerNode arrayInitializer)
- {
- var capacity = EmitUnwrap(EmitExpression(arrayInitializer.Capacity));
- var elementSize = SizeOf(arrayInitializer.ElementType);
-
- var capacityInBytes = VarName();
- _builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {elementSize}");
- var totalSize = VarName();
- _builder.AppendLine($" {totalSize} =l add {capacityInBytes}, 8");
-
- var arrayPointer = VarName();
- _builder.AppendLine($" {arrayPointer} =l alloc8 {totalSize}");
- _builder.AppendLine($" storel {capacity}, {arrayPointer}");
-
- var dataPointer = VarName();
- _builder.AppendLine($" {dataPointer} =l add {arrayPointer}, 8");
- _builder.AppendLine($" call $nub_memset(l {dataPointer}, w 0, l {capacityInBytes})");
-
- return new Val(arrayPointer, arrayInitializer.Type, ValKind.Immediate);
- }
-
- private static Val EmitDereference(BoundDereferenceNode dereference)
- {
- var result = EmitUnwrap(EmitExpression(dereference.Expression));
- var outputName = VarName();
- _builder.AppendLine($" {outputName} {QBEAssign(dereference.Type)} {QBELoad(dereference.Type)} {result}");
- return new Val(outputName, dereference.Type, ValKind.Immediate);
- }
-
- private static Val EmitAddressOf(BoundAddressOfNode addressOf)
- {
- switch (addressOf.Expression)
- {
- case BoundArrayIndexAccessNode arrayIndexAccess:
- {
- var pointer = EmitArrayIndexPointer(arrayIndexAccess);
- return new Val(pointer, addressOf.Type, ValKind.Immediate);
- }
- case BoundDereferenceNode dereference:
- {
- return EmitExpression(dereference.Expression);
- }
- case BoundIdentifierNode identifier:
- {
- if (identifier.Namespace.HasValue)
- {
- throw new NotSupportedException("There is nothing to address in another namespace");
- }
-
- return _variables.Single(x => x.Name == identifier.Name).Val;
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
- }
-
- private static Val EmitBinaryExpression(BoundBinaryExpressionNode binaryExpression)
- {
- var left = EmitUnwrap(EmitExpression(binaryExpression.Left));
- var right = EmitUnwrap(EmitExpression(binaryExpression.Right));
- var outputName = VarName();
- var output = new Val(outputName, binaryExpression.Type, ValKind.Immediate);
-
- switch (binaryExpression.Operator)
- {
- case BinaryExpressionOperator.Equal:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =w ceql {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w ceqw {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
- {
- _builder.AppendLine($" {outputName} =w ceqw {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.NotEqual:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =w cnel {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w cnew {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
- {
- _builder.AppendLine($" {outputName} =w cnew {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.GreaterThan:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =w csgtl {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w csgtw {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
- {
- _builder.AppendLine($" {outputName} =w csgtw {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.GreaterThanOrEqual:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =w csgel {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w csgew {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
- {
- _builder.AppendLine($" {outputName} =w csgew {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.LessThan:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =w csltl {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w csltw {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
- {
- _builder.AppendLine($" {outputName} =w csltw {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.LessThanOrEqual:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =w cslel {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w cslew {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
- {
- _builder.AppendLine($" {outputName} =w cslew {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.Plus:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =l add {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w add {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.Minus:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =l sub {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w sub {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.Multiply:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =l mul {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w mul {left}, {right}");
- return output;
- }
-
- break;
- }
- case BinaryExpressionOperator.Divide:
- {
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I64))
- {
- _builder.AppendLine($" {outputName} =l div {left}, {right}");
- return output;
- }
-
- if (binaryExpression.Left.Type.Equals(NubPrimitiveType.I32))
- {
- _builder.AppendLine($" {outputName} =w div {left}, {right}");
- return output;
- }
-
- break;
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
-
- throw new NotSupportedException($"Binary operator {binaryExpression.Operator} for types {binaryExpression.Left.Type} and {binaryExpression.Right.Type} not supported");
- }
-
- private static Val EmitIdentifier(BoundIdentifierNode identifier)
- {
- if (_definitionTable.LookupFunc(identifier.Namespace.Or(_syntaxTree.Namespace), identifier.Name).TryGetValue(out var func))
- {
- return new Val(FuncName(func), identifier.Type, ValKind.Func);
- }
-
- if (!identifier.Namespace.HasValue)
- {
- return _variables.Single(v => v.Name == identifier.Name).Val;
- }
-
- throw new UnreachableException();
- }
-
- private static Val EmitLiteral(BoundLiteralNode literal)
- {
- switch (literal.Kind)
- {
- case LiteralKind.Integer:
- {
- if (literal.Type.IsFloat32)
- {
- var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture);
- var bits = BitConverter.SingleToInt32Bits(value);
- return new Val(bits.ToString(), literal.Type, ValKind.Immediate);
- }
-
- if (literal.Type.IsFloat64)
- {
- var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
- var bits = BitConverter.DoubleToInt64Bits(value);
- return new Val(bits.ToString(), literal.Type, ValKind.Immediate);
- }
-
- if (literal.Type.IsInteger)
- {
- return new Val(literal.Literal, literal.Type, ValKind.Immediate);
- }
- break;
- }
- case LiteralKind.Float:
- {
- if (literal.Type.IsInteger)
- {
- return new Val(literal.Literal.Split(".").First(), literal.Type, ValKind.Immediate);
- }
-
- if (literal.Type.IsFloat32)
- {
- var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture);
- var bits = BitConverter.SingleToInt32Bits(value);
- return new Val(bits.ToString(), literal.Type, ValKind.Immediate);
- }
-
- if (literal.Type.IsFloat64)
- {
- var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
- var bits = BitConverter.DoubleToInt64Bits(value);
- return new Val(bits.ToString(), literal.Type, ValKind.Immediate);
- }
- break;
- }
- case LiteralKind.String:
- {
- if (literal.Type.IsString)
- {
- var stringLiteral = new StringLiteral(literal.Literal, StringName());
- _stringLiterals.Add(stringLiteral);
- return new Val(stringLiteral.Name, literal.Type, ValKind.Immediate);
- }
-
- if (literal.Type.IsCString)
- {
- var cStringLiteral = new CStringLiteral(literal.Literal, CStringName());
- _cStringLiterals.Add(cStringLiteral);
- return new Val(cStringLiteral.Name, literal.Type, ValKind.Immediate);
- }
- break;
- }
- case LiteralKind.Bool:
- {
- if (literal.Type.IsBool)
- {
- return new Val(bool.Parse(literal.Literal) ? "1" : "0", literal.Type, ValKind.Immediate);
- }
- break;
- }
- }
-
- throw new NotSupportedException($"Cannot create literal of kind '{literal.Kind}' for type {literal.Type}");
- }
-
- private static Val EmitStructInitializer(BoundStructInitializerNode structInitializer)
- {
- var structDefinition = _definitionTable.LookupStruct(structInitializer.StructType.Namespace, structInitializer.StructType.Name).GetValue();
-
- var output = VarName();
- var size = SizeOf(structInitializer.StructType);
- _builder.AppendLine($" {output} =l alloc8 {size}");
-
- foreach (var field in structDefinition.Fields)
- {
- var offset = OffsetOf(structDefinition, field.Name);
-
- if (structInitializer.Initializers.TryGetValue(field.Name, out var fieldValue))
- {
- var value = EmitUnwrap(EmitExpression(fieldValue));
- var pointer = VarName();
- _builder.AppendLine($" {pointer} =l add {output}, {offset}");
- EmitCopy(field.Type, value, pointer);
- }
- else if (field.Value.HasValue)
- {
- var value = EmitUnwrap(EmitExpression(field.Value.Value));
- var pointer = VarName();
- _builder.AppendLine($" {pointer} =l add {output}, {offset}");
- EmitCopy(field.Type, value, pointer);
- }
- else
- {
- Debug.Assert(false);
- }
- }
-
- return new Val(output, structInitializer.StructType, ValKind.Immediate);
- }
-
- private static Val EmitUnaryExpression(BoundUnaryExpressionNode unaryExpression)
- {
- var operand = EmitUnwrap(EmitExpression(unaryExpression.Operand));
- var outputName = VarName();
-
- switch (unaryExpression.Operator)
- {
- case UnaryExpressionOperator.Negate:
- {
- switch (unaryExpression.Operand.Type)
- {
- case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
- _builder.AppendLine($" {outputName} =l neg {operand}");
- return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
- case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }:
- _builder.AppendLine($" {outputName} =w neg {operand}");
- return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
- case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
- _builder.AppendLine($" {outputName} =d neg {operand}");
- return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
- case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
- _builder.AppendLine($" {outputName} =s neg {operand}");
- return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
- }
-
- break;
- }
- case UnaryExpressionOperator.Invert:
- {
- switch (unaryExpression.Operand.Type)
- {
- case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }:
- _builder.AppendLine($" {outputName} =w xor {operand}, 1");
- return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
- }
-
- break;
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
-
- throw new NotSupportedException($"Unary operator {unaryExpression.Operator} for type {unaryExpression.Operand.Type} not supported");
- }
-
- private static Val EmitMemberAccess(BoundMemberAccessNode memberAccess)
- {
- var item = EmitUnwrap(EmitExpression(memberAccess.Expression));
- var output = VarName();
-
- switch (memberAccess.Expression.Type)
- {
- case NubArrayType:
- {
- if (memberAccess.Member == "count")
- {
- _builder.AppendLine($" {output} =l loadl {item}");
- break;
- }
-
- throw new UnreachableException();
- }
- case NubStringType:
- {
- _builder.AppendLine($" {output} =l call $nub_string_length(l {item})");
- break;
- }
- case NubCStringType:
- {
- _builder.AppendLine($" {output} =l call $nub_cstring_length(l {item})");
- break;
- }
- case NubStructType structType:
- {
- var structDefinition = _definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue();
- var offset = OffsetOf(structDefinition, memberAccess.Member);
-
- var offsetName = VarName();
- _builder.AppendLine($" {offsetName} =l add {item}, {offset}");
- _builder.AppendLine($" {output} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {item}");
- break;
- }
- default:
- {
- throw new ArgumentOutOfRangeException();
- }
- }
-
- return new Val(output, memberAccess.Type, ValKind.Immediate);
- }
-
- private static Val EmitFixedArrayInitializer(BoundFixedArrayInitializerNode fixedArrayInitializer)
- {
- var totalSize = SizeOf(fixedArrayInitializer.Type);
- var outputName = VarName();
- _builder.AppendLine($" {outputName} =l alloc8 {totalSize}");
-
- _builder.AppendLine($" storel {fixedArrayInitializer.Capacity}, {outputName}");
-
- var dataPtr = VarName();
- _builder.AppendLine($" {dataPtr} =l add {outputName}, 8");
-
- var dataSize = totalSize - 8;
- _builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {dataSize})");
-
- return new Val(outputName, fixedArrayInitializer.Type, ValKind.Immediate);
- }
-
- private static Val EmitFuncCall(BoundFuncCallNode funcCall)
- {
- var funcType = (NubFuncType)funcCall.Expression.Type;
-
- var parameterStrings = new List();
-
- for (var i = 0; i < funcCall.Parameters.Count; i++)
- {
- var parameter = funcCall.Parameters[i];
- var result = EmitUnwrap(EmitExpression(parameter));
-
- var qbeType = parameter.Type switch
- {
- NubArrayType => "l",
- NubPointerType => "l",
- NubPrimitiveType pointerType => pointerType.Kind switch
- {
- PrimitiveTypeKind.I64 => "l",
- PrimitiveTypeKind.I32 => "w",
- PrimitiveTypeKind.I16 => "sh",
- PrimitiveTypeKind.I8 => "sb",
- PrimitiveTypeKind.U64 => "l",
- PrimitiveTypeKind.U32 => "w",
- PrimitiveTypeKind.U16 => "uh",
- PrimitiveTypeKind.U8 => "ub",
- PrimitiveTypeKind.F64 => "d",
- PrimitiveTypeKind.F32 => "s",
- PrimitiveTypeKind.Bool => "w",
- _ => throw new ArgumentOutOfRangeException()
- },
- NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
- NubFixedArrayType => "l",
- NubFuncType => "l",
- NubCStringType => "l",
- NubStringType => "l",
- _ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used in function calls")
- };
- parameterStrings.Add($"{qbeType} {result}");
- }
-
- var funcPointer = EmitUnwrap(EmitExpression(funcCall.Expression));
-
- if (funcType.ReturnType is not NubVoidType)
- {
- var outputName = VarName();
- _builder.AppendLine($" {outputName} {QBEAssign(funcCall.Type)} call {funcPointer}({string.Join(", ", parameterStrings)})");
- return new Val(outputName, funcCall.Type, ValKind.Immediate);
- }
- else
- {
- _builder.AppendLine($" call {funcPointer}({string.Join(", ", parameterStrings)})");
- return new Val(string.Empty, funcCall.Type, ValKind.Immediate);
- }
- }
-
- private static void EmitCopy(NubType type, string sourcePtr, string destinationPtr)
- {
- if (SizeOf(type) > 8)
- {
- _builder.AppendLine($" blit {sourcePtr}, {destinationPtr}, {SizeOf(type)}");
- }
- else
- {
- _builder.AppendLine($" {QBEStore(type)} {sourcePtr}, {destinationPtr}");
- }
- }
-
- private static string EmitUnwrap(Val val)
- {
- if (val.Type.IsVoid)
- {
- throw new InvalidOperationException("Cannot unwrap temporary of void type");
- }
-
- switch (val.Kind)
- {
- case ValKind.Func:
- case ValKind.Immediate:
- return val.Name;
- case ValKind.Pointer:
- if (IsPointerType(val.Type))
- {
- return val.Name;
- }
- else
- {
- var result = VarName();
- _builder.AppendLine($" {result} {QBEAssign(val.Type)} {QBELoad(val.Type)} {val.Name}");
- return result;
- }
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
-}
-
-internal class StringLiteral(string value, string name)
-{
- public string Value { get; } = value;
- public string Name { get; } = name;
-}
-
-internal class CStringLiteral(string value, string name)
-{
- public string Value { get; } = value;
- public string Name { get; } = name;
-}
-
-internal class Variable(string name, Val val)
-{
- public string Name { get; } = name;
- public Val Val { get; } = val;
-}
-
-internal class Val(string name, NubType type, ValKind kind)
-{
- public string Name { get; } = name;
- public NubType Type { get; } = type;
- public ValKind Kind { get; } = kind;
-
- public override string ToString()
- {
- throw new InvalidOperationException();
- }
-}
-
-internal enum ValKind
-{
- Func,
- Pointer,
- Immediate
-}
\ No newline at end of file
diff --git a/src/Syntax/DefinitionTable.cs b/src/Syntax/DefinitionTable.cs
deleted file mode 100644
index 4df8f31..0000000
--- a/src/Syntax/DefinitionTable.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using Common;
-using Syntax.Parsing;
-using Syntax.Parsing.Node;
-using Syntax.Typing;
-using Syntax.Typing.BoundNode;
-
-namespace Syntax;
-
-public class DefinitionTable
-{
- private readonly IEnumerable _syntaxTrees;
-
- public DefinitionTable(IEnumerable syntaxTrees)
- {
- _syntaxTrees = syntaxTrees;
- }
-
- public Optional LookupFunc(string @namespace, string name)
- {
- var definition = _syntaxTrees
- .Where(c => c.Namespace == @namespace)
- .SelectMany(c => c.Definitions)
- .OfType()
- .SingleOrDefault(f => f.Name == name);
-
- return Optional.OfNullable(definition);
- }
-
- public Optional LookupStruct(string @namespace, string name)
- {
- var definition = _syntaxTrees
- .Where(c => c.Namespace == @namespace)
- .SelectMany(c => c.Definitions)
- .OfType()
- .SingleOrDefault(f => f.Name == name);
-
- return Optional.OfNullable(definition);
- }
-
- public IEnumerable GetStructs()
- {
- return _syntaxTrees
- .SelectMany(c => c.Definitions)
- .OfType();
- }
-}
-
-public class BoundDefinitionTable
-{
- private readonly IEnumerable _syntaxTrees;
-
- public BoundDefinitionTable(IEnumerable syntaxTrees)
- {
- _syntaxTrees = syntaxTrees;
- }
-
- public Optional LookupFunc(string @namespace, string name)
- {
- var definition = _syntaxTrees
- .Where(c => c.Namespace == @namespace)
- .SelectMany(c => c.Definitions)
- .OfType()
- .SingleOrDefault(f => f.Name == name);
-
- return Optional.OfNullable(definition);
- }
-
- public Optional LookupStruct(string @namespace, string name)
- {
- var definition = _syntaxTrees
- .Where(c => c.Namespace == @namespace)
- .SelectMany(c => c.Definitions)
- .OfType()
- .SingleOrDefault(f => f.Name == name);
-
- return Optional.OfNullable(definition);
- }
-
- public IEnumerable GetStructs()
- {
- return _syntaxTrees
- .SelectMany(c => c.Definitions)
- .OfType();
- }
-}
\ No newline at end of file
diff --git a/src/Syntax/Diagnostics/ConsoleColors.cs b/src/Syntax/Diagnostics/ConsoleColors.cs
deleted file mode 100644
index 887a2fa..0000000
--- a/src/Syntax/Diagnostics/ConsoleColors.cs
+++ /dev/null
@@ -1,177 +0,0 @@
-using System.Text;
-using Syntax.Tokenization;
-
-namespace Syntax.Diagnostics;
-
-public static class ConsoleColors
-{
- public const string Reset = "\e[0m";
- public const string Bold = "\e[1m";
- public const string Faint = "\e[2m";
- public const string Italic = "\e[3m";
- public const string Underline = "\e[4m";
- public const string SlowBlink = "\e[5m";
- public const string RapidBlink = "\e[6m";
- public const string SwapBgAndFg = "\e[7m";
- public const string Conceal = "\e[8m";
- public const string CrossedOut = "\e[9m";
-
- public const string DefaultFont = "\e[10m";
- public const string AltFont1 = "\e[11m";
- public const string AltFont2 = "\e[12m";
- public const string AltFont3 = "\e[13m";
- public const string AltFont4 = "\e[14m";
- public const string AltFont5 = "\e[15m";
- public const string AltFont6 = "\e[16m";
- public const string AltFont7 = "\e[17m";
- public const string AltFont8 = "\e[18m";
- public const string AltFont9 = "\e[19m";
-
- public const string Black = "\e[30m";
- public const string Red = "\e[31m";
- public const string Green = "\e[32m";
- public const string Yellow = "\e[33m";
- public const string Blue = "\e[34m";
- public const string Magenta = "\e[35m";
- public const string Cyan = "\e[36m";
- public const string White = "\e[37m";
-
- public const string BrightBlack = "\e[90m";
- public const string BrightRed = "\e[91m";
- public const string BrightGreen = "\e[92m";
- public const string BrightYellow = "\e[93m";
- public const string BrightBlue = "\e[94m";
- public const string BrightMagenta = "\e[95m";
- public const string BrightCyan = "\e[96m";
- public const string BrightWhite = "\e[97m";
-
- private static bool IsColorSupported()
- {
- var term = Environment.GetEnvironmentVariable("TERM");
- var colorTerm = Environment.GetEnvironmentVariable("COLORTERM");
- return !string.IsNullOrEmpty(term) || !string.IsNullOrEmpty(colorTerm) || !Console.IsOutputRedirected;
- }
-
- public static string Colorize(string text, string color)
- {
- return IsColorSupported() ? $"{color}{text}{Reset}" : text;
- }
-
- private static string GetTokenColor(Token token)
- {
- switch (token)
- {
- case DocumentationToken:
- return Faint;
- case IdentifierToken:
- return White;
- case LiteralToken literal:
- return literal.Kind switch
- {
- LiteralKind.String => Green,
- LiteralKind.Integer or LiteralKind.Float => BrightBlue,
- LiteralKind.Bool => Blue,
- _ => White
- };
- case ModifierToken:
- return White;
- case SymbolToken symbol:
- switch (symbol.Symbol)
- {
- case Symbol.If:
- case Symbol.Else:
- case Symbol.While:
- case Symbol.Break:
- case Symbol.Continue:
- case Symbol.Return:
- return Magenta;
- case Symbol.Func:
- case Symbol.Struct:
- case Symbol.Namespace:
- case Symbol.Let:
- case Symbol.Alloc:
- return Blue;
- case Symbol.Assign:
- case Symbol.Bang:
- case Symbol.Equal:
- case Symbol.NotEqual:
- case Symbol.LessThan:
- case Symbol.LessThanOrEqual:
- case Symbol.GreaterThan:
- case Symbol.GreaterThanOrEqual:
- case Symbol.Plus:
- case Symbol.Minus:
- case Symbol.Star:
- case Symbol.ForwardSlash:
- case Symbol.Caret:
- case Symbol.Ampersand:
- return White;
- case Symbol.Semicolon:
- case Symbol.Colon:
- case Symbol.Comma:
- case Symbol.Period:
- case Symbol.DoubleColon:
- return Faint;
- case Symbol.OpenParen:
- case Symbol.CloseParen:
- case Symbol.OpenBrace:
- case Symbol.CloseBrace:
- case Symbol.OpenBracket:
- case Symbol.CloseBracket:
- return Yellow;
- default:
- return White;
- }
- default:
- return White;
- }
- }
-
- public static string ColorizeSource(string source)
- {
- var sourceText = new SourceText(string.Empty, source);
- var tokens = Tokenizer.Tokenize(sourceText, out _);
- var result = new StringBuilder();
- var lastCharIndex = 0;
-
- foreach (var token in tokens)
- {
- var tokenStartIndex = GetCharacterIndex(sourceText, token.Span.Start);
- var tokenEndIndex = GetCharacterIndex(sourceText, token.Span.End);
-
- if (tokenStartIndex > lastCharIndex)
- {
- var between = sourceText.Content.Substring(lastCharIndex, tokenStartIndex - lastCharIndex);
- result.Append(between);
- }
-
- var tokenText = sourceText.Content.Substring(tokenStartIndex, tokenEndIndex - tokenStartIndex);
-
- result.Append(Colorize(tokenText, GetTokenColor(token)));
- lastCharIndex = tokenEndIndex;
- }
-
- if (lastCharIndex < sourceText.Content.Length)
- {
- var remaining = sourceText.Content[lastCharIndex..];
- result.Append(Colorize(remaining, Faint));
- }
-
- return result.ToString();
- }
-
- private static int GetCharacterIndex(SourceText sourceText, SourceLocation location)
- {
- var lines = sourceText.Content.Split('\n');
- var index = 0;
-
- for (var i = 0; i < location.Line - 1 && i < lines.Length; i++)
- {
- index += lines[i].Length + 1;
- }
-
- index += location.Column - 1;
-
- return Math.Min(index, sourceText.Content.Length);
- }
-}
\ No newline at end of file
diff --git a/src/Syntax/Diagnostics/Diagnostic.cs b/src/Syntax/Diagnostics/Diagnostic.cs
deleted file mode 100644
index 4ba1ee3..0000000
--- a/src/Syntax/Diagnostics/Diagnostic.cs
+++ /dev/null
@@ -1,216 +0,0 @@
-using System.Text;
-using Syntax.Parsing;
-using Syntax.Parsing.Node;
-using Syntax.Tokenization;
-
-namespace Syntax.Diagnostics;
-
-public class Diagnostic
-{
- public class DiagnosticBuilder
- {
- private readonly DiagnosticSeverity _severity;
- private readonly string _message;
- private string? _help;
- private SourceSpan? _sourceSpan;
-
- public DiagnosticBuilder(DiagnosticSeverity severity, string message)
- {
- _severity = severity;
- _message = message;
- }
-
- public DiagnosticBuilder At(Token token)
- {
- _sourceSpan = token.Span;
- return this;
- }
-
- public DiagnosticBuilder At(Node node)
- {
- _sourceSpan = SourceSpan.Merge(node.Tokens.Select(t => t.Span));
- return this;
- }
-
- public DiagnosticBuilder At(SourceSpan span)
- {
- _sourceSpan = span;
- return this;
- }
-
- public DiagnosticBuilder WithHelp(string help)
- {
- _help = help;
- return this;
- }
-
- public Diagnostic Build() => new(_severity, _message, _sourceSpan, _help);
- }
-
- public static DiagnosticBuilder Error(string message) => new(DiagnosticSeverity.Error, message);
- public static DiagnosticBuilder Warning(string message) => new(DiagnosticSeverity.Warning, message);
- public static DiagnosticBuilder Info(string message) => new(DiagnosticSeverity.Info, message);
-
- public DiagnosticSeverity Severity { get; }
- public string Message { get; }
- public SourceSpan? Span { get; }
- public string? Help { get; }
-
- private Diagnostic(DiagnosticSeverity severity, string message, SourceSpan? span, string? help)
- {
- Severity = severity;
- Message = message;
- Span = span;
- Help = help;
- }
-
- public string FormatANSI()
- {
- var sb = new StringBuilder();
-
- var severityText = GetSeverityText(Severity);
- sb.Append(severityText);
-
- if (Span.HasValue)
- {
- var locationText = $" at {Span.Value.Text.Path}:{Span}";
- sb.Append(ConsoleColors.Colorize(locationText, ConsoleColors.Faint));
- }
-
- sb.Append(": ");
- sb.Append(ConsoleColors.Colorize(Message, ConsoleColors.BrightWhite));
-
- if (Span.HasValue)
- {
- sb.AppendLine();
- AppendSourceContext(sb, Span.Value, Severity);
- }
-
- if (!string.IsNullOrEmpty(Help))
- {
- sb.AppendLine();
- sb.Append(ConsoleColors.Colorize($"help: {Help}", ConsoleColors.Cyan));
- }
-
- return sb.ToString();
- }
-
- private static string GetSeverityText(DiagnosticSeverity severity)
- {
- return severity switch
- {
- DiagnosticSeverity.Error => ConsoleColors.Colorize("error", ConsoleColors.Bold + ConsoleColors.Red),
- DiagnosticSeverity.Warning => ConsoleColors.Colorize("warning", ConsoleColors.Bold + ConsoleColors.Yellow),
- DiagnosticSeverity.Info => ConsoleColors.Colorize("info", ConsoleColors.Bold + ConsoleColors.Blue),
- _ => throw new ArgumentOutOfRangeException(nameof(severity), severity, "Unknown diagnostic severity")
- };
- }
-
- private static void AppendSourceContext(StringBuilder sb, SourceSpan span, DiagnosticSeverity severity)
- {
- var lines = span.Text.Content.Split('\n');
- var startLine = span.Start.Line;
- var endLine = span.End.Line;
-
- const int contextLines = 3;
-
- var lineNumWidth = Math.Min(endLine + contextLines, lines.Length).ToString().Length;
-
- var contextStart = Math.Max(1, startLine - contextLines);
- var contextEnd = Math.Min(lines.Length, endLine + contextLines);
-
- var contextWidth = 0;
- for (var i = contextStart; i <= contextEnd; i++)
- {
- if (lines[i - 1].Length > contextWidth)
- {
- contextWidth = lines[i - 1].Length;
- }
- }
-
- sb.AppendLine(ConsoleColors.Colorize('╭' + new string('─', lineNumWidth + 2) + '┬' + new string('─', contextWidth + 2) + '╮', ConsoleColors.Faint));
-
- for (var lineNum = contextStart; lineNum < startLine; lineNum++)
- {
- AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
- }
-
- for (var lineNum = startLine; lineNum <= endLine; lineNum++)
- {
- AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
- AppendErrorIndicators(sb, span, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth, severity);
- }
-
- for (var lineNum = endLine + 1; lineNum <= contextEnd; lineNum++)
- {
- AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth);
- }
-
- sb.Append(ConsoleColors.Colorize('╰' + new string('─', lineNumWidth + 2) + '┴' + new string('─', contextWidth + 2) + '╯', ConsoleColors.Faint));
- }
-
- private static void AppendContextLine(StringBuilder sb, int lineNum, string line, int lineNumWidth, int contextWidth)
- {
- sb.Append(ConsoleColors.Colorize('│' + " ", ConsoleColors.Faint));
- var lineNumStr = lineNum.ToString().PadLeft(lineNumWidth);
- sb.Append(ConsoleColors.Colorize(lineNumStr, ConsoleColors.Faint));
- sb.Append(ConsoleColors.Colorize(" │ ", ConsoleColors.Faint));
- sb.Append(ConsoleColors.ColorizeSource(line.PadRight(contextWidth)));
- sb.Append(ConsoleColors.Colorize(" " + '│', ConsoleColors.Faint));
- sb.AppendLine();
- }
-
- private static void AppendErrorIndicators(StringBuilder sb, SourceSpan span, int lineNum, string line, int lineNumWidth, int contextWidth, DiagnosticSeverity severity)
- {
- var color = severity switch
- {
- DiagnosticSeverity.Info => ConsoleColors.Blue,
- DiagnosticSeverity.Warning => ConsoleColors.Yellow,
- DiagnosticSeverity.Error => ConsoleColors.Red,
- _ => throw new ArgumentOutOfRangeException(nameof(severity), severity, null)
- };
-
- sb.Append(ConsoleColors.Colorize('│' + " ", ConsoleColors.Faint));
- sb.Append(new string(' ', lineNumWidth));
- sb.Append(ConsoleColors.Colorize(" │ ", ConsoleColors.Faint));
- var indicators = GetIndicatorsForLine(span, lineNum, line);
- sb.Append(ConsoleColors.Colorize(indicators.PadRight(contextWidth), color));
- sb.Append(ConsoleColors.Colorize(" " + '│', ConsoleColors.Faint));
- sb.AppendLine();
- }
-
- private static string GetIndicatorsForLine(SourceSpan span, int lineNum, string line)
- {
- const char indicator = '^';
-
- if (lineNum == span.Start.Line && lineNum == span.End.Line)
- {
- var startCol = Math.Max(0, span.Start.Column - 1);
- var endCol = Math.Min(line.Length, span.End.Column - 1);
- var length = Math.Max(1, endCol - startCol);
-
- return new string(' ', startCol) + new string(indicator, length);
- }
-
- if (lineNum == span.Start.Line)
- {
- var startCol = Math.Max(0, span.Start.Column - 1);
- return new string(' ', startCol) + new string(indicator, Math.Max(0, line.Length - startCol));
- }
-
- if (lineNum == span.End.Line)
- {
- var endCol = Math.Min(line.Length, span.End.Column - 1);
- return new string(indicator, Math.Max(0, endCol));
- }
-
- return new string(indicator, line.Length);
- }
-}
-
-public enum DiagnosticSeverity
-{
- Info,
- Warning,
- Error
-}
\ No newline at end of file
diff --git a/src/Syntax/Parsing/Node/Definition.cs b/src/Syntax/Parsing/Node/Definition.cs
deleted file mode 100644
index aec8f54..0000000
--- a/src/Syntax/Parsing/Node/Definition.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Common;
-using Syntax.Tokenization;
-using Syntax.Typing;
-
-namespace Syntax.Parsing.Node;
-
-public abstract record DefinitionNode(IEnumerable Tokens, Optional Documentation, string Namespace) : Node(Tokens);
-
-public record FuncParameter(string Name, NubType Type);
-public abstract record FuncDefinition(IEnumerable Tokens, Optional Documentation, string Namespace, string Name, List Parameters, NubType ReturnType) : DefinitionNode(Tokens, Documentation, Namespace);
-public record LocalFuncDefinitionNode(IEnumerable Tokens, Optional Documentation, string Namespace, string Name, List Parameters, BlockNode Body, NubType ReturnType, bool Exported) : FuncDefinition(Tokens, Documentation, Namespace, Name, Parameters, ReturnType);
-public record ExternFuncDefinitionNode(IEnumerable Tokens, Optional Documentation, string Namespace, string Name, string CallName, List Parameters, NubType ReturnType) : FuncDefinition(Tokens, Documentation, Namespace, Name, Parameters, ReturnType);
-
-public record StructField(string Name, NubType Type, Optional Value);
-public record StructDefinitionNode(IEnumerable Tokens, Optional Documentation, string Namespace, string Name, List Fields) : DefinitionNode(Tokens, Documentation, Namespace);
diff --git a/src/Syntax/Parsing/Node/Expression.cs b/src/Syntax/Parsing/Node/Expression.cs
deleted file mode 100644
index a71316b..0000000
--- a/src/Syntax/Parsing/Node/Expression.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using Common;
-using Syntax.Tokenization;
-using Syntax.Typing;
-
-namespace Syntax.Parsing.Node;
-
-public abstract record ExpressionNode(IEnumerable Tokens) : Node(Tokens);
-public abstract record LValueNode(IEnumerable Tokens) : ExpressionNode(Tokens);
-
-public record BinaryExpressionNode(IEnumerable Tokens, ExpressionNode Left, BinaryExpressionOperator Operator, ExpressionNode Right) : ExpressionNode(Tokens);
-
-public enum BinaryExpressionOperator
-{
- Equal,
- NotEqual,
- GreaterThan,
- GreaterThanOrEqual,
- LessThan,
- LessThanOrEqual,
- Plus,
- Minus,
- Multiply,
- Divide
-}
-
-public record UnaryExpressionNode(IEnumerable Tokens, UnaryExpressionOperator Operator, ExpressionNode Operand) : ExpressionNode(Tokens);
-
-public enum UnaryExpressionOperator
-{
- Negate,
- Invert
-}
-
-public record FuncCallNode(IEnumerable Tokens, ExpressionNode Expression, List Parameters) : ExpressionNode(Tokens);
-public record IdentifierNode(IEnumerable Tokens, Optional Namespace, string Name) : LValueNode(Tokens);
-public record ArrayInitializerNode(IEnumerable Tokens, ExpressionNode Capacity, NubType ElementType) : ExpressionNode(Tokens);
-public record ArrayIndexAccessNode(IEnumerable Tokens, ExpressionNode Array, ExpressionNode Index) : LValueNode(Tokens);
-public record AnonymousFuncNode(IEnumerable Tokens, List Parameters, BlockNode Body, NubType ReturnType) : ExpressionNode(Tokens);
-public record AddressOfNode(IEnumerable Tokens, LValueNode Expression) : ExpressionNode(Tokens);
-public record FixedArrayInitializerNode(IEnumerable Tokens, NubType ElementType, int Capacity) : ExpressionNode(Tokens);
-public record LiteralNode(IEnumerable Tokens, string Literal, LiteralKind Kind) : ExpressionNode(Tokens);
-public record MemberAccessNode(IEnumerable Tokens, ExpressionNode Expression, string Member) : ExpressionNode(Tokens);
-public record StructInitializerNode(IEnumerable Tokens, NubStructType StructType, Dictionary Initializers) : ExpressionNode(Tokens);
-public record DereferenceNode(IEnumerable Tokens, ExpressionNode Expression) : LValueNode(Tokens);
diff --git a/src/Syntax/Parsing/Node/Node.cs b/src/Syntax/Parsing/Node/Node.cs
deleted file mode 100644
index 5d4357e..0000000
--- a/src/Syntax/Parsing/Node/Node.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using Syntax.Tokenization;
-
-namespace Syntax.Parsing.Node;
-
-public abstract record Node(IEnumerable Tokens);
-public record BlockNode(IEnumerable Tokens, List Statements) : Node(Tokens);
diff --git a/src/Syntax/Parsing/Node/Statement.cs b/src/Syntax/Parsing/Node/Statement.cs
deleted file mode 100644
index db506de..0000000
--- a/src/Syntax/Parsing/Node/Statement.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Common;
-using Syntax.Tokenization;
-using Syntax.Typing;
-
-namespace Syntax.Parsing.Node;
-
-public record StatementNode(IEnumerable Tokens) : Node(Tokens);
-public record StatementExpressionNode(IEnumerable Tokens, ExpressionNode Expression) : StatementNode(Tokens);
-public record ReturnNode(IEnumerable Tokens, Optional Value) : StatementNode(Tokens);
-public record MemberAssignmentNode(IEnumerable Tokens, MemberAccessNode MemberAccess, ExpressionNode Value) : StatementNode(Tokens);
-public record IfNode(IEnumerable Tokens, ExpressionNode Condition, BlockNode Body, Optional> Else) : StatementNode(Tokens);
-public record DereferenceAssignmentNode(IEnumerable Tokens, DereferenceNode Dereference, ExpressionNode Value) : StatementNode(Tokens);
-public record VariableAssignmentNode(IEnumerable Tokens, IdentifierNode Identifier, ExpressionNode Value) : StatementNode(Tokens);
-public record VariableDeclarationNode(IEnumerable Tokens, string Name, NubType Type) : StatementNode(Tokens);
-public record ContinueNode(IEnumerable Tokens) : StatementNode(Tokens);
-public record BreakNode(IEnumerable Tokens) : StatementNode(Tokens);
-public record ArrayIndexAssignmentNode(IEnumerable Tokens, ArrayIndexAccessNode ArrayIndexAccess, ExpressionNode Value) : StatementNode(Tokens);
-public record WhileNode(IEnumerable Tokens, ExpressionNode Condition, BlockNode Body) : StatementNode(Tokens);
diff --git a/src/Syntax/Parsing/Parser.cs b/src/Syntax/Parsing/Parser.cs
deleted file mode 100644
index 546310f..0000000
--- a/src/Syntax/Parsing/Parser.cs
+++ /dev/null
@@ -1,939 +0,0 @@
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using Common;
-using Syntax.Diagnostics;
-using Syntax.Parsing.Node;
-using Syntax.Tokenization;
-using Syntax.Typing;
-
-namespace Syntax.Parsing;
-
-public static class Parser
-{
- private static string _namespace = null!;
- private static List _diagnostics = [];
- private static IEnumerable _tokens = [];
- private static int _index;
-
- public static SyntaxTree? ParseFile(IEnumerable tokens, string filePath, out IEnumerable diagnostics)
- {
- _tokens = tokens;
- _namespace = null!;
- _diagnostics = [];
- _index = 0;
-
- try
- {
- ExpectSymbol(Symbol.Namespace);
- var @namespace = ExpectIdentifier();
- _namespace = @namespace.Value;
- }
- catch (ParseException ex)
- {
- _diagnostics.Add(ex.Diagnostic);
- diagnostics = _diagnostics;
- return null;
- }
-
- try
- {
- List definitions = [];
-
- while (Peek().HasValue)
- {
- var definition = ParseDefinition();
- definitions.Add(definition);
- }
-
- diagnostics = _diagnostics;
- return new SyntaxTree(filePath, _namespace, definitions);
- }
- catch (ParseException ex)
- {
- _diagnostics.Add(ex.Diagnostic);
- RecoverToNextDefinition();
- }
-
- diagnostics = _diagnostics;
- return null;
- }
-
- private static DefinitionNode ParseDefinition()
- {
- var startIndex = _index;
- List modifiers = [];
-
- List documentationParts = [];
- while (_index < _tokens.Count() && _tokens.ElementAt(_index) is DocumentationToken commentToken)
- {
- documentationParts.Add(commentToken.Documentation);
- _index++;
- }
-
- var documentation = documentationParts.Count == 0 ? null : string.Join('\n', documentationParts);
-
- while (TryExpectModifier(out var modifier))
- {
- modifiers.Add(modifier);
- }
-
- var keyword = ExpectSymbol();
- return keyword.Symbol switch
- {
- Symbol.Func => ParseFuncDefinition(startIndex, modifiers, Optional.OfNullable(documentation)),
- Symbol.Struct => ParseStruct(startIndex, modifiers, Optional.OfNullable(documentation)),
- _ => throw new ParseException(Diagnostic
- .Error($"Expected 'func' or 'struct', but found '{keyword.Symbol}'")
- .WithHelp("Valid definition keywords are 'func' and 'struct'")
- .At(keyword)
- .Build())
- };
- }
-
- private static DefinitionNode ParseFuncDefinition(int startIndex, List modifiers, Optional documentation)
- {
- var name = ExpectIdentifier();
- List parameters = [];
-
- ExpectSymbol(Symbol.OpenParen);
-
- while (!TryExpectSymbol(Symbol.CloseParen))
- {
- parameters.Add(ParseFuncParameter());
-
- if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen })
- {
- _diagnostics.Add(Diagnostic
- .Warning("Missing comma between function parameters")
- .WithHelp("Add a ',' to separate parameters")
- .At(token)
- .Build());
- }
- }
-
- var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
-
- var isExtern = modifiers.RemoveAll(x => x.Modifier == Modifier.Extern) > 0;
- if (isExtern)
- {
- if (modifiers.Count != 0)
- {
- throw new ParseException(Diagnostic
- .Error($"Invalid modifier for extern function: {modifiers[0].Modifier}")
- .WithHelp($"Extern functions cannot use the '{modifiers[0].Modifier}' modifier")
- .At(modifiers[0])
- .Build());
- }
-
- var callName = name.Value;
-
- if (TryExpectSymbol(Symbol.Calls))
- {
- callName = ExpectIdentifier().Value;
- }
-
- return new ExternFuncDefinitionNode(GetTokensForNode(startIndex), documentation, _namespace, name.Value, callName, parameters, returnType);
- }
-
- var body = ParseBlock();
- var exported = modifiers.RemoveAll(x => x.Modifier == Modifier.Export) > 0;
-
- if (modifiers.Count != 0)
- {
- throw new ParseException(Diagnostic
- .Error($"Invalid modifiers for function: {modifiers[0].Modifier}")
- .WithHelp($"Functions cannot use the '{modifiers[0].Modifier}' modifier")
- .At(modifiers[0])
- .Build());
- }
-
- return new LocalFuncDefinitionNode(GetTokensForNode(startIndex), documentation, _namespace, name.Value, parameters, body, returnType, exported);
- }
-
- private static StructDefinitionNode ParseStruct(int startIndex, List _, Optional documentation)
- {
- var name = ExpectIdentifier().Value;
-
- ExpectSymbol(Symbol.OpenBrace);
-
- List variables = [];
-
- while (!TryExpectSymbol(Symbol.CloseBrace))
- {
- var variableName = ExpectIdentifier().Value;
- ExpectSymbol(Symbol.Colon);
- var variableType = ParseType();
-
- var variableValue = Optional.Empty();
-
- if (TryExpectSymbol(Symbol.Assign))
- {
- variableValue = ParseExpression();
- }
-
- variables.Add(new StructField(variableName, variableType, variableValue));
- }
-
- return new StructDefinitionNode(GetTokensForNode(startIndex), documentation, _namespace, name, variables);
- }
-
- private static FuncParameter ParseFuncParameter()
- {
- var name = ExpectIdentifier();
- ExpectSymbol(Symbol.Colon);
- var type = ParseType();
-
- return new FuncParameter(name.Value, type);
- }
-
- private static StatementNode ParseStatement()
- {
- var startIndex = _index;
- if (!Peek().TryGetValue(out var token))
- {
- throw new ParseException(Diagnostic
- .Error("Unexpected end of file while parsing statement")
- .At(_tokens.Last())
- .Build());
- }
-
- if (token is SymbolToken symbol)
- {
- switch (symbol.Symbol)
- {
- case Symbol.Return:
- return ParseReturn(startIndex);
- case Symbol.If:
- return ParseIf(startIndex);
- case Symbol.While:
- return ParseWhile(startIndex);
- case Symbol.Let:
- return ParseVariableDeclaration(startIndex);
- case Symbol.Break:
- return ParseBreak(startIndex);
- case Symbol.Continue:
- return ParseContinue(startIndex);
- }
- }
-
- return ParseStatementExpression(startIndex);
- }
-
- private static StatementNode ParseStatementExpression(int startIndex)
- {
- var expr = ParseExpression();
-
- if (Peek().TryGetValue(out var token))
- {
- if (token is SymbolToken symbol)
- {
- switch (symbol.Symbol)
- {
- case Symbol.Assign:
- {
- switch (expr)
- {
- case MemberAccessNode memberAccess:
- {
- Next();
- var value = ParseExpression();
- return new MemberAssignmentNode(GetTokensForNode(startIndex), memberAccess, value);
- }
- case ArrayIndexAccessNode arrayIndexAccess:
- {
- Next();
- var value = ParseExpression();
- return new ArrayIndexAssignmentNode(GetTokensForNode(startIndex), arrayIndexAccess, value);
- }
- case IdentifierNode identifier:
- {
- Next();
- var value = ParseExpression();
- return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier, value);
- }
- case DereferenceNode dereference:
- {
- Next();
- var value = ParseExpression();
- return new DereferenceAssignmentNode(GetTokensForNode(startIndex), dereference, value);
- }
- }
-
- break;
- }
- }
- }
- }
-
- return new StatementExpressionNode(GetTokensForNode(startIndex), expr);
- }
-
- private static VariableDeclarationNode ParseVariableDeclaration(int startIndex)
- {
- ExpectSymbol(Symbol.Let);
- var name = ExpectIdentifier().Value;
- ExpectSymbol(Symbol.Colon);
- var type = ParseType();
-
- return new VariableDeclarationNode(GetTokensForNode(startIndex), name, type);
- }
-
- private static StatementNode ParseBreak(int startIndex)
- {
- ExpectSymbol(Symbol.Break);
- Next();
- return new BreakNode(GetTokensForNode(startIndex));
- }
-
- private static StatementNode ParseContinue(int startIndex)
- {
- ExpectSymbol(Symbol.Continue);
- return new ContinueNode(GetTokensForNode(startIndex));
- }
-
- private static ReturnNode ParseReturn(int startIndex)
- {
- ExpectSymbol(Symbol.Return);
- var value = Optional.Empty();
- if (!TryExpectSymbol(Symbol.Semicolon))
- {
- value = ParseExpression();
- }
-
- return new ReturnNode(GetTokensForNode(startIndex), value);
- }
-
- private static IfNode ParseIf(int startIndex)
- {
- ExpectSymbol(Symbol.If);
- var condition = ParseExpression();
- var body = ParseBlock();
-
- var elseStatement = Optional>.Empty();
- if (TryExpectSymbol(Symbol.Else))
- {
- var newStartIndex = _index;
- elseStatement = TryExpectSymbol(Symbol.If)
- ? (Variant)ParseIf(newStartIndex)
- : (Variant)ParseBlock();
- }
-
- return new IfNode(GetTokensForNode(startIndex), condition, body, elseStatement);
- }
-
- private static WhileNode ParseWhile(int startIndex)
- {
- ExpectSymbol(Symbol.While);
- var condition = ParseExpression();
- var body = ParseBlock();
- return new WhileNode(GetTokensForNode(startIndex), condition, body);
- }
-
- private static ExpressionNode ParseExpression(int precedence = 0)
- {
- var startIndex = _index;
- var left = ParsePrimaryExpression();
-
- while (true)
- {
- var token = Peek();
- if (!token.HasValue || token.Value is not SymbolToken symbolToken || !TryGetBinaryOperator(symbolToken.Symbol, out var op) ||
- GetBinaryOperatorPrecedence(op.Value) < precedence)
- {
- break;
- }
-
- Next();
- var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
-
- left = new BinaryExpressionNode(GetTokensForNode(startIndex), left, op.Value, right);
- }
-
- return left;
- }
-
- private static int GetBinaryOperatorPrecedence(BinaryExpressionOperator binaryExpressionOperator)
- {
- return binaryExpressionOperator switch
- {
- BinaryExpressionOperator.Multiply => 3,
- BinaryExpressionOperator.Divide => 3,
- BinaryExpressionOperator.Plus => 2,
- BinaryExpressionOperator.Minus => 2,
- BinaryExpressionOperator.GreaterThan => 1,
- BinaryExpressionOperator.GreaterThanOrEqual => 1,
- BinaryExpressionOperator.LessThan => 1,
- BinaryExpressionOperator.LessThanOrEqual => 1,
- BinaryExpressionOperator.Equal => 0,
- BinaryExpressionOperator.NotEqual => 0,
- _ => throw new ArgumentOutOfRangeException(nameof(binaryExpressionOperator), binaryExpressionOperator, null)
- };
- }
-
- private static bool TryGetBinaryOperator(Symbol symbol, [NotNullWhen(true)] out BinaryExpressionOperator? binaryExpressionOperator)
- {
- switch (symbol)
- {
- case Symbol.Equal:
- binaryExpressionOperator = BinaryExpressionOperator.Equal;
- return true;
- case Symbol.NotEqual:
- binaryExpressionOperator = BinaryExpressionOperator.NotEqual;
- return true;
- case Symbol.LessThan:
- binaryExpressionOperator = BinaryExpressionOperator.LessThan;
- return true;
- case Symbol.LessThanOrEqual:
- binaryExpressionOperator = BinaryExpressionOperator.LessThanOrEqual;
- return true;
- case Symbol.GreaterThan:
- binaryExpressionOperator = BinaryExpressionOperator.GreaterThan;
- return true;
- case Symbol.GreaterThanOrEqual:
- binaryExpressionOperator = BinaryExpressionOperator.GreaterThanOrEqual;
- return true;
- case Symbol.Plus:
- binaryExpressionOperator = BinaryExpressionOperator.Plus;
- return true;
- case Symbol.Minus:
- binaryExpressionOperator = BinaryExpressionOperator.Minus;
- return true;
- case Symbol.Star:
- binaryExpressionOperator = BinaryExpressionOperator.Multiply;
- return true;
- case Symbol.ForwardSlash:
- binaryExpressionOperator = BinaryExpressionOperator.Divide;
- return true;
- default:
- binaryExpressionOperator = null;
- return false;
- }
- }
-
- private static ExpressionNode ParsePrimaryExpression()
- {
- var startIndex = _index;
- ExpressionNode expr;
-
- var token = ExpectToken();
- switch (token)
- {
- case LiteralToken literal:
- {
- expr = new LiteralNode(GetTokensForNode(startIndex), literal.Value, literal.Kind);
- break;
- }
- case IdentifierToken identifier:
- {
- var @namespace = Optional.Empty();
- var name = identifier.Value;
- if (TryExpectSymbol(Symbol.DoubleColon))
- {
- @namespace = identifier.Value;
- name = ExpectIdentifier().Value;
- }
-
- expr = new IdentifierNode(GetTokensForNode(startIndex), @namespace, name);
- break;
- }
- case SymbolToken symbolToken:
- {
- switch (symbolToken.Symbol)
- {
- case Symbol.Func:
- {
- List parameters = [];
- ExpectSymbol(Symbol.OpenParen);
- while (!TryExpectSymbol(Symbol.CloseParen))
- {
- var parameter = ParseFuncParameter();
- parameters.Add(parameter);
- if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen })
- {
- _diagnostics.Add(Diagnostic
- .Warning("Missing comma between function arguments")
- .WithHelp("Add a ',' to separate arguments")
- .At(nextToken)
- .Build());
- }
- }
-
- var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
-
- var body = ParseBlock();
-
- expr = new AnonymousFuncNode(GetTokensForNode(startIndex), parameters, body, returnType);
- break;
- }
- case Symbol.OpenParen:
- {
- var expression = ParseExpression();
- ExpectSymbol(Symbol.CloseParen);
- expr = expression;
- break;
- }
- case Symbol.Ampersand:
- {
- var expression = ParsePrimaryExpression();
- if (expression is not LValueNode lValue)
- {
- throw new ParseException(Diagnostic
- .Error("& symbol can only be used on lvalues")
- .At(expression)
- .Build());
- }
-
- expr = new AddressOfNode(GetTokensForNode(startIndex), lValue);
- break;
- }
- case Symbol.Minus:
- {
- var expression = ParsePrimaryExpression();
- expr = new UnaryExpressionNode(GetTokensForNode(startIndex), UnaryExpressionOperator.Negate, expression);
- break;
- }
- case Symbol.Bang:
- {
- var expression = ParsePrimaryExpression();
- expr = new UnaryExpressionNode(GetTokensForNode(startIndex), UnaryExpressionOperator.Invert, expression);
- break;
- }
- case Symbol.OpenBracket:
- {
- if (Peek().TryGetValue(out var capacityToken) && capacityToken is LiteralToken { Kind: LiteralKind.Integer } literalToken)
- {
- var capacity = int.Parse(literalToken.Value);
- Next();
- ExpectSymbol(Symbol.CloseBracket);
- var elementType = ParseType();
-
- if (capacity > 0)
- {
- expr = new FixedArrayInitializerNode(GetTokensForNode(startIndex), elementType, capacity);
- }
- else
- {
- throw new ParseException(Diagnostic
- .Error("Fixed array size must be a positive integer")
- .WithHelp("Use a positive integer literal for the array size")
- .At(literalToken)
- .Build());
- }
- }
- else
- {
- var capacity = ParseExpression();
- ExpectSymbol(Symbol.CloseBracket);
- var type = ParseType();
-
- expr = new ArrayInitializerNode(GetTokensForNode(startIndex), capacity, type);
- }
-
- break;
- }
- case Symbol.Alloc:
- {
- var type = ParseType();
- Dictionary initializers = [];
- ExpectSymbol(Symbol.OpenBrace);
- while (!TryExpectSymbol(Symbol.CloseBrace))
- {
- var name = ExpectIdentifier().Value;
- ExpectSymbol(Symbol.Assign);
- var value = ParseExpression();
- initializers.Add(name, value);
- }
-
- if (type is not NubStructType structType)
- {
- throw new ParseException(Diagnostic
- .Error($"Cannot alloc type '{type}'")
- .At(symbolToken)
- .Build());
- }
-
- expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers);
- break;
- }
- default:
- {
- throw new ParseException(Diagnostic
- .Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
- .WithHelp("Expected literal, identifier, or '(' to start expression")
- .At(symbolToken)
- .Build());
- }
- }
-
- break;
- }
- default:
- {
- throw new ParseException(Diagnostic
- .Error($"Unexpected token '{token.GetType().Name}' in expression")
- .WithHelp("Expected literal, identifier, or parenthesized expression")
- .At(token)
- .Build());
- }
- }
-
- return ParsePostfixOperators(startIndex, expr);
- }
-
- private static ExpressionNode ParsePostfixOperators(int startIndex, ExpressionNode expr)
- {
- while (true)
- {
- if (TryExpectSymbol(Symbol.Caret))
- {
- expr = new DereferenceNode(GetTokensForNode(startIndex), expr);
- continue;
- }
-
- if (TryExpectSymbol(Symbol.Period))
- {
- var structMember = ExpectIdentifier().Value;
- expr = new MemberAccessNode(GetTokensForNode(startIndex), expr, structMember);
- continue;
- }
-
- if (TryExpectSymbol(Symbol.OpenBracket))
- {
- var index = ParseExpression();
- ExpectSymbol(Symbol.CloseBracket);
- expr = new ArrayIndexAccessNode(GetTokensForNode(startIndex), expr, index);
- continue;
- }
-
- if (TryExpectSymbol(Symbol.OpenParen))
- {
- var parameters = new List();
- while (!TryExpectSymbol(Symbol.CloseParen))
- {
- parameters.Add(ParseExpression());
- if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen })
- {
- _diagnostics.Add(Diagnostic
- .Warning("Missing comma between function arguments")
- .WithHelp("Add a ',' to separate arguments")
- .At(nextToken)
- .Build());
- }
- }
-
- expr = new FuncCallNode(GetTokensForNode(startIndex), expr, parameters);
- continue;
- }
-
- break;
- }
-
- return expr;
- }
-
- private static BlockNode ParseBlock()
- {
- var startIndex = _index;
- ExpectSymbol(Symbol.OpenBrace);
- List statements = [];
- while (Peek().HasValue && !TryExpectSymbol(Symbol.CloseBrace))
- {
- try
- {
- statements.Add(ParseStatement());
- }
- catch (ParseException ex)
- {
- _diagnostics.Add(ex.Diagnostic);
- RecoverToNextStatement();
- }
- }
-
- return new BlockNode(GetTokensForNode(startIndex), statements);
- }
-
- private static NubType ParseType()
- {
- if (TryExpectIdentifier(out var name))
- {
- if (name.Value == "any")
- {
- return new NubAnyType();
- }
-
- if (name.Value == "void")
- {
- return new NubVoidType();
- }
-
- if (name.Value == "string")
- {
- return new NubStringType();
- }
-
- if (name.Value == "cstring")
- {
- return new NubCStringType();
- }
-
- if (NubPrimitiveType.TryParse(name.Value, out var primitiveTypeKind))
- {
- return new NubPrimitiveType(primitiveTypeKind.Value);
- }
-
- var @namespace = _namespace;
- if (TryExpectSymbol(Symbol.DoubleColon))
- {
- @namespace = ExpectIdentifier().Value;
- }
-
- if (@namespace == null)
- {
- throw new ParseException(Diagnostic
- .Error($"Struct '{name.Value}' does not belong to a namespace")
- .WithHelp("Make sure you have specified a namespace at the top of the file")
- .At(name)
- .Build());
- }
-
- return new NubStructType(@namespace , name.Value);
- }
-
- if (TryExpectSymbol(Symbol.Caret))
- {
- var baseType = ParseType();
- return new NubPointerType(baseType);
- }
-
- if (TryExpectSymbol(Symbol.Func))
- {
- ExpectSymbol(Symbol.OpenParen);
- List parameters = [];
- while (!TryExpectSymbol(Symbol.CloseParen))
- {
- var parameter = ParseType();
- parameters.Add(parameter);
- if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen })
- {
- _diagnostics.Add(Diagnostic
- .Warning("Missing comma between func type arguments")
- .WithHelp("Add a ',' to separate arguments")
- .At(nextToken)
- .Build());
- }
- }
-
- var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
-
- return new NubFuncType(returnType, parameters);
- }
-
- if (TryExpectSymbol(Symbol.OpenBracket))
- {
- if (Peek().TryGetValue(out var token) && token is LiteralToken { Kind: LiteralKind.Integer, Value: var sizeValue })
- {
- Next();
- ExpectSymbol(Symbol.CloseBracket);
- var baseType = ParseType();
-
- var size = int.Parse(sizeValue);
-
- if (size > 0)
- {
- return new NubFixedArrayType(baseType, size);
- }
- else
- {
- throw new UnreachableException();
- }
- }
- else
- {
- ExpectSymbol(Symbol.CloseBracket);
- var baseType = ParseType();
- return new NubArrayType(baseType);
- }
- }
-
- if (!Peek().TryGetValue(out var peekToken))
- {
- throw new ParseException(Diagnostic
- .Error("Unexpected end of file while parsing type")
- .WithHelp("Expected a type name")
- .At(_tokens.Last())
- .Build());
- }
-
- throw new ParseException(Diagnostic
- .Error("Invalid type Syntax")
- .WithHelp("Expected type name, '^' for pointer, or '[]' for array")
- .At(peekToken)
- .Build());
-}
-
- private static Token ExpectToken()
- {
- if (!Peek().TryGetValue(out var token))
- {
- throw new ParseException(Diagnostic
- .Error("Unexpected end of file")
- .WithHelp("Expected more tokens to complete the Syntax")
- .At(_tokens.Last())
- .Build());
- }
-
- Next();
- return token;
- }
-
- private static SymbolToken ExpectSymbol()
- {
- var token = ExpectToken();
- if (token is not SymbolToken symbol)
- {
- throw new ParseException(Diagnostic
- .Error($"Expected symbol, but found {token.GetType().Name}")
- .WithHelp("This position requires a symbol like '(', ')', '{', '}', etc.")
- .At(token)
- .Build());
- }
-
- return symbol;
- }
-
- private static void ExpectSymbol(Symbol expectedSymbol)
- {
- var token = ExpectSymbol();
- if (token.Symbol != expectedSymbol)
- {
- throw new ParseException(Diagnostic
- .Error($"Expected '{expectedSymbol}', but found '{token.Symbol}'")
- .WithHelp($"Insert '{expectedSymbol}' here")
- .At(token)
- .Build());
- }
- }
-
- private static bool TryExpectSymbol(Symbol symbol)
- {
- if (Peek() is { Value: SymbolToken symbolToken } && symbolToken.Symbol == symbol)
- {
- Next();
- return true;
- }
-
- return false;
- }
-
- private static bool TryExpectModifier([NotNullWhen(true)] out ModifierToken? modifier)
- {
- if (Peek() is { Value: ModifierToken modifierToken })
- {
- modifier = modifierToken;
- Next();
- return true;
- }
-
- modifier = null;
- return false;
- }
-
- private static bool TryExpectIdentifier([NotNullWhen(true)] out IdentifierToken? identifier)
- {
- if (Peek() is { Value: IdentifierToken identifierToken })
- {
- identifier = identifierToken;
- Next();
- return true;
- }
-
- identifier = null;
- return false;
- }
-
- private static IdentifierToken ExpectIdentifier()
- {
- var token = ExpectToken();
- if (token is not IdentifierToken identifier)
- {
- throw new ParseException(Diagnostic
- .Error($"Expected identifier, but found {token.GetType().Name}")
- .WithHelp("Provide a valid identifier name here")
- .At(token)
- .Build());
- }
-
- return identifier;
- }
-
- private static void RecoverToNextDefinition()
- {
- while (Peek().HasValue)
- {
- var token = Peek().Value;
- if (token is SymbolToken { Symbol: Symbol.Func or Symbol.Struct } or ModifierToken)
- {
- break;
- }
-
- Next();
- }
- }
-
- private static void RecoverToNextStatement()
- {
- while (Peek().TryGetValue(out var token))
- {
- if (token is SymbolToken { Symbol: Symbol.CloseBrace } or IdentifierToken or SymbolToken
- {
- Symbol: Symbol.Return or Symbol.If or Symbol.While or Symbol.Let or Symbol.Break or Symbol.Continue
- })
- {
- break;
- }
-
- Next();
- }
- }
-
- private static Optional Peek(int offset = 0)
- {
- var peekIndex = _index + offset;
- while (peekIndex < _tokens.Count() && _tokens.ElementAt(peekIndex) is DocumentationToken)
- {
- peekIndex++;
- }
-
- if (peekIndex < _tokens.Count())
- {
- return _tokens.ElementAt(peekIndex);
- }
-
- return Optional.Empty();
- }
-
- private static void Next()
- {
- while (_index < _tokens.Count() && _tokens.ElementAt(_index) is DocumentationToken)
- {
- _index++;
- }
-
- _index++;
- }
-
- private static IEnumerable GetTokensForNode(int startIndex)
- {
- return _tokens.Skip(startIndex).Take(Math.Min(_index, _tokens.Count() - 1) - startIndex);
- }
-}
-
-public class ParseException : Exception
-{
- public Diagnostic Diagnostic { get; }
-
- public ParseException(Diagnostic diagnostic) : base(diagnostic.Message)
- {
- Diagnostic = diagnostic;
- }
-}
\ No newline at end of file
diff --git a/src/Syntax/Parsing/SyntaxTree.cs b/src/Syntax/Parsing/SyntaxTree.cs
deleted file mode 100644
index 914a9ed..0000000
--- a/src/Syntax/Parsing/SyntaxTree.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-using Syntax.Parsing.Node;
-
-namespace Syntax.Parsing;
-
-public record SyntaxTree(string FilePath, string Namespace, List Definitions);
diff --git a/src/Syntax/Source.cs b/src/Syntax/Source.cs
deleted file mode 100644
index bfeb6af..0000000
--- a/src/Syntax/Source.cs
+++ /dev/null
@@ -1,274 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-
-namespace Syntax;
-
-///
-/// Represents a location in source code with line and column information.
-/// Lines and columns are 1-based to match typical editor conventions.
-///
-public readonly struct SourceLocation : IEquatable, IComparable
-{
- public SourceLocation(int line, int column)
- {
- if (line < 1)
- {
- throw new ArgumentOutOfRangeException(nameof(line), "Line must be >= 1");
- }
-
- if (column < 1)
- {
- throw new ArgumentOutOfRangeException(nameof(column), "Column must be >= 1");
- }
-
- Line = line;
- Column = column;
- }
-
- public int Line { get; }
- public int Column { get; }
-
- public int CompareTo(SourceLocation other)
- {
- var lineComparison = Line.CompareTo(other.Line);
- if (lineComparison == 0)
- {
- return Column.CompareTo(other.Column);
- }
-
- return lineComparison;
- }
-
- public override string ToString()
- {
- return $"{Line}:{Column}";
- }
-
- public bool Equals(SourceLocation other)
- {
- return Line == other.Line && Column == other.Column;
- }
-
- public override bool Equals([NotNullWhen(true)] object? obj)
- {
- return obj is SourceLocation other && Equals(other);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Line, Column);
- }
-
- public static bool operator ==(SourceLocation left, SourceLocation right) => left.Equals(right);
- public static bool operator !=(SourceLocation left, SourceLocation right) => !left.Equals(right);
- public static bool operator <(SourceLocation left, SourceLocation right) => left.CompareTo(right) < 0;
- public static bool operator >(SourceLocation left, SourceLocation right) => left.CompareTo(right) > 0;
- public static bool operator <=(SourceLocation left, SourceLocation right) => left.CompareTo(right) <= 0;
- public static bool operator >=(SourceLocation left, SourceLocation right) => left.CompareTo(right) >= 0;
-}
-
-///
-/// Represents source text with a name (typically filename) and content.
-/// Equality is based on both name and content for better semantics.
-///
-public struct SourceText : IEquatable
-{
- private int _lines = -1;
-
- public SourceText(string path, string content)
- {
- Path = path ?? throw new ArgumentNullException(nameof(path));
- Content = content ?? throw new ArgumentNullException(nameof(content));
- }
-
- public string Path { get; }
- public string Content { get; }
-
- public int LineCount()
- {
- if (_lines == -1)
- {
- _lines = Content.Split('\n').Length + 1;
- }
-
- return _lines;
- }
-
- ///
- /// Gets a specific line from the source text (1-based).
- ///
- public string GetLine(int lineNumber)
- {
- if (lineNumber < 1)
- {
- throw new ArgumentOutOfRangeException(nameof(lineNumber));
- }
-
- var lines = Content.Split('\n');
- return lineNumber <= lines.Length ? lines[lineNumber - 1] : string.Empty;
- }
-
- public bool Equals(SourceText other)
- {
- return Path == other.Path && Content == other.Content;
- }
-
- public override bool Equals([NotNullWhen(true)] object? obj)
- {
- return obj is SourceText other && Equals(other);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Path, Content);
- }
-
- public override string ToString()
- {
- return Path;
- }
-
- public static bool operator ==(SourceText left, SourceText right) => left.Equals(right);
- public static bool operator !=(SourceText left, SourceText right) => !left.Equals(right);
-}
-
-///
-/// Represents a span of source code from a start to end location within a source text.
-///
-public readonly struct SourceSpan : IEquatable
-{
- public SourceSpan(SourceText text, SourceLocation start, SourceLocation end)
- {
- if (start > end)
- {
- throw new ArgumentException("Start location cannot be after end location");
- }
-
- if (end.Line > text.LineCount() || end.Line == text.LineCount() && end.Column > text.GetLine(text.LineCount()).Length + 1)
- {
- throw new ArgumentException("End location cannot be after text end location");
- }
-
- Text = text;
- Start = start;
- End = end;
- }
-
- public SourceText Text { get; }
- public SourceLocation Start { get; }
- public SourceLocation End { get; }
-
- ///
- /// Gets whether this span represents a single point (start == end).
- ///
- public bool IsEmpty => Start == End;
-
- ///
- /// Gets whether this span is contained within a single line.
- ///
- public bool IsSingleLine => Start.Line == End.Line;
-
- ///
- /// Gets the text content covered by this span.
- ///
- public string GetText()
- {
- if (IsEmpty)
- {
- return string.Empty;
- }
-
- var lines = Text.Content.Split('\n');
-
- if (IsSingleLine)
- {
- var line = lines[Start.Line - 1];
- var startCol = Math.Min(Start.Column - 1, line.Length);
- var endCol = Math.Min(End.Column - 1, line.Length);
- return line.Substring(startCol, Math.Max(0, endCol - startCol));
- }
-
- var result = new List();
- for (var i = Start.Line - 1; i < Math.Min(End.Line, lines.Length); i++)
- {
- var line = lines[i];
- if (i == Start.Line - 1)
- {
- result.Add(line[Math.Min(Start.Column - 1, line.Length)..]);
- }
- else if (i == End.Line - 1)
- {
- result.Add(line[..Math.Min(End.Column - 1, line.Length)]);
- }
- else
- {
- result.Add(line);
- }
- }
-
- return string.Join("\n", result);
- }
-
- ///
- /// Merges multiple source spans from the same file into a single span.
- /// The result spans from the earliest start to the latest end.
- ///
- public static SourceSpan Merge(IEnumerable spans)
- {
- var spanArray = spans.ToArray();
- if (spanArray.Length == 0)
- {
- throw new ArgumentException("Cannot merge empty collection of spans", nameof(spans));
- }
-
- var firstText = spanArray[0].Text;
- if (spanArray.Any(s => !s.Text.Equals(firstText)))
- {
- throw new ArgumentException("All spans must be from the same source text", nameof(spans));
- }
-
- var minStart = spanArray.Min(s => s.Start);
- var maxEnd = spanArray.Max(s => s.End);
-
- return new SourceSpan(firstText, minStart, maxEnd);
- }
-
- public override string ToString()
- {
- if (IsEmpty)
- {
- return $"{Start}";
- }
-
- if (IsSingleLine)
- {
- return Start.Column == End.Column ? $"{Start}" : $"{Start.Line}:{Start.Column}-{End.Column}";
- }
-
- return $"{Start}-{End}";
- }
-
- public bool Equals(SourceSpan other)
- {
- return Text.Equals(other.Text) && Start.Equals(other.Start) && End.Equals(other.End);
- }
-
- public override bool Equals([NotNullWhen(true)] object? obj)
- {
- return obj is SourceSpan other && Equals(other);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Text, Start, End);
- }
-
- public static bool operator ==(SourceSpan left, SourceSpan right)
- {
- return left.Equals(right);
- }
-
- public static bool operator !=(SourceSpan left, SourceSpan right)
- {
- return !left.Equals(right);
- }
-}
\ No newline at end of file
diff --git a/src/Syntax/Syntax.csproj b/src/Syntax/Syntax.csproj
deleted file mode 100644
index 31addee..0000000
--- a/src/Syntax/Syntax.csproj
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- net9.0
- enable
- enable
- true
-
-
-
-
-
-
-
diff --git a/src/Syntax/Tokenization/DocumentationToken.cs b/src/Syntax/Tokenization/DocumentationToken.cs
deleted file mode 100644
index 54a0e51..0000000
--- a/src/Syntax/Tokenization/DocumentationToken.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Syntax.Tokenization;
-
-public class DocumentationToken(SourceSpan span, string documentation) : Token(span)
-{
- public string Documentation { get; } = documentation;
-}
\ No newline at end of file
diff --git a/src/Syntax/Tokenization/IdentifierToken.cs b/src/Syntax/Tokenization/IdentifierToken.cs
deleted file mode 100644
index 7d8c9e7..0000000
--- a/src/Syntax/Tokenization/IdentifierToken.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Syntax.Tokenization;
-
-public class IdentifierToken(SourceSpan span, string value) : Token(span)
-{
- public string Value { get; } = value;
-}
\ No newline at end of file
diff --git a/src/Syntax/Tokenization/LiteralToken.cs b/src/Syntax/Tokenization/LiteralToken.cs
deleted file mode 100644
index f16671e..0000000
--- a/src/Syntax/Tokenization/LiteralToken.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace Syntax.Tokenization;
-
-public class LiteralToken(SourceSpan span, LiteralKind kind, string value) : Token(span)
-{
- public LiteralKind Kind { get; } = kind;
- public string Value { get; } = value;
-}
-
-public enum LiteralKind
-{
- Integer,
- Float,
- String,
- Bool
-}
\ No newline at end of file
diff --git a/src/Syntax/Tokenization/ModifierToken.cs b/src/Syntax/Tokenization/ModifierToken.cs
deleted file mode 100644
index 5312667..0000000
--- a/src/Syntax/Tokenization/ModifierToken.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Syntax.Tokenization;
-
-public class ModifierToken(SourceSpan span, Modifier modifier) : Token(span)
-{
- public Modifier Modifier { get; } = modifier;
-}
-
-public enum Modifier
-{
- Extern,
- Export
-}
\ No newline at end of file
diff --git a/src/Syntax/Tokenization/SymbolToken.cs b/src/Syntax/Tokenization/SymbolToken.cs
deleted file mode 100644
index af31ca0..0000000
--- a/src/Syntax/Tokenization/SymbolToken.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-namespace Syntax.Tokenization;
-
-public class SymbolToken(SourceSpan span, Symbol symbol) : Token(span)
-{
- public Symbol Symbol { get; } = symbol;
-}
-
-public enum Symbol
-{
- Func,
- Return,
- If,
- Else,
- While,
- Break,
- Continue,
- Semicolon,
- Colon,
- OpenParen,
- CloseParen,
- OpenBrace,
- CloseBrace,
- OpenBracket,
- CloseBracket,
- Comma,
- Period,
- Assign,
- Bang,
- Equal,
- NotEqual,
- LessThan,
- LessThanOrEqual,
- GreaterThan,
- GreaterThanOrEqual,
- Plus,
- Minus,
- Star,
- ForwardSlash,
- Struct,
- Caret,
- Ampersand,
- DoubleColon,
- Namespace,
- Let,
- Alloc,
- Calls
-}
\ No newline at end of file
diff --git a/src/Syntax/Tokenization/Token.cs b/src/Syntax/Tokenization/Token.cs
deleted file mode 100644
index 89f3f47..0000000
--- a/src/Syntax/Tokenization/Token.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Syntax.Tokenization;
-
-public abstract class Token(SourceSpan span)
-{
- public SourceSpan Span { get; } = span;
-}
\ No newline at end of file
diff --git a/src/Syntax/Tokenization/Tokenizer.cs b/src/Syntax/Tokenization/Tokenizer.cs
deleted file mode 100644
index 5a3784d..0000000
--- a/src/Syntax/Tokenization/Tokenizer.cs
+++ /dev/null
@@ -1,283 +0,0 @@
-using Common;
-using Syntax.Diagnostics;
-
-namespace Syntax.Tokenization;
-
-public static class Tokenizer
-{
- private static readonly Dictionary Keywords = new()
- {
- ["namespace"] = Symbol.Namespace,
- ["func"] = Symbol.Func,
- ["if"] = Symbol.If,
- ["else"] = Symbol.Else,
- ["while"] = Symbol.While,
- ["break"] = Symbol.Break,
- ["continue"] = Symbol.Continue,
- ["return"] = Symbol.Return,
- ["alloc"] = Symbol.Alloc,
- ["struct"] = Symbol.Struct,
- ["let"] = Symbol.Let,
- ["calls"] = Symbol.Calls,
- };
-
- private static readonly Dictionary Modifiers = new()
- {
- ["export"] = Modifier.Export,
- ["extern"] = Modifier.Extern,
- };
-
- private static readonly Dictionary Chians = new()
- {
- [['=', '=']] = Symbol.Equal,
- [['!', '=']] = Symbol.NotEqual,
- [['<', '=']] = Symbol.LessThanOrEqual,
- [['>', '=']] = Symbol.GreaterThanOrEqual,
- [[':', ':']] = Symbol.DoubleColon,
- };
-
- private static readonly Dictionary Chars = new()
- {
- [';'] = Symbol.Semicolon,
- [':'] = Symbol.Colon,
- ['('] = Symbol.OpenParen,
- [')'] = Symbol.CloseParen,
- ['{'] = Symbol.OpenBrace,
- ['}'] = Symbol.CloseBrace,
- ['['] = Symbol.OpenBracket,
- [']'] = Symbol.CloseBracket,
- [','] = Symbol.Comma,
- ['.'] = Symbol.Period,
- ['='] = Symbol.Assign,
- ['<'] = Symbol.LessThan,
- ['>'] = Symbol.GreaterThan,
- ['+'] = Symbol.Plus,
- ['-'] = Symbol.Minus,
- ['*'] = Symbol.Star,
- ['/'] = Symbol.ForwardSlash,
- ['!'] = Symbol.Bang,
- ['^'] = Symbol.Caret,
- ['&'] = Symbol.Ampersand,
- };
-
- private static SourceText _sourceText;
- private static int _index;
-
- public static IEnumerable Tokenize(SourceText sourceText, out IEnumerable diagnostics)
- {
- _sourceText = sourceText;
- _index = 0;
-
- List tokens = [];
- while (ParseToken().TryGetValue(out var token))
- {
- tokens.Add(token);
- }
-
- // TODO: Implement diagnostics
- diagnostics = [];
- return tokens;
- }
-
- private static void ConsumeWhitespace()
- {
- while (Peek().TryGetValue(out var character) && char.IsWhiteSpace(character))
- {
- Next();
- }
- }
-
- private static Optional ParseToken()
- {
- ConsumeWhitespace();
- var startIndex = _index;
-
- if (!Peek().TryGetValue(out var current))
- {
- return Optional.Empty();
- }
-
- if (current == '/' && Peek(1).TryGetValue(out var nextChar) && nextChar == '/')
- {
- Next();
- Next();
-
- if (Peek().TryGetValue(out var thirdChar) && thirdChar == '/')
- {
- Next();
- var buffer = string.Empty;
- while (Peek().TryGetValue(out var character) && character != '\n')
- {
- buffer += character;
- Next();
- }
-
- Next();
- return new DocumentationToken(CreateSpan(startIndex), buffer);
- }
-
- while (Peek().TryGetValue(out var character) && character != '\n')
- {
- Next();
- }
-
- Next();
- return ParseToken();
- }
-
- if (char.IsLetter(current) || current == '_')
- {
- var buffer = string.Empty;
-
- while (Peek().TryGetValue(out var next) && (char.IsLetterOrDigit(next) || next == '_'))
- {
- buffer += next;
- Next();
- }
-
- if (Keywords.TryGetValue(buffer, out var keywordSymbol))
- {
- return new SymbolToken(CreateSpan(startIndex), keywordSymbol);
- }
-
- if (Modifiers.TryGetValue(buffer, out var modifer))
- {
- return new ModifierToken(CreateSpan(startIndex), modifer);
- }
-
- if (buffer is "true" or "false")
- {
- return new LiteralToken(CreateSpan(startIndex), LiteralKind.Bool, buffer);
- }
-
- return new IdentifierToken(CreateSpan(startIndex), buffer);
- }
-
- if (char.IsDigit(current))
- {
- var isFloat = false;
- var buffer = string.Empty;
-
- while (Peek().TryGetValue(out var next))
- {
- if (next == '.')
- {
- if (isFloat)
- {
- throw new Exception("More than one period found in float literal");
- }
-
- isFloat = true;
- buffer += next;
- Next();
- }
- else if (char.IsDigit(next))
- {
- buffer += next;
- Next();
- }
- else
- {
- break;
- }
- }
-
- return new LiteralToken(CreateSpan(startIndex), isFloat ? LiteralKind.Float : LiteralKind.Integer, buffer);
- }
-
- // TODO: Revisit this
- foreach (var chain in Chians)
- {
- if (current != chain.Key[0]) continue;
-
- for (var i = 1; i < chain.Key.Length; i++)
- {
- var c = Peek(i);
- if (!c.HasValue || c.Value != chain.Key[i]) break;
-
- if (i == chain.Key.Length - 1)
- {
- for (var j = 0; j <= i; j++)
- {
- Next();
- }
-
- return new SymbolToken(CreateSpan(startIndex), chain.Value);
- }
- }
- }
-
- if (Chars.TryGetValue(current, out var charSymbol))
- {
- Next();
- return new SymbolToken(CreateSpan(startIndex), charSymbol);
- }
-
- if (current == '"')
- {
- Next();
- var buffer = string.Empty;
-
- while (true)
- {
- if (!Peek().TryGetValue(out var next))
- {
- throw new Exception("Unclosed string literal");
- }
-
- if (next == '"')
- {
- Next();
- break;
- }
-
- buffer += next;
- Next();
- }
-
- return new LiteralToken(CreateSpan(startIndex), LiteralKind.String, buffer);
- }
-
- throw new Exception($"Unknown character {current}");
- }
-
- private static SourceLocation CreateLocation(int index)
- {
- var line = 1;
- var column = 1;
- for (var i = 0; i < Math.Min(index, _sourceText.Content.Length - 1); i++)
- {
- if (_sourceText.Content[i] == '\n')
- {
- column = 1;
- line += 1;
- }
- else
- {
- column += 1;
- }
- }
-
- return new SourceLocation(line, column);
- }
-
- private static SourceSpan CreateSpan(int startIndex)
- {
- return new SourceSpan(_sourceText, CreateLocation(startIndex), CreateLocation(_index));
- }
-
- private static Optional Peek(int offset = 0)
- {
- if (_index + offset < _sourceText.Content.Length)
- {
- return _sourceText.Content[_index + offset];
- }
-
- return Optional.Empty();
- }
-
- private static void Next()
- {
- _index++;
- }
-}
\ No newline at end of file
diff --git a/src/Syntax/Typing/Binder.cs b/src/Syntax/Typing/Binder.cs
deleted file mode 100644
index 306d40f..0000000
--- a/src/Syntax/Typing/Binder.cs
+++ /dev/null
@@ -1,463 +0,0 @@
-using Common;
-using Syntax.Parsing;
-using Syntax.Parsing.Node;
-using Syntax.Tokenization;
-using Syntax.Typing.BoundNode;
-using UnaryExpressionNode = Syntax.Parsing.Node.UnaryExpressionNode;
-
-namespace Syntax.Typing;
-
-// TODO: Currently anonymous function does not get a new scope
-public static class Binder
-{
- private static SyntaxTree _syntaxTree = null!;
- private static DefinitionTable _definitionTable = null!;
-
- private static Dictionary _variables = new();
- private static NubType? _funcReturnType;
-
- public static BoundSyntaxTree Bind(SyntaxTree syntaxTree, DefinitionTable definitionTable)
- {
- _syntaxTree = syntaxTree;
- _definitionTable = definitionTable;
-
- _variables = [];
- _funcReturnType = null;
-
- var definitions = new List();
-
- foreach (var definition in syntaxTree.Definitions)
- {
- definitions.Add(BindDefinition(definition));
- }
-
- return new BoundSyntaxTree(syntaxTree.FilePath, syntaxTree.Namespace, definitions);
- }
-
- private static BoundDefinitionNode BindDefinition(DefinitionNode node)
- {
- return node switch
- {
- ExternFuncDefinitionNode definition => BindExternFuncDefinition(definition),
- LocalFuncDefinitionNode definition => BindLocalFuncDefinition(definition),
- StructDefinitionNode definition => BindStruct(definition),
- _ => throw new ArgumentOutOfRangeException(nameof(node))
- };
- }
-
- private static BoundStructDefinitionNode BindStruct(StructDefinitionNode node)
- {
- var defOpt = _definitionTable.LookupStruct(node.Namespace, node.Name);
- if (!defOpt.TryGetValue(out var definition))
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- var structFields = new List();
-
- foreach (var structField in node.Fields)
- {
- var value = Optional.Empty();
-
- if (structField.Value.HasValue)
- {
- var definitionField = definition.Fields.FirstOrDefault(f => f.Name == structField.Name);
- if (definitionField == null)
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- value = BindExpression(structField.Value.Value, definitionField.Type);
- }
-
- structFields.Add(new BoundStructField(structField.Name, structField.Type, value));
- }
-
- return new BoundStructDefinitionNode(node.Tokens, node.Documentation, node.Namespace, node.Name, structFields);
- }
-
- private static BoundExternFuncDefinitionNode BindExternFuncDefinition(ExternFuncDefinitionNode node)
- {
- var parameters = new List();
-
- foreach (var parameter in node.Parameters)
- {
- parameters.Add(new BoundFuncParameter(parameter.Name, parameter.Type));
- }
-
- return new BoundExternFuncDefinitionNode(node.Tokens, node.Documentation, node.Namespace, node.Name, node.CallName, parameters, node.ReturnType);
- }
-
- private static BoundLocalFuncDefinitionNode BindLocalFuncDefinition(LocalFuncDefinitionNode node)
- {
- _variables.Clear();
- _funcReturnType = node.ReturnType;
-
- var parameters = new List();
-
- foreach (var parameter in node.Parameters)
- {
- parameters.Add(new BoundFuncParameter(parameter.Name, parameter.Type));
- _variables[parameter.Name] = parameter.Type;
- }
-
- var body = BindBlock(node.Body);
-
- return new BoundLocalFuncDefinitionNode(node.Tokens, node.Documentation, node.Namespace, node.Name, parameters, body, node.ReturnType, node.Exported);
- }
-
- private static BoundBlockNode BindBlock(BlockNode node)
- {
- var statements = new List();
-
- foreach (var statement in node.Statements)
- {
- statements.Add(BindStatement(statement));
- }
-
- return new BoundBlockNode(node.Tokens, statements);
- }
-
- private static BoundStatementNode BindStatement(StatementNode node)
- {
- return node switch
- {
- ArrayIndexAssignmentNode statement => BindArrayIndex(statement),
- BreakNode statement => BindBreak(statement),
- ContinueNode statement => BindContinue(statement),
- DereferenceAssignmentNode statement => BindDereferenceAssignment(statement),
- IfNode statement => BindIf(statement),
- MemberAssignmentNode statement => BindMemberAssignment(statement),
- ReturnNode statement => BindReturn(statement),
- StatementExpressionNode statement => BindStatementExpression(statement),
- VariableAssignmentNode statement => BindVariableAssignment(statement),
- VariableDeclarationNode statement => BindVariableDeclaration(statement),
- WhileNode statement => BindWhile(statement),
- _ => throw new ArgumentOutOfRangeException(nameof(node))
- };
- }
-
- private static BoundArrayIndexAssignmentNode BindArrayIndex(ArrayIndexAssignmentNode statement)
- {
- var boundArrayIndex = BindArrayIndexAccess(statement.ArrayIndexAccess);
- var elementType = ((NubArrayType)boundArrayIndex.Type).ElementType;
- return new BoundArrayIndexAssignmentNode(statement.Tokens, boundArrayIndex, BindExpression(statement.Value, elementType));
- }
-
- private static BoundBreakNode BindBreak(BreakNode statement)
- {
- return new BoundBreakNode(statement.Tokens);
- }
-
- private static BoundContinueNode BindContinue(ContinueNode statement)
- {
- return new BoundContinueNode(statement.Tokens);
- }
-
- private static BoundDereferenceAssignmentNode BindDereferenceAssignment(DereferenceAssignmentNode statement)
- {
- var boundDereference = BindDereference(statement.Dereference);
- var dereferenceBaseType = ((NubPointerType)boundDereference.Type).BaseType;
- return new BoundDereferenceAssignmentNode(statement.Tokens, boundDereference, BindExpression(statement.Value, dereferenceBaseType));
- }
-
- private static BoundIfNode BindIf(IfNode statement)
- {
- var elseStatement = Optional.Empty>();
-
- if (statement.Else.HasValue)
- {
- elseStatement = statement.Else.Value.Match>
- (
- elseIf => BindIf(elseIf),
- @else => BindBlock(@else)
- );
- }
-
- return new BoundIfNode(statement.Tokens, BindExpression(statement.Condition, NubPrimitiveType.Bool), BindBlock(statement.Body), elseStatement);
- }
-
- private static BoundMemberAssignmentNode BindMemberAssignment(MemberAssignmentNode statement)
- {
- var boundMemberAccess = BindMemberAccess(statement.MemberAccess);
- var elementType = ((NubArrayType)boundMemberAccess.Type).ElementType;
- return new BoundMemberAssignmentNode(statement.Tokens, boundMemberAccess, BindExpression(statement.Value, elementType));
- }
-
- private static BoundReturnNode BindReturn(ReturnNode statement)
- {
- var value = Optional.Empty();
-
- if (statement.Value.HasValue)
- {
- value = BindExpression(statement.Value.Value, _funcReturnType);
- }
-
- return new BoundReturnNode(statement.Tokens, value);
- }
-
- private static BoundStatementExpressionNode BindStatementExpression(StatementExpressionNode statement)
- {
- return new BoundStatementExpressionNode(statement.Tokens, BindExpression(statement.Expression));
- }
-
- private static BoundVariableAssignmentNode BindVariableAssignment(VariableAssignmentNode statement)
- {
- var variableType = _variables[statement.Identifier.Name];
- return new BoundVariableAssignmentNode(statement.Tokens, BindIdentifier(statement.Identifier), BindExpression(statement.Value, variableType));
- }
-
- private static BoundVariableDeclarationNode BindVariableDeclaration(VariableDeclarationNode statement)
- {
- _variables[statement.Name] = statement.Type;
- return new BoundVariableDeclarationNode(statement.Tokens, statement.Name, statement.Type);
- }
-
- private static BoundWhileNode BindWhile(WhileNode statement)
- {
- return new BoundWhileNode(statement.Tokens, BindExpression(statement.Condition, NubPrimitiveType.Bool), BindBlock(statement.Body));
- }
-
- private static BoundExpressionNode BindExpression(ExpressionNode node, NubType? expectedType = null)
- {
- return node switch
- {
- AddressOfNode expression => BindAddressOf(expression),
- AnonymousFuncNode expression => BindAnonymousFunc(expression),
- ArrayIndexAccessNode expression => BindArrayIndexAccess(expression),
- ArrayInitializerNode expression => BindArrayInitializer(expression),
- BinaryExpressionNode expression => BindBinaryExpression(expression),
- DereferenceNode expression => BindDereference(expression),
- FixedArrayInitializerNode expression => BindFixedArrayInitializer(expression),
- FuncCallNode expression => BindFuncCall(expression),
- IdentifierNode expression => BindIdentifier(expression),
- LiteralNode expression => BindLiteral(expression, expectedType),
- MemberAccessNode expression => BindMemberAccess(expression),
- StructInitializerNode expression => BindStructInitializer(expression),
- UnaryExpressionNode expression => BindUnaryExpression(expression),
- _ => throw new ArgumentOutOfRangeException(nameof(node))
- };
- }
-
- private static BoundAddressOfNode BindAddressOf(AddressOfNode expression)
- {
- var inner = (BoundLValueNode)BindExpression(expression.Expression);
- return new BoundAddressOfNode(expression.Tokens, new NubPointerType(inner.Type), inner);
- }
-
- private static BoundAnonymousFuncNode BindAnonymousFunc(AnonymousFuncNode expression)
- {
- var parameters = new List();
- var parameterTypes = new List();
-
- foreach (var parameter in expression.Parameters)
- {
- var boundParameter = new BoundFuncParameter(parameter.Name, parameter.Type);
- parameters.Add(boundParameter);
- parameterTypes.Add(boundParameter.Type);
- }
-
- var body = BindBlock(expression.Body);
-
- return new BoundAnonymousFuncNode(expression.Tokens, new NubFuncType(expression.ReturnType, parameterTypes), parameters, body, expression.ReturnType);
- }
-
- private static BoundArrayIndexAccessNode BindArrayIndexAccess(ArrayIndexAccessNode expression)
- {
- var boundArray = BindExpression(expression.Array);
- var elementType = ((NubArrayType)boundArray.Type).ElementType;
- return new BoundArrayIndexAccessNode(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, NubPrimitiveType.U64));
- }
-
- private static BoundArrayInitializerNode BindArrayInitializer(ArrayInitializerNode expression)
- {
- return new BoundArrayInitializerNode(expression.Tokens, new NubArrayType(expression.ElementType), BindExpression(expression.Capacity, NubPrimitiveType.U64),
- expression.ElementType);
- }
-
- private static BoundBinaryExpressionNode BindBinaryExpression(BinaryExpressionNode expression)
- {
- var boundLeft = BindExpression(expression.Left);
- var boundRight = BindExpression(expression.Right, boundLeft.Type);
- return new BoundBinaryExpressionNode(expression.Tokens, boundLeft.Type, boundLeft, expression.Operator, boundRight);
- }
-
- private static BoundDereferenceNode BindDereference(DereferenceNode expression)
- {
- var boundExpression = BindExpression(expression.Expression);
- var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType;
- return new BoundDereferenceNode(expression.Tokens, dereferencedType, boundExpression);
- }
-
- private static BoundFixedArrayInitializerNode BindFixedArrayInitializer(FixedArrayInitializerNode expression)
- {
- return new BoundFixedArrayInitializerNode(expression.Tokens, new NubArrayType(expression.ElementType), expression.ElementType, expression.Capacity);
- }
-
- private static BoundFuncCallNode BindFuncCall(FuncCallNode expression)
- {
- var boundExpression = BindExpression(expression.Expression);
-
- var funcType = (NubFuncType)boundExpression.Type;
- var returnType = ((NubFuncType)boundExpression.Type).ReturnType;
-
- var parameters = new List();
-
- foreach (var (i, parameter) in expression.Parameters.Index())
- {
- if (i >= funcType.Parameters.Count)
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- var expectedType = funcType.Parameters[i];
-
- parameters.Add(BindExpression(parameter, expectedType));
- }
-
- return new BoundFuncCallNode(expression.Tokens, returnType, boundExpression, parameters);
- }
-
- private static BoundIdentifierNode BindIdentifier(IdentifierNode expression)
- {
- NubType? type = null;
-
- var definition = _definitionTable.LookupFunc(expression.Namespace.Or(_syntaxTree.Namespace), expression.Name);
- if (definition.HasValue)
- {
- type = new NubFuncType(definition.Value.ReturnType, definition.Value.Parameters.Select(p => p.Type).ToList());
- }
-
- if (type == null && !expression.Namespace.HasValue)
- {
- type = _variables[expression.Name];
- }
-
- if (type == null)
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- return new BoundIdentifierNode(expression.Tokens, type, expression.Namespace, expression.Name);
- }
-
- private static BoundLiteralNode BindLiteral(LiteralNode expression, NubType? expectedType = null)
- {
- var type = expectedType ?? expression.Kind switch
- {
- LiteralKind.Integer => NubPrimitiveType.I64,
- LiteralKind.Float => NubPrimitiveType.F64,
- LiteralKind.String => new NubStringType(),
- LiteralKind.Bool => NubPrimitiveType.Bool,
- _ => throw new ArgumentOutOfRangeException()
- };
-
- return new BoundLiteralNode(expression.Tokens, type, expression.Literal, expression.Kind);
- }
-
- private static BoundMemberAccessNode BindMemberAccess(MemberAccessNode expression)
- {
- var boundExpression = BindExpression(expression.Expression);
-
- NubType? type = null;
-
- switch (boundExpression.Type)
- {
- case NubArrayType:
- case NubStringType:
- case NubCStringType:
- {
- if (expression.Member == "count")
- {
- type = NubPrimitiveType.U64;
- }
-
- break;
- }
- case NubStructType structType:
- {
- var defOpt = _definitionTable.LookupStruct(structType.Namespace, structType.Name);
- if (!defOpt.TryGetValue(out var definition))
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- var field = definition.Fields.FirstOrDefault(f => f.Name == expression.Member);
- if (field == null)
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- type = field.Type;
- break;
- }
- }
-
- if (type == null)
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- return new BoundMemberAccessNode(expression.Tokens, type, boundExpression, expression.Member);
- }
-
- private static BoundStructInitializerNode BindStructInitializer(StructInitializerNode expression)
- {
- var defOpt = _definitionTable.LookupStruct(expression.StructType.Namespace, expression.StructType.Name);
- if (!defOpt.TryGetValue(out var definition))
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- var initializers = new Dictionary();
-
- foreach (var (member, initializer) in expression.Initializers)
- {
- var definitionField = definition.Fields.FirstOrDefault(x => x.Name == member);
- if (definitionField == null)
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- initializers[member] = BindExpression(initializer, definitionField.Type);
- }
-
- return new BoundStructInitializerNode(expression.Tokens, expression.StructType, expression.StructType, initializers);
- }
-
- private static BoundUnaryExpressionNode BindUnaryExpression(UnaryExpressionNode expression)
- {
- var boundOperand = BindExpression(expression.Operand);
-
- NubType? type = null;
-
- switch (expression.Operator)
- {
- case UnaryExpressionOperator.Negate:
- {
- boundOperand = BindExpression(expression.Operand, NubPrimitiveType.I64);
-
- if (boundOperand.Type.IsNumber)
- {
- type = boundOperand.Type;
- }
-
- break;
- }
- case UnaryExpressionOperator.Invert:
- {
- boundOperand = BindExpression(expression.Operand, NubPrimitiveType.Bool);
-
- type = new NubPrimitiveType(PrimitiveTypeKind.Bool);
- break;
- }
- }
-
- if (type == null)
- {
- throw new NotImplementedException("Diagnostics not implemented");
- }
-
- return new BoundUnaryExpressionNode(expression.Tokens, type, expression.Operator, boundOperand);
- }
-}
\ No newline at end of file
diff --git a/src/Syntax/Typing/BoundNode/Definition.cs b/src/Syntax/Typing/BoundNode/Definition.cs
deleted file mode 100644
index fcfa22c..0000000
--- a/src/Syntax/Typing/BoundNode/Definition.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Common;
-using Syntax.Tokenization;
-
-namespace Syntax.Typing.BoundNode;
-
-public abstract record BoundDefinitionNode(IEnumerable Tokens, Optional Documentation, string Namespace) : BoundNode(Tokens);
-
-public record BoundFuncParameter(string Name, NubType Type);
-public abstract record BoundFuncDefinition(IEnumerable Tokens, Optional Documentation, string Namespace, string Name, List Parameters, NubType ReturnType) : BoundDefinitionNode(Tokens, Documentation, Namespace);
-public record BoundLocalFuncDefinitionNode(IEnumerable Tokens, Optional Documentation, string Namespace, string Name, List Parameters, BoundBlockNode Body, NubType ReturnType, bool Exported) : BoundFuncDefinition(Tokens, Documentation, Namespace, Name, Parameters, ReturnType);
-public record BoundExternFuncDefinitionNode(IEnumerable Tokens, Optional Documentation, string Namespace, string Name, string CallName, List Parameters, NubType ReturnType) : BoundFuncDefinition(Tokens, Documentation, Namespace, Name, Parameters, ReturnType);
-
-public record BoundStructField(string Name, NubType Type, Optional Value);
-public record BoundStructDefinitionNode(IEnumerable Tokens, Optional Documentation, string Namespace, string Name, List Fields) : BoundDefinitionNode(Tokens, Documentation, Namespace);
diff --git a/src/Syntax/Typing/BoundNode/Expression.cs b/src/Syntax/Typing/BoundNode/Expression.cs
deleted file mode 100644
index f6f204f..0000000
--- a/src/Syntax/Typing/BoundNode/Expression.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Common;
-using Syntax.Parsing.Node;
-using Syntax.Tokenization;
-
-namespace Syntax.Typing.BoundNode;
-
-public abstract record BoundExpressionNode(IEnumerable Tokens, NubType Type) : BoundNode(Tokens);
-public abstract record BoundLValueNode(IEnumerable Tokens, NubType Type) : BoundExpressionNode(Tokens, Type);
-public record BoundBinaryExpressionNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Left, BinaryExpressionOperator Operator, BoundExpressionNode Right) : BoundExpressionNode(Tokens, Type);
-public record BoundUnaryExpressionNode(IEnumerable Tokens, NubType Type, UnaryExpressionOperator Operator, BoundExpressionNode Operand) : BoundExpressionNode(Tokens, Type);
-public record BoundFuncCallNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression, List Parameters) : BoundExpressionNode(Tokens, Type);
-public record BoundIdentifierNode(IEnumerable Tokens, NubType Type, Optional Namespace, string Name) : BoundLValueNode(Tokens, Type);
-public record BoundArrayInitializerNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Capacity, NubType ElementType) : BoundExpressionNode(Tokens, Type);
-public record BoundArrayIndexAccessNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Array, BoundExpressionNode Index) : BoundLValueNode(Tokens, Type);
-public record BoundAnonymousFuncNode(IEnumerable Tokens, NubType Type, List Parameters, BoundBlockNode Body, NubType ReturnType) : BoundExpressionNode(Tokens, Type);
-public record BoundAddressOfNode(IEnumerable Tokens, NubType Type, BoundLValueNode Expression) : BoundExpressionNode(Tokens, Type);
-public record BoundFixedArrayInitializerNode(IEnumerable Tokens, NubType Type, NubType ElementType, int Capacity) : BoundExpressionNode(Tokens, Type);
-public record BoundLiteralNode(IEnumerable Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type);
-public record BoundMemberAccessNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression, string Member) : BoundExpressionNode(Tokens, Type);
-public record BoundStructInitializerNode(IEnumerable Tokens, NubType Type, NubStructType StructType, Dictionary Initializers) : BoundExpressionNode(Tokens, Type);
-public record BoundDereferenceNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression) : BoundLValueNode(Tokens, Type);
diff --git a/src/Syntax/Typing/BoundNode/Node.cs b/src/Syntax/Typing/BoundNode/Node.cs
deleted file mode 100644
index 6030c31..0000000
--- a/src/Syntax/Typing/BoundNode/Node.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using Syntax.Tokenization;
-
-namespace Syntax.Typing.BoundNode;
-
-public abstract record BoundNode(IEnumerable Tokens);
-public record BoundBlockNode(IEnumerable Tokens, List Statements) : BoundNode(Tokens);
diff --git a/src/Syntax/Typing/BoundNode/Statement.cs b/src/Syntax/Typing/BoundNode/Statement.cs
deleted file mode 100644
index 151626a..0000000
--- a/src/Syntax/Typing/BoundNode/Statement.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Common;
-using Syntax.Tokenization;
-
-namespace Syntax.Typing.BoundNode;
-
-public record BoundStatementNode(IEnumerable Tokens) : BoundNode(Tokens);
-public record BoundStatementExpressionNode(IEnumerable Tokens, BoundExpressionNode Expression) : BoundStatementNode(Tokens);
-public record BoundReturnNode(IEnumerable Tokens, Optional Value) : BoundStatementNode(Tokens);
-public record BoundMemberAssignmentNode(IEnumerable Tokens, BoundMemberAccessNode MemberAccess, BoundExpressionNode Value) : BoundStatementNode(Tokens);
-public record BoundIfNode(IEnumerable Tokens, BoundExpressionNode Condition, BoundBlockNode Body, Optional> Else) : BoundStatementNode(Tokens);
-public record BoundDereferenceAssignmentNode(IEnumerable Tokens, BoundDereferenceNode Dereference, BoundExpressionNode Value) : BoundStatementNode(Tokens);
-public record BoundVariableAssignmentNode(IEnumerable Tokens, BoundIdentifierNode Identifier, BoundExpressionNode Value) : BoundStatementNode(Tokens);
-public record BoundVariableDeclarationNode(IEnumerable Tokens, string Name, NubType Type) : BoundStatementNode(Tokens);
-public record BoundContinueNode(IEnumerable Tokens) : BoundStatementNode(Tokens);
-public record BoundBreakNode(IEnumerable Tokens) : BoundStatementNode(Tokens);
-public record BoundArrayIndexAssignmentNode(IEnumerable Tokens, BoundArrayIndexAccessNode ArrayIndexAccess, BoundExpressionNode Value) : BoundStatementNode(Tokens);
-public record BoundWhileNode(IEnumerable Tokens, BoundExpressionNode Condition, BoundBlockNode Body) : BoundStatementNode(Tokens);
diff --git a/src/Syntax/Typing/BoundSyntaxTree.cs b/src/Syntax/Typing/BoundSyntaxTree.cs
deleted file mode 100644
index 0dd20b5..0000000
--- a/src/Syntax/Typing/BoundSyntaxTree.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-using Syntax.Typing.BoundNode;
-
-namespace Syntax.Typing;
-
-public record BoundSyntaxTree(string FilePath, string Namespace, List Definitions);
diff --git a/src/Syntax/Typing/NubType.cs b/src/Syntax/Typing/NubType.cs
deleted file mode 100644
index 1c89f69..0000000
--- a/src/Syntax/Typing/NubType.cs
+++ /dev/null
@@ -1,303 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-
-namespace Syntax.Typing;
-
-public abstract class NubType
-{
- public bool IsInteger => this is NubPrimitiveType
- {
- Kind: PrimitiveTypeKind.I8
- or PrimitiveTypeKind.I16
- or PrimitiveTypeKind.I32
- or PrimitiveTypeKind.I64
- or PrimitiveTypeKind.U8
- or PrimitiveTypeKind.U16
- or PrimitiveTypeKind.U32
- or PrimitiveTypeKind.U64
- };
-
- public bool IsFloat32 => this is NubPrimitiveType
- {
- Kind: PrimitiveTypeKind.F32
- };
-
- public bool IsFloat64 => this is NubPrimitiveType
- {
- Kind: PrimitiveTypeKind.F64
- };
-
- public bool IsNumber => IsFloat32 || IsFloat64 || IsInteger;
-
- public bool IsVoid => this is NubVoidType;
-
- public bool IsString => this is NubStringType;
-
- public bool IsCString => this is NubCStringType;
-
- public bool IsBool => this is NubPrimitiveType
- {
- Kind: PrimitiveTypeKind.Bool
- };
-
- public abstract override bool Equals(object? obj);
- public abstract override int GetHashCode();
- public abstract override string ToString();
-}
-
-public class NubCStringType : NubType
-{
- public override bool Equals(object? obj)
- {
- return obj is NubCStringType;
- }
-
- public override int GetHashCode()
- {
- return "cstring".GetHashCode();
- }
-
- public override string ToString()
- {
- return "cstring";
- }
-}
-
-public class NubStringType : NubType
-{
- public override bool Equals(object? obj)
- {
- return obj is NubStringType;
- }
-
- public override int GetHashCode()
- {
- return "string".GetHashCode();
- }
-
- public override string ToString()
- {
- return "string";
- }
-}
-
-public class NubFuncType(NubType returnType, List parameters) : NubType
-{
- public NubType ReturnType { get; } = returnType;
- public List Parameters { get; } = parameters;
-
- public override bool Equals(object? obj)
- {
- return obj is NubFuncType other && other.ReturnType.Equals(ReturnType) && other.Parameters.SequenceEqual(Parameters);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(ReturnType, Parameters);
- }
-
- public override string ToString()
- {
- return $"func({string.Join(", ", Parameters)}): {ReturnType}";
- }
-}
-
-public class NubStructType(string @namespace, string name) : NubType
-{
- public string Namespace { get; } = @namespace;
- public string Name { get; } = name;
-
- public override bool Equals(object? obj)
- {
- return obj is NubStructType other && other.Namespace == Namespace && other.Name == Name;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Namespace, Name);
- }
-
- public override string ToString()
- {
- return $"{Namespace}::{Name}";
- }
-}
-
-public class NubPointerType(NubType baseType) : NubType
-{
- public NubType BaseType { get; } = baseType;
-
- public override bool Equals(object? obj)
- {
- return obj is NubPointerType other && BaseType.Equals(other.BaseType);
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(BaseType);
- }
-
- public override string ToString()
- {
- return "^" + BaseType;
- }
-}
-
-public class NubArrayType(NubType elementType) : NubType
-{
- public NubType ElementType { get; } = elementType;
-
- public override bool Equals(object? obj)
- {
- if (obj is NubArrayType other)
- {
- return ElementType.Equals(other.ElementType);
- }
- return false;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(ElementType);
- }
-
- public override string ToString()
- {
- return "[]" + ElementType;
- }
-}
-
-public class NubFixedArrayType(NubType elementType, int capacity) : NubType
-{
- public NubType ElementType { get; } = elementType;
- public int Capacity { get; } = capacity;
-
- public override string ToString() => $"[{Capacity}]{ElementType}";
-
- public override bool Equals(object? obj)
- {
- return obj is NubFixedArrayType other && ElementType.Equals(other.ElementType) && Capacity == other.Capacity;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(ElementType, Capacity);
- }
-}
-
-public class NubAnyType : NubType
-{
- public override string ToString() => "any";
-
- public override bool Equals(object? obj)
- {
- return obj is NubAnyType;
- }
-
- public override int GetHashCode()
- {
- return "any".GetHashCode();
- }
-}
-
-public class NubVoidType : NubType
-{
- public override string ToString() => "void";
-
- public override bool Equals(object? obj)
- {
- return obj is NubVoidType;
- }
-
- public override int GetHashCode()
- {
- return GetType().GetHashCode();
- }
-}
-
-public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType
-{
- public PrimitiveTypeKind Kind { get; } = kind;
-
- public static NubPrimitiveType I64 => new(PrimitiveTypeKind.I64);
- public static NubPrimitiveType I32 => new(PrimitiveTypeKind.I32);
- public static NubPrimitiveType I16 => new(PrimitiveTypeKind.I16);
- public static NubPrimitiveType I8 => new(PrimitiveTypeKind.I8);
-
- public static NubPrimitiveType U64 => new(PrimitiveTypeKind.U64);
- public static NubPrimitiveType U32 => new(PrimitiveTypeKind.U32);
- public static NubPrimitiveType U16 => new(PrimitiveTypeKind.U16);
- public static NubPrimitiveType U8 => new(PrimitiveTypeKind.U8);
-
- public static NubPrimitiveType F64 => new(PrimitiveTypeKind.F64);
- public static NubPrimitiveType F32 => new(PrimitiveTypeKind.F32);
-
- public static NubPrimitiveType Bool => new(PrimitiveTypeKind.Bool);
-
- public static bool TryParse(string s, [NotNullWhen(true)] out PrimitiveTypeKind? kind)
- {
- kind = s switch
- {
- "i64" => PrimitiveTypeKind.I64,
- "i32" => PrimitiveTypeKind.I32,
- "i16" => PrimitiveTypeKind.I16,
- "i8" => PrimitiveTypeKind.I8,
- "u64" => PrimitiveTypeKind.U64,
- "u32" => PrimitiveTypeKind.U32,
- "u16" => PrimitiveTypeKind.U16,
- "u8" => PrimitiveTypeKind.U8,
- "f64" => PrimitiveTypeKind.F64,
- "f32" => PrimitiveTypeKind.F32,
- "bool" => PrimitiveTypeKind.Bool,
- _ => null
- };
-
- return kind != null;
- }
-
- public override bool Equals(object? obj)
- {
- return obj is NubPrimitiveType other && other.Kind == Kind;
- }
-
- public override int GetHashCode()
- {
- return HashCode.Combine(Kind);
- }
-
- public override string ToString()
- {
- return Kind switch
- {
- PrimitiveTypeKind.I8 => "i8",
- PrimitiveTypeKind.I16 => "i16",
- PrimitiveTypeKind.I32 => "i32",
- PrimitiveTypeKind.I64 => "i64",
-
- PrimitiveTypeKind.U8 => "u8",
- PrimitiveTypeKind.U16 => "u16",
- PrimitiveTypeKind.U32 => "u32",
- PrimitiveTypeKind.U64 => "u64",
-
- PrimitiveTypeKind.F32 => "f32",
- PrimitiveTypeKind.F64 => "f64",
-
- PrimitiveTypeKind.Bool => "bool",
- _ => throw new ArgumentOutOfRangeException(nameof(kind), Kind, null)
- };
- }
-}
-
-public enum PrimitiveTypeKind
-{
- I64,
- I32,
- I16,
- I8,
- U64,
- U32,
- U16,
- U8,
- F64,
- F32,
- Bool
-}
\ No newline at end of file
diff --git a/src/Syntax/Typing/TypeChecker.cs b/src/Syntax/Typing/TypeChecker.cs
deleted file mode 100644
index e935a2b..0000000
--- a/src/Syntax/Typing/TypeChecker.cs
+++ /dev/null
@@ -1,633 +0,0 @@
-// using System.Diagnostics;
-// using Syntax.Diagnostics;
-// using Syntax.Parsing;
-// using Syntax.Parsing.Node;
-// using Syntax.Tokenization;
-//
-// namespace Syntax.Typing;
-//
-// public static class TypeChecker
-// {
-// private static SyntaxTree _syntaxTree = null!;
-// private static DefinitionTable _definitionTable = null!;
-//
-// private static Dictionary _variables = new();
-// private static List _diagnostics = [];
-// private static NubType? _currentFunctionReturnType;
-// private static Queue _anonymousFunctions = [];
-//
-// public static void Check(SyntaxTree syntaxTree, DefinitionTable definitionTable, out IEnumerable diagnostics)
-// {
-// _syntaxTree = syntaxTree;
-// _definitionTable = definitionTable;
-//
-// _variables = new Dictionary();
-// _diagnostics = [];
-// _currentFunctionReturnType = null;
-// _anonymousFunctions = [];
-//
-// foreach (var structDef in syntaxTree.Definitions.OfType())
-// {
-// CheckStructDef(structDef);
-// }
-//
-// foreach (var funcDef in syntaxTree.Definitions.OfType())
-// {
-// CheckFuncDef(funcDef.Parameters, funcDef.Body, funcDef.ReturnType);
-// }
-//
-// while (_anonymousFunctions.TryDequeue(out var func))
-// {
-// CheckFuncDef(func.Parameters, func.Body, func.ReturnType);
-//
-// }
-//
-// diagnostics = _diagnostics;
-// }
-//
-// private static void CheckStructDef(StructDefinitionNode structDef)
-// {
-// var fields = new Dictionary();
-// foreach (var field in structDef.Fields)
-// {
-// if (fields.ContainsKey(field.Name))
-// {
-// ReportError($"Duplicate field '{field.Name}' in struct '{structDef.Name}'", structDef);
-// continue;
-// }
-//
-// if (field.Value.HasValue)
-// {
-// var fieldType = CheckExpression(field.Value.Value, field.Type);
-// if (fieldType != null && !fieldType.Equals(field.Type))
-// {
-// ReportError("Default field initializer does not match the defined type", field.Value.Value);
-// }
-// }
-//
-// fields[field.Name] = field.Type;
-// }
-// }
-//
-// private static void CheckFuncDef(List parameters, BlockNode body, NubType returnType)
-// {
-// _variables.Clear();
-// _currentFunctionReturnType = returnType;
-//
-// foreach (var param in parameters)
-// {
-// _variables[param.Name] = param.Type;
-// }
-//
-// CheckBlock(body);
-// }
-//
-// private static void CheckBlock(BlockNode block)
-// {
-// foreach (var statement in block.Statements)
-// {
-// CheckStatement(statement);
-// }
-// }
-//
-// private static void CheckStatement(StatementNode statement)
-// {
-// switch (statement)
-// {
-// case ArrayIndexAssignmentNode arrayIndexAssignment:
-// CheckArrayIndexAssignment(arrayIndexAssignment);
-// break;
-// case VariableAssignmentNode variableAssignment:
-// CheckVariableAssignment(variableAssignment);
-// break;
-// case VariableDeclarationNode variableDeclaration:
-// CheckVariableVariableDeclaration(variableDeclaration);
-// break;
-// case IfNode ifNode:
-// CheckIf(ifNode);
-// break;
-// case MemberAssignmentNode memberAssignment:
-// CheckMemberAssignment(memberAssignment);
-// break;
-// case WhileNode whileNode:
-// CheckWhile(whileNode);
-// break;
-// case ReturnNode returnNode:
-// CheckReturn(returnNode);
-// break;
-// case StatementExpressionNode statementExpression:
-// CheckExpression(statementExpression.Expression);
-// break;
-// case BreakNode:
-// case ContinueNode:
-// break;
-// case DereferenceAssignmentNode dereferenceAssignment:
-// CheckDereferenceAssignment(dereferenceAssignment);
-// break;
-// default:
-// ReportError($"Unsupported statement type: {statement.GetType().Name}", statement);
-// break;
-// }
-// }
-//
-// private static void CheckMemberAssignment(MemberAssignmentNode memberAssignment)
-// {
-// var memberType = CheckExpression(memberAssignment.MemberAccess);
-// if (memberType == null) return;
-// var valueType = CheckExpression(memberAssignment.Value, memberType);
-// if (valueType == null) return;
-//
-// if (!NubType.IsCompatibleWith(memberType, valueType))
-// {
-// ReportError($"'{valueType}' is not assignable to member of type '{memberType}'", memberAssignment);
-// }
-// }
-//
-// private static void CheckArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment)
-// {
-// var itemType = CheckExpression(arrayIndexAssignment.ArrayIndexAccess);
-// if (itemType == null) return;
-// var valueType = CheckExpression(arrayIndexAssignment.Value, itemType);
-// if (valueType == null) return;
-//
-// if (!NubType.IsCompatibleWith(itemType, valueType))
-// {
-// ReportError($"'{valueType}' is not assignable to array of type '{itemType}'", arrayIndexAssignment);
-// }
-// }
-//
-// private static void CheckVariableAssignment(VariableAssignmentNode variableAssignment)
-// {
-// if (!_variables.TryGetValue(variableAssignment.Identifier.Name, out var variable))
-// {
-// ReportError($"Variable '{variableAssignment.Identifier}' is not declared", variableAssignment);
-// return;
-// }
-//
-// var valueType = CheckExpression(variableAssignment.Value, variable);
-// if (valueType == null) return;
-//
-// if (!NubType.IsCompatibleWith(variableAssignment.Value.Type, variable))
-// {
-// ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Identifier}' with type '{variable}'", variableAssignment);
-// }
-// }
-//
-// private static void CheckVariableVariableDeclaration(VariableDeclarationNode variableDeclaration)
-// {
-// if (_variables.TryGetValue(variableDeclaration.Name, out var variable))
-// {
-// ReportError($"Cannot redeclare variable '{variable}'", variableDeclaration);
-// }
-//
-// _variables[variableDeclaration.Name] = variableDeclaration.Type;
-// }
-//
-// private static NubType? CheckDereference(DereferenceNode dereference)
-// {
-// var exprType = CheckExpression(dereference.Expression);
-// if (exprType == null) return null;
-//
-// if (exprType is not NubPointerType nubPointerType)
-// {
-// ReportError($"Cannot dereference a non-pointer type {exprType}", dereference);
-// return null;
-// }
-//
-// return nubPointerType.BaseType;
-// }
-//
-// private static NubType CheckFixedInitializerArray(FixedArrayInitializerNode fixedArrayInitializer)
-// {
-// return new NubFixedArrayType(fixedArrayInitializer.ElementType, fixedArrayInitializer.Capacity);
-// }
-//
-// private static NubType? CheckFuncCall(FuncCallNode funcCall)
-// {
-// var identType = CheckExpression(funcCall.Expression);
-// if (identType is not NubFuncType funcType)
-// {
-// ReportError("Cannot call function on non-function type", funcCall);
-// return null;
-// }
-//
-// if (funcCall.Parameters.Count != funcType.Parameters.Count)
-// {
-// ReportError($"{funcType} expects {funcType.Parameters.Count} arguments, but was called with {funcType.Parameters.Count} arguments", funcCall);
-// return null;
-// }
-//
-// for (var i = 0; i < funcCall.Parameters.Count; i++)
-// {
-// var parameter = funcCall.Parameters[i];
-// var parameterType = CheckExpression(parameter);
-// if (parameterType == null) return null;
-//
-// if (!NubType.IsCompatibleWith(parameterType, funcType.Parameters[i]))
-// {
-// ReportError($"'{parameterType}' does not match expected type {funcType.Parameters[i]}", funcCall);
-// return null;
-// }
-// }
-//
-// return funcType.ReturnType;
-// }
-//
-// private static void CheckIf(IfNode ifNode)
-// {
-// var conditionType = CheckExpression(ifNode.Condition, NubPrimitiveType.Bool);
-// if (conditionType != null && !conditionType.Equals(NubPrimitiveType.Bool))
-// {
-// ReportError($"If condition must be a boolean expression, got '{conditionType}'", ifNode.Condition);
-// }
-//
-// CheckBlock(ifNode.Body);
-//
-// if (ifNode.Else.HasValue)
-// {
-// var elseValue = ifNode.Else.Value;
-// elseValue.Match(CheckIf, CheckBlock);
-// }
-// }
-//
-// private static void CheckWhile(WhileNode whileNode)
-// {
-// var conditionType = CheckExpression(whileNode.Condition, NubPrimitiveType.Bool);
-// if (conditionType != null && !conditionType.Equals(NubPrimitiveType.Bool))
-// {
-// ReportError($"While condition must be a boolean expression, got '{conditionType}'", whileNode.Condition);
-// }
-//
-// CheckBlock(whileNode.Body);
-// }
-//
-// private static void CheckReturn(ReturnNode returnNode)
-// {
-// if (returnNode.Value.HasValue)
-// {
-// var returnType = CheckExpression(returnNode.Value.Value, _currentFunctionReturnType);
-// if (returnType == null) return;
-//
-// if (_currentFunctionReturnType == null)
-// {
-// ReportError("Cannot return a value from a function with no return type", returnNode.Value.Value);
-// return;
-// }
-//
-// if (!NubType.IsCompatibleWith(returnType, _currentFunctionReturnType))
-// {
-// ReportError($"Return value of type '{returnType}' is not compatible with function return type '{_currentFunctionReturnType}'", returnNode.Value.Value);
-// }
-// }
-// else if (_currentFunctionReturnType != null)
-// {
-// ReportError($"Function must return a value of type '{_currentFunctionReturnType}'", returnNode);
-// }
-// }
-//
-// private static void CheckDereferenceAssignment(DereferenceAssignmentNode dereferenceAssignment)
-// {
-// var dereferenceType = CheckExpression(dereferenceAssignment.Dereference);
-// if (dereferenceType == null) return;
-// var valueType = CheckExpression(dereferenceAssignment.Value, dereferenceType);
-// if (valueType == null) return;
-//
-// if (!NubType.IsCompatibleWith(dereferenceType, valueType))
-// {
-// ReportError($"'{valueType}' is not assignable to type '{dereferenceType}'", dereferenceAssignment);
-// }
-// }
-//
-// private static NubType? CheckExpression(ExpressionNode expression, NubType? expectedType = null)
-// {
-// var resultType = expression switch
-// {
-// AddressOfNode addressOf => CheckAddressOf(addressOf),
-// AnonymousFuncNode anonymousFunc => CheckAnonymousFunc(anonymousFunc),
-// ArrayIndexAccessNode arrayIndex => CheckArrayIndex(arrayIndex),
-// ArrayInitializerNode arrayInitializer => CheckArrayInitializer(arrayInitializer),
-// LiteralNode literal => CheckLiteral(literal, expectedType),
-// IdentifierNode identifier => CheckIdentifier(identifier),
-// BinaryExpressionNode binaryExpr => CheckBinaryExpression(binaryExpr),
-// DereferenceNode dereference => CheckDereference(dereference),
-// FixedArrayInitializerNode fixedArray => CheckFixedInitializerArray(fixedArray),
-// FuncCallNode funcCallExpr => CheckFuncCall(funcCallExpr),
-// StructInitializerNode structInit => CheckStructInitializer(structInit),
-// UnaryExpressionNode unaryExpression => CheckUnaryExpression(unaryExpression),
-// MemberAccessNode memberAccess => CheckMemberAccess(memberAccess),
-// _ => throw new UnreachableException()
-// };
-//
-// if (resultType != null)
-// {
-// expression.Type = resultType;
-// }
-//
-// return resultType;
-// }
-//
-// private static NubType CheckAnonymousFunc(AnonymousFuncNode anonymousFunc)
-// {
-// _anonymousFunctions.Enqueue(anonymousFunc);
-// return new NubFuncType(anonymousFunc.ReturnType, anonymousFunc.Parameters.Select(p => p.Type).ToList());
-// }
-//
-// private static NubType? CheckLiteral(LiteralNode literal, NubType? expectedType = null)
-// {
-// if (expectedType != null)
-// {
-// if (expectedType.IsNumber && literal.Kind is not LiteralKind.Integer and not LiteralKind.Float)
-// {
-// ReportError("Expression expects a numeric literal", literal);
-// return null;
-// }
-//
-// if (expectedType.IsInteger && literal.Kind == LiteralKind.Float)
-// {
-// if (literal.Kind == LiteralKind.Float)
-// {
-// ReportWarning("Float used in integer context. Everything after the '.' will be ignored", literal);
-// }
-// }
-//
-// return expectedType;
-// }
-//
-// return literal.Kind switch
-// {
-// LiteralKind.Integer => NubPrimitiveType.I64,
-// LiteralKind.Float => NubPrimitiveType.F64,
-// LiteralKind.String => new NubCStringType(),
-// LiteralKind.Bool => NubPrimitiveType.Bool,
-// _ => throw new ArgumentOutOfRangeException()
-// };
-// }
-//
-// private static NubType? CheckArrayIndex(ArrayIndexAccessNode arrayIndexAccess)
-// {
-// var expressionType = CheckExpression(arrayIndexAccess.Array);
-// if (expressionType == null) return null;
-// var indexType = CheckExpression(arrayIndexAccess.Index, NubPrimitiveType.U64);
-// if (indexType is { IsInteger: false })
-// {
-// ReportError("Array index type must be a number", arrayIndexAccess.Index);
-// }
-//
-// if (expressionType is NubArrayType arrayType)
-// {
-// return arrayType.ElementType;
-// }
-//
-// if (expressionType is NubFixedArrayType fixedArrayType)
-// {
-// return fixedArrayType.ElementType;
-// }
-//
-// ReportError($"Cannot access index of non-array type {expressionType}", arrayIndexAccess.Array);
-// return null;
-// }
-//
-// private static NubType CheckArrayInitializer(ArrayInitializerNode arrayInitializer)
-// {
-// var capacityType = CheckExpression(arrayInitializer.Capacity, NubPrimitiveType.U64);
-// if (capacityType is { IsInteger: false })
-// {
-// ReportError("Array capacity type must be an integer", arrayInitializer.Capacity);
-// }
-//
-// return new NubArrayType(arrayInitializer.ElementType);
-// }
-//
-// private static NubType? CheckIdentifier(IdentifierNode identifier)
-// {
-// var definition = _definitionTable.LookupFunc(identifier.Namespace.Or(_syntaxTree.Namespace), identifier.Name);
-// if (definition.HasValue)
-// {
-// return new NubFuncType(definition.Value.ReturnType, definition.Value.Parameters.Select(p => p.Type).ToList());
-// }
-//
-// if (!identifier.Namespace.HasValue)
-// {
-// return _variables[identifier.Name];
-// }
-//
-// ReportError($"Identifier '{identifier}' not found", identifier);
-// return null;
-// }
-//
-// private static NubType? CheckAddressOf(AddressOfNode addressOf)
-// {
-// var exprType = CheckExpression(addressOf.Expression);
-// if (exprType == null) return null;
-//
-// return new NubPointerType(exprType);
-// }
-//
-// private static NubType? CheckBinaryExpression(BinaryExpressionNode binaryExpr)
-// {
-// var leftType = CheckExpression(binaryExpr.Left);
-// var rightType = CheckExpression(binaryExpr.Right);
-//
-// if (leftType == null || rightType == null) return null;
-//
-// if (!leftType.Equals(rightType))
-// {
-// ReportError($"Left '{leftType}' and right '{rightType}' side of the binary expression must be the same type", binaryExpr);
-// return null;
-// }
-//
-// switch (binaryExpr.Operator)
-// {
-// case BinaryExpressionOperator.Equal:
-// case BinaryExpressionOperator.NotEqual:
-// return NubPrimitiveType.Bool;
-// case BinaryExpressionOperator.GreaterThan:
-// case BinaryExpressionOperator.GreaterThanOrEqual:
-// case BinaryExpressionOperator.LessThan:
-// case BinaryExpressionOperator.LessThanOrEqual:
-// if (!IsNumeric(leftType))
-// {
-// ReportError($"Comparison operators require numeric operands, got '{leftType}' and '{rightType}'", binaryExpr);
-// return null;
-// }
-//
-// return NubPrimitiveType.Bool;
-// case BinaryExpressionOperator.Plus:
-// case BinaryExpressionOperator.Minus:
-// case BinaryExpressionOperator.Multiply:
-// case BinaryExpressionOperator.Divide:
-// if (!IsNumeric(leftType))
-// {
-// ReportError($"Arithmetic operators require numeric operands, got '{leftType}' and '{rightType}'", binaryExpr);
-// return null;
-// }
-//
-// return leftType;
-// default:
-// ReportError($"Unsupported binary operator: {binaryExpr.Operator}", binaryExpr);
-// return null;
-// }
-// }
-//
-// private static NubType? CheckStructInitializer(StructInitializerNode structInit)
-// {
-// var initialized = new HashSet();
-//
-// var defOpt = _definitionTable.LookupStruct(structInit.StructType.Namespace, structInit.StructType.Name);
-// if (!defOpt.TryGetValue(out var definition))
-// {
-// ReportError($"Struct type '{structInit.StructType.Name}' is not defined", structInit);
-// return null;
-// }
-//
-// foreach (var initializer in structInit.Initializers)
-// {
-// var definitionField = definition.Fields.FirstOrDefault(f => f.Name == initializer.Key);
-// if (definitionField == null)
-// {
-// ReportError($"Field '{initializer.Key}' does not exist in struct '{structInit.StructType.Name}'", initializer.Value);
-// continue;
-// }
-//
-// var initializerType = CheckExpression(initializer.Value, definitionField.Type);
-// if (initializerType != null && !NubType.IsCompatibleWith(initializerType, definitionField.Type))
-// {
-// ReportError($"Cannot initialize field '{initializer.Key}' of type '{definitionField.Type}' with expression of type '{initializerType}'", initializer.Value);
-// }
-//
-// initialized.Add(initializer.Key);
-// }
-//
-// foreach (var field in definition.Fields.Where(f => f.Value.HasValue))
-// {
-// initialized.Add(field.Name);
-// }
-//
-// foreach (var field in definition.Fields)
-// {
-// if (!initialized.Contains(field.Name))
-// {
-// ReportError($"Struct field '{field.Name}' is not initialized on type '{structInit.StructType.Name}'", structInit);
-// }
-// }
-//
-// return structInit.StructType;
-// }
-//
-// private static NubType? CheckUnaryExpression(UnaryExpressionNode unaryExpression)
-// {
-// var operandType = CheckExpression(unaryExpression.Operand);
-// if (operandType == null) return null;
-//
-// switch (unaryExpression.Operator)
-// {
-// case UnaryExpressionOperator.Negate:
-// {
-// if (operandType.Equals(NubPrimitiveType.I8) ||
-// operandType.Equals(NubPrimitiveType.I16) ||
-// operandType.Equals(NubPrimitiveType.I32) ||
-// operandType.Equals(NubPrimitiveType.I64) ||
-// operandType.Equals(NubPrimitiveType.F32) ||
-// operandType.Equals(NubPrimitiveType.F64))
-// {
-// return operandType;
-// }
-//
-// ReportError($"Cannot negate non-numeric type {operandType}", unaryExpression.Operand);
-// return null;
-// }
-// case UnaryExpressionOperator.Invert:
-// {
-// if (!operandType.Equals(NubPrimitiveType.Bool))
-// {
-// ReportError($"Cannot invert non-boolean type {operandType}", unaryExpression.Operand);
-// return null;
-// }
-//
-// return operandType;
-// }
-// default:
-// {
-// ReportError($"Unsupported unary operator: {unaryExpression.Operator}", unaryExpression);
-// return null;
-// }
-// }
-// }
-//
-// private static NubType? CheckMemberAccess(MemberAccessNode memberAccess)
-// {
-// var expressionType = CheckExpression(memberAccess.Expression);
-// if (expressionType == null) return null;
-//
-// switch (expressionType)
-// {
-// case NubArrayType:
-// {
-// if (memberAccess.Member == "count")
-// {
-// return NubPrimitiveType.I64;
-// }
-//
-// break;
-// }
-// case NubStructType structType:
-// {
-// var defOpt = _definitionTable.LookupStruct(structType.Namespace, structType.Name);
-// if (!defOpt.TryGetValue(out var definition))
-// {
-// ReportError($"Struct type '{structType.Name}' is not defined", memberAccess);
-// return null;
-// }
-//
-// var field = definition.Fields.FirstOrDefault(f => f.Name == memberAccess.Member);
-// if (field == null)
-// {
-// ReportError($"Field '{memberAccess.Member}' does not exist in struct '{structType.Name}'", memberAccess);
-// return null;
-// }
-//
-// return field.Type;
-// }
-// }
-//
-// ReportError($"Cannot access member '{memberAccess.Member}' on type '{expressionType}'", memberAccess);
-// return null;
-// }
-//
-// private static void ReportError(string message, Node node)
-// {
-// var diagnostic = Diagnostic.Error(message).At(node).Build();
-// _diagnostics.Add(diagnostic);
-// }
-//
-// private static void ReportWarning(string message, Node node)
-// {
-// var diagnostic = Diagnostic.Warning(message).At(node).Build();
-// _diagnostics.Add(diagnostic);
-// }
-//
-// private static bool IsNumeric(NubType type)
-// {
-// if (type is not NubPrimitiveType primitiveType)
-// {
-// return false;
-// }
-//
-// switch (primitiveType.Kind)
-// {
-// case PrimitiveTypeKind.I8:
-// case PrimitiveTypeKind.I16:
-// case PrimitiveTypeKind.I32:
-// case PrimitiveTypeKind.I64:
-// case PrimitiveTypeKind.U8:
-// case PrimitiveTypeKind.U16:
-// case PrimitiveTypeKind.U32:
-// case PrimitiveTypeKind.U64:
-// case PrimitiveTypeKind.F32:
-// case PrimitiveTypeKind.F64:
-// return true;
-// default:
-// return false;
-// }
-// }
-// }
\ No newline at end of file