Show ClassDef.cs syntax highlighted
/* **********************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This source code is subject to terms and conditions of the Shared Source License
* for IronPython. A copy of the license can be found in the License.html file
* at the root of this distribution. If you can not locate the Shared Source License
* for IronPython, please send an email to ironpy@microsoft.com.
* By using this source code in any fashion, you are agreeing to be bound by
* the terms of the Shared Source License for IronPython.
*
* You must not remove this notice, or any other, from this software.
*
* **********************************************************************************/
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.CodeDom;
using System.Text.RegularExpressions;
using System.Diagnostics;
using IronPython.Runtime;
using IronPython.Runtime.Operations;
using IronPython.Runtime.Calls;
using IronPython.CodeDom;
using IronPython.Compiler.Generation;
namespace IronPython.Compiler.Ast {
/// <summary>
/// Summary description for ClassDef.
/// </summary>
public class ClassDefinition : ScopeStatement {
private Location header;
private SymbolId name;
private Expression[] bases;
private static int index = 0;
public ClassDefinition(SymbolId name, Expression[] bases, Statement body)
: base(body) {
this.name = name;
this.bases = bases;
}
public Location Header {
get { return header; }
set { header = value; }
}
public SymbolId Name {
get { return name; }
set { name = value; }
}
public IList<Expression> Bases {
get { return bases; }
}
internal override void Emit(CodeGen cg) {
cg.EmitPosition(Start, header);
CodeGen icg = CreateClassMaker(cg);
try {
// emit call to MakeClass(ICallerContext mod, string modName, string name, Tuple bases, IDictionary<object, object> vars)
// ICallerContext mod
cg.EmitModuleInstance();
// string modName (can't pull from context, could be changed)
cg.EmitGetGlobal(SymbolTable.Name);
cg.Emit(OpCodes.Castclass, typeof(string));
// class name
cg.EmitString(name.GetString());
// bases array
cg.EmitObjectArray(bases);
cg.EmitCall(typeof(Ops), "MakeTuple");
// vars
cg.EmitEnvironmentOrNull();
cg.EmitContextOrNull();
cg.EmitCall(icg.MethodInfo);
cg.EmitCall(typeof(Ops), "MakeClass");
// store result to class name
cg.EmitSet(name);
} finally {
icg.Dispose();
}
}
private CodeGen CreateClassMaker(CodeGen cg) {
Type[] signature = new Type[2];
signature[0] = IsClosure ? cg.EnvironmentSlot.Type : typeof(FunctionEnvironmentDictionary);
signature[1] = cg.ContextSlot != null ? cg.ContextSlot.Type : typeof(ICallerContext);
Debug.Assert(typeof(IModuleScope).IsAssignableFrom(signature[0]));
Debug.Assert(typeof(ICallerContext).IsAssignableFrom(signature[1]));
CodeGen icg = cg.DefineUserHiddenMethod(name.GetString() + "$maker" + System.Threading.Interlocked.Increment(ref index),
typeof(IDictionary<object, object>), signature);
if (IsClosure) icg.StaticLinkSlot = icg.GetArgumentSlot(0);
if (cg.ContextSlot != null) icg.ContextSlot = icg.GetArgumentSlot(1);
if (icg.ContextSlot != null) {
icg.ModuleSlot = new PropertySlot(icg.ContextSlot, typeof(ICallerContext).GetProperty("Module"));
} else if (icg.StaticLinkSlot != null) {
icg.ModuleSlot = new PropertySlot(icg.ContextSlot, typeof(ICallerContext).GetProperty("Module"));
}
icg.Names = CodeGen.CreateLocalNamespace(icg);
icg.Context = cg.Context;
// emit class initialization
EmitClassInitialization(cg, icg);
icg.EnvironmentSlot.EmitGet(icg);
icg.Emit(OpCodes.Ret);
return icg;
}
private void EmitClassInitialization(CodeGen cg, CodeGen icg) {
// Populate the namespace with slots
PrepareForEmit(cg, icg);
Body.Emit(icg);
}
internal void PrepareForEmit(CodeGen cg, CodeGen icg) {
Debug.Assert(cg != null, "null codegen");
Debug.Assert(icg != null, "null init codegen");
PromoteLocalsToEnvironment();
icg.ContextSlot = icg.EnvironmentSlot = CreateEnvironment(icg);
CreateGlobalSlots(icg, cg);
CreateClosureSlots(icg);
// Detect class locals that may be used uninitialized
// and create global-backed slots for them
FlowChecker.Check(this);
CreateBackedSlots(icg);
string doc = Body.Documentation;
if (doc != null) {
icg.EmitString(doc);
icg.EmitSet(SymbolTable.Doc);
}
}
private void CreateBackedSlots(CodeGen icg) {
foreach (KeyValuePair<SymbolId, Binding> kv in Names) {
if (kv.Value.IsLocal && kv.Value.Uninitialized) {
Slot global = icg.Names.Globals.GetOrMakeSlot(kv.Key);
Slot attribute = icg.Names.Slots[kv.Key];
icg.Names.Slots[kv.Key] = new GlobalBackedSlot(attribute, global);
}
}
}
public override void Walk(IAstWalker walker) {
if (walker.Walk(this)) {
foreach (Expression e in bases) e.Walk(walker);
Body.Walk(walker);
}
walker.PostWalk(this);
}
}
}
See more files for this project here