This commit is contained in:
nub31
2025-10-20 18:31:43 +02:00
parent 6671fced57
commit 78441549c7
12 changed files with 313 additions and 724 deletions

View File

@@ -2,14 +2,13 @@
using NubLang.Ast; using NubLang.Ast;
using NubLang.Diagnostics; using NubLang.Diagnostics;
using NubLang.Generation; using NubLang.Generation;
using NubLang.Modules;
using NubLang.Syntax; using NubLang.Syntax;
var diagnostics = new List<Diagnostic>(); var diagnostics = new List<Diagnostic>();
var syntaxTrees = new List<SyntaxTree>(); var syntaxTrees = new List<SyntaxTree>();
var nubFiles = args.Where(x => Path.GetExtension(x) == ".nub"); var nubFiles = args.Where(x => Path.GetExtension(x) == ".nub").ToArray();
var objectFiles = args.Where(x => Path.GetExtension(x) is ".o" or ".a"); var objectFileArgs = args.Where(x => Path.GetExtension(x) is ".o" or ".a").ToArray();
foreach (var file in nubFiles) foreach (var file in nubFiles)
{ {
@@ -24,16 +23,15 @@ foreach (var file in nubFiles)
syntaxTrees.Add(syntaxTree); syntaxTrees.Add(syntaxTree);
} }
var moduleRepository = new ModuleRepository(syntaxTrees); var modules = Module.Collect(syntaxTrees);
var compilationUnits = new List<CompilationUnit>();
var definitions = new List<DefinitionNode>(); for (var i = 0; i < nubFiles.Length; i++)
foreach (var syntaxTree in syntaxTrees)
{ {
var typeChecker = new TypeChecker(syntaxTree, moduleRepository); var typeChecker = new TypeChecker(syntaxTrees[i], modules);
typeChecker.Check(); var compilationUnit = typeChecker.Check();
definitions.AddRange(typeChecker.Definitions); compilationUnits.Add(compilationUnit);
diagnostics.AddRange(typeChecker.Diagnostics); diagnostics.AddRange(typeChecker.Diagnostics);
} }
@@ -47,36 +45,57 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
return 1; return 1;
} }
var cPaths = new List<string>();
Directory.CreateDirectory(".build"); Directory.CreateDirectory(".build");
var generator = new Generator(definitions); for (var i = 0; i < nubFiles.Length; i++)
var c = generator.Emit();
var cFilePath = Path.Combine(".build", "out.c");
File.WriteAllText(cFilePath, c);
using var compileProcess = Process.Start("gcc", [
"-ffreestanding", "-nostartfiles", "-std=c23",
"-g", "-lm",
"-c", "-o", Path.Combine(".build", "out.o"),
cFilePath,
]);
compileProcess.WaitForExit();
if (compileProcess.ExitCode != 0)
{ {
Console.Error.WriteLine($"gcc failed with exit code {compileProcess.ExitCode}"); var file = nubFiles[i];
return 1; var compilationUnit = compilationUnits[i];
var generator = new Generator(compilationUnit);
var directory = Path.GetDirectoryName(file);
if (!string.IsNullOrWhiteSpace(directory))
{
Directory.CreateDirectory(Path.Combine(".build", directory));
}
var path = Path.Combine(".build", Path.ChangeExtension(file, "c"));
File.WriteAllText(path, generator.Emit());
cPaths.Add(path);
} }
if (moduleRepository.Modules().TryGetValue("main", out var mainModule)) var objectPaths = new List<string>();
foreach (var cPath in cPaths)
{
var objectPath = Path.ChangeExtension(cPath, "o");
using var compileProcess = Process.Start("gcc", [
"-ffreestanding", "-nostartfiles", "-std=c23",
"-g", "-lm",
"-c", "-o", objectPath,
cPath,
]);
compileProcess.WaitForExit();
if (compileProcess.ExitCode != 0)
{
Console.Error.WriteLine($"gcc failed with exit code {compileProcess.ExitCode}");
return 1;
}
objectPaths.Add(objectPath);
}
if (modules.TryGetValue("main", out var mainModule))
{ {
var mainFunction = mainModule var mainFunction = mainModule
.Functions(true) .Functions(true)
.FirstOrDefault(x => x.ExternSymbol == "main"); .FirstOrDefault(x => x.Prototype.ExternSymbol == "main");
if (mainFunction is { ExternSymbol: not null }) if (mainFunction is { Prototype.ExternSymbol: not null })
{ {
var runtime = $""" var runtime = $"""
.intel_syntax noprefix .intel_syntax noprefix
@@ -85,7 +104,7 @@ if (moduleRepository.Modules().TryGetValue("main", out var mainModule))
.globl _start .globl _start
_start: _start:
mov rdi, rsp # Pass stack pointer to main (length + cstring pointers) mov rdi, rsp # Pass stack pointer to main (length + cstring pointers)
call {mainFunction.ExternSymbol} call {mainFunction.Prototype.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
syscall syscall
@@ -111,9 +130,9 @@ if (moduleRepository.Modules().TryGetValue("main", out var mainModule))
"-ffreestanding", "-nostartfiles", "-std=c23", "-ffreestanding", "-nostartfiles", "-std=c23",
"-g", "-lm", "-g", "-lm",
"-o", Path.Combine(".build", "out"), "-o", Path.Combine(".build", "out"),
Path.Combine(".build", "out.o"), ..objectPaths,
Path.Combine(".build", "runtime.o"), Path.Combine(".build", "runtime.o"),
..objectFiles ..objectFileArgs
])); ]));
if (linkProcess == null) return 1; if (linkProcess == null) return 1;

View File

@@ -0,0 +1,15 @@
namespace NubLang.Ast;
public sealed class CompilationUnit
{
public CompilationUnit(List<FuncNode> functions, List<NubStructType> importedStructTypes, List<FuncPrototypeNode> importedFunctions)
{
Functions = functions;
ImportedStructTypes = importedStructTypes;
ImportedFunctions = importedFunctions;
}
public List<FuncNode> Functions { get; }
public List<NubStructType> ImportedStructTypes { get; }
public List<FuncPrototypeNode> ImportedFunctions { get; }
}

View File

@@ -10,15 +10,9 @@ public abstract record DefinitionNode(List<Token> Tokens, string Module, string
public record FuncParameterNode(List<Token> Tokens, string Name, NubType Type) : Node(Tokens); public record FuncParameterNode(List<Token> Tokens, string Name, NubType Type) : Node(Tokens);
public record FuncSignatureNode(List<Token> Tokens, List<FuncParameterNode> Parameters, NubType ReturnType) : Node(Tokens); public record FuncPrototypeNode(List<Token> Tokens, string Module, string Name, string? ExternSymbol, List<FuncParameterNode> Parameters, NubType ReturnType) : Node(Tokens);
public record FuncNode(List<Token> Tokens, string Module, string Name, string? ExternSymbol, FuncSignatureNode Signature, BlockNode? Body) : DefinitionNode(Tokens, Module, Name); public record FuncNode(List<Token> Tokens, FuncPrototypeNode Prototype, BlockNode? Body) : DefinitionNode(Tokens, Prototype.Module, Prototype.Name);
public record StructFieldNode(List<Token> Tokens, string Name, NubType Type, ExpressionNode? Value) : Node(Tokens);
public record StructFuncNode(List<Token> Tokens, string Name, FuncSignatureNode Signature, BlockNode Body) : Node(Tokens);
public record StructNode(List<Token> Tokens, string Module, string Name, List<StructFieldNode> Fields, List<StructFuncNode> Functions) : DefinitionNode(Tokens, Module, Name);
#endregion #endregion
@@ -32,8 +26,6 @@ public record BlockNode(List<Token> Tokens, List<StatementNode> Statements) : St
public record StatementFuncCallNode(List<Token> Tokens, FuncCallNode FuncCall) : StatementNode(Tokens); public record StatementFuncCallNode(List<Token> Tokens, FuncCallNode FuncCall) : StatementNode(Tokens);
public record StatementStructFuncCallNode(List<Token> Tokens, StructFuncCallNode StructFuncCall) : StatementNode(Tokens);
public record ReturnNode(List<Token> Tokens, ExpressionNode? Value) : TerminalStatementNode(Tokens); public record ReturnNode(List<Token> Tokens, ExpressionNode? Value) : TerminalStatementNode(Tokens);
public record AssignmentNode(List<Token> Tokens, LValueExpressionNode Target, ExpressionNode Value) : StatementNode(Tokens); public record AssignmentNode(List<Token> Tokens, LValueExpressionNode Target, ExpressionNode Value) : StatementNode(Tokens);
@@ -108,8 +100,6 @@ public record UnaryExpressionNode(List<Token> Tokens, NubType Type, UnaryOperato
public record FuncCallNode(List<Token> Tokens, NubType Type, ExpressionNode Expression, List<ExpressionNode> Parameters) : RValueExpressionNode(Tokens, Type); public record FuncCallNode(List<Token> Tokens, NubType Type, ExpressionNode Expression, List<ExpressionNode> Parameters) : RValueExpressionNode(Tokens, Type);
public record StructFuncCallNode(List<Token> Tokens, NubType Type, string Module, string StructName, string FuncName, ExpressionNode StructExpression, List<ExpressionNode> Parameters) : RValueExpressionNode(Tokens, Type);
public record LValueIdentifierNode(List<Token> Tokens, NubType Type, string Name) : LValueExpressionNode(Tokens, Type); public record LValueIdentifierNode(List<Token> Tokens, NubType Type, string Name) : LValueExpressionNode(Tokens, Type);
public record RValueIdentifierNode(List<Token> Tokens, NubType Type, string Name) : RValueExpressionNode(Tokens, Type); public record RValueIdentifierNode(List<Token> Tokens, NubType Type, string Name) : RValueExpressionNode(Tokens, Type);

View File

@@ -100,7 +100,7 @@ public class NubFuncType(List<NubType> parameters, NubType returnType) : NubType
} }
} }
public class NubStructType(string module, string name, List<NubStructFieldType> fields, List<NubStructFuncType> functions) : NubType public class NubStructType(string module, string name, List<NubStructFieldType> fields) : NubType
{ {
public override bool IsValueType => true; public override bool IsValueType => true;
public override bool IsScalar => false; public override bool IsScalar => false;
@@ -108,9 +108,8 @@ public class NubStructType(string module, string name, List<NubStructFieldType>
public string Module { get; } = module; public string Module { get; } = module;
public string Name { get; } = name; public string Name { get; } = name;
public List<NubStructFieldType> Fields { get; set; } = fields; public List<NubStructFieldType> Fields { get; set; } = fields;
public List<NubStructFuncType> Functions { get; set; } = functions;
public override string ToString() => $"{Module}.{Name}"; public override string ToString() => $"{Module}::{Name}";
public override bool Equals(NubType? other) => other is NubStructType structType && Name == structType.Name && Module == structType.Module; public override bool Equals(NubType? other) => other is NubStructType structType && Name == structType.Name && Module == structType.Module;
public override int GetHashCode() => HashCode.Combine(typeof(NubStructType), Module, Name); public override int GetHashCode() => HashCode.Combine(typeof(NubStructType), Module, Name);
} }

View File

@@ -1,6 +1,5 @@
using System.Diagnostics; using System.Diagnostics;
using NubLang.Diagnostics; using NubLang.Diagnostics;
using NubLang.Modules;
using NubLang.Syntax; using NubLang.Syntax;
namespace NubLang.Ast; namespace NubLang.Ast;
@@ -8,64 +7,69 @@ namespace NubLang.Ast;
public sealed class TypeChecker public sealed class TypeChecker
{ {
private readonly SyntaxTree _syntaxTree; private readonly SyntaxTree _syntaxTree;
private readonly Dictionary<string, Module> _visibleModules; private readonly Dictionary<string, Module> _importedModules;
private readonly Stack<Scope> _scopes = []; private readonly Stack<Scope> _scopes = [];
private readonly Stack<NubType> _funcReturnTypes = []; private readonly Stack<NubType> _funcReturnTypes = [];
private readonly Dictionary<(string Module, string Name), NubType> _typeCache = new(); private readonly Dictionary<(string Module, string Name), NubType> _typeCache = new();
private readonly HashSet<(string Module, string Name)> _resolvingTypes = []; private readonly HashSet<(string Module, string Name)> _resolvingTypes = [];
private readonly HashSet<string> _checkedTemplateStructs = [];
private Scope CurrentScope => _scopes.Peek(); private Scope CurrentScope => _scopes.Peek();
public TypeChecker(SyntaxTree syntaxTree, ModuleRepository moduleRepository) public List<Diagnostic> Diagnostics { get; } = [];
public TypeChecker(SyntaxTree syntaxTree, Dictionary<string, Module> modules)
{ {
_syntaxTree = syntaxTree; _syntaxTree = syntaxTree;
_visibleModules = moduleRepository _importedModules = modules
.Modules() .Where(x => syntaxTree.Imports.Contains(x.Key) || _syntaxTree.ModuleName == x.Key)
.Where(x => syntaxTree.Metadata.Imports.Contains(x.Key) || _syntaxTree.Metadata.ModuleName == x.Key)
.ToDictionary(); .ToDictionary();
} }
public List<DefinitionNode> Definitions { get; } = []; public CompilationUnit Check()
public List<Diagnostic> Diagnostics { get; } = [];
public void Check()
{ {
_scopes.Clear(); _scopes.Clear();
_funcReturnTypes.Clear(); _funcReturnTypes.Clear();
_typeCache.Clear(); _typeCache.Clear();
_resolvingTypes.Clear(); _resolvingTypes.Clear();
_checkedTemplateStructs.Clear();
Diagnostics.Clear(); using (BeginRootScope(_syntaxTree.ModuleName))
Definitions.Clear();
using (BeginRootScope(_syntaxTree.Metadata.ModuleName))
{ {
foreach (var definition in _syntaxTree.Definitions) var functions = new List<FuncNode>();
foreach (var funcSyntax in _syntaxTree.Definitions.OfType<FuncSyntax>())
{ {
try try
{ {
switch (definition) functions.Add(CheckFuncDefinition(funcSyntax));
{
case FuncSyntax funcSyntax:
Definitions.Add(CheckFuncDefinition(funcSyntax));
break;
case StructSyntax structSyntax:
Definitions.Add(CheckStructDefinition(structSyntax));
break;
case StructTemplateSyntax:
break;
default:
throw new ArgumentOutOfRangeException();
}
} }
catch (TypeCheckerException e) catch (TypeCheckerException e)
{ {
Diagnostics.Add(e.Diagnostic); Diagnostics.Add(e.Diagnostic);
} }
} }
var importedStructTypes = new List<NubStructType>();
var importedFunctions = new List<FuncPrototypeNode>();
foreach (var (name, module) in _importedModules)
{
foreach (var structSyntax in module.Structs(false))
{
var fields = structSyntax.Fields
.Select(f => new NubStructFieldType(f.Name, ResolveType(f.Type), f.Value != null))
.ToList();
importedStructTypes.Add(new NubStructType(name, structSyntax.Name, fields));
}
foreach (var funcSyntax in module.Functions(false))
{
importedFunctions.Add(CheckFuncPrototype(funcSyntax.Prototype));
}
}
return new CompilationUnit(functions, importedStructTypes, importedFunctions);
} }
} }
@@ -77,7 +81,7 @@ public sealed class TypeChecker
} }
else else
{ {
_scopes.Push(new Scope(_syntaxTree.Metadata.ModuleName)); _scopes.Push(new Scope(_syntaxTree.ModuleName));
} }
return new ScopeDisposer(this); return new ScopeDisposer(this);
@@ -101,74 +105,25 @@ public sealed class TypeChecker
} }
} }
private StructNode CheckStructDefinition(StructSyntax node)
{
var fieldTypes = node.Fields
.Select(x => new NubStructFieldType(x.Name, ResolveType(x.Type), x.Value != null))
.ToList();
var fieldFunctions = node.Functions
.Select(x =>
{
var parameters = x.Signature.Parameters.Select(y => ResolveType(y.Type)).ToList();
var returnType = ResolveType(x.Signature.ReturnType);
return new NubStructFuncType(x.Name, parameters, returnType);
})
.ToList();
var structType = new NubStructType(CurrentScope.Module, node.Name, fieldTypes, fieldFunctions);
CurrentScope.DeclareVariable(new Variable("this", structType, VariableKind.RValue));
var fields = node.Fields.Select(CheckStructField).ToList();
var functions = node.Functions.Select(CheckStructFunc).ToList();
return new StructNode(node.Tokens, CurrentScope.Module, node.Name, fields, functions);
}
private StructFuncNode CheckStructFunc(StructFuncSyntax function)
{
foreach (var parameter in function.Signature.Parameters)
{
CurrentScope.DeclareVariable(new Variable(parameter.Name, ResolveType(parameter.Type), VariableKind.RValue));
}
_funcReturnTypes.Push(ResolveType(function.Signature.ReturnType));
var body = CheckBlock(function.Body);
_funcReturnTypes.Pop();
return new StructFuncNode(function.Tokens, function.Name, CheckFuncSignature(function.Signature), body);
}
private StructFieldNode CheckStructField(StructFieldSyntax field)
{
ExpressionNode? value = null;
if (field.Value != null)
{
value = CheckExpression(field.Value, ResolveType(field.Type));
}
return new StructFieldNode(field.Tokens, field.Name, ResolveType(field.Type), value);
}
private FuncNode CheckFuncDefinition(FuncSyntax node) private FuncNode CheckFuncDefinition(FuncSyntax node)
{ {
foreach (var parameter in node.Signature.Parameters) foreach (var parameter in node.Prototype.Parameters)
{ {
CurrentScope.DeclareVariable(new Variable(parameter.Name, ResolveType(parameter.Type), VariableKind.RValue)); CurrentScope.DeclareVariable(new Variable(parameter.Name, ResolveType(parameter.Type), VariableKind.RValue));
} }
var signature = CheckFuncSignature(node.Signature); var prototype = CheckFuncPrototype(node.Prototype);
BlockNode? body = null; BlockNode? body = null;
if (node.Body != null) if (node.Body != null)
{ {
_funcReturnTypes.Push(signature.ReturnType); _funcReturnTypes.Push(prototype.ReturnType);
body = CheckBlock(node.Body); body = CheckBlock(node.Body);
if (!AlwaysReturns(body)) if (!AlwaysReturns(body))
{ {
if (signature.ReturnType is NubVoidType) if (prototype.ReturnType is NubVoidType)
{ {
body.Statements.Add(new ReturnNode(node.Tokens.Skip(node.Tokens.Count - 1).ToList(), null)); body.Statements.Add(new ReturnNode(node.Tokens.Skip(node.Tokens.Count - 1).ToList(), null));
} }
@@ -184,7 +139,7 @@ public sealed class TypeChecker
_funcReturnTypes.Pop(); _funcReturnTypes.Pop();
} }
return new FuncNode(node.Tokens, CurrentScope.Module, node.Name, node.ExternSymbol, signature, body); return new FuncNode(node.Tokens, prototype, body);
} }
private AssignmentNode CheckAssignment(AssignmentSyntax statement) private AssignmentNode CheckAssignment(AssignmentSyntax statement)
@@ -231,7 +186,6 @@ public sealed class TypeChecker
return expression switch return expression switch
{ {
FuncCallNode funcCall => new StatementFuncCallNode(statement.Tokens, funcCall), FuncCallNode funcCall => new StatementFuncCallNode(statement.Tokens, funcCall),
StructFuncCallNode structFuncCall => new StatementStructFuncCallNode(statement.Tokens, structFuncCall),
_ => throw new TypeCheckerException(Diagnostic.Error("Expressions statements can only be function calls").At(statement).Build()) _ => throw new TypeCheckerException(Diagnostic.Error("Expressions statements can only be function calls").At(statement).Build())
}; };
} }
@@ -269,7 +223,7 @@ public sealed class TypeChecker
return new WhileNode(statement.Tokens, condition, body); return new WhileNode(statement.Tokens, condition, body);
} }
private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax statement) private FuncPrototypeNode CheckFuncPrototype(FuncPrototypeSyntax statement)
{ {
var parameters = new List<FuncParameterNode>(); var parameters = new List<FuncParameterNode>();
foreach (var parameter in statement.Parameters) foreach (var parameter in statement.Parameters)
@@ -277,7 +231,7 @@ public sealed class TypeChecker
parameters.Add(new FuncParameterNode(parameter.Tokens, parameter.Name, ResolveType(parameter.Type))); parameters.Add(new FuncParameterNode(parameter.Tokens, parameter.Name, ResolveType(parameter.Type)));
} }
return new FuncSignatureNode(statement.Tokens, parameters, ResolveType(statement.ReturnType)); return new FuncPrototypeNode(statement.Tokens, CurrentScope.Module, statement.Name, statement.ExternSymbol, parameters, ResolveType(statement.ReturnType));
} }
private ExpressionNode CheckExpression(ExpressionSyntax node, NubType? expectedType = null) private ExpressionNode CheckExpression(ExpressionSyntax node, NubType? expectedType = null)
@@ -290,7 +244,6 @@ public sealed class TypeChecker
BinaryExpressionSyntax expression => CheckBinaryExpression(expression, expectedType), BinaryExpressionSyntax expression => CheckBinaryExpression(expression, expectedType),
UnaryExpressionSyntax expression => CheckUnaryExpression(expression, expectedType), UnaryExpressionSyntax expression => CheckUnaryExpression(expression, expectedType),
DereferenceSyntax expression => CheckDereference(expression), DereferenceSyntax expression => CheckDereference(expression),
MemberFuncCallSyntax expression => CheckMemberFuncCall(expression),
FuncCallSyntax expression => CheckFuncCall(expression), FuncCallSyntax expression => CheckFuncCall(expression),
LocalIdentifierSyntax expression => CheckLocalIdentifier(expression), LocalIdentifierSyntax expression => CheckLocalIdentifier(expression),
ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression), ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression),
@@ -608,56 +561,6 @@ public sealed class TypeChecker
return new FuncCallNode(expression.Tokens, funcType.ReturnType, accessor, parameters); return new FuncCallNode(expression.Tokens, funcType.ReturnType, accessor, parameters);
} }
private StructFuncCallNode CheckMemberFuncCall(MemberFuncCallSyntax expression)
{
// todo(nub31): When adding interfaces, also support other types than structs
var target = CheckExpression(expression.Target);
if (target.Type is NubStructType structType)
{
var function = structType.Functions.FirstOrDefault(x => x.Name == expression.Name);
if (function == null)
{
throw new TypeCheckerException(Diagnostic
.Error($"Function {expression.Name} not found on struct {structType}")
.At(expression)
.Build());
}
if (expression.Parameters.Count != function.Parameters.Count)
{
throw new TypeCheckerException(Diagnostic
.Error($"Function {function.Name} expects {function.Parameters.Count} parameters but got {expression.Parameters.Count}")
.At(expression.Parameters.LastOrDefault(expression))
.Build());
}
var parameters = new List<ExpressionNode>();
for (var i = 0; i < expression.Parameters.Count; i++)
{
var parameter = expression.Parameters[i];
var expectedType = function.Parameters[i];
var parameterExpression = CheckExpression(parameter, expectedType);
if (parameterExpression.Type != expectedType)
{
throw new TypeCheckerException(Diagnostic
.Error($"Parameter {i + 1} does not match the type {expectedType} for function {function}")
.At(parameter)
.Build());
}
parameters.Add(parameterExpression);
}
return new StructFuncCallNode(expression.Tokens, function.ReturnType, structType.Module, structType.Name, expression.Name, target, parameters);
}
throw new TypeCheckerException(Diagnostic
.Error($"No function {expression.Name} exists on type {target.Type}")
.At(expression)
.Build());
}
private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression) private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression)
{ {
var scopeIdent = CurrentScope.LookupVariable(expression.Name); var scopeIdent = CurrentScope.LookupVariable(expression.Name);
@@ -671,14 +574,14 @@ public sealed class TypeChecker
}; };
} }
var module = _visibleModules[CurrentScope.Module]; var module = _importedModules[CurrentScope.Module];
var function = module.Functions(true).FirstOrDefault(x => x.Name == expression.Name); var function = module.Functions(true).FirstOrDefault(x => x.Name == expression.Name);
if (function != null) if (function != null)
{ {
var parameters = function.Signature.Parameters.Select(x => ResolveType(x.Type)).ToList(); var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Signature.ReturnType)); var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
return new FuncIdentifierNode(expression.Tokens, type, CurrentScope.Module, expression.Name, function.ExternSymbol); return new FuncIdentifierNode(expression.Tokens, type, CurrentScope.Module, expression.Name, function.Prototype.ExternSymbol);
} }
throw new TypeCheckerException(Diagnostic.Error($"Symbol {expression.Name} not found").At(expression).Build()); throw new TypeCheckerException(Diagnostic.Error($"Symbol {expression.Name} not found").At(expression).Build());
@@ -686,7 +589,7 @@ public sealed class TypeChecker
private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression) private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression)
{ {
if (!_visibleModules.TryGetValue(expression.Module, out var module)) if (!_importedModules.TryGetValue(expression.Module, out var module))
{ {
throw new TypeCheckerException(Diagnostic throw new TypeCheckerException(Diagnostic
.Error($"Module {expression.Module} not found") .Error($"Module {expression.Module} not found")
@@ -700,9 +603,9 @@ public sealed class TypeChecker
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)
{ {
var parameters = function.Signature.Parameters.Select(x => ResolveType(x.Type)).ToList(); var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Signature.ReturnType)); var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
return new FuncIdentifierNode(expression.Tokens, type, expression.Module, expression.Name, function.ExternSymbol); return new FuncIdentifierNode(expression.Tokens, type, expression.Module, expression.Name, function.Prototype.ExternSymbol);
} }
throw new TypeCheckerException(Diagnostic throw new TypeCheckerException(Diagnostic
@@ -824,8 +727,6 @@ public sealed class TypeChecker
.Error($"Struct {structType.Name} does not have a field named {initializer.Key}") .Error($"Struct {structType.Name} does not have a field named {initializer.Key}")
.At(initializer.Value) .At(initializer.Value)
.Build()); .Build());
continue;
} }
initializers.Add(initializer.Key, CheckExpression(initializer.Value, typeField.Type)); initializers.Add(initializer.Key, CheckExpression(initializer.Value, typeField.Type));
@@ -849,34 +750,12 @@ public sealed class TypeChecker
private BlockNode CheckBlock(BlockSyntax node) private BlockNode CheckBlock(BlockSyntax node)
{ {
var statements = new List<StatementNode>();
var reachable = true;
var warnedUnreachable = false;
using (BeginScope()) using (BeginScope())
{ {
var statements = new List<StatementNode>();
foreach (var statement in node.Statements) foreach (var statement in node.Statements)
{ {
var checkedStatement = CheckStatement(statement); statements.Add(CheckStatement(statement));
if (reachable)
{
if (checkedStatement is TerminalStatementNode)
{
reachable = false;
}
statements.Add(checkedStatement);
}
else
{
if (!warnedUnreachable)
{
Diagnostics.Add(Diagnostic.Warning("Statement is unreachable").At(statement).Build());
warnedUnreachable = true;
}
}
} }
return new BlockNode(node.Tokens, statements); return new BlockNode(node.Tokens, statements);
@@ -937,27 +816,11 @@ public sealed class TypeChecker
PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType)), PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType)),
StringTypeSyntax => new NubStringType(), StringTypeSyntax => new NubStringType(),
CustomTypeSyntax c => ResolveCustomType(c), CustomTypeSyntax c => ResolveCustomType(c),
StructTemplateTypeSyntax t => ResolveStructTemplateType(t),
SubstitutionTypeSyntax s => ResolveTypeSubstitution(s),
VoidTypeSyntax => new NubVoidType(), VoidTypeSyntax => new NubVoidType(),
_ => throw new NotSupportedException($"Unknown type syntax: {type}") _ => throw new NotSupportedException($"Unknown type syntax: {type}")
}; };
} }
private NubType ResolveTypeSubstitution(SubstitutionTypeSyntax substitution)
{
var type = CurrentScope.LookupTypeSubstitution(substitution.Name);
if (type == null)
{
throw new TypeCheckerException(Diagnostic
.Error($"Template argument {substitution.Name} does not exist")
.At(substitution)
.Build());
}
return type;
}
private NubType ResolveCustomType(CustomTypeSyntax customType) private NubType ResolveCustomType(CustomTypeSyntax customType)
{ {
var key = (customType.Module, customType.Name); var key = (customType.Module, customType.Name);
@@ -969,14 +832,14 @@ public sealed class TypeChecker
if (!_resolvingTypes.Add(key)) if (!_resolvingTypes.Add(key))
{ {
var placeholder = new NubStructType(customType.Module, customType.Name, [], []); var placeholder = new NubStructType(customType.Module, customType.Name, []);
_typeCache[key] = placeholder; _typeCache[key] = placeholder;
return placeholder; return placeholder;
} }
try try
{ {
if (!_visibleModules.TryGetValue(customType.Module, out var module)) if (!_importedModules.TryGetValue(customType.Module, out var module))
{ {
throw new TypeCheckerException(Diagnostic throw new TypeCheckerException(Diagnostic
.Error($"Module {customType.Module} not found") .Error($"Module {customType.Module} not found")
@@ -990,7 +853,7 @@ public sealed class TypeChecker
var structDef = module.Structs(includePrivate).FirstOrDefault(x => x.Name == customType.Name); var structDef = module.Structs(includePrivate).FirstOrDefault(x => x.Name == customType.Name);
if (structDef != null) if (structDef != null)
{ {
var result = new NubStructType(customType.Module, structDef.Name, [], []); var result = new NubStructType(customType.Module, structDef.Name, []);
_typeCache[key] = result; _typeCache[key] = result;
var fields = structDef.Fields var fields = structDef.Fields
@@ -998,19 +861,6 @@ public sealed class TypeChecker
.ToList(); .ToList();
result.Fields.AddRange(fields); result.Fields.AddRange(fields);
var functions = structDef.Functions
.Select(x =>
{
var parameters = x.Signature.Parameters
.Select(y => ResolveType(y.Type))
.ToList();
return new NubStructFuncType(x.Name, parameters, ResolveType(x.Signature.ReturnType));
})
.ToList();
result.Functions.AddRange(functions);
return result; return result;
} }
@@ -1024,71 +874,6 @@ public sealed class TypeChecker
_resolvingTypes.Remove(key); _resolvingTypes.Remove(key);
} }
} }
private NubStructType ResolveStructTemplateType(StructTemplateTypeSyntax structTemplate)
{
if (!_visibleModules.TryGetValue(structTemplate.Module, out var module))
{
throw new TypeCheckerException(Diagnostic
.Error($"Module {structTemplate.Module} not found")
.WithHelp($"import \"{structTemplate.Module}\"")
.At(structTemplate)
.Build());
}
var includePrivate = structTemplate.Module == CurrentScope.Module;
var templateDef = module
.StructTemplates(includePrivate)
.FirstOrDefault(x => x.Name == structTemplate.Name);
if (templateDef == null)
{
throw new TypeCheckerException(Diagnostic
.Error($"Template type {structTemplate.Name} not found in module {structTemplate.Module}")
.At(structTemplate)
.Build());
}
var templateParameterTypes = structTemplate.TemplateParameters.Select(ResolveType).ToList();
var mangledName = $"{structTemplate.Name}.{NameMangler.Mangle(templateParameterTypes)}";
using (BeginRootScope(structTemplate.Module))
{
for (var i = 0; i < templateParameterTypes.Count; i++)
{
var parameterName = templateDef.TemplateArguments[i];
var parameterType = templateParameterTypes[i];
CurrentScope.DeclareTypeSubstitution(parameterName, parameterType);
}
var fieldTypes = templateDef.Fields
.Select(x => new NubStructFieldType(x.Name, ResolveType(x.Type), x.Value != null))
.ToList();
var fieldFunctions = templateDef.Functions
.Select(x =>
{
var parameters = x.Signature.Parameters.Select(y => ResolveType(y.Type)).ToList();
var returnType = ResolveType(x.Signature.ReturnType);
return new NubStructFuncType(x.Name, parameters, returnType);
})
.ToList();
var structType = new NubStructType(structTemplate.Module, mangledName, fieldTypes, fieldFunctions);
if (!_checkedTemplateStructs.Contains($"{structTemplate.Module}.{mangledName}"))
{
CurrentScope.DeclareVariable(new Variable("this", structType, VariableKind.RValue));
var fields = templateDef.Fields.Select(CheckStructField).ToList();
var functions = templateDef.Functions.Select(CheckStructFunc).ToList();
Definitions.Add(new StructNode(templateDef.Tokens, structTemplate.Module, mangledName, fields, functions));
_checkedTemplateStructs.Add($"{structTemplate.Module}.{mangledName}");
}
return structType;
}
}
} }
public enum VariableKind public enum VariableKind

View File

@@ -1,4 +1,3 @@
using System.Text;
using NubLang.Ast; using NubLang.Ast;
using NubLang.Syntax; using NubLang.Syntax;
@@ -6,17 +5,14 @@ namespace NubLang.Generation;
public class Generator public class Generator
{ {
private readonly List<DefinitionNode> _definitions; private readonly CompilationUnit _compilationUnit;
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 List<NubStructType> _structTypes = [];
private int _tmpIndex; private int _tmpIndex;
private int _funcDefIndex;
public Generator(List<DefinitionNode> definitions) public Generator(CompilationUnit compilationUnit)
{ {
_definitions = definitions; _compilationUnit = compilationUnit;
_writer = new IndentedTextWriter(); _writer = new IndentedTextWriter();
} }
@@ -26,54 +22,6 @@ public class Generator
return $"_t{++_tmpIndex}"; return $"_t{++_tmpIndex}";
} }
private string MapType(NubType nubType)
{
return nubType switch
{
NubArrayType arrayType => MapType(arrayType.ElementType),
NubConstArrayType arrayType => MapType(arrayType.ElementType),
NubBoolType => "bool",
NubCStringType => "char",
NubFloatType floatType => floatType.Width switch
{
32 => "f32",
64 => "f64",
_ => throw new ArgumentOutOfRangeException()
},
NubFuncType funcType => MapFuncType(funcType),
NubIntType intType => (intType.Signed, intType.Width) switch
{
(false, 8) => "u8",
(false, 16) => "u16",
(false, 32) => "u32",
(false, 64) => "u64",
(true, 8) => "i8",
(true, 16) => "i16",
(true, 32) => "i32",
(true, 64) => "i64",
_ => throw new ArgumentOutOfRangeException()
},
NubPointerType pointerType => MapType(pointerType.BaseType),
NubStringType => throw new NotImplementedException(),
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}";
_funcDefs.Push((name, funcType));
return name;
}
private string MapNameWithType(NubType nubType, string name) private string MapNameWithType(NubType nubType, string name)
{ {
var prefix = ""; var prefix = "";
@@ -81,7 +29,7 @@ public class Generator
switch (nubType) switch (nubType)
{ {
case NubCStringType or NubPointerType: case NubCStringType or NubPointerType or NubFuncType:
prefix = "*"; prefix = "*";
break; break;
case NubArrayType: case NubArrayType:
@@ -92,7 +40,42 @@ public class Generator
break; break;
} }
return $"{MapType(nubType)} {prefix}{name}{postfix}"; return $"{MapBaseType(nubType)} {prefix}{name}{postfix}";
string MapBaseType(NubType type)
{
return type switch
{
NubArrayType arrayType => MapBaseType(arrayType.ElementType),
NubConstArrayType arrayType => MapBaseType(arrayType.ElementType),
NubBoolType => "bool",
NubCStringType => "char",
NubFloatType floatType => floatType.Width switch
{
32 => "f32",
64 => "f64",
_ => throw new ArgumentOutOfRangeException()
},
NubFuncType funcType => "void",
NubIntType intType => (intType.Signed, intType.Width) switch
{
(false, 8) => "u8",
(false, 16) => "u16",
(false, 32) => "u32",
(false, 64) => "u64",
(true, 8) => "i8",
(true, 16) => "i16",
(true, 32) => "i32",
(true, 64) => "i64",
_ => throw new ArgumentOutOfRangeException()
},
NubPointerType pointerType => MapBaseType(pointerType.BaseType),
NubStringType => throw new NotImplementedException(),
NubStructType structType => StructName(structType.Module, structType.Name),
NubVoidType => "void",
_ => throw new ArgumentOutOfRangeException(nameof(type))
};
}
} }
private static string FuncName(string module, string name, string? externSymbol) private static string FuncName(string module, string name, string? externSymbol)
@@ -105,139 +88,101 @@ public class Generator
return $"{module}_{name}"; return $"{module}_{name}";
} }
private static string StructFuncName(string module, string name, string function)
{
return $"{module}_{name}_{function}";
}
public string Emit() public string Emit()
{ {
const string header = """ // note(nub31): Struct definitions
typedef __builtin_va_list va_list; foreach (var structType in _compilationUnit.ImportedStructTypes)
#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#define NULL ((void*)0)
typedef unsigned long size_t;
typedef unsigned long uintptr_t;
#define offsetof(type, member) __builtin_offsetof(type, member)
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
typedef float f32;
typedef double f64;
#define I8_C(x) x
#define U8_C(x) x##U
#define I16_C(x) x
#define U16_C(x) x##U
#define I32_C(x) x
#define U32_C(x) x##U
#define I64_C(x) x##LL
#define U64_C(x) x##ULL
""";
_writer.WriteLine();
var appendNewLine = false;
foreach (var funcNode in _definitions.OfType<FuncNode>())
{ {
EmitLine(funcNode.Tokens.FirstOrDefault()); _writer.WriteLine("typedef struct");
appendNewLine = true; _writer.WriteLine("{");
var parameters = funcNode.Signature.Parameters.Count != 0 using (_writer.Indent())
? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name))) {
: "void"; foreach (var field in structType.Fields)
{
_writer.WriteLine($"{MapNameWithType(field.Type, field.Name)};");
}
}
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol); _writer.WriteLine($"}} {StructName(structType.Module, structType.Name)};");
_writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters});");
}
if (appendNewLine)
{
_writer.WriteLine(); _writer.WriteLine();
} }
foreach (var structNode in _definitions.OfType<StructNode>()) // note(nub31): Forward declarations
foreach (var prototype in _compilationUnit.ImportedFunctions)
{ {
foreach (var structFuncNode in structNode.Functions) EmitLine(prototype.Tokens.FirstOrDefault());
{ var parameters = prototype.Parameters.Count != 0
EmitLine(structFuncNode.Tokens.FirstOrDefault()); ? string.Join(", ", prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
var parameters = structFuncNode.Signature.Parameters.Count != 0 : "void";
? string.Join(", ", structFuncNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
var name = StructFuncName(structNode.Module, structNode.Name, structFuncNode.Name); var name = FuncName(prototype.Module, prototype.Name, prototype.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(structFuncNode.Signature.ReturnType, name)}({parameters})"); _writer.WriteLine($"{MapNameWithType(prototype.ReturnType, name)}({parameters});");
EmitBlock(structFuncNode.Body);
_writer.WriteLine();
}
} }
foreach (var funcNode in _definitions.OfType<FuncNode>()) _writer.WriteLine();
// note(nub31): Normal functions
foreach (var funcNode in _compilationUnit.Functions)
{ {
if (funcNode.Body == null) continue; if (funcNode.Body == null) continue;
EmitLine(funcNode.Tokens.FirstOrDefault()); EmitLine(funcNode.Tokens.FirstOrDefault());
var parameters = funcNode.Signature.Parameters.Count != 0 var parameters = funcNode.Prototype.Parameters.Count != 0
? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name))) ? string.Join(", ", funcNode.Prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void"; : "void";
if (funcNode.ExternSymbol == null) if (funcNode.Prototype.ExternSymbol == null)
{ {
_writer.Write("static "); _writer.Write("static ");
} }
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol); var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters})"); _writer.WriteLine($"{MapNameWithType(funcNode.Prototype.ReturnType, name)}({parameters})");
EmitBlock(funcNode.Body); EmitBlock(funcNode.Body);
_writer.WriteLine(); _writer.WriteLine();
} }
List<string> typedefs = []; return $"""
typedef __builtin_va_list va_list;
while (_funcDefs.TryPop(out var funcTypeDef)) #define va_start(ap, last) __builtin_va_start(ap, last)
{ #define va_arg(ap, type) __builtin_va_arg(ap, type)
var returnType = MapType(funcTypeDef.FuncType.ReturnType); #define va_end(ap) __builtin_va_end(ap)
var paramList = string.Join(", ", funcTypeDef.FuncType.Parameters.Select((type, i) => MapNameWithType(type, $"arg{i}"))); #define va_copy(dest, src) __builtin_va_copy(dest, src)
if (funcTypeDef.FuncType.Parameters.Count == 0)
{
paramList = "void";
}
typedefs.Add($"typedef {returnType} (*{funcTypeDef.Name})({paramList});"); #define NULL ((void*)0)
}
var structDefSb = new StringBuilder(); typedef unsigned long size_t;
foreach (var structType in _structTypes) typedef unsigned long uintptr_t;
{
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)};"); #define offsetof(type, member) __builtin_offsetof(type, member)
structDefSb.AppendLine();
}
return header + structDefSb + "\n\n" + string.Join('\n', typedefs) + "\n\n" + _writer; typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
typedef float f32;
typedef double f64;
#define I8_C(x) x
#define U8_C(x) x##U
#define I16_C(x) x
#define U16_C(x) x##U
#define I32_C(x) x
#define U32_C(x) x##U
#define I64_C(x) x##LL
#define U64_C(x) x##ULL
{_writer}
""";
} }
private void EmitStatement(StatementNode statementNode) private void EmitStatement(StatementNode statementNode)
@@ -269,9 +214,6 @@ public class Generator
case StatementFuncCallNode statementFuncCallNode: case StatementFuncCallNode statementFuncCallNode:
EmitStatementFuncCall(statementFuncCallNode); EmitStatementFuncCall(statementFuncCallNode);
break; break;
case StatementStructFuncCallNode statementStructFuncCallNode:
EmitStatementStructFuncCall(statementStructFuncCallNode);
break;
case VariableDeclarationNode variableDeclarationNode: case VariableDeclarationNode variableDeclarationNode:
EmitVariableDeclaration(variableDeclarationNode); EmitVariableDeclaration(variableDeclarationNode);
break; break;
@@ -316,7 +258,7 @@ public class Generator
private void EmitIf(IfNode ifNode, bool elseIf = false) private void EmitIf(IfNode ifNode, bool elseIf = false)
{ {
var condition = EmitExpression(ifNode.Condition); var condition = EmitExpression(ifNode.Condition);
_writer.WriteLine($"{(elseIf ? "else" : "")} if ({condition})"); _writer.WriteLine($"{(elseIf ? "else " : "")}if ({condition})");
EmitBlock(ifNode.Body); EmitBlock(ifNode.Body);
ifNode.Else?.Match ifNode.Else?.Match
( (
@@ -373,12 +315,6 @@ public class Generator
_writer.WriteLine($"{funcCall};"); _writer.WriteLine($"{funcCall};");
} }
private void EmitStatementStructFuncCall(StatementStructFuncCallNode statementStructFuncCallNode)
{
var structFuncCall = EmitStructFuncCall(statementStructFuncCallNode.StructFuncCall);
_writer.WriteLine($"{structFuncCall};");
}
private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode) private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode)
{ {
if (variableDeclarationNode.Assignment != null) if (variableDeclarationNode.Assignment != null)
@@ -423,7 +359,6 @@ public class Generator
SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode), SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode),
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode), StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode), StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode),
StructFuncCallNode structFuncCallNode => EmitStructFuncCall(structFuncCallNode),
StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode), StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode),
UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode), UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode),
UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode), UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode),
@@ -606,12 +541,7 @@ public class Generator
private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode) private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode)
{ {
if (sizeBuiltinNode.TargetType is NubConstArrayType constArrayType) throw new NotImplementedException();
{
return $"sizeof({MapType(constArrayType.ElementType)}) * {constArrayType.Size}";
}
return $"sizeof({MapType(sizeBuiltinNode.TargetType)})";
} }
private string EmitStringLiteral(StringLiteralNode stringLiteralNode) private string EmitStringLiteral(StringLiteralNode stringLiteralNode)
@@ -625,14 +555,6 @@ public class Generator
return $"{structExpr}.{structFieldAccessNode.Field}"; return $"{structExpr}.{structFieldAccessNode.Field}";
} }
private string EmitStructFuncCall(StructFuncCallNode structFuncCallNode)
{
var thisParameter = EmitExpression(structFuncCallNode.StructExpression);
var name = StructFuncName(structFuncCallNode.Module, structFuncCallNode.StructName, structFuncCallNode.FuncName);
var parameterNames = structFuncCallNode.Parameters.Select(EmitExpression).ToList();
return $"{name}({thisParameter}, {string.Join(", ", parameterNames)})";
}
private string EmitStructInitializer(StructInitializerNode structInitializerNode) private string EmitStructInitializer(StructInitializerNode structInitializerNode)
{ {
var initValues = new List<string>(); var initValues = new List<string>();

View File

@@ -1,37 +0,0 @@
using NubLang.Syntax;
namespace NubLang.Modules;
public class Module
{
private readonly List<DefinitionSyntax> _definitions = [];
public void Register(DefinitionSyntax definition)
{
_definitions.Add(definition);
}
public List<StructSyntax> Structs(bool includePrivate)
{
return _definitions
.OfType<StructSyntax>()
.Where(x => x.Exported || includePrivate)
.ToList();
}
public List<StructTemplateSyntax> StructTemplates(bool includePrivate)
{
return _definitions
.OfType<StructTemplateSyntax>()
.Where(x => x.Exported || includePrivate)
.ToList();
}
public List<FuncSyntax> Functions(bool includePrivate)
{
return _definitions
.OfType<FuncSyntax>()
.Where(x => x.Exported || includePrivate)
.ToList();
}
}

View File

@@ -1,41 +0,0 @@
using NubLang.Syntax;
namespace NubLang.Modules;
public class ModuleRepository
{
private readonly Dictionary<string, Module> _modules = new();
public ModuleRepository(List<SyntaxTree> syntaxTrees)
{
foreach (var syntaxTree in syntaxTrees)
{
var module = GetOrCreate(syntaxTree.Metadata.ModuleName);
ProcessSyntaxTree(module, syntaxTree);
}
}
private static void ProcessSyntaxTree(Module module, SyntaxTree syntaxTree)
{
foreach (var definition in syntaxTree.Definitions)
{
module.Register(definition);
}
}
public Dictionary<string, Module> Modules()
{
return _modules;
}
private Module GetOrCreate(string name)
{
if (!_modules.TryGetValue(name, out var module))
{
module = new Module();
_modules[name] = module;
}
return module;
}
}

View File

@@ -0,0 +1,39 @@
namespace NubLang.Syntax;
public sealed class Module
{
public static Dictionary<string, Module> Collect(List<SyntaxTree> syntaxTrees)
{
var modules = new Dictionary<string, Module>();
foreach (var syntaxTree in syntaxTrees)
{
if (!modules.TryGetValue(syntaxTree.ModuleName, out var module))
{
module = new Module();
modules.Add(syntaxTree.ModuleName, module);
}
module._definitions.AddRange(syntaxTree.Definitions);
}
return modules;
}
private readonly List<DefinitionSyntax> _definitions = [];
public List<StructSyntax> Structs(bool includePrivate)
{
return _definitions
.OfType<StructSyntax>()
.Where(x => x.Exported || includePrivate)
.ToList();
}
public List<FuncSyntax> Functions(bool includePrivate)
{
return _definitions
.OfType<FuncSyntax>()
.Where(x => x.Exported || includePrivate)
.ToList();
}
}

View File

@@ -5,7 +5,6 @@ namespace NubLang.Syntax;
public sealed class Parser public sealed class Parser
{ {
private readonly HashSet<string> _templateArguments = [];
private List<Token> _tokens = []; private List<Token> _tokens = [];
private int _tokenIndex; private int _tokenIndex;
private string _moduleName = string.Empty; private string _moduleName = string.Empty;
@@ -21,16 +20,7 @@ public sealed class Parser
_tokens = tokens; _tokens = tokens;
_tokenIndex = 0; _tokenIndex = 0;
_moduleName = string.Empty; _moduleName = string.Empty;
_templateArguments.Clear();
var metadata = ParseMetadata();
var definitions = ParseDefinitions();
return new SyntaxTree(definitions, metadata);
}
private SyntaxTreeMetadata ParseMetadata()
{
var imports = new List<string>(); var imports = new List<string>();
try try
@@ -57,11 +47,6 @@ public sealed class Parser
} }
} }
return new SyntaxTreeMetadata(_moduleName, imports);
}
private List<DefinitionSyntax> ParseDefinitions()
{
var definitions = new List<DefinitionSyntax>(); var definitions = new List<DefinitionSyntax>();
while (HasToken) while (HasToken)
@@ -80,7 +65,7 @@ public sealed class Parser
} }
var keyword = ExpectSymbol(); var keyword = ExpectSymbol();
var definition = keyword.Symbol switch DefinitionSyntax definition = keyword.Symbol switch
{ {
Symbol.Func => ParseFunc(startIndex, exported, null), Symbol.Func => ParseFunc(startIndex, exported, null),
Symbol.Struct => ParseStruct(startIndex, exported), Symbol.Struct => ParseStruct(startIndex, exported),
@@ -108,12 +93,22 @@ public sealed class Parser
} }
} }
return definitions; return new SyntaxTree(definitions, _moduleName, imports);
} }
private FuncSignatureSyntax ParseFuncSignature() private FuncParameterSyntax ParseFuncParameter()
{ {
var startIndex = _tokenIndex; var startIndex = _tokenIndex;
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon);
var type = ParseType();
return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
}
private FuncSyntax ParseFunc(int startIndex, bool exported, string? externSymbol)
{
var name = ExpectIdentifier();
List<FuncParameterSyntax> parameters = []; List<FuncParameterSyntax> parameters = [];
ExpectSymbol(Symbol.OpenParen); ExpectSymbol(Symbol.OpenParen);
@@ -131,23 +126,7 @@ public sealed class Parser
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax([]); var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax([]);
return new FuncSignatureSyntax(GetTokens(startIndex), parameters, returnType); var prototype = new FuncPrototypeSyntax(GetTokens(startIndex), name.Value, exported, externSymbol, parameters, returnType);
}
private FuncParameterSyntax ParseFuncParameter()
{
var startIndex = _tokenIndex;
var name = ExpectIdentifier();
ExpectSymbol(Symbol.Colon);
var type = ParseType();
return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
}
private FuncSyntax ParseFunc(int startIndex, bool exported, string? externSymbol)
{
var name = ExpectIdentifier();
var signature = ParseFuncSignature();
BlockSyntax? body = null; BlockSyntax? body = null;
var bodyStartIndex = _tokenIndex; var bodyStartIndex = _tokenIndex;
@@ -156,64 +135,36 @@ public sealed class Parser
body = ParseBlock(bodyStartIndex); body = ParseBlock(bodyStartIndex);
} }
return new FuncSyntax(GetTokens(startIndex), name.Value, exported, externSymbol, signature, body); return new FuncSyntax(GetTokens(startIndex), prototype, body);
} }
private DefinitionSyntax ParseStruct(int startIndex, bool exported) private StructSyntax ParseStruct(int startIndex, bool exported)
{ {
var name = ExpectIdentifier(); var name = ExpectIdentifier();
if (TryExpectSymbol(Symbol.LessThan))
{
while (!TryExpectSymbol(Symbol.GreaterThan))
{
_templateArguments.Add(ExpectIdentifier().Value);
TryExpectSymbol(Symbol.Comma);
}
}
ExpectSymbol(Symbol.OpenBrace); ExpectSymbol(Symbol.OpenBrace);
List<StructFieldSyntax> fields = []; List<StructFieldSyntax> fields = [];
List<StructFuncSyntax> funcs = [];
while (!TryExpectSymbol(Symbol.CloseBrace)) while (!TryExpectSymbol(Symbol.CloseBrace))
{ {
var memberStartIndex = _tokenIndex; var memberStartIndex = _tokenIndex;
if (TryExpectSymbol(Symbol.Func)) var fieldName = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Colon);
var fieldType = ParseType();
ExpressionSyntax? fieldValue = null;
if (TryExpectSymbol(Symbol.Assign))
{ {
var funcName = ExpectIdentifier().Value; fieldValue = ParseExpression();
var funcSignature = ParseFuncSignature();
var funcBody = ParseBlock();
funcs.Add(new StructFuncSyntax(GetTokens(memberStartIndex), funcName, funcSignature, funcBody));
} }
else
{
var fieldName = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Colon);
var fieldType = ParseType();
ExpressionSyntax? fieldValue = null; fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldType, fieldValue));
if (TryExpectSymbol(Symbol.Assign))
{
fieldValue = ParseExpression();
}
fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldType, fieldValue));
}
} }
if (_templateArguments.Count > 0) return new StructSyntax(GetTokens(startIndex), name.Value, exported, fields);
{
var templateArguments = _templateArguments.ToList();
_templateArguments.Clear();
return new StructTemplateSyntax(GetTokens(startIndex), templateArguments, name.Value, exported, fields, funcs);
}
return new StructSyntax(GetTokens(startIndex), name.Value, exported, fields, funcs);
} }
private StatementSyntax ParseStatement() private StatementSyntax ParseStatement()
@@ -543,24 +494,6 @@ public sealed class Parser
if (TryExpectSymbol(Symbol.Period)) if (TryExpectSymbol(Symbol.Period))
{ {
var member = ExpectIdentifier().Value; var member = ExpectIdentifier().Value;
if (TryExpectSymbol(Symbol.OpenParen))
{
var parameters = new List<ExpressionSyntax>();
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseExpression());
if (!TryExpectSymbol(Symbol.Comma))
{
ExpectSymbol(Symbol.CloseParen);
break;
}
}
expr = new MemberFuncCallSyntax(GetTokens(startIndex), member, expr, parameters);
continue;
}
expr = new MemberAccessSyntax(GetTokens(startIndex), expr, member); expr = new MemberAccessSyntax(GetTokens(startIndex), expr, member);
continue; continue;
} }
@@ -672,11 +605,6 @@ public sealed class Parser
var startIndex = _tokenIndex; var startIndex = _tokenIndex;
if (TryExpectIdentifier(out var name)) if (TryExpectIdentifier(out var name))
{ {
if (_templateArguments.Contains(name.Value))
{
return new SubstitutionTypeSyntax(GetTokens(startIndex), name.Value);
}
if (name.Value[0] == 'u' && int.TryParse(name.Value[1..], out var size)) if (name.Value[0] == 'u' && int.TryParse(name.Value[1..], out var size))
{ {
if (size is not 8 and not 16 and not 32 and not 64) if (size is not 8 and not 16 and not 32 and not 64)
@@ -740,21 +668,6 @@ public sealed class Parser
name = customTypeName; name = customTypeName;
} }
var templateParameters = new List<TypeSyntax>();
if (TryExpectSymbol(Symbol.LessThan))
{
while (!TryExpectSymbol(Symbol.GreaterThan))
{
templateParameters.Add(ParseType());
TryExpectSymbol(Symbol.Comma);
}
}
if (templateParameters.Count > 0)
{
return new StructTemplateTypeSyntax(GetTokens(startIndex), templateParameters, module, name.Value);
}
return new CustomTypeSyntax(GetTokens(startIndex), module, name.Value); return new CustomTypeSyntax(GetTokens(startIndex), module, name.Value);
} }
} }
@@ -946,9 +859,7 @@ public sealed class Parser
} }
} }
public record SyntaxTreeMetadata(string ModuleName, List<string> Imports); public record SyntaxTree(List<DefinitionSyntax> Definitions, string ModuleName, List<string> Imports);
public record SyntaxTree(List<DefinitionSyntax> Definitions, SyntaxTreeMetadata Metadata);
public class ParseException : Exception public class ParseException : Exception
{ {

View File

@@ -8,17 +8,13 @@ public abstract record DefinitionSyntax(List<Token> Tokens, string Name, bool Ex
public record FuncParameterSyntax(List<Token> Tokens, string Name, TypeSyntax Type) : SyntaxNode(Tokens); public record FuncParameterSyntax(List<Token> Tokens, string Name, TypeSyntax Type) : SyntaxNode(Tokens);
public record FuncSignatureSyntax(List<Token> Tokens, List<FuncParameterSyntax> Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens); public record FuncPrototypeSyntax(List<Token> Tokens, string Name, bool Exported, string? ExternSymbol, List<FuncParameterSyntax> Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens);
public record FuncSyntax(List<Token> Tokens, string Name, bool Exported, string? ExternSymbol, FuncSignatureSyntax Signature, BlockSyntax? Body) : DefinitionSyntax(Tokens, Name, Exported); public record FuncSyntax(List<Token> Tokens, FuncPrototypeSyntax Prototype, BlockSyntax? Body) : DefinitionSyntax(Tokens, Prototype.Name, Prototype.Exported);
public record StructFieldSyntax(List<Token> Tokens, string Name, TypeSyntax Type, ExpressionSyntax? Value) : SyntaxNode(Tokens); public record StructFieldSyntax(List<Token> Tokens, string Name, TypeSyntax Type, ExpressionSyntax? Value) : SyntaxNode(Tokens);
public record StructFuncSyntax(List<Token> Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : SyntaxNode(Tokens); public record StructSyntax(List<Token> Tokens, string Name, bool Exported, List<StructFieldSyntax> Fields) : DefinitionSyntax(Tokens, Name, Exported);
public record StructSyntax(List<Token> Tokens, 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 enum UnaryOperatorSyntax public enum UnaryOperatorSyntax
{ {
@@ -86,8 +82,6 @@ public record UnaryExpressionSyntax(List<Token> Tokens, UnaryOperatorSyntax Oper
public record FuncCallSyntax(List<Token> Tokens, ExpressionSyntax Expression, List<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens); public record FuncCallSyntax(List<Token> Tokens, ExpressionSyntax Expression, List<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens);
public record MemberFuncCallSyntax(List<Token> Tokens, string Name, ExpressionSyntax Target, List<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens);
public record LocalIdentifierSyntax(List<Token> Tokens, string Name) : ExpressionSyntax(Tokens); public record LocalIdentifierSyntax(List<Token> Tokens, string Name) : ExpressionSyntax(Tokens);
public record ModuleIdentifierSyntax(List<Token> Tokens, string Module, string Name) : ExpressionSyntax(Tokens); public record ModuleIdentifierSyntax(List<Token> Tokens, string Module, string Name) : ExpressionSyntax(Tokens);
@@ -146,8 +140,4 @@ public record ConstArrayTypeSyntax(List<Token> Tokens, TypeSyntax BaseType, int
public record CustomTypeSyntax(List<Token> Tokens, string Module, string Name) : TypeSyntax(Tokens); public record CustomTypeSyntax(List<Token> Tokens, string Module, string Name) : TypeSyntax(Tokens);
public record StructTemplateTypeSyntax(List<Token> Tokens, List<TypeSyntax> TemplateParameters, string Module, string Name) : TypeSyntax(Tokens);
public record SubstitutionTypeSyntax(List<Token> Tokens, string Name) : TypeSyntax(Tokens);
#endregion #endregion

View File

@@ -5,7 +5,10 @@ module "main"
extern "main" func main(args: []cstring): i64 extern "main" func main(args: []cstring): i64
{ {
raylib::SetConfigFlags(4 | 64) raylib::SetConfigFlags(4 | 64)
raylib::InitWindow(1600, 900, "Hi from nub-lang") raylib::InitWindow(1600, 900, "Hi from nub-lang")
defer raylib::CloseWindow()
raylib::SetTargetFPS(240) raylib::SetTargetFPS(240)
let width: i32 = 150 let width: i32 = 150
@@ -20,26 +23,20 @@ extern "main" func main(args: []cstring): i64
let bgColor: raylib::Color = { r = 0 g = 0 b = 0 a = 255 } let bgColor: raylib::Color = { r = 0 g = 0 b = 0 a = 255 }
let color: raylib::Color = { r = 255 g = 255 b = 255 a = 255 } let color: raylib::Color = { r = 255 g = 255 b = 255 a = 255 }
while !raylib::WindowShouldClose() while !raylib::WindowShouldClose() {
{ if x <= 0 {
if x <= 0
{
direction.x = 1 direction.x = 1
} } else if x + width >= raylib::GetScreenWidth() {
else if x + width >= raylib::GetScreenWidth()
{
direction.x = -1 direction.x = -1
} }
else if y <= 0
{ if y <= 0 {
direction.y = 1 direction.y = 1
} } else if y + height >= raylib::GetScreenHeight() {
else if y + height >= raylib::GetScreenHeight()
{
direction.y = -1 direction.y = -1
} }
x = x + @floatToInt(i32, direction.x * speed * raylib::GetFrameTime()) x = x + @floatToInt(i32, direction.x * speed * raylib::GetFrameTime())
y = y + @floatToInt(i32, direction.y * speed * raylib::GetFrameTime()) y = y + @floatToInt(i32, direction.y * speed * raylib::GetFrameTime())
raylib::BeginDrawing() raylib::BeginDrawing()