/// <summary> /// Makes a new static field slot. Type is ignored. If we ever change ignoring type then we /// need to make BuiltinWrapper generic and update StaticFieldBuiltinSlot to get the correct /// type. /// </summary> public override Slot MakeSlot(Name name, Type type) { StaticFieldSlot fs; object builtin; if (!fields.TryGetValue(name, out fs)) { if (!TypeCache.Builtin.TryGetSlot(DefaultContext.Default, SymbolTable.StringToId(name.GetString()), out builtin)) { // name does not collide w/ a built-in name, define a real field. FieldBuilder fb = typeGen.myType.DefineField(name.GetString(), typeof(object), FieldAttributes.Public | FieldAttributes.Static); fs = new StaticFieldSlot(fb); } else { // name collides w/ a built-in name. Our field becomes strongly typed to // BuiltinWrapper. We then return a // StaticFieldBuiltinSlot which checks the value to see if it's a built-in or // not. FieldBuilder fb = typeGen.myType.DefineField(name.GetString(), typeof(BuiltinWrapper), FieldAttributes.Public | FieldAttributes.Static); fs = new StaticFieldBuiltinSlot(fb); } fields[name] = fs; } return(fs); }
// // This generates a method like the following: // // TryGetExtraValue(int name, object out value) { // if (name1 == name) { // value = type.name1Slot; // return true; // } // if (name2 == name) { // value = type.name2Slot; // return true; // } // ... // return false // } private void MakeGetMethod() { CodeGen cg = tg.DefineMethodOverride(typeof(CustomFieldIdDict).GetMethod("TryGetExtraValue")); foreach (KeyValuePair <Name, Slot> entry in names.Slots) { cg.EmitSymbolIdInt(entry.Key.GetString()); cg.EmitArgAddr(0); cg.EmitFieldGet(typeof(SymbolId), "Id"); Label next = cg.DefineLabel(); cg.Emit(OpCodes.Bne_Un, next); cg.EmitArgGet(1); // ugly special casing builtins this way, but they're special... // Builtins can be in one of two states: // Not defined, but available internally to the module // Defined, and exposed externally from the module. // In both cases we have static fields for these, and we're in the custom dict. // // Therefore we keep track of which state they're in w/ a wrapper object, // and here we need to emit the real value, not the value that's availble // internally to the module. StaticFieldBuiltinSlot builtin = entry.Value as StaticFieldBuiltinSlot; if (builtin == null) { entry.Value.EmitGet(cg); } else { builtin.EmitGetRaw(cg); } cg.Emit(OpCodes.Stind_Ref); cg.EmitInt(1); cg.EmitReturn(); cg.MarkLabel(next); } cg.EmitInt(0); cg.EmitReturn(); cg.Finish(); }