-
Notifications
You must be signed in to change notification settings - Fork 86
createthrow runtime binding helper
As we noted in the high-level description of execution flow when searching for a binding rule, DynamicMetaObjects and binders should NEVER throw when they fail to bind an operation. Of course, they throw if there's some internal integrity error, but when they cannot produce a binding for an operation, they should return a DynamicMetaObject representing a Throw expression of an appropriate error so that the binding process finishes smoothly. The reason is that another DynamicMetaObject or binder down the chain of execution might handle the operation. There are situations described later where DynamicMetaObjects call on binders to get their rule or error meta-object to fold those into the result the DynamicMetaObject produces.
Since there's enough boiler plate code to creating this ThrowExpression, Sympl has a runtime helper function in the RuntimeHelpers class from runtime.cs:
public static DynamicMetaObject CreateThrow
(DynamicMetaObject target, DynamicMetaObject[] args,
BindingRestrictions moreTests,
Type exception, params object[] exceptionArgs) {
Expression[] argExprs = null;
Type[] argTypes = Type.EmptyTypes;
int i;
if (exceptionArgs != null) {
i = exceptionArgs.Length;
argExprs = new Expression[i];
argTypes = new Type[i];
i = 0;
foreach (object o in exceptionArgs) {
Expression e = Expression.Constant(o);
argExprs[i] = e;
argTypes[i] = e.Type;
i += 1;
}
}
ConstructorInfo constructor =
exception.GetConstructor(argTypes);
if (constructor == null) {
throw new ArgumentException(
"Type doesn't have constructor with a given signature");
}
return new DynamicMetaObject(
Expression.Throw(
Expression.New(constructor, argExprs),
typeof(object)),
target.Restrictions.Merge(
BindingRestrictions.Combine(args)).Merge(moreTests));
This function takes the target and arguments that were passed to a binder's FallbackX method. Since this ThrowExpression is a binding result (and therefore a rule), it is important to put the right restrictions on it. Otherwise, the rule might fire as a false positives and throw when a successful binding could be found. CreateThrow takes moreTests for this purpose. The function also takes the exception type and arguments for the ThrowExpression.
If there are any arguments to the Exception constructor, CreateThrow gathers their types and Constant expressions for each value. Then it looks up the constructor using the argument types.
CreateThrow passes the object type to the Throw factory to ensure the ThrowExpression's Type property represents the object type. Though Throw never really returns, its factory has this overload precisely to support the strict typing model of Expression Trees. The DLR CallSites use the Expression.Type property also to ensure DynamicMetaObjects and binders return implementations for operations that is strictly typed as assignable to object. For more information on why, see section 3.2.4.
The resulting DynamicMetaObject has default restrictions like Sympl puts on almost all rules its binders produce. Since the restrictions for throwing need to match the restrictions a binder would have produced for a positive rule, there are a couple of calls to CreateThrow that pass several restrictions they got from RuntimeHelpers.GetTargetArgsRestrictions. These restrictions duplicate the default restrictions CreateThrow adds, but fortunately the DLR removes duplicates restrictions when it produces the final expression in DynamicMetaObjectBinder.
Frontmatter
1 Introduction
1.1 Sources
1.2 Walkthrough Organization
2 Quick Language Overview
3 Walkthrough of Hello World
3.1 Quick Code Overview
3.2 Hosting, Globals, and .NET Namespaces Access
3.2.1 DLR Dynamic Binding and Interoperability -- a Very Quick Description
3.2.2 DynamicObjectHelpers
3.2.3 TypeModels and TypeModelMetaObjects
3.2.4 TypeModelMetaObject's BindInvokeMember -- Finding a Binding
3.2.5 TypeModelMetaObject.BindInvokeMember -- Restrictions and Conversions
3.3 Import Code Generation and File Module Scopes
3.4 Function Call and Dotted Expression Code Generation
3.4.1 Analyzing Function and Member Invocations
3.4.2 Analyzing Dotted Expressions
3.4.3 What Hello World Needs
3.5 Identifier and File Globals Code Generation
3.6 Sympl.ExecuteFile and Finally Running Code
4 Assignment to Globals and Locals
5 Function Definition and Dynamic Invocations
5.1 Defining Functions
5.2 SymplInvokeBinder and Binding Function Calls
6 CreateThrow Runtime Binding Helper
7 A Few Easy, Direct Translations to Expression Trees
7.1 Let* Binding
7.2 Lambda Expressions and Closures
7.3 Conditional (IF) Expressions
7.4 Eq Expressions
7.5 Loop Expressions
8 Literal Expressions
8.1 Integers and Strings
8.2 Keyword Constants
8.3 Quoted Lists and Symbols
8.3.1 AnalyzeQuoteExpr -- Code Generation
8.3.2 Cons and List Keyword Forms and Runtime Support
9 Importing Sympl Libraries and Accessing and Invoking Their Globals
10 Type instantiation
10.1 New Keyword Form Code Generation
10.2 Binding CreateInstance Operations in TypeModelMetaObject
10.3 Binding CreateInstance Operations in FallbackCreateInstance
10.4 Instantiating Arrays and GetRuntimeTypeMoFromModel
11 SymplGetMemberBinder and Binding .NET Instance Members
12 ErrorSuggestion Arguments to Binder FallbackX Methods
13 SymplSetMemberBinder and Binding .NET Instance Members
14 SymplInvokeMemberBinder and Binding .NET Member Invocations
14.1 FallbackInvokeMember
14.2 FallbackInvoke
15 Indexing Expressions: GetIndex and SetIndex
15.1 SymplGetIndexBinder's FallbackGetIndex
15.2 GetIndexingExpression
15.3 SymplSetIndexBinder's FallbackSetIndex
16 Generic Type Instantiation
17 Arithmetic, Comparison, and Boolean Operators
17.1 Analysis and Code Generation for Binary Operations
17.2 Analysis and Code Generation for Unary Operations
17.3 SymplBinaryOperationBinder
17.4 SymplUnaryOperationBinder
18 Canonical Binders or L2 Cache Sharing
19 Binding COM Objects
20 Using Defer When MetaObjects Have No Value
21 SymPL Language Description
21.1 High-level
21.2 Lexical Aspects
21.3 Built-in Types
21.4 Control Flow
21.4.1 Function Call
21.4.2 Conditionals
21.4.3 Loops
21.4.4 Try/Catch/Finally and Throw
21.5 Built-in Operations
21.6 Globals, Scopes, and Import
21.6.1 File Scopes and Import
21.6.2 Lexical Scoping
21.6.3 Closures
21.7 Why No Classes
21.8 Keywords
21.9 Example Code (mostly from test.sympl)
22 Runtime and Hosting
22.1 Class Summary
23 Appendixes
23.1 Supporting the DLR Hosting APIs
23.1.1 Main and Example Host Consumer
23.1.2 Runtime.cs Changes
23.1.3 Sympl.cs Changes
23.1.4 Why Not Show Using ScriptRuntime.Globals Namespace Reflection
23.1.5 The New DlrHosting.cs File
23.2 Using the Codeplex.com DefaultBinder for rich .NET interop
23.3 Using Codeplex.com Namespace/Type Trackers instead of ExpandoObjects
23.4 Using Codeplex.com GeneratorFunctionExpression
Other documents:
Dynamic Language Runtime
DLR Hostirng Spec
Expression Trees v2 Spec
Getting Started with the DLR as a Library Author
Sites, Binders, and Dynamic Object Interop Spec