Make coroutine functions be forced to be created with the coroutine keyword.

This commit is contained in:
Deukhoofd 2019-02-14 12:42:47 +01:00
parent dbf4d8a82e
commit 8da35b4e71
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
9 changed files with 38 additions and 18 deletions

View File

@ -6,6 +6,11 @@ namespace Upsilon.BaseTypes.ScriptFunction
{
public abstract class ScriptFunction : ScriptType
{
protected ScriptFunction(bool isCoroutine)
{
IsCoroutine = isCoroutine;
}
public override TypeContainer Type => BaseTypes.Type.Function;
public override object ToCSharpObject()
{
@ -17,6 +22,8 @@ namespace Upsilon.BaseTypes.ScriptFunction
return null;
}
public bool IsCoroutine { get; }
public abstract ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span);
public abstract IEnumerator RunCoroutine(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span);
}

View File

@ -14,7 +14,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
public class ScriptMethodInfoFunction : ScriptFunction
{
public ScriptMethodInfoFunction(UserDataMethod method, object o, bool directTypeManipulation,
bool passScriptReference = false, bool passScopeReference = false)
bool isCoroutine, bool passScriptReference = false, bool passScopeReference = false) : base(isCoroutine)
{
Method = method;
_object = o;

View File

@ -16,7 +16,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
{
public List<ScriptRuntimeFunctionOption> Options { get; }
public ScriptRuntimeFunction(List<ScriptRuntimeFunctionOption> options)
public ScriptRuntimeFunction(List<ScriptRuntimeFunctionOption> options, bool isCoroutine) : base(isCoroutine)
{
Options = options;
}
@ -95,7 +95,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
}
}
}
else if (parameter.VariableSymbol is TableVariableSymbol tableVariableSymbol)
else if (parameter.VariableSymbol is TableVariableSymbol)
{
if (parameterType.GetScriptType() != BaseTypes.Type.Table)
{

View File

@ -1,3 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@ -77,7 +78,8 @@ namespace Upsilon.BaseTypes.UserData
}
if (Methods.TryGetValue(member, out var method))
{
return (new ScriptMethodInfoFunction(method, value, false), false, null);
var isCoroutine = typeof(IEnumerator).IsAssignableFrom(method.ReturnType);
return (new ScriptMethodInfoFunction(method, value, false, isCoroutine), false, null);
}
return (null, true, $"Can't find public member '{member}' on type '{Type}'.");

View File

@ -691,7 +691,8 @@ namespace Upsilon.Binder
}
else
{
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block, e.Span, innerScope, functionVariableSymbol);
var unbound = new UnboundFunctionExpression(parameters.ToImmutable(), e.Block, e.Span, innerScope,
functionVariableSymbol, e.IsCoroutine);
_unboundFunctions.Add(unbound);
return unbound;
}

View File

@ -40,7 +40,8 @@ namespace Upsilon.Binder
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
{
var option = new ScriptRuntimeFunction.ScriptRuntimeFunctionOption(Parameters, Block, scope);
var func = new ScriptRuntimeFunction(new List<ScriptRuntimeFunction.ScriptRuntimeFunctionOption>(){option});
var func = new ScriptRuntimeFunction(new List<ScriptRuntimeFunction.ScriptRuntimeFunctionOption>() {option},
IsCoroutine);
return func;
}

View File

@ -42,18 +42,22 @@ namespace Upsilon.Binder
{
throw new EvaluationException(state.Script.FileName, $"Variable is not a function.", functionCall.Identifier.Span);
}
var ls = new List<ScriptType>();
foreach (var t in functionCall.Parameters)
if (function.IsCoroutine)
{
var evaluate = t.Evaluate(scope, diagnostics, ref state);
ls.Add(evaluate);
var ls = new List<ScriptType>();
foreach (var t in functionCall.Parameters)
{
var evaluate = t.Evaluate(scope, diagnostics, ref state);
ls.Add(evaluate);
}
var coroutine = function.RunCoroutine(diagnostics, ls.ToArray(), state.Script, scope, Span);
while (coroutine.MoveNext())
{
yield return coroutine.Current;
}
yield break;
}
var coroutine = function.RunCoroutine(diagnostics, ls.ToArray(), state.Script, scope, Span);
while (coroutine.MoveNext())
{
yield return coroutine.Current;
}
yield break;
}
var value = Expression.Evaluate(scope, diagnostics, ref state);
yield return value;

View File

@ -9,8 +9,8 @@ namespace Upsilon.Binder
public class UnboundFunctionExpression : BoundFunctionExpression
{
public UnboundFunctionExpression(ImmutableArray<BoundVariableSymbol> parameters,
BlockStatementSyntax unboundBlock, TextSpan span, BoundScope scope, string name)
: base(parameters, null, span, scope, BaseTypes.Type.Unknown, false)
BlockStatementSyntax unboundBlock, TextSpan span, BoundScope scope, string name, bool isCoroutine)
: base(parameters, null, span, scope, BaseTypes.Type.Unknown, isCoroutine)
{
UnboundBlock = unboundBlock;
Name = name;

View File

@ -91,6 +91,11 @@ namespace Upsilon.Evaluator
throw new ArgumentException(($"Function '{functionName}' could not be found"));
}
var function = (ScriptRuntimeFunction) statement;
if (!function.IsCoroutine)
{
throw new EvaluationException(_script.FileName,
$"Function with name '{functionName}' is not a coroutine, and can't be executed as such.", e.Span);
}
var option = function.GetValidOption(parameters);
if (option == null)
{