public JsNode VisitOperatorResolveResult(OperatorResolveResult res)
 {
     if (res.Operands.Count == 1)
     {
         return(Unary(res));
     }
     else if (res.Operands.Count == 2)
     {
         res = WorkaroundIssue501(res);
         var node2 = Binary(res);
         if (Importer.ForceIntegers)
         {
             if (Importer.IsInteger(res.Type) && res.OperatorType == ExpressionType.Divide)
             {
                 node2 = Importer.ForceInteger(node2);
             }
         }
         return(node2);
     }
     else if (res.Operands.Count == 3)
     {
         return(Trinary(res));
     }
     else
     {
         throw new NotImplementedException();
     }
 }
예제 #2
0
        /// <summary>
        /// Wraps a setter invocation with a js function that returns the setter value back, if another assignment operation occurs
        /// var x = contact.Name = "Shooki";
        /// var x = contact.setName("Shooki"); //error
        /// var x = (function(arg){contact.setName(arg);return arg;}).call(this, "Shooki");
        /// </summary>
        /// <param name="res"></param>
        /// <param name="node2"></param>
        /// <returns></returns>
        private JNode WrapSetterToReturnValueIfNeeded(OperatorResolveResult res, JNode node2)
        {
            var node3 = node2 as JInvocationExpression;

            if (node3 == null)
            {
                return(node2);
            }
            var parent = res.GetParent(Project);

            if (parent is OperatorResolveResult)
            {
                var parentOp = (OperatorResolveResult)parent;
                if (RequiresWrapSetterToReturnValueIfNeeded(res, parentOp))
                {
                    var lastArg = node3.Arguments.Last();
                    var prmName = "$p" + ParameterNameCounter++;
                    node3.Arguments[node3.Arguments.Count - 1] = J.Member(prmName);

                    var func = J.Function(prmName).Add(((JExpression)node2).Statement());
                    func.Add(J.Return(J.Member(prmName)));
                    node2 = WrapFunctionAndInvoke(res, func.Block, lastArg);
                }
            }
            return(node2);
        }
예제 #3
0
        private object GetConstValue(OperatorResolveResult orr, bool isLeft, bool isChar)
        {
            var result = isLeft ? orr.Operands.First() : orr.Operands.Last();

            if (result.IsCompileTimeConstant)
            {
                return(WrapConstValue(result.ConstantValue));
            }
            ConversionResolveResult rr = result as ConversionResolveResult;

            if (rr != null && rr.Input.IsCompileTimeConstant)
            {
                if (isChar)
                {
                    return(isLeft ? this.BinaryOperatorExpression.Left.ToString() : this.BinaryOperatorExpression.Right.ToString());
                }
                else if (rr.Input.Type.Kind == TypeKind.Enum)
                {
                    MemberResolveResult reslut = (MemberResolveResult)rr.Input;
                    return("\"" + reslut.Member.Name + "\"");
                }
                return(WrapConstValue(rr.Input.ConstantValue));
            }
            return(null);
        }
예제 #4
0
        public ArgumentsInfo(IEmitter emitter, BinaryOperatorExpression binaryOperatorExpression, OperatorResolveResult operatorResolveResult, IMethod method)
        {
            Emitter               = emitter;
            Expression            = binaryOperatorExpression;
            OperatorResolveResult = operatorResolveResult;

            BuildOperatorArgumentsList(new Expression[] { binaryOperatorExpression.Left, binaryOperatorExpression.Right }, operatorResolveResult.UserDefinedOperatorMethod ?? method);
            BuildOperatorTypedArguments();
        }
예제 #5
0
        public ArgumentsInfo(IEmitter emitter, UnaryOperatorExpression unaryOperatorExpression, OperatorResolveResult operatorResolveResult, IMethod method)
        {
            Emitter               = emitter;
            Expression            = unaryOperatorExpression;
            OperatorResolveResult = operatorResolveResult;

            BuildOperatorArgumentsList(new Expression[] { unaryOperatorExpression.Expression }, operatorResolveResult.UserDefinedOperatorMethod ?? method);
            BuildOperatorTypedArguments();
        }
        private JsNode Unary(OperatorResolveResult res)
        {
            if (res.UserDefinedOperatorMethod != null && !Sk.UseNativeOperatorOverloads(res.UserDefinedOperatorMethod.DeclaringTypeDefinition))
            {
                var fake = Cs.InvokeMethod(res.UserDefinedOperatorMethod, null, res.Operands[0]);
                return(Visit(fake));
            }

            var isProperty = false;
            var meRes      = res.Operands[0] as MemberResolveResult;

            if (meRes != null && meRes.Member != null && IsEntityFunctionProperty(meRes.Member, res))
            {
                isProperty = true;
            }

            JsExpression node2;

            if (res.OperatorType.IsAny(ExpressionType.Negate, ExpressionType.PreDecrementAssign, ExpressionType.PreIncrementAssign, ExpressionType.Not, ExpressionType.OnesComplement))
            {
                var simpler = res.OperatorType.ExtractCompoundAssignment();
                if (isProperty && simpler != null)
                {
                    var fakeCs = meRes.ShallowClone().Binary(simpler.Value, Cs.Value(1, Project), meRes.Type);
                    node2 = VisitExpression(fakeCs);
                }
                else
                {
                    node2 = new JsPreUnaryExpression {
                        Operator = Visit(res.OperatorType), Right = VisitExpression(res.Operands[0])
                    };
                }
            }
            else if (res.OperatorType.IsAny(ExpressionType.PostIncrementAssign, ExpressionType.PostDecrementAssign, ExpressionType.PreIncrementAssign, ExpressionType.PreDecrementAssign))
            {
                if (isProperty)
                {
                    var simpler = res.OperatorType.ExtractCompoundAssignment();
                    var fakeCs  = meRes.ShallowClone().Binary(simpler.Value, Cs.Value(1, Project), meRes.Type);
                    node2 = VisitExpression(fakeCs);
                }
                else
                {
                    node2 = new JsPostUnaryExpression {
                        Operator = Visit(res.OperatorType), Left = VisitExpression(res.Operands[0])
                    };
                }
            }
            else
            {
                throw new NotImplementedException();
            }
            return(node2);
        }
예제 #7
0
 bool RequiresWrapSetterToReturnValueIfNeeded(OperatorResolveResult op, OperatorResolveResult parentOp)
 {
     if (parentOp.OperatorType == System.Linq.Expressions.ExpressionType.Assign)
     {
         return(true);
     }
     if (parentOp.OperatorType == System.Linq.Expressions.ExpressionType.Conditional && parentOp.Operands.IndexOf(op) > 0)
     {
         return(true);
     }
     return(false);
 }
		public override JsExpression VisitOperatorResolveResult(OperatorResolveResult rr, object data) {
			bool isUserDefined = (rr.UserDefinedOperatorMethod != null && _metadataImporter.GetMethodSemantics(rr.UserDefinedOperatorMethod).Type != MethodScriptSemantics.ImplType.NativeOperator);
			var arguments = new JsExpression[rr.Operands.Count + 1];
			for (int i = 0; i < rr.Operands.Count; i++)
				arguments[i] = VisitResolveResult(rr.Operands[i], null);
			arguments[arguments.Length - 1] = isUserDefined ? _getMember(rr.UserDefinedOperatorMethod) : _instantiateType(rr.Type);
			if (rr.OperatorType == ExpressionType.Conditional)
				return CompileFactoryCall("Condition", new[] { typeof(Expression), typeof(Expression), typeof(Expression), typeof(Type) }, arguments);
			else {
				return CompileFactoryCall(rr.OperatorType.ToString(), rr.Operands.Count == 1 ? new[] { typeof(Expression), isUserDefined ? typeof(MethodInfo) : typeof(Type) } : new[] { typeof(Expression), typeof(Expression), isUserDefined ? typeof(MethodInfo) : typeof(Type) }, arguments);
			}
		}
예제 #9
0
        Value VisitUnaryOperator(OperatorResolveResult result, UnaryOperatorType operatorType, bool checkForOverflow = false)
        {
            Debug.Assert(result.Operands.Count == 1);
            var            operand  = Convert(result.Operands[0]).ToResolveResult(context);
            CSharpResolver resolver = new CSharpResolver(debuggerTypeSystem).WithCheckForOverflow(checkForOverflow);
            var            val      = resolver.ResolveUnaryOperator(operatorType, operand);

            if (val.IsCompileTimeConstant)
            {
                return(Convert(val));
            }
            throw new GetValueException("Operator {0} is not supported for {1}!", operatorType, new CSharpAmbience().ConvertType(operand.Type));
        }
 private JsNode Trinary(OperatorResolveResult res)
 {
     if (res.OperatorType == ExpressionType.Conditional)
     {
         var node5 = new JsConditionalExpression {
             Condition = VisitExpression(res.Operands[0]), TrueExpression = VisitExpression(res.Operands[1]), FalseExpression = VisitExpression(res.Operands[2])
         };
         return(node5);
     }
     else
     {
         throw new NotImplementedException();
     }
 }
예제 #11
0
        private void VisitStringConcat(OperatorResolveResult orr, bool isLeft, bool isChar)
        {
            object constValue = GetConstValue(orr, isLeft, isChar);

            if (constValue != null)
            {
                this.Write(constValue);
            }
            else
            {
                var express = isLeft ? this.BinaryOperatorExpression.Left : this.BinaryOperatorExpression.Right;
                if (isChar)
                {
                    this.Write("string.char");
                    this.WriteOpenParentheses();
                    express.AcceptVisitor(this.Emitter);
                    this.WriteCloseParentheses();
                }
                else if (express is IdentifierExpression || express is InvocationExpression)
                {
                    var resolverResult = this.Emitter.Resolver.ResolveNode(express, this.Emitter);
                    if (resolverResult.Type.Kind == TypeKind.Struct)
                    {
                        express.AcceptVisitor(this.Emitter);
                    }
                    else if (resolverResult.Type.Kind == TypeKind.Enum)
                    {
                        TransformCtx.ExportEnums.Add(resolverResult.Type);
                        this.Write("System.Enum.toString");
                        this.WriteOpenParentheses();
                        express.AcceptVisitor(this.Emitter);
                        this.WriteComma();
                        string typeName = BridgeTypes.ToJsName(resolverResult.Type, this.Emitter);
                        this.Write(typeName);
                        this.WriteCloseParentheses();
                    }
                    else
                    {
                        this.Write("System.strconcat");
                        this.WriteOpenParentheses();
                        express.AcceptVisitor(this.Emitter);
                        this.WriteCloseParentheses();
                    }
                }
                else
                {
                    express.AcceptVisitor(this.Emitter);
                }
            }
        }
 /// <summary>
 /// https://github.com/icsharpcode/NRefactory/issues/501
 /// </summary>
 OperatorResolveResult WorkaroundIssue501(OperatorResolveResult res)
 {
     if (res.UserDefinedOperatorMethod == null)
     {
         return(res);
     }
     if ((res.OperatorType == ExpressionType.AndAlso && res.UserDefinedOperatorMethod.Name == "op_BitwiseAnd") ||
         (res.OperatorType == ExpressionType.OrElse && res.UserDefinedOperatorMethod.Name == "op_BitwiseOr"))
     {
         var fake = new OperatorResolveResult(res.Type, res.OperatorType, null, res.IsLiftedOperator, res.Operands);
         return(fake);
     }
     return(res);
 }
예제 #13
0
        Value VisitTernaryOperator(OperatorResolveResult result)
        {
            Debug.Assert(result.Operands.Count == 3);
            var condition = Convert(result.Operands[0]);

            if (!condition.Type.IsKnownType(KnownTypeCode.Boolean))
            {
                throw new GetValueException("Boolean expression expected!");
            }
            if ((bool)condition.PrimitiveValue)
            {
                return(Convert(result.Operands[1]));
            }
            return(Convert(result.Operands[2]));
        }
예제 #14
0
        bool RequiresWrapSetterToReturnValue(OperatorResolveResult op)
        {
            var node = op.GetFirstNode();

            if (node == null)
            {
                return(false);
            }

            var parentNode = node.Parent;

            if (parentNode == null)
            {
                return(false);
            }

            if (parentNode is ReturnStatement)
            {
                return(true);
            }


            var parentRes = parentNode.Resolve();

            if (parentRes is OperatorResolveResult)
            {
                var parentOp = (OperatorResolveResult)parentRes;

                if (parentOp.OperatorType == ExpressionType.Assign)
                {
                    return(true);
                }
                if (parentOp.OperatorType == ExpressionType.Conditional && parentOp.Operands.IndexOf(op) > 0)
                {
                    return(true);
                }
                return(false);
            }
            if (parentRes is LocalResolveResult && parentRes.GetFirstNode() is VariableInitializer)
            {
                return(true);
            }
            return(false);
        }
예제 #15
0
        public override string VisitOperatorResolveResult(OperatorResolveResult rr, object data)
        {
            bool isUserDefined = rr.UserDefinedOperatorMethod != null && !this._emitter.Validator.IsExternalType(rr.UserDefinedOperatorMethod.DeclaringTypeDefinition);
            var  arguments     = new string[rr.Operands.Count + 1];

            for (int i = 0; i < rr.Operands.Count; i++)
            {
                arguments[i] = VisitResolveResult(rr.Operands[i], null);
            }
            arguments[arguments.Length - 1] = isUserDefined ? this.GetMember(rr.UserDefinedOperatorMethod) : ExpressionTreeBuilder.GetTypeName(rr.Type, this._emitter);
            if (rr.OperatorType == ExpressionType.Conditional)
            {
                return(CompileFactoryCall("Condition", new[] { typeof(Expression), typeof(Expression), typeof(Expression), typeof(Type) }, arguments));
            }
            else
            {
                return(CompileFactoryCall(rr.OperatorType.ToString(), rr.Operands.Count == 1 ? new[] { typeof(Expression), isUserDefined ? typeof(MethodInfo) : typeof(Type) } : new[] { typeof(Expression), typeof(Expression), isUserDefined ? typeof(MethodInfo) : typeof(Type) }, arguments));
            }
        }
예제 #16
0
        protected bool IsUserOperator(OperatorResolveResult orr)
        {
            var method = orr != null ? orr.UserDefinedOperatorMethod : null;

            if (method != null)
            {
                var inline = this.Emitter.GetInline(method);

                if (!string.IsNullOrWhiteSpace(inline))
                {
                    return(true);
                }
                else if (!this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #17
0
        /// <summary>
        /// Wraps a setter invocation with a js function that returns the setter value back, if another assignment operation occurs
        /// var x = contact.Name = "Shooki";
        /// var x = contact.setName("Shooki"); //error
        /// var x = (function(arg){contact.setName(arg);return arg;}).call(this, "Shooki");
        /// </summary>
        /// <param name="res"></param>
        /// <param name="node2"></param>
        /// <returns></returns>
        internal JsNode WrapSetterToReturnValueIfNeeded(OperatorResolveResult res, JsNode node2)
        {
            var node3 = node2 as JsInvocationExpression;

            if (node3 == null)
            {
                return(node2);
            }

            if (RequiresWrapSetterToReturnValue(res))
            {
                var lastArg = node3.Arguments.Last();
                var prmName = "$p" + ParameterNameCounter++;
                node3.Arguments[node3.Arguments.Count - 1] = Js.Member(prmName);

                var func = Js.Function(prmName).Add(((JsExpression)node2).Statement());
                func.Add(Js.Return(Js.Member(prmName)));
                node2 = WrapFunctionAndInvoke(res, func, lastArg);
            }
            return(node2);
        }
예제 #18
0
        Value VisitConditionalOperator(OperatorResolveResult result, BinaryOperatorType bitwiseOperatorType)
        {
            Debug.Assert(result.Operands.Count == 2);
            var            lhs      = Convert(result.Operands[0]).GetPermanentReference(evalThread);
            CSharpResolver resolver = new CSharpResolver(debuggerTypeSystem);
            Value          condVal;

            if (bitwiseOperatorType == BinaryOperatorType.BitwiseAnd)
            {
                condVal = Convert(resolver.ResolveConditionFalse(lhs.ToResolveResult(context)));
            }
            else
            {
                condVal = Convert(resolver.ResolveCondition(lhs.ToResolveResult(context)));
            }
            if ((bool)condVal.PrimitiveValue)
            {
                return(lhs);
            }
            var rhs = Convert(result.Operands[1]);
            var val = resolver.ResolveBinaryOperator(bitwiseOperatorType, lhs.ToResolveResult(context), rhs.ToResolveResult(context));

            return(Convert(val));
        }
예제 #19
0
        protected void VisitBinaryOperatorExpression()
        {
            BinaryOperatorExpression binaryOperatorExpression = this.BinaryOperatorExpression;
            var  resolveOperator      = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression, this.Emitter);
            var  expectedType         = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression);
            bool isDecimalExpected    = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isDecimal            = Helpers.IsDecimalType(resolveOperator.Type, this.Emitter.Resolver);
            OperatorResolveResult orr = resolveOperator as OperatorResolveResult;
            var leftResolverResult    = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Left, this.Emitter);
            var rightResolverResult   = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Right, this.Emitter);

            if (resolveOperator is ConstantResolveResult)
            {
                this.WriteScript(((ConstantResolveResult)resolveOperator).ConstantValue);
                return;
            }

            if (!((expectedType.IsKnownType(KnownTypeCode.String) || resolveOperator.Type.IsKnownType(KnownTypeCode.String)) && binaryOperatorExpression.Operator == BinaryOperatorType.Add) && (Helpers.IsDecimalType(leftResolverResult.Type, this.Emitter.Resolver) || Helpers.IsDecimalType(rightResolverResult.Type, this.Emitter.Resolver)))
            {
                isDecimal         = true;
                isDecimalExpected = true;
            }

            if (isDecimal && isDecimalExpected && binaryOperatorExpression.Operator != BinaryOperatorType.NullCoalescing)
            {
                this.HandleDecimal(resolveOperator);
                return;
            }

            var delegateOperator = false;

            if (this.ResolveOperator(binaryOperatorExpression, orr))
            {
                return;
            }

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Divide &&
                (
                    (Helpers.IsIntegerType(leftResolverResult.Type, this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(rightResolverResult.Type, this.Emitter.Resolver)) ||

                    (Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), this.Emitter.Resolver) &&
                     Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), this.Emitter.Resolver))
                ))
            {
                this.Write("Bridge.Int.div(");
                binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);
                this.Write(", ");
                binaryOperatorExpression.Right.AcceptVisitor(this.Emitter);
                this.Write(")");
                return;
            }

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Add ||
                binaryOperatorExpression.Operator == BinaryOperatorType.Subtract)
            {
                var add = binaryOperatorExpression.Operator == BinaryOperatorType.Add;

                if (this.Emitter.Validator.IsDelegateOrLambda(leftResolverResult) && this.Emitter.Validator.IsDelegateOrLambda(rightResolverResult))
                {
                    delegateOperator = true;
                    this.Write(Bridge.Translator.Emitter.ROOT + "." + (add ? Bridge.Translator.Emitter.DELEGATE_COMBINE : Bridge.Translator.Emitter.DELEGATE_REMOVE));
                    this.WriteOpenParentheses();
                }
            }

            bool   nullable     = orr != null && orr.IsLiftedOperator;
            bool   isCoalescing = binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing;
            string root         = Bridge.Translator.Emitter.ROOT + ".Nullable.";
            bool   special      = nullable || isCoalescing;
            bool   rootSpecial  = nullable;

            if (rootSpecial)
            {
                this.Write(root);
            }
            else if (isCoalescing)
            {
                this.Write(Bridge.Translator.Emitter.ROOT + ".");
            }
            else
            {
                binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);
            }

            if (!delegateOperator)
            {
                if (!special)
                {
                    this.WriteSpace();
                }
                bool isBool = NullableType.IsNullable(resolveOperator.Type) ? NullableType.GetUnderlyingType(resolveOperator.Type).IsKnownType(KnownTypeCode.Boolean) : resolveOperator.Type.IsKnownType(KnownTypeCode.Boolean);
                switch (binaryOperatorExpression.Operator)
                {
                case BinaryOperatorType.Add:
                    this.Write(rootSpecial ? "add" : "+");
                    break;

                case BinaryOperatorType.BitwiseAnd:
                    if (isBool)
                    {
                        this.Write(rootSpecial ? "and" : "&&");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "band" : "&");
                    }

                    break;

                case BinaryOperatorType.BitwiseOr:
                    if (isBool)
                    {
                        this.Write(rootSpecial ? "or" : "||");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "bor" : "|");
                    }
                    break;

                case BinaryOperatorType.ConditionalAnd:
                    this.Write(rootSpecial ? "and" : "&&");
                    break;

                case BinaryOperatorType.NullCoalescing:
                    this.Write("coalesce");
                    break;

                case BinaryOperatorType.ConditionalOr:
                    this.Write(rootSpecial ? "or" : "||");
                    break;

                case BinaryOperatorType.Divide:
                    this.Write(rootSpecial ? "div" : "/");
                    break;

                case BinaryOperatorType.Equality:
                    this.Write(rootSpecial ? "eq" : "===");
                    break;

                case BinaryOperatorType.ExclusiveOr:
                    this.Write(rootSpecial ? "xor" : "^");
                    break;

                case BinaryOperatorType.GreaterThan:
                    this.Write(rootSpecial ? "gt" : ">");
                    break;

                case BinaryOperatorType.GreaterThanOrEqual:
                    this.Write(rootSpecial ? "gte" : ">=");
                    break;

                case BinaryOperatorType.InEquality:
                    this.Write(rootSpecial ? "neq" : "!==");
                    break;

                case BinaryOperatorType.LessThan:
                    this.Write(rootSpecial ? "lt" : "<");
                    break;

                case BinaryOperatorType.LessThanOrEqual:
                    this.Write(rootSpecial ? "lte" : "<=");
                    break;

                case BinaryOperatorType.Modulus:
                    this.Write(rootSpecial ? "mod" : "%");
                    break;

                case BinaryOperatorType.Multiply:
                    this.Write(rootSpecial ? "mul" : "*");
                    break;

                case BinaryOperatorType.ShiftLeft:
                    this.Write(rootSpecial ? "sl" : "<<");
                    break;

                case BinaryOperatorType.ShiftRight:
                    this.Write(rootSpecial ? "sr" : ">>");
                    break;

                case BinaryOperatorType.Subtract:
                    this.Write(rootSpecial ? "sub" : "-");
                    break;

                default:
                    throw new EmitterException(binaryOperatorExpression, "Unsupported binary operator: " + binaryOperatorExpression.Operator.ToString());
                }
            }
            else
            {
                this.WriteComma();
            }

            if (special)
            {
                this.WriteOpenParentheses();
                binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);
                this.WriteComma();
            }
            else
            {
                this.WriteSpace();
            }

            binaryOperatorExpression.Right.AcceptVisitor(this.Emitter);

            if (delegateOperator || special)
            {
                this.WriteCloseParentheses();
            }
        }
예제 #20
0
        protected bool ResolveOperator(BinaryOperatorExpression binaryOperatorExpression, OperatorResolveResult orr)
        {
            var method = orr != null ? orr.UserDefinedOperatorMethod : null;

            if (method != null)
            {
                var inline = this.Emitter.GetInline(method);

                if (!string.IsNullOrWhiteSpace(inline))
                {
                    new InlineArgumentsBlock(this.Emitter,
                                             new ArgumentsInfo(this.Emitter, binaryOperatorExpression, orr, method), inline).Emit();
                    return(true);
                }
                else if (!this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition))
                {
                    if (orr.IsLiftedOperator)
                    {
                        this.Write(Bridge.Translator.Emitter.ROOT + ".Nullable.lift(");
                    }

                    this.Write(BridgeTypes.ToJsName(method.DeclaringType, this.Emitter));
                    this.WriteDot();

                    this.Write(OverloadsCollection.Create(this.Emitter, method).GetOverloadName());

                    if (orr.IsLiftedOperator)
                    {
                        this.WriteComma();
                    }
                    else
                    {
                        this.WriteOpenParentheses();
                    }

                    new ExpressionListBlock(this.Emitter,
                                            new Expression[] { binaryOperatorExpression.Left, binaryOperatorExpression.Right }, null).Emit();
                    this.WriteCloseParentheses();

                    return(true);
                }
            }

            return(false);
        }
예제 #21
0
 public JsNode VisitOperatorResolveResult(OperatorResolveResult res)
 {
     return(new ResolveResultVisitor_Operator {
         Compiler = Compiler, Importer = this, Project = Project
     }.VisitOperatorResolveResult(res));
 }
예제 #22
0
        public static int CheckConversion(ConversionBlock block, Expression expression)
        {
            try
            {
                var rr           = block.Emitter.Resolver.ResolveNode(expression, block.Emitter);
                var conversion   = block.Emitter.Resolver.Resolver.GetConversion(expression);
                var expectedType = block.Emitter.Resolver.Resolver.GetExpectedType(expression);

                var level = ConversionBlock.CheckDecimalConversion(block, expression, rr, expectedType, conversion) ? 1 : 0;

                if (Helpers.IsDecimalType(expectedType, block.Emitter.Resolver) && !conversion.IsUserDefined)
                {
                    return(level);
                }

                if (conversion == null)
                {
                    return(level);
                }

                if (conversion.IsIdentityConversion)
                {
                    return(level);
                }

                var isNumLifted = conversion.IsImplicit && conversion.IsLifted && conversion.IsNumericConversion && !(expression is BinaryOperatorExpression);
                if (isNumLifted && !conversion.IsUserDefined)
                {
                    return(level);
                }
                bool isLifted = conversion.IsLifted && !isNumLifted && !(block is CastBlock) && !Helpers.IsDecimalType(expectedType, block.Emitter.Resolver);
                if (isLifted)
                {
                    level++;
                    block.Write("Bridge.Nullable.lift(");
                }

                if (conversion.IsUserDefined)
                {
                    var method = conversion.Method;

                    string inline = block.Emitter.GetInline(method);

                    if (conversion.IsExplicit && !string.IsNullOrWhiteSpace(inline))
                    {
                        // Still returns true if Nullable.lift( was written.
                        return(level);
                    }

                    if (!string.IsNullOrWhiteSpace(inline))
                    {
                        if (expression is InvocationExpression)
                        {
                            new InlineArgumentsBlock(block.Emitter, new ArgumentsInfo(block.Emitter, (InvocationExpression)expression), inline).Emit();
                        }
                        else if (expression is ObjectCreateExpression)
                        {
                            new InlineArgumentsBlock(block.Emitter, new ArgumentsInfo(block.Emitter, (InvocationExpression)expression), inline).Emit();
                        }
                        else if (expression is UnaryOperatorExpression)
                        {
                            var unaryExpression       = (UnaryOperatorExpression)expression;
                            var resolveOperator       = block.Emitter.Resolver.ResolveNode(unaryExpression, block.Emitter);
                            OperatorResolveResult orr = resolveOperator as OperatorResolveResult;
                            new InlineArgumentsBlock(block.Emitter, new ArgumentsInfo(block.Emitter, unaryExpression, orr, method), inline).Emit();
                        }
                        else if (expression is BinaryOperatorExpression)
                        {
                            var binaryExpression      = (BinaryOperatorExpression)expression;
                            var resolveOperator       = block.Emitter.Resolver.ResolveNode(binaryExpression, block.Emitter);
                            OperatorResolveResult orr = resolveOperator as OperatorResolveResult;
                            new InlineArgumentsBlock(block.Emitter, new ArgumentsInfo(block.Emitter, binaryExpression, orr, method), inline).Emit();
                        }
                        else
                        {
                            new InlineArgumentsBlock(block.Emitter, new ArgumentsInfo(block.Emitter, expression), inline).Emit();
                        }

                        block.DisableEmitConversionExpression = true;

                        // Still returns true if Nullable.lift( was written.
                        return(level);
                    }
                    else
                    {
                        if (method.DeclaringTypeDefinition != null && block.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition))
                        {
                            // Still returns true if Nullable.lift( was written.
                            return(level);
                        }

                        block.Write(BridgeTypes.ToJsName(method.DeclaringType, block.Emitter));
                        block.WriteDot();

                        block.Write(OverloadsCollection.Create(block.Emitter, method).GetOverloadName());
                    }

                    if (isLifted)
                    {
                        block.WriteComma();
                    }
                    else
                    {
                        block.WriteOpenParentheses();
                        level++;
                    }

                    var arg = method.Parameters[0];

                    if (Helpers.IsDecimalType(arg.Type, block.Emitter.Resolver, arg.IsParams) && !Helpers.IsDecimalType(rr.Type, block.Emitter.Resolver) && !expression.IsNull)
                    {
                        block.Write("Bridge.Decimal");
                        if (NullableType.IsNullable(arg.Type) && ConversionBlock.ShouldBeLifted(expression))
                        {
                            block.Write(".lift");
                        }
                        block.WriteOpenParentheses();
                        level++;
                    }

                    return(level);
                }
                // Still returns true if Nullable.lift( was written.
                return(level);
            }
            catch
            {
            }

            return(0);
        }
 public virtual TResult VisitOperatorResolveResult(OperatorResolveResult rr, TData data)
 {
     VisitChildResolveResults(rr, data);
     return(default(TResult));
 }
예제 #24
0
        protected void VisitUnaryOperatorExpression()
        {
            var  unaryOperatorExpression = this.UnaryOperatorExpression;
            var  oldType              = this.Emitter.UnaryOperatorType;
            var  oldAccessor          = this.Emitter.IsUnaryAccessor;
            var  resolveOperator      = this.Emitter.Resolver.ResolveNode(unaryOperatorExpression, this.Emitter);
            var  expectedType         = this.Emitter.Resolver.Resolver.GetExpectedType(unaryOperatorExpression);
            bool isDecimalExpected    = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isDecimal            = Helpers.IsDecimalType(resolveOperator.Type, this.Emitter.Resolver);
            bool isLongExpected       = Helpers.Is64Type(expectedType, this.Emitter.Resolver);
            bool isLong               = Helpers.Is64Type(resolveOperator.Type, this.Emitter.Resolver);
            OperatorResolveResult orr = resolveOperator as OperatorResolveResult;
            int count = this.Emitter.Writers.Count;

            if (resolveOperator is ConstantResolveResult)
            {
                this.WriteScript(((ConstantResolveResult)resolveOperator).ConstantValue);
                return;
            }

            if (Helpers.IsDecimalType(resolveOperator.Type, this.Emitter.Resolver))
            {
                isDecimal         = true;
                isDecimalExpected = true;
            }

            if (isDecimal && isDecimalExpected && unaryOperatorExpression.Operator != UnaryOperatorType.Await)
            {
                this.HandleDecimal(resolveOperator);
                return;
            }

            if (this.ResolveOperator(unaryOperatorExpression, orr))
            {
                return;
            }

            if (Helpers.Is64Type(resolveOperator.Type, this.Emitter.Resolver))
            {
                isLong         = true;
                isLongExpected = true;
            }

            if (isLong && isLongExpected && unaryOperatorExpression.Operator != UnaryOperatorType.Await)
            {
                this.HandleDecimal(resolveOperator, true);
                return;
            }

            if (this.ResolveOperator(unaryOperatorExpression, orr))
            {
                return;
            }

            var  op = unaryOperatorExpression.Operator;
            var  argResolverResult = this.Emitter.Resolver.ResolveNode(unaryOperatorExpression.Expression, this.Emitter);
            bool nullable          = NullableType.IsNullable(argResolverResult.Type);

            if (nullable)
            {
                if (op != UnaryOperatorType.Increment &&
                    op != UnaryOperatorType.Decrement &&
                    op != UnaryOperatorType.PostIncrement &&
                    op != UnaryOperatorType.PostDecrement)
                {
                    this.Write(JS.Types.SYSTEM_NULLABLE + ".");
                }
            }

            bool isAccessor = false;

            var memberArgResolverResult = argResolverResult as MemberResolveResult;

            if (memberArgResolverResult != null)
            {
                var prop = memberArgResolverResult.Member as IProperty;

                if (prop != null)
                {
                    var isIgnore   = memberArgResolverResult.Member.DeclaringTypeDefinition != null && this.Emitter.Validator.IsExternalType(memberArgResolverResult.Member.DeclaringTypeDefinition);
                    var inlineAttr = prop.Getter != null?this.Emitter.GetAttribute(prop.Getter.Attributes, Translator.Bridge_ASSEMBLY + ".TemplateAttribute") : null;

                    var ignoreAccessor     = prop.Getter != null && this.Emitter.Validator.IsExternalType(prop.Getter);
                    var isAccessorsIndexer = this.Emitter.Validator.IsAccessorsIndexer(memberArgResolverResult.Member);

                    isAccessor = true;

                    if (inlineAttr == null && (isIgnore || ignoreAccessor) && !isAccessorsIndexer)
                    {
                        isAccessor = false;
                    }
                }
            }
            else if (argResolverResult is ArrayAccessResolveResult)
            {
                isAccessor = ((ArrayAccessResolveResult)argResolverResult).Indexes.Count > 1;
            }

            this.Emitter.UnaryOperatorType = op;

            if ((isAccessor) &&
                (op == UnaryOperatorType.Increment ||
                 op == UnaryOperatorType.Decrement ||
                 op == UnaryOperatorType.PostIncrement ||
                 op == UnaryOperatorType.PostDecrement))
            {
                this.Emitter.IsUnaryAccessor = true;

                if (nullable)
                {
                    this.Write(JS.Funcs.BRIDGE_HASVALUE);
                    this.WriteOpenParentheses();
                    this.Emitter.IsUnaryAccessor = false;
                    unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    this.Write(") ? ");
                    this.Emitter.IsUnaryAccessor = true;
                    unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    this.Write(" : null)");
                }
                else
                {
                    unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                }

                this.Emitter.IsUnaryAccessor = oldAccessor;

                if (this.Emitter.Writers.Count > count)
                {
                    this.PopWriter();
                }
            }
            else
            {
                switch (op)
                {
                case UnaryOperatorType.BitNot:
                    if (nullable)
                    {
                        this.Write("bnot(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(")");
                    }
                    else
                    {
                        this.Write("~");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Decrement:
                    if (nullable)
                    {
                        this.Write(JS.Funcs.BRIDGE_HASVALUE);
                        this.WriteOpenParentheses();
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(") ? ");
                        this.Write("--");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(" : null)");
                    }
                    else
                    {
                        this.Write("--");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Increment:
                    if (nullable)
                    {
                        this.Write(JS.Funcs.BRIDGE_HASVALUE);
                        this.WriteOpenParentheses();
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(") ? ");
                        this.Write("++");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(" : null)");
                    }
                    else
                    {
                        this.Write("++");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Minus:
                    if (nullable)
                    {
                        this.Write("neg(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(")");
                    }
                    else
                    {
                        this.Write("-");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Not:
                    if (nullable)
                    {
                        this.Write("not(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(")");
                    }
                    else
                    {
                        this.Write("!");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Plus:
                    if (nullable)
                    {
                        this.Write("pos(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(")");
                    }
                    else
                    {
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }

                    break;

                case UnaryOperatorType.PostDecrement:
                    if (nullable)
                    {
                        this.Write(JS.Funcs.BRIDGE_HASVALUE);
                        this.WriteOpenParentheses();
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(") ? ");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write("--");
                        this.Write(" : null)");
                    }
                    else
                    {
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write("--");
                    }
                    break;

                case UnaryOperatorType.PostIncrement:
                    if (nullable)
                    {
                        this.Write(JS.Funcs.BRIDGE_HASVALUE);
                        this.WriteOpenParentheses();
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(") ? ");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write("++");
                        this.Write(" : null)");
                    }
                    else
                    {
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write("++");
                    }
                    break;

                case UnaryOperatorType.Await:
                    if (this.Emitter.ReplaceAwaiterByVar)
                    {
                        var index = System.Array.IndexOf(this.Emitter.AsyncBlock.AwaitExpressions, unaryOperatorExpression.Expression) + 1;
                        this.Write(JS.Vars.ASYNC_TASK_RESULT + index);
                    }
                    else
                    {
                        var oldValue = this.Emitter.ReplaceAwaiterByVar;
                        var oldAsyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

                        if (this.Emitter.IsAsync && !this.Emitter.AsyncExpressionHandling)
                        {
                            this.WriteAwaiters(unaryOperatorExpression.Expression);
                            this.Emitter.ReplaceAwaiterByVar     = true;
                            this.Emitter.AsyncExpressionHandling = true;
                        }

                        this.WriteAwaiter(unaryOperatorExpression.Expression);

                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
                    }
                    break;

                default:
                    throw new EmitterException(unaryOperatorExpression, "Unsupported unary operator: " + unaryOperatorExpression.Operator.ToString());
                }

                if (this.Emitter.Writers.Count > count)
                {
                    this.PopWriter();
                }
            }

            this.Emitter.UnaryOperatorType = oldType;
        }
예제 #25
0
        protected bool ResolveOperator(UnaryOperatorExpression unaryOperatorExpression, OperatorResolveResult orr)
        {
            if (orr != null && orr.UserDefinedOperatorMethod != null)
            {
                var method = orr.UserDefinedOperatorMethod;
                var inline = this.Emitter.GetInline(method);

                if (!string.IsNullOrWhiteSpace(inline))
                {
                    new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, unaryOperatorExpression, orr, method), inline).Emit();
                    return(true);
                }
                else
                {
                    if (orr.IsLiftedOperator)
                    {
                        this.Write(JS.Types.SYSTEM_NULLABLE + "." + JS.Funcs.Math.LIFT + "(");
                    }

                    this.Write(BridgeTypes.ToJsName(method.DeclaringType, this.Emitter));
                    this.WriteDot();

                    this.Write(OverloadsCollection.Create(this.Emitter, method).GetOverloadName());

                    if (orr.IsLiftedOperator)
                    {
                        this.WriteComma();
                    }
                    else
                    {
                        this.WriteOpenParentheses();
                    }

                    new ExpressionListBlock(this.Emitter, new Expression[] { unaryOperatorExpression.Expression }, null, null, 0).Emit();
                    this.WriteCloseParentheses();

                    return(true);
                }
            }

            return(false);
        }
예제 #26
0
        protected bool ResolveOperator(BinaryOperatorExpression binaryOperatorExpression, OperatorResolveResult orr)
        {
            var method = orr != null ? orr.UserDefinedOperatorMethod : null;

            if (method != null)
            {
                var inline = this.Emitter.GetInline(method);

                if (!string.IsNullOrWhiteSpace(inline))
                {
                    new InlineArgumentsBlock(this.Emitter,
                                             new ArgumentsInfo(this.Emitter, binaryOperatorExpression, orr, method), inline).Emit();
                    return(true);
                }
                else if (!this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition))
                {
                    string name = OverloadsCollection.Create(this.Emitter, method).GetOverloadName();
                    if (Helpers.GetOperatorMapping(name) != null)
                    {
                        return(false);
                    }

                    if (orr.IsLiftedOperator)
                    {
                        this.Write(Bridge.Translator.Emitter.ROOT + ".Nullable.");

                        string action = "lift";

                        switch (this.BinaryOperatorExpression.Operator)
                        {
                        case BinaryOperatorType.GreaterThan:
                            action = "liftcmp";
                            break;

                        case BinaryOperatorType.GreaterThanOrEqual:
                            action = "liftcmp";
                            break;

                        case BinaryOperatorType.Equality:
                            action = "lifteq";
                            break;

                        case BinaryOperatorType.InEquality:
                            action = "liftne";
                            break;

                        case BinaryOperatorType.LessThan:
                            action = "liftcmp";
                            break;

                        case BinaryOperatorType.LessThanOrEqual:
                            action = "liftcmp";
                            break;
                        }

                        this.Write(action + "(");
                    }

                    this.Write(BridgeTypes.ToJsName(method.DeclaringType, this.Emitter));
                    this.WriteDot();
                    this.Write(name);

                    if (orr.IsLiftedOperator)
                    {
                        this.WriteComma();
                    }
                    else
                    {
                        this.WriteOpenParentheses();
                    }

                    new ExpressionListBlock(this.Emitter, new Expression[] { binaryOperatorExpression.Left, binaryOperatorExpression.Right }, null).Emit();
                    this.WriteCloseParentheses();
                    return(true);
                }
            }

            return(false);
        }
예제 #27
0
        protected bool ResolveOperator(UnaryOperatorExpression unaryOperatorExpression, OperatorResolveResult orr)
        {
            if (orr != null && orr.UserDefinedOperatorMethod != null)
            {
                var method = orr.UserDefinedOperatorMethod;
                var inline = this.Emitter.GetInline(method);

                if (!string.IsNullOrWhiteSpace(inline))
                {
                    new InlineArgumentsBlock(this.Emitter, new ArgumentsInfo(this.Emitter, unaryOperatorExpression, orr), inline).Emit();
                    return(true);
                }
                else
                {
                    if (orr.IsLiftedOperator)
                    {
                        this.Write(Bridge.Translator.Emitter.ROOT + ".Nullable.lift(");
                    }

                    this.Write(this.Emitter.ShortenTypeName(Helpers.GetScriptFullName(method.DeclaringType)));
                    this.WriteDot();

                    this.Write(OverloadsCollection.Create(this.Emitter, method).GetOverloadName());

                    if (orr.IsLiftedOperator)
                    {
                        this.WriteComma();
                    }
                    else
                    {
                        this.WriteOpenParentheses();
                    }

                    new ExpressionListBlock(this.Emitter, new Expression[] { unaryOperatorExpression.Expression }, null).Emit();
                    this.WriteCloseParentheses();

                    return(true);
                }
            }

            return(false);
        }
예제 #28
0
 string Visit(OperatorResolveResult result)
 {
     throw new NotImplementedException();
 }
예제 #29
0
        protected void VisitUnaryOperatorExpression()
        {
            var unaryOperatorExpression = this.UnaryOperatorExpression;
            var oldType     = this.Emitter.UnaryOperatorType;
            var oldAccessor = this.Emitter.IsUnaryAccessor;

            var resolveOperator       = this.Emitter.Resolver.ResolveNode(unaryOperatorExpression, this.Emitter);
            OperatorResolveResult orr = resolveOperator as OperatorResolveResult;

            if (resolveOperator is ConstantResolveResult)
            {
                this.WriteScript(((ConstantResolveResult)resolveOperator).ConstantValue);
                return;
            }

            if (this.ResolveOperator(unaryOperatorExpression, orr))
            {
                return;
            }

            var  op = unaryOperatorExpression.Operator;
            var  argResolverResult = this.Emitter.Resolver.ResolveNode(unaryOperatorExpression.Expression, this.Emitter);
            bool nullable          = NullableType.IsNullable(argResolverResult.Type);

            if (nullable)
            {
                if (op != UnaryOperatorType.Increment &&
                    op != UnaryOperatorType.Decrement &&
                    op != UnaryOperatorType.PostIncrement &&
                    op != UnaryOperatorType.PostDecrement)
                {
                    this.Write(Bridge.Translator.Emitter.ROOT + ".Nullable.");
                }
            }

            bool isAccessor = false;
            var  memberArgResolverResult = argResolverResult as MemberResolveResult;

            if (memberArgResolverResult != null && memberArgResolverResult.Member is IProperty)
            {
                isAccessor = true;
            }
            else if (argResolverResult is ArrayAccessResolveResult)
            {
                isAccessor = ((ArrayAccessResolveResult)argResolverResult).Indexes.Count > 1;
            }

            this.Emitter.UnaryOperatorType = op;

            if (isAccessor &&
                (op == UnaryOperatorType.Increment ||
                 op == UnaryOperatorType.Decrement ||
                 op == UnaryOperatorType.PostIncrement ||
                 op == UnaryOperatorType.PostDecrement))
            {
                this.Emitter.IsUnaryAccessor = true;

                if (nullable)
                {
                    this.Write("(Bridge.hasValue(");
                    this.Emitter.IsUnaryAccessor = false;
                    unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    this.Write(") ? ");
                    this.Emitter.IsUnaryAccessor = true;
                    unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    this.Write(" : null)");
                }
                else
                {
                    unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                }

                this.Emitter.IsUnaryAccessor = oldAccessor;
            }
            else
            {
                switch (op)
                {
                case UnaryOperatorType.BitNot:
                    if (nullable)
                    {
                        this.Write("bnot(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(")");
                    }
                    else
                    {
                        this.Write("~");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Decrement:
                    if (nullable)
                    {
                        this.Write("(Bridge.hasValue(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(") ? --");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(" : null)");
                    }
                    else
                    {
                        this.Write("--");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Increment:
                    if (nullable)
                    {
                        this.Write("(Bridge.hasValue(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(") ? ++");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(" : null)");
                    }
                    else
                    {
                        this.Write("++");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Minus:
                    if (nullable)
                    {
                        this.Write("neg(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(")");
                    }
                    else
                    {
                        this.Write("-");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Not:
                    if (nullable)
                    {
                        this.Write("not(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(")");
                    }
                    else
                    {
                        this.Write("!");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }
                    break;

                case UnaryOperatorType.Plus:
                    if (nullable)
                    {
                        this.Write("pos(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(")");
                    }
                    else
                    {
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                    }

                    break;

                case UnaryOperatorType.PostDecrement:
                    if (nullable)
                    {
                        this.Write("(Bridge.hasValue(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(") ? ");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write("-- : null)");
                    }
                    else
                    {
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write("--");
                    }
                    break;

                case UnaryOperatorType.PostIncrement:
                    if (nullable)
                    {
                        this.Write("(Bridge.hasValue(");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write(") ? ");
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write("++ : null)");
                    }
                    else
                    {
                        unaryOperatorExpression.Expression.AcceptVisitor(this.Emitter);
                        this.Write("++");
                    }
                    break;

                case UnaryOperatorType.Await:
                    if (this.Emitter.ReplaceAwaiterByVar)
                    {
                        var index = System.Array.IndexOf(this.Emitter.AsyncBlock.AwaitExpressions, unaryOperatorExpression.Expression) + 1;
                        this.Write("$taskResult" + index);
                    }
                    else
                    {
                        var oldValue = this.Emitter.ReplaceAwaiterByVar;
                        var oldAsyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

                        if (this.Emitter.IsAsync && !this.Emitter.AsyncExpressionHandling)
                        {
                            this.WriteAwaiters(unaryOperatorExpression.Expression);
                            this.Emitter.ReplaceAwaiterByVar     = true;
                            this.Emitter.AsyncExpressionHandling = true;
                        }

                        this.WriteAwaiter(unaryOperatorExpression.Expression);

                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
                    }
                    break;

                default:
                    throw (Exception)this.Emitter.CreateException(unaryOperatorExpression, "Unsupported unary operator: " + unaryOperatorExpression.Operator.ToString());
                }
            }

            this.Emitter.UnaryOperatorType = oldType;
        }
예제 #30
0
        protected void VisitBinaryOperatorExpression()
        {
            BinaryOperatorExpression binaryOperatorExpression = this.BinaryOperatorExpression;
            var  resolveOperator       = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression, this.Emitter);
            var  expectedType          = this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression);
            bool isDecimalExpected     = Helpers.IsDecimalType(expectedType, this.Emitter.Resolver);
            bool isDecimal             = Helpers.IsDecimalType(resolveOperator.Type, this.Emitter.Resolver);
            OperatorResolveResult orr  = resolveOperator as OperatorResolveResult;
            var    leftResolverResult  = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Left, this.Emitter);
            var    rightResolverResult = this.Emitter.Resolver.ResolveNode(binaryOperatorExpression.Right, this.Emitter);
            var    charToString        = -1;
            string variable            = null;
            bool   leftIsNull          = this.BinaryOperatorExpression.Left is NullReferenceExpression;
            bool   rightIsNull         = this.BinaryOperatorExpression.Right is NullReferenceExpression;
            bool   isStringConcat      = false;

            /*
             * if ((leftIsNull || rightIsNull) && (binaryOperatorExpression.Operator == BinaryOperatorType.Equality || binaryOperatorExpression.Operator == BinaryOperatorType.InEquality))
             * {
             *  if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality)
             *  {
             *      this.Write("!");
             *  }
             *
             *  this.Write(LuaHelper.Root,".hasValue");
             *
             *  this.WriteOpenParentheses();
             *
             *  if (leftIsNull)
             *  {
             *      binaryOperatorExpression.Right.AcceptVisitor(this.Emitter);
             *  }
             *  else
             *  {
             *      binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);
             *  }
             *
             *  this.WriteCloseParentheses();
             *  return;
             * }*/

            if (orr != null && orr.Type.IsKnownType(KnownTypeCode.String))
            {
                isStringConcat = true;
                for (int i = 0; i < orr.Operands.Count; i++)
                {
                    var crr = orr.Operands[i] as ConversionResolveResult;
                    if (crr != null && crr.Input.Type.IsKnownType(KnownTypeCode.Char))
                    {
                        charToString = i;
                    }
                }
            }

            if (resolveOperator is ConstantResolveResult)
            {
                this.WriteScript(((ConstantResolveResult)resolveOperator).ConstantValue);
                return;
            }

            if (!((expectedType.IsKnownType(KnownTypeCode.String) || resolveOperator.Type.IsKnownType(KnownTypeCode.String)) && binaryOperatorExpression.Operator == BinaryOperatorType.Add) && (Helpers.IsDecimalType(leftResolverResult.Type, this.Emitter.Resolver) || Helpers.IsDecimalType(rightResolverResult.Type, this.Emitter.Resolver)))
            {
                isDecimal         = true;
                isDecimalExpected = true;
            }

            if (isDecimal && isDecimalExpected && binaryOperatorExpression.Operator != BinaryOperatorType.NullCoalescing)
            {
                this.HandleDecimal(resolveOperator);
                return;
            }

            var delegateOperator = false;

            if (this.ResolveOperator(binaryOperatorExpression, orr))
            {
                return;
            }

            /*
             * if (binaryOperatorExpression.Operator == BinaryOperatorType.Divide &&
             *  (
             *      (Helpers.IsIntegerType(leftResolverResult.Type, this.Emitter.Resolver) &&
             *      Helpers.IsIntegerType(rightResolverResult.Type, this.Emitter.Resolver)) ||
             *
             *      (Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), this.Emitter.Resolver) &&
             *      Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), this.Emitter.Resolver))
             *  ))
             * {
             *  this.Write("{0}.Number.div(".F(LuaHelper.Root));
             *  binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);
             *  this.Write(", ");
             *  binaryOperatorExpression.Right.AcceptVisitor(this.Emitter);
             *  this.Write(")");
             *  return;
             * }
             */

            if (binaryOperatorExpression.Operator == BinaryOperatorType.Add ||
                binaryOperatorExpression.Operator == BinaryOperatorType.Subtract)
            {
                var add = binaryOperatorExpression.Operator == BinaryOperatorType.Add;

                if (this.Emitter.Validator.IsDelegateOrLambda(leftResolverResult) || this.Emitter.Validator.IsDelegateOrLambda(rightResolverResult))
                {
                    delegateOperator = true;
                    this.Write(Bridge.Translator.Emitter.ROOT + "." + (add ? Bridge.Translator.Emitter.DELEGATE_COMBINE : Bridge.Translator.Emitter.DELEGATE_REMOVE));
                    this.WriteOpenParentheses();
                }
            }

            bool isBool    = NullableType.IsNullable(resolveOperator.Type) ? NullableType.GetUnderlyingType(resolveOperator.Type).IsKnownType(KnownTypeCode.Boolean) : resolveOperator.Type.IsKnownType(KnownTypeCode.Boolean);
            bool isBitwise = (binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseAnd && !isBool) ||
                             (binaryOperatorExpression.Operator == BinaryOperatorType.BitwiseOr && !isBool) ||
                             binaryOperatorExpression.Operator == BinaryOperatorType.ExclusiveOr ||
                             binaryOperatorExpression.Operator == BinaryOperatorType.ShiftLeft ||
                             binaryOperatorExpression.Operator == BinaryOperatorType.ShiftRight;

            bool isIntDiv = binaryOperatorExpression.Operator == BinaryOperatorType.Divide &&
                            (
                (Helpers.IsIntegerType(leftResolverResult.Type, this.Emitter.Resolver) &&
                 Helpers.IsIntegerType(rightResolverResult.Type, this.Emitter.Resolver)) ||

                (Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Left), this.Emitter.Resolver) &&
                 Helpers.IsIntegerType(this.Emitter.Resolver.Resolver.GetExpectedType(binaryOperatorExpression.Right), this.Emitter.Resolver))
                            );

            bool   nullable     = orr != null && orr.IsLiftedOperator;
            bool   isCoalescing = binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing;
            string root         = Bridge.Translator.Emitter.ROOT + ".Nullable.";
            bool   special      = nullable;
            bool   rootSpecial  = nullable;

            if (!nullable)
            {
                if (isBitwise || isIntDiv)
                {
                    root        = Bridge.Translator.Emitter.ROOT + ".";
                    special     = true;
                    rootSpecial = true;
                }
            }

            if (rootSpecial)
            {
                this.Write(root);
            }
            else if (isStringConcat)
            {
                VisitStringConcat(orr, true, charToString == 0);
            }
            else
            {
                if (isCoalescing)
                {
                    this.Write("(");
                    variable = this.GetTempVarName();
                    this.Write(variable);
                    this.Write(" = ");
                }
                else if (charToString == 0)
                {
                    this.Write("string.char(");
                }

                binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);

                if (isCoalescing)
                {
                    this.Write(", {0}.hasValue(".F(LuaHelper.Root));
                    this.Write(variable);
                    this.Write(") ? ");
                    this.Write(variable);
                }
                else if (charToString == 0)
                {
                    this.Write(")");
                }
            }

            if (!delegateOperator)
            {
                if (!special)
                {
                    this.WriteSpace();
                }

                bool isUint = resolveOperator.Type.IsKnownType(KnownTypeCode.UInt16) ||
                              resolveOperator.Type.IsKnownType(KnownTypeCode.UInt32) ||
                              resolveOperator.Type.IsKnownType(KnownTypeCode.UInt64);

                bool is64bit = resolveOperator.Type.IsKnownType(KnownTypeCode.UInt64) ||
                               resolveOperator.Type.IsKnownType(KnownTypeCode.Int64);

                if (isBitwise && is64bit)
                {
                    throw new EmitterException(this.BinaryOperatorExpression, "Bitwise operations are not allowed on 64-bit types");
                }

                switch (binaryOperatorExpression.Operator)
                {
                case BinaryOperatorType.Add:
                    if (isStringConcat)
                    {
                        this.Write(rootSpecial ? "and" : "..");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "and" : "+");
                    }
                    break;

                case BinaryOperatorType.BitwiseAnd:
                    if (isBool)
                    {
                        this.Write(rootSpecial ? "and" : "and");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "band" : "&");
                    }

                    break;

                case BinaryOperatorType.BitwiseOr:
                    if (isBool)
                    {
                        this.Write(rootSpecial ? "or" : "or");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "bor" : "|");
                    }
                    break;

                case BinaryOperatorType.ConditionalAnd:
                    this.Write(rootSpecial ? "and" : "and");
                    break;

                case BinaryOperatorType.NullCoalescing:
                    this.Write(":");
                    break;

                case BinaryOperatorType.ConditionalOr:
                    this.Write(rootSpecial ? "or" : "or");
                    break;

                case BinaryOperatorType.Divide:
                    this.Write(rootSpecial ? "div" : "/");
                    break;

                case BinaryOperatorType.Equality:
                    this.Write(rootSpecial ? "eq" : "==");
                    break;

                case BinaryOperatorType.ExclusiveOr:
                    this.Write(rootSpecial ? "xor" : "^");
                    break;

                case BinaryOperatorType.GreaterThan:
                    this.Write(rootSpecial ? ">" : ">");
                    break;

                case BinaryOperatorType.GreaterThanOrEqual:
                    this.Write(rootSpecial ? "gte" : ">=");
                    break;

                case BinaryOperatorType.InEquality:
                    this.Write(rootSpecial ? "neq" : "~=");
                    break;

                case BinaryOperatorType.LessThan:
                    this.Write(rootSpecial ? "lt" : "<");
                    break;

                case BinaryOperatorType.LessThanOrEqual:
                    this.Write(rootSpecial ? "lte" : "<=");
                    break;

                case BinaryOperatorType.Modulus:
                    this.Write(rootSpecial ? "mod" : "%");
                    break;

                case BinaryOperatorType.Multiply:
                    this.Write(rootSpecial ? "mul" : "*");
                    break;

                case BinaryOperatorType.ShiftLeft:
                    this.Write(rootSpecial ? "sl" : "<<");
                    break;

                case BinaryOperatorType.ShiftRight:
                    if (isUint)
                    {
                        this.Write(rootSpecial ? "srr" : ">>>");
                    }
                    else
                    {
                        this.Write(rootSpecial ? "sr" : ">>");
                    }

                    break;

                case BinaryOperatorType.Subtract:
                    this.Write(rootSpecial ? "sub" : "-");
                    break;

                default:
                    throw new EmitterException(binaryOperatorExpression, "Unsupported binary operator: " + binaryOperatorExpression.Operator.ToString());
                }
            }
            else
            {
                this.WriteComma();
            }

            if (isStringConcat)
            {
                this.WriteSpace();
                VisitStringConcat(orr, false, charToString == 1);
            }
            else
            {
                if (special)
                {
                    this.WriteOpenParentheses();
                    if (charToString == 0)
                    {
                        this.Write("string.char(");
                    }

                    binaryOperatorExpression.Left.AcceptVisitor(this.Emitter);

                    if (charToString == 0)
                    {
                        this.Write(")");
                    }

                    this.WriteComma();
                }
                else
                {
                    this.WriteSpace();
                }

                if (charToString == 1)
                {
                    this.Write("string.char(");
                }

                binaryOperatorExpression.Right.AcceptVisitor(this.Emitter);

                if (charToString == 1 || isCoalescing)
                {
                    this.Write(")");
                }

                if (delegateOperator || special)
                {
                    this.WriteCloseParentheses();
                }
            }
        }