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 innerScope = new BoundScope(Scope);
|
||||||
var parameters = ImmutableArray.CreateBuilder<BoundVariableSymbol>();
|
var parameters = ImmutableArray.CreateBuilder<BoundVariableSymbol>();
|
||||||
foreach (var identifierToken in e.Parameters)
|
foreach (var identifierToken in e.Parameters)
|
||||||
{
|
{
|
||||||
var variable = identifierToken;
|
var variable = identifierToken;
|
||||||
var scriptType = Type.Unknown;
|
VariableSymbol variableSymbol;
|
||||||
if (variable.TypeName != null)
|
if (variable.TypeName != null)
|
||||||
{
|
{
|
||||||
var type = BoundTypeHandler.GetTypeDefinition(variable.TypeName.Name);
|
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);
|
else
|
||||||
parameters.Add(new BoundVariableSymbol(vari, identifierToken.Span));
|
{
|
||||||
innerScope.DefineLocalVariable(vari);
|
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))
|
if (parameters.All(x => x.Type != Type.Unknown))
|
||||||
|
@ -470,13 +473,13 @@ namespace Upsilon.Binder
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block, e.Span, innerScope);
|
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block, e.Span, innerScope);
|
||||||
if (variableSymbol == null)
|
if (functionVariableSymbol == null)
|
||||||
{
|
{
|
||||||
_unboundFunctions.Add( Guid.NewGuid().ToString(), unbound);
|
_unboundFunctions.Add( Guid.NewGuid().ToString(), unbound);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_unboundFunctions.Add(variableSymbol, unbound);
|
_unboundFunctions.Add(functionVariableSymbol, unbound);
|
||||||
}
|
}
|
||||||
return unbound;
|
return unbound;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
using Upsilon.BoundTypes;
|
||||||
|
|
||||||
namespace Upsilon.Binder
|
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 class TableVariableSymbol : VariableSymbol
|
||||||
{
|
{
|
||||||
public Dictionary<string, VariableSymbol> Variables { get; }
|
public Dictionary<string, VariableSymbol> Variables { get; }
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
|
|
||||||
|
@ -5,7 +6,7 @@ namespace Upsilon.BoundTypes
|
||||||
{
|
{
|
||||||
public static class BoundTypeHandler
|
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))},
|
{"string", new BoundTypeDefinition(Type.String, typeof(string))},
|
||||||
{
|
{
|
||||||
|
@ -13,12 +14,14 @@ namespace Upsilon.BoundTypes
|
||||||
new BoundTypeDefinition(Type.Number,
|
new BoundTypeDefinition(Type.Number,
|
||||||
new[] {typeof(int), typeof(long), typeof(float), typeof(double)})
|
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)
|
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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.BaseTypes.Number;
|
using Upsilon.BaseTypes.Number;
|
||||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
|
@ -53,7 +54,7 @@ namespace Upsilon.Evaluator
|
||||||
return _returnValue;
|
return _returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptType Evaluate(BoundScript e, string functionName, ImmutableArray<ScriptType> parameters)
|
public ScriptType Evaluate(BoundScript e, string functionName, object[] parameters)
|
||||||
{
|
{
|
||||||
EvaluateNode(e.Statement);
|
EvaluateNode(e.Statement);
|
||||||
if (!Scope.TryGet(functionName, out var statement) || statement.Type != Type.Function)
|
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++)
|
for (var index = 0; index < parameters.Length; index++)
|
||||||
{
|
{
|
||||||
var parameter = parameters[index];
|
var parameter = parameters[index];
|
||||||
var parameterName = function.Parameters[index];
|
var parameterSymbol = (FunctionParameterSymbol)function.Parameters[index].VariableSymbol;
|
||||||
innerEvaluator.Scope.CreateLocal(parameterName.VariableSymbol, parameter);
|
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);
|
var result = innerEvaluator.EvaluateNode(function.Block);
|
||||||
|
|
|
@ -74,15 +74,7 @@ namespace Upsilon.Evaluator
|
||||||
|
|
||||||
public object EvaluateFunction(string functionName, object[] parameters = null)
|
public object EvaluateFunction(string functionName, object[] parameters = null)
|
||||||
{
|
{
|
||||||
var luaParameters = ImmutableArray.CreateBuilder<ScriptType>();
|
return Convert(Evaluator.Evaluate(Bind(), functionName, parameters));
|
||||||
if (parameters != null)
|
|
||||||
{
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
luaParameters.Add(parameter.ToScriptType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Convert(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T Convert<T>(ScriptType t)
|
private static T Convert<T>(ScriptType t)
|
||||||
|
@ -108,15 +100,7 @@ namespace Upsilon.Evaluator
|
||||||
|
|
||||||
public T EvaluateFunction<T>(string functionName, object[] parameters = null)
|
public T EvaluateFunction<T>(string functionName, object[] parameters = null)
|
||||||
{
|
{
|
||||||
var luaParameters = ImmutableArray.CreateBuilder<ScriptType>();
|
return Convert<T>(Evaluator.Evaluate(Bind(), functionName, parameters));
|
||||||
if (parameters != null)
|
|
||||||
{
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
luaParameters.Add(parameter.ToScriptType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Convert<T>(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetVariable<T>(string variableName)
|
public T GetVariable<T>(string variableName)
|
||||||
|
|
Loading…
Reference in New Issue