private XamlIlNodeEmitResult EmitCore(IXamlIlAstNode value, IXamlIlCodeGen codeGen) { XamlIlNodeEmitResult res = null; foreach (var e in _emitters) { if (e is IXamlIlAstNodeEmitter ve) { res = ve.Emit(value, this, codeGen); if (res != null) { return(res); } } } if (value is IXamlIlAstEmitableNode en) { return(en.Emit(this, codeGen)); } else { throw new XamlIlLoadException("Unable to find emitter for node type: " + value.GetType().FullName, value); } }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode value, IXamlIlCodeGen codeGen, IXamlIlType expectedType) { var res = EmitCore(value, codeGen); var returnedType = res.ReturnType; if (returnedType != null || expectedType != null) { if (returnedType != null && expectedType == null) { throw new XamlIlLoadException( $"Emit of node {value} resulted in {returnedType.GetFqn()} while caller expected void", value); } if (expectedType != null && returnedType == null) { throw new XamlIlLoadException( $"Emit of node {value} resulted in void while caller expected {expectedType.GetFqn()}", value); } if (!expectedType.IsAssignableFrom(returnedType)) { throw new XamlIlLoadException( $"Emit of node {value} resulted in {returnedType.GetFqn()} which is not convertible to expected {expectedType.GetFqn()}", value); } if (returnedType.IsValueType && !expectedType.IsValueType) { codeGen.Generator.Emit(OpCodes.Box, returnedType); } } return(res); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlCodeGen codeGen) { var type = TargetType.GetClrType(); var member = ResolveMember(type); if (member is IXamlIlProperty prop) { codeGen.Generator.Emit(OpCodes.Call, prop.Getter); return(XamlIlNodeEmitResult.Type(prop.Getter.ReturnType)); } else if (member is IXamlIlField field) { if (field.IsLiteral) { var ftype = field.FieldType.IsEnum ? field.FieldType.GetEnumUnderlyingType() : field.FieldType; if (ftype.Name == "UInt64" || ftype.Name == "Int64") { codeGen.Generator.Emit(OpCodes.Ldc_I8, TypeSystemHelpers.ConvertLiteralToLong(field.GetLiteralValue())); } else if (ftype.Name == "Double") { codeGen.Generator.Emit(OpCodes.Ldc_R8, (double)field.GetLiteralValue()); } else if (ftype.Name == "Single") { codeGen.Generator.Emit(OpCodes.Ldc_R4, (float)field.GetLiteralValue()); } else if (ftype.Name == "String") { codeGen.Generator.Emit(OpCodes.Ldstr, (string)field.GetLiteralValue()); } else { codeGen.Generator.Emit(OpCodes.Ldc_I4, TypeSystemHelpers.ConvertLiteralToInt(field.GetLiteralValue())); } } else { codeGen.Generator.Emit(OpCodes.Ldsfld, field); } return(XamlIlNodeEmitResult.Type(field.FieldType)); } else { throw new XamlIlLoadException( $"Unable to resolve {Member} as static field, property, constant or enum value", this); } }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlCodeGen codeGen) { var type = Value.GetClrType(); var method = _systemType.Methods.FirstOrDefault(m => m.Name == "GetTypeFromHandle" && m.Parameters.Count == 1 && m.Parameters[0].Name == "RuntimeTypeHandle"); if (method == null) { throw new XamlIlTypeSystemException( $"Unable to find GetTypeFromHandle(RuntimeTypeHandle) on {_systemType.GetFqn()}"); } codeGen.Generator .Emit(OpCodes.Ldtoken, type) .Emit(OpCodes.Call, method); return(XamlIlNodeEmitResult.Type(_systemType)); }
/// <summary> /// populate = true: /// void Populate(IServiceProvider sp, T target); /// populate = false /// T Build(IServiceProvider sp); /// </summary> public void Compile(IXamlIlAstNode root, IXamlIlCodeGen codeGen, XamlIlContext context, bool populate) { var contextLocal = codeGen.Generator.DefineLocal(context.ContextType); codeGen.Generator .Emit(OpCodes.Ldarg_0) .Emit(OpCodes.Newobj, context.Constructor) .Emit(OpCodes.Stloc, contextLocal); var rootGrp = (XamlIlValueWithManipulationNode)root; var emitContext = new XamlIlEmitContext(_configuration, context, contextLocal, Emitters); if (populate) { codeGen.Generator .Emit(OpCodes.Ldloc, contextLocal) .Emit(OpCodes.Ldarg_1) .Emit(OpCodes.Stfld, context.RootObjectField) .Emit(OpCodes.Ldarg_1); emitContext.Emit(rootGrp.Manipulation, codeGen, null); codeGen.Generator.Emit(OpCodes.Ret); } else { codeGen.Generator.Emit(OpCodes.Ldloc, contextLocal); emitContext.Emit(rootGrp.Value, codeGen, rootGrp.Value.Type.GetClrType()); codeGen.Generator .Emit(OpCodes.Stfld, context.RootObjectField); codeGen.Generator .Emit(OpCodes.Ldloc, contextLocal) .Emit(OpCodes.Ldfld, context.RootObjectField) .Emit(OpCodes.Dup); emitContext.Emit(rootGrp.Manipulation, codeGen, null); codeGen.Generator.Emit(OpCodes.Ret); } }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (Constant is string) { codeGen.Generator.Emit(OpCodes.Ldstr, (string)Constant); } else if (Constant is long || Constant is ulong) { codeGen.Generator.Emit(OpCodes.Ldc_I8, TypeSystemHelpers.ConvertLiteralToLong(Constant)); } else if (Constant is float f) { codeGen.Generator.Emit(OpCodes.Ldc_R4, f); } else if (Constant is double d) { codeGen.Generator.Emit(OpCodes.Ldc_R8, d); } else { codeGen.Generator.Emit(OpCodes.Ldc_I4, TypeSystemHelpers.ConvertLiteralToInt(Constant)); } return(XamlIlNodeEmitResult.Type(Type.GetClrType())); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlPropertyValueManipulationNode pvm)) { return(null); } codeGen.Generator.Emit(pvm.Property.Getter.IsStatic ? OpCodes.Call : OpCodes.Callvirt, pvm.Property.Getter); context.Emit(pvm.Manipulation, codeGen, null); return(XamlIlNodeEmitResult.Void); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlManipulationGroupNode group)) { return(null); } if (group.Children.Count == 0) { codeGen.Generator.Emit(OpCodes.Pop); } else { for (var c = 0; c < group.Children.Count; c++) { if (c != group.Children.Count - 1) { codeGen.Generator.Emit(OpCodes.Dup); } context.Emit(group.Children[c], codeGen, null); } } return(XamlIlNodeEmitResult.Void); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlAstNewClrObjectNode n)) { return(null); } var type = n.Type.GetClrType(); var argTypes = n.Arguments.Select(a => a.Type.GetClrType()).ToList(); var ctor = type.FindConstructor(argTypes); if (ctor == null) { throw new XamlIlLoadException( $"Unable to find public constructor for type {type.GetFqn()}({string.Join(", ", argTypes.Select(at => at.GetFqn()))})", n); } for (var c = 0; c < n.Arguments.Count; c++) { var ctorArg = n.Arguments[c]; context.Emit(ctorArg, codeGen, ctor.Parameters[c]); } var gen = codeGen.Generator .Emit(OpCodes.Newobj, ctor); return(XamlIlNodeEmitResult.Type(type)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlInstanceMethodCallBaseNode mc)) { return(null); } for (var c = 0; c < mc.Arguments.Count; c++) { context.Emit(mc.Arguments[c], codeGen, mc.Method.Parameters[c]); } codeGen.Generator.Emit(mc.Method.IsStatic ? OpCodes.Call : OpCodes.Callvirt, mc.Method); var isVoid = mc.Method.ReturnType.Equals(context.Configuration.WellKnownTypes.Void); if (mc is XamlIlInstanceNoReturnMethodCallNode && !isVoid) { codeGen.Generator.Emit(OpCodes.Pop); } if (mc is XamlIlStaticReturnMethodCallNode && isVoid) { throw new XamlIlLoadException( $"XamlIlStaticReturnMethodCallNode expects a value while {mc.Method.Name} returns void", node); } return(isVoid ? XamlIlNodeEmitResult.Void : XamlIlNodeEmitResult.Type(mc.Method.ReturnType)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlValueWithManipulationNode vwm)) { return(null); } var created = context.Emit(vwm.Value, codeGen, vwm.Type.GetClrType()); if (vwm.Manipulation != null && !(vwm.Manipulation is XamlIlManipulationGroupNode grp && grp.Children.Count == 0)) { codeGen.Generator.Emit(OpCodes.Dup); context.Emit(vwm.Manipulation, codeGen, null); } return(XamlIlNodeEmitResult.Type(created.ReturnType)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlPropertyAssignmentNode an)) { return(null); } var callOp = an.Property.Setter.IsStatic ? OpCodes.Call : OpCodes.Callvirt; context.Emit(an.Value, codeGen, an.Property.Setter.Parameters.Last()); codeGen.Generator.Emit(callOp, an.Property.Setter); return(XamlIlNodeEmitResult.Void); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlCodeGen codeGen) { codeGen.Generator.Emit(OpCodes.Ldnull); return(XamlIlNodeEmitResult.Type(XamlIlPseudoType.Null)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlMarkupExtensionNode me)) { return(null); } var ptype = me.Manipulation?.Parameters[0] ?? me.Property.PropertyType; var rtype = me.ProvideValue.ReturnType; context.Emit(me.Value, codeGen, me.Value.Type.GetClrType()); if (me.ProvideValue.Parameters.Count != 0) { //TODO: IProvideValueTarget codeGen.Generator .Emit(OpCodes.Ldloc, context.ContextLocal); } var resultLocal = codeGen.Generator.DefineLocal(rtype); codeGen.Generator .Emit(OpCodes.Call, me.ProvideValue) .Emit(OpCodes.Stloc, resultLocal); IXamlIlEmitter CallSetter() { if (me.Manipulation != null) { // {target}.{Property}.{Method)(res) var res = codeGen.Generator.DefineLocal(ptype); if (me.Property != null) { codeGen.Generator .Emit(OpCodes.Stloc, res) .EmitCall(me.Property.Getter) .Emit(OpCodes.Ldloc, res); } codeGen.Generator .EmitCall(me.Manipulation, true); return(codeGen.Generator); } return(codeGen.Generator.EmitCall(me.Property.Setter)); } // Now we have the value returned by markup extension in resultLocal //Simplest case: exact type match if (ptype.Equals(rtype)) { codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal); CallSetter(); return(XamlIlNodeEmitResult.Void); } var exit = codeGen.Generator.DefineLabel(); if (ptype.IsValueType && rtype.IsValueType) { // If both are value types, try convert non-nullable to nullable if (ptype.IsNullableOf(rtype)) { codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Newobj, ptype.Constructors.First(c => c.Parameters.Count == 1 && c.Parameters[0].Equals(rtype))); CallSetter(); return(XamlIlNodeEmitResult.Void); } } else if (rtype.IsValueType && !ptype.IsValueType) { // If target is object, simply box if (ptype.Equals(context.Configuration.WellKnownTypes.Object)) { codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Box, rtype); CallSetter(); return(XamlIlNodeEmitResult.Void); } } else if (ptype.IsValueType) { // Cast attempt only makes sense if it's an object if (rtype.Equals(context.Configuration.WellKnownTypes.Object)) { var notMatchedType = codeGen.Generator.DefineLabel(); codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Isinst, ptype) .Emit(OpCodes.Brfalse, notMatchedType) .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Unbox_Any, ptype); CallSetter() .Emit(OpCodes.Br, exit) .MarkLabel(notMatchedType); } } else { // if(res==null) target.Property = null; var notNull = codeGen.Generator.DefineLabel(); codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Brtrue, notNull) .Emit(OpCodes.Ldloc, resultLocal); CallSetter() .Emit(OpCodes.Br, exit) .MarkLabel(notNull); // if (res is T matched) target.Property = matched; var nonMatchedType = codeGen.Generator.DefineLabel(); codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Isinst, ptype) .Emit(OpCodes.Dup) .Emit(OpCodes.Brfalse, nonMatchedType); CallSetter(); codeGen.Generator.Emit(OpCodes.Br, exit) .MarkLabel(nonMatchedType) .Emit(OpCodes.Pop); } // Cast attempts have failed, call external method codeGen.Generator .Emit(OpCodes.Ldstr, me.Property?.Name) .Emit(OpCodes.Ldloc, context.ContextLocal) .Emit(OpCodes.Ldloc, resultLocal); if (rtype.IsValueType) { codeGen.Generator.Emit(OpCodes.Box, rtype); } codeGen.Generator .Emit(OpCodes.Call, context.Configuration.TypeMappings.ApplyNonMatchingMarkupExtension) .Emit(OpCodes.Br, exit); codeGen.Generator.MarkLabel(exit); return(XamlIlNodeEmitResult.Void); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlAstTextNode text)) { return(null); } if (!text.Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String)) { throw new XamlIlLoadException("Text node type wasn't resolved to well-known System.String", node); } codeGen.Generator.Emit(OpCodes.Ldstr, text.Text); return(XamlIlNodeEmitResult.Type(text.Type.GetClrType())); }