/// <summary> /// Creates reference to variable and resolves to it's type /// </summary> public static RppId StaticId(RppVar rppVar) { RppId classParamInput = Id(rppVar.Name); SymbolTable symbolTable = new SymbolTable(); symbolTable.AddLocalVar(rppVar.Name, rppVar.Type.Value, rppVar); classParamInput.Analyze(symbolTable, new Diagnostic()); return classParamInput; }
private static void LoadValFromRef(RppVar node, ILGenerator body, Dictionary<LocalBuilder, Tuple<FieldBuilder, Type>> capturedVars) { Type varType = node.Type.Value.NativeType; body.Emit(OpCodes.Ldfld, GetRefElemField(GetRefType(varType))); if (varType.IsClass) { Type varTypeInClosureContext = capturedVars == null ? varType : capturedVars[node.Builder].Item2; body.Emit(OpCodes.Castclass, varTypeInClosureContext); } }
public static void Load(RppVar node, ILGenerator body, Dictionary<LocalBuilder, Tuple<FieldBuilder, Type>> capturedVars) { if (node.IsCaptured) { LoadRef(node, body, capturedVars); LoadValFromRef(node, body, capturedVars); } else { body.Emit(OpCodes.Ldloc, node.Builder); } }
/// <summary> /// If var is primitive, then instance of <c>Ref<primitiveType></c> is created. If /// var is class, then <c>Ref<object></c> is created because <c>Reflection.Emit</c> doesn't let /// me create instance of generic type with type builder as parameters (or actually it let's me create /// but I can't get constructors). So we have to cast everytime we load value from <c>elem</c>. /// </summary> private static void Declare(RppVar node, ILGenerator body, bool initialize) { Type varType = node.Type.Value.NativeType; if (node.IsCaptured) { Type elementType = varType; varType = GetRefType(varType); ConstructorInfo constructor = initialize ? GetSpecificConstructor(varType, elementType) : varType.GetConstructor(Type.EmptyTypes); Debug.Assert(constructor != null, "constructor != null"); body.Emit(OpCodes.Newobj, constructor); initialize = true; } node.Builder = body.DeclareLocal(varType); node.Builder.SetLocalSymInfo(node.Name); if (initialize) { body.Emit(OpCodes.Stloc, node.Builder); } }
public override void Visit(RppVar node) { if (!(node.InitExpr is RppEmptyExpr) && !(node.InitExpr is RppDefaultExpr)) { node.InitExpr.Accept(this); ClrVarCodegen.DeclareAndInitialize(node, _body); } else { ClrVarCodegen.Declare(node, _body); } }
private static void LoadRef(RppVar node, ILGenerator body, Dictionary<LocalBuilder, Tuple<FieldBuilder, Type>> capturedVars) { if (capturedVars != null) { FieldBuilder field = capturedVars[node.Builder].Item1; body.Emit(OpCodes.Ldarg_0); body.Emit(OpCodes.Ldfld, field); } else { // When we access captured variable not from a closure, we need to load it almost as if we would do it from a closure body.Emit(OpCodes.Ldloc, node.Builder); } }
public static void DeclareAndInitialize(RppVar node, ILGenerator body) { Declare(node, body, true); }
public static void Store(RppVar node, ILGenerator body, Dictionary<LocalBuilder, Tuple<FieldBuilder, Type>> capturedVars) { if (node.IsCaptured) { // TODO this is not very optimal, we save what's on stack to local var, loading this.refField and then // loading temp var and storing then to this.refField.elem // This is needed because clr want's to have this, field, value -> on stack Type varType = node.Type.Value.NativeType; LocalBuilder tempVar = body.DeclareLocal(varType); body.Emit(OpCodes.Stloc, tempVar); LoadRef(node, body, capturedVars); body.Emit(OpCodes.Ldloc, tempVar); body.Emit(OpCodes.Stfld, GetRefElemField(GetRefType(varType))); } else { body.Emit(OpCodes.Stloc, node.Builder); } }
public static void Declare(RppVar node, ILGenerator body) { Declare(node, body, false); }