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 definitions = new List<DefinitionNode>();
var referencedStructTypes = new HashSet<NubStructType>();
foreach (var syntaxTree in syntaxTrees) foreach (var syntaxTree in syntaxTrees)
{ {
var typeChecker = new TypeChecker(syntaxTree, moduleRepository); var typeChecker = new TypeChecker(syntaxTree, moduleRepository);
@@ -37,11 +35,6 @@ foreach (var syntaxTree in syntaxTrees)
definitions.AddRange(typeChecker.Definitions); definitions.AddRange(typeChecker.Definitions);
diagnostics.AddRange(typeChecker.Diagnostics); diagnostics.AddRange(typeChecker.Diagnostics);
foreach (var structType in typeChecker.ReferencedStructTypes)
{
referencedStructTypes.Add(structType);
}
} }
foreach (var diagnostic in diagnostics) foreach (var diagnostic in diagnostics)
@@ -56,7 +49,7 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
Directory.CreateDirectory(".build"); Directory.CreateDirectory(".build");
var generator = new Generator(definitions, referencedStructTypes); var generator = new Generator(definitions);
var c = generator.Emit(); var c = generator.Emit();
var cFilePath = Path.Combine(".build", "out.c"); var cFilePath = Path.Combine(".build", "out.c");
@@ -91,7 +84,7 @@ if (moduleRepository.Modules().TryGetValue("main", out var mainModule))
.text .text
.globl _start .globl _start
_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} call {mainFunction.ExternSymbol}
mov rdi, rax # Move return value into rdi mov rdi, rax # Move return value into rdi
mov rax, 60 # syscall: exit mov rax, 60 # syscall: exit

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 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 #endregion
#region Statements #region Statements

View File

@@ -29,7 +29,6 @@ public sealed class TypeChecker
public List<DefinitionNode> Definitions { get; } = []; public List<DefinitionNode> Definitions { get; } = [];
public List<Diagnostic> Diagnostics { get; } = []; public List<Diagnostic> Diagnostics { get; } = [];
public List<NubStructType> ReferencedStructTypes { get; } = [];
public void Check() public void Check()
{ {
@@ -41,7 +40,6 @@ public sealed class TypeChecker
Diagnostics.Clear(); Diagnostics.Clear();
Definitions.Clear(); Definitions.Clear();
ReferencedStructTypes.Clear();
using (BeginRootScope(_syntaxTree.Metadata.ModuleName)) using (BeginRootScope(_syntaxTree.Metadata.ModuleName))
{ {
@@ -57,9 +55,6 @@ public sealed class TypeChecker
case StructSyntax structSyntax: case StructSyntax structSyntax:
Definitions.Add(CheckStructDefinition(structSyntax)); Definitions.Add(CheckStructDefinition(structSyntax));
break; break;
case GlobalVariableSyntax globalVariableSyntax:
Definitions.Add(CheckGlobalVariable(globalVariableSyntax));
break;
case StructTemplateSyntax: case StructTemplateSyntax:
break; break;
default: default:
@@ -90,39 +85,7 @@ public sealed class TypeChecker
private ScopeDisposer BeginRootScope(string moduleName) private ScopeDisposer BeginRootScope(string moduleName)
{ {
if (!_visibleModules.TryGetValue(moduleName, out var moduleScope)) _scopes.Push(new Scope(moduleName));
{
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));
}
return new ScopeDisposer(this); 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); 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) private AssignmentNode CheckAssignment(AssignmentSyntax statement)
{ {
var target = CheckExpression(statement.Target); var target = CheckExpression(statement.Target);
@@ -702,7 +660,6 @@ public sealed class TypeChecker
private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression) private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression)
{ {
// First, look in the current scope for a matching identifier
var scopeIdent = CurrentScope.LookupVariable(expression.Name); var scopeIdent = CurrentScope.LookupVariable(expression.Name);
if (scopeIdent != null) 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 module = _visibleModules[CurrentScope.Module];
var function = module.Functions(true).FirstOrDefault(x => x.Name == expression.Name); 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 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); var function = module.Functions(includePrivate).FirstOrDefault(x => x.Name == expression.Name);
if (function != null) if (function != null)
{ {
@@ -1069,8 +1011,6 @@ public sealed class TypeChecker
.ToList(); .ToList();
result.Functions.AddRange(functions); result.Functions.AddRange(functions);
ReferencedStructTypes.Add(result);
return result; return result;
} }
@@ -1146,8 +1086,6 @@ public sealed class TypeChecker
_checkedTemplateStructs.Add($"{structTemplate.Module}.{mangledName}"); _checkedTemplateStructs.Add($"{structTemplate.Module}.{mangledName}");
} }
ReferencedStructTypes.Add(structType);
return structType; return structType;
} }
} }

View File

@@ -1,3 +1,4 @@
using System.Text;
using NubLang.Ast; using NubLang.Ast;
using NubLang.Syntax; using NubLang.Syntax;
@@ -6,17 +7,16 @@ namespace NubLang.Generation;
public class Generator public class Generator
{ {
private readonly List<DefinitionNode> _definitions; private readonly List<DefinitionNode> _definitions;
private readonly HashSet<NubStructType> _structTypes;
private readonly IndentedTextWriter _writer; private readonly IndentedTextWriter _writer;
private readonly Stack<List<DeferNode>> _deferStack = []; private readonly Stack<List<DeferNode>> _deferStack = [];
private readonly Stack<(string Name, NubFuncType FuncType)> _funcDefs = []; private readonly Stack<(string Name, NubFuncType FuncType)> _funcDefs = [];
private readonly List<NubStructType> _structTypes = [];
private int _tmpIndex; private int _tmpIndex;
private int _funcDefIndex; private int _funcDefIndex;
public Generator(List<DefinitionNode> definitions, HashSet<NubStructType> structTypes) public Generator(List<DefinitionNode> definitions)
{ {
_definitions = definitions; _definitions = definitions;
_structTypes = structTypes;
_writer = new IndentedTextWriter(); _writer = new IndentedTextWriter();
} }
@@ -55,12 +55,18 @@ public class Generator
}, },
NubPointerType pointerType => MapType(pointerType.BaseType), NubPointerType pointerType => MapType(pointerType.BaseType),
NubStringType => throw new NotImplementedException(), NubStringType => throw new NotImplementedException(),
NubStructType structType => StructName(structType.Module, structType.Name), NubStructType structType => MapStructType(structType),
NubVoidType => "void", NubVoidType => "void",
_ => throw new ArgumentOutOfRangeException(nameof(nubType)) _ => throw new ArgumentOutOfRangeException(nameof(nubType))
}; };
} }
private string MapStructType(NubStructType structType)
{
_structTypes.Add(structType);
return StructName(structType.Module, structType.Name);
}
private string MapFuncType(NubFuncType funcType) private string MapFuncType(NubFuncType funcType)
{ {
var name = $"_func_type_def{++_funcDefIndex}"; var name = $"_func_type_def{++_funcDefIndex}";
@@ -146,21 +152,7 @@ public class Generator
#define U64_C(x) x##ULL #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; var appendNewLine = false;
@@ -231,7 +223,21 @@ public class Generator
typedefs.Add($"typedef {returnType} (*{funcTypeDef.Name})({paramList});"); 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) private void EmitStatement(StatementNode statementNode)

View File

@@ -34,12 +34,4 @@ public class Module
.Where(x => x.Exported || includePrivate) .Where(x => x.Exported || includePrivate)
.ToList(); .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.Func => ParseFunc(startIndex, exported, null),
Symbol.Struct => ParseStruct(startIndex, exported), Symbol.Struct => ParseStruct(startIndex, exported),
Symbol.Let => ParseGlobalVariable(startIndex, exported),
_ => throw new ParseException(Diagnostic _ => throw new ParseException(Diagnostic
.Error($"Expected 'func' or 'struct' but found '{keyword.Symbol}'") .Error($"Expected 'func' or 'struct' but found '{keyword.Symbol}'")
.WithHelp("Valid definition keywords are 'func' and 'struct'") .WithHelp("Valid definition keywords are 'func' and 'struct'")
@@ -112,22 +111,6 @@ public sealed class Parser
return definitions; 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() private FuncSignatureSyntax ParseFuncSignature()
{ {
var startIndex = _tokenIndex; var startIndex = _tokenIndex;
@@ -924,21 +907,6 @@ public sealed class Parser
return identifier; 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) private bool TryExpectIntLiteral([NotNullWhen(true)] out IntLiteralToken? stringLiteral)
{ {
if (CurrentToken is IntLiteralToken token) if (CurrentToken is IntLiteralToken token)
@@ -952,36 +920,6 @@ public sealed class Parser
return false; 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() private StringLiteralToken ExpectStringLiteral()
{ {
var token = ExpectToken(); 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 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 public enum UnaryOperatorSyntax
{ {
Negate, Negate,

View File

@@ -1,9 +1,5 @@
out: .build/out.o .build/out: main.nub
gcc -nostartfiles -lm -o out x86_64.s .build/out.o
.build/out.o: main.nub
nubc main.nub nubc main.nub
clean: clean:
@rm -r .build 2>/dev/null || true @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