Пример #1
0
        private IPythonType TryDetermineReturnValue()
        {
            var annotationType = Eval.GetTypeFromAnnotation(FunctionDefinition.ReturnAnnotation);

            if (!annotationType.IsUnknown())
            {
                // Annotations are typically types while actually functions return
                // instances unless specifically annotated to a type such as Type[T].
                // TODO: try constructing argument set from types. Consider Tuple[_T1, _T2] where _T1 = TypeVar('_T1', str, bytes)
                var t = annotationType.CreateInstance(ArgumentSet.Empty(FunctionDefinition.ReturnAnnotation, Eval));
                // If instance could not be created, such as when return type is List[T] and
                // type of T is not yet known, just use the type.
                var instance = t.IsUnknown() ? (IMember)annotationType : t;
                _overload.SetReturnValue(instance, true); _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  = Eval.GetValueFromExpression(yieldExpr.Expression) ?? Eval.UnknownType;
                    var returnValue = new PythonGenerator(Eval.Interpreter, yieldValue);
                    _overload.SetReturnValue(returnValue, true);
                }
            }
            return(annotationType);
        }
        private void Assign(SequenceExpression seq, ValueEnumerator valueEnum)
        {
            foreach (var item in seq.Items)
            {
                switch (item)
                {
                case StarredExpression stx when stx.Expression is NameExpression nex && !string.IsNullOrEmpty(nex.Name):
                    AssignVariable(nex, valueEnum.Next());
                    break;

                case ParenthesisExpression pex when pex.Expression is NameExpression nex && !string.IsNullOrEmpty(nex.Name):
                    AssignVariable(nex, valueEnum.Next());
                    break;

                case NameExpression nex when !string.IsNullOrEmpty(nex.Name):
                    AssignVariable(nex, valueEnum.Next());
                    break;

                // Nested sequence expression in sequence, Tuple[Tuple[int, str], int], List[Tuple[int], str]
                // TODO: Because of bug with how collection types are constructed, they don't make nested collection types
                // into instances, meaning we have to create it here
                case SequenceExpression se when valueEnum.Peek is IPythonCollection || valueEnum.Peek is IPythonCollectionType:
                    var collection = valueEnum.Next();
                    var pc         = collection as IPythonCollection;
                    var pct        = collection as IPythonCollectionType;
                    Assign(se, pc ?? pct.CreateInstance(ArgumentSet.Empty(se, Eval)));
                    break;

                case SequenceExpression se:
                    Assign(se, valueEnum);
                    break;
                }
            }
        }
        public IMember GetValueFromCallable(CallExpression expr, LookupOptions lookupOptions = LookupOptions.Normal)
        {
            if (expr?.Target == null)
            {
                return(null);
            }

            var target = GetValueFromExpression(expr.Target, lookupOptions);

            target?.AddReference(GetLocationOfName(expr.Target));

            var result = GetValueFromGeneric(target, expr, lookupOptions);

            if (result != null)
            {
                return(result);
            }

            // Should only be two types of returns here. First, an bound type
            // so we can invoke Call over the instance. Second, an type info
            // so we can create an instance of the type (as in C() where C is class).
            IMember value = null;
            var     args  = ArgumentSet.Empty(expr, this);

            switch (target)
            {
            case IPythonBoundType bt:     // Bound property, method or an iterator.
                value = GetValueFromBound(bt, expr);
                break;

            case IPythonInstance pi:
                value = GetValueFromInstanceCall(pi, expr);
                break;

            case IPythonFunctionType ft:     // Standalone function or a class method call.
                var instance = ft.DeclaringType?.CreateInstance(args) as IPythonInstance;
                value = GetValueFromFunctionType(ft, instance, expr);
                break;

            case IPythonClassType cls:
                value = GetValueFromClassCtor(cls, expr);
                break;

            case IPythonType t:
                // Target is type (info), the call creates instance.
                // For example, 'x = C; y = x()' or 'x = C()' where C is class
                value = t.CreateInstance(args);
                break;
            }

            if (value == null)
            {
                Log?.Log(TraceEventType.Verbose, $"Unknown callable: {expr.Target.ToCodeString(Ast).Trim()}");
            }

            return(value);
        }
        private void DeclareParameter(Parameter p, ParameterInfo pi)
        {
            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
            {
                paramType = pi?.DefaultValue?.GetPythonType() ?? UnknownType;
            }
            DeclareVariable(p.Name, paramType.CreateInstance(ArgumentSet.Empty(p.NameExpression, this)),
                            VariableSource.Declaration, p.NameExpression);
        }
Пример #5
0
        public IMember GetValueFromIndex(IndexExpression expr, LookupOptions lookupOptions = LookupOptions.Normal)
        {
            if (expr?.Target == null)
            {
                return(null);
            }

            var target = GetValueFromExpression(expr.Target, lookupOptions);
            // Try generics first since this may be an expression like Dict[int, str]
            var result = GetValueFromGeneric(target, expr, lookupOptions);

            if (result != null)
            {
                return(result);
            }

            if (expr.Index is SliceExpression || expr.Index is TupleExpression)
            {
                // When slicing, assume result is the same type
                return(target);
            }

            var type = target.GetPythonType();

            if (type != null)
            {
                if (!(target is IPythonInstance instance))
                {
                    instance = type.CreateInstance(ArgumentSet.Empty(expr, this)) as IPythonInstance;
                }
                if (instance != null)
                {
                    var index = GetValueFromExpression(expr.Index, lookupOptions);
                    if (index != null)
                    {
                        return(type.Index(instance, new ArgumentSet(new[] { index }, expr, this)));
                    }
                }
            }

            return(UnknownType);
        }
        public IMember GetValueFromClassCtor(IPythonClassType cls, CallExpression expr)
        {
            SymbolTable.Evaluate(cls.ClassDefinition);
            // Determine argument types
            var args = ArgumentSet.Empty(expr, this);
            var init = cls.GetMember <IPythonFunctionType>(@"__init__");

            if (init != null)
            {
                using (OpenScope(cls.DeclaringModule, cls.ClassDefinition, out _)) {
                    var a = new ArgumentSet(init, 0, cls, expr, this);
                    if (a.Errors.Count > 0)
                    {
                        // AddDiagnostics(Module.Uri, a.Errors);
                    }
                    args = a.Evaluate();
                }
            }
            return(cls.CreateInstance(args));
        }
Пример #7
0
        private void HandleTypedVariable(IPythonType variableType, IMember value, Expression expr)
        {
            // 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;
                }
            }
            var args = ArgumentSet.Empty(expr, Eval);

            instance = instance ?? variableType?.CreateInstance(args) ?? Eval.UnknownType.CreateInstance(ArgumentSet.WithoutContext);

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

            if (expr 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);
                }
            }
        }
        private IMember GetValueFromUnaryOp(UnaryExpression expr, string op, LookupOptions lookupOptions)
        {
            var target = GetValueFromExpression(expr.Expression, lookupOptions);

            if (target is IPythonInstance instance)
            {
                var fn = instance.GetPythonType()?.GetMember <IPythonFunctionType>(op);
                // Process functions declared in code modules. Scraped/compiled/stub modules do not actually perform any operations.
                if (fn?.DeclaringModule != null && (fn.DeclaringModule.ModuleType == ModuleType.User || fn.DeclaringModule.ModuleType == ModuleType.Library))
                {
                    var result = fn.Call(instance, op, ArgumentSet.Empty(expr, this));
                    if (!result.IsUnknown())
                    {
                        return(result);
                    }
                }
                return(instance is IPythonConstant c && instance.TryGetConstant <int>(out var value)
                    ? new PythonConstant(-value, c.Type)
                    : instance);
            }
            return(UnknownType);
        }
        public static IMember GetReturnValueFromAnnotation(ExpressionEval eval, Expression annotation)
        {
            if (eval == null || annotation == null)
            {
                return(null);
            }

            var annotationType = eval.GetTypeFromAnnotation(annotation, LookupOptions.All);

            if (annotationType.IsUnknown())
            {
                return(null);
            }

            // Annotations are typically types while actually functions return
            // instances unless specifically annotated to a type such as Type[T].
            // TODO: try constructing argument set from types. Consider Tuple[_T1, _T2] where _T1 = TypeVar('_T1', str, bytes)
            var t = annotationType.CreateInstance(ArgumentSet.Empty(annotation, eval));
            // If instance could not be created, such as when return type is List[T] and
            // type of T is not yet known, just use the type.
            var instance = t.IsUnknown() ? (IMember)annotationType : t;

            return(instance);
        }
Пример #10
0
        public IMember GetConstantFromLiteral(Expression expr)
        {
            if (expr is ConstantExpression ce)
            {
                switch (ce.Value)
                {
                case string s:
                    return(new PythonUnicodeString(s, Interpreter));

                case AsciiString b:
                    return(new PythonAsciiString(b, Interpreter));

                case int integer:
                    return(new PythonConstant(integer, Interpreter.GetBuiltinType(BuiltinTypeId.Int)));

                case bool b:
                    return(new PythonConstant(b, Interpreter.GetBuiltinType(BuiltinTypeId.Bool)));
                }
            }

            var t = SuppressBuiltinLookup ? UnknownType : (GetTypeFromLiteral(expr) ?? UnknownType);

            return(t.CreateInstance(ArgumentSet.Empty(expr, this)));
        }
 public override IMember Index(IArgumentSet args)
 => _collectionType.Index(this, args).GetPythonType().CreateInstance(ArgumentSet.Empty(args.Expression, args.Eval));
        public IReadOnlyList <IParameterInfo> CreateFunctionParameters(
            IPythonClassType self,
            IPythonClassMember function,
            FunctionDefinition fd,
            bool declareVariables)
        {
            // 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 = fd.Parameters.FirstOrDefault();
                if (p0 != null && !string.IsNullOrEmpty(p0.Name))
                {
                    var annType = GetTypeFromAnnotation(p0.Annotation, out var isGeneric);
                    // 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.
                    if (declareVariables)
                    {
                        DeclareVariable(p0.Name, self.CreateInstance(ArgumentSet.Empty(p0.NameExpression, this)),
                                        VariableSource.Declaration, p0.NameExpression);
                    }
                    // Set parameter info, declare type as annotation type for generic self
                    // e.g def test(self: T)
                    var pi = new ParameterInfo(Ast, p0, isGeneric ? annType : self, null, false);
                    parameters.Add(pi);
                    skip++;
                }
            }

            // Declare parameters in scope
            for (var i = skip; i < fd.Parameters.Length; i++)
            {
                var p = fd.Parameters[i];
                if (!string.IsNullOrEmpty(p.Name))
                {
                    var defaultValue = GetValueFromExpression(p.DefaultValue);
                    var paramType    = GetTypeFromAnnotation(p.Annotation, out var isGeneric) ?? UnknownType;
                    if (paramType.IsUnknown())
                    {
                        // 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): ...
                        paramType = GetTypeFromAnnotation(p.Annotation, out isGeneric, LookupOptions.Local | LookupOptions.Builtins);
                        // Default value of None does not mean the parameter is None, just says it can be missing.
                        defaultValue = defaultValue.IsUnknown() || defaultValue.IsOfType(BuiltinTypeId.None) ? null : defaultValue;
                        if (paramType == null && defaultValue != null)
                        {
                            paramType = defaultValue.GetPythonType();
                        }
                    }
                    // If all else fails, look up globally.
                    var pi = new ParameterInfo(Ast, p, paramType, defaultValue, isGeneric | paramType.IsGeneric());
                    if (declareVariables)
                    {
                        DeclareParameter(p, pi);
                    }
                    parameters.Add(pi);
                }
                else if (p.IsList || p.IsDictionary)
                {
                    parameters.Add(new ParameterInfo(Ast, p, null, null, false));
                }
            }
            return(parameters);
        }
 private IMember GetValueFromProperty(IPythonPropertyType p, IPythonInstance instance, CallExpression expr)
 {
     // Function may not have been walked yet. Do it now.
     SymbolTable.Evaluate(p.FunctionDefinition);
     return(instance.Call(p.Name, ArgumentSet.Empty(expr, this)));
 }
        private IMember GetValueFromMember(MemberExpression expr)
        {
            if (expr?.Target == null || string.IsNullOrEmpty(expr.Name))
            {
                return(null);
            }

            IPythonInstance instance = null;
            var             m        = GetValueFromExpression(expr.Target);

            if (m is IPythonType typeInfo)
            {
                var member = typeInfo.GetMember(expr.Name);
                // If container is class/type info rather than the instance, then the method is an unbound function.
                // Example: C.f where f is a method of C. Compare to C().f where f is bound to the instance of C.
                if (member is PythonFunctionType f && !f.IsStatic && !f.IsClassMethod)
                {
                    f.AddReference(GetLocationOfName(expr));
                    return(f.ToUnbound());
                }
                instance = new PythonInstance(typeInfo);
            }

            instance = instance ?? m as IPythonInstance;
            var type = m?.GetPythonType(); // Try inner type

            var value = type?.GetMember(expr.Name);

            type?.AddMemberReference(expr.Name, this, GetLocationOfName(expr));

            if (type is IPythonModule)
            {
                return(value);
            }

            // Class type GetMember returns a type. However, class members are
            // mostly instances (consider self.x = 1, x is an instance of int).
            // However, it is indeed possible to have them as types, like in
            //  class X ...
            //  class C: ...
            //      self.x = X
            // which is somewhat rare as compared to self.x = X() but does happen.

            switch (value)
            {
            case IPythonClassType _:
                return(value);

            case IPythonPropertyType prop:
                return(prop.Call(instance, prop.Name, ArgumentSet.Empty(expr, this)));

            case IPythonType p:
                return(new PythonBoundType(p, instance));

            case null:
                Log?.Log(TraceEventType.Verbose, $"Unknown member {expr.ToCodeString(Ast).Trim()}");
                return(UnknownType);

            default:
                return(value);
            }
        }
Пример #15
0
 public static Field Simple(string name)
 {
     return(new Field(string.Empty, name, ArgumentSet.Empty(), DirectiveSet.Empty(), SelectionSet.Empty()));
 }