/// <summary> /// /// </summary> /// <param name="ctx"></param> /// <param name="tag"></param> /// <returns></returns> internal static Type GuessIfType(this CompileContext ctx, ElseifTag tag) { var types = new List <Type>(); var hasVoid = false; for (var i = 0; i < tag.Children.Count; i++) { var type = ctx.GuessType(tag.Children[i]); if (type.FullName == "System.Void") { hasVoid = true; } else { types.Add(type); } } if (types.Count == 1) { return(types[0]); } if (types.Count == 0 && hasVoid) { return(typeof(void)); } return(typeof(string)); }
/// <summary> /// calling the tag. /// </summary> /// <param name="il">The <see cref="ILGenerator"/></param> /// <param name="ctx">The <see cref="CompileContext"/></param> /// <param name="tag">The <see cref="ITag"/></param> /// <param name="before">The action.</param> /// <param name="completed">The action of the completed.</param> public static void CallTag(this ILGenerator il, CompileContext ctx, ITag tag, Action <ILGenerator, bool, bool> before,//hasReturn,call Action <ILGenerator, Type> completed) { if (tag is EndTag _ || tag is CommentTag _) { return; } if (tag is TextTag textTag) { if (string.IsNullOrEmpty(textTag.Text)) { return; } before?.Invoke(il, true, false); var text = textTag.ToString(ctx.OutMode); il.Emit(OpCodes.Ldstr, text); completed?.Invoke(il, typeof(string)); return; } if (tag is ITypeTag typeTag) { if (typeTag.Value == null) { return; } before?.Invoke(il, true, false); Type returnType = il.CallTypeTag(typeTag); completed?.Invoke(il, returnType); return; } if (tag is SetTag setTag) { ctx.Set(setTag.Name, ctx.GuessType(setTag.Value)); } var m = ctx.CompileTag(tag); if (m.ReturnType.FullName != "System.Void") { before?.Invoke(il, true, true); il.Emit(OpCodes.Call, m); completed?.Invoke(il, m.ReturnType); } else { before?.Invoke(il, false, true); il.Emit(OpCodes.Call, m); completed?.Invoke(il, null); } }
/// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="tag"></param> /// <param name="ctx"></param> /// <returns></returns> internal static MethodInfo IfCompile <T>(this CompileContext ctx, T tag) where T : ElseifTag { var stringBuilderType = typeof(StringBuilder); var t = tag; var type = ctx.GuessType(t); var mb = ctx.CreateReutrnMethod <T>(type); var il = mb.GetILGenerator(); var labelEnd = il.DefineLabel(); il.DeclareLocal(type); il.DeclareLocal(stringBuilderType); il.Emit(OpCodes.Newobj, stringBuilderType.GetConstructor(Type.EmptyTypes)); il.Emit(OpCodes.Stloc_1); for (var i = 0; i < t.Children.Count; i++) { il.CallTag(ctx, t.Children[i], (nil, hasReturn, needCall) => { if (hasReturn) { nil.Emit(OpCodes.Ldloc_1); } if (needCall) { nil.Emit(OpCodes.Ldarg_0); nil.Emit(OpCodes.Ldarg_1); } }, (nil, returnType) => { if (returnType == null) { return; } nil.StringAppend(ctx, returnType); nil.Emit(OpCodes.Pop); }); } il.Emit(OpCodes.Ldloc_1); il.Call(stringBuilderType, stringBuilderType.GetMethodInfo("ToString", Type.EmptyTypes)); il.Emit(OpCodes.Stloc_0); il.MarkLabel(labelEnd); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); return(mb.GetBaseDefinition()); }