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.Diagnostics;
using NubLang.Generation;
using NubLang.Modules;
using NubLang.Syntax;
var diagnostics = new List<Diagnostic>();
var syntaxTrees = new List<SyntaxTree>();
var nubFiles = args.Where(x => Path.GetExtension(x) == ".nub");
var objectFiles = args.Where(x => Path.GetExtension(x) is ".o" or ".a");
var nubFiles = args.Where(x => Path.GetExtension(x) == ".nub").ToArray();
var objectFileArgs = args.Where(x => Path.GetExtension(x) is ".o" or ".a").ToArray();
foreach (var file in nubFiles)
{
@@ -24,16 +23,15 @@ foreach (var file in nubFiles)
syntaxTrees.Add(syntaxTree);
}
var moduleRepository = new ModuleRepository(syntaxTrees);
var modules = Module.Collect(syntaxTrees);
var compilationUnits = new List<CompilationUnit>();
var definitions = new List<DefinitionNode>();
foreach (var syntaxTree in syntaxTrees)
for (var i = 0; i < nubFiles.Length; i++)
{
var typeChecker = new TypeChecker(syntaxTree, moduleRepository);
typeChecker.Check();
var typeChecker = new TypeChecker(syntaxTrees[i], modules);
var compilationUnit = typeChecker.Check();
definitions.AddRange(typeChecker.Definitions);
compilationUnits.Add(compilationUnit);
diagnostics.AddRange(typeChecker.Diagnostics);
}
@@ -47,36 +45,57 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
return 1;
}
var cPaths = new List<string>();
Directory.CreateDirectory(".build");
var generator = new Generator(definitions);
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)
for (var i = 0; i < nubFiles.Length; i++)
{
Console.Error.WriteLine($"gcc failed with exit code {compileProcess.ExitCode}");
return 1;
var file = nubFiles[i];
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
.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 = $"""
.intel_syntax noprefix
@@ -85,7 +104,7 @@ if (moduleRepository.Modules().TryGetValue("main", out var mainModule))
.globl _start
_start:
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 rax, 60 # syscall: exit
syscall
@@ -111,9 +130,9 @@ if (moduleRepository.Modules().TryGetValue("main", out var mainModule))
"-ffreestanding", "-nostartfiles", "-std=c23",
"-g", "-lm",
"-o", Path.Combine(".build", "out"),
Path.Combine(".build", "out.o"),
..objectPaths,
Path.Combine(".build", "runtime.o"),
..objectFiles
..objectFileArgs
]));
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 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 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);
public record FuncNode(List<Token> Tokens, FuncPrototypeNode Prototype, BlockNode? Body) : DefinitionNode(Tokens, Prototype.Module, Prototype.Name);
#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 StatementStructFuncCallNode(List<Token> Tokens, StructFuncCallNode StructFuncCall) : StatementNode(Tokens);
public record ReturnNode(List<Token> Tokens, ExpressionNode? Value) : TerminalStatementNode(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 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 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 IsScalar => false;
@@ -108,9 +108,8 @@ public class NubStructType(string module, string name, List<NubStructFieldType>
public string Module { get; } = module;
public string Name { get; } = name;
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 int GetHashCode() => HashCode.Combine(typeof(NubStructType), Module, Name);
}

View File

@@ -1,6 +1,5 @@
using System.Diagnostics;
using NubLang.Diagnostics;
using NubLang.Modules;
using NubLang.Syntax;
namespace NubLang.Ast;
@@ -8,64 +7,69 @@ namespace NubLang.Ast;
public sealed class TypeChecker
{
private readonly SyntaxTree _syntaxTree;
private readonly Dictionary<string, Module> _visibleModules;
private readonly Dictionary<string, Module> _importedModules;
private readonly Stack<Scope> _scopes = [];
private readonly Stack<NubType> _funcReturnTypes = [];
private readonly Dictionary<(string Module, string Name), NubType> _typeCache = new();
private readonly HashSet<(string Module, string Name)> _resolvingTypes = [];
private readonly HashSet<string> _checkedTemplateStructs = [];
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;
_visibleModules = moduleRepository
.Modules()
.Where(x => syntaxTree.Metadata.Imports.Contains(x.Key) || _syntaxTree.Metadata.ModuleName == x.Key)
_importedModules = modules
.Where(x => syntaxTree.Imports.Contains(x.Key) || _syntaxTree.ModuleName == x.Key)
.ToDictionary();
}
public List<DefinitionNode> Definitions { get; } = [];
public List<Diagnostic> Diagnostics { get; } = [];
public void Check()
public CompilationUnit Check()
{
_scopes.Clear();
_funcReturnTypes.Clear();
_typeCache.Clear();
_resolvingTypes.Clear();
_checkedTemplateStructs.Clear();
Diagnostics.Clear();
Definitions.Clear();
using (BeginRootScope(_syntaxTree.Metadata.ModuleName))
using (BeginRootScope(_syntaxTree.ModuleName))
{
foreach (var definition in _syntaxTree.Definitions)
var functions = new List<FuncNode>();
foreach (var funcSyntax in _syntaxTree.Definitions.OfType<FuncSyntax>())
{
try
{
switch (definition)
{
case FuncSyntax funcSyntax:
Definitions.Add(CheckFuncDefinition(funcSyntax));
break;
case StructSyntax structSyntax:
Definitions.Add(CheckStructDefinition(structSyntax));
break;
case StructTemplateSyntax:
break;
default:
throw new ArgumentOutOfRangeException();
}
functions.Add(CheckFuncDefinition(funcSyntax));
}
catch (TypeCheckerException e)
{
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
{
_scopes.Push(new Scope(_syntaxTree.Metadata.ModuleName));
_scopes.Push(new Scope(_syntaxTree.ModuleName));
}
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)
{
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));
}
var signature = CheckFuncSignature(node.Signature);
var prototype = CheckFuncPrototype(node.Prototype);
BlockNode? body = null;
if (node.Body != null)
{
_funcReturnTypes.Push(signature.ReturnType);
_funcReturnTypes.Push(prototype.ReturnType);
body = CheckBlock(node.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));
}
@@ -184,7 +139,7 @@ public sealed class TypeChecker
_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)
@@ -231,7 +186,6 @@ public sealed class TypeChecker
return expression switch
{
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())
};
}
@@ -269,7 +223,7 @@ public sealed class TypeChecker
return new WhileNode(statement.Tokens, condition, body);
}
private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax statement)
private FuncPrototypeNode CheckFuncPrototype(FuncPrototypeSyntax statement)
{
var parameters = new List<FuncParameterNode>();
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)));
}
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)
@@ -290,7 +244,6 @@ public sealed class TypeChecker
BinaryExpressionSyntax expression => CheckBinaryExpression(expression, expectedType),
UnaryExpressionSyntax expression => CheckUnaryExpression(expression, expectedType),
DereferenceSyntax expression => CheckDereference(expression),
MemberFuncCallSyntax expression => CheckMemberFuncCall(expression),
FuncCallSyntax expression => CheckFuncCall(expression),
LocalIdentifierSyntax expression => CheckLocalIdentifier(expression),
ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression),
@@ -608,56 +561,6 @@ public sealed class TypeChecker
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)
{
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);
if (function != null)
{
var parameters = function.Signature.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Signature.ReturnType));
return new FuncIdentifierNode(expression.Tokens, type, CurrentScope.Module, expression.Name, function.ExternSymbol);
var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
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());
@@ -686,7 +589,7 @@ public sealed class TypeChecker
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
.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);
if (function != null)
{
var parameters = function.Signature.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Signature.ReturnType));
return new FuncIdentifierNode(expression.Tokens, type, expression.Module, expression.Name, function.ExternSymbol);
var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
return new FuncIdentifierNode(expression.Tokens, type, expression.Module, expression.Name, function.Prototype.ExternSymbol);
}
throw new TypeCheckerException(Diagnostic
@@ -824,8 +727,6 @@ public sealed class TypeChecker
.Error($"Struct {structType.Name} does not have a field named {initializer.Key}")
.At(initializer.Value)
.Build());
continue;
}
initializers.Add(initializer.Key, CheckExpression(initializer.Value, typeField.Type));
@@ -849,34 +750,12 @@ public sealed class TypeChecker
private BlockNode CheckBlock(BlockSyntax node)
{
var statements = new List<StatementNode>();
var reachable = true;
var warnedUnreachable = false;
using (BeginScope())
{
var statements = new List<StatementNode>();
foreach (var statement in node.Statements)
{
var checkedStatement = 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;
}
}
statements.Add(CheckStatement(statement));
}
return new BlockNode(node.Tokens, statements);
@@ -937,27 +816,11 @@ public sealed class TypeChecker
PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType)),
StringTypeSyntax => new NubStringType(),
CustomTypeSyntax c => ResolveCustomType(c),
StructTemplateTypeSyntax t => ResolveStructTemplateType(t),
SubstitutionTypeSyntax s => ResolveTypeSubstitution(s),
VoidTypeSyntax => new NubVoidType(),
_ => 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)
{
var key = (customType.Module, customType.Name);
@@ -969,14 +832,14 @@ public sealed class TypeChecker
if (!_resolvingTypes.Add(key))
{
var placeholder = new NubStructType(customType.Module, customType.Name, [], []);
var placeholder = new NubStructType(customType.Module, customType.Name, []);
_typeCache[key] = placeholder;
return placeholder;
}
try
{
if (!_visibleModules.TryGetValue(customType.Module, out var module))
if (!_importedModules.TryGetValue(customType.Module, out var module))
{
throw new TypeCheckerException(Diagnostic
.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);
if (structDef != null)
{
var result = new NubStructType(customType.Module, structDef.Name, [], []);
var result = new NubStructType(customType.Module, structDef.Name, []);
_typeCache[key] = result;
var fields = structDef.Fields
@@ -998,19 +861,6 @@ public sealed class TypeChecker
.ToList();
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;
}
@@ -1024,71 +874,6 @@ public sealed class TypeChecker
_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

View File

@@ -1,4 +1,3 @@
using System.Text;
using NubLang.Ast;
using NubLang.Syntax;
@@ -6,17 +5,14 @@ namespace NubLang.Generation;
public class Generator
{
private readonly List<DefinitionNode> _definitions;
private readonly CompilationUnit _compilationUnit;
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)
public Generator(CompilationUnit compilationUnit)
{
_definitions = definitions;
_compilationUnit = compilationUnit;
_writer = new IndentedTextWriter();
}
@@ -26,54 +22,6 @@ public class Generator
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)
{
var prefix = "";
@@ -81,7 +29,7 @@ public class Generator
switch (nubType)
{
case NubCStringType or NubPointerType:
case NubCStringType or NubPointerType or NubFuncType:
prefix = "*";
break;
case NubArrayType:
@@ -92,7 +40,42 @@ public class Generator
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)
@@ -105,139 +88,101 @@ public class Generator
return $"{module}_{name}";
}
private static string StructFuncName(string module, string name, string function)
{
return $"{module}_{name}_{function}";
}
public string Emit()
{
const string header = """
typedef __builtin_va_list va_list;
#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>())
// note(nub31): Struct definitions
foreach (var structType in _compilationUnit.ImportedStructTypes)
{
EmitLine(funcNode.Tokens.FirstOrDefault());
appendNewLine = true;
var parameters = funcNode.Signature.Parameters.Count != 0
? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
_writer.WriteLine("typedef struct");
_writer.WriteLine("{");
using (_writer.Indent())
{
foreach (var field in structType.Fields)
{
_writer.WriteLine($"{MapNameWithType(field.Type, field.Name)};");
}
}
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters});");
}
if (appendNewLine)
{
_writer.WriteLine($"}} {StructName(structType.Module, structType.Name)};");
_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(structFuncNode.Tokens.FirstOrDefault());
var parameters = structFuncNode.Signature.Parameters.Count != 0
? string.Join(", ", structFuncNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
EmitLine(prototype.Tokens.FirstOrDefault());
var parameters = prototype.Parameters.Count != 0
? string.Join(", ", prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
var name = StructFuncName(structNode.Module, structNode.Name, structFuncNode.Name);
_writer.WriteLine($"{MapNameWithType(structFuncNode.Signature.ReturnType, name)}({parameters})");
EmitBlock(structFuncNode.Body);
_writer.WriteLine();
}
var name = FuncName(prototype.Module, prototype.Name, prototype.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(prototype.ReturnType, name)}({parameters});");
}
foreach (var funcNode in _definitions.OfType<FuncNode>())
_writer.WriteLine();
// note(nub31): Normal functions
foreach (var funcNode in _compilationUnit.Functions)
{
if (funcNode.Body == null) continue;
EmitLine(funcNode.Tokens.FirstOrDefault());
var parameters = funcNode.Signature.Parameters.Count != 0
? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
var parameters = funcNode.Prototype.Parameters.Count != 0
? string.Join(", ", funcNode.Prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
if (funcNode.ExternSymbol == null)
if (funcNode.Prototype.ExternSymbol == null)
{
_writer.Write("static ");
}
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters})");
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(funcNode.Prototype.ReturnType, name)}({parameters})");
EmitBlock(funcNode.Body);
_writer.WriteLine();
}
List<string> typedefs = [];
return $"""
typedef __builtin_va_list va_list;
while (_funcDefs.TryPop(out var funcTypeDef))
{
var returnType = MapType(funcTypeDef.FuncType.ReturnType);
var paramList = string.Join(", ", funcTypeDef.FuncType.Parameters.Select((type, i) => MapNameWithType(type, $"arg{i}")));
if (funcTypeDef.FuncType.Parameters.Count == 0)
{
paramList = "void";
}
#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)
typedefs.Add($"typedef {returnType} (*{funcTypeDef.Name})({paramList});");
}
#define NULL ((void*)0)
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)};");
}
typedef unsigned long size_t;
typedef unsigned long uintptr_t;
structDefSb.AppendLine($"}} {StructName(structType.Module, structType.Name)};");
structDefSb.AppendLine();
}
#define offsetof(type, member) __builtin_offsetof(type, member)
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)
@@ -269,9 +214,6 @@ public class Generator
case StatementFuncCallNode statementFuncCallNode:
EmitStatementFuncCall(statementFuncCallNode);
break;
case StatementStructFuncCallNode statementStructFuncCallNode:
EmitStatementStructFuncCall(statementStructFuncCallNode);
break;
case VariableDeclarationNode variableDeclarationNode:
EmitVariableDeclaration(variableDeclarationNode);
break;
@@ -316,7 +258,7 @@ public class Generator
private void EmitIf(IfNode ifNode, bool elseIf = false)
{
var condition = EmitExpression(ifNode.Condition);
_writer.WriteLine($"{(elseIf ? "else" : "")} if ({condition})");
_writer.WriteLine($"{(elseIf ? "else " : "")}if ({condition})");
EmitBlock(ifNode.Body);
ifNode.Else?.Match
(
@@ -373,12 +315,6 @@ public class Generator
_writer.WriteLine($"{funcCall};");
}
private void EmitStatementStructFuncCall(StatementStructFuncCallNode statementStructFuncCallNode)
{
var structFuncCall = EmitStructFuncCall(statementStructFuncCallNode.StructFuncCall);
_writer.WriteLine($"{structFuncCall};");
}
private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode)
{
if (variableDeclarationNode.Assignment != null)
@@ -423,7 +359,6 @@ public class Generator
SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode),
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode),
StructFuncCallNode structFuncCallNode => EmitStructFuncCall(structFuncCallNode),
StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode),
UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode),
UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode),
@@ -606,12 +541,7 @@ public class Generator
private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode)
{
if (sizeBuiltinNode.TargetType is NubConstArrayType constArrayType)
{
return $"sizeof({MapType(constArrayType.ElementType)}) * {constArrayType.Size}";
}
return $"sizeof({MapType(sizeBuiltinNode.TargetType)})";
throw new NotImplementedException();
}
private string EmitStringLiteral(StringLiteralNode stringLiteralNode)
@@ -625,14 +555,6 @@ public class Generator
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)
{
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
{
private readonly HashSet<string> _templateArguments = [];
private List<Token> _tokens = [];
private int _tokenIndex;
private string _moduleName = string.Empty;
@@ -21,16 +20,7 @@ public sealed class Parser
_tokens = tokens;
_tokenIndex = 0;
_moduleName = string.Empty;
_templateArguments.Clear();
var metadata = ParseMetadata();
var definitions = ParseDefinitions();
return new SyntaxTree(definitions, metadata);
}
private SyntaxTreeMetadata ParseMetadata()
{
var imports = new List<string>();
try
@@ -57,11 +47,6 @@ public sealed class Parser
}
}
return new SyntaxTreeMetadata(_moduleName, imports);
}
private List<DefinitionSyntax> ParseDefinitions()
{
var definitions = new List<DefinitionSyntax>();
while (HasToken)
@@ -80,7 +65,7 @@ public sealed class Parser
}
var keyword = ExpectSymbol();
var definition = keyword.Symbol switch
DefinitionSyntax definition = keyword.Symbol switch
{
Symbol.Func => ParseFunc(startIndex, exported, null),
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 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 = [];
ExpectSymbol(Symbol.OpenParen);
@@ -131,23 +126,7 @@ public sealed class Parser
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax([]);
return new FuncSignatureSyntax(GetTokens(startIndex), 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();
var prototype = new FuncPrototypeSyntax(GetTokens(startIndex), name.Value, exported, externSymbol, parameters, returnType);
BlockSyntax? body = null;
var bodyStartIndex = _tokenIndex;
@@ -156,64 +135,36 @@ public sealed class Parser
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();
if (TryExpectSymbol(Symbol.LessThan))
{
while (!TryExpectSymbol(Symbol.GreaterThan))
{
_templateArguments.Add(ExpectIdentifier().Value);
TryExpectSymbol(Symbol.Comma);
}
}
ExpectSymbol(Symbol.OpenBrace);
List<StructFieldSyntax> fields = [];
List<StructFuncSyntax> funcs = [];
while (!TryExpectSymbol(Symbol.CloseBrace))
{
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;
var funcSignature = ParseFuncSignature();
var funcBody = ParseBlock();
funcs.Add(new StructFuncSyntax(GetTokens(memberStartIndex), funcName, funcSignature, funcBody));
fieldValue = ParseExpression();
}
else
{
var fieldName = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Colon);
var fieldType = ParseType();
ExpressionSyntax? fieldValue = null;
if (TryExpectSymbol(Symbol.Assign))
{
fieldValue = ParseExpression();
}
fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldType, fieldValue));
}
fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldType, fieldValue));
}
if (_templateArguments.Count > 0)
{
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);
return new StructSyntax(GetTokens(startIndex), name.Value, exported, fields);
}
private StatementSyntax ParseStatement()
@@ -543,24 +494,6 @@ public sealed class Parser
if (TryExpectSymbol(Symbol.Period))
{
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);
continue;
}
@@ -672,11 +605,6 @@ public sealed class Parser
var startIndex = _tokenIndex;
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 (size is not 8 and not 16 and not 32 and not 64)
@@ -740,21 +668,6 @@ public sealed class Parser
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);
}
}
@@ -946,9 +859,7 @@ public sealed class Parser
}
}
public record SyntaxTreeMetadata(string ModuleName, List<string> Imports);
public record SyntaxTree(List<DefinitionSyntax> Definitions, SyntaxTreeMetadata Metadata);
public record SyntaxTree(List<DefinitionSyntax> Definitions, string ModuleName, List<string> Imports);
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 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 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, 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 StructSyntax(List<Token> Tokens, string Name, bool Exported, List<StructFieldSyntax> Fields) : DefinitionSyntax(Tokens, Name, Exported);
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 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 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 StructTemplateTypeSyntax(List<Token> Tokens, List<TypeSyntax> TemplateParameters, string Module, string Name) : TypeSyntax(Tokens);
public record SubstitutionTypeSyntax(List<Token> Tokens, string Name) : TypeSyntax(Tokens);
#endregion

View File

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