Пример #1
0
        private void ExtendAll(Node location, IPythonCollection values)
        {
            Eval.LookupNameInScopes(AllVariableName, out var scope, LookupOptions.Global);
            if (scope == null)
            {
                return;
            }

            var all    = scope.Variables[AllVariableName]?.Value as IPythonCollection;
            var list   = PythonCollectionType.CreateConcatenatedList(Module.Interpreter, all, values);
            var source = list.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;

            Eval.DeclareVariable(AllVariableName, list, source, location);
        }
Пример #2
0
        private void ExtendAll(Node declNode, IReadOnlyList <IMember> values)
        {
            Eval.LookupNameInScopes(AllVariableName, out var scope, LookupOptions.Normal);
            if (scope == null)
            {
                return;
            }

            var loc = Eval.GetLoc(declNode);

            var allContents = (scope.Variables[AllVariableName].Value as IPythonCollection)?.Contents;

            var list   = PythonCollectionType.CreateConcatenatedList(Module.Interpreter, loc, allContents, values);
            var source = list.IsGeneric() ? VariableSource.Generic : VariableSource.Declaration;

            Eval.DeclareVariable(AllVariableName, list, source, loc);
        }
Пример #3
0
        private IMember GetValueFromBinaryOp(Expression expr)
        {
            if (expr is AndExpression)
            {
                return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));
            }

            if (expr is OrExpression orexp)
            {
                // Consider 'self.__params = types.MappingProxyType(params or {})'
                var leftSide = GetValueFromExpression(orexp.Left);
                if (!leftSide.IsUnknown())
                {
                    return(leftSide);
                }
                var rightSide = GetValueFromExpression(orexp.Right);
                return(rightSide.IsUnknown() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : rightSide);
            }

            if (!(expr is BinaryExpression binop) || binop.Left == null)
            {
                return(null);
            }

            // TODO: Specific parsing
            // TODO: warn about incompatible types like 'str' + 1
            switch (binop.Operator)
            {
            case PythonOperator.Equal:
            case PythonOperator.GreaterThan:
            case PythonOperator.GreaterThanOrEqual:
            case PythonOperator.In:
            case PythonOperator.Is:
            case PythonOperator.IsNot:
            case PythonOperator.LessThan:
            case PythonOperator.LessThanOrEqual:
            case PythonOperator.Not:
            case PythonOperator.NotEqual:
            case PythonOperator.NotIn:
                // Assume all of these return True/False
                return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));

            case PythonOperator.Divide:
            case PythonOperator.TrueDivide:
                if (Interpreter.LanguageVersion.Is3x())
                {
                    return(Interpreter.GetBuiltinType(BuiltinTypeId.Float));
                }

                break;
            }

            var left  = GetValueFromExpression(binop.Left) ?? UnknownType;
            var right = GetValueFromExpression(binop.Right) ?? UnknownType;


            var rightType = right.GetPythonType();

            if (rightType?.TypeId == BuiltinTypeId.Float)
            {
                return(right);
            }

            var leftType = left.GetPythonType();

            if (leftType?.TypeId == BuiltinTypeId.Float)
            {
                return(left);
            }

            if (rightType?.TypeId == BuiltinTypeId.Long)
            {
                return(right);
            }

            if (leftType?.TypeId == BuiltinTypeId.Long)
            {
                return(left);
            }

            if (binop.Operator == PythonOperator.Add &&
                leftType?.TypeId == BuiltinTypeId.List && rightType?.TypeId == BuiltinTypeId.List &&
                left is IPythonCollection lc && right is IPythonCollection rc)
            {
                return(PythonCollectionType.CreateConcatenatedList(Module.Interpreter, GetLoc(expr), lc, rc));
            }

            return(left.IsUnknown() ? right : left);
        }
        private IMember GetValueFromBinaryOp(Expression expr, LookupOptions lookupOptions)
        {
            if (expr is AndExpression a)
            {
                GetValueFromExpression(a.Left, lookupOptions);
                GetValueFromExpression(a.Right, lookupOptions);
                return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));
            }

            if (expr is OrExpression orexp)
            {
                // Consider 'self.__params = types.MappingProxyType(params or {})'
                var leftSide = GetValueFromExpression(orexp.Left, lookupOptions);
                if (!leftSide.IsUnknown())
                {
                    return(leftSide);
                }
                var rightSide = GetValueFromExpression(orexp.Right, lookupOptions);
                return(rightSide.IsUnknown() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : rightSide);
            }

            if (!(expr is BinaryExpression binop) || binop.Left == null)
            {
                return(null);
            }

            var op = binop.Operator;

            var left  = GetValueFromExpression(binop.Left, lookupOptions) ?? UnknownType;
            var right = GetValueFromExpression(binop.Right, lookupOptions) ?? UnknownType;

            if (left.IsUnknown() && right.IsUnknown())
            {
                // Fast path for when nothing below will give any results.
                if (op.IsComparison())
                {
                    return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));
                }

                return(UnknownType);
            }

            var leftType  = left.GetPythonType();
            var rightType = right.GetPythonType();

            var leftTypeId  = leftType.TypeId;
            var rightTypeId = rightType.TypeId;

            if (op == PythonOperator.Add &&
                leftTypeId == rightTypeId &&
                left is IPythonCollection lc && right is IPythonCollection rc)
            {
                switch (leftTypeId)
                {
                case BuiltinTypeId.List:
                    return(PythonCollectionType.CreateConcatenatedList(Module, lc, rc));

                case BuiltinTypeId.Tuple:
                    return(PythonCollectionType.CreateConcatenatedTuple(Module, lc, rc));
                }
            }

            // Mod-style string formatting; don't bother looking at the right side.
            if (op == PythonOperator.Mod && (leftTypeId == BuiltinTypeId.Str || leftTypeId == BuiltinTypeId.Unicode))
            {
                return(Interpreter.GetBuiltinType(leftTypeId));
            }

            var leftIsSupported  = IsSupportedBinopBuiltin(leftTypeId);
            var rightIsSupported = IsSupportedBinopBuiltin(rightTypeId);

            if (leftIsSupported && rightIsSupported)
            {
                if (TryGetValueFromBuiltinBinaryOp(op, leftTypeId, rightTypeId, Interpreter.LanguageVersion.Is3x(), out var member))
                {
                    return(member);
                }
            }

            if (leftIsSupported)
            {
                IMember ret;

                if (op.IsComparison())
                {
                    // If the op is a comparison, and the thing on the left is the builtin,
                    // flip the operation and call it instead.
                    ret = CallOperator(op.InvertComparison(), right, rightType, left, leftType, expr, tryRight: false);
                }
                else
                {
                    ret = CallOperator(op, left, leftType, right, rightType, expr, tryLeft: false);
                }

                if (!ret.IsUnknown())
                {
                    return(ret);
                }

                return(op.IsComparison() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : left);
            }

            if (rightIsSupported)
            {
                // Try calling the function on the left side, otherwise just return right.
                var ret = CallOperator(op, left, leftType, right, rightType, expr, tryRight: false);

                if (!ret.IsUnknown())
                {
                    return(ret);
                }

                return(op.IsComparison() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : right);
            }

            var callRet = CallOperator(op, left, leftType, right, rightType, expr);

            if (!callRet.IsUnknown())
            {
                return(callRet);
            }

            if (op.IsComparison())
            {
                callRet = CallOperator(op.InvertComparison(), right, rightType, left, leftType, expr);

                if (!callRet.IsUnknown())
                {
                    return(callRet);
                }
            }

            // TODO: Specific parsing
            // TODO: warn about incompatible types like 'str' + 1
            switch (op)
            {
            case PythonOperator.Equal:
            case PythonOperator.GreaterThan:
            case PythonOperator.GreaterThanOrEqual:
            case PythonOperator.In:
            case PythonOperator.Is:
            case PythonOperator.IsNot:
            case PythonOperator.LessThan:
            case PythonOperator.LessThanOrEqual:
            case PythonOperator.Not:
            case PythonOperator.NotEqual:
            case PythonOperator.NotIn:
                // Assume all of these return True/False
                return(Interpreter.GetBuiltinType(BuiltinTypeId.Bool));

            case PythonOperator.Divide:
            case PythonOperator.TrueDivide:
                if (Interpreter.LanguageVersion.Is3x())
                {
                    return(Interpreter.GetBuiltinType(BuiltinTypeId.Float));
                }

                break;
            }

            return(left.IsUnknown() ? right : left);
        }