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

View File

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

View File

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

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

View File

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