using System.Collections; using System.Collections.Generic; using Upsilon.BaseTypes.Number; using Upsilon.Binder.VariableSymbols; using Upsilon.Evaluator; using Upsilon.Text; namespace Upsilon.Binder { public class BoundNumericForStatement : BoundStatement { public VariableSymbol Variable { get; } public BoundExpression BoundStart { get; } public BoundExpression BoundStop { get; } public BoundExpression BoundStep { get; } public BoundBlockStatement Block { get; } public BoundNumericForStatement(VariableSymbol variable, BoundExpression boundStart, BoundExpression boundStop, BoundExpression boundStep, BoundBlockStatement block, TextSpan span) : base(span) { Variable = variable; BoundStart = boundStart; BoundStop = boundStop; BoundStep = boundStep; Block = block; } public override BoundKind Kind => BoundKind.BoundNumericForStatement; public override IEnumerable GetChildren() { yield return BoundStart; yield return BoundStop; yield return BoundStep; 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, }; var startVal = (ScriptNumberLong) BoundStart.Evaluate(innerScope, diagnostics, ref innerState); innerScope.CreateLocal(Variable, startVal); var stopVal = (ScriptNumberLong)BoundStop.Evaluate(innerScope, diagnostics, ref innerState); long step = 1; if (BoundStep != null) { var stepVal = (ScriptNumberLong) BoundStep.Evaluate(innerScope, diagnostics, ref innerState); step = stepVal.Value; } if (step > 0) { for (; startVal.Value <= stopVal.Value; startVal.Value = startVal.Value + step) { Block.Evaluate(innerScope, diagnostics, ref innerState); if (innerState.HasBroken) break; if (innerState.Returned) { outerState.Returned = true; outerState.ReturnValue = innerState.ReturnValue; return; } } } else if (step < 0) { for (; startVal.Value >= stopVal.Value; startVal.Value = startVal.Value + step) { Block.Evaluate(innerScope, diagnostics, ref innerState); if (innerState.HasBroken) break; if (innerState.Returned) { outerState.Returned = true; outerState.ReturnValue = innerState.ReturnValue; return; } } } } internal override IEnumerator EvaluateCoroutine(EvaluationScope outerScope, Diagnostics diagnostics, EvaluationState outerState) { var innerScope = new EvaluationScope(outerScope); var innerState = new EvaluationState() { Script = outerState.Script, }; var startVal = (ScriptNumberLong) BoundStart.Evaluate(innerScope, diagnostics, ref innerState); innerScope.CreateLocal(Variable, startVal); var stopVal = (ScriptNumberLong)BoundStop.Evaluate(innerScope, diagnostics, ref innerState); long step = 1; if (BoundStep != null) { var stepVal = (ScriptNumberLong) BoundStep.Evaluate(innerScope, diagnostics, ref innerState); step = stepVal.Value; } if (step > 0) { for (; startVal.Value <= stopVal.Value; startVal.Value = startVal.Value + step) { var coroutine = Block.EvaluateCoroutine(innerScope, diagnostics, innerState); while (coroutine.MoveNext()) { yield return coroutine.Current; } if (innerState.HasBroken) break; if (innerState.Returned) { outerState.Returned = true; outerState.ReturnValue = innerState.ReturnValue; yield break; } } } else if (step < 0) { for (; startVal.Value >= stopVal.Value; startVal.Value = startVal.Value + step) { var coroutine = Block.EvaluateCoroutine(innerScope, diagnostics, innerState); while (coroutine.MoveNext()) { yield return coroutine.Current; } if (innerState.HasBroken) break; if (innerState.Returned) { outerState.Returned = true; outerState.ReturnValue = innerState.ReturnValue; yield break; } } } } } }