Type check when calling script function from CSharp
This commit is contained in:
parent
ba82b28ee4
commit
babbf2875f
|
@ -439,22 +439,25 @@ namespace Upsilon.Binder
|
|||
}
|
||||
}
|
||||
|
||||
private BoundExpression BindFunctionExpression(FunctionExpressionSyntax e, string variableSymbol = null)
|
||||
private BoundExpression BindFunctionExpression(FunctionExpressionSyntax e, string functionVariableSymbol = null)
|
||||
{
|
||||
var innerScope = new BoundScope(Scope);
|
||||
var parameters = ImmutableArray.CreateBuilder<BoundVariableSymbol>();
|
||||
foreach (var identifierToken in e.Parameters)
|
||||
{
|
||||
var variable = identifierToken;
|
||||
var scriptType = Type.Unknown;
|
||||
VariableSymbol variableSymbol;
|
||||
if (variable.TypeName != null)
|
||||
{
|
||||
var type = BoundTypeHandler.GetTypeDefinition(variable.TypeName.Name);
|
||||
scriptType = type.ScriptType;
|
||||
variableSymbol = new FunctionParameterSymbol(variable.IdentifierName.Name, type);
|
||||
}
|
||||
var vari = new VariableSymbol(variable.IdentifierName.Name, scriptType, true);
|
||||
parameters.Add(new BoundVariableSymbol(vari, identifierToken.Span));
|
||||
innerScope.DefineLocalVariable(vari);
|
||||
else
|
||||
{
|
||||
variableSymbol = new FunctionParameterSymbol(variable.IdentifierName.Name, Type.Unknown);
|
||||
}
|
||||
parameters.Add(new BoundVariableSymbol(variableSymbol, identifierToken.Span));
|
||||
innerScope.DefineLocalVariable(variableSymbol);
|
||||
}
|
||||
|
||||
if (parameters.All(x => x.Type != Type.Unknown))
|
||||
|
@ -470,13 +473,13 @@ namespace Upsilon.Binder
|
|||
else
|
||||
{
|
||||
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block, e.Span, innerScope);
|
||||
if (variableSymbol == null)
|
||||
if (functionVariableSymbol == null)
|
||||
{
|
||||
_unboundFunctions.Add( Guid.NewGuid().ToString(), unbound);
|
||||
}
|
||||
else
|
||||
{
|
||||
_unboundFunctions.Add(variableSymbol, unbound);
|
||||
_unboundFunctions.Add(functionVariableSymbol, unbound);
|
||||
}
|
||||
return unbound;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Upsilon.BaseTypes;
|
||||
using Upsilon.BoundTypes;
|
||||
|
||||
namespace Upsilon.Binder
|
||||
{
|
||||
|
@ -34,6 +35,22 @@ namespace Upsilon.Binder
|
|||
}
|
||||
}
|
||||
|
||||
public class FunctionParameterSymbol : VariableSymbol
|
||||
{
|
||||
public BoundTypeDefinition BoundTypeDefinition { get; }
|
||||
|
||||
public FunctionParameterSymbol(string name, Type type) : base(name, type, true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public FunctionParameterSymbol(string name, BoundTypeDefinition type) : base(name, type.ScriptType, true)
|
||||
{
|
||||
BoundTypeDefinition = type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TableVariableSymbol : VariableSymbol
|
||||
{
|
||||
public Dictionary<string, VariableSymbol> Variables { get; }
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Upsilon.BaseTypes;
|
||||
|
||||
|
@ -5,7 +6,7 @@ namespace Upsilon.BoundTypes
|
|||
{
|
||||
public static class BoundTypeHandler
|
||||
{
|
||||
private static Dictionary<string, BoundTypeDefinition> _typeDefinitions = new Dictionary<string, BoundTypeDefinition>
|
||||
private static readonly Dictionary<string, BoundTypeDefinition> TypeDefinitions = new Dictionary<string, BoundTypeDefinition>
|
||||
{
|
||||
{"string", new BoundTypeDefinition(Type.String, typeof(string))},
|
||||
{
|
||||
|
@ -13,12 +14,14 @@ namespace Upsilon.BoundTypes
|
|||
new BoundTypeDefinition(Type.Number,
|
||||
new[] {typeof(int), typeof(long), typeof(float), typeof(double)})
|
||||
},
|
||||
{"bool", new BoundTypeDefinition(Type.Boolean, typeof(bool))}
|
||||
{"bool", new BoundTypeDefinition(Type.Boolean, typeof(bool))},
|
||||
{"table", new BoundTypeDefinition(Type.Table, typeof(IEnumerator))},
|
||||
{"function", new BoundTypeDefinition(Type.Function, new System.Type[0])},
|
||||
};
|
||||
|
||||
public static BoundTypeDefinition GetTypeDefinition(string key)
|
||||
{
|
||||
return _typeDefinitions[key.ToLowerInvariant()];
|
||||
return TypeDefinitions[key.ToLowerInvariant()];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace Upsilon.Evaluator
|
||||
{
|
||||
public class EvaluationException : Exception
|
||||
{
|
||||
public EvaluationException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Net.Http.Headers;
|
||||
using Upsilon.BaseTypes;
|
||||
using Upsilon.BaseTypes.Number;
|
||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||
|
@ -53,7 +54,7 @@ namespace Upsilon.Evaluator
|
|||
return _returnValue;
|
||||
}
|
||||
|
||||
public ScriptType Evaluate(BoundScript e, string functionName, ImmutableArray<ScriptType> parameters)
|
||||
public ScriptType Evaluate(BoundScript e, string functionName, object[] parameters)
|
||||
{
|
||||
EvaluateNode(e.Statement);
|
||||
if (!Scope.TryGet(functionName, out var statement) || statement.Type != Type.Function)
|
||||
|
@ -65,8 +66,28 @@ namespace Upsilon.Evaluator
|
|||
for (var index = 0; index < parameters.Length; index++)
|
||||
{
|
||||
var parameter = parameters[index];
|
||||
var parameterName = function.Parameters[index];
|
||||
innerEvaluator.Scope.CreateLocal(parameterName.VariableSymbol, parameter);
|
||||
var parameterSymbol = (FunctionParameterSymbol)function.Parameters[index].VariableSymbol;
|
||||
if (parameterSymbol.BoundTypeDefinition != null)
|
||||
{
|
||||
bool isCompatible = false;
|
||||
var parameterType = parameter.GetType();
|
||||
foreach (var validType in parameterSymbol.BoundTypeDefinition.ValidInternalTypes)
|
||||
{
|
||||
if (validType.IsAssignableFrom(parameterType))
|
||||
{
|
||||
isCompatible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isCompatible)
|
||||
{
|
||||
throw new EvaluationException(
|
||||
$"Parameter '{parameterSymbol.Name}' of function '{functionName}' can't handle the given object with type '{parameterType}'");
|
||||
}
|
||||
}
|
||||
|
||||
innerEvaluator.Scope.CreateLocal(parameterSymbol, parameter.ToScriptType());
|
||||
}
|
||||
|
||||
var result = innerEvaluator.EvaluateNode(function.Block);
|
||||
|
|
|
@ -74,15 +74,7 @@ namespace Upsilon.Evaluator
|
|||
|
||||
public object EvaluateFunction(string functionName, object[] parameters = null)
|
||||
{
|
||||
var luaParameters = ImmutableArray.CreateBuilder<ScriptType>();
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
luaParameters.Add(parameter.ToScriptType());
|
||||
}
|
||||
}
|
||||
return Convert(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable()));
|
||||
return Convert(Evaluator.Evaluate(Bind(), functionName, parameters));
|
||||
}
|
||||
|
||||
private static T Convert<T>(ScriptType t)
|
||||
|
@ -108,15 +100,7 @@ namespace Upsilon.Evaluator
|
|||
|
||||
public T EvaluateFunction<T>(string functionName, object[] parameters = null)
|
||||
{
|
||||
var luaParameters = ImmutableArray.CreateBuilder<ScriptType>();
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
luaParameters.Add(parameter.ToScriptType());
|
||||
}
|
||||
}
|
||||
return Convert<T>(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable()));
|
||||
return Convert<T>(Evaluator.Evaluate(Bind(), functionName, parameters));
|
||||
}
|
||||
|
||||
public T GetVariable<T>(string variableName)
|
||||
|
|
Loading…
Reference in New Issue