public string sig() { string sig = access.ToString().ToLower() + " "; if (type == MethodType.StaticFunction || type == MethodType.Extension) { sig += "static "; } if (type == MethodType.Abstract) { sig += "abstract "; } else if (type == MethodType.Override) { sig += "override "; } else if (type == MethodType.Virtual) { sig += "virtual "; } if (async) { sig += "async "; } sig += $"{(returnType != null ? returnType.RealName(true) : "")} {name}{(genericSuffix.Valid() ? $"{genericSuffix}" : "")}"; var funcFirstArg = type == MethodType.Extension ? $"this {classType.RealName(true)} self" : ""; sig += $"({CodeGenTools.MergeSig(funcFirstArg, args)}) {constraints}"; return(sig); }
public void Commit(Action <string> sink) { if (doNotGen) { return; } //if (stubMode && (type == MethodType.Override || (classBuilder.name == "SerializationExtensions"))) return; if (stubMode && (type == MethodType.Override)) { return; } var indent = ""; if (classBuilder.namespaceName.Valid()) { indent = ("\t\t"); } else { indent = ("\t"); } sink(indent + sig()); sink($"{indent}{{"); if (!stubMode) { if (isDebug) { sink("#if !RELEASE"); } if (needBaseValCall && !doNotCallBaseMethod) { if (returnType != typeof(void)) { sink($"{indent}\tvar baseVal = base.{RemoveBaseIfNeeded(name)}({CodeGenTools.ExtranctArgNames(args)});"); } else { sink($"{indent}\tbase.{RemoveBaseIfNeeded(name)}({CodeGenTools.ExtranctArgNames(args)});"); } } sink(builder.ToStringWithoutListLineEnd()); if (isDebug) { sink("#else"); sink($"{indent}\tthrow new HackCommandExecutionOnReleaseBuild();"); sink("#endif"); } } else { sink(indent + "\tthrow new NotImplementedException();"); } sink($"{indent}}}"); }
static void GenerateConstructionFromRoot(Type type) { var rootType = type.FindTagInHierarchy <RootType>()?.type; if (rootType == null) { return; } Action <MethodBuilder> fillCreateWithLivableSetup = sink => { sink.content($"inst.root = this;"); // if (type.HasReferenceId()) // sink.content($"inst.Id = entityIdFactory++;"); //if (type.HasNestedLivableChildren()) sink.content($"inst.{SetupHierarchyFuncName}();"); sink.content($"inst.{SetupChildrenIdFuncName}();"); //if (type.HasChildrenThatNeedsRootSetup()) }; var constructorMethodFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; if (type.IsAbstract == false && (!type.IsGenericType || type.IsConstructedGenericType)) { bool hasConstructor = false; foreach (var methodInfo in type.GetMethods(constructorMethodFlags)) { if (methodInfo.Name.StartsWith("Ctor")) { var sig = methodInfo.GetParameters().Select(p => $"{p.ParameterType.RealName(true)} {p.Name}") .PrintCollection(); var call = methodInfo.GetParameters().Select(p => p.Name).PrintCollection(); // ctor mwthod found var constructFull = GenClassSink(rootType).Method(type.CreateLivableInRootFunc(), rootType, MethodType.Instance, type, sig, "", ""); constructFull.indent++; //constructFull.content($"var inst = pool.{type.GetFromPoolFunc()}();"); CreateNewInstance(constructFull, new DataInfo { type = type, baseAccess = "inst", sureIsNull = true }, "", true, "", true); fillCreateWithLivableSetup(constructFull); constructFull.content($"inst.{methodInfo.Name}({call});"); constructFull.content($"return inst;"); hasConstructor = true; } } if (!hasConstructor) { var createWithSetup = GenClassSink(rootType).Method(type.CreateLivableInRootFunc(), rootType, MethodType.Instance, type, "", "", ""); createWithSetup.indent++; CreateNewInstance(createWithSetup, new DataInfo { type = type, baseAccess = "inst", sureIsNull = true }, "", true, "", true); fillCreateWithLivableSetup(createWithSetup); createWithSetup.content($"return inst;"); } } // Create from prototype if ((type.ReadGenFlags() & GenTaskFlags.UpdateFrom) != 0) { var createFromProrotype = GenClassSink(rootType).Method(type.CreateLivableInRootFunc(), rootType, MethodType.Instance, type, $"{type.RealName(true)} prototype", "", ""); createFromProrotype.indent++; //CreateNewInstance(createFromProrotype, new DataInfo{type = type, baseAccess = "inst", sureIsNull = true}, "", true, "", true ); //createFromProrotype.content($"var inst = ({type.RealName(true)})prototype.NewInst();"); GenUpdateValueFromInstance(createFromProrotype, new DataInfo { type = type, baseAccess = $"inst", sureIsNull = true }, "prototype", false, needCreateVar: true); fillCreateWithLivableSetup(createFromProrotype); createFromProrotype.content($"return inst;"); } if (polymorphicRootNodes.ContainsKey(type)) { MethodInfo polymorphicConstructor = null; foreach (var methodInfo in type.GetMethods(constructorMethodFlags)) { if (methodInfo.Name.StartsWith("Prepare") && (methodInfo.IsVirtual || methodInfo.IsAbstract)) { var sig = methodInfo.GetParameters().Select(p => $"{p.ParameterType.RealName(true)} {p.Name}") .PrintCollection(); var enumTypeRef = type.PolymorphicRootTypeEnumName(); if (string.IsNullOrEmpty(type.Namespace) == false) { enumTypeRef = type.Namespace + "." + enumTypeRef; } sig = CodeGenTools.MergeSig($"{enumTypeRef} classId", sig); var call = methodInfo.GetParameters().Select(p => p.Name).PrintCollection(); // ctor mwthod found var constructFull = GenClassSink(rootType).Method($"CreatePolymorphic{type.UniqueName(false)}", rootType, MethodType.Instance, type, sig, "", ""); constructFull.indent++; constructFull.content($"var inst = {type.NewPolymorphicFromClassIdExpression(type.NeedsPooledPolymorphConstruction())};"); fillCreateWithLivableSetup(constructFull); constructFull.content($"inst.{methodInfo.Name}({call});"); constructFull.content($"return inst;"); } } } }
public static void CreateNewInstance(MethodBuilder sink, DataInfo info, string classIdReader, bool pooled, string refInst, bool needCreateVar, bool wrapType = false) { // Some bullshit logic here // All of this because of value wrapper concept that should be reconsidered var t = wrapType ? info.realType : info.type; var name = wrapType ? info.accessPrefix + info.baseAccess : info.access; string newExpr = ""; bool needCast = false; if (t == typeof(string)) { newExpr = "string.Empty"; } else if (t.IsArray) { newExpr = $"Array.Empty<{t.RealName(true).Remove(t.RealName(true).Length - 2)}>()"; } else if (t.CanBeAncestor() && info.cantBeAncestor == false) { needCast = true; if (CodeGenTools.Valid(refInst)) { string poolArg = ""; if (t.HasPool() && pooled) { poolArg = "pool"; } newExpr = $"{refInst}.{PolymorphNewInstOfSameType}({poolArg})"; } else { if (CodeGenTools.Valid(classIdReader) == false) { if (t.IsAbstract) { return; } newExpr = NewInstExpr(t, pooled); } else { var staticTypeCreator = baseClassMap.GetOrDefault(t, t).RealName(true); if (t.IsGenericParameter) { if (t.GetGenericParameterConstraints().TryFind(par => !par.IsInterface, out var hardPar)) { staticTypeCreator = hardPar.RealName(true); } else { Error($"can't generate new instance construction for unknown type {t} in {info.carrierType}, constrain this type with some base class like DataNode"); } } newExpr = $"{staticTypeCreator}.{PolymorphInstanceFuncName}({classIdReader})"; } } } else { createNormally: if (t.IsAbstract) { Error($"Type {t} is abstract but required to have constructor during {sink.classBuilder.name} generation"); return; } newExpr = NewInstExpr(t, pooled, info.defaultValue); } sink.content($"{(needCreateVar ? "var " : "")}{name} = {(needCast ? $"({t.RealName(true)})" : "")}{newExpr};"); }
public void content(string source) { contentBuilder.AppendLine(CodeGenTools.Indent(indent) + source); }
static void GenerateFieldWrappers() { Dictionary <string, List <__GenReplaceFieldBase> > fieldsCodeReplace = new Dictionary <string, List <__GenReplaceFieldBase> >(); foreach (var typePair in typeGenRequested) { var type = typePair.Key; bool updateEvent = type.HasAttribute <GenUpdatedEvent>(); //if (type.IsGameNode() == false && !type.IsDataRoot() && !updateEvent) continue; var sink = GenClassSink(type); if (updateEvent) { sink.inheritance("IHasUpdateEvent"); sink.content("[GenIgnore] EventStream updated = new EventStream();"); sink.content("public IEventReader Updated => updated;"); } Action <Type, string, int, bool, bool> genField = (fType, fName, index, reactive, recordable) => { var recordInteraction = ""; var updateInteraction = updateEvent ? "updated.Send();" : ""; if (reactive) { sink.usingSink("ZergRush.ReactiveCore"); var cellName = $"{fName}Cell"; sink.content( $"[GenIgnore] public Cell<{fType.RealName(true)}> {cellName} = new Cell<{fType.RealName(true)}>();"); sink.content( $"{fType.RealName(true)} _{fName} {{ get {{ return {cellName}.value; }} set {{ {cellName}.value = value; {recordInteraction} {updateInteraction}}} }}"); } else { var backingFieldName = $"__{fName}"; sink.content($"[GenIgnore] public {fType.RealName(true)} {backingFieldName};"); sink.content( $"{fType.RealName(true)} _{fName} {{ get {{ return {backingFieldName}; }} set {{ {backingFieldName} = value; {recordInteraction} {updateInteraction}}} }}"); } }; int fieldIndex = 0; foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (field.HasAttribute <GenUICell>() || field.HasAttribute <GenRecordable>()) { fieldIndex++; var tag = (__GenReplaceFieldBase)field.GetAttributeIfAny <GenUICell>() ?? field.GetAttributeIfAny <GenRecordable>(); tag.type = field.FieldType; tag.name = field.Name; fieldsCodeReplace.TryGetOrNew(type.RealName()).Add(tag); genField(field.FieldType, field.Name, fieldIndex, field.HasAttribute <GenUICell>(), field.HasAttribute <GenRecordable>()); } } foreach (var field in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (field.HasAttribute <GenInclude>() == false) { continue; } if (field.HasAttribute <GenUICell>() || field.HasAttribute <GenRecordable>()) { fieldIndex++; genField(field.PropertyType, field.Name, fieldIndex, field.HasAttribute <GenUICell>(), field.HasAttribute <GenRecordable>()); } } } if (fieldsCodeReplace.Count > 0) { foreach (var info in fieldsCodeReplace) { Debug.Log($"Type: {info.Key} Field to replace: {info.Value.Select(i => i.name).PrintCollection()}"); var filePath = info.Value[0].file; Debug.Log($"Type: {info.Key} filePath: {filePath}"); var allText = File.ReadAllLines(filePath); foreach (var field in info.Value) { var tagLine = allText[field.line - 1]; tagLine = tagLine + "[GenInclude]"; allText[field.line - 1] = tagLine; var targetLine = allText[field.line]; Debug.Log($"replacing " + targetLine); var isPublic = targetLine.Contains("public") ? "public" : ""; var backingFieldName = "_" + field.name; var whiteSpaceCount = 0; ConsumeSpaces(ref whiteSpaceCount, targetLine); targetLine = CodeGenTools.Indent(whiteSpaceCount / 4) + $"{isPublic} {field.type.RealName(true)} {field.name} {{ get {{ return {backingFieldName}; }} set {{ {backingFieldName} = value;}} }}"; Debug.Log(targetLine); allText[field.line] = targetLine; } File.WriteAllLines(filePath, allText); } } }
public void content(string str) { builder.Append(CodeGenTools.Indent(indent + classBuilder.indent)); builder.AppendLine(str); }
public static void GeneralReadFrom(MethodBuilder sink, DataInfo info, Action <MethodBuilder, DataInfo> baseReadCall, string isNullReader, string classIdReader, string directReader, string refInst, string refIdReader, bool pooled, Func <Type, string> configIdReader = null, bool needCreateVar = false, bool useTempVarThenAssign = false, bool getDataNodeFromRootWithRefId = false) { var t = info.type; var canBeNull = info.canBeNull && !t.IsValueType; var originalInfo = info; string tempVar = "__" + originalInfo.baseAccess.Replace("[", "").Replace("]", ""); if (useTempVarThenAssign) { sink.content($"var {tempVar} = {originalInfo.access};"); info = new DataInfo { type = originalInfo.type, baseAccess = tempVar, }; } var name = info.access; bool newInstCalled = false; if (needCreateVar) { sink.content($"{info.type.RealName(true)} {info.name} = default;"); } if (t.IsImmutableValueType() || t.IsValueType && t.IsControllable() == false) { sink.content($"{name} = {directReader};"); return; } else if (t.IsRef()) { if (CodeGenTools.Valid(refIdReader)) { sink.content($"{info.access}.id = {refIdReader};"); } else { throw new NotImplementedException(); } } else { if (canBeNull) { sink.content($"if ({isNullReader}) {{"); sink.indent++; SinkRemovePostProcess(sink, info, pooled); sink.content($"{name} = null;"); sink.indent--; sink.content($"}}"); sink.content($"else {{ "); sink.indent++; } bool fromExternalSource = false; if (t.IsConfig() && info.insideConfigStorage == false) { ConfigFromId(sink, info, configIdReader, false); fromExternalSource = true; } else if (getDataNodeFromRootWithRefId && typeof(IReferencableFromDataRoot).IsAssignableFrom(t)) { sink.content($"{info.access} = ({info.type.RealName(true)})root.Recall({refIdReader});"); fromExternalSource = true; } else { if (info.sureIsNull && !info.type.IsValueType) { CreateNewInstance(sink, info, classIdReader, pooled, refInst, false); newInstCalled = true; } else { string createNewCondition = ""; if (canBeNull || info.CanBeNullAfterConstruction()) { createNewCondition = $"{name} == null"; } string classIdVarName = $"{name.Replace('[', '_').Replace(']', '_').Replace('.', '_')}ClassId"; if (t.CanBeAncestor() && info.cantBeAncestor == false) { sink.content($"var {classIdVarName} = {classIdReader};"); createNewCondition = AddOrCondition(createNewCondition, $"{name}.{PolymorphClassIdGetter} != {classIdVarName}"); } if (info.type.IsImmutableType() == false && CodeGenTools.Valid(createNewCondition)) { sink.content($"if ({createNewCondition}) {{"); sink.indent++; SinkRemovePostProcess(sink, info, pooled); CreateNewInstance(sink, info, classIdVarName, pooled, refInst, false); newInstCalled = true; sink.indent--; sink.content($"}}"); } } } if (!fromExternalSource) { baseReadCall(sink, info); } if (canBeNull) { sink.indent--; sink.content($"}}"); } } if (useTempVarThenAssign) { sink.content($"{originalInfo.access} = {tempVar};"); } }
public void content(string source) { classContent.AppendLine(CodeGenTools.Indent(indent) + source); }