Better support for method overloading
This commit is contained in:
parent
921abce011
commit
898cabb237
|
@ -322,14 +322,16 @@ namespace Upsilon.Binder
|
||||||
if (udSymbol.Parent.Properties.TryGetValue(resolved.Name.ToLowerInvariant(),
|
if (udSymbol.Parent.Properties.TryGetValue(resolved.Name.ToLowerInvariant(),
|
||||||
out var ubProperty) && ubProperty is UserDataBoundMethod ubMethod)
|
out var ubProperty) && ubProperty is UserDataBoundMethod ubMethod)
|
||||||
{
|
{
|
||||||
returnType = ubMethod.ResultType;
|
var option = ubMethod.Validate(parameters.ToImmutable());
|
||||||
var (isValid, error, wrongParameter) = ubMethod.ValidateParameters(parameters.ToImmutable());
|
if (option == null)
|
||||||
if (!isValid)
|
|
||||||
{
|
{
|
||||||
var span = e.Span;
|
_diagnostics.LogError(
|
||||||
if (wrongParameter != null)
|
$"No valid function with name '{ubMethod.Name}' and parameter types {string.Join(", ", parameters.Select(x => $"'x.Type'"))} found",
|
||||||
span = wrongParameter.Span;
|
expression.Span);
|
||||||
_diagnostics.LogError(error, span);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
returnType = option.ResultType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -906,10 +908,13 @@ namespace Upsilon.Binder
|
||||||
BoundExpression indexableExpression;
|
BoundExpression indexableExpression;
|
||||||
var value = BindExpression(e.Expression);
|
var value = BindExpression(e.Expression);
|
||||||
|
|
||||||
|
|
||||||
if (e.TableExpression.Kind == SyntaxKind.IndexExpression)
|
if (e.TableExpression.Kind == SyntaxKind.IndexExpression)
|
||||||
{
|
{
|
||||||
var indexable =
|
var idExp = BindIndexExpression((IndexExpressionSyntax) e.TableExpression, true);
|
||||||
(BoundIndexExpression) BindIndexExpression((IndexExpressionSyntax) e.TableExpression, true);
|
if (idExp is BoundBadExpression)
|
||||||
|
return new BoundExpressionStatement(new BoundBadExpression(e.Span), e.Span);
|
||||||
|
var indexable = (BoundIndexExpression) idExp;
|
||||||
|
|
||||||
if (indexable.Identifier.Kind == BoundKind.VariableExpression &&
|
if (indexable.Identifier.Kind == BoundKind.VariableExpression &&
|
||||||
indexable.Index.Kind == BoundKind.BoundLiteralExpression)
|
indexable.Index.Kind == BoundKind.BoundLiteralExpression)
|
||||||
|
|
|
@ -7,10 +7,10 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
{
|
{
|
||||||
public abstract class FunctionVariableSymbol : VariableSymbol
|
public abstract class FunctionVariableSymbol : VariableSymbol
|
||||||
{
|
{
|
||||||
public List<FunctionVariableSymbolOption> FunctionOption { get; } = new List<FunctionVariableSymbolOption>();
|
public List<FunctionVariableSymbolOption> FunctionOption { get; protected set; } = new List<FunctionVariableSymbolOption>();
|
||||||
|
|
||||||
public FunctionVariableSymbol(string name, bool local, Type resultType)
|
public FunctionVariableSymbol(string name, bool local, Type resultType)
|
||||||
: base(name, BaseTypes.Type.Function, local)
|
: base(name, Type.Function, local)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
@ -16,6 +17,12 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
FunctionOption.Add(new InternalFunctionVariableOption(resultType, functionParameters, overrideResultType));
|
FunctionOption.Add(new InternalFunctionVariableOption(resultType, functionParameters, overrideResultType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InternalFunctionVariableSymbol(string name, bool local, Type resultType, List<FunctionVariableSymbolOption> options)
|
||||||
|
: base(name, local, resultType)
|
||||||
|
{
|
||||||
|
FunctionOption = options;
|
||||||
|
}
|
||||||
|
|
||||||
public override (bool IsValid, string Error,
|
public override (bool IsValid, string Error,
|
||||||
BoundExpression WrongParameter) ValidateParameters(ImmutableArray<BoundExpression> callingParameters)
|
BoundExpression WrongParameter) ValidateParameters(ImmutableArray<BoundExpression> callingParameters)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,8 +29,6 @@ namespace Upsilon.BoundTypes
|
||||||
Properties = backingType;
|
Properties = backingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static UserDataBoundTypeDefinition Create(System.Type backingType, string name)
|
public static UserDataBoundTypeDefinition Create(System.Type backingType, string name)
|
||||||
{
|
{
|
||||||
var obj = new UserDataBoundTypeDefinition(backingType, name)
|
var obj = new UserDataBoundTypeDefinition(backingType, name)
|
||||||
|
@ -58,7 +56,7 @@ namespace Upsilon.BoundTypes
|
||||||
{
|
{
|
||||||
obj.Properties.Add(f.Name.ToLowerInvariant(), f);
|
obj.Properties.Add(f.Name.ToLowerInvariant(), f);
|
||||||
}
|
}
|
||||||
var methods = new List<UserDataBoundMethod>();
|
var methods = new Dictionary<string, UserDataBoundMethod>();
|
||||||
var backingMethods = backingType.GetMethods();
|
var backingMethods = backingType.GetMethods();
|
||||||
foreach (var backingMethod in backingMethods)
|
foreach (var backingMethod in backingMethods)
|
||||||
{
|
{
|
||||||
|
@ -78,21 +76,25 @@ namespace Upsilon.BoundTypes
|
||||||
Type = StaticScope.DeriveValidTypes(parameter.ParameterType),
|
Type = StaticScope.DeriveValidTypes(parameter.ParameterType),
|
||||||
IsOptional = parameter.IsOptional
|
IsOptional = parameter.IsOptional
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
methods.Add(new UserDataBoundMethod()
|
var option = new UserDataBoundMethodOption(backingMethod.ReturnType.GetScriptType(), parameters);
|
||||||
|
if (methods.TryGetValue(methodName, out var func))
|
||||||
{
|
{
|
||||||
Name = methodName,
|
func.Options.Add(option);
|
||||||
Type = Type.Function,
|
}
|
||||||
ResultType = backingMethod.ReturnType.GetScriptType(),
|
else
|
||||||
Parameters = parameters
|
{
|
||||||
});
|
methods.Add(methodName,
|
||||||
|
new UserDataBoundMethod(methodName, new List<UserDataBoundMethodOption>() {option}));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
foreach (var f in methods)
|
foreach (var f in methods)
|
||||||
{
|
{
|
||||||
var cleanedName = f.Name.ToLowerInvariant();
|
var cleanedName = f.Value.Name.ToLowerInvariant();
|
||||||
// TODO: handle this better, considering overloads
|
// TODO: handle this better, considering overloads
|
||||||
if (obj.Properties.ContainsKey(cleanedName))
|
if (obj.Properties.ContainsKey(cleanedName))
|
||||||
continue;
|
continue;
|
||||||
obj.Properties.Add(cleanedName, f);
|
obj.Properties.Add(cleanedName, f.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -159,55 +161,68 @@ namespace Upsilon.BoundTypes
|
||||||
public class UserDataBoundMethod: UserDataBoundProperty
|
public class UserDataBoundMethod: UserDataBoundProperty
|
||||||
{
|
{
|
||||||
public override string ActualType => "Function";
|
public override string ActualType => "Function";
|
||||||
|
public List<UserDataBoundMethodOption> Options;
|
||||||
|
|
||||||
|
public UserDataBoundMethod(string name, List<UserDataBoundMethodOption> options)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserDataBoundMethodOption Validate(ImmutableArray<BoundExpression> callingParameters)
|
||||||
|
{
|
||||||
|
return Options.FirstOrDefault(x => x.ValidateParameters(callingParameters));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserDataBoundMethodOption
|
||||||
|
{
|
||||||
|
public UserDataBoundMethodOption(TypeContainer resultType, UserDataBoundFunctionParameter[] parameters)
|
||||||
|
{
|
||||||
|
ResultType = resultType;
|
||||||
|
Parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
public TypeContainer ResultType { get; set; }
|
public TypeContainer ResultType { get; set; }
|
||||||
public UserDataBoundFunctionParameter[] Parameters { get; set; }
|
public UserDataBoundFunctionParameter[] Parameters { get; set; }
|
||||||
|
|
||||||
public (bool IsValid, string Error,
|
public bool ValidateParameters(ImmutableArray<BoundExpression> callingParameters)
|
||||||
BoundExpression WrongParameter) ValidateParameters(ImmutableArray<BoundExpression> callingParameters)
|
|
||||||
{
|
{
|
||||||
if (callingParameters.Length < Parameters.Count(x => !x.IsOptional)
|
if (callingParameters.Length < Parameters.Count(x => !x.IsOptional)
|
||||||
|| callingParameters.Length > Parameters.Length)
|
|| callingParameters.Length > Parameters.Length)
|
||||||
{
|
{
|
||||||
return (false,
|
return false;
|
||||||
$"Invalid number of parameters for function '{Name}'. Expected {Parameters.Length}, got {callingParameters.Length}",
|
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < callingParameters.Length; i++)
|
for (var i = 0; i < callingParameters.Length; i++)
|
||||||
{
|
{
|
||||||
var functionParameter = Parameters[i];
|
var functionParameter = Parameters[i];
|
||||||
var callingParameter = callingParameters[i];
|
var callingParameter = callingParameters[i];
|
||||||
if (callingParameter.Type == BaseTypes.Type.Unknown || callingParameter.Type == BaseTypes.Type.Nil)
|
if (callingParameter.Type == Type.Unknown || callingParameter.Type == Type.Nil)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!functionParameter.Type.Type.HasFlag(callingParameter.Type))
|
if (!functionParameter.Type.Type.HasFlag(callingParameter.Type))
|
||||||
{
|
{
|
||||||
return (false,
|
return false;
|
||||||
$"Unexpected variable passed to internal function at variable {i + 1}. " +
|
|
||||||
$"Expected one of the following: {functionParameter.Type}, got: '{callingParameter.Type}'",
|
|
||||||
callingParameter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functionParameter.Type.Type.HasFlag(BaseTypes.Type.UserData))
|
if (functionParameter.Type.Type.HasFlag(Type.UserData))
|
||||||
{
|
{
|
||||||
var variable = Binder.Binder.ResolveVariable(callingParameter, null);
|
var variable = Binder.Binder.ResolveVariable(callingParameter, null);
|
||||||
if (variable != null && variable.TypeContainer == BaseTypes.Type.UserData)
|
if (variable != null && variable.TypeContainer == Type.UserData)
|
||||||
{
|
{
|
||||||
var parent =
|
var parent =
|
||||||
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) variable).BoundTypeDefinition;
|
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) variable).BoundTypeDefinition;
|
||||||
if (functionParameter.ActualType != null &&
|
if (functionParameter.ActualType != null &&
|
||||||
!string.Equals(functionParameter.ActualType, parent.Name, StringComparison.InvariantCultureIgnoreCase))
|
!string.Equals(functionParameter.ActualType, parent.Name, StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
return (false,
|
return false;
|
||||||
$"Unexpected variable passed to internal function at variable {i + 1}. " +
|
|
||||||
$"Expected to be the following: {functionParameter.ActualType}, got: '{parent.Name}'",
|
|
||||||
callingParameter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (true, null, null);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue