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); }
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 }
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); }
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)); } } } }
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 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); } }
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)); }
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); }
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)); } }