CiMaybeAssign Coerce(CiMaybeAssign expr, CiType expected)
{
CiType got = expr.Type;
if (expected.Equals(got))
{
return(expr);
}
if (expected == CiIntType.Value && got == CiByteType.Value)
{
CiConstExpr konst = expr as CiConstExpr;
if (konst != null)
{
return(new CiConstExpr((object)(int)(byte)konst.Value));
}
CiCondExpr cond = expr as CiCondExpr;
if (cond != null && (cond.OnTrue is CiConstExpr || cond.OnFalse is CiConstExpr))
{
// avoid ((foo ? 1 : 0) & 0xff) in Java
return(Coerce(cond, expected));
}
if (expr is CiArrayAccess)
{
CiConstAccess ca = ((CiArrayAccess)expr).Array as CiConstAccess;
if (ca != null && ca.Const.Is7Bit)
{
return(expr);
}
}
return(new CiCoercion {
ResultType = expected, Inner = expr
});
}
if (expected == CiByteType.Value && got == CiIntType.Value)
{
CiConstExpr konst = expr as CiConstExpr;
if (konst != null)
{
return(new CiConstExpr((object)(byte)(int)konst.Value));
}
return(new CiCoercion {
ResultType = expected, Inner = expr
});
}
if (expected == CiStringPtrType.Value && (got == CiType.Null || got is CiStringType))
{
return(expr);
}
if (expected is CiStringStorageType && got is CiStringType)
{
return(expr);
}
if (expected is CiClassType)
{
if (got == CiType.Null)
{
return(expr);
}
if (Extends(got, ((CiClassType)expected).Class))
{
if (expr is CiCondExpr)
{
// C doesn't like &(cond ? foo : bar)
return(Coerce((CiCondExpr)expr, expected));
}
return(new CiCoercion {
ResultType = expected, Inner = expr
});
}
}
if (expected is CiArrayPtrType)
{
if (got == CiType.Null)
{
return(expr);
}
CiArrayType gotArray = got as CiArrayType;
if (got != null && ((CiArrayPtrType)expected).ElementType.Equals(gotArray.ElementType))
{
return new CiCoercion {
ResultType = expected, Inner = expr
}
}
;
}
throw new ResolveException("Expected {0}, got {1}", expected, got);
}
CiExpr Coerce(CiExpr expr, CiType expected)
{
return((CiExpr)Coerce((CiMaybeAssign)expr, expected));
}
object ResolveConstExpr(CiExpr expr, CiType type)
{
expr = Coerce(Resolve(expr), type);
CiConstExpr ce = expr as CiConstExpr;
if (ce == null)
{
throw new ResolveException("{0} is not constant", expr);
}
return(ce.Value);
}
object ResolveConstInitializer(ref CiType type, object value)
{
if (type is CiArrayType)
{
object[] array = value as object[];
if (array == null)
{
return(value);
}
CiType elementType = ((CiArrayType)type).ElementType;
if (type is CiArrayStorageType)
{
int expected = ((CiArrayStorageType)type).Length;
if (array.Length != expected)
{
throw new ResolveException("Expected {0} array elements, got {1}", expected, array.Length);
}
}
else
{
type = new CiArrayStorageType {
ElementType = elementType, Length = array.Length
};
}
Array dest = Array.CreateInstance(elementType.DotNetType, array.Length);
for (int i = 0; i < array.Length; i++)
{
dest.SetValue(ResolveConstInitializer(ref elementType, array[i]), i);
}
return(dest);
}
if (value is CiExpr)
{
return(ResolveConstExpr((CiExpr)value, type));
}
return(value);
}
void ICiSymbolVisitor.Visit(CiEnum enu)
{
}