private void CheckForItemInRangeLoop(ForStatement node)
{
MethodInvocationExpression mi = node.Iterator as MethodInvocationExpression;
if (null == mi) return;
if (!IsRangeInvocation(mi)) return;
DeclarationCollection declarations = node.Declarations;
if (declarations.Count != 1) return;
ExpressionCollection args = mi.Arguments;
Block body = new Block(node.LexicalInfo);
Expression min;
Expression max;
Expression step;
if (args.Count == 1)
{
min = CodeBuilder.CreateIntegerLiteral(0);
max = args[0];
step = CodeBuilder.CreateIntegerLiteral(1);
}
else if (args.Count == 2)
{
min = args[0];
max = args[1];
step = CodeBuilder.CreateIntegerLiteral(1);
}
else
{
min = args[0];
max = args[1];
step = args[2];
}
InternalLocal numVar = CodeBuilder.DeclareTempLocal(
_currentMethod,
TypeSystemServices.IntType);
Expression numRef = CodeBuilder.CreateReference(numVar);
// __num = <min>
body.Add(
CodeBuilder.CreateAssignment(
numRef,
min));
Expression endRef;
if (max.NodeType == NodeType.IntegerLiteralExpression)
{
endRef = max;
}
else
{
InternalLocal endVar = CodeBuilder.DeclareTempLocal(
_currentMethod,
TypeSystemServices.IntType);
endRef = CodeBuilder.CreateReference(endVar);
// __end = <end>
body.Add(
CodeBuilder.CreateAssignment(
endRef,
max));
}
if (args.Count == 1)
{
if (max.NodeType == NodeType.IntegerLiteralExpression)
{
if (((IntegerLiteralExpression)max).Value < 0)
{
// raise ArgumentOutOfRangeException("max") (if <max> < 0)
Statement statement = CodeBuilder.RaiseException(
body.LexicalInfo,
TypeSystemServices.Map(System_ArgumentOutOfRangeException_ctor),
CodeBuilder.CreateStringLiteral("max"));
body.Add(statement);
}
}
else
{
IfStatement ifStatement = new IfStatement(body.LexicalInfo);
ifStatement.TrueBlock = new Block();
// raise ArgumentOutOfRangeException("max") if __end < 0
Statement statement = CodeBuilder.RaiseException(
body.LexicalInfo,
TypeSystemServices.Map(System_ArgumentOutOfRangeException_ctor),
CodeBuilder.CreateStringLiteral("max"));
ifStatement.Condition = CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.LessThan,
endRef,
CodeBuilder.CreateIntegerLiteral(0));
ifStatement.TrueBlock.Add(statement);
body.Add(ifStatement);
}
}
Expression stepRef;
switch (args.Count)
{
case 1:
stepRef = CodeBuilder.CreateIntegerLiteral(1);
break;
case 2:
if ((min.NodeType == NodeType.IntegerLiteralExpression) &&
(max.NodeType == NodeType.IntegerLiteralExpression) &&
(((IntegerLiteralExpression)max).Value < ((IntegerLiteralExpression)min).Value))
{
// __step = -1
stepRef = CodeBuilder.CreateIntegerLiteral(-1);
}
else if ((min.NodeType == NodeType.IntegerLiteralExpression) &&
(max.NodeType == NodeType.IntegerLiteralExpression))
{
// __step = 1
stepRef = CodeBuilder.CreateIntegerLiteral(1);
}
else
{
InternalLocal stepVar = CodeBuilder.DeclareTempLocal(
_currentMethod,
TypeSystemServices.IntType);
stepRef = CodeBuilder.CreateReference(stepVar);
// __step = 1
body.Add(
CodeBuilder.CreateAssignment(
stepRef,
CodeBuilder.CreateIntegerLiteral(1)));
// __step = -1 if __end < __num
IfStatement ifStatement = new IfStatement(node.LexicalInfo);
ifStatement.Condition = CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.LessThan,
endRef,
numRef);
ifStatement.TrueBlock = new Block();
ifStatement.TrueBlock.Add(
CodeBuilder.CreateAssignment(
stepRef,
CodeBuilder.CreateIntegerLiteral(-1)));
body.Add(ifStatement);
}
break;
default:
if (step.NodeType == NodeType.IntegerLiteralExpression)
{
stepRef = step;
}
else
{
InternalLocal stepVar = CodeBuilder.DeclareTempLocal(
_currentMethod,
TypeSystemServices.IntType);
stepRef = CodeBuilder.CreateReference(stepVar);
// __step = <step>
body.Add(
CodeBuilder.CreateAssignment(
stepRef,
step));
}
break;
}
if (args.Count == 3)
{
Expression condition = null;
bool run = false;
if (step.NodeType == NodeType.IntegerLiteralExpression)
{
if (((IntegerLiteralExpression)step).Value < 0)
{
if ((max.NodeType == NodeType.IntegerLiteralExpression) &&
(min.NodeType == NodeType.IntegerLiteralExpression))
{
run = (((IntegerLiteralExpression)max).Value > ((IntegerLiteralExpression)min).Value);
}
else
{
condition = CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.GreaterThan,
endRef,
numRef);
}
}
else
{
if ((max.NodeType == NodeType.IntegerLiteralExpression) &&
(min.NodeType == NodeType.IntegerLiteralExpression))
{
run = (((IntegerLiteralExpression)max).Value < ((IntegerLiteralExpression)min).Value);
}
else
{
condition = CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.LessThan,
endRef,
numRef);
}
}
}
else
{
if ((max.NodeType == NodeType.IntegerLiteralExpression) &&
(min.NodeType == NodeType.IntegerLiteralExpression))
{
if (((IntegerLiteralExpression)max).Value < ((IntegerLiteralExpression)min).Value)
{
condition = CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.GreaterThan,
stepRef,
CodeBuilder.CreateIntegerLiteral(0));
}
else
{
condition = CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.LessThan,
stepRef,
CodeBuilder.CreateIntegerLiteral(0));
}
}
else
{
condition = CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.Or,
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.And,
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.LessThan,
stepRef,
CodeBuilder.CreateIntegerLiteral(0)),
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.GreaterThan,
endRef,
numRef)),
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.And,
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.GreaterThan,
stepRef,
CodeBuilder.CreateIntegerLiteral(0)),
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
BinaryOperatorType.LessThan,
endRef,
numRef)));
}
}
// raise ArgumentOutOfRangeException("step") if (__step < 0 and __end > __begin) or (__step > 0 and __end < __begin)
Statement statement = CodeBuilder.RaiseException(
body.LexicalInfo,
TypeSystemServices.Map(System_ArgumentOutOfRangeException_ctor),
CodeBuilder.CreateStringLiteral("step"));
if (condition != null)
{
IfStatement ifStatement = new IfStatement(body.LexicalInfo);
ifStatement.TrueBlock = new Block();
ifStatement.Condition = condition;
ifStatement.TrueBlock.Add(statement);
body.Add(ifStatement);
}
else if (run)
{
body.Add(statement);
}
// __end = __num + __step * cast(int, Math.Ceiling((__end - __num)/cast(double, __step)))
if ((step.NodeType == NodeType.IntegerLiteralExpression) &&
(max.NodeType == NodeType.IntegerLiteralExpression) &&
(min.NodeType == NodeType.IntegerLiteralExpression))
{
int stepVal = (int)((IntegerLiteralExpression)step).Value;
int maxVal = (int)((IntegerLiteralExpression)max).Value;
int minVal = (int)((IntegerLiteralExpression)min).Value;
endRef = CodeBuilder.CreateIntegerLiteral(
minVal + stepVal * (int)System.Math.Ceiling((maxVal - minVal) / ((double)stepVal)));
}
else
{
Expression endBak = endRef;
if (max.NodeType == NodeType.IntegerLiteralExpression)
{
InternalLocal endVar = CodeBuilder.DeclareTempLocal(
_currentMethod,
TypeSystemServices.IntType);
endRef = CodeBuilder.CreateReference(endVar);
}
body.Add(
CodeBuilder.CreateAssignment(
endRef,
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.IntType,
BinaryOperatorType.Addition,
numRef,
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.IntType,
BinaryOperatorType.Multiply,
stepRef,
CodeBuilder.CreateCast(
TypeSystemServices.IntType,
CodeBuilder.CreateMethodInvocation(
TypeSystemServices.Map(System_Math_Ceiling),
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.DoubleType,
BinaryOperatorType.Division,
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.IntType,
BinaryOperatorType.Subtraction,
endBak,
numRef),
CodeBuilder.CreateCast(
TypeSystemServices.DoubleType,
stepRef))))))));
}
}
// while __num != __end:
WhileStatement ws = new WhileStatement(node.LexicalInfo);
BinaryOperatorType op = BinaryOperatorType.Inequality;
if (stepRef.NodeType == NodeType.IntegerLiteralExpression)
{
if (((IntegerLiteralExpression)stepRef).Value > 0)
{
op = BinaryOperatorType.LessThan;
}
else
{
op = BinaryOperatorType.GreaterThan;
}
}
ws.Condition = CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.BoolType,
op,
numRef,
endRef);
ws.Condition.LexicalInfo = node.LexicalInfo;
// item = __num
ws.Block.Add(
CodeBuilder.CreateAssignment(
CodeBuilder.CreateReference((InternalLocal)declarations[0].Entity),
numRef));
Block rawBlock = new Block();
rawBlock["checked"] = false;
// __num += __step
rawBlock.Add(
CodeBuilder.CreateAssignment(
numRef,
CodeBuilder.CreateBoundBinaryExpression(
TypeSystemServices.IntType,
BinaryOperatorType.Addition,
numRef,
stepRef)));
ws.Block.Add(rawBlock as Statement);
// <block>
ws.Block.Add(node.Block);
ws.OrBlock = node.OrBlock;
ws.ThenBlock = node.ThenBlock;
body.Add(ws);
ReplaceCurrentNode(body);
}