Type check when calling script function from CSharp

This commit is contained in:
Deukhoofd 2018-11-28 20:53:45 +01:00
parent ba82b28ee4
commit babbf2875f
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
6 changed files with 72 additions and 32 deletions

View File

@ -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;
}

View File

@ -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; }

View File

@ -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()];
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace Upsilon.Evaluator
{
public class EvaluationException : Exception
{
public EvaluationException(string message) : base(message)
{
}
}
}

View File

@ -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);

View File

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