public async Task HandleAnnotatedExpressionAsync(ExpressionWithAnnotation expr, IMember value, CancellationToken cancellationToken = default)
        {
            if (expr?.Annotation == null)
            {
                return;
            }

            var variableType = await Eval.GetTypeFromAnnotationAsync(expr.Annotation, cancellationToken);

            // If value is null, then this is a pure declaration like
            //   x: List[str]
            // without a value. If value is provided, then this is
            //   x: List[str] = [...]

            // Check value type for compatibility
            IMember instance = null;

            if (value != null)
            {
                var valueType = value.GetPythonType();
                if (!variableType.IsUnknown() && !valueType.Equals(variableType))
                {
                    // TODO: warn incompatible value type.
                    // TODO: verify values. Value may be list() while variable type is List[str].
                    // Leave it as variable type.
                }
                else
                {
                    instance = value;
                }
            }
            instance = instance ?? variableType?.CreateInstance(variableType.Name, Eval.GetLoc(expr.Expression), ArgumentSet.Empty) ?? Eval.UnknownType;

            if (expr.Expression is NameExpression ne)
            {
                Eval.DeclareVariable(ne.Name, instance, expr.Expression);
                return;
            }

            if (expr.Expression is MemberExpression m)
            {
                // self.x : int = 42
                var self    = Eval.LookupNameInScopes("self", out var scope);
                var argType = self?.GetPythonType();
                if (argType is PythonClassType cls && scope != null)
                {
                    cls.AddMember(m.Name, instance, true);
                }
            }
        }
Ejemplo n.º 2
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);
                    }
                }
            }
        }
        public async Task EvaluateClassAsync(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Open class scope chain
            using (Eval.OpenScope(_classDef, out var outerScope)) {
                var instance = Eval.GetInScope(_classDef.Name, outerScope);
                if (!(instance?.GetPythonType() is PythonClassType classInfo))
                {
                    if (instance != null)
                    {
                        // TODO: warning that variable is already declared of a different type.
                    }
                    // May be odd case like class inside a class.
                    return;
                }

                // Evaluate inner classes, if any
                await EvaluateInnerClassesAsync(_classDef, cancellationToken);

                _class = classInfo;
                // Set bases to the class.
                var bases = new List <IPythonType>();
                foreach (var a in _classDef.Bases.Where(a => string.IsNullOrEmpty(a.Name)))
                {
                    // We cheat slightly and treat base classes as annotations.
                    var b = await Eval.GetTypeFromAnnotationAsync(a.Expression, cancellationToken);

                    if (b != null)
                    {
                        bases.Add(b.GetPythonType());
                    }
                }
                _class.SetBases(Interpreter, bases);

                // Declare __class__ variable in the scope.
                Eval.DeclareVariable("__class__", _class, _classDef);

                await ProcessClassBody(cancellationToken);
            }
        }
Ejemplo n.º 4
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);
        }