Upsilon/Upsilon/Binder/BoundStatements/BoundWhileStatement.cs

82 lines
2.6 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Upsilon.BaseTypes;
using Upsilon.Evaluator;
using Upsilon.Text;
namespace Upsilon.Binder
{
internal class BoundWhileStatement : BoundStatement
{
public BoundExpression Condition { get; }
public BoundStatement Block { get; }
public BoundWhileStatement(BoundExpression condition, BoundStatement block, TextSpan eSpan)
:base(eSpan)
{
Condition = condition;
Block = block;
}
public override BoundKind Kind => BoundKind.BoundWhileStatement;
public override IEnumerable<BoundNode> GetChildren()
{
yield return Condition;
yield return Block;
}
internal override void Evaluate(EvaluationScope outerScope, Diagnostics diagnostics, ref EvaluationState outerState)
{
var innerScope = new EvaluationScope(outerScope);
var innerState = new EvaluationState()
{
Script = outerState.Script
};
while ((ScriptBoolean) Condition.Evaluate(innerScope, diagnostics, ref innerState))
{
Block.Evaluate(innerScope, diagnostics, ref innerState);
if (innerState.HasBroken || innerState.Returned)
{
if (innerState.Returned)
{
outerState.Returned = true;
outerState.ReturnValue = innerState.ReturnValue;
}
break;
}
}
}
internal override IEnumerator EvaluateCoroutine(EvaluationScope outerScope, Diagnostics diagnostics, EvaluationState outerState)
{
var innerScope = new EvaluationScope(outerScope);
var innerState = new EvaluationState()
{
Script = outerState.Script
};
while ((ScriptBoolean) Condition.Evaluate(innerScope, diagnostics, ref innerState))
{
var coroutine = Block.EvaluateCoroutine(innerScope, diagnostics, innerState);
while (coroutine.MoveNext())
{
yield return coroutine.Current;
}
if (innerState.HasBroken || innerState.Returned)
{
if (innerState.Returned)
{
outerState.Returned = true;
outerState.ReturnValue = innerState.ReturnValue;
}
break;
}
}
}
}
}