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 public abstract class ScriptFunction : ScriptType
{ {
protected ScriptFunction(bool isCoroutine)
{
IsCoroutine = isCoroutine;
}
public override TypeContainer Type => BaseTypes.Type.Function; public override TypeContainer Type => BaseTypes.Type.Function;
public override object ToCSharpObject() public override object ToCSharpObject()
{ {
@ -17,6 +22,8 @@ namespace Upsilon.BaseTypes.ScriptFunction
return null; return null;
} }
public bool IsCoroutine { get; }
public abstract ScriptType Run(Diagnostics diagnostics, ScriptType[] variables, Script script, EvaluationScope scope, TextSpan span); 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); 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 class ScriptMethodInfoFunction : ScriptFunction
{ {
public ScriptMethodInfoFunction(UserDataMethod method, object o, bool directTypeManipulation, 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; Method = method;
_object = o; _object = o;

View File

@ -16,7 +16,7 @@ namespace Upsilon.BaseTypes.ScriptFunction
{ {
public List<ScriptRuntimeFunctionOption> Options { get; } public List<ScriptRuntimeFunctionOption> Options { get; }
public ScriptRuntimeFunction(List<ScriptRuntimeFunctionOption> options) public ScriptRuntimeFunction(List<ScriptRuntimeFunctionOption> options, bool isCoroutine) : base(isCoroutine)
{ {
Options = options; 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) if (parameterType.GetScriptType() != BaseTypes.Type.Table)
{ {

View File

@ -1,3 +1,4 @@
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
@ -77,7 +78,8 @@ namespace Upsilon.BaseTypes.UserData
} }
if (Methods.TryGetValue(member, out var method)) 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}'."); return (null, true, $"Can't find public member '{member}' on type '{Type}'.");

View File

@ -691,7 +691,8 @@ namespace Upsilon.Binder
} }
else 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); _unboundFunctions.Add(unbound);
return unbound; return unbound;
} }

View File

@ -40,7 +40,8 @@ namespace Upsilon.Binder
internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state) internal override ScriptType Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state)
{ {
var option = new ScriptRuntimeFunction.ScriptRuntimeFunctionOption(Parameters, Block, scope); 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; 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); 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); var ls = new List<ScriptType>();
ls.Add(evaluate); 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); var value = Expression.Evaluate(scope, diagnostics, ref state);
yield return value; yield return value;

View File

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

View File

@ -91,6 +91,11 @@ namespace Upsilon.Evaluator
throw new ArgumentException(($"Function '{functionName}' could not be found")); throw new ArgumentException(($"Function '{functionName}' could not be found"));
} }
var function = (ScriptRuntimeFunction) statement; 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); var option = function.GetValidOption(parameters);
if (option == null) if (option == null)
{ {