diff --git a/Upsilon/BaseTypes/ScriptFunction.cs b/Upsilon/BaseTypes/ScriptFunction.cs index 4c15a78..b74d1f4 100644 --- a/Upsilon/BaseTypes/ScriptFunction.cs +++ b/Upsilon/BaseTypes/ScriptFunction.cs @@ -25,13 +25,13 @@ namespace Upsilon.BaseTypes public abstract ScriptType Run(Diagnostics diagnostics, ScriptType[] variables); } - internal class ScriptInternalFunction : ScriptFunction, IScopeOwner + internal class ScriptRuntimeFunction : ScriptFunction, IScopeOwner { public BoundBlockStatement Block { get; } public ImmutableArray Parameters { get; } public EvaluationScope EvaluationScope { get; } - public ScriptInternalFunction(ImmutableArray parameters, BoundBlockStatement block, + public ScriptRuntimeFunction(ImmutableArray parameters, BoundBlockStatement block, EvaluationScope evaluationScope) { Parameters = parameters; @@ -59,11 +59,13 @@ namespace Upsilon.BaseTypes _method = method; _object = o; _directTypeManipulation = directTypeManipulation; + ReturnType = _method.ReturnType; } private readonly UserDataMethod _method; private readonly object _object; private readonly bool _directTypeManipulation; + public System.Type ReturnType { get; } public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables) { diff --git a/Upsilon/BaseTypes/TypeConversion.cs b/Upsilon/BaseTypes/TypeConversion.cs index 715658e..fffd48a 100644 --- a/Upsilon/BaseTypes/TypeConversion.cs +++ b/Upsilon/BaseTypes/TypeConversion.cs @@ -1,5 +1,7 @@ +using System; using System.Collections; using Upsilon.BaseTypes.Number; +using Upsilon.BaseTypes.ScriptTypeInterfaces; using Upsilon.BaseTypes.UserData; namespace Upsilon.BaseTypes @@ -43,7 +45,7 @@ namespace Upsilon.BaseTypes return new GenericUserData(o); } - public static Type GetLuaType(object o) + public static Type GetScriptType(object o) { if (o is ScriptType t) { @@ -70,5 +72,38 @@ namespace Upsilon.BaseTypes return Type.UserData; } } + + public static Type GetScriptType(this System.Type t) + { + if (t == typeof(bool)) + return Type.Boolean; + if (t == typeof(string)) + return Type.String; + if (t == typeof(int)) + return Type.Number; + if (t == typeof(long)) + return Type.Number; + if (t == typeof(float)) + return Type.Number; + if (t == typeof(double)) + return Type.Number; + if (t == typeof(void)) + return Type.Nil; + + if (t == typeof(ScriptString)) + return Type.String; + if (typeof(ScriptNumber).IsAssignableFrom(t)) + return Type.Number; + if (typeof(ScriptFunction).IsAssignableFrom(t)) + return Type.Function; + if (typeof(ScriptTable).IsAssignableFrom(t)) + return Type.Table; + if (t == typeof(IIterable)) + return Type.Nil; + + + throw new ArgumentException(t.ToString()); + } + } } \ No newline at end of file diff --git a/Upsilon/BaseTypes/UserData/UserDataMethod.cs b/Upsilon/BaseTypes/UserData/UserDataMethod.cs index 23eb27b..928467c 100644 --- a/Upsilon/BaseTypes/UserData/UserDataMethod.cs +++ b/Upsilon/BaseTypes/UserData/UserDataMethod.cs @@ -32,6 +32,7 @@ namespace Upsilon.BaseTypes.UserData public string Name { get; } private List MethodParts { get; } + public System.Type ReturnType { get; } public UserDataMethod(MethodInfo method) { @@ -41,6 +42,7 @@ namespace Upsilon.BaseTypes.UserData { part }; + ReturnType = part.Method.ReturnType; } public void LoadMethodPart(MethodInfo method) diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index d26f9c0..275f9b7 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -232,27 +232,32 @@ namespace Upsilon.Binder returnType = function.ResultType; var pars = function.Parameters; - if (pars.Length != parameters.Count) + + + if (!function.IsInternal) { - _diagnostics.LogError( - $"Invalid number of parameters for function '{function.Name}'. Expected {pars.Length}, got {parameters.Count}", - e.Span); - } - else - { - for (var i = 0; i < pars.Length; i++) + if (pars.Length != parameters.Count) { - var functionParameter = pars[i]; - var callingParameter = parameters[i]; - if (functionParameter.Type != Type.Unknown && - callingParameter.Type != Type.Unknown && callingParameter.Type != Type.Nil) + _diagnostics.LogError( + $"Invalid number of parameters for function '{function.Name}'. Expected {pars.Length}, got {parameters.Count}", + e.Span); + } + else + { + for (var i = 0; i < pars.Length; i++) { - if (callingParameter.Type != functionParameter.Type) + var functionParameter = pars[i]; + var callingParameter = parameters[i]; + if (functionParameter.Type != Type.Unknown && + callingParameter.Type != Type.Unknown && callingParameter.Type != Type.Nil) { - _diagnostics.LogError( - $"Invalid type for function '{function.Name}' at parameter '{functionParameter.Name}'. " + - $"Expected type '{functionParameter.Type}', got '{callingParameter.Type}'", - callingParameter.Span); + if (callingParameter.Type != functionParameter.Type) + { + _diagnostics.LogError( + $"Invalid type for function '{function.Name}' at parameter '{functionParameter.Name}'. " + + $"Expected type '{functionParameter.Type}', got '{callingParameter.Type}'", + callingParameter.Span); + } } } } @@ -508,7 +513,7 @@ namespace Upsilon.Binder if (!Scope.TryGetVariable(name, !isLocal, out var variable)) { - var functionVariable = new FunctionVariableSymbol(name, isLocal, parameters.ToImmutable(), func.ReturnType) + var functionVariable = new FunctionVariableSymbol(name, isLocal, parameters.ToImmutable(), func.ReturnType, false) { CommentValue = commentData.ToArray() }; diff --git a/Upsilon/Binder/VariableSymbol.cs b/Upsilon/Binder/VariableSymbol.cs index d160a4a..2f954f9 100644 --- a/Upsilon/Binder/VariableSymbol.cs +++ b/Upsilon/Binder/VariableSymbol.cs @@ -26,12 +26,14 @@ namespace Upsilon.Binder public ImmutableArray Parameters { get; } public Type ResultType { get; internal set; } public bool IsBound { get; set; } + public bool IsInternal { get; } - public FunctionVariableSymbol(string name, bool local, ImmutableArray parameters, Type resultType) + public FunctionVariableSymbol(string name, bool local, ImmutableArray parameters, Type resultType, bool isInternal) : base(name, Type.Function, local) { Parameters = parameters; ResultType = resultType; + IsInternal = isInternal; } } diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 40a7d7f..de617d5 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -61,33 +61,36 @@ namespace Upsilon.Evaluator { throw new ArgumentException(($"Function '{functionName}' could not be found")); } - var function = (ScriptInternalFunction) statement; + var function = (ScriptRuntimeFunction) statement; var innerEvaluator = new Evaluator(_diagnostics, Scope); - for (var index = 0; index < parameters.Length; index++) + if (parameters != null) { - var parameter = parameters[index]; - var parameterSymbol = (FunctionParameterSymbol)function.Parameters[index].VariableSymbol; - if (parameterSymbol.BoundTypeDefinition != null) + for (var index = 0; index < parameters.Length; index++) { - bool isCompatible = false; - var parameterType = parameter.GetType(); - foreach (var validType in parameterSymbol.BoundTypeDefinition.ValidInternalTypes) + var parameter = parameters[index]; + var parameterSymbol = (FunctionParameterSymbol)function.Parameters[index].VariableSymbol; + if (parameterSymbol.BoundTypeDefinition != null) { - if (validType.IsAssignableFrom(parameterType)) + bool isCompatible = false; + var parameterType = parameter.GetType(); + foreach (var validType in parameterSymbol.BoundTypeDefinition.ValidInternalTypes) { - isCompatible = true; - break; + 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}'"); } } - 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()); } - - innerEvaluator.Scope.CreateLocal(parameterSymbol, parameter.ToScriptType()); } var result = innerEvaluator.EvaluateNode(function.Block); @@ -414,13 +417,13 @@ namespace Upsilon.Evaluator private ScriptType EvaluateBoundFunctionStatement(BoundFunctionExpression boundFunctionExpression) { - var func = new ScriptInternalFunction(boundFunctionExpression.Parameters, boundFunctionExpression.Block, Scope); + var func = new ScriptRuntimeFunction(boundFunctionExpression.Parameters, boundFunctionExpression.Block, Scope); return func; } private ScriptType EvaluateUnboundFunctionStatement(UnboundFunctionExpression unboundFunctionExpression) { - var func = new ScriptInternalFunction(unboundFunctionExpression.Parameters, unboundFunctionExpression.Block, Scope); + var func = new ScriptRuntimeFunction(unboundFunctionExpression.Parameters, unboundFunctionExpression.Block, Scope); return func; } diff --git a/Upsilon/StandardLibraries/BasicFunctions.cs b/Upsilon/StandardLibraries/BasicFunctions.cs index 1c8c0be..4535726 100644 --- a/Upsilon/StandardLibraries/BasicFunctions.cs +++ b/Upsilon/StandardLibraries/BasicFunctions.cs @@ -8,7 +8,7 @@ using Upsilon.BaseTypes.ScriptTypeInterfaces; namespace Upsilon.StandardLibraries { - internal class BasicFunctions : LuaLibrary + internal class BasicFunctions : ScriptLibrary { [StandardLibraryScriptFunction("assert")] public void Assert(ScriptBoolean boolean, ScriptString message = null) diff --git a/Upsilon/StandardLibraries/LuaLibrary.cs b/Upsilon/StandardLibraries/ScriptLibrary.cs similarity index 76% rename from Upsilon/StandardLibraries/LuaLibrary.cs rename to Upsilon/StandardLibraries/ScriptLibrary.cs index e91a8b1..7534687 100644 --- a/Upsilon/StandardLibraries/LuaLibrary.cs +++ b/Upsilon/StandardLibraries/ScriptLibrary.cs @@ -5,11 +5,11 @@ using Upsilon.BaseTypes.UserData; namespace Upsilon.StandardLibraries { - internal abstract class LuaLibrary + internal abstract class ScriptLibrary { - public Dictionary LoadMethods() + public Dictionary LoadMethods() { - var dictionary = new Dictionary(); + var dictionary = new Dictionary(); var methods = GetType().GetMethods(); foreach (var methodInfo in methods) { diff --git a/Upsilon/StandardLibraries/StaticScope.cs b/Upsilon/StandardLibraries/StaticScope.cs index 3308edd..b7c51a2 100644 --- a/Upsilon/StandardLibraries/StaticScope.cs +++ b/Upsilon/StandardLibraries/StaticScope.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Upsilon.BaseTypes; @@ -42,13 +43,16 @@ namespace Upsilon.StandardLibraries public static (EvaluationScope, BoundScope) CreateStandardLibrary() { var basicFunctions = new BasicFunctions().LoadMethods(); - var scope = new EvaluationScope(basicFunctions.ToDictionary(x => x.Key, x => (ScriptType)x.Value)); - var boundScope = - new BoundScope( - scope.Variables.ToDictionary(x => x.Key, - x => (VariableSymbol) new FunctionVariableSymbol(x.Key, false, - ImmutableArray.Empty, x.Value.Type) {IsBound = true}), - null); + var funcs = new Dictionary(); + var boundFuncs = new Dictionary(); + foreach (var func in basicFunctions) + { + funcs.Add(func.Key, func.Value); + boundFuncs.Add(func.Key, new FunctionVariableSymbol(func.Key, true, ImmutableArray.Empty, + func.Value.ReturnType.GetScriptType(), true){IsBound = true}); + } + var scope = new EvaluationScope(funcs); + var boundScope = new BoundScope(boundFuncs, null); return (scope, boundScope); }