Better support for binding functions, specifically nested functions

This commit is contained in:
Deukhoofd 2018-11-28 13:30:24 +01:00
parent 71397f5db2
commit 576273ac56
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
1 changed files with 25 additions and 7 deletions

View File

@ -192,7 +192,8 @@ namespace Upsilon.Binder
if (expression.Type != Type.Function && expression.Type != Type.Unknown) if (expression.Type != Type.Function && expression.Type != Type.Unknown)
{ {
//TODO Better error //TODO Better error
throw new Exception(); _diagnostics.LogError($"Unknown function called.", e.Span);
return new BoundLiteralExpression(new ScriptNull(), e.Span);
} }
var parameters = ImmutableArray.CreateBuilder<BoundExpression>(); var parameters = ImmutableArray.CreateBuilder<BoundExpression>();
@ -203,10 +204,8 @@ namespace Upsilon.Binder
} }
var returnType = Type.Unknown; var returnType = Type.Unknown;
if (expression.Kind == BoundKind.VariableExpression) if (ResolveVariable(expression) is FunctionVariableSymbol function)
{ {
var variableExpression =(BoundVariableExpression) expression;
var function = (FunctionVariableSymbol)variableExpression.Variable.VariableSymbol;
if (!function.IsBound) if (!function.IsBound)
{ {
Scope = new BoundScope(Scope); Scope = new BoundScope(Scope);
@ -221,20 +220,38 @@ namespace Upsilon.Binder
var unboundFunctionStatement = _unboundFunctions[function.Name]; var unboundFunctionStatement = _unboundFunctions[function.Name];
unboundFunctionStatement.Block = unboundFunctionStatement.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock); (BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
returnType = Scope.ReturnType; returnType = Scope.ReturnType;
Scope = Scope.ParentScope; Scope = Scope.ParentScope;
function.IsBound = true; function.IsBound = true;
function.ResultType = returnType; function.ResultType = returnType;
_unboundFunctions.Remove(function.Name); _unboundFunctions.Remove(function.Name);
} }
returnType = function.ResultType; returnType = function.ResultType;
} }
//TODO: validate parameters //TODO: validate parameters
return new BoundFunctionCallExpression(expression, parameters.ToImmutable(), e.Span, returnType); return new BoundFunctionCallExpression(expression, parameters.ToImmutable(), e.Span, returnType);
} }
private VariableSymbol ResolveVariable(BoundExpression expression)
{
if (expression.Kind == BoundKind.VariableExpression)
{
var variableExpression = (BoundVariableExpression) expression;
return variableExpression.Variable.VariableSymbol;
}
if (expression.Kind == BoundKind.BoundFullstopIndexExpression)
{
var fullStopIndexExpression = (BoundFullStopIndexExpression) expression;
var indexerExpression = fullStopIndexExpression.Expression;
var indexerVariable = (TableVariableSymbol)ResolveVariable(indexerExpression);
return indexerVariable.Variables[fullStopIndexExpression.Index];
}
return null;
}
private BoundExpression BindVariableExpression(VariableExpressionSyntax e) private BoundExpression BindVariableExpression(VariableExpressionSyntax e)
{ {
var name = e.Identifier.Name; var name = e.Identifier.Name;
@ -461,6 +478,7 @@ namespace Upsilon.Binder
}; };
variable = functionVariable; variable = functionVariable;
functionVariable.IsBound = !(func is UnboundFunctionExpression); functionVariable.IsBound = !(func is UnboundFunctionExpression);
functionVariable.ResultType = func.ReturnType;
if (isLocal) if (isLocal)
Scope.DefineLocalVariable(variable); Scope.DefineLocalVariable(variable);
else else