Rework type binding to allow for type awareness in iterators
This commit is contained in:
parent
64aedceb85
commit
f55e6d314d
|
@ -15,13 +15,13 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
public ScriptMethodInfoFunction(UserDataMethod method, object o, bool directTypeManipulation,
|
public ScriptMethodInfoFunction(UserDataMethod method, object o, bool directTypeManipulation,
|
||||||
bool passScriptReference = false, bool passScopeReference = false)
|
bool passScriptReference = false, bool passScopeReference = false)
|
||||||
{
|
{
|
||||||
_method = method;
|
Method = method;
|
||||||
_object = o;
|
_object = o;
|
||||||
_directTypeManipulation = directTypeManipulation;
|
_directTypeManipulation = directTypeManipulation;
|
||||||
_passScriptReference = passScriptReference;
|
_passScriptReference = passScriptReference;
|
||||||
_passScopeReference = passScopeReference;
|
_passScopeReference = passScopeReference;
|
||||||
|
|
||||||
ReturnType = _method.ReturnType;
|
ReturnType = Method.ReturnType;
|
||||||
|
|
||||||
if (method.GetMethods().First().Attribute != null)
|
if (method.GetMethods().First().Attribute != null)
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly UserDataMethod _method;
|
public UserDataMethod Method { get; }
|
||||||
private readonly object _object;
|
private readonly object _object;
|
||||||
private readonly bool _directTypeManipulation;
|
private readonly bool _directTypeManipulation;
|
||||||
private readonly bool _passScriptReference;
|
private readonly bool _passScriptReference;
|
||||||
|
@ -42,7 +42,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
|
|
||||||
public IEnumerable<UserDataMethod.UserDataMethodParameter> GetParameterInfo()
|
public IEnumerable<UserDataMethod.UserDataMethodParameter> GetParameterInfo()
|
||||||
{
|
{
|
||||||
return _method.GetMethods().First().Parameters;
|
return Method.GetMethods().First().Parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span)
|
public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span)
|
||||||
|
@ -61,7 +61,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
{
|
{
|
||||||
// grab the parameters, and just invoke it
|
// grab the parameters, and just invoke it
|
||||||
var array = objects.ToArray();
|
var array = objects.ToArray();
|
||||||
var methodInfo = _method.GetMethod(ref array);
|
var methodInfo = Method.GetMethod(ref array);
|
||||||
result = methodInfo.Invoke(null, array);
|
result = methodInfo.Invoke(null, array);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -90,7 +90,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
foreach (var match in methods)
|
foreach (var match in methods)
|
||||||
{
|
{
|
||||||
// if the method does not have the name we're looking for, continue
|
// if the method does not have the name we're looking for, continue
|
||||||
if (!string.Equals(match.Name, _method.Name)) continue;
|
if (!string.Equals(match.Name, Method.Name)) continue;
|
||||||
// Use the type binder to check if the match is allowed
|
// Use the type binder to check if the match is allowed
|
||||||
if (UpsilonBinder.Default.IsValidMatch(match, convertedTypes))
|
if (UpsilonBinder.Default.IsValidMatch(match, convertedTypes))
|
||||||
{
|
{
|
||||||
|
@ -108,7 +108,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
|
||||||
if (method == null)
|
if (method == null)
|
||||||
{
|
{
|
||||||
throw new ScriptRuntimeException(
|
throw new ScriptRuntimeException(
|
||||||
$"Can't find method {_method.Name} with parameter types {string.Join(", ", convertedTypes.Select(x => x.Name))} on type {_object.GetType().Name}",
|
$"Can't find method {Method.Name} with parameter types {string.Join(", ", convertedTypes.Select(x => x.Name))} on type {_object.GetType().Name}",
|
||||||
span, diagnostics.ScriptString.GetSpan(span));
|
span, diagnostics.ScriptString.GetSpan(span));
|
||||||
}
|
}
|
||||||
// get the method parameters
|
// get the method parameters
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Upsilon.BaseTypes
|
||||||
|
{
|
||||||
|
public class TypeContainer
|
||||||
|
{
|
||||||
|
public Type Type { get; }
|
||||||
|
|
||||||
|
protected TypeContainer(Type t)
|
||||||
|
{
|
||||||
|
Type = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator TypeContainer (Type type)
|
||||||
|
{
|
||||||
|
return new TypeContainer(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Type(TypeContainer t)
|
||||||
|
{
|
||||||
|
return t.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool Equals(TypeContainer other)
|
||||||
|
{
|
||||||
|
return Type == other.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
if (obj is Type t)
|
||||||
|
{
|
||||||
|
return t == Type;
|
||||||
|
}
|
||||||
|
if (obj.GetType() != this.GetType()) return false;
|
||||||
|
return Equals((TypeContainer) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return (int) Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator == (TypeContainer a, object b)
|
||||||
|
{
|
||||||
|
return Equals(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator != (TypeContainer a, object b)
|
||||||
|
{
|
||||||
|
return !Equals(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CompositeTypeContainer : TypeContainer
|
||||||
|
{
|
||||||
|
public ImmutableArray<Type> Types { get; set; }
|
||||||
|
|
||||||
|
public CompositeTypeContainer() : base(Type.Table)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,7 +55,7 @@ namespace Upsilon.Binder
|
||||||
foreach (var valueParameter in unboundFunctionStatement.Value.Parameters)
|
foreach (var valueParameter in unboundFunctionStatement.Value.Parameters)
|
||||||
{
|
{
|
||||||
Scope.AssignToNearest(valueParameter.VariableSymbol);
|
Scope.AssignToNearest(valueParameter.VariableSymbol);
|
||||||
if (valueParameter.VariableSymbol.Type == Type.Unknown)
|
if (valueParameter.VariableSymbol.TypeContainer == Type.Unknown)
|
||||||
_diagnostics.LogUnknownVariableType(valueParameter.VariableSymbol.Name, valueParameter.Span);
|
_diagnostics.LogUnknownVariableType(valueParameter.VariableSymbol.Name, valueParameter.Span);
|
||||||
}
|
}
|
||||||
unboundFunctionStatement.Value.Block =
|
unboundFunctionStatement.Value.Block =
|
||||||
|
@ -220,13 +220,14 @@ namespace Upsilon.Binder
|
||||||
parameters.Add(bound);
|
parameters.Add(bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnType = Type.Unknown;
|
TypeContainer returnType = Type.Unknown;
|
||||||
var resolved = ResolveVariable(expression, _diagnostics);
|
var resolved = ResolveVariable(expression, _diagnostics);
|
||||||
if (resolved == null)
|
if (resolved == null)
|
||||||
{
|
{
|
||||||
_diagnostics.LogError("Can't resolve variable", expression.Span);
|
_diagnostics.LogError("Can't resolve variable", expression.Span);
|
||||||
}
|
}
|
||||||
if (resolved is FunctionVariableSymbol function)
|
|
||||||
|
else if (resolved is FunctionVariableSymbol function)
|
||||||
{
|
{
|
||||||
if (function is ScriptFunctionVariableSymbol scriptFunction)
|
if (function is ScriptFunctionVariableSymbol scriptFunction)
|
||||||
{
|
{
|
||||||
|
@ -237,7 +238,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
var functionVariable = scriptFunction.Parameters[index];
|
var functionVariable = scriptFunction.Parameters[index];
|
||||||
var callingVariable = parameters[index];
|
var callingVariable = parameters[index];
|
||||||
functionVariable.Type = callingVariable.Type;
|
functionVariable.TypeContainer = callingVariable.Type;
|
||||||
Scope.DefineLocalVariable(functionVariable);
|
Scope.DefineLocalVariable(functionVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,10 +281,16 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (resolved is InternalFunctionVariableSymbol internalFunction)
|
||||||
|
{
|
||||||
|
returnType = internalFunction.GetResultType(parameters.ToArray());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
returnType = function.ResultType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
returnType = function.ResultType;
|
|
||||||
|
|
||||||
var (isValid, error, wrongParameter) = function.ValidateParameters(parameters.ToImmutable());
|
var (isValid, error, wrongParameter) = function.ValidateParameters(parameters.ToImmutable());
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
{
|
{
|
||||||
|
@ -331,11 +338,11 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
diagnostics?.LogError("Can't resolve variable", expression.Span);
|
diagnostics?.LogError("Can't resolve variable", expression.Span);
|
||||||
}
|
}
|
||||||
else if (indexerVariable.Type == Type.Table)
|
else if (indexerVariable.TypeContainer == Type.Table)
|
||||||
{
|
{
|
||||||
return ((TableVariableSymbol)indexerVariable).Variables[fullStopIndexExpression.Index];
|
return ((TableVariableSymbol)indexerVariable).Variables[fullStopIndexExpression.Index];
|
||||||
}
|
}
|
||||||
else if (indexerVariable.Type == Type.UserData)
|
else if (indexerVariable.TypeContainer == Type.UserData)
|
||||||
{
|
{
|
||||||
var parent =
|
var parent =
|
||||||
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) indexerVariable).BoundTypeDefinition;
|
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) indexerVariable).BoundTypeDefinition;
|
||||||
|
@ -349,7 +356,7 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (indexerVariable.Type == Type.Unknown)
|
else if (indexerVariable.TypeContainer == Type.Unknown)
|
||||||
{
|
{
|
||||||
if (indexerVariable is UserDataVariableSymbol funcSymbol)
|
if (indexerVariable is UserDataVariableSymbol funcSymbol)
|
||||||
{
|
{
|
||||||
|
@ -405,17 +412,18 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
if (assignment.Kind == BoundKind.BoundTableExpression)
|
if (assignment.Kind == BoundKind.BoundTableExpression)
|
||||||
{
|
{
|
||||||
variable = new TableVariableSymbol(name, isLocal, ((BoundTableExpression)assignment).Expressions);
|
variable = new TableVariableSymbol(name, isLocal,
|
||||||
|
((BoundTableExpression) assignment).Expressions, assignment.Type);
|
||||||
}
|
}
|
||||||
else if (assignment.Kind == BoundKind.VariableExpression)
|
else if (assignment.Kind == BoundKind.VariableExpression)
|
||||||
{
|
{
|
||||||
variable = new TableVariableSymbol(name, isLocal,
|
variable = new TableVariableSymbol(name, isLocal,
|
||||||
((TableVariableSymbol) ((BoundVariableExpression) assignment).Variable.VariableSymbol)
|
((TableVariableSymbol) ((BoundVariableExpression) assignment).Variable.VariableSymbol)
|
||||||
.Variables);
|
.Variables, assignment.Type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
variable = new TableVariableSymbol(name, isLocal);
|
variable = new TableVariableSymbol(name, isLocal, assignment.Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -435,26 +443,26 @@ namespace Upsilon.Binder
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
|
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
|
||||||
if (assignment.Type != variable.Type)
|
if (assignment.Type != variable.TypeContainer)
|
||||||
{
|
{
|
||||||
if (variable.Type == Type.Nil || assignment.Type == Type.Nil)
|
if (variable.TypeContainer == Type.Nil || assignment.Type == Type.Nil)
|
||||||
{
|
{
|
||||||
variable.Type = assignment.Type;
|
variable.TypeContainer = assignment.Type;
|
||||||
}
|
}
|
||||||
else if (variable.Type == Type.Unknown)
|
else if (variable.TypeContainer == Type.Unknown)
|
||||||
{
|
{
|
||||||
variable.Type = assignment.Type;
|
variable.TypeContainer = assignment.Type;
|
||||||
}
|
}
|
||||||
else if (assignment.Type == Type.Unknown && assignment is BoundVariableExpression v)
|
else if (assignment.Type == Type.Unknown && assignment is BoundVariableExpression v)
|
||||||
{
|
{
|
||||||
v.Variable.VariableSymbol.Type = variable.Type;
|
v.Variable.VariableSymbol.TypeContainer = variable.TypeContainer;
|
||||||
}
|
}
|
||||||
else if (assignment.Type == Type.Unknown)
|
else if (assignment.Type == Type.Unknown)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_diagnostics.LogCannotConvert(assignment.Type, variable.Type, assignment.Span);
|
_diagnostics.LogCannotConvert(assignment.Type, variable.TypeContainer, assignment.Span);
|
||||||
return (null, false);
|
return (null, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,7 +482,7 @@ namespace Upsilon.Binder
|
||||||
var (symbol, isCreation) = TryBindVariable(name, isLocal, boundExpression, e.CommentData);
|
var (symbol, isCreation) = TryBindVariable(name, isLocal, boundExpression, e.CommentData);
|
||||||
if (symbol != null)
|
if (symbol != null)
|
||||||
{
|
{
|
||||||
if (symbol.Type == Type.Unknown)
|
if (symbol.TypeContainer == Type.Unknown)
|
||||||
{
|
{
|
||||||
_diagnostics.LogUnknownVariableType(symbol.Name, variableExpression.Span);
|
_diagnostics.LogUnknownVariableType(symbol.Name, variableExpression.Span);
|
||||||
}
|
}
|
||||||
|
@ -496,7 +504,7 @@ namespace Upsilon.Binder
|
||||||
foreach (var identifierToken in s.Identifiers)
|
foreach (var identifierToken in s.Identifiers)
|
||||||
{
|
{
|
||||||
var boundVariable = TryBindVariable(identifierToken.Name, isLocal, assignment, null);
|
var boundVariable = TryBindVariable(identifierToken.Name, isLocal, assignment, null);
|
||||||
if (boundVariable.Symbol.Type == Type.Unknown)
|
if (boundVariable.Symbol.TypeContainer == Type.Unknown)
|
||||||
{
|
{
|
||||||
_diagnostics.LogUnknownVariableType(boundVariable.Symbol.Name, identifierToken.Span);
|
_diagnostics.LogUnknownVariableType(boundVariable.Symbol.Name, identifierToken.Span);
|
||||||
}
|
}
|
||||||
|
@ -610,7 +618,7 @@ namespace Upsilon.Binder
|
||||||
|
|
||||||
foreach (var parameter in func.Parameters)
|
foreach (var parameter in func.Parameters)
|
||||||
{
|
{
|
||||||
var vari = new VariableSymbol(parameter.VariableSymbol.Name, parameter.VariableSymbol.Type, true);
|
var vari = new VariableSymbol(parameter.VariableSymbol.Name, parameter.VariableSymbol.TypeContainer, true);
|
||||||
parameters.Add(vari);
|
parameters.Add(vari);
|
||||||
innerScope.DefineLocalVariable(vari);
|
innerScope.DefineLocalVariable(vari);
|
||||||
}
|
}
|
||||||
|
@ -637,15 +645,15 @@ namespace Upsilon.Binder
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
|
// don't allow assigning different typed variables to a variable, unless either of them is nil, allow assigning nil to all variables
|
||||||
if (variable.Type != Type.Function)
|
if (variable.TypeContainer != Type.Function)
|
||||||
{
|
{
|
||||||
if (variable.Type == Type.Nil || variable.Type == Type.Unknown)
|
if (variable.TypeContainer == Type.Nil || variable.TypeContainer == Type.Unknown)
|
||||||
{
|
{
|
||||||
variable.Type = Type.Function;
|
variable.TypeContainer = Type.Function;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_diagnostics.LogCannotConvert(Type.Function, variable.Type, e.Span);
|
_diagnostics.LogCannotConvert(Type.Function, variable.TypeContainer, e.Span);
|
||||||
return new BoundExpressionStatement(new BoundBadExpression(e.Span), e.Span);
|
return new BoundExpressionStatement(new BoundBadExpression(e.Span), e.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -712,7 +720,7 @@ namespace Upsilon.Binder
|
||||||
_diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span);
|
_diagnostics.LogInvalidIndexExpression(expression.Type, index.Type, e.Span);
|
||||||
return new BoundBadExpression(e.Span);
|
return new BoundBadExpression(e.Span);
|
||||||
}
|
}
|
||||||
switch (expression.Type)
|
switch (expression.Type.Type)
|
||||||
{
|
{
|
||||||
case Type.Table:
|
case Type.Table:
|
||||||
if (isAssignment)
|
if (isAssignment)
|
||||||
|
@ -726,7 +734,7 @@ namespace Upsilon.Binder
|
||||||
var variableDic = table.Expressions;
|
var variableDic = table.Expressions;
|
||||||
if (variableDic.TryGetValue(realIndex.Value.ToString(), out var variable))
|
if (variableDic.TryGetValue(realIndex.Value.ToString(), out var variable))
|
||||||
{
|
{
|
||||||
return new BoundIndexExpression(expression, index, variable.Type, e.Span);
|
return new BoundIndexExpression(expression, index, variable.TypeContainer, e.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
_diagnostics.LogError($"No variable '{realIndex.Value}' found in table.",
|
_diagnostics.LogError($"No variable '{realIndex.Value}' found in table.",
|
||||||
|
@ -746,7 +754,7 @@ namespace Upsilon.Binder
|
||||||
var variableDic = tableSymbol.Variables;
|
var variableDic = tableSymbol.Variables;
|
||||||
if (variableDic.TryGetValue(realIndex.Value.ToString(), out var variable))
|
if (variableDic.TryGetValue(realIndex.Value.ToString(), out var variable))
|
||||||
{
|
{
|
||||||
return new BoundIndexExpression(expression, index, variable.Type, e.Span);
|
return new BoundIndexExpression(expression, index, variable.TypeContainer, e.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
_diagnostics.LogError($"No variable '{realIndex.Value}' found in table '{realTable.VariableSymbol.Name}'.",
|
_diagnostics.LogError($"No variable '{realIndex.Value}' found in table '{realTable.VariableSymbol.Name}'.",
|
||||||
|
@ -768,7 +776,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
var expression = BindExpression(e.Expression);
|
var expression = BindExpression(e.Expression);
|
||||||
var index = e.Index.Name;
|
var index = e.Index.Name;
|
||||||
switch (expression.Type)
|
switch (expression.Type.Type)
|
||||||
{
|
{
|
||||||
case Type.Table:
|
case Type.Table:
|
||||||
if (isAssignment)
|
if (isAssignment)
|
||||||
|
@ -780,7 +788,7 @@ namespace Upsilon.Binder
|
||||||
var table = (BoundTableExpression)expression;
|
var table = (BoundTableExpression)expression;
|
||||||
if (table.Expressions.TryGetValue(index, out var variable))
|
if (table.Expressions.TryGetValue(index, out var variable))
|
||||||
{
|
{
|
||||||
return new BoundFullStopIndexExpression(expression, index, variable.Type, e.Span);
|
return new BoundFullStopIndexExpression(expression, index, variable.TypeContainer, e.Span);
|
||||||
}
|
}
|
||||||
_diagnostics.LogError($"No variable '{index}' found in table.", e.Span);
|
_diagnostics.LogError($"No variable '{index}' found in table.", e.Span);
|
||||||
}
|
}
|
||||||
|
@ -791,7 +799,7 @@ namespace Upsilon.Binder
|
||||||
var variableDic = ((TableVariableSymbol) realTable.VariableSymbol).Variables;
|
var variableDic = ((TableVariableSymbol) realTable.VariableSymbol).Variables;
|
||||||
if (variableDic.TryGetValue(index, out var variable))
|
if (variableDic.TryGetValue(index, out var variable))
|
||||||
{
|
{
|
||||||
return new BoundFullStopIndexExpression(expression, index, variable.Type, e.Span);
|
return new BoundFullStopIndexExpression(expression, index, variable.TypeContainer, e.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
_diagnostics.LogError($"No variable '{index}' found in table '{realTable.VariableSymbol.Name}'.",
|
_diagnostics.LogError($"No variable '{index}' found in table '{realTable.VariableSymbol.Name}'.",
|
||||||
|
@ -897,13 +905,29 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
Scope = new BoundScope(Scope);
|
Scope = new BoundScope(Scope);
|
||||||
var array = ImmutableArray.CreateBuilder<BoundVariableSymbol>();
|
var array = ImmutableArray.CreateBuilder<BoundVariableSymbol>();
|
||||||
foreach (var variableIdentifier in e.Variables)
|
|
||||||
{
|
var keyVar = e.Variables[0];
|
||||||
var variable = new VariableSymbol(variableIdentifier.Name, Type.Unknown, true);
|
var keyVariable = new VariableSymbol(keyVar.Name, Type.String, true);
|
||||||
Scope.DefineLocalVariable(variable);
|
Scope.DefineLocalVariable(keyVariable);
|
||||||
array.Add(new BoundVariableSymbol(variable, true, variableIdentifier.Span));
|
array.Add(new BoundVariableSymbol(keyVariable, true, keyVar.Span));
|
||||||
}
|
|
||||||
var boundEnumerableExpression = BindExpression(e.EnumerableExpression);
|
var boundEnumerableExpression = BindExpression(e.EnumerableExpression);
|
||||||
|
|
||||||
|
var valueVar = e.Variables[1];
|
||||||
|
VariableSymbol valueVariable;
|
||||||
|
if (boundEnumerableExpression.Type is CompositeTypeContainer composite && composite.Types.Length == 2)
|
||||||
|
{
|
||||||
|
valueVariable = new VariableSymbol(valueVar.Name, composite.Types[1], true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
valueVariable = new VariableSymbol(valueVar.Name, Type.Unknown, true);
|
||||||
|
}
|
||||||
|
Scope.DefineLocalVariable(valueVariable);
|
||||||
|
array.Add(new BoundVariableSymbol(valueVariable, true, valueVar.Span));
|
||||||
|
|
||||||
|
|
||||||
var block = BindBlockStatement(e.Block);
|
var block = BindBlockStatement(e.Block);
|
||||||
|
|
||||||
return new BoundGenericForStatement(array.ToImmutable(), boundEnumerableExpression, block, e.Span);
|
return new BoundGenericForStatement(array.ToImmutable(), boundEnumerableExpression, block, e.Span);
|
||||||
|
|
|
@ -17,6 +17,6 @@ namespace Upsilon.Binder
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type => Type.Nil;
|
public override TypeContainer Type => BaseTypes.Type.Nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@ namespace Upsilon.Binder
|
||||||
yield return RightExpression;
|
yield return RightExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type { get; }
|
public override TypeContainer Type { get; }
|
||||||
|
|
||||||
public BoundBinaryOperator Operator { get; }
|
public BoundBinaryOperator Operator { get; }
|
||||||
public BoundExpression LeftExpression { get; }
|
public BoundExpression LeftExpression { get; }
|
||||||
|
|
|
@ -9,6 +9,6 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Type Type { get; }
|
public abstract TypeContainer Type { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ namespace Upsilon.Binder
|
||||||
public ImmutableArray<BoundExpression> Parameters { get; }
|
public ImmutableArray<BoundExpression> Parameters { get; }
|
||||||
|
|
||||||
public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray<BoundExpression> parameters,
|
public BoundFunctionCallExpression(BoundExpression identifier, ImmutableArray<BoundExpression> parameters,
|
||||||
TextSpan span, Type type) : base(span)
|
TextSpan span, TypeContainer type) : base(span)
|
||||||
{
|
{
|
||||||
Identifier = identifier;
|
Identifier = identifier;
|
||||||
Parameters = parameters;
|
Parameters = parameters;
|
||||||
|
@ -29,6 +29,6 @@ namespace Upsilon.Binder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type { get; }
|
public override TypeContainer Type { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 Upsilon.BaseTypes;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ namespace Upsilon.Binder
|
||||||
yield return Block;
|
yield return Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type => Type.Function;
|
public override TypeContainer Type => BaseTypes.Type.Function;
|
||||||
public BoundScope Scope { get; set; }
|
public BoundScope Scope { get; set; }
|
||||||
public Type ReturnType { get; }
|
public Type ReturnType { get; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Upsilon.Binder
|
||||||
yield return Index;
|
yield return Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type { get; }
|
public override TypeContainer Type { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundFullStopIndexExpression : BoundExpression
|
public class BoundFullStopIndexExpression : BoundExpression
|
||||||
|
@ -47,6 +47,6 @@ namespace Upsilon.Binder
|
||||||
yield return Expression;
|
yield return Expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type { get; }
|
public override TypeContainer Type { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,7 @@ namespace Upsilon.Binder
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type => Value.Type;
|
public override TypeContainer Type => Value.Type;
|
||||||
public ScriptType Value { get; }
|
public ScriptType Value { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.Binder.VariableSymbols;
|
using Upsilon.Binder.VariableSymbols;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
@ -24,7 +24,39 @@ namespace Upsilon.Binder
|
||||||
return Statements;
|
return Statements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type => Type.Table;
|
public override TypeContainer Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Type? valueType = null;
|
||||||
|
foreach (var statement in Statements)
|
||||||
|
{
|
||||||
|
if (!(statement is BoundExpressionStatement exp))
|
||||||
|
{
|
||||||
|
valueType = BaseTypes.Type.Unknown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!valueType.HasValue)
|
||||||
|
{
|
||||||
|
valueType = exp.Expression.Type;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (valueType == exp.Expression.Type) continue;
|
||||||
|
valueType = BaseTypes.Type.Unknown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var valueRealType = BaseTypes.Type.Unknown;
|
||||||
|
if (valueType.HasValue)
|
||||||
|
valueRealType = valueType.Value;
|
||||||
|
|
||||||
|
var arr = new[] {BaseTypes.Type.String, valueRealType};
|
||||||
|
return new CompositeTypeContainer()
|
||||||
|
{
|
||||||
|
Types = arr.ToImmutableArray()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Dictionary<string, VariableSymbol> Expressions { get; }
|
public Dictionary<string, VariableSymbol> Expressions { get; }
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Upsilon.Binder
|
||||||
yield return InExpression;
|
yield return InExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type { get; }
|
public override TypeContainer Type { get; }
|
||||||
|
|
||||||
public BoundUnaryExpression(BoundUnaryOperator op, BoundExpression inExpression, Type type, TextSpan span) : base(span)
|
public BoundUnaryExpression(BoundUnaryOperator op, BoundExpression inExpression, Type type, TextSpan span) : base(span)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.Text;
|
using Upsilon.Text;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
|
@ -20,6 +21,6 @@ namespace Upsilon.Binder
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type => Variable.Type;
|
public override TypeContainer Type => Variable.Type;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ namespace Upsilon.Binder
|
||||||
{
|
{
|
||||||
public UnboundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters,
|
public UnboundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters,
|
||||||
BlockStatementSyntax unboundBlock, TextSpan span, BoundScope scope)
|
BlockStatementSyntax unboundBlock, TextSpan span, BoundScope scope)
|
||||||
: base(parameters, null, span, scope, Type.Unknown)
|
: base(parameters, null, span, scope, BaseTypes.Type.Unknown)
|
||||||
{
|
{
|
||||||
UnboundBlock = unboundBlock;
|
UnboundBlock = unboundBlock;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,6 @@ namespace Upsilon.Binder
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Type Type => VariableSymbol.Type;
|
public override TypeContainer Type => VariableSymbol.TypeContainer;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,18 +8,12 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
public Type ResultType { get; internal set; }
|
public Type ResultType { get; internal set; }
|
||||||
|
|
||||||
public FunctionVariableSymbol(string name, bool local, Type resultType)
|
public FunctionVariableSymbol(string name, bool local, Type resultType)
|
||||||
: base(name, Type.Function, local)
|
: base(name, BaseTypes.Type.Function, local)
|
||||||
{
|
{
|
||||||
ResultType = resultType;
|
ResultType = resultType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract (bool IsValid, string Error, BoundExpression WrongParameter) ValidateParameters(
|
public abstract (bool IsValid, string Error, BoundExpression WrongParameter) ValidateParameters(
|
||||||
ImmutableArray<BoundExpression> callingParameters);
|
ImmutableArray<BoundExpression> callingParameters);
|
||||||
|
|
||||||
public override Type Type
|
|
||||||
{
|
|
||||||
get => Type.Function;
|
|
||||||
set{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.BoundTypes;
|
using Upsilon.BoundTypes;
|
||||||
using Type = Upsilon.BaseTypes.Type;
|
using Type = Upsilon.BaseTypes.Type;
|
||||||
|
|
||||||
|
@ -8,37 +9,17 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
{
|
{
|
||||||
public class InternalFunctionVariableSymbol : FunctionVariableSymbol
|
public class InternalFunctionVariableSymbol : FunctionVariableSymbol
|
||||||
{
|
{
|
||||||
public class InternalFunctionParameter
|
private InternalFunctionParameter[] FunctionParameters { get; }
|
||||||
{
|
|
||||||
public InternalFunctionParameter(string name, Type type, bool isOptional)
|
|
||||||
{
|
|
||||||
ValidTypes = type;
|
|
||||||
IsOptional = isOptional;
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InternalFunctionParameter(string name, Type type, string[] expectedUserData, bool isOptional)
|
|
||||||
{
|
|
||||||
ValidTypes = type;
|
|
||||||
ExpectedUserData = expectedUserData;
|
|
||||||
IsOptional = isOptional;
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
public Type ValidTypes { get; }
|
|
||||||
public string[] ExpectedUserData { get; }
|
|
||||||
public bool IsOptional { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public InternalFunctionParameter[] FunctionParameters { get; }
|
|
||||||
private int MinimalParametersRequired { get; }
|
private int MinimalParametersRequired { get; }
|
||||||
|
private MethodInfo OverrideResultType { get; }
|
||||||
|
|
||||||
public InternalFunctionVariableSymbol(string name, bool local, Type resultType, InternalFunctionParameter[] functionParameters)
|
public InternalFunctionVariableSymbol(string name, bool local, Type resultType,
|
||||||
|
InternalFunctionParameter[] functionParameters, MethodInfo overrideResultType)
|
||||||
: base(name, local, resultType)
|
: base(name, local, resultType)
|
||||||
{
|
{
|
||||||
FunctionParameters = functionParameters;
|
FunctionParameters = functionParameters;
|
||||||
MinimalParametersRequired = functionParameters.Count(x => !x.IsOptional);
|
MinimalParametersRequired = functionParameters.Count(x => !x.IsOptional);
|
||||||
|
OverrideResultType = overrideResultType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (bool IsValid, string Error,
|
public override (bool IsValid, string Error,
|
||||||
|
@ -70,7 +51,7 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
if (functionParameter.ValidTypes.HasFlag(Type.UserData))
|
if (functionParameter.ValidTypes.HasFlag(Type.UserData))
|
||||||
{
|
{
|
||||||
var variable = Binder.ResolveVariable(callingParameter, null);
|
var variable = Binder.ResolveVariable(callingParameter, null);
|
||||||
if (variable != null && variable.Type == Type.UserData)
|
if (variable != null && variable.TypeContainer == Type.UserData)
|
||||||
{
|
{
|
||||||
var parent =
|
var parent =
|
||||||
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) variable).BoundTypeDefinition;
|
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) variable).BoundTypeDefinition;
|
||||||
|
@ -87,5 +68,35 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
|
|
||||||
return (true, null, null);
|
return (true, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TypeContainer GetResultType(BoundExpression[] parameters)
|
||||||
|
{
|
||||||
|
if (OverrideResultType == null)
|
||||||
|
return ResultType;
|
||||||
|
return (TypeContainer) OverrideResultType.Invoke(null, new object[] {parameters});
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InternalFunctionParameter
|
||||||
|
{
|
||||||
|
public InternalFunctionParameter(string name, TypeContainer type, bool isOptional)
|
||||||
|
{
|
||||||
|
ValidTypes = type;
|
||||||
|
IsOptional = isOptional;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InternalFunctionParameter(string name, TypeContainer type, string[] expectedUserData, bool isOptional)
|
||||||
|
{
|
||||||
|
ValidTypes = type;
|
||||||
|
ExpectedUserData = expectedUserData;
|
||||||
|
IsOptional = isOptional;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public Type ValidTypes { get; }
|
||||||
|
public string[] ExpectedUserData { get; }
|
||||||
|
public bool IsOptional { get; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -28,13 +28,13 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
{
|
{
|
||||||
var functionParameter = Parameters[i];
|
var functionParameter = Parameters[i];
|
||||||
var callingParameter = callingParameters[i];
|
var callingParameter = callingParameters[i];
|
||||||
if (functionParameter.Type != Type.Unknown &&
|
if (functionParameter.TypeContainer != BaseTypes.Type.Unknown &&
|
||||||
callingParameter.Type != Type.Unknown && callingParameter.Type != Type.Nil)
|
callingParameter.Type != BaseTypes.Type.Unknown && callingParameter.Type != BaseTypes.Type.Nil)
|
||||||
{
|
{
|
||||||
if (callingParameter.Type != functionParameter.Type)
|
if (callingParameter.Type != functionParameter.TypeContainer)
|
||||||
{
|
{
|
||||||
return (false, $"Invalid type for function '{Name}' at parameter '{functionParameter.Name}'. " +
|
return (false, $"Invalid type for function '{Name}' at parameter '{functionParameter.Name}'. " +
|
||||||
$"Expected type '{functionParameter.Type}', got '{callingParameter.Type}'",
|
$"Expected type '{functionParameter.TypeContainer}', got '{callingParameter.Type}'",
|
||||||
callingParameter);
|
callingParameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,16 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
{
|
{
|
||||||
public Dictionary<string, VariableSymbol> Variables { get; }
|
public Dictionary<string, VariableSymbol> Variables { get; }
|
||||||
public bool ContentAware { get; }
|
public bool ContentAware { get; }
|
||||||
public TableVariableSymbol(string name, bool local, Dictionary<string, VariableSymbol> variables)
|
public TableVariableSymbol(string name, bool local, Dictionary<string, VariableSymbol> variables,
|
||||||
:base (name, Type.Table, local)
|
TypeContainer type)
|
||||||
|
:base (name, type, local)
|
||||||
{
|
{
|
||||||
Variables = variables;
|
Variables = variables;
|
||||||
ContentAware = true;
|
ContentAware = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TableVariableSymbol(string name, bool local)
|
public TableVariableSymbol(string name, bool local, TypeContainer type)
|
||||||
:base (name, Type.Table, local)
|
:base (name, type, local)
|
||||||
{
|
{
|
||||||
Variables = new Dictionary<string, VariableSymbol>();
|
Variables = new Dictionary<string, VariableSymbol>();
|
||||||
ContentAware = false;
|
ContentAware = false;
|
||||||
|
|
|
@ -8,9 +8,9 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
public BoundTypeDefinition BoundTypeDefinition { get; }
|
public BoundTypeDefinition BoundTypeDefinition { get; }
|
||||||
public UserDataBoundTypeDefinition Parent { get; }
|
public UserDataBoundTypeDefinition Parent { get; }
|
||||||
|
|
||||||
public UserDataVariableSymbol(string name, Type type) : base(name, type, true)
|
public UserDataVariableSymbol(string name, Type typeContainer) : base(name, typeContainer, true)
|
||||||
{
|
{
|
||||||
_type = type;
|
_typeContainer = typeContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserDataVariableSymbol(string name, BoundTypeDefinition type, UserDataBoundTypeDefinition parent = null)
|
public UserDataVariableSymbol(string name, BoundTypeDefinition type, UserDataBoundTypeDefinition parent = null)
|
||||||
|
@ -20,11 +20,11 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type _type;
|
private TypeContainer _typeContainer;
|
||||||
public override Type Type
|
public override TypeContainer TypeContainer
|
||||||
{
|
{
|
||||||
get => BoundTypeDefinition?.ScriptType ?? _type;
|
get => BoundTypeDefinition?.ScriptType ?? _typeContainer;
|
||||||
set => _type = Type;
|
set => _typeContainer = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,14 +4,14 @@ namespace Upsilon.Binder.VariableSymbols
|
||||||
{
|
{
|
||||||
public class VariableSymbol
|
public class VariableSymbol
|
||||||
{
|
{
|
||||||
public VariableSymbol(string name, Type type, bool local)
|
public VariableSymbol(string name, TypeContainer typeContainer, bool local)
|
||||||
{
|
{
|
||||||
Type = type;
|
TypeContainer = typeContainer;
|
||||||
Local = local;
|
Local = local;
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Type Type { get; set; } = Type.Unknown;
|
public virtual TypeContainer TypeContainer { get; set; }
|
||||||
public bool Local { get; }
|
public bool Local { get; }
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public string[] CommentValue { get; set; }
|
public string[] CommentValue { get; set; }
|
||||||
|
|
|
@ -191,7 +191,7 @@ namespace Upsilon.BoundTypes
|
||||||
if (functionParameter.Type.HasFlag(Type.UserData))
|
if (functionParameter.Type.HasFlag(Type.UserData))
|
||||||
{
|
{
|
||||||
var variable = Binder.Binder.ResolveVariable(callingParameter, null);
|
var variable = Binder.Binder.ResolveVariable(callingParameter, null);
|
||||||
if (variable != null && variable.Type == Type.UserData)
|
if (variable != null && variable.TypeContainer == Type.UserData)
|
||||||
{
|
{
|
||||||
var parent =
|
var parent =
|
||||||
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) variable).BoundTypeDefinition;
|
(UserDataBoundTypeDefinition) ((UserDataVariableSymbol) variable).BoundTypeDefinition;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Upsilon.BaseTypes;
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.BaseTypes.Number;
|
using Upsilon.BaseTypes.Number;
|
||||||
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
using Upsilon.BaseTypes.ScriptTypeInterfaces;
|
||||||
using Upsilon.Binder;
|
using Upsilon.Binder;
|
||||||
|
using Upsilon.Binder.VariableSymbols;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
|
|
||||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||||
|
@ -39,19 +39,27 @@ namespace Upsilon.StandardLibraries
|
||||||
}
|
}
|
||||||
|
|
||||||
[ScriptFunction("ipairs", "Iterates over an iterable variable, like a table, until it encounters a nil value.",
|
[ScriptFunction("ipairs", "Iterates over an iterable variable, like a table, until it encounters a nil value.",
|
||||||
directScriptManipulation: true)]
|
directScriptManipulation: true, overrideReturnType: typeof(BasicFunctions), overrideReturnMethod: nameof(PairsBindHandler))]
|
||||||
public IIterable UpTillNullPairs(IIterable table)
|
public UpTillNullPairsScriptIterator UpTillNullPairs(IIterable table)
|
||||||
{
|
{
|
||||||
return new UpTillNullPairsScriptIterator(table);
|
return new UpTillNullPairsScriptIterator(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
[ScriptFunction("pairs", "Iterates over an iterable variable, like a table, skipping all nil values.",
|
[ScriptFunction("pairs", "Iterates over an iterable variable, like a table, skipping all nil values.",
|
||||||
directScriptManipulation: true)]
|
directScriptManipulation: true, overrideReturnType: typeof(BasicFunctions), overrideReturnMethod: nameof(PairsBindHandler))]
|
||||||
public IIterable Pairs(IIterable table)
|
public PairsScriptIterator Pairs(IIterable table)
|
||||||
{
|
{
|
||||||
return new PairsScriptIterator(table);
|
return new PairsScriptIterator(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TypeContainer PairsBindHandler(BoundExpression[] variableSymbols)
|
||||||
|
{
|
||||||
|
if (variableSymbols.Length != 1)
|
||||||
|
return BaseTypes.Type.Unknown;
|
||||||
|
var parameter = variableSymbols[0];
|
||||||
|
return parameter.Type;
|
||||||
|
}
|
||||||
|
|
||||||
[ScriptFunction("print", "Prints a message to the action given in the script options", passScriptReference: true,
|
[ScriptFunction("print", "Prints a message to the action given in the script options", passScriptReference: true,
|
||||||
directScriptManipulation: true)]
|
directScriptManipulation: true)]
|
||||||
public void Print(Script script, ScriptType message)
|
public void Print(Script script, ScriptType message)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Upsilon.StandardLibraries
|
namespace Upsilon.StandardLibraries
|
||||||
{
|
{
|
||||||
|
@ -6,13 +7,20 @@ namespace Upsilon.StandardLibraries
|
||||||
public class ScriptFunctionAttribute : Attribute
|
public class ScriptFunctionAttribute : Attribute
|
||||||
{
|
{
|
||||||
public ScriptFunctionAttribute(string name, string comment = null,
|
public ScriptFunctionAttribute(string name, string comment = null,
|
||||||
bool directScriptManipulation = false, bool passScriptReference = false, bool passScopeReference = false)
|
bool directScriptManipulation = false, bool passScriptReference = false, bool passScopeReference = false,
|
||||||
|
Type overrideReturnType = null, string overrideReturnMethod = null)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Comment = comment;
|
Comment = comment;
|
||||||
DirectScriptManipulation = directScriptManipulation;
|
DirectScriptManipulation = directScriptManipulation;
|
||||||
PassScriptReference = passScriptReference;
|
PassScriptReference = passScriptReference;
|
||||||
PassScopeReference = passScopeReference;
|
PassScopeReference = passScopeReference;
|
||||||
|
if (overrideReturnType != null && overrideReturnMethod != null)
|
||||||
|
{
|
||||||
|
var method = overrideReturnType.GetMethod(overrideReturnMethod,
|
||||||
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
OverrideReturnType = method;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
@ -20,5 +28,6 @@ namespace Upsilon.StandardLibraries
|
||||||
public bool DirectScriptManipulation { get; }
|
public bool DirectScriptManipulation { get; }
|
||||||
public bool PassScriptReference { get; }
|
public bool PassScriptReference { get; }
|
||||||
public bool PassScopeReference { get; }
|
public bool PassScopeReference { get; }
|
||||||
|
public MethodInfo OverrideReturnType { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -65,7 +65,7 @@ namespace Upsilon.StandardLibraries
|
||||||
var derivedType = DeriveValidTypes(typeInfo.Type);
|
var derivedType = DeriveValidTypes(typeInfo.Type);
|
||||||
return new InternalFunctionVariableSymbol.InternalFunctionParameter(func.Key, derivedType,
|
return new InternalFunctionVariableSymbol.InternalFunctionParameter(func.Key, derivedType,
|
||||||
typeInfo.IsOptional);
|
typeInfo.IsOptional);
|
||||||
}).ToArray())
|
}).ToArray(), func.Value.MethodInfoFunction.Method.GetMethods()[0].Attribute.OverrideReturnType)
|
||||||
{
|
{
|
||||||
CommentValue = func.Value.CommentValue?.Split('\n')
|
CommentValue = func.Value.CommentValue?.Split('\n')
|
||||||
};
|
};
|
||||||
|
@ -128,7 +128,7 @@ namespace Upsilon.StandardLibraries
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = genericParameters[genericParameters.Length - 1].GetScriptType();
|
var result = genericParameters[genericParameters.Length - 1].GetScriptType();
|
||||||
return new InternalFunctionVariableSymbol(name, true, result, parameters.ToArray());
|
return new InternalFunctionVariableSymbol(name, true, result, parameters.ToArray(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VariableSymbol BuildActionVariableSymbol(string name, System.Type type)
|
private static VariableSymbol BuildActionVariableSymbol(string name, System.Type type)
|
||||||
|
@ -136,10 +136,10 @@ namespace Upsilon.StandardLibraries
|
||||||
var genericParameters = type.GetGenericArguments();
|
var genericParameters = type.GetGenericArguments();
|
||||||
return new InternalFunctionVariableSymbol(name, true, Type.Nil,
|
return new InternalFunctionVariableSymbol(name, true, Type.Nil,
|
||||||
genericParameters.Select(DeriveValidTypes).Select(t =>
|
genericParameters.Select(DeriveValidTypes).Select(t =>
|
||||||
new InternalFunctionVariableSymbol.InternalFunctionParameter(name, t, false)).ToArray());
|
new InternalFunctionVariableSymbol.InternalFunctionParameter(name, t, false)).ToArray(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type DeriveValidTypes(System.Type type)
|
public static TypeContainer DeriveValidTypes(System.Type type)
|
||||||
{
|
{
|
||||||
if (type.IsEnum)
|
if (type.IsEnum)
|
||||||
return Type.UserData | Type.Number;
|
return Type.UserData | Type.Number;
|
||||||
|
|
|
@ -29,9 +29,7 @@ namespace Upsilon.Text
|
||||||
{
|
{
|
||||||
if (StartLine == EndLine && linePosition == StartLine)
|
if (StartLine == EndLine && linePosition == StartLine)
|
||||||
{
|
{
|
||||||
if (characterPosition >= StartPosition && characterPosition <= EndPosition)
|
return characterPosition >= StartPosition && characterPosition <= EndPosition;
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (StartLine == linePosition && StartPosition <= characterPosition) return true;
|
if (StartLine == linePosition && StartPosition <= characterPosition) return true;
|
||||||
if (StartLine < linePosition && EndLine > linePosition) return true;
|
if (StartLine < linePosition && EndLine > linePosition) return true;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Upsilon;
|
using Upsilon;
|
||||||
|
using Upsilon.BaseTypes;
|
||||||
using Upsilon.Evaluator;
|
using Upsilon.Evaluator;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
@ -98,5 +99,21 @@ return value
|
||||||
var actual = Executor.EvaluateScript<long>(input, Options);
|
var actual = Executor.EvaluateScript<long>(input, Options);
|
||||||
Assert.Equal(6, actual);
|
Assert.Equal(6, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GenericForLoopValueTypeBindTest()
|
||||||
|
{
|
||||||
|
const string input = @"
|
||||||
|
arr = {100, 56, 28}
|
||||||
|
for key, val in ipairs(arr) do
|
||||||
|
a = val
|
||||||
|
break
|
||||||
|
end
|
||||||
|
";
|
||||||
|
var script = Executor.ParseInputAndEvaluate(input, Options);
|
||||||
|
Assert.True(script.Bind().Scope.TryGetVariable("a", true, out var variable));
|
||||||
|
Assert.Equal(Type.Number, variable.TypeContainer.Type);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue