From 8d5b20f6e5c63481c406ccbd30775897919f6cd4 Mon Sep 17 00:00:00 2001 From: nub31 Date: Mon, 7 Jul 2025 18:18:47 +0200 Subject: [PATCH] Anon funcs works --- example/src/main.nub | 71 ++++--- .../Generation/QBE/QBEGenerator.Expression.cs | 4 +- .../NubLang/Generation/QBE/QBEGenerator.cs | 17 +- src/compiler/NubLang/Syntax/Binding/Binder.cs | 136 ++++++++------ .../Syntax/Binding/Node/BoundDefinition.cs | 10 +- .../Syntax/Binding/Node/BoundExpression.cs | 2 +- .../Syntax/Parsing/Node/DefinitionSyntax.cs | 10 +- .../Syntax/Parsing/Node/ExpressionSyntax.cs | 4 +- src/compiler/NubLang/Syntax/Parsing/Parser.cs | 173 ++++++------------ .../NubLang/Syntax/Tokenization/Token.cs | 3 +- .../NubLang/Syntax/Tokenization/Tokenizer.cs | 1 + 11 files changed, 212 insertions(+), 219 deletions(-) diff --git a/example/src/main.nub b/example/src/main.nub index 01ea5f5..952c9a7 100644 --- a/example/src/main.nub +++ b/example/src/main.nub @@ -1,39 +1,52 @@ -struct name -{ - first: cstring - last: cstring -} +// struct name +// { +// first: cstring +// last: cstring +// } -struct human -{ - name: name - age: i64 -} +// struct human +// { +// name: name +// age: i64 +// } -trait printable -{ - func print() -} +// trait printable +// { +// func print() +// } -impl printable for human -{ - func print() { - c::puts(this.name.first) - } -} +// impl printable for human +// { +// func print() { +// c::puts(this.name.first) +// } +// } func main(args: []cstring): i64 { - let human = alloc human - { - name = alloc name { - first = "john" - last = "doe" - } - age = 23 - } + // let human = alloc human + // { + // name = alloc name { + // first = "john" + // last = "doe" + // } + // age = 23 + // } - human.print() + // human.print() + + print_result(12, func(num) { return num == 12 }) return 0 } + +func print_result(num: u64, delegate: func(u64): bool) { + if (delegate(num)) + { + c::puts("true") + } + else + { + c::puts("false") + } +} \ No newline at end of file diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs index 5435be8..e1b11e1 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs @@ -232,8 +232,8 @@ public partial class QBEGenerator private Val EmitLocalFuncIdent(BoundLocalFuncIdent localFuncIdent) { - var func = _definitionTable.LookupExternFunc(localFuncIdent.Namespace, localFuncIdent.Name); - return new Val(ExternFuncName(func), localFuncIdent.Type, ValKind.Direct); + var func = _definitionTable.LookupLocalFunc(localFuncIdent.Namespace, localFuncIdent.Name); + return new Val(LocalFuncName(func), localFuncIdent.Type, ValKind.Direct); } private Val EmitVariableIdent(BoundVariableIdent variableIdent) diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs index 47c481a..f7f8162 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -67,19 +67,19 @@ public partial class QBEGenerator foreach (var funcDef in _syntaxTree.Definitions.OfType()) { - EmitFuncDefinition(funcDef, LocalFuncName(funcDef), funcDef.Parameters, funcDef.ReturnType, funcDef.Body); + EmitFuncDefinition(LocalFuncName(funcDef), funcDef.Signature.Parameters, funcDef.Signature.ReturnType, funcDef.Body); _writer.NewLine(); } while (_anonymousFunctions.TryDequeue(out var anon)) { - EmitFuncDefinition(anon.Func, anon.Name, anon.Func.Parameters, anon.Func.ReturnType, anon.Func.Body); + EmitFuncDefinition(anon.Name, anon.Func.Parameters, anon.Func.ReturnType, anon.Func.Body); _writer.NewLine(); } foreach (var (impl, name) in _implFunctions) { - EmitFuncDefinition(impl, name, impl.Parameters, impl.ReturnType, impl.Body); + EmitFuncDefinition(name, impl.Signature.Parameters, impl.Signature.ReturnType, impl.Body); _writer.NewLine(); } @@ -347,8 +347,10 @@ public partial class QBEGenerator return "l"; } - private void EmitFuncDefinition(BoundNode debugNode, string name, List parameters, NubType returnType, BoundBlock body) + private void EmitFuncDefinition(string name, IEnumerable parameters, NubType returnType, BoundBlock body) { + var parameterArray = parameters.ToArray(); + _variables.Clear(); _variableScopes.Clear(); _labelIndex = 0; @@ -364,14 +366,13 @@ public partial class QBEGenerator builder.Append(name); - var parameterStrings = parameters.Select(x => FuncQBETypeName(x.Type) + $" %{x.Name}"); + var parameterStrings = parameterArray.Select(x => FuncQBETypeName(x.Type) + $" %{x.Name}"); builder.Append($"({string.Join(", ", parameterStrings)})"); _writer.StartFunction(builder.ToString()); - _writer.WriteDebugLocation(debugNode); - var parameterVars = parameters.Select(parameter => new Variable(parameter.Name, new Val("%" + parameter.Name, parameter.Type, ValKind.Direct))).ToList(); + var parameterVars = parameterArray.Select(parameter => new Variable(parameter.Name, new Val("%" + parameter.Name, parameter.Type, ValKind.Direct))).ToList(); EmitBlock(body, parameterVars); @@ -438,7 +439,7 @@ public partial class QBEGenerator foreach (var func in traitDef.Functions) { - _writer.Indented($"l, # func {func.Name}({string.Join(", ", func.Parameters.Select(x => $"{x.Name}: {x.Type}"))}): {func.ReturnType}"); + _writer.Indented($"l, # func {func.Name}({string.Join(", ", func.Signature.Parameters.Select(x => $"{x.Name}: {x.Type}"))}): {func.Signature.ReturnType}"); } _writer.WriteLine("}"); diff --git a/src/compiler/NubLang/Syntax/Binding/Binder.cs b/src/compiler/NubLang/Syntax/Binding/Binder.cs index 93a30ee..f829366 100644 --- a/src/compiler/NubLang/Syntax/Binding/Binder.cs +++ b/src/compiler/NubLang/Syntax/Binding/Binder.cs @@ -13,8 +13,8 @@ public sealed class Binder private readonly DefinitionTable _definitionTable; // TODO: Implement proper variable tracking and scoping - private Dictionary _variables = new(); - private NubType? _functionReturnType; + private readonly Dictionary _variables = []; + private readonly Stack _funcReturnTypes = []; public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable) { @@ -24,8 +24,8 @@ public sealed class Binder public BoundSyntaxTree Bind() { - _variables = []; - _functionReturnType = null; + _variables.Clear(); + _funcReturnTypes.Clear(); var diagnostics = new List(); var definitions = new List(); @@ -63,17 +63,18 @@ public sealed class Binder _variables.Clear(); var functions = new List(); - foreach (var function in node.Functions) + foreach (var func in node.Functions) { - var parameters = new List(); + var signature = BindFuncSignature(func.Signature); - foreach (var parameter in function.Parameters) + foreach (var parameter in signature.Parameters) { _variables[parameter.Name] = parameter.Type; - parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type)); } - functions.Add(new BoundTraitFuncImpl(function.Tokens, function.Name, parameters, function.ReturnType, BindBlock(function.Body))); + var body = BindFuncBody(func.Body, signature.ReturnType); + + functions.Add(new BoundTraitFuncImpl(func.Tokens, func.Name, signature, body)); } return new BoundTraitImpl(node.Tokens, node.Namespace, node.TraitType, node.ForType, functions); @@ -85,14 +86,7 @@ public sealed class Binder foreach (var function in node.Functions) { - var parameters = new List(); - - foreach (var parameter in function.Parameters) - { - parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type)); - } - - functions.Add(new BoundTraitFunc(node.Tokens, function.Name, parameters, function.ReturnType)); + functions.Add(new BoundTraitFunc(node.Tokens, function.Name, BindFuncSignature(function.Signature))); } return new BoundTrait(node.Tokens, node.Namespace, node.Name, functions); @@ -119,44 +113,23 @@ public sealed class Binder private BoundExternFunc BindExternFuncDefinition(ExternFuncSyntax node) { - var parameters = new List(); - - foreach (var parameter in node.Parameters) - { - parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type)); - } - - return new BoundExternFunc(node.Tokens, node.Namespace, node.Name, node.CallName, parameters, node.ReturnType); + return new BoundExternFunc(node.Tokens, node.Namespace, node.Name, node.CallName, BindFuncSignature(node.Signature)); } private BoundLocalFunc BindLocalFuncDefinition(LocalFuncSyntax node) { _variables.Clear(); - _functionReturnType = node.ReturnType; - var parameters = new List(); + var signature = BindFuncSignature(node.Signature); - foreach (var parameter in node.Parameters) + foreach (var parameter in signature.Parameters) { _variables[parameter.Name] = parameter.Type; - parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type)); } - var body = BindBlock(node.Body); + var body = BindFuncBody(node.Body, signature.ReturnType); - return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, parameters, body, node.ReturnType); - } - - private BoundBlock BindBlock(BlockSyntax node) - { - var statements = new List(); - - foreach (var statement in node.Statements) - { - statements.Add(BindStatement(statement)); - } - - return new BoundBlock(node.Tokens, statements); + return new BoundLocalFunc(node.Tokens, node.Namespace, node.Name, signature, body); } private BoundStatement BindStatement(StatementSyntax node) @@ -214,7 +187,7 @@ public sealed class Binder if (statement.Value.HasValue) { - value = BindExpression(statement.Value.Value, _functionReturnType); + value = BindExpression(statement.Value.Value, _funcReturnTypes.Peek()); } return new BoundReturn(statement.Tokens, value); @@ -262,7 +235,7 @@ public sealed class Binder return node switch { AddressOfSyntax expression => BindAddressOf(expression), - AnonymousFuncSyntax expression => BindAnonymousFunc(expression), + AnonymousFuncSyntax expression => BindAnonymousFunc(expression, expectedType), ArrayIndexAccessSyntax expression => BindArrayIndexAccess(expression), ArrayInitializerSyntax expression => BindArrayInitializer(expression), BinaryExpressionSyntax expression => BindBinaryExpression(expression), @@ -283,18 +256,37 @@ public sealed class Binder return new BoundAddressOf(expression.Tokens, new NubPointerType(inner.Type), inner); } - private BoundAnonymousFunc BindAnonymousFunc(AnonymousFuncSyntax expression) + private BoundAnonymousFunc BindAnonymousFunc(AnonymousFuncSyntax expression, NubType? expectedType = null) { - var parameters = new List(); - - foreach (var parameter in expression.Parameters) + if (expectedType == null) { - parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type)); + throw new BindException(Diagnostic.Error("Cannot infer argument types for anonymous function").At(expression).Build()); } - var body = BindBlock(expression.Body); + if (expectedType is not NubFuncType funcType) + { + throw new BindException(Diagnostic.Error($"Expected {expectedType}, but got anonymous function").At(expression).Build()); + } - return new BoundAnonymousFunc(expression.Tokens, new NubFuncType(expression.ReturnType, parameters.Select(x => x.Type).ToList()), parameters, body, expression.ReturnType); + var parameters = new List(); + + for (var i = 0; i < expression.Parameters.Count; i++) + { + if (i >= funcType.Parameters.Count) + { + throw new BindException(Diagnostic.Error($"Anonymous function expected a maximum of {funcType.Parameters.Count} arguments").Build()); + } + + var expectedParameterType = funcType.Parameters[i]; + var parameter = expression.Parameters[i]; + parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, expectedParameterType)); + + _variables[parameter.Name] = expectedParameterType; + } + + var body = BindFuncBody(expression.Body, funcType.ReturnType); + + return new BoundAnonymousFunc(expression.Tokens, new NubFuncType(funcType.ReturnType, parameters.Select(x => x.Type).ToList()), parameters, funcType.ReturnType, body); } private BoundArrayIndexAccess BindArrayIndexAccess(ArrayIndexAccessSyntax expression) @@ -359,7 +351,7 @@ public sealed class Binder var localFunc = localFuncs[0]; - var type = new NubFuncType(localFunc.ReturnType, localFunc.Parameters.Select(p => p.Type).ToList()); + var type = new NubFuncType(localFunc.Signature.ReturnType, localFunc.Signature.Parameters.Select(p => p.Type).ToList()); return new BoundLocalFuncIdent(expression.Tokens, type, @namespace, expression.Name); } @@ -373,7 +365,7 @@ public sealed class Binder var externFunc = externFuncs[0]; - var type = new NubFuncType(externFunc.ReturnType, externFunc.Parameters.Select(p => p.Type).ToList()); + var type = new NubFuncType(externFunc.Signature.ReturnType, externFunc.Signature.Parameters.Select(p => p.Type).ToList()); return new BoundExternFuncIdent(expression.Tokens, type, @namespace, expression.Name); } @@ -413,7 +405,7 @@ public sealed class Binder var impl = traitFuncImpls[0]; - var type = new NubFuncType(impl.ReturnType, impl.Parameters.Select(p => p.Type).ToList()); + var type = new NubFuncType(impl.Signature.ReturnType, impl.Signature.Parameters.Select(p => p.Type).ToList()); return new BoundTraitImplFuncAccess(expression.Tokens, type, boundExpression, expression.Member); } @@ -439,7 +431,7 @@ public sealed class Binder var traitFunc = traitFuncs[0]; - var type = new NubFuncType(traitFunc.ReturnType, traitFunc.Parameters.Select(p => p.Type).ToList()); + var type = new NubFuncType(traitFunc.Signature.ReturnType, traitFunc.Signature.Parameters.Select(p => p.Type).ToList()); return new BoundTraitFuncAccess(expression.Tokens, type, customType, boundExpression, expression.Member); } } @@ -551,6 +543,18 @@ public sealed class Binder return new BoundUnaryExpression(expression.Tokens, type, BindBinaryOperator(expression.Operator), boundOperand); } + private BoundFuncSignature BindFuncSignature(FuncSignatureSyntax node) + { + var parameters = new List(); + + foreach (var parameter in node.Parameters) + { + parameters.Add(new BoundFuncParameter(parameter.Tokens, parameter.Name, parameter.Type)); + } + + return new BoundFuncSignature(node.Tokens, parameters, node.ReturnType); + } + private BoundBinaryOperator BindBinaryOperator(BinaryOperator op) { return op switch @@ -578,6 +582,26 @@ public sealed class Binder _ => throw new ArgumentOutOfRangeException(nameof(op), op, null) }; } + + private BoundBlock BindBlock(BlockSyntax node) + { + var statements = new List(); + + foreach (var statement in node.Statements) + { + statements.Add(BindStatement(statement)); + } + + return new BoundBlock(node.Tokens, statements); + } + + private BoundBlock BindFuncBody(BlockSyntax block, NubType returnType) + { + _funcReturnTypes.Push(returnType); + var body = BindBlock(block); + _funcReturnTypes.Pop(); + return body; + } } public class BindException : Exception diff --git a/src/compiler/NubLang/Syntax/Binding/Node/BoundDefinition.cs b/src/compiler/NubLang/Syntax/Binding/Node/BoundDefinition.cs index e5327ef..5bf7f49 100644 --- a/src/compiler/NubLang/Syntax/Binding/Node/BoundDefinition.cs +++ b/src/compiler/NubLang/Syntax/Binding/Node/BoundDefinition.cs @@ -9,18 +9,20 @@ public abstract record BoundDefinitionMember(IEnumerable Tokens) : BoundN public record BoundFuncParameter(IEnumerable Tokens, string Name, NubType Type) : BoundDefinitionMember(Tokens); -public record BoundLocalFunc(IEnumerable Tokens, string Namespace, string Name, List Parameters, BoundBlock Body, NubType ReturnType) : BoundDefinition(Tokens, Namespace); +public record BoundFuncSignature(IEnumerable Tokens, IEnumerable Parameters, NubType ReturnType) : BoundDefinitionMember(Tokens); -public record BoundExternFunc(IEnumerable Tokens, string Namespace, string Name, string CallName, List Parameters, NubType ReturnType) : BoundDefinition(Tokens, Namespace); +public record BoundLocalFunc(IEnumerable Tokens, string Namespace, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinition(Tokens, Namespace); + +public record BoundExternFunc(IEnumerable Tokens, string Namespace, string Name, string CallName, BoundFuncSignature Signature) : BoundDefinition(Tokens, Namespace); public record BoundStructField(IEnumerable Tokens, int Index, string Name, NubType Type, Optional Value) : BoundDefinitionMember(Tokens); public record BoundStruct(IEnumerable Tokens, string Namespace, string Name, List Fields) : BoundDefinition(Tokens, Namespace); -public record BoundTraitFunc(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType) : BoundDefinitionMember(Tokens); +public record BoundTraitFunc(IEnumerable Tokens, string Name, BoundFuncSignature Signature) : BoundDefinitionMember(Tokens); public record BoundTrait(IEnumerable Tokens, string Namespace, string Name, List Functions) : BoundDefinition(Tokens, Namespace); -public record BoundTraitFuncImpl(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType, BoundBlock Body) : BoundDefinitionMember(Tokens); +public record BoundTraitFuncImpl(IEnumerable Tokens, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinitionMember(Tokens); public record BoundTraitImpl(IEnumerable Tokens, string Namespace, NubType TraitType, NubType ForType, List Functions) : BoundDefinition(Tokens, Namespace); \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Binding/Node/BoundExpression.cs b/src/compiler/NubLang/Syntax/Binding/Node/BoundExpression.cs index ea0c0ba..84b41cc 100644 --- a/src/compiler/NubLang/Syntax/Binding/Node/BoundExpression.cs +++ b/src/compiler/NubLang/Syntax/Binding/Node/BoundExpression.cs @@ -40,7 +40,7 @@ public record BoundArrayInitializer(IEnumerable Tokens, NubType Type, Bou public record BoundArrayIndexAccess(IEnumerable Tokens, NubType Type, BoundExpression Target, BoundExpression Index) : BoundExpression(Tokens, Type); -public record BoundAnonymousFunc(IEnumerable Tokens, NubType Type, List Parameters, BoundBlock Body, NubType ReturnType) : BoundExpression(Tokens, Type); +public record BoundAnonymousFunc(IEnumerable Tokens, NubType Type, IEnumerable Parameters, NubType ReturnType, BoundBlock Body) : BoundExpression(Tokens, Type); public record BoundAddressOf(IEnumerable Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type); diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/DefinitionSyntax.cs b/src/compiler/NubLang/Syntax/Parsing/Node/DefinitionSyntax.cs index 1296528..07e0cb6 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Node/DefinitionSyntax.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Node/DefinitionSyntax.cs @@ -9,18 +9,20 @@ public abstract record DefinitionMemberSyntax(IEnumerable Tokens) : Synta public record FuncParameterSyntax(IEnumerable Tokens, string Name, NubType Type) : DefinitionMemberSyntax(Tokens); -public record LocalFuncSyntax(IEnumerable Tokens, string Namespace, string Name, List Parameters, BlockSyntax Body, NubType ReturnType) : DefinitionSyntax(Tokens, Namespace); +public record FuncSignatureSyntax(IEnumerable Tokens, IEnumerable Parameters, NubType ReturnType) : DefinitionMemberSyntax(Tokens); -public record ExternFuncSyntax(IEnumerable Tokens, string Namespace, string Name, string CallName, List Parameters, NubType ReturnType) : DefinitionSyntax(Tokens, Namespace); +public record LocalFuncSyntax(IEnumerable Tokens, string Namespace, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Tokens, Namespace); + +public record ExternFuncSyntax(IEnumerable Tokens, string Namespace, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Tokens, Namespace); public record StructFieldSyntax(IEnumerable Tokens, int Index, string Name, NubType Type, Optional Value) : DefinitionMemberSyntax(Tokens); public record StructSyntax(IEnumerable Tokens, string Namespace, string Name, List Fields) : DefinitionSyntax(Tokens, Namespace); -public record TraitFuncSyntax(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType) : DefinitionMemberSyntax(Tokens); +public record TraitFuncSyntax(IEnumerable Tokens, string Name, FuncSignatureSyntax Signature) : DefinitionMemberSyntax(Tokens); public record TraitSyntax(IEnumerable Tokens, string Namespace, string Name, List Functions) : DefinitionSyntax(Tokens, Namespace); -public record TraitFuncImplSyntax(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType, BlockSyntax Body) : DefinitionMemberSyntax(Tokens); +public record TraitFuncImplSyntax(IEnumerable Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionMemberSyntax(Tokens); public record TraitImplSyntax(IEnumerable Tokens, string Namespace, NubType TraitType, NubType ForType, List Functions) : DefinitionSyntax(Tokens, Namespace); \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Parsing/Node/ExpressionSyntax.cs b/src/compiler/NubLang/Syntax/Parsing/Node/ExpressionSyntax.cs index 93c343d..1bf3ef0 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Node/ExpressionSyntax.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Node/ExpressionSyntax.cs @@ -37,7 +37,9 @@ public record ArrayInitializerSyntax(IEnumerable Tokens, ExpressionSyntax public record ArrayIndexAccessSyntax(IEnumerable Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens); -public record AnonymousFuncSyntax(IEnumerable Tokens, List Parameters, BlockSyntax Body, NubType ReturnType) : ExpressionSyntax(Tokens); +public record AnonymousFuncParameterSyntax(IEnumerable Tokens, string Name) : ExpressionSyntax(Tokens); + +public record AnonymousFuncSyntax(IEnumerable Tokens, List Parameters, BlockSyntax Body) : ExpressionSyntax(Tokens); public record AddressOfSyntax(IEnumerable Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens); diff --git a/src/compiler/NubLang/Syntax/Parsing/Parser.cs b/src/compiler/NubLang/Syntax/Parsing/Parser.cs index 5af4cc3..33caa09 100644 --- a/src/compiler/NubLang/Syntax/Parsing/Parser.cs +++ b/src/compiler/NubLang/Syntax/Parsing/Parser.cs @@ -12,7 +12,6 @@ public sealed class Parser private readonly IEnumerable _tokens; private readonly List _diagnostics = []; - private NubType? _functionReturnType; private int _tokenIndex; public Parser(IEnumerable tokens) @@ -24,7 +23,6 @@ public sealed class Parser public SyntaxTree Parse() { _diagnostics.Clear(); - _functionReturnType = null; _tokenIndex = 0; if (TryExpectSymbol(Symbol.Namespace)) @@ -61,7 +59,7 @@ public sealed class Parser Symbol.Func => ParseFunc(startIndex), Symbol.Struct => ParseStruct(startIndex), Symbol.Trait => ParseTrait(startIndex), - Symbol.Impl => ParseImplementation(startIndex), + Symbol.Impl => ParseImpl(startIndex), _ => throw new ParseException(Diagnostic .Error($"Expected 'func' or 'struct', but found '{keyword.Symbol}'") .WithHelp("Valid definition keywords are 'func' and 'struct'") @@ -72,6 +70,48 @@ public sealed class Parser return node; } + private FuncSignatureSyntax ParseFuncSignature(FuncParameterSyntax? thisArg = null) + { + var startIndex = _tokenIndex; + + List parameters = []; + + if (thisArg != null) + { + parameters.Add(thisArg); + } + + ExpectSymbol(Symbol.OpenParen); + + while (!TryExpectSymbol(Symbol.CloseParen)) + { + parameters.Add(ParseFuncParameter()); + + if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen }) + { + _diagnostics.Add(Diagnostic + .Warning("Missing comma between function parameters") + .WithHelp("Add a ',' to separate parameters") + .At(token) + .Build()); + } + } + + var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType(); + + 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 DefinitionSyntax ParseExtern(int startIndex) { var keyword = ExpectSymbol(); @@ -85,25 +125,6 @@ public sealed class Parser private ExternFuncSyntax ParseExternFunc(int startIndex) { var name = ExpectIdentifier(); - List parameters = []; - - ExpectSymbol(Symbol.OpenParen); - - while (!TryExpectSymbol(Symbol.CloseParen)) - { - parameters.Add(ParseFuncParameter()); - - if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen }) - { - _diagnostics.Add(Diagnostic - .Warning("Missing comma between function parameters") - .WithHelp("Add a ',' to separate parameters") - .At(token) - .Build()); - } - } - - var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType(); var callName = name.Value; if (TryExpectSymbol(Symbol.Calls)) @@ -111,36 +132,18 @@ public sealed class Parser callName = ExpectIdentifier().Value; } - return new ExternFuncSyntax(GetTokens(startIndex), _namespace, name.Value, callName, parameters, returnType); + var signature = ParseFuncSignature(); + + return new ExternFuncSyntax(GetTokens(startIndex), _namespace, name.Value, callName, signature); } private LocalFuncSyntax ParseFunc(int startIndex) { var name = ExpectIdentifier(); - List parameters = []; - - ExpectSymbol(Symbol.OpenParen); - - while (!TryExpectSymbol(Symbol.CloseParen)) - { - parameters.Add(ParseFuncParameter()); - - if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen }) - { - _diagnostics.Add(Diagnostic - .Warning("Missing comma between function parameters") - .WithHelp("Add a ',' to separate parameters") - .At(token) - .Build()); - } - } - - var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType(); - _functionReturnType = returnType; - + var signature = ParseFuncSignature(); var body = ParseBlock(); - return new LocalFuncSyntax(GetTokens(startIndex), _namespace, name.Value, parameters, body, returnType); + return new LocalFuncSyntax(GetTokens(startIndex), _namespace, name.Value, signature, body); } private StructSyntax ParseStruct(int startIndex) @@ -189,32 +192,15 @@ public sealed class Parser ExpectSymbol(Symbol.Func); var funcName = ExpectIdentifier().Value; - var parameters = new List(); + var signature = ParseFuncSignature(); - ExpectSymbol(Symbol.OpenParen); - while (!TryExpectSymbol(Symbol.CloseParen)) - { - var parameter = ParseFuncParameter(); - parameters.Add(parameter); - if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) - { - _diagnostics.Add(Diagnostic - .Warning("Missing comma between function arguments") - .WithHelp("Add a ',' to separate arguments") - .At(nextToken) - .Build()); - } - } - - var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType(); - - functions.Add(new TraitFuncSyntax(GetTokens(funcStartIndex), funcName, parameters, returnType)); + functions.Add(new TraitFuncSyntax(GetTokens(funcStartIndex), funcName, signature)); } return new TraitSyntax(GetTokens(startIndex), _namespace, name, functions); } - private TraitImplSyntax ParseImplementation(int startIndex) + private TraitImplSyntax ParseImpl(int startIndex) { var traitType = ParseType(); ExpectSymbol(Symbol.For); @@ -228,47 +214,16 @@ public sealed class Parser var funcStartIndex = _tokenIndex; ExpectSymbol(Symbol.Func); var functionName = ExpectIdentifier().Value; - var parameters = new List - { - new([], "this", forType) - }; - - ExpectSymbol(Symbol.OpenParen); - - while (!TryExpectSymbol(Symbol.CloseParen)) - { - parameters.Add(ParseFuncParameter()); - - if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var token) && token is not SymbolToken { Symbol: Symbol.CloseParen }) - { - _diagnostics.Add(Diagnostic - .Warning("Missing comma between function parameters") - .WithHelp("Add a ',' to separate parameters") - .At(token) - .Build()); - } - } - - var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType(); + var signature = ParseFuncSignature(new FuncParameterSyntax([], "this", forType)); var body = ParseBlock(); - functions.AddRange(new TraitFuncImplSyntax(GetTokens(funcStartIndex), functionName, parameters, returnType, body)); + functions.AddRange(new TraitFuncImplSyntax(GetTokens(funcStartIndex), functionName, signature, body)); } return new TraitImplSyntax(GetTokens(startIndex), _namespace, traitType, forType, functions); } - private FuncParameterSyntax ParseFuncParameter() - { - var startIndex = _tokenIndex; - var name = ExpectIdentifier(); - ExpectSymbol(Symbol.Colon); - var type = ParseType(); - - return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type); - } - private StatementSyntax ParseStatement() { var startIndex = _tokenIndex; @@ -353,7 +308,8 @@ public sealed class Parser ExpectSymbol(Symbol.Return); var value = Optional.Empty(); - if (_functionReturnType is not NubVoidType) + + if (!TryExpectSymbol(Symbol.Semi)) { value = ParseExpression(); } @@ -500,27 +456,18 @@ public sealed class Parser { case Symbol.Func: { - List parameters = []; + List parameters = []; ExpectSymbol(Symbol.OpenParen); while (!TryExpectSymbol(Symbol.CloseParen)) { - var parameter = ParseFuncParameter(); - parameters.Add(parameter); - if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) - { - _diagnostics.Add(Diagnostic - .Warning("Missing comma between function arguments") - .WithHelp("Add a ',' to separate arguments") - .At(nextToken) - .Build()); - } + var parameterStartIndex = _tokenIndex; + var name = ExpectIdentifier(); + parameters.Add(new AnonymousFuncParameterSyntax(GetTokens(parameterStartIndex), name.Value)); } - var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType(); - var body = ParseBlock(); - expr = new AnonymousFuncSyntax(GetTokens(startIndex), parameters, body, returnType); + expr = new AnonymousFuncSyntax(GetTokens(startIndex), parameters, body); break; } case Symbol.OpenParen: diff --git a/src/compiler/NubLang/Syntax/Tokenization/Token.cs b/src/compiler/NubLang/Syntax/Tokenization/Token.cs index 373794f..6afd393 100644 --- a/src/compiler/NubLang/Syntax/Tokenization/Token.cs +++ b/src/compiler/NubLang/Syntax/Tokenization/Token.cs @@ -70,5 +70,6 @@ public enum Symbol Trait, Impl, For, - Extern + Extern, + Semi } \ No newline at end of file diff --git a/src/compiler/NubLang/Syntax/Tokenization/Tokenizer.cs b/src/compiler/NubLang/Syntax/Tokenization/Tokenizer.cs index 9bd064d..f8fb7f6 100644 --- a/src/compiler/NubLang/Syntax/Tokenization/Tokenizer.cs +++ b/src/compiler/NubLang/Syntax/Tokenization/Tokenizer.cs @@ -55,6 +55,7 @@ public sealed class Tokenizer ['!'] = Symbol.Bang, ['^'] = Symbol.Caret, ['&'] = Symbol.Ampersand, + [';'] = Symbol.Semi, }; private readonly SourceText _sourceText;