Repository navigation
Expand file tree
/
Copy pathPythonTypeSlot.cs
More file actions
135 lines (118 loc) · 5 KB
/
Copy pathPythonTypeSlot.cs
File metadata and controls
135 lines (118 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Apache License, Version 2.0, please send an email to
* [email protected]. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
#if FEATURE_CORE_DLR
using System.Linq.Expressions;
#else
using Microsoft.Scripting.Ast;
#endif
using System.Dynamic;
using System.Runtime.InteropServices;
using IronPython.Runtime.Binding;
using IronPython.Runtime.Operations;
using Microsoft.Scripting.Utils;
using AstUtils = Microsoft.Scripting.Ast.Utils;
namespace IronPython.Runtime.Types {
using Ast = Expression;
/// <summary>
/// A TypeSlot is an item that gets stored in a type's dictionary. Slots provide an
/// opportunity to customize access at runtime when a value is get or set from a dictionary.
/// </summary>
[PythonType]
public class PythonTypeSlot {
/// <summary>
/// Gets the value stored in the slot for the given instance binding it to an instance if one is provided and
/// the slot binds to instances.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
internal virtual bool TryGetValue(CodeContext context, object instance, PythonType owner, out object value) {
value = null;
return false;
}
/// <summary>
/// Sets the value of the slot for the given instance.
/// </summary>
/// <returns>true if the value was set, false if it can't be set</returns>
internal virtual bool TrySetValue(CodeContext context, object instance, PythonType owner, object value) {
return false;
}
/// <summary>
/// Deletes the value stored in the slot from the instance.
/// </summary>
/// <returns>true if the value was deleted, false if it can't be deleted</returns>
internal virtual bool TryDeleteValue(CodeContext context, object instance, PythonType owner) {
return false;
}
internal virtual bool IsAlwaysVisible {
get {
return true;
}
}
/// <summary>
/// True if generating code for gets can result in more optimal accesses.
/// </summary>
internal virtual bool CanOptimizeGets {
get {
return false;
}
}
/// <summary>
/// Gets an expression which is used for accessing this slot. If the slot lookup fails the error expression
/// is used again.
///
/// The default implementation just calls the TryGetValue method. Subtypes of PythonTypeSlot can override
/// this and provide a more optimal implementation.
/// </summary>
internal virtual void MakeGetExpression(PythonBinder/*!*/ binder, Expression/*!*/ codeContext, DynamicMetaObject instance, DynamicMetaObject/*!*/ owner, ConditionalBuilder/*!*/ builder) {
ParameterExpression tmp = Ast.Variable(typeof(object), "slotTmp");
Expression call = Ast.Call(
typeof(PythonOps).GetMethod("SlotTryGetValue"),
codeContext,
AstUtils.Convert(AstUtils.WeakConstant(this), typeof(PythonTypeSlot)),
instance != null ? instance.Expression : AstUtils.Constant(null),
owner.Expression,
tmp
);
builder.AddVariable(tmp);
if (!GetAlwaysSucceeds) {
builder.AddCondition(
call,
tmp
);
} else {
builder.FinishCondition(Ast.Block(call, tmp));
}
}
/// <summary>
/// True if TryGetValue will always succeed, false if it may fail.
///
/// This is used to optimize away error generation code.
/// </summary>
internal virtual bool GetAlwaysSucceeds {
get {
return false;
}
}
internal virtual bool IsSetDescriptor(CodeContext context, PythonType owner) {
return false;
}
public virtual object __get__(CodeContext/*!*/ context, object instance, [DefaultParameterValue(null)]object typeContext) {
PythonType dt = typeContext as PythonType;
object res;
if (TryGetValue(context, instance, dt, out res))
return res;
throw PythonOps.AttributeErrorForMissingAttribute(dt == null ? "?" : dt.Name, "__get__");
}
}
}