Anon funcs works

This commit is contained in:
nub31
2025-07-07 18:18:47 +02:00
parent 2a8578726d
commit 8d5b20f6e5
11 changed files with 212 additions and 219 deletions

View File

@@ -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")
}
}

View File

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

View File

@@ -67,19 +67,19 @@ public partial class QBEGenerator
foreach (var funcDef in _syntaxTree.Definitions.OfType<BoundLocalFunc>())
{
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<BoundFuncParameter> parameters, NubType returnType, BoundBlock body)
private void EmitFuncDefinition(string name, IEnumerable<BoundFuncParameter> 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("}");

View File

@@ -13,8 +13,8 @@ public sealed class Binder
private readonly DefinitionTable _definitionTable;
// TODO: Implement proper variable tracking and scoping
private Dictionary<string, NubType> _variables = new();
private NubType? _functionReturnType;
private readonly Dictionary<string, NubType> _variables = [];
private readonly Stack<NubType> _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<Diagnostic>();
var definitions = new List<BoundDefinition>();
@@ -63,17 +63,18 @@ public sealed class Binder
_variables.Clear();
var functions = new List<BoundTraitFuncImpl>();
foreach (var function in node.Functions)
foreach (var func in node.Functions)
{
var parameters = new List<BoundFuncParameter>();
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<BoundFuncParameter>();
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<BoundFuncParameter>();
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<BoundFuncParameter>();
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<BoundStatement>();
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<BoundFuncParameter>();
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<BoundFuncParameter>();
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<BoundFuncParameter>();
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<BoundStatement>();
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

View File

@@ -9,18 +9,20 @@ public abstract record BoundDefinitionMember(IEnumerable<Token> Tokens) : BoundN
public record BoundFuncParameter(IEnumerable<Token> Tokens, string Name, NubType Type) : BoundDefinitionMember(Tokens);
public record BoundLocalFunc(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundFuncParameter> Parameters, BoundBlock Body, NubType ReturnType) : BoundDefinition(Tokens, Namespace);
public record BoundFuncSignature(IEnumerable<Token> Tokens, IEnumerable<BoundFuncParameter> Parameters, NubType ReturnType) : BoundDefinitionMember(Tokens);
public record BoundExternFunc(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<BoundFuncParameter> Parameters, NubType ReturnType) : BoundDefinition(Tokens, Namespace);
public record BoundLocalFunc(IEnumerable<Token> Tokens, string Namespace, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinition(Tokens, Namespace);
public record BoundExternFunc(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, BoundFuncSignature Signature) : BoundDefinition(Tokens, Namespace);
public record BoundStructField(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<BoundExpression> Value) : BoundDefinitionMember(Tokens);
public record BoundStruct(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundStructField> Fields) : BoundDefinition(Tokens, Namespace);
public record BoundTraitFunc(IEnumerable<Token> Tokens, string Name, List<BoundFuncParameter> Parameters, NubType ReturnType) : BoundDefinitionMember(Tokens);
public record BoundTraitFunc(IEnumerable<Token> Tokens, string Name, BoundFuncSignature Signature) : BoundDefinitionMember(Tokens);
public record BoundTrait(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundTraitFunc> Functions) : BoundDefinition(Tokens, Namespace);
public record BoundTraitFuncImpl(IEnumerable<Token> Tokens, string Name, List<BoundFuncParameter> Parameters, NubType ReturnType, BoundBlock Body) : BoundDefinitionMember(Tokens);
public record BoundTraitFuncImpl(IEnumerable<Token> Tokens, string Name, BoundFuncSignature Signature, BoundBlock Body) : BoundDefinitionMember(Tokens);
public record BoundTraitImpl(IEnumerable<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, List<BoundTraitFuncImpl> Functions) : BoundDefinition(Tokens, Namespace);

View File

@@ -40,7 +40,7 @@ public record BoundArrayInitializer(IEnumerable<Token> Tokens, NubType Type, Bou
public record BoundArrayIndexAccess(IEnumerable<Token> Tokens, NubType Type, BoundExpression Target, BoundExpression Index) : BoundExpression(Tokens, Type);
public record BoundAnonymousFunc(IEnumerable<Token> Tokens, NubType Type, List<BoundFuncParameter> Parameters, BoundBlock Body, NubType ReturnType) : BoundExpression(Tokens, Type);
public record BoundAnonymousFunc(IEnumerable<Token> Tokens, NubType Type, IEnumerable<BoundFuncParameter> Parameters, NubType ReturnType, BoundBlock Body) : BoundExpression(Tokens, Type);
public record BoundAddressOf(IEnumerable<Token> Tokens, NubType Type, BoundExpression Expression) : BoundExpression(Tokens, Type);

View File

@@ -9,18 +9,20 @@ public abstract record DefinitionMemberSyntax(IEnumerable<Token> Tokens) : Synta
public record FuncParameterSyntax(IEnumerable<Token> Tokens, string Name, NubType Type) : DefinitionMemberSyntax(Tokens);
public record LocalFuncSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, List<FuncParameterSyntax> Parameters, BlockSyntax Body, NubType ReturnType) : DefinitionSyntax(Tokens, Namespace);
public record FuncSignatureSyntax(IEnumerable<Token> Tokens, IEnumerable<FuncParameterSyntax> Parameters, NubType ReturnType) : DefinitionMemberSyntax(Tokens);
public record ExternFuncSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<FuncParameterSyntax> Parameters, NubType ReturnType) : DefinitionSyntax(Tokens, Namespace);
public record LocalFuncSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionSyntax(Tokens, Namespace);
public record ExternFuncSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, FuncSignatureSyntax Signature) : DefinitionSyntax(Tokens, Namespace);
public record StructFieldSyntax(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<ExpressionSyntax> Value) : DefinitionMemberSyntax(Tokens);
public record StructSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, List<StructFieldSyntax> Fields) : DefinitionSyntax(Tokens, Namespace);
public record TraitFuncSyntax(IEnumerable<Token> Tokens, string Name, List<FuncParameterSyntax> Parameters, NubType ReturnType) : DefinitionMemberSyntax(Tokens);
public record TraitFuncSyntax(IEnumerable<Token> Tokens, string Name, FuncSignatureSyntax Signature) : DefinitionMemberSyntax(Tokens);
public record TraitSyntax(IEnumerable<Token> Tokens, string Namespace, string Name, List<TraitFuncSyntax> Functions) : DefinitionSyntax(Tokens, Namespace);
public record TraitFuncImplSyntax(IEnumerable<Token> Tokens, string Name, List<FuncParameterSyntax> Parameters, NubType ReturnType, BlockSyntax Body) : DefinitionMemberSyntax(Tokens);
public record TraitFuncImplSyntax(IEnumerable<Token> Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : DefinitionMemberSyntax(Tokens);
public record TraitImplSyntax(IEnumerable<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, List<TraitFuncImplSyntax> Functions) : DefinitionSyntax(Tokens, Namespace);

View File

@@ -37,7 +37,9 @@ public record ArrayInitializerSyntax(IEnumerable<Token> Tokens, ExpressionSyntax
public record ArrayIndexAccessSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens);
public record AnonymousFuncSyntax(IEnumerable<Token> Tokens, List<FuncParameterSyntax> Parameters, BlockSyntax Body, NubType ReturnType) : ExpressionSyntax(Tokens);
public record AnonymousFuncParameterSyntax(IEnumerable<Token> Tokens, string Name) : ExpressionSyntax(Tokens);
public record AnonymousFuncSyntax(IEnumerable<Token> Tokens, List<AnonymousFuncParameterSyntax> Parameters, BlockSyntax Body) : ExpressionSyntax(Tokens);
public record AddressOfSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens);

View File

@@ -12,7 +12,6 @@ public sealed class Parser
private readonly IEnumerable<Token> _tokens;
private readonly List<Diagnostic> _diagnostics = [];
private NubType? _functionReturnType;
private int _tokenIndex;
public Parser(IEnumerable<Token> 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<FuncParameterSyntax> 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<FuncParameterSyntax> 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<FuncParameterSyntax> 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<FuncParameterSyntax>();
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<FuncParameterSyntax>
{
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<ExpressionSyntax>.Empty();
if (_functionReturnType is not NubVoidType)
if (!TryExpectSymbol(Symbol.Semi))
{
value = ParseExpression();
}
@@ -500,27 +456,18 @@ public sealed class Parser
{
case Symbol.Func:
{
List<FuncParameterSyntax> parameters = [];
List<AnonymousFuncParameterSyntax> 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:

View File

@@ -70,5 +70,6 @@ public enum Symbol
Trait,
Impl,
For,
Extern
Extern,
Semi
}

View File

@@ -55,6 +55,7 @@ public sealed class Tokenizer
['!'] = Symbol.Bang,
['^'] = Symbol.Caret,
['&'] = Symbol.Ampersand,
[';'] = Symbol.Semi,
};
private readonly SourceText _sourceText;