using System; using System.Collections; using System.Collections.Generic; using Upsilon.BaseTypes; using Upsilon.BaseTypes.ScriptFunction; using Upsilon.Evaluator; using Upsilon.Exceptions; using Upsilon.Text; using Type = Upsilon.BaseTypes.Type; namespace Upsilon.Binder { public class BoundYieldStatement : BoundStatement { public BoundExpression Expression { get; } public BoundYieldStatement(BoundExpression expression, TextSpan span) : base(span) { Expression = expression; } public override BoundKind Kind => BoundKind.BoundYieldStatement; public override IEnumerable GetChildren() { yield return Expression; } internal override void Evaluate(EvaluationScope scope, Diagnostics diagnostics, ref EvaluationState state) { throw new EvaluationException(state.Script.FileName, "Yielding in a function that's not executed as a coroutine is not possible.", Span); } internal override IEnumerator EvaluateCoroutine(EvaluationScope scope, Diagnostics diagnostics, EvaluationState state) { if (Expression.Kind == BoundKind.BoundFunctionCallExpression) { var functionCall = (BoundFunctionCallExpression) Expression; var variable = functionCall.Identifier.Evaluate(scope, diagnostics, ref state); if (!(variable is ScriptFunction function)) { throw new EvaluationException(state.Script.FileName, $"Variable is not a function.", functionCall.Identifier.Span); } if (function.IsCoroutine) { var ls = new List(); foreach (var t in functionCall.Parameters) { var evaluate = t.Evaluate(scope, diagnostics, ref state); ls.Add(evaluate); } var coroutine = function.RunCoroutine(diagnostics, ls.ToArray(), scope, Span, state); while (coroutine.MoveNext()) { yield return coroutine.Current; } yield break; } } var value = Expression.Evaluate(scope, diagnostics, ref state); yield return value; } } }