///
/// <summary>
/// Assigns a value to the specified identifier (field or property).
/// Since any field or property that is a ValueType will not have its
/// value changed without explicitly being set, this method is given the
/// entire list of objects of the lhs chain expression and uses recursion to
/// set them right to left.
/// </summary>
///
/// <example>
/// <c language="C#">x.y.z = 3</c>
/// This will set z = 3, then y = z (the newly changed z), then x = y.
/// If the expression is simply <c language="C#">x = 3</c>, then that is the only assignment
/// performed and all List arguments contain only a single value.
/// </example>
///
/// <param name="envChain">
/// List of CseObjects from the chain expression of the lhs. This makes up the
/// list of environment objects. In the case of x = 3, envChain would contain
/// x's value.
/// </param>
/// <param name="envNames">List of field/property names in the lhs chain expression. In the case of x = 3, envNames would contain "x".</param>
/// <param name="envIndices">
/// List of array indices for each array in the lhs chain expression. For each non-array, the
/// envIndices at that index is null. In the case of x = 3, envIndices would contain null.
/// In the case of x[2] = 3, envIndices would contain 2.
/// </param>
/// <param name="xrhs">Rhs expression</param>
///
/// <returns>xrhs's Value property</returns>
///
/// <exception cref="CseLogicExceptionType.ARRAY_INDEX_NOT_INT" />
/// <exception cref="CseLogicExceptionType.CANT_FIND_IDENT_IN_ENV" />
///
internal static object Assign(List <CseObject> envChain, List <string> envNames, List <CseObject> envIndices, CseObject xrhs)
{
object rhs = (xrhs == null ? null : xrhs.Value);
if (envChain.Count == 0)
{
return(rhs);
}
CseObject env = envChain[envChain.Count - 1];
string envName = envNames[envNames.Count - 1];
CseObject envIndex = envIndices[envIndices.Count - 1];
//Type instanceType = TypeExp.GetTypeObj(env.Value);
Type instanceType = env.ValueType;
// Arrays
if (envIndex != null)
{
MemberInfo member;
ICollection arrMember;
member = instanceType.GetField(envName, defaultFlags | BindingFlags.GetField);
if (member != null)
{
arrMember = (ICollection)((FieldInfo)member).GetValue(env.Value);
}
else
{
member = instanceType.GetProperty(envName, defaultFlags | BindingFlags.GetProperty);
if (member != null)
{
arrMember = (ICollection)((PropertyInfo)member).GetValue(env.Value, null);
}
else
{
throw new CseLogicException(CseLogicExceptionType.CANT_FIND_IDENT_IN_ENV, envName, env.Value.ToString());
}
}
Array arrMemberAsArray = arrMember as Array;
IDictionary arrMemberAsIDict = arrMember as IDictionary;
if (arrMemberAsArray != null)
{
int index;
if (int.TryParse(envIndex.Value.ToString(), out index))
{
arrMemberAsArray.SetValue(rhs, index);
}
else
{
throw new CseLogicException(CseLogicExceptionType.ARRAY_INDEX_NOT_INT);
}
}
else if (arrMemberAsIDict != null)
{
arrMemberAsIDict[envIndex.Value] = rhs;
}
}
// Nonarrays
else
{
if (env == CsEval.EvalEnvironment)
{
CseObject tempLookup = TempIdentifierExp.Lookup(envName);
if (tempLookup != null)
{
TempIdentifierExp.Assign(envName, rhs);
return(tempLookup);
}
}
FieldInfo fieldInfo = instanceType.GetField(envName, defaultFlags | BindingFlags.GetField);
if (fieldInfo != null)
{
fieldInfo.SetValue(env.Value, rhs);
}
else
{
PropertyInfo propertyInfo = instanceType.GetProperty(envName, defaultFlags | BindingFlags.GetProperty);
if (propertyInfo != null)
{
propertyInfo.SetValue(env.Value, rhs, null);
}
else
{
throw new CseLogicException(CseLogicExceptionType.CANT_FIND_IDENT_IN_ENV, envName, env.Value.ToString());
}
}
}
envChain.RemoveAt(envChain.Count - 1);
envNames.RemoveAt(envNames.Count - 1);
envIndices.RemoveAt(envIndices.Count - 1);
return(IdentifierExp.Assign(envChain, envNames, envIndices, env));
}