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

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