This commit is contained in:
nub31
2025-10-17 23:39:13 +02:00
parent 267da1941d
commit 6671fced57
11 changed files with 32 additions and 186 deletions

View File

@@ -28,8 +28,6 @@ var moduleRepository = new ModuleRepository(syntaxTrees);
var definitions = new List<DefinitionNode>();
var referencedStructTypes = new HashSet<NubStructType>();
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
""";

View File

@@ -20,8 +20,6 @@ public record StructFuncNode(List<Token> Tokens, string Name, FuncSignatureNode
public record StructNode(List<Token> Tokens, string Module, string Name, List<StructFieldNode> Fields, List<StructFuncNode> Functions) : DefinitionNode(Tokens, Module, Name);
public record GlobalVariableNode(List<Token> Tokens, string Module, string Name, ExpressionNode Value) : DefinitionNode(Tokens, Module, Name);
#endregion
#region Statements

View File

@@ -29,7 +29,6 @@ public sealed class TypeChecker
public List<DefinitionNode> Definitions { get; } = [];
public List<Diagnostic> Diagnostics { get; } = [];
public List<NubStructType> 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;
}
}

View File

@@ -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<DefinitionNode> _definitions;
private readonly HashSet<NubStructType> _structTypes;
private readonly IndentedTextWriter _writer;
private readonly Stack<List<DeferNode>> _deferStack = [];
private readonly Stack<(string Name, NubFuncType FuncType)> _funcDefs = [];
private readonly List<NubStructType> _structTypes = [];
private int _tmpIndex;
private int _funcDefIndex;
public Generator(List<DefinitionNode> definitions, HashSet<NubStructType> structTypes)
public Generator(List<DefinitionNode> 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)

View File

@@ -34,12 +34,4 @@ public class Module
.Where(x => x.Exported || includePrivate)
.ToList();
}
public List<GlobalVariableSyntax> GlobalVariables(bool includePrivate)
{
return _definitions
.OfType<GlobalVariableSyntax>()
.Where(x => x.Exported || includePrivate)
.ToList();
}
}

View File

@@ -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();

View File

@@ -20,8 +20,6 @@ public record StructSyntax(List<Token> Tokens, string Name, bool Exported, List<
public record StructTemplateSyntax(List<Token> Tokens, List<string> TemplateArguments, string Name, bool Exported, List<StructFieldSyntax> Fields, List<StructFuncSyntax> Functions) : DefinitionSyntax(Tokens, Name, Exported);
public record GlobalVariableSyntax(List<Token> Tokens, string Name, bool Exported, TypeSyntax? ExplicitType, ExpressionSyntax Value) : DefinitionSyntax(Tokens, Name, Exported);
public enum UnaryOperatorSyntax
{
Negate,

View File

@@ -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

View File

@@ -1,10 +0,0 @@
.intel_syntax noprefix
.text
.globl _start
_start:
mov rdi, rsp
call main
mov rdi, rax
mov rax, 60
syscall

View File

@@ -1,3 +0,0 @@
.build
out.a
out