Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

193 lines
5.8 KiB
C#

//
// DynamicContext.cs
//
// Authors:
// Marek Safar <marek.safar@gmail.com>
//
// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Dynamic;
using Compiler = Mono.CSharp;
using System.Reflection;
using System.Collections.Generic;
namespace Microsoft.CSharp.RuntimeBinder
{
class DynamicContext
{
static DynamicContext dc;
static object compiler_initializer = new object ();
static object lock_object = new object ();
readonly Compiler.ModuleContainer module;
readonly Compiler.ReflectionImporter importer;
private DynamicContext (Compiler.ModuleContainer module, Compiler.ReflectionImporter importer)
{
this.module = module;
this.importer = importer;
}
public Compiler.CompilerContext CompilerContext {
get {
return module.Compiler;
}
}
public Compiler.ModuleContainer Module {
get {
return module;
}
}
public static DynamicContext Create ()
{
if (dc != null)
return dc;
lock (compiler_initializer) {
if (dc != null)
return dc;
var settings = new Compiler.CompilerSettings () {
WarningLevel = 0
};
var cc = new Compiler.CompilerContext (settings, ErrorPrinter.Instance) {
IsRuntimeBinder = true
};
//
// Any later loaded assemblies are handled internally by GetAssemblyDefinition
// domain.AssemblyLoad cannot be used as that would be too destructive as we
// would hold all loaded assemblies even if they can be never visited
//
// TODO: Remove this code and rely on GetAssemblyDefinition only
//
var module = new Compiler.ModuleContainer (cc);
module.HasTypesFullyDefined = true;
// Setup fake assembly, it's used mostly to simplify checks like friend-access
var temp = new Compiler.AssemblyDefinitionDynamic (module, "dynamic");
module.SetDeclaringAssembly (temp);
var importer = new Compiler.ReflectionImporter (module, cc.BuiltinTypes) {
IgnorePrivateMembers = false
};
// Import all currently loaded assemblies
// TODO: Rewrite this to populate type cache on-demand, that should greatly
// reduce our start-up cost
var domain = AppDomain.CurrentDomain;
foreach (var a in AppDomain.CurrentDomain.GetAssemblies ()) {
importer.ImportAssembly (a, module.GlobalRootNamespace);
}
cc.BuiltinTypes.CheckDefinitions (module);
module.InitializePredefinedTypes ();
dc = new DynamicContext (module, importer);
}
return dc;
}
//
// Creates mcs expression from dynamic object
//
public Compiler.Expression CreateCompilerExpression (CSharpArgumentInfo info, DynamicMetaObject value)
{
//
// No type details provider, go with runtime type
//
if (info == null) {
if (value.LimitType == typeof (object))
return new Compiler.NullLiteral (Compiler.Location.Null);
return new Compiler.RuntimeValueExpression (value, ImportType (value.RuntimeType));
}
//
// Value is known to be a type
//
if ((info.Flags & CSharpArgumentInfoFlags.IsStaticType) != 0)
return new Compiler.TypeExpression (ImportType ((Type) value.Value), Compiler.Location.Null);
if (value.Value == null &&
(info.Flags & (CSharpArgumentInfoFlags.IsOut | CSharpArgumentInfoFlags.IsRef | CSharpArgumentInfoFlags.UseCompileTimeType)) == 0 &&
value.LimitType == typeof (object)) {
return new Compiler.NullLiteral (Compiler.Location.Null);
}
//
// Use compilation time type when type was known not to be dynamic during compilation
//
Type value_type = (info.Flags & CSharpArgumentInfoFlags.UseCompileTimeType) != 0 ? value.Expression.Type : value.LimitType;
var type = ImportType (value_type);
if ((info.Flags & CSharpArgumentInfoFlags.Constant) != 0) {
var c = Compiler.Constant.CreateConstantFromValue (type, value.Value, Compiler.Location.Null);
//
// It can be null for misused Constant flag
//
if (c != null)
return c;
}
return new Compiler.RuntimeValueExpression (value, type);
}
//
// Creates mcs arguments from dynamic argument info
//
public Compiler.Arguments CreateCompilerArguments (IEnumerable<CSharpArgumentInfo> info, DynamicMetaObject[] args)
{
var res = new Compiler.Arguments (args.Length);
int pos = 0;
// enumerates over args
foreach (var item in info) {
var expr = CreateCompilerExpression (item, args[pos++]);
if (item.IsNamed) {
res.Add (new Compiler.NamedArgument (item.Name, Compiler.Location.Null, expr, item.ArgumentModifier));
} else {
res.Add (new Compiler.Argument (expr, item.ArgumentModifier));
}
if (pos == args.Length)
break;
}
return res;
}
public Compiler.TypeSpec ImportType (Type type)
{
lock (lock_object) {
return importer.ImportType (type);
}
}
}
}