/// <summary>
/// Finds variables that were assigned to and determines their types.
/// </summary>
/// <param name="root"> The root of the abstract syntax tree to search. </param>
/// <param name="variableTypes"> A dictionary containing the variables that were assigned to. </param>
private Dictionary <Scope.DeclaredVariable, InferredTypeInfo> FindTypedVariables()
{
var result = new Dictionary <Scope.DeclaredVariable, InferredTypeInfo>();
// Special case for the common case of an incrementing or decrementing loop variable.
// The loop must be one of the following forms:
// for (var i = <int>; i < <int>; i ++)
// for (var i = <int>; i < <int>; ++ i)
// for (var i = <int>; i > <int>; i --)
// for (var i = <int>; i > <int>; -- i)
// for (i = <int>; i < <int>; i ++)
// for (i = <int>; i < <int>; ++ i)
// for (i = <int>; i > <int>; i --)
// for (i = <int>; i > <int>; -- i)
Scope loopVariableScope = null;
string loopVariableName = null;
// First, check the init statement.
bool initIsOkay = false;
if (this.InitVarStatement != null &&
this.InitVarStatement.Declarations.Count == 1 &&
this.InitVarStatement.Declarations[0].InitExpression != null &&
this.InitVarStatement.Declarations[0].InitExpression.ResultType == PrimitiveType.Int32)
{
// for (var i = <int>; ?; ?)
loopVariableScope = this.InitVarStatement.Scope;
loopVariableName = this.InitVarStatement.Declarations[0].VariableName;
initIsOkay = loopVariableScope is DeclarativeScope && loopVariableScope.HasDeclaredVariable(loopVariableName) == true;
}
else if (this.InitExpression != null &&
this.InitExpression is AssignmentExpression &&
((AssignmentExpression)this.InitExpression).ResultType == PrimitiveType.Int32 &&
((AssignmentExpression)this.InitExpression).Target is NameExpression)
{
// for (i = <int>; ?; ?)
loopVariableScope = ((NameExpression)((AssignmentExpression)this.InitExpression).Target).Scope;
loopVariableName = ((NameExpression)((AssignmentExpression)this.InitExpression).Target).Name;
initIsOkay = loopVariableScope is DeclarativeScope && loopVariableScope.HasDeclaredVariable(loopVariableName) == true;
}
// Next, check the condition expression.
bool conditionAndInitIsOkay = false;
bool lessThan = true;
if (initIsOkay == true &&
this.ConditionStatement != null &&
this.Condition is BinaryExpression &&
(((BinaryExpression)this.Condition).OperatorType == OperatorType.LessThan ||
((BinaryExpression)this.Condition).OperatorType == OperatorType.GreaterThan) &&
((BinaryExpression)this.Condition).Left is NameExpression &&
((NameExpression)((BinaryExpression)this.Condition).Left).Name == loopVariableName &&
((BinaryExpression)this.Condition).Right.ResultType == PrimitiveType.Int32)
{
// for (?; i < <int>; ?)
// for (?; i > <int>; ?)
lessThan = ((BinaryExpression)this.Condition).OperatorType == OperatorType.LessThan;
conditionAndInitIsOkay = true;
}
// Next, check the increment expression.
bool everythingIsOkay = false;
if (conditionAndInitIsOkay == true)
{
if (lessThan == true &&
this.IncrementStatement != null &&
this.Increment is AssignmentExpression &&
(((AssignmentExpression)this.Increment).OperatorType == OperatorType.PostIncrement ||
((AssignmentExpression)this.Increment).OperatorType == OperatorType.PreIncrement) &&
((NameExpression)((AssignmentExpression)this.Increment).Target).Name == loopVariableName)
{
// for (?; i < <int>; i ++)
// for (?; i < <int>; ++ i)
everythingIsOkay = true;
}
else if (lessThan == false &&
this.IncrementStatement != null &&
this.Increment is AssignmentExpression &&
(((AssignmentExpression)this.Increment).OperatorType == OperatorType.PostDecrement ||
((AssignmentExpression)this.Increment).OperatorType == OperatorType.PreDecrement) &&
((NameExpression)((AssignmentExpression)this.Increment).Target).Name == loopVariableName)
{
// for (?; i > <int>; i --)
// for (?; i > <int>; -- i)
everythingIsOkay = true;
}
}
bool continueEncountered = false;
if (everythingIsOkay == true)
{
// The loop variable can be optimized to an integer.
var variable = loopVariableScope.GetDeclaredVariable(loopVariableName);
if (variable != null)
{
result.Add(variable, new InferredTypeInfo()
{
Type = PrimitiveType.Int32, Conditional = false
});
}
FindTypedVariables(this.Body, result, conditional: false, continueEncountered: ref continueEncountered);
}
else
{
// Unoptimized.
FindTypedVariables(this, result, conditional: false, continueEncountered: ref continueEncountered);
}
return(result);
}