protected internal override void TraverseOperator(Operator op) { op.Args.ForEach(Traverse); // todo. also support nullables and lifted versions of operators op.Args.Any(arg => Types[arg].IsNullable()).AssertFalse(); var impArgs = op.Args; var anyBool = impArgs.Any(arg => Types[arg] == typeof(bool)); if (anyBool) { Types.Add(op, typeof(bool)); return; } var opt = op.OperatorType; if (opt.IsAssign() || opt == OperatorType.Coalesce || opt == OperatorType.LeftShift || opt == OperatorType.RightShift) { Types.Add(op, Types[op.Args.First()]); } else if (opt == OperatorType.AndAlso || opt == OperatorType.OrElse || opt == OperatorType.Not || opt == OperatorType.GreaterThan || opt == OperatorType.GreaterThanOrEqual || opt == OperatorType.Equal || opt == OperatorType.NotEqual || opt == OperatorType.LessThan || opt == OperatorType.LessThanOrEqual) { Types.Add(op, typeof(bool)); } else { if (op.IsUnary()) { var t_target = Types[op.Unary().Target]; if (t_target == null) Types.Add(op, null); else { (t_target.IsInteger() || t_target.IsFloatingPoint()).AssertTrue(); Types.Add(op, t_target); } } else if (op.IsBinary()) { var t_lhs = Types[op.Binary().Lhs]; var t_rhs = Types[op.Binary().Rhs]; if (t_lhs == null || t_rhs == null) Types.Add(op, null); else { if (t_lhs.IsInteger() && t_rhs.IsInteger()) { Func<Type, int> bitness = t => t == typeof(sbyte) || t == typeof(byte) ? 8 : t == typeof(short) || t == typeof(ushort) ? 16 : t == typeof(int) || t == typeof(uint) ? 32 : t == typeof(long) || t == typeof(ulong) ? 64 : ((Func<int>)(() => { throw AssertionHelper.Fail(); }))(); Func<Type, bool> signed = t => t == typeof(sbyte) || t == typeof(short) || t == typeof(int) || t == typeof(long) ? true : t == typeof(byte) || t == typeof(ushort) || t == typeof(uint) || t == typeof(ulong) ? false : ((Func<bool>)(() => { throw AssertionHelper.Fail(); }))(); Func<int, bool, Type> mk_int = (n_bits, is_signed) => { if (n_bits == 8) return is_signed ? typeof(sbyte) : typeof(byte); if (n_bits == 16) return is_signed ? typeof(short) : typeof(ushort); if (n_bits == 32) return is_signed ? typeof(int) : typeof(uint); if (n_bits == 64) return is_signed ? typeof(long) : typeof(ulong); throw AssertionHelper.Fail(); }; // todo. the rules below are specific to C# Func<Type, Type, bool> has_cast_to = (wb, t) => wb == t || bitness(wb) < bitness(t); Func<Type, Type, bool> args_match = (t1, t2) => has_cast_to(t_lhs, t1) && has_cast_to(t_rhs, t2); Type t_result = null; if (args_match(typeof(int), typeof(int))) t_result = typeof(int); else if (args_match(typeof(uint), typeof(uint))) t_result = typeof(uint); else if (args_match(typeof(long), typeof(long))) t_result = typeof(long); else if (args_match(typeof(ulong), typeof(ulong))) t_result = typeof(ulong); else t_result.AssertNotNull(); Types.Add(op, t_result); } else { (t_lhs.IsFloatingPoint() && t_rhs.IsFloatingPoint()).AssertTrue(); if (t_lhs == typeof(double) || t_rhs == typeof(double)) Types.Add(op, typeof(double)); else if (t_lhs == typeof(float) || t_rhs == typeof(float)) Types.Add(op, typeof(float)); else throw AssertionHelper.Fail(); } } } else { throw AssertionHelper.Fail(); } } }
protected internal override void TraverseOperator(Operator op) { var opt = op.OperatorType; if (op.IsUnary()) { if (!opt.ToString().StartsWith("Post")) _writer.Write(opt.ToCSharpSymbol()); Traverse(op.Args.First()); if (opt.ToString().StartsWith("Post")) _writer.Write(opt.ToCSharpSymbol()); } else if (op.IsBinary()) { Traverse(op.Args.First()); _writer.Write(" " + opt.ToCSharpSymbol() + " "); Traverse(op.Args.Second()); } else { op.Unsupported(); } }