public Expression CompileUnOp(AstUnary uo) { var operand = CompileExpression(uo.Operand); if (operand.IsInvalid) { return(Expression.Invalid); } switch (uo.Type) { case AstUnaryType.IncreasePrefix: case AstUnaryType.DecreasePrefix: case AstUnaryType.IncreasePostfix: case AstUnaryType.DecreasePostfix: return(!operand.ReturnType.IsIntegralType && !operand.ReturnType.IsFloatingPointType ? Error(uo.Source, ErrorCode.E2063, "Incremental operators can only be used on integers") : new FixOp(uo.Source, (FixOpType)uo.Type, operand)); } var args = new[] { operand }; var opOp = uo.Type.ToSymbol(); var op = TryResolveOperatorOverload(uo.Source, NameResolver.GetTypeOperators(operand.ReturnType, opOp), args); return(op != null ? new CallUnOp(uo.Source, op, args[0]) : Error(uo.Source, ErrorCode.E2065, operand.ReturnType.Quote() + " has no operators matching the argument list")); }
Expression CompileBinOp(Source src, AstBinaryType binOp, Expression left, Expression right) { if (left.IsInvalid || right.IsInvalid) { return(Expression.Invalid); } if ((left.ReturnType is NullType || left.ReturnType is MethodGroupType) && right.ReturnType.IsReferenceType) { var leftCast = TryCompileImplicitCast(src, right.ReturnType, left); if (leftCast != null) { left = leftCast; } } else if ((right.ReturnType is NullType || right.ReturnType is MethodGroupType) && left.ReturnType.IsReferenceType) { var rightCast = TryCompileImplicitCast(src, left.ReturnType, right); if (rightCast != null) { right = rightCast; } } var args = new[] { left, right }; var opOp = binOp.ToSymbol(); var op = TryResolveOperatorOverload(src, NameResolver.GetTypeOperators(left.ReturnType, right.ReturnType, opOp), args); if (op != null) { return(new CallBinOp(src, op, args[0], args[1])); } switch (binOp) { case AstBinaryType.LogAnd: case AstBinaryType.LogOr: { left = CompileImplicitCast(src, Essentials.Bool, left); right = CompileImplicitCast(src, Essentials.Bool, right); return(new BranchOp( src, Essentials.Bool, binOp == AstBinaryType.LogAnd ? BranchType.And : BranchType.Or, left, right)); } case AstBinaryType.Null: { if (left.ReturnType.IsNull) { return(right); } if (!left.ReturnType.IsReferenceType) { return(Error(src, ErrorCode.E2015, "'??' cannot be used on operand of type " + left.ReturnType.Quote() + " because it is not a reference type")); } right = CompileImplicitCast(src, left.ReturnType, right); return(new NullOp(src, left, right)); } case AstBinaryType.Equal: case AstBinaryType.NotEqual: { if (left.ReturnType.IsReferenceType && right.ReturnType.IsReferenceType) { return(new ReferenceOp(src, Essentials.Bool, binOp == AstBinaryType.Equal ? EqualityType.Equal : EqualityType.NotEqual, left, right)); } break; } case AstBinaryType.Sequence: return(new SequenceOp(left, right)); } return(Error(src, ErrorCode.E2016, left.ReturnType.Quote() + " has no operators " + binOp.ToSymbol().Quote() + " matching the argument list")); }