diff --git a/compiler/NubLang.CLI/Program.cs b/compiler/NubLang.CLI/Program.cs index 6d8e53f..a0e4474 100644 --- a/compiler/NubLang.CLI/Program.cs +++ b/compiler/NubLang.CLI/Program.cs @@ -28,8 +28,6 @@ var moduleRepository = new ModuleRepository(syntaxTrees); var definitions = new List(); -var referencedStructTypes = new HashSet(); - foreach (var syntaxTree in syntaxTrees) { var typeChecker = new TypeChecker(syntaxTree, moduleRepository); @@ -37,11 +35,6 @@ foreach (var syntaxTree in syntaxTrees) definitions.AddRange(typeChecker.Definitions); diagnostics.AddRange(typeChecker.Diagnostics); - - foreach (var structType in typeChecker.ReferencedStructTypes) - { - referencedStructTypes.Add(structType); - } } foreach (var diagnostic in diagnostics) @@ -56,7 +49,7 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro Directory.CreateDirectory(".build"); -var generator = new Generator(definitions, referencedStructTypes); +var generator = new Generator(definitions); var c = generator.Emit(); var cFilePath = Path.Combine(".build", "out.c"); @@ -91,10 +84,10 @@ if (moduleRepository.Modules().TryGetValue("main", out var mainModule)) .text .globl _start _start: - mov rdi, [rsp + 8] # Pass stack pointer to main (argv-like) + mov rdi, rsp # Pass stack pointer to main (length + cstring pointers) call {mainFunction.ExternSymbol} - mov rdi, rax # Move return value into rdi - mov rax, 60 # syscall: exit + mov rdi, rax # Move return value into rdi + mov rax, 60 # syscall: exit syscall """; diff --git a/compiler/NubLang/Ast/Node.cs b/compiler/NubLang/Ast/Node.cs index 9ba1d41..7ea2009 100644 --- a/compiler/NubLang/Ast/Node.cs +++ b/compiler/NubLang/Ast/Node.cs @@ -20,8 +20,6 @@ public record StructFuncNode(List Tokens, string Name, FuncSignatureNode public record StructNode(List Tokens, string Module, string Name, List Fields, List Functions) : DefinitionNode(Tokens, Module, Name); -public record GlobalVariableNode(List Tokens, string Module, string Name, ExpressionNode Value) : DefinitionNode(Tokens, Module, Name); - #endregion #region Statements diff --git a/compiler/NubLang/Ast/TypeChecker.cs b/compiler/NubLang/Ast/TypeChecker.cs index 78fd1ac..a977fdb 100644 --- a/compiler/NubLang/Ast/TypeChecker.cs +++ b/compiler/NubLang/Ast/TypeChecker.cs @@ -29,7 +29,6 @@ public sealed class TypeChecker public List Definitions { get; } = []; public List Diagnostics { get; } = []; - public List ReferencedStructTypes { get; } = []; public void Check() { @@ -41,7 +40,6 @@ public sealed class TypeChecker Diagnostics.Clear(); Definitions.Clear(); - ReferencedStructTypes.Clear(); using (BeginRootScope(_syntaxTree.Metadata.ModuleName)) { @@ -57,9 +55,6 @@ public sealed class TypeChecker case StructSyntax structSyntax: Definitions.Add(CheckStructDefinition(structSyntax)); break; - case GlobalVariableSyntax globalVariableSyntax: - Definitions.Add(CheckGlobalVariable(globalVariableSyntax)); - break; case StructTemplateSyntax: break; default: @@ -90,39 +85,7 @@ public sealed class TypeChecker private ScopeDisposer BeginRootScope(string moduleName) { - if (!_visibleModules.TryGetValue(moduleName, out var moduleScope)) - { - throw new TypeCheckerException(Diagnostic.Error($"Module with name {moduleName} not found").Build()); - } - - var scope = new Scope(moduleName); - _scopes.Push(scope); - - foreach (var globalVariable in moduleScope.GlobalVariables(true)) - { - NubType? type; - - if (globalVariable.ExplicitType != null) - { - type = ResolveType(globalVariable.ExplicitType); - var valueExpression = CheckExpression(globalVariable.Value, type); - - if (valueExpression.Type != ResolveType(globalVariable.ExplicitType)) - { - throw new TypeCheckerException(Diagnostic - .Error("Value does not match explicit type of global variable") - .At(globalVariable.Value) - .Build()); - } - } - else - { - type = CheckExpression(globalVariable.Value).Type; - } - - scope.DeclareVariable(new Variable(globalVariable.Name, type, VariableKind.LValue)); - } - + _scopes.Push(new Scope(moduleName)); return new ScopeDisposer(this); } @@ -224,11 +187,6 @@ public sealed class TypeChecker return new FuncNode(node.Tokens, CurrentScope.Module, node.Name, node.ExternSymbol, signature, body); } - private GlobalVariableNode CheckGlobalVariable(GlobalVariableSyntax node) - { - return new GlobalVariableNode(node.Tokens, CurrentScope.Module, node.Name, CheckExpression(node.Value)); - } - private AssignmentNode CheckAssignment(AssignmentSyntax statement) { var target = CheckExpression(statement.Target); @@ -702,7 +660,6 @@ public sealed class TypeChecker private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression) { - // First, look in the current scope for a matching identifier var scopeIdent = CurrentScope.LookupVariable(expression.Name); if (scopeIdent != null) { @@ -714,7 +671,6 @@ public sealed class TypeChecker }; } - // Second, look in the current module for a function matching the identifier var module = _visibleModules[CurrentScope.Module]; var function = module.Functions(true).FirstOrDefault(x => x.Name == expression.Name); @@ -741,20 +697,6 @@ public sealed class TypeChecker var includePrivate = expression.Module == CurrentScope.Module; - var globalVariable = module.GlobalVariables(includePrivate).FirstOrDefault(x => x.Name == expression.Name); - if (globalVariable != null) - { - // todo(nub31): This should be done in the global scope - NubType? type = null; - if (globalVariable.ExplicitType != null) - { - type = ResolveType(globalVariable.ExplicitType); - } - - return CheckExpression(globalVariable.Value, type); - } - - // First, look for the exported function in the specified module var function = module.Functions(includePrivate).FirstOrDefault(x => x.Name == expression.Name); if (function != null) { @@ -1069,8 +1011,6 @@ public sealed class TypeChecker .ToList(); result.Functions.AddRange(functions); - - ReferencedStructTypes.Add(result); return result; } @@ -1146,8 +1086,6 @@ public sealed class TypeChecker _checkedTemplateStructs.Add($"{structTemplate.Module}.{mangledName}"); } - ReferencedStructTypes.Add(structType); - return structType; } } diff --git a/compiler/NubLang/Generation/Generator.cs b/compiler/NubLang/Generation/Generator.cs index 8529af3..6838ff7 100644 --- a/compiler/NubLang/Generation/Generator.cs +++ b/compiler/NubLang/Generation/Generator.cs @@ -1,3 +1,4 @@ +using System.Text; using NubLang.Ast; using NubLang.Syntax; @@ -6,17 +7,16 @@ namespace NubLang.Generation; public class Generator { private readonly List _definitions; - private readonly HashSet _structTypes; private readonly IndentedTextWriter _writer; private readonly Stack> _deferStack = []; private readonly Stack<(string Name, NubFuncType FuncType)> _funcDefs = []; + private readonly List _structTypes = []; private int _tmpIndex; private int _funcDefIndex; - public Generator(List definitions, HashSet structTypes) + public Generator(List definitions) { _definitions = definitions; - _structTypes = structTypes; _writer = new IndentedTextWriter(); } @@ -55,12 +55,18 @@ public class Generator }, NubPointerType pointerType => MapType(pointerType.BaseType), NubStringType => throw new NotImplementedException(), - NubStructType structType => StructName(structType.Module, structType.Name), + NubStructType structType => MapStructType(structType), NubVoidType => "void", _ => throw new ArgumentOutOfRangeException(nameof(nubType)) }; } + private string MapStructType(NubStructType structType) + { + _structTypes.Add(structType); + return StructName(structType.Module, structType.Name); + } + private string MapFuncType(NubFuncType funcType) { var name = $"_func_type_def{++_funcDefIndex}"; @@ -146,21 +152,7 @@ public class Generator #define U64_C(x) x##ULL """; - foreach (var structType in _structTypes) - { - _writer.WriteLine("typedef struct"); - _writer.WriteLine("{"); - using (_writer.Indent()) - { - foreach (var field in structType.Fields) - { - _writer.WriteLine($"{MapNameWithType(field.Type, field.Name)};"); - } - } - - _writer.WriteLine($"}} {StructName(structType.Module, structType.Name)};"); - _writer.WriteLine(); - } + _writer.WriteLine(); var appendNewLine = false; @@ -231,7 +223,21 @@ public class Generator typedefs.Add($"typedef {returnType} (*{funcTypeDef.Name})({paramList});"); } - return header + "\n\n" + string.Join('\n', typedefs) + "\n\n" + _writer; + var structDefSb = new StringBuilder(); + foreach (var structType in _structTypes) + { + structDefSb.AppendLine("typedef struct"); + structDefSb.AppendLine("{"); + foreach (var field in structType.Fields) + { + structDefSb.AppendLine($" {MapNameWithType(field.Type, field.Name)};"); + } + + structDefSb.AppendLine($"}} {StructName(structType.Module, structType.Name)};"); + structDefSb.AppendLine(); + } + + return header + structDefSb + "\n\n" + string.Join('\n', typedefs) + "\n\n" + _writer; } private void EmitStatement(StatementNode statementNode) diff --git a/compiler/NubLang/Modules/Module.cs b/compiler/NubLang/Modules/Module.cs index 3d3ba95..33d1b5a 100644 --- a/compiler/NubLang/Modules/Module.cs +++ b/compiler/NubLang/Modules/Module.cs @@ -34,12 +34,4 @@ public class Module .Where(x => x.Exported || includePrivate) .ToList(); } - - public List GlobalVariables(bool includePrivate) - { - return _definitions - .OfType() - .Where(x => x.Exported || includePrivate) - .ToList(); - } } \ No newline at end of file diff --git a/compiler/NubLang/Syntax/Parser.cs b/compiler/NubLang/Syntax/Parser.cs index c1e3130..f94a033 100644 --- a/compiler/NubLang/Syntax/Parser.cs +++ b/compiler/NubLang/Syntax/Parser.cs @@ -84,7 +84,6 @@ public sealed class Parser { Symbol.Func => ParseFunc(startIndex, exported, null), Symbol.Struct => ParseStruct(startIndex, exported), - Symbol.Let => ParseGlobalVariable(startIndex, exported), _ => throw new ParseException(Diagnostic .Error($"Expected 'func' or 'struct' but found '{keyword.Symbol}'") .WithHelp("Valid definition keywords are 'func' and 'struct'") @@ -112,22 +111,6 @@ public sealed class Parser return definitions; } - private GlobalVariableSyntax ParseGlobalVariable(int startIndex, bool exported) - { - var name = ExpectIdentifier(); - - TypeSyntax? type = null; - if (TryExpectSymbol(Symbol.Colon)) - { - type = ParseType(); - } - - ExpectSymbol(Symbol.Assign); - var value = ParseExpression(); - - return new GlobalVariableSyntax(GetTokens(startIndex), name.Value, exported, type, value); - } - private FuncSignatureSyntax ParseFuncSignature() { var startIndex = _tokenIndex; @@ -924,21 +907,6 @@ public sealed class Parser return identifier; } - private IntLiteralToken ExpectIntLiteral() - { - var token = ExpectToken(); - if (token is not IntLiteralToken identifier) - { - throw new ParseException(Diagnostic - .Error($"Expected int literal, but found {token.GetType().Name}") - .WithHelp("Provide a valid int literal") - .At(token) - .Build()); - } - - return identifier; - } - private bool TryExpectIntLiteral([NotNullWhen(true)] out IntLiteralToken? stringLiteral) { if (CurrentToken is IntLiteralToken token) @@ -952,36 +920,6 @@ public sealed class Parser return false; } - private FloatLiteralToken ExpectFloatLiteral() - { - var token = ExpectToken(); - if (token is not FloatLiteralToken identifier) - { - throw new ParseException(Diagnostic - .Error($"Expected float literal, but found {token.GetType().Name}") - .WithHelp("Provide a valid float literal") - .At(token) - .Build()); - } - - return identifier; - } - - private BoolLiteralToken ExpectBoolLiteral() - { - var token = ExpectToken(); - if (token is not BoolLiteralToken identifier) - { - throw new ParseException(Diagnostic - .Error($"Expected bool literal, but found {token.GetType().Name}") - .WithHelp("Provide a valid bool literal") - .At(token) - .Build()); - } - - return identifier; - } - private StringLiteralToken ExpectStringLiteral() { var token = ExpectToken(); diff --git a/compiler/NubLang/Syntax/Syntax.cs b/compiler/NubLang/Syntax/Syntax.cs index d60be9e..33d5e95 100644 --- a/compiler/NubLang/Syntax/Syntax.cs +++ b/compiler/NubLang/Syntax/Syntax.cs @@ -20,8 +20,6 @@ public record StructSyntax(List Tokens, string Name, bool Exported, List< public record StructTemplateSyntax(List Tokens, List TemplateArguments, string Name, bool Exported, List Fields, List Functions) : DefinitionSyntax(Tokens, Name, Exported); -public record GlobalVariableSyntax(List Tokens, string Name, bool Exported, TypeSyntax? ExplicitType, ExpressionSyntax Value) : DefinitionSyntax(Tokens, Name, Exported); - public enum UnaryOperatorSyntax { Negate, diff --git a/examples/hello-world/.gitignore b/examples/.gitignore similarity index 100% rename from examples/hello-world/.gitignore rename to examples/.gitignore diff --git a/examples/hello-world/makefile b/examples/hello-world/makefile index 8c2858d..490cbcc 100644 --- a/examples/hello-world/makefile +++ b/examples/hello-world/makefile @@ -1,9 +1,5 @@ -out: .build/out.o - gcc -nostartfiles -lm -o out x86_64.s .build/out.o - -.build/out.o: main.nub +.build/out: main.nub nubc main.nub clean: @rm -r .build 2>/dev/null || true - @rm out 2>/dev/null || true diff --git a/examples/hello-world/x86_64.s b/examples/hello-world/x86_64.s deleted file mode 100644 index f55a1d0..0000000 --- a/examples/hello-world/x86_64.s +++ /dev/null @@ -1,10 +0,0 @@ -.intel_syntax noprefix - -.text -.globl _start -_start: - mov rdi, rsp - call main - mov rdi, rax - mov rax, 60 - syscall diff --git a/examples/raylib/.gitignore b/examples/raylib/.gitignore deleted file mode 100644 index a8b1f05..0000000 --- a/examples/raylib/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.build -out.a -out \ No newline at end of file