2019-02-13 17:10:39 +00:00
|
|
|
using System.Collections;
|
2018-11-27 17:38:28 +00:00
|
|
|
using System.Collections.Generic;
|
2019-02-13 15:29:58 +00:00
|
|
|
using Upsilon.BaseTypes.Number;
|
2018-11-30 14:28:36 +00:00
|
|
|
using Upsilon.Binder.VariableSymbols;
|
2019-02-13 15:29:58 +00:00
|
|
|
using Upsilon.Evaluator;
|
2018-11-25 18:30:18 +00:00
|
|
|
using Upsilon.Text;
|
|
|
|
|
2018-11-23 13:38:45 +00:00
|
|
|
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,
|
2018-11-25 18:30:18 +00:00
|
|
|
BoundExpression boundStop, BoundExpression boundStep, BoundBlockStatement block, TextSpan span) : base(span)
|
2018-11-23 13:38:45 +00:00
|
|
|
{
|
|
|
|
Variable = variable;
|
|
|
|
BoundStart = boundStart;
|
|
|
|
BoundStop = boundStop;
|
|
|
|
BoundStep = boundStep;
|
|
|
|
Block = block;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override BoundKind Kind => BoundKind.BoundNumericForStatement;
|
2019-01-17 12:56:53 +00:00
|
|
|
|
|
|
|
public override IEnumerable<BoundNode> GetChildren()
|
|
|
|
{
|
|
|
|
yield return BoundStart;
|
|
|
|
yield return BoundStop;
|
|
|
|
yield return BoundStep;
|
|
|
|
yield return Block;
|
|
|
|
}
|
2019-02-13 15:29:58 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2019-02-13 17:10:39 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-23 13:38:45 +00:00
|
|
|
}
|
|
|
|
}
|