Example #1
0
        public async Task HandleTupleAssignmentAsync(TupleExpression lhs, Expression rhs, IMember value, CancellationToken cancellationToken = default) {
            cancellationToken.ThrowIfCancellationRequested();

            if (rhs is TupleExpression tex) {
                var returnedExpressions = tex.Items.ToArray();
                var names = lhs.Items.OfType<NameExpression>().Select(x => x.Name).ToArray();
                for (var i = 0; i < Math.Min(names.Length, returnedExpressions.Length); i++) {
                    if (returnedExpressions[i] != null && !string.IsNullOrEmpty(names[i])) {
                        var v = await Eval.GetValueFromExpressionAsync(returnedExpressions[i], cancellationToken);
                        if (v != null) {
                            Eval.DeclareVariable(names[i], v, returnedExpressions[i]);
                        }
                    }
                }
                return;
            }

            // Tuple = 'tuple value' (such as from callable). Transfer values.
            if (value is IPythonCollection seq) {
                var types = seq.Contents.Select(c => c.GetPythonType()).ToArray();
                var expressions = lhs.Items.OfType<NameExpression>().ToArray();
                var names = expressions.Select(x => x.Name).ToArray();
                for (var i = 0; i < Math.Min(names.Length, types.Length); i++) {
                    if (names[i] != null && types[i] != null) {
                        var instance = types[i].CreateInstance(null, Eval.GetLoc(expressions[i]), ArgumentSet.Empty);
                        Eval.DeclareVariable(names[i], instance, expressions[i]);
                    }
                }
            }
        }
        public async Task <bool> HandleTryExceptAsync(TryStatement node, CancellationToken cancellationToken = default)
        {
            await node.Body.WalkAsync(Walker, cancellationToken);

            foreach (var handler in node.Handlers.MaybeEnumerate())
            {
                if (handler.Test != null && handler.Target is NameExpression nex)
                {
                    var value = await Eval.GetValueFromExpressionAsync(handler.Test, cancellationToken);

                    Eval.DeclareVariable(nex.Name, value, nex);
                }
                await handler.Body.WalkAsync(Walker, cancellationToken);
            }

            if (node.Finally != null)
            {
                await node.Finally.WalkAsync(Walker, cancellationToken);
            }
            if (node.Else != null)
            {
                await node.Else.WalkAsync(Walker, cancellationToken);
            }
            return(false);
        }
Example #3
0
        public override async Task <bool> WalkAsync(ReturnStatement node, CancellationToken cancellationToken = default)
        {
            var value = await Eval.GetValueFromExpressionAsync(node.Expression, cancellationToken);

            if (value != null)
            {
                _overload.AddReturnValue(value);
            }
            return(true); // We want to evaluate all code so all private variables in __new__ get defined
        }
Example #4
0
        public override async Task <bool> WalkAsync(ReturnStatement node, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var value = await Eval.GetValueFromExpressionAsync(node.Expression, cancellationToken);

            if (!value.IsUnknown())
            {
                _result = value;
                return(false);
            }
            return(true);
        }
Example #5
0
        public async Task HandleWithAsync(WithStatement node, CancellationToken cancellationToken = default) {
            cancellationToken.ThrowIfCancellationRequested();
            foreach (var item in node.Items.Where(x => x.Variable != null)) {
                var contextManager = await Eval.GetValueFromExpressionAsync(item.ContextManager, cancellationToken);
                var cmType = contextManager.GetPythonType();

                var enter = cmType?.GetMember(node.IsAsync ? @"__aenter__" : @"__enter__")?.GetPythonType<IPythonFunctionType>();
                if (enter != null) {
                    var context = await Eval.GetValueFromFunctionTypeAsync(enter, null, null, cancellationToken);
                    if (item.Variable is NameExpression nex && !string.IsNullOrEmpty(nex.Name)) {
                        Eval.DeclareVariable(nex.Name, context, Eval.GetLoc(item));
                    }
                }
            }
        }
Example #6
0
        public override async Task EvaluateAsync(CancellationToken cancellationToken = default)
        {
            if (SymbolTable.ReplacedByStubs.Contains(Target))
            {
                return;
            }

            cancellationToken.ThrowIfCancellationRequested();
            // Process annotations.
            var annotationType = await Eval.GetTypeFromAnnotationAsync(FunctionDefinition.ReturnAnnotation, cancellationToken);

            if (!annotationType.IsUnknown())
            {
                // Annotations are typically types while actually functions return
                // instances unless specifically annotated to a type such as Type[T].
                var instance = annotationType.CreateInstance(annotationType.Name, Eval.GetLoc(FunctionDefinition), ArgumentSet.Empty);
                _overload.SetReturnValue(instance, true);
            }
            else
            {
                // Check if function is a generator
                var suite     = FunctionDefinition.Body as SuiteStatement;
                var yieldExpr = suite?.Statements.OfType <ExpressionStatement>().Select(s => s.Expression as YieldExpression).ExcludeDefault().FirstOrDefault();
                if (yieldExpr != null)
                {
                    // Function return is an iterator
                    var yieldValue = await Eval.GetValueFromExpressionAsync(yieldExpr.Expression, cancellationToken) ?? Eval.UnknownType;

                    var returnValue = new PythonGenerator(Eval.Interpreter, yieldValue);
                    _overload.SetReturnValue(returnValue, true);
                }
            }

            using (Eval.OpenScope(FunctionDefinition, out _)) {
                await DeclareParametersAsync(cancellationToken);

                if (annotationType.IsUnknown() || Module.ModuleType == ModuleType.User)
                {
                    // Return type from the annotation is sufficient for libraries
                    // and stubs, no need to walk the body.
                    if (FunctionDefinition.Body != null && Module.ModuleType != ModuleType.Specialized)
                    {
                        await FunctionDefinition.Body.WalkAsync(this, cancellationToken);
                    }
                }
            }
        }
Example #7
0
        public async Task HandleForAsync(ForStatement node, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var iterable = await Eval.GetValueFromExpressionAsync(node.List, cancellationToken);

            var iterator = (iterable as IPythonIterable)?.GetIterator();

            if (iterator == null)
            {
                // TODO: report that expression does not evaluate to iterable.
            }
            var value = iterator?.Next ?? Eval.UnknownType;

            switch (node.Left)
            {
            case NameExpression nex:
                // for x in y:
                Eval.DeclareVariable(nex.Name, value, Eval.GetLoc(node.Left));
                break;

            case TupleExpression tex:
                // x = [('abc', 42, True), ('abc', 23, False)]
                // for some_str, some_int, some_bool in x:
                var names = tex.Items.OfType <NameExpression>().Select(x => x.Name).ToArray();
                if (value is IPythonIterable valueIterable)
                {
                    var valueIterator = valueIterable.GetIterator();
                    foreach (var n in names)
                    {
                        Eval.DeclareVariable(n, valueIterator?.Next ?? Eval.UnknownType, Eval.GetLoc(node.Left));
                    }
                }
                else
                {
                    // TODO: report that expression yields value that does not evaluate to iterable.
                }
                break;
            }

            if (node.Body != null)
            {
                await node.Body.WalkAsync(Walker, cancellationToken);
            }
        }
Example #8
0
        public override async Task <bool> WalkAsync(AssignmentStatement node, CancellationToken cancellationToken = default)
        {
            var value = await Eval.GetValueFromExpressionAsync(node.Right, cancellationToken);

            foreach (var lhs in node.Left)
            {
                switch (lhs)
                {
                case MemberExpression memberExp when memberExp.Target is NameExpression nameExp1: {
                    if (_function.DeclaringType.GetPythonType() is PythonClassType t && nameExp1.Name == "self")
                    {
                        t.AddMembers(new[] { new KeyValuePair <string, IMember>(memberExp.Name, value) }, true);
                    }
                    continue;
                }

                case NameExpression nameExp2 when nameExp2.Name == "self":
                    return(true);    // Don't assign to 'self'
                }
            }
            return(await base.WalkAsync(node, cancellationToken));
        }
Example #9
0
        private async Task DeclareParameterAsync(Parameter p, int index, ParameterInfo pi, CancellationToken cancellationToken = default)
        {
            IPythonType paramType;

            // If type is known from annotation, use it.
            if (pi != null && !pi.Type.IsUnknown() && !pi.Type.IsGenericParameter())
            {
                // TODO: technically generics may have constraints. Should we consider them?
                paramType = pi.Type;
            }
            else
            {
                var defaultValue = await Eval.GetValueFromExpressionAsync(p.DefaultValue, cancellationToken) ?? Eval.UnknownType;

                paramType = defaultValue.GetPythonType();
                if (!paramType.IsUnknown())
                {
                    pi?.SetDefaultValueType(paramType);
                }
            }

            Eval.DeclareVariable(p.Name, paramType, p.NameExpression);
        }
Example #10
0
        private async Task DeclareParametersAsync(CancellationToken cancellationToken = default)
        {
            // For class method no need to add extra parameters, but first parameter type should be the class.
            // For static and unbound methods do not add or set anything.
            // For regular bound methods add first parameter and set it to the class.

            var parameters = new List <ParameterInfo>();
            var skip       = 0;

            if (_self != null && _function.HasClassFirstArgument())
            {
                var p0 = FunctionDefinition.Parameters.FirstOrDefault();
                if (p0 != null && !string.IsNullOrEmpty(p0.Name))
                {
                    // Actual parameter type will be determined when method is invoked.
                    // The reason is that if method might be called on a derived class.
                    // Declare self or cls in this scope.
                    Eval.DeclareVariable(p0.Name, _self, p0.NameExpression);
                    // Set parameter info.
                    var pi = new ParameterInfo(Ast, p0, _self);
                    pi.SetType(_self);
                    parameters.Add(pi);
                    skip++;
                }
            }

            // Declare parameters in scope
            for (var i = skip; i < FunctionDefinition.Parameters.Length; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var p = FunctionDefinition.Parameters[i];
                if (!string.IsNullOrEmpty(p.Name))
                {
                    // If parameter has default value, look for the annotation locally first
                    // since outer type may be getting redefined. Consider 's = None; def f(s: s = 123): ...
                    IPythonType paramType = null;
                    if (p.DefaultValue != null)
                    {
                        paramType = await Eval.GetTypeFromAnnotationAsync(p.Annotation, cancellationToken, LookupOptions.Local | LookupOptions.Builtins);

                        if (paramType == null)
                        {
                            var defaultValue = await Eval.GetValueFromExpressionAsync(p.DefaultValue, cancellationToken);

                            if (!defaultValue.IsUnknown())
                            {
                                paramType = defaultValue.GetPythonType();
                            }
                        }
                    }
                    // If all else fails, look up globally.
                    paramType = paramType ?? await Eval.GetTypeFromAnnotationAsync(p.Annotation, cancellationToken);

                    var pi = new ParameterInfo(Ast, p, paramType);
                    await DeclareParameterAsync(p, i, pi, cancellationToken);

                    parameters.Add(pi);
                }
            }
            _overload.SetParameters(parameters);
        }
        public async Task HandleAssignmentAsync(AssignmentStatement node, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var value = await Eval.GetValueFromExpressionAsync(node.Right, cancellationToken);

            if (value.IsUnknown())
            {
                Log?.Log(TraceEventType.Verbose, $"Undefined value: {node.Right.ToCodeString(Ast).Trim()}");
            }

            if (value?.GetPythonType().TypeId == BuiltinTypeId.Ellipsis)
            {
                value = Eval.UnknownType;
            }

            if (node.Left.FirstOrDefault() is TupleExpression lhs)
            {
                // Tuple = Tuple. Transfer values.
                var texHandler = new TupleExpressionHandler(Walker);
                await texHandler.HandleTupleAssignmentAsync(lhs, node.Right, value, cancellationToken);

                return;
            }
            foreach (var expr in node.Left.OfType <ExpressionWithAnnotation>())
            {
                // x: List[str] = [...]
                await HandleAnnotatedExpressionAsync(expr, value, cancellationToken);
            }

            foreach (var ne in node.Left.OfType <NameExpression>())
            {
                if (Eval.CurrentScope.NonLocals[ne.Name] != null)
                {
                    Eval.LookupNameInScopes(ne.Name, out var scope, LookupOptions.Nonlocal);
                    if (scope != null)
                    {
                        scope.Variables[ne.Name].Value = value;
                    }
                    else
                    {
                        // TODO: report variable is not declared in outer scopes.
                    }
                    continue;
                }

                if (Eval.CurrentScope.Globals[ne.Name] != null)
                {
                    Eval.LookupNameInScopes(ne.Name, out var scope, LookupOptions.Global);
                    if (scope != null)
                    {
                        scope.Variables[ne.Name].Value = value;
                    }
                    else
                    {
                        // TODO: report variable is not declared in global scope.
                    }
                    continue;
                }

                Eval.DeclareVariable(ne.Name, value, Eval.GetLoc(ne));
            }
        }