public override async Task GenerateInTranslationCreateClass(ObjectGeneration obj, StructuredStringBuilder sb) { using (var args = new Function(sb, $"public static void FillPublic{ModuleNickname}")) { args.Add($"{obj.Interface(getter: false, internalInterface: true)} item"); args.Add($"XElement {XElementLine.GetParameterName(obj, Context.Backend)}"); foreach (var item in MainAPI.ReaderAPI.CustomAPI) { if (!item.API.TryResolve(obj, TranslationDirection.Reader, Context.Backend, out var line)) { continue; } args.Add(line.Result); } args.Add($"ErrorMaskBuilder? errorMask"); args.Add($"{nameof(TranslationCrystal)}? translationMask"); } using (sb.CurlyBrace()) { sb.AppendLine("try"); using (sb.CurlyBrace()) { sb.AppendLine($"foreach (var elem in {XElementLine.GetParameterName(obj, Context.Backend)}.Elements())"); using (sb.CurlyBrace()) { using (var args = sb.Call( $"{TranslationCreateClass(obj)}.FillPublicElement{ModuleNickname}")) { args.Add("item: item"); args.Add($"{XElementLine.GetParameterName(obj, Context.Backend)}: elem"); args.Add("name: elem.Name.LocalName"); args.Add("errorMask: errorMask"); if (TranslationMaskParameter) { args.Add("translationMask: translationMask"); } foreach (var item in MainAPI.ReaderAPI.CustomAPI) { if (!item.API.TryGetPassthrough(obj, TranslationDirection.Reader, Context.Backend, out var passthrough)) { continue; } args.Add(passthrough); } } } } sb.AppendLine("catch (Exception ex)"); sb.AppendLine("when (errorMask != null)"); using (sb.CurlyBrace()) { sb.AppendLine("errorMask.ReportException(ex);"); } } sb.AppendLine(); FillPublicElement(obj, sb); await base.GenerateInTranslationCreateClass(obj, sb); }
public void FunctionDuplicateElementInImage() { var f = new Function <int, int>(); f.Add(new OrderedTuple2 <int, int>(1, 2)); Assert.ThrowsException <DuplicateElementInFunctionImageException>( () => f.Add(new OrderedTuple2 <int, int>(1, 3)) ); }
public void GenerateCopyInRet_Internal( StructuredStringBuilder sb, ObjectGeneration objGen, TypeGeneration typeGen, Accessor nodeAccessor, Accessor itemAccessor, bool ret, Accessor errorMaskAccessor, Accessor translationMaskAccessor) { var list = typeGen as ListType; if (!XmlMod.TryGetTypeGeneration(list.SubTypeGeneration.GetType(), out var subTransl)) { throw new ArgumentException("Unsupported type generator: " + list.SubTypeGeneration); } if (ret) { throw new NotImplementedException(); } MaskGenerationUtility.WrapErrorFieldIndexPush( sb: sb, toDo: () => { using (var args = new Function( sb, $"if ({TranslatorName}<{list.SubTypeGeneration.TypeName(getter: false, needsCovariance: true)}>.Instance.Parse")) { args.AddPassArg($"{XmlTranslationModule.XElementLine.GetParameterName(objGen, Context.Backend)}"); args.Add($"enumer: out var {typeGen.Name}Item"); args.Add($"transl: {subTransl.GetTranslatorInstance(list.SubTypeGeneration, getter: false)}.Parse"); args.Add("errorMask: errorMask"); args.Add($"translationMask: {translationMaskAccessor})"); } using (sb.CurlyBrace()) { if (typeGen.Nullable) { sb.AppendLine($"{itemAccessor.Access} = {typeGen.Name}Item.ToExtendedList();"); } else { sb.AppendLine($"{itemAccessor.Access}.SetTo({typeGen.Name}Item);"); } } sb.AppendLine("else"); using (sb.CurlyBrace()) { list.GenerateClear(sb, itemAccessor); } }, errorMaskAccessor: errorMaskAccessor, indexAccessor: typeGen.IndexEnumInt); }
public DALViewModel(IRegionManager regionManager, IXmlCompareUserControl UserControl) { _regionManager = regionManager; m_UserControl = UserControl; CancelCommand = new DelegateCommand(CancelExecute); ToCommand = new DelegateCommand(ToCommandExecute); FromCommand = new DelegateCommand(FromCommandExecute); OkCommand = new DelegateCommand(OkCommandExecute); List <CFunction> lstFunc = m_UserControl.GetFunctions(); foreach (CFunction tmp in lstFunc) { Function.Add(tmp); } m_CurrentFunction = null; }
/// <summary> /// Generates service method code. /// </summary> /// <param name="serviceMethod">the service method</param> public void GenerateServiceMethodCode(Function serviceMethod) { var body = serviceMethod.Annotations.OfType <FunctionBodyAnnotation>().SingleOrDefault(); serviceMethod.Annotations.RemoveAll(a => a is MethodCodeAnnotation); string methodCode = string.Empty; // Generate the method code - CodeDom annotations take preference over FunctionBodyAnnotations (QueryExpressions) CodeDomBodyAnnotation codeAnnotation = serviceMethod.Annotations.OfType <CodeDomBodyAnnotation>().SingleOrDefault(); if (codeAnnotation != default(CodeDomBodyAnnotation)) { methodCode = this.GenerateMethodCode(codeAnnotation.Statements, serviceMethod.Model); } else if (body != default(FunctionBodyAnnotation)) { methodCode = this.GenerateMethodCode(body.FunctionBody, serviceMethod.Model); } serviceMethod.Add(new MethodCodeAnnotation { Code = methodCode }); }
void ReadOptionalObjectInfo(OptionalObjectInfo entity, PublicObjectDescriptor parent) { if (entity == null) { return; } UInt32 address = (UInt32)entity.Address + ImageBase; VBStruct.Make <OptionalObjectInfo>(entity, address, true); Bytes.MakeNameAnyway((UInt32)address, "OptInf_" + parent.Name); if (entity.Controls != null && entity.Controls.Length > 0) { //address = (UInt32)entity.Address + ImageBase; if (entity.Controls.Length == 1) { address = (UInt32)entity.Controls[0].Address + ImageBase; VBStruct.Make <VBControl>(entity.Controls[0], address, true); Bytes.MakeNameAnyway((UInt32)address, "Control_" + parent.Name); } else { foreach (VBControl item in entity.Controls) { address = (UInt32)item.Address + ImageBase; VBStruct.Make <VBControl>(item, address, true); Bytes.MakeNameAnyway((UInt32)address, "Control_" + parent.Name + "_" + item.Name2); } } } if (entity.EventLinks != null && entity.EventLinks.Length > 0) { Int32 i = 1; foreach (EventLink2 item in entity.EventLinks) { address = (UInt32)item.Address + ImageBase; VBStruct.Make <EventLink2>(item, address, true); // 事件列表命名 String name = String.Empty; if (parent.ProcNames != null && parent.ProcNames.Length > i - 1) { name = parent.Name + "_" + parent.ProcNames[i - 1].FriendName; } if (String.IsNullOrEmpty(name)) { name = parent.Name + "_" + i.ToString("X2"); } i++; Bytes.MakeNameAnyway((UInt32)address, "Event_" + name); // 跳转命名 address = (UInt32)item.Jump; Bytes.MakeNameAnyway(address, "j" + name); Bytes.MakeCode(address); // 函数命名 if (Bytes.Byte(address) == 0xE9) { // Jump语句,下一个字就是函数起始地址 address = Bytes.Dword(address + 1) + address + 5; Function func = Function.FindByAddress(address); if (func == null) { // 如果函数不存在,则创建函数 Function.Add(address, Bytes.BadAddress); func = Function.FindByAddress(address); } else { // 函数存在,但是函数的起始地址并不是当前行,表明这个函数分析有错,修改地址 if (func.Start != address) { //Function.Delete(func.Start); //Function.Add(func.Start, address - 1); func.End = address - 1; Function.Add(address, Bytes.BadAddress); func = Function.FindByAddress(address); } } if (func == null) { KernelWin.WriteLine("0x{0:X} 创建函数失败!", address); } else { Bytes.MakeLabelAnyway(address, name); } } } } }
Node ParseRHS(Node lhs, int minprec) { if ((op.flags & BuiltinOp.unary_only) != 0) { Error(op.name + " cannot be used as a binary operator"); } var sop = op; Next(); if (sop.name == "=") { var ph = lhs.t as PlaceHolder; if (ph == null) { Error("left of = must be a variable"); } return(new Node(sop, ParseExp(minprec), lhs)); // swap order to keep consistent L->R eval } else if (sop.name == "=>") { var f = prog.GenFun(funnames); funnames.Add(f.name); //if(curfun!=null) // FIXME: what if an error occurs below? we'd have a half finished function curfun.Add(f); //else topfun = f; var bf = curfun; curfun = f; f.root = ParseExp(minprec); curfun = bf; if (lhs.t is BuiltinOp) { switch (lhs.t.name) { case "=": var ph = lhs.At(1).t as PlaceHolder; f.args.Add(ph); return(new Node(f, lhs.At(0))); case "__tuple": lhs.ForEach(n => { if (!(n.t is PlaceHolder)) { Error("lambda parameters must be identifiers"); } f.args.Add(n.t as PlaceHolder); }); return(new Node(new FunctionValue { reff = f, name = f.name })); // fixme: dup } } else if (lhs.t is PlaceHolder) { f.args.Add(lhs.t as PlaceHolder); return(new Node(new FunctionValue { reff = f, name = f.name })); } Error("left of => must be a variable/tuple or assignment"); } else if (sop.name == "|>") { return(new Node(sop, ParseExp(minprec), lhs)); // same order as __apply } return(new Node(sop, lhs, ParseExp(minprec))); }
protected virtual void FillPublicElement(ObjectGeneration obj, StructuredStringBuilder sb) { using (var args = new Function(sb, $"public static void FillPublicElement{ModuleNickname}")) { args.Add($"{obj.Interface(getter: false)} item"); args.Add($"XElement {XElementLine.GetParameterName(obj, Context.Backend)}"); args.Add("string name"); args.Add($"ErrorMaskBuilder? errorMask"); args.Add($"{nameof(TranslationCrystal)}? translationMask"); } using (sb.CurlyBrace()) { sb.AppendLine("switch (name)"); using (sb.CurlyBrace()) { foreach (var field in obj.IterateFields()) { if (field.Derivative) { continue; } if (field.ReadOnly) { continue; } if (!TryGetTypeGeneration(field.GetType(), out var generator)) { throw new ArgumentException("Unsupported type generator: " + field); } sb.AppendLine($"case \"{field.Name}\":"); using (sb.IncreaseDepth()) { if (generator.ShouldGenerateCopyIn(field)) { List <string> conditions = new List <string>(); if (TranslationMaskParameter) { conditions.Add(field.GetTranslationIfAccessor("translationMask")); } if (conditions.Count > 0) { using (var args = sb.If(ands: true)) { foreach (var item in conditions) { args.Add(item); } } } using (sb.CurlyBrace(doIt: conditions.Count > 0)) { generator.GenerateCopyIn( sb: sb, objGen: obj, typeGen: field, nodeAccessor: XElementLine.GetParameterName(obj, Context.Backend).Result, itemAccessor: Accessor.FromType(field, "item"), translationMaskAccessor: "translationMask", errorMaskAccessor: $"errorMask"); } } sb.AppendLine("break;"); } } sb.AppendLine("default:"); using (sb.IncreaseDepth()) { if (obj.HasLoquiBaseObject) { using (var args = sb.Call( $"{obj.BaseClass.CommonClassName(LoquiInterfaceType.ISetter)}.FillPublicElement{ModuleNickname}{obj.GetBaseMask_GenericTypes(MaskType.Error)}")) { args.Add("item: item"); args.Add($"{XElementLine.GetParameterName(obj, Context.Backend)}: {XElementLine.GetParameterName(obj, Context.Backend)}"); args.Add("name: name"); args.Add("errorMask: errorMask"); if (TranslationMaskParameter) { args.Add($"translationMask: translationMask"); } } } sb.AppendLine("break;"); } } } sb.AppendLine(); }
public virtual void GenerateWriteToNode(ObjectGeneration obj, StructuredStringBuilder sb) { using (var args = new Function(sb, $"public static void WriteToNode{ModuleNickname}{obj.GetGenericTypes(MaskType.Normal)}")) { args.Add($"{obj.Interface(internalInterface: true, getter: true)} item"); args.Add($"XElement {XElementLine.GetParameterName(obj, Context.Backend)}"); args.Add($"ErrorMaskBuilder? errorMask"); args.Add($"{nameof(TranslationCrystal)}? translationMask"); } using (sb.CurlyBrace()) { if (obj.HasLoquiBaseObject) { using (var args = sb.Call( $"{TranslationWriteClass(obj.BaseClass)}.WriteToNode{ModuleNickname}")) { args.Add($"item: item"); args.Add($"{XElementLine.GetParameterName(obj, Context.Backend)}: {XElementLine.GetParameterName(obj, Context.Backend)}"); args.Add($"errorMask: errorMask"); args.Add($"translationMask: translationMask"); } } foreach (var field in obj.IterateFieldIndices()) { if (!TryGetTypeGeneration(field.Field.GetType(), out var generator)) { throw new ArgumentException("Unsupported type generator: " + field.Field); } if (!generator.ShouldGenerateWrite(field.Field)) { continue; } List <string> conditions = new List <string>(); if (field.Field.Nullable) { conditions.Add($"{field.Field.NullableAccessor(getter: true, accessor: Accessor.FromType(field.Field, "item"))}"); } if (TranslationMaskParameter) { conditions.Add(field.Field.GetTranslationIfAccessor("translationMask")); } if (conditions.Count > 0) { using (var args = sb.If(ands: true)) { foreach (var item in conditions) { args.Add(item); } } } using (sb.CurlyBrace(doIt: conditions.Count > 0)) { var maskType = Gen.MaskModule.GetMaskModule(field.Field.GetType()).GetErrorMaskTypeStr(field.Field); generator.GenerateWrite( sb: sb, objGen: obj, typeGen: field.Field, writerAccessor: $"{XElementLine.GetParameterName(obj, Context.Backend)}", itemAccessor: Accessor.FromType(field.Field, "item"), errorMaskAccessor: $"errorMask", translationMaskAccessor: "translationMask", nameAccessor: $"nameof(item.{field.Field.Name})"); } } } sb.AppendLine(); }
internal string Restructor() { if (CodeProblems()) { return("Cannot restruct code while there are errors / edits."); } bool cull_unused_args = false; if (cull_unused_args) { // If by means of editing a function argument (or free variable) has become unused, it // can be removed. This also removes all caller argument values, which is contentious, // since it may be code the programmer cares about, so ideally should be a separate pass // from Restructor where it shows you graphically in the editor what is dead code. // Until we have that, we just delete it, to ensure the Restructor algoritm is maximally // efficient. // FIXME: also, this must not remove parameters needed for the function-value arguments // to e.g. game(). for (;;) { bool modified = false; mf.ForAllFuncs(f => { f.freevars.RemoveAll(ph => !f.ExistsNode(n => n.t == ph)); // Have to use a regular loop to ensure element is removed within iteration. for (int i = 0; i < f.args.Count; i++) { var ph = f.args[i]; if (!f.ExistsNode(n => n.t == ph)) { // FIXME: this also removes code with side effects, which is clearly NOT // ok. A side effect argument should be pulled out of the argument list // and made into a seperate statement. f.args.RemoveAt(i); mf.ForAllNodes(n => { if (n.t == f) { n.Remove(i); modified = true; } }); i--; } } }); if (!modified) { break; } } } for (; ;) { Debug.WriteLine("Starting Pass"); // Iterate thru all code, and add every possible TwoNode you find into a map from each // possible kind of TwoNode to a list of occurrences. (collecting structurally // equivalent copies in the code). // For example, if the code is `(1+2)*(1+3)`, then parent `+` with child `1` (at index // 0) will be the highest occurring TwoNode. var rd = new Dictionary <TwoNode, SameNodeSet>(new TwoNodeEqualityComparer()); mf.ForAllRoots((n, f) => n.Register(rd, f)); // Add all map items where the list has at least 2 items to an overal list, and sort // that by occurrences. var lsns = new List <SameNodeSet>(); foreach (KeyValuePair <TwoNode, SameNodeSet> kvp in rd) { if (kvp.Value.l.Count > 1) { lsns.Add(kvp.Value); } } lsns.Sort(new SameNodeSetOrderComparer()); lsns.RemoveAll(sns => { // Any node may only participate in one TwoNode, since a refactor is destructive. // Combinations that didn't get to participate can be picked up by next passes. sns.l.RemoveAll(tn => { bool used = tn.a.refactorused || tn.b.refactorused; // have to do this while checking, because of add(add(add(...))) situations tn.a.refactorused = tn.b.refactorused = true; return(used); }); return(sns.l.Count <= 1); }); // Nothing to refactor, we're done! if (lsns.Count == 0) { break; } lsns.Sort(new SameNodeSetOrderComparer()); // Go through the overal list in order of number of occurrences: foreach (var sns in lsns) { var a = sns.l[0].a; var b = sns.l[0].b; var pos = sns.l[0].pos; // Create a new function that will have the TwoNode as body. Generate placeholders // for all children of the parent that are not the given child, and all children of // the child. // So here the function would be: `f(x) = 1 + x` var f = GenFun(); f.root = new Node(a.t); // Find the lowest common ancestor function that dominates all occurrences, so // function is defined as local as possible.Make that the parent function. (this // could be skipped if all functions were global). Function parent = null; foreach (var tn in sns.l) { parent = tn.domf.LCA(parent); } Debug.WriteLine("Make Function " + f.name + " : " + sns.l.Count + " => " + parent.name); parent.Add(f); for (var i = 0; i < a.Arity(); i++) { if (i == pos) { var nb = new Node(b.t); b.ForEach(n => nb.Add(GenVar(f))); f.root.Add(nb); } else { f.root.Add(GenVar(f)); } } // if the child was already a placeholder, it becomes a free variable of the new // function, similarly if either node is a function, then its free vars are added // to the new function. b.IfPlaceHolder(ph => f.freevars.Add(ph)); a.IfFunction(of => f.AddFreeVarsFrom(of)); b.IfFunction(of => f.AddFreeVarsFrom(of)); // if the child wasn't the last child: (because if it is the last child, the order // of evaluation vs the other children doesn't change, so no special action is // needed!) if (pos + 1 < a.Arity()) { // Find all side-effects in all children of the child. This takes the entire // call graph into account from this node. var bdb = new Dictionary <NodeType, SideEffect>(); b.t.CollectSideEffects(bdb, b); // If there are any side - effecs, for each following child, for each of its // occurrences, check if the two children are order dependent. // E.g. `f(a = 1, a)` or `f(a, a = 1)` are order dependent, and we have to // ensure to retain the evaluation order. `f(a = 1, b)` is not order dependent. if (bdb.Count > 0) { for (int p = pos + 1; p < a.Arity(); p++) { foreach (var tn in sns.l) { // TODO: could instead compare against b's dict rather than create var adb = new Dictionary <NodeType, SideEffect>(); tn.a.At(p).CollectSideEffects(adb); if (adb.Count > 0) { foreach (var bkvp in bdb) { SideEffect ase; if (adb.TryGetValue(bkvp.Key, out ase)) { var bse = bkvp.Value; if (ase.write || bse.write) { // Found an order-dependent occurrence. // TODO: should really allow for non-se callers to call a // pure version of function goto have_se; } } } } } continue; have_se: foreach (var tn in sns.l) { Function nof = GenFun(); parent.Add(nof); nof.root = tn.a.At(p); tn.a.Remove(p); tn.a.Insert(p, new Node( new FunctionValue { reff = nof, name = nof.name })); // FIXME: free vars? } var apply = new Node(uniques.applyop, f.root.At(p)); f.root.Remove(p); f.root.Insert(p, apply); } } } f.root.Sanity(); // Now replace all occurrences with our new function, so our expression becomes // `f(2) * f(3)`. foreach (var tn in sns.l) { Debug.Assert(tn.a.Arity() + tn.b.Arity() - 1 == f.args.Count); Debug.Assert(tn.a.At(pos) == tn.b); tn.a.t = f; tn.a.Remove(pos); tn.b.ForEach((n, j) => tn.a.Insert(pos + j, n)); tn.a.Sanity(); } // If any arguments are equal accross all occurrences, merge those arguments. f.MergeEqualArgs(sns.l); } // Inline all functions that have just 1 caller. This is essential, because the above // algorithm generates a ton of mini-functions whose body contains just one node, so // this inlining is responsible for making those back into the largest possible // functions, and shifting the boundaries of abstractions. // Going down to one caller is a natural consequence of the above algorithm whenever a // function call with multiple occurrences becomes the given child of a new function. // Together, these parts of the algorithm create the "emergent" behavior of finding // optimal function boundaries regardless of the code structure. InlineAll(); } InlineAll(); Validate(); // should not be needed, just incase restructor trampled on some types return("Restructed."); }