public void EvaluateClass()
        {
            // Open class scope chain
            using (Eval.OpenScope(Module, _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.
                    }
                    return;
                }

                // Evaluate inner classes, if any
                EvaluateInnerClasses(_classDef);
                _class = classInfo;

                var bases = ProcessBases();
                _class.SetBases(bases, Eval.CurrentScope);
                _class.DecideGeneric();
                // Declare __class__ variable in the scope.
                Eval.DeclareVariable("__class__", _class, VariableSource.Declaration);
                ProcessClassBody();
            }
        }
Esempio n. 2
0
 private bool IsValidAssignment(string name, Location loc)
 {
     if (Eval.GetInScope(name) is ILocatedMember m)
     {
         // Class and function definition are processed first, so only override
         // if assignment happens after declaration
         if (loc.IndexSpan.Start < m.Location.IndexSpan.Start)
         {
             return(false);
         }
     }
     return(true);
 }
        private void AssignImportedVariables(IPythonModule module, DottedName moduleImportExpression, NameExpression asNameExpression)
        {
            // "import fob.oar as baz" is handled as
            // baz = import_module('fob.oar')
            if (asNameExpression != null)
            {
                Eval.DeclareVariable(asNameExpression.Name, module, asNameExpression);
                return;
            }

            // "import fob.oar" is handled as
            // import_module('fob.oar')
            // fob = import_module('fob')
            var importNames = moduleImportExpression.Names;

            PythonPackage pythonPackage = null;
            var           existingDepth = 0;

            var childPackage = Eval.GetInScope <PythonPackage>(importNames[0].Name);

            while (childPackage != null && existingDepth < importNames.Count - 1)
            {
                existingDepth++;
                pythonPackage = childPackage;
                childPackage  = pythonPackage.GetMember <PythonPackage>(importNames[existingDepth].Name);
            }

            var child = module;

            for (var i = importNames.Count - 2; i >= existingDepth; i--)
            {
                var childName  = importNames[i + 1].Name;
                var parentName = importNames[i].Name;
                var parent     = new PythonPackage(parentName, Eval.Services);
                parent.AddChildModule(childName, child);
                child = parent;
            }

            if (pythonPackage == null)
            {
                Eval.DeclareVariable(importNames[0].Name, child, importNames[0]);
            }
            else
            {
                pythonPackage.AddChildModule(importNames[existingDepth].Name, child);
            }
        }
        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);
            }
        }
        public override bool Walk(PythonAst node)
        {
            Check.InvalidOperation(() => Ast == node, "walking wrong AST");
            _cancellationToken.ThrowIfCancellationRequested();

            // Collect basic information about classes and functions in order
            // to correctly process forward references. Does not determine
            // types yet since at this time imports or generic definitions
            // have not been processed.
            SymbolTable.Build(Eval);

            // There are cases (see typeshed datetime stub) with constructs
            //   class A:
            //      def __init__(self, x: Optional[B]): ...
            //
            //   _A = A
            //
            //   class B:
            //      def func(self, x: Optional[_A])
            //
            // so evaluation of A -> B ends up incomplete since _A is not known yet.
            // Thus, when A type is created, we need to go and evaluate all assignments
            // that might be referring to it in the right hand side.
            if (Ast.Body is SuiteStatement ste)
            {
                foreach (var statement in ste.Statements.OfType <AssignmentStatement>())
                {
                    if (statement.Left.Count == 1 && statement.Left[0] is NameExpression leftNex && statement.Right is NameExpression rightNex)
                    {
                        var m = Eval.GetInScope <IPythonClassType>(rightNex.Name);
                        if (m != null)
                        {
                            Eval.DeclareVariable(leftNex.Name, m, VariableSource.Declaration, leftNex);
                        }
                    }
                }
            }

            return(base.Walk(node));
        }
        public void EvaluateClass()
        {
            // Open class scope chain
            using (Eval.OpenScope(Module, _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.
                    }
                    return;
                }

                // Evaluate inner classes, if any
                EvaluateInnerClasses(_classDef);

                _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 = Eval.GetTypeFromAnnotation(a.Expression);
                    if (b != null)
                    {
                        var t = b.GetPythonType();
                        bases.Add(t);
                        t.AddReference(Eval.GetLocationOfName(a.Expression));
                    }
                }
                _class.SetBases(bases);

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

                ProcessClassBody();
            }
        }
 private bool IsValidAssignment(string name, Location loc) => !Eval.GetInScope(name).IsDeclaredAfter(loc);