// (clr-field-set! type field-name obj value) public override Expression Generate(object args, CodeBlock cb) { Type t = null; string type = null; bool inferred = false; object rtype = Builtins.First(args); ExtractTypeInfo(rtype, out t, out type, out inferred); string member = SymbolTable.IdToString((SymbolId)Builtins.Second(Builtins.Second(args))); BindingFlags bf = BindingFlags.Instance; Expression instance = GetAst(Builtins.Third(args), cb); if (instance is ConstantExpression && ((ConstantExpression)instance).Value == null) { bf = BindingFlags.Static; instance = null; if (inferred) { ClrSyntaxError("clr-field-set!", "type inference not possible on static member", member); } } else if (inferred) { if (instance is UnaryExpression && instance.Type == typeof(object)) { var ue = (UnaryExpression)instance; instance = ue.Operand; } t = instance.Type; } else { instance = ConvertToHelper(t, instance); } type = t.Name; FieldInfo fi = t.GetField(member, BindingFlags.Public | bf | BindingFlags.FlattenHierarchy); if (fi == null) { ClrSyntaxError("clr-field-set!", "field not found on type: " + type, args); } if (fi.IsLiteral) { ClrSyntaxError("clr-field-set!", "cannot set a constant field: " + type); } Expression value = GetAst(Builtins.Car(Builtins.LastPair(args)), cb); return(Ast.Comma(Ast.AssignField(instance, fi, value), Ast.ReadField(null, Unspecified))); }
internal override Expression ToExpression(MethodBinderContext context, IList <ArgBuilder> args, IList <Expression> parameters, Expression ret) { List <Expression> sets = new List <Expression>(); Variable tmp = null;// context.GetTemporary(ret.Type, "val"); for (int i = 0; i < _indexesUsed.Length; i++) { Expression value = parameters[parameters.Count - _kwArgCount + _indexesUsed[i]]; switch (_membersSet[i].MemberType) { case MemberTypes.Field: FieldInfo fi = (FieldInfo)_membersSet[i]; if (!fi.IsLiteral && !fi.IsInitOnly) { sets.Add(Ast.AssignField(Ast.Read(tmp), fi, Ast.ConvertHelper(value, fi.FieldType))); } else { // call a helper which throws the error but "returns object" sets.Add( Ast.Convert( Ast.Call( typeof(RuntimeHelpers).GetMethod("ReadOnlyAssignError"), Ast.Constant(true), Ast.Constant(fi.Name) ), fi.FieldType ) ); } break; case MemberTypes.Property: PropertyInfo pi = (PropertyInfo)_membersSet[i]; if (pi.GetSetMethod(ScriptDomainManager.Options.PrivateBinding) != null) { sets.Add(Ast.AssignProperty(Ast.Read(tmp), pi, Ast.ConvertHelper(value, pi.PropertyType))); } else { // call a helper which throws the error but "returns object" sets.Add( Ast.Convert( Ast.Call( typeof(RuntimeHelpers).GetMethod("ReadOnlyAssignError"), Ast.Constant(false), Ast.Constant(pi.Name) ), pi.PropertyType ) ); } break; } } Expression newCall = Ast.Comma( 0, ArrayUtils.Insert <Expression>( Ast.Assign(tmp, ret), sets.ToArray() ) ); return(_builder.ToExpression(context, args, parameters, newCall)); }
private void MakeFieldRule(Type targetType, MemberGroup fields) { FieldTracker field = (FieldTracker)fields[0]; if (field.DeclaringType.IsGenericType && field.DeclaringType.GetGenericTypeDefinition() == typeof(StrongBox <>)) { // work around a CLR bug where we can't access generic fields from dynamic methods. Type[] generic = field.DeclaringType.GetGenericArguments(); AddToBody( Rule.MakeReturn(Binder, MakeReturnValue( Ast.Call( typeof(BinderOps).GetMethod("UpdateBox").MakeGenericMethod(generic), Ast.ConvertHelper(Instance, field.DeclaringType), Ast.ConvertHelper(Rule.Parameters[1], generic[0]) ) ) ) ); } else if (field.IsInitOnly || field.IsLiteral || (field.IsStatic && targetType != field.DeclaringType)) // TODO: Field static check too python specific { AddToBody(Binder.MakeReadOnlyMemberError(Rule, targetType, StringName)); } else if (field.DeclaringType.IsValueType) { AddToBody(Rule.MakeError(Ast.New(typeof(ArgumentException).GetConstructor(new Type[] { typeof(string) }), Ast.Constant("cannot assign to value types")))); } else if (field.IsPublic && field.DeclaringType.IsVisible) { AddToBody( Rule.MakeReturn( Binder, MakeReturnValue( Ast.AssignField( field.IsStatic ? null : Ast.Convert(Rule.Parameters[0], field.DeclaringType), field.Field, Binder.ConvertExpression(Rule.Parameters[1], field.FieldType) ) ) ) ); } else { AddToBody( Rule.MakeReturn( Binder, MakeReturnValue( Ast.Call( Ast.ConvertHelper(Ast.RuntimeConstant(field.Field), typeof(FieldInfo)), typeof(FieldInfo).GetMethod("SetValue", new Type[] { typeof(object), typeof(object) }), field.IsStatic ? Ast.Null() : (Expression)Ast.ConvertHelper(Instance, typeof(object)), Ast.ConvertHelper(Rule.Parameters[1], typeof(object)) ) ) ) ); } }