/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public virtual ASTItem Transform(ASTItem el) { if (el is AST.AssignmentExpression) { var ase = ((AST.AssignmentExpression)el); if (ase.Operator != AssignmentOperatorType.Assign) { AST.Expression clonedleft = ase.Left.Clone(); var newop = new AST.BinaryOperatorExpression() { Operator = ase.Operator.ToBinaryOperator(), Left = clonedleft, Right = ase.Right, Parent = ase, SourceExpression = ase.SourceExpression, SourceResultType = ase.SourceResultType }; newop.Left.Parent = newop.Right.Parent = newop; ase.Operator = AssignmentOperatorType.Assign; ase.Right = newop; return(null); } } return(el); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { if (el.Name != null && (el is AST.Bus || el is AST.Process || el is AST.DataElement)) { el.Name = Naming.ToValidName(el.Name); } if (el is AST.Bus && ((AST.Bus)el).InstanceName != null) { ((AST.Bus)el).InstanceName = Naming.ToValidName(((AST.Bus)el).InstanceName); } if (el is AST.Process && ((AST.Process)el).InstanceName != null) { ((AST.Process)el).InstanceName = Naming.ToValidName(((AST.Process)el).InstanceName); } if (el is AST.Constant) { if (((Constant)el).Source is Mono.Cecil.FieldDefinition) { el.Name = Naming.ToValidName((((Constant)el).Source as Mono.Cecil.FieldDefinition).DeclaringType.FullName + "." + el.Name); } else if (el.Parent != null && !string.IsNullOrWhiteSpace(el.Parent.Name)) { el.Name = Naming.ToValidName(el.Parent.Name + "." + el.Name); } } return(el); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public virtual ASTItem Transform(ASTItem item) { var exp = item as Expression; if (exp == null) { return(item); } // If this is top-level, we do not want a wrapping if (exp.Parent is Statement || exp.Parent is ParenthesizedExpression) { return(item); } if (!SIMPLE_TYPES.Any(x => exp.GetType().IsAssignableFrom(x)) && !(exp.Parent is AssignmentExpression)) { var np = new ParenthesizedExpression() { Expression = exp, Parent = exp.Parent, Name = exp.Name, SourceExpression = exp.SourceExpression, SourceResultType = exp.SourceResultType }; exp.ReplaceWith(np); exp.Parent = np; return(np); } return(item); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { if (el is AST.DataElement) { // Force loop variable as integers if (el.Parent is ForStatement) { var fs = el.Parent as ForStatement; if (fs.LoopIndex == el) { State.TypeLookup[el] = VHDLTypes.INTEGER; return(el); } } State.VHDLType(el as AST.DataElement); } if (el is AST.EmptyExpression) { return(el); } if (el is AST.Expression) { State.VHDLType(el as AST.Expression); } return(el); }
/// <summary> /// Transform the specified item. /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to transform.</param> public ASTItem Transform(ASTItem item) { var mt = item as Method; if (mt == null) { return(item); } var usednames = new Dictionary <string, string>(); foreach (var v in mt.AllVariables) { var basename = v.Name; var i = 2; while (usednames.ContainsKey(v.Name)) { v.Name = basename + i.ToString(); i++; if (i > 200) { throw new Exception("More than 200 identical variables? Something is wrong ..."); } } usednames[v.Name] = string.Empty; } return(mt); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public virtual ASTItem Transform(ASTItem item) { var ss = item as AST.SwitchStatement; if (ss == null) { return(item); } if (m_visited.Contains(ss)) { return(item); } m_visited.Add(ss); var changed = false; foreach (var cs in ss.Cases) { var last = cs.Item2.SelectMany(x => x.LeavesOnly()).LastOrDefault(); if (last is BreakStatement) { var es = new EmptyStatement(); (last as Statement).ReplaceWith(es); changed = true; } } return(changed ? null : ss); }
private static void RepeatedApply(IASTTransform[] transforms, Func <IEnumerable <ASTItem> > it) { var repeat = true; #if DEBUG_TRANSFORMS object lastchanger = null; ASTItem lastchange = null; #endif while (repeat) { repeat = false; #if DEBUG_TRANSFORMS Console.WriteLine("**** Restart ****"); #endif foreach (var x in it()) { if (x.Parent == x) { throw new Exception("Self-parenting is a bad idea"); } foreach (var f in transforms) { if (f.Transform(x) != x) { #if DEBUG_TRANSFORMS lastchanger = f; lastchange = x; if (x is AST.Expression) { Console.WriteLine(x.GetType().FullName + ": " + (x as AST.Expression).SourceExpression.ToString()); } if (x is AST.Statement) { Console.WriteLine(x.GetType().FullName + ": " + (x as AST.Statement).SourceStatement.ToString()); } Console.WriteLine("........... restarting after change by {0}", f.GetType().FullName); #endif repeat = true; break; } } if (repeat) { break; } } } }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { if (el is AST.DataElement) { var de = el as AST.DataElement; if (de.DefaultValue == null) { throw new MissingMethodException("All elements should have a default value assigned"); } } return(el); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="_item">The item to visit.</param> public virtual ASTItem Transform(ASTItem _item) { var item = _item as Expression; if (item == null) { return(_item); } // This fixes a case where the NRefactory code injects a cast to UIntPtr, // even though none is present in the code, nor the IL var wrap = false; var self = item; if (self is ParenthesizedExpression) { self = (self as ParenthesizedExpression).Expression; wrap = true; } if (self is CastExpression && (self as CastExpression).SourceResultType.IsSameTypeReference(typeof(UIntPtr))) { self = (self as CastExpression).Expression; } else { self = item; } if (wrap && self != item) { var p = self; self = new ParenthesizedExpression() { Expression = p as Expression, SourceExpression = (p as Expression).SourceExpression, SourceResultType = (p as Expression).SourceResultType, Parent = p.Parent, }; p.Parent = self; } if (self != item) { return(item.ReplaceWith(self)); } return(item); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { var ss = el as SwitchStatement; if (ss == null) { return(el); } // We cannot support conversions as part of the switch statements, // so we statically compute them here var nonstatic = ss.Cases.SelectMany(x => x.Item1).OfType <CustomNodes.ConversionExpression>().ToArray(); if (nonstatic.Length != 0) { foreach (var e in nonstatic) { var et = State.VHDLType(e); var cx = e.Expression; var pt = State.VHDLType(cx); // If we have a coversion thing caused by an off enum if (et.IsEnum && pt == VHDLTypes.INTEGER && cx is PrimitiveExpression) { var name = State.RegisterCustomEnum(ss.SwitchExpression.SourceResultType, et, (cx as PrimitiveExpression).Value); var c = new AST.Constant() { Name = name, CecilType = ss.SwitchExpression.SourceResultType, DefaultValue = name // (cx as PrimitiveExpression).Value }; var mr = new AST.MemberReferenceExpression() { Parent = ss, SourceResultType = c.CecilType, Target = c }; e.ReplaceWith(mr); } } return(null); } return(el); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public ASTItem Transform(ASTItem item) { var rs = item as AST.ReturnStatement; if (rs == null) { return(item); } if (rs.ReturnExpression is EmptyExpression) { return(item); } var stm = new ExpressionStatement() { Expression = new AST.AssignmentExpression() { Left = new AST.MemberReferenceExpression() { Target = Method.ReturnVariable, Name = Method.ReturnVariable.Name, SourceExpression = rs.ReturnExpression.SourceExpression, SourceResultType = Method.ReturnVariable.CecilType }, Right = rs.ReturnExpression, SourceExpression = rs.ReturnExpression.SourceExpression, SourceResultType = Method.ReturnVariable.CecilType, Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign } }; rs.PrependStatement(stm); stm.UpdateParents(); rs.ReplaceWith(new ReturnStatement() { ReturnExpression = new EmptyExpression() { SourceExpression = rs.ReturnExpression.SourceExpression, SourceResultType = Method.ReturnVariable.CecilType.LoadType(typeof(void)) }, }); return(stm); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public virtual ASTItem Transform(ASTItem item) { // This fixes a case where the code has double castings that introduce unwanted parenthesis var self = item as CastExpression; if (self == null) { return(item); } var child = self.Expression; if (child is CastExpression && child.SourceResultType.IsSameTypeReference(self.SourceResultType)) { self.Expression = ((CastExpression)child).Expression; self.Expression.Parent = self; return(null); } return(item); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public virtual ASTItem Transform(ASTItem item) { var expression = item as AssignmentExpression; if (expression == null) { return(item); } var target_left = expression.Left.GetTarget(); var target_right = expression.Right.GetTarget(); if (target_left == target_right && target_left != null && expression.Parent is ExpressionStatement && expression.Operator == ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign) { return(expression.ReplaceWith(new EmptyExpression() { SourceExpression = expression.SourceExpression, })); } return(item); }
/// <summary> /// Transforms a <see cref="ForStatement"/> to a <see cref="WhileStatement"/> /// </summary> /// <returns>The input item or a newly created <see cref="WhileStatement"/>.</returns> /// <param name="item">The item to transform.</param> public ASTItem Transform(ASTItem item) { var fs = item as ForStatement; if (fs == null) { return(item); } if (fs.LoopBody.All().OfType <BreakStatement>().Any()) { throw new Exception("Cannot transform loops with break or continue inside"); } var init = new ExpressionStatement(fs.Initializer); var ws = new WhileStatement(fs.Condition, fs.LoopBody); ws.Body.AppendStatement(new ExpressionStatement(fs.Increment)); fs.ReplaceWith(ws); return(fs); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public virtual ASTItem Transform(ASTItem item) { if (item is AssignmentExpression) { if (item.Parent is Statement) { var aes = item as AssignmentExpression; if (aes.Right is ParenthesizedExpression) { return(aes.Right.ReplaceWith(((ParenthesizedExpression)aes.Right).Expression)); } } } else if (item is IfElseStatement) { var ies = item as IfElseStatement; if (ies.Condition is ParenthesizedExpression) { return(ies.Condition.ReplaceWith(((ParenthesizedExpression)ies.Condition).Expression)); } } return(item); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public ASTItem Transform(ASTItem item) { if (item is ReturnStatement && Method.Parent is AST.Process && ((AST.Process)Method.Parent).MainMethod == Method) { if (m_handled.Contains(item)) { return(item); } m_handled.Add(item); var parentif = item.Parent; while (parentif != null && !(parentif is AST.IfElseStatement)) { parentif = parentif.Parent; } if (parentif == null) { Console.WriteLine("Unable to transform return statement in main method, try building the source program in Debug mode."); return(item); } if (!(((AST.IfElseStatement)parentif).FalseStatement is EmptyStatement)) { Console.WriteLine("Unable to transform return statement in main method, try building the source program in Debug mode."); return(item); } Statement[] blocksource; if (parentif.Parent is AST.Method) { blocksource = (parentif.Parent as AST.Method).Statements; } else if (parentif.Parent is AST.BlockStatement) { blocksource = (parentif.Parent as AST.BlockStatement).Statements; } else { Console.WriteLine("Unable to transform return statement in main method, try building the source program in Debug mode."); return(item); } var ix = Array.IndexOf(blocksource, parentif); if (ix < 0) { Console.WriteLine("Unable to transform return statement in main method, try building the source program in Debug mode."); return(item); } var remain = blocksource.Skip(ix + 1).ToArray(); ((ReturnStatement)item).ReplaceWith(new EmptyStatement() { Parent = item.Parent }); // If there are no other statements, we are good, but this should not happen if (remain.Length == 0) { return(null); } else { if (parentif.Parent is AST.Method) { (parentif.Parent as AST.Method).Statements = blocksource.Take(ix + 1).ToArray(); } else // if (parentif.Parent is AST.BlockStatement) { (parentif.Parent as AST.BlockStatement).Statements = blocksource.Take(ix + 1).ToArray(); } // One left, then skip the block construct if (remain.Length == 1) { ((AST.IfElseStatement)parentif).FalseStatement = remain[0]; } else { ((AST.IfElseStatement)parentif).FalseStatement = new BlockStatement() { Parent = parentif, Statements = remain, }; } ((AST.IfElseStatement)parentif).FalseStatement.UpdateParents(); return(null); } } return(item); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public ASTItem Transform(ASTItem item) { var ase = item as AssignmentExpression; if (ase == null) { return(item); } if (ase.Parent == null || ase.Left is EmptyExpression) { return(item); } var last = ase.Right.All().LastOrDefault(x => x is AssignmentExpression) as AssignmentExpression; var targets = new[] { ase.Left }.Concat(ase.Right.All().OfType <AssignmentExpression>().Select(x => x.Left)).ToArray(); if (last == null) { return(item); } Func <Expression> assignWith; var statements = new List <Statement>(); // Unwrap the last statement to see if it is really a primitive var lastexp = last.Right; while (OptimizeChainedInitializations) { if (lastexp is ParenthesizedExpression) { lastexp = ((ParenthesizedExpression)lastexp).Expression; continue; } if (lastexp is CustomNodes.ConversionExpression) { lastexp = ((CustomNodes.ConversionExpression)lastexp).Expression; continue; } break; } if (OptimizeChainedInitializations && lastexp is PrimitiveExpression) { assignWith = () => last.Right.Clone(); } else { var tmp = State.RegisterTemporaryVariable(Method, last.Right.SourceResultType); assignWith = () => new IdentifierExpression() { Name = tmp.Name, Target = tmp, SourceResultType = tmp.CecilType, SourceExpression = ase.SourceExpression, }; var tmpstm = new ExpressionStatement() { Expression = new AssignmentExpression() { Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, Left = assignWith(), Right = last.Right, SourceExpression = ase.SourceExpression, SourceResultType = tmp.CecilType } }; statements.Add(tmpstm); } foreach (var el in targets) { var s = new ExpressionStatement() { Expression = new AssignmentExpression() { Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, Left = el, Right = assignWith(), SourceExpression = ase.SourceExpression, SourceResultType = el.SourceResultType } }; statements.Add(s); } var blstm = new BlockStatement() { Statements = statements.ToArray(), }; ase.PrependStatement(blstm); if (ase.Parent is ExpressionStatement) { ((Statement)ase.Parent).ReplaceWith(new EmptyStatement()); } else { ase.ReplaceWith(new EmptyExpression()); } blstm.UpdateParents(); return(null); /* * * // If we have another assignment somewhere, break it up * var sue = ase.Right.All().FirstOrDefault(x => x is AssignmentExpression) as AssignmentExpression; * if (sue != null) * { * var pstm = new ExpressionStatement() * { * Expression = ase.Right, * SourceStatement = ase.SourceExpression.Clone() * }; * * ase.PrependStatement(pstm); * ase.Right.Parent = pstm; * * var nase = new AssignmentExpression() * { * Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, * Left = ase.Left, * Right = sue.Left, * SourceExpression = ase.SourceExpression, * SourceResultType = ase.SourceResultType * }; * * ase.ReplaceWith(nase); * nase.Left.Parent = nase.Right.Parent = nase; * } */ }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public virtual ASTItem Transform(ASTItem item) { var ss = item as AST.SwitchStatement; if (ss == null) { return(item); } if (m_visited.Contains(ss)) { return(item); } m_visited.Add(ss); // Figure out if the switch is using goto statements var goto_statements = ss.Cases.SelectMany(x => x.Item2).SelectMany(x => x.All()).OfType <GotoStatement>().ToList(); if (goto_statements.Count == 0) { return(item); } // Extract the cases that we will work with var cases = ss.Cases.ToList(); // Grab the name of the label, so we can look for it var labelname = goto_statements.First().Label; if (goto_statements.Any(x => x.Label != labelname)) { return(item); } // We assume that there is just one label with the given name in the method var mp = item.GetNearestParent <Method>(); if (mp == null) { return(item); } // Find the one label statement that is the goto target var lbltarget = mp.All().OfType <LabelStatement>().Where(x => x.Label == labelname).FirstOrDefault(); if (lbltarget == null) { return(item); } // Find the if(...) statements that are actually stray case statements foreach (var ifs in ((Method)mp).Statements.SelectMany(x => x.All()).OfType <IfElseStatement>()) { // Goldilocks testing, we only accept something like: // if (switch_var == value) { // ... // goto label; // } if (!(ifs.FalseStatement is EmptyStatement)) { continue; } if (!(ifs.TrueStatement.All().Last() is GotoStatement)) { continue; } if ((ifs.TrueStatement.All().Last() as GotoStatement).Label != labelname) { continue; } if (!(ifs.Condition is BinaryOperatorExpression)) { continue; } var beo = ifs.Condition as BinaryOperatorExpression; if (beo.Operator != ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Equality) { continue; } Expression casetarget; if (beo.Left.GetTarget() == ss.SwitchExpression.GetTarget()) { casetarget = beo.Right; } else if (beo.Right.GetTarget() == ss.SwitchExpression.GetTarget()) { casetarget = beo.Left; } else { continue; } if (casetarget == null) { continue; } // We have a case that looks just right :) cases.Add(new Tuple <Expression[], Statement[]>( new Expression[] { casetarget }, new Statement[] { ifs.TrueStatement } )); ifs.ReplaceWith(new EmptyStatement()); ifs.TrueStatement.Parent = ss; ifs.TrueStatement.UpdateParents(); } // Sometimes we have an added filter on the outside if (ss.Parent != lbltarget.Parent) { var ssp = ss.Parent; while (ssp != null && !(ssp is IfElseStatement)) { ssp = ssp.Parent; } var ssifp = ssp as IfElseStatement; if (ssifp != null) { var beo = ssifp.Condition as BinaryOperatorExpression; if (beo != null) { if (beo.Left.GetTarget() == ss.SwitchExpression.GetTarget() || beo.Right.GetTarget() == ss.SwitchExpression.GetTarget()) { var replace = false; if (ssifp.TrueStatement.All().Contains(ss)) { replace = !ssifp.FalseStatement.LeavesOnly().Any(x => !(x is EmptyStatement)); } else if (ssifp.FalseStatement.All().Contains(ss)) { replace = !ssifp.TrueStatement.LeavesOnly().Any(x => !(x is EmptyStatement)); } if (replace) { ssifp.ReplaceWith(ss); } } } } } // Find the container for the goto label Statement[] ps; if (lbltarget.Parent is BlockStatement) { ps = (lbltarget.Parent as BlockStatement).Statements; } else { ps = (lbltarget.Parent as Method).Statements; } // Find the switch and label taget in the list var labelindex = Array.IndexOf(ps, lbltarget); var switchindex = Array.IndexOf(ps, ss); // If we have different parents, the index does not point to the switch, // so we figure out where the switch ends if (switchindex < 0) { var ssp = ss.Parent; while (ssp != null && ssp.Parent != lbltarget.Parent) { ssp = ssp.Parent; } if (ssp == null) { return(item); } switchindex = Array.IndexOf(ps, ssp); } if (labelindex < 0 || switchindex < 0 || switchindex > labelindex) { return(item); } // Extract the items between the switch and the label target and use as the default case var defaultstatements = ps.Skip(switchindex + 1).Take(labelindex - switchindex - 1).Where(x => !(x is EmptyStatement)).ToList(); var remainingstatements = ps.Take(switchindex + 1).Concat(ps.Skip(labelindex + 1)).ToArray(); // We can get an empty case due to the transformations above cases = cases.Where(x => !x.Item2.All(y => y is EmptyStatement)).ToList(); // If we have default actions, or the switch is missing a default entry, add it if (defaultstatements.Count != 0 || !cases.Any(x => x.Item1.All(y => y is EmptyExpression))) { cases.Add(new Tuple <Expression[], Statement[]>( new Expression[] { new EmptyExpression() }, defaultstatements.ToArray() )); foreach (var n in defaultstatements) { n.Parent = ss; } defaultstatements.UpdateParents(); } // Set up the switch and replace the statements ss.Cases = cases.ToArray(); ss.UpdateParents(); // Rewrite the list of statements back, excluding the default case if (lbltarget.Parent is BlockStatement) { (lbltarget.Parent as BlockStatement).Statements = remainingstatements; (lbltarget.Parent as BlockStatement).UpdateParents(); } else { (lbltarget.Parent as Method).Statements = remainingstatements; foreach (var n in remainingstatements) { n.UpdateParents(); } } // Rewrite all goto's into break statements, requery the cases as we may have changed them goto_statements = ss.Cases.SelectMany(x => x.Item2).SelectMany(x => x.All()).OfType <GotoStatement>().ToList(); foreach (var n in goto_statements) { n.ReplaceWith(new EmptyStatement()); } return(null); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { if (State.Config.SUPPORTS_VHDL_2008) { return(el); } if (el is ConditionalExpression) { var ce = el as ConditionalExpression; if (CompressLogicalAssignments) { var pe = ce.Parent; if (pe is ParenthesizedExpression) { pe = pe.Parent; } // See if we can avoid introducing a temporary variable // when the conditional target is a boolean assignment if (pe is AssignmentExpression) { var ase = pe as AssignmentExpression; var tvhdl = State.VHDLType(ase.Left); var svhdl = State.VHDLType(ce); if (tvhdl == VHDLTypes.SYSTEM_BOOL && svhdl == VHDLTypes.SYSTEM_BOOL && ase.Operator == ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign) { var tg = ase.Left.GetTarget(); CreateIfElse(ce, tg); ase.ReplaceWith(new EmptyExpression() { Parent = ase.Parent, SourceExpression = ase.SourceExpression, SourceResultType = null }); return(null); } } } var tmp = State.RegisterTemporaryVariable(Method, ce.SourceResultType); State.TypeLookup[tmp] = State.VHDLType(ce); CreateIfElse(ce, tmp); var iex = new IdentifierExpression() { Name = tmp.Name, SourceExpression = ce.SourceExpression, SourceResultType = ce.SourceResultType, Target = tmp, }; State.TypeLookup[iex] = State.VHDLType(tmp); ce.ReplaceWith(iex); return(iex); } return(el); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public ASTItem Transform(ASTItem item) { if (!(item is AST.Method) || !((Method)item).IsStateMachine) { return(item); } var method = item as AST.Method; if (!method.All().OfType <AwaitExpression>().Any()) { return(item); } var enumname = "FSM_" + method.Name + "_State"; // Construct an enum type that matches the desired states var enumtype = new Mono.Cecil.TypeDefinition("", enumname, Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.AutoClass | Mono.Cecil.TypeAttributes.AnsiClass | Mono.Cecil.TypeAttributes.Sealed, method.SourceMethod.Module.ImportReference(typeof(System.Enum))) { IsSealed = true, }; enumtype.DeclaringType = method.SourceMethod.DeclaringType; enumtype.Fields.Add(new Mono.Cecil.FieldDefinition($"value__", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.SpecialName | Mono.Cecil.FieldAttributes.RTSpecialName, method.SourceMethod.Module.ImportReference(typeof(int)))); var statenametemplate = $"{enumtype.DeclaringType.FullName}_{enumname}_State"; var fragments = SplitIntoFragments(method.Statements); var statecount = fragments.Count; var enumfields = new Mono.Cecil.FieldDefinition[statecount]; // Add each of the states to the type for (var i = 0; i < statecount; i++) { enumtype.Fields.Add(enumfields[i] = new Mono.Cecil.FieldDefinition($"State{i}", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.Literal, enumtype) { Constant = i }); } // The variable being updated internally in the method var run_state_var = new AST.Variable("FSM_RunState", enumfields[0]) { CecilType = enumtype, DefaultValue = 0, Source = new Mono.Cecil.ParameterDefinition("FSM_RunState", Mono.Cecil.ParameterAttributes.None, enumtype) }; // The current state used in the state machine process var current_state_signal = new AST.Signal("FSM_CurrentState", enumfields[0]) { CecilType = enumtype, DefaultValue = 0, Source = new Mono.Cecil.ParameterDefinition("FSM_CurrentState", Mono.Cecil.ParameterAttributes.None, enumtype) }; // The next state that is propagated to var next_state_signal = new AST.Signal("FSM_NextState", enumfields[0]) { CecilType = enumtype, DefaultValue = 0, Source = new Mono.Cecil.ParameterDefinition("FSM_NextState", Mono.Cecil.ParameterAttributes.None, enumtype) }; // Construct a state-machine method, that will be rendered as a process var stateMachineProcess = new AST.Method() { Name = "FSM_" + method.Name + "_Method", Parameters = new AST.Parameter[0], ReturnVariable = null, Parent = method.Parent, Variables = method.AllVariables.Concat(new Variable[] { run_state_var }).ToArray(), AllVariables = method.AllVariables.Concat(new Variable[] { }).ToArray(), IsStateMachine = true }; var enumdataitems = enumfields.Select(x => new Constant(x.Name, x) { CecilType = enumtype }).ToArray(); var isSimpleStatePossible = fragments.SelectMany(x => x.SelectMany(y => y.All().OfType <CaseGotoStatement>())).All(x => !x.FallThrough); List <Statement> cases; // If we have no fallthrough states, we build a switch if (isSimpleStatePossible) { cases = new List <Statement>(new[] { new EmptyStatement(), CreateSwitchStatement(fragments, current_state_signal, enumdataitems) }); } // Otherwise, we build an if-based state machine else { cases = WrapFragmentsWithLabels(fragments, run_state_var, enumdataitems); cases.Insert(0, new ExpressionStatement( new AssignmentExpression( new IdentifierExpression(run_state_var), new IdentifierExpression(current_state_signal) ) )); } stateMachineProcess.Statements = cases.ToArray(); foreach (var v in stateMachineProcess.Statements) { v.Parent = stateMachineProcess; v.UpdateParents(); ReplaceGotoWithVariables(v, run_state_var, next_state_signal, enumdataitems); } method.Statements = new Statement[] { new ExpressionStatement( new AssignmentExpression( new IdentifierExpression(current_state_signal), new IdentifierExpression(next_state_signal) ) ) { Parent = method } }; method.IsStateMachine = false; var proc = method.GetNearestParent <Process>(); proc.Methods = proc.Methods.Concat(new[] { stateMachineProcess }).ToArray(); // Move variables into the shared area proc.InternalDataElements = proc.InternalDataElements .Union(new[] { current_state_signal, next_state_signal }) //.Union(method.AllVariables) .ToArray(); proc.SharedVariables = proc.SharedVariables.Union(method.AllVariables).ToArray(); method.Variables = new Variable[0]; method.AllVariables = new Variable[0]; return(stateMachineProcess); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="item">The item to visit.</param> public ASTItem Transform(ASTItem item) { var stm = item as AST.ForStatement; if (stm == null) { return(item); } if (m_processed.Contains(stm)) { return(item); } m_processed.Add(stm); Tuple <int, int, int> loopedges = null; try { loopedges = stm.GetStaticForLoopValues(); } catch { return(item); } var incr = loopedges.Item3; if (incr == 1) { return(item); } var tmp = State.RegisterTemporaryVariable(Method, stm.LoopIndex.CecilType); State.TypeLookup[tmp] = VHDLTypes.INTEGER; // Find the first expression, so we can inject the assignment before it var firstexp = stm.LoopBody.All().OfType <Expression>().First(); // Replace all the references foreach (var x in stm.All().OfType <Expression>()) { var target = x.GetTarget(); if (target == stm.LoopIndex) { x.SetTarget(tmp); } } var exp = firstexp.SourceExpression; // Inject the assignment var nstm = new ExpressionStatement() { Expression = new AssignmentExpression() { Left = new IdentifierExpression() { Name = tmp.Name, Target = tmp, SourceExpression = exp, SourceResultType = tmp.CecilType }, Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, Right = new BinaryOperatorExpression() { Left = new IdentifierExpression() { Name = stm.LoopIndex.Name, Target = stm.LoopIndex, SourceExpression = exp, SourceResultType = stm.LoopIndex.CecilType }, Operator = ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Multiply, Right = new PrimitiveExpression() { Value = incr, SourceResultType = tmp.CecilType, SourceExpression = exp, }, SourceExpression = exp, SourceResultType = tmp.CecilType }, SourceExpression = exp, SourceResultType = tmp.CecilType } }; nstm.UpdateParents(); foreach (var x in nstm.All().OfType <Expression>()) { State.TypeLookup[x] = VHDLTypes.INTEGER; } stm.LoopBody.PrependStatement(nstm); //Do not fix again stm.Increment = new AssignmentExpression( new IdentifierExpression(stm.LoopIndex), new BinaryOperatorExpression( new IdentifierExpression(stm.LoopIndex), ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Add, new PrimitiveExpression(1, tmp.CecilType) ) { SourceResultType = tmp.CecilType } ) { Parent = stm, SourceResultType = tmp.CecilType }; stm.Condition = new BinaryOperatorExpression( new IdentifierExpression(stm.LoopIndex), ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.LessThan, new PrimitiveExpression(loopedges.Item2 / loopedges.Item3, tmp.CecilType.Module.ImportReference(typeof(int))) ) { Parent = stm, SourceResultType = tmp.CecilType.Module.ImportReference(typeof(bool)) }; return(nstm); }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { var uoe = el as UnaryOperatorExpression; if (uoe == null) { return(el); } var incr = new[] { ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.Increment, ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.Decrement, ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostIncrement, ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostDecrement }.Contains(uoe.Operator); if (!incr) { return(el); } var cnst = new PrimitiveExpression() { SourceExpression = uoe.SourceExpression, SourceResultType = uoe.SourceResultType.LoadType(typeof(int)), Value = 1 }; State.TypeLookup[cnst] = VHDLTypes.INTEGER; var boe = new BinaryOperatorExpression() { Left = uoe.Operand.Clone(), Right = cnst, SourceExpression = uoe.SourceExpression, SourceResultType = uoe.SourceResultType, Operator = uoe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.Decrement || uoe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostDecrement ? ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Subtract : ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Add }; State.TypeLookup[boe] = State.VHDLType(uoe.Operand); // Prepare an assignment expresion var ase = new AssignmentExpression() { Left = uoe.Operand.Clone(), Right = boe, Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, SourceExpression = uoe.SourceExpression, SourceResultType = uoe.SourceResultType }; var exps = new ExpressionStatement() { Expression = ase, }; exps.UpdateParents(); if (uoe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostIncrement || uoe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostDecrement) { if (uoe.Parent is ExpressionStatement || uoe.Parent is ForStatement) { // Simple "i++;" statements are replaced with i = i + 1 uoe.ReplaceWith(ase); return(ase); } else { // More complicated are split uoe.AppendStatement(exps); // Remove the operator now, as the assignment happens after uoe.ReplaceWith(uoe.Operand); return(exps); } } else { // If the left-hand-side is also the target, we can just replace // with the binary operator without needing a temporary variable if (uoe.Operand.GetTarget() != null && boe.Parent is AssignmentExpression && ((AssignmentExpression)boe.Parent).Left.GetTarget() == uoe.Operand.GetTarget()) { uoe.ReplaceWith(boe); return(boe); } else { // TODO: Can have more complex cases where // the expression is use multiple times in the same statement and some need the updated version, // others the non-updated version. // To support this, we need to seek for references to the target // and replace the references with the correct pre/post versions uoe.PrependStatement(exps); uoe.ReplaceWith(boe); return(boe); } } }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { var ss = el as SwitchStatement; if (ss == null) return el; var exptype = State.VHDLType(ss.SwitchExpression); // Extract expression types var targets = ss .Cases .SelectMany(x => x.Item1) .Where(x => x != null && !(x is EmptyExpression)) .Select(x => State.VHDLType(x)) .Distinct() .ToArray(); // Case where the expressions are all integer literals, // but the source is some numeric if (targets.Length == 1 && targets.First() != exptype) { var mp = ss.GetNearestParent<Method>(); if (mp != null) { var targettype = ss .Cases .SelectMany(x => x.Item1) .First(x => x != null && !(x is EmptyExpression)) .SourceResultType; // Create a variable the same type as the cases // and set it to the switch expression var nvar = State.RegisterTemporaryVariable(mp, targettype); State.TypeLookup[nvar] = targets.First(); var nvexp = new IdentifierExpression() { Name = nvar.Name, SourceExpression = ss.SwitchExpression.SourceExpression, SourceResultType = nvar.CecilType, Target = nvar }; var asss = new AST.ExpressionStatement() { Expression = new AST.AssignmentExpression() { Left = nvexp, Operator = ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign, Right = ss.SwitchExpression, SourceExpression = ss.SwitchExpression.SourceExpression, SourceResultType = nvar.CecilType } }; ss.SwitchExpression = nvexp.Clone(); ss.SwitchExpression.Parent = ss; asss.UpdateParents(); ss.PrependStatement(asss); return null; } } return el; }
/// <summary> /// Applies the transformation /// </summary> /// <returns>The transformed item.</returns> /// <param name="el">The item to visit.</param> public ASTItem Transform(ASTItem el) { if (m_done.ContainsKey(el)) { return(el); } var res = el; if (el is AST.BinaryOperatorExpression) { var boe = ((AST.BinaryOperatorExpression)el); var tvhdl = State.VHDLType(boe); var le = boe.Left; var re = boe.Right; var le_type = State.VHDLType(le); var re_type = State.VHDLType(re); Mono.Cecil.TypeReference tvhdlsource = boe.SourceResultType; if ((boe.Operator.IsArithmeticOperator() || boe.Operator.IsCompareOperator())) { if (tvhdl != VHDLTypes.INTEGER) { tvhdl = State.TypeScope.NumericEquivalent(tvhdl, false) ?? tvhdl; } } else if (boe.Operator == BinaryOperatorType.ShiftLeft || boe.Operator == BinaryOperatorType.ShiftRight) { // Handle later } else if (boe.Operator.IsBitwiseOperator()) { tvhdl = State.TypeScope.SystemEquivalent(tvhdl); } var lhstype = le_type; var rhstype = re_type; var lhssource = boe.Left.SourceResultType; var rhssource = boe.Right.SourceResultType; if (boe.Operator.IsLogicalOperator()) { // Force both sides to booleans lhstype = VHDLTypes.BOOL; rhstype = VHDLTypes.BOOL; lhssource = rhssource = boe.SourceResultType.LoadType(typeof(bool)); } else if (boe.Operator.IsArithmeticOperator() || boe.Operator.IsBitwiseOperator()) { // Force both sides to the result type lhstype = tvhdl; rhstype = tvhdl; } else if (boe.Operator.IsCompareOperator()) { // Use whatever is not unconstrained integer for the compare if (lhstype == VHDLTypes.INTEGER) { lhstype = rhstype; } else { rhstype = lhstype; } } if (boe.Operator == BinaryOperatorType.ShiftLeft || boe.Operator == BinaryOperatorType.ShiftRight) { rhstype = VHDLTypes.INTEGER; if (lhstype == VHDLTypes.INTEGER) { var p = boe.Parent; while (p is AST.ParenthesizedExpression) { p = p.Parent; } lhstype = State.VHDLType(p as AST.Expression); lhssource = ((AST.Expression)p).SourceResultType; } else { lhstype = State.TypeScope.NumericEquivalent(lhstype); } } // Overrides for special types switch (boe.Operator) { case BinaryOperatorType.ShiftLeft: case BinaryOperatorType.ShiftRight: rhssource = boe.SourceResultType.LoadType(typeof(int)); rhstype = VHDLTypes.INTEGER; break; } var newleft = VHDLTypeConversion.ConvertExpression(State, Method, boe.Left, lhstype, lhssource, false); var newright = VHDLTypeConversion.ConvertExpression(State, Method, boe.Right, rhstype, rhssource, false); if (boe.Operator.IsLogicalOperator() || boe.Operator.IsCompareOperator()) { State.TypeLookup[boe] = VHDLTypes.BOOL; } else { State.TypeLookup[boe] = tvhdl; } if (boe.Operator == BinaryOperatorType.Multiply && tvhdl != VHDLTypes.INTEGER) { VHDLTypeConversion.WrapExpression(State, boe, string.Format("resize({0}, {1})", "{0}", tvhdl.Length), tvhdl); m_done[boe] = string.Empty; return(null); } if (newleft != le || newright != re) { return(null); } } else if (el is AST.AssignmentExpression) { var ase = ((AST.AssignmentExpression)el); var tvhdl = State.VHDLType(ase.Left); var r = ase.Right; ase.SourceResultType = ase.Left.SourceResultType; var n = VHDLTypeConversion.ConvertExpression(State, Method, ase.Right, tvhdl, ase.Left.SourceResultType, false); State.TypeLookup[ase] = State.TypeLookup[n] = tvhdl; if (n != r) { return(null); } } else if (el is AST.CastExpression) { var cse = ((AST.CastExpression)el); var tvhdl = State.VHDLType(cse); if (cse.Parent is AST.BinaryOperatorExpression) { var pboe = cse.Parent as AST.BinaryOperatorExpression; if (pboe.Right == cse && (pboe.Operator == BinaryOperatorType.ShiftLeft || pboe.Operator == BinaryOperatorType.ShiftRight)) { tvhdl = VHDLTypes.INTEGER; } } res = cse.ReplaceWith( VHDLTypeConversion.ConvertExpression(State, Method, cse.Expression, tvhdl, cse.SourceResultType, true) ); State.TypeLookup[cse] = State.TypeLookup[res] = tvhdl; return(res); } else if (el is AST.IndexerExpression) { var ie = ((AST.IndexerExpression)el); var tvhdl = VHDLTypes.INTEGER; var r = ie.IndexExpression; var n = VHDLTypeConversion.ConvertExpression(State, Method, ie.IndexExpression, tvhdl, ie.SourceResultType.LoadType(typeof(int)), false); State.TypeLookup[n] = tvhdl; State.TypeLookup[ie] = State.TypeScope.GetByName(State.VHDLType(ie.Target).ElementName); if (n != r) { return(null); } } else if (el is AST.IfElseStatement) { var ies = el as AST.IfElseStatement; var tvhdl = VHDLTypes.BOOL; var r = ies.Condition; var n = VHDLTypeConversion.ConvertExpression(State, Method, ies.Condition, tvhdl, r.SourceResultType.LoadType(typeof(bool)), false); State.TypeLookup[n] = tvhdl; if (n != r) { return(null); } } else if (el is AST.UnaryOperatorExpression) { var uoe = el as AST.UnaryOperatorExpression; if (uoe.Operator == UnaryOperatorType.Not) { var tvhdl = VHDLTypes.BOOL; var n = VHDLTypeConversion.ConvertExpression(State, Method, uoe.Operand, tvhdl, uoe.SourceResultType.LoadType(typeof(bool)), false); State.TypeLookup[n] = tvhdl; if (n != uoe.Operand) { return(null); } } } else if (el is AST.InvocationExpression) { var ie = el as AST.InvocationExpression; var method = (AST.Method)ie.Target; var changed = false; for (var i = 0; i < ie.ArgumentExpressions.Length; i++) { var a = ie.ArgumentExpressions[i]; if (a is AST.PrimitiveExpression) { var tvhdl = State.TypeScope.GetVHDLType(method.Parameters[i].CecilType); changed |= VHDLTypeConversion.ConvertExpression(State, Method, a, tvhdl, a.SourceResultType, false) != a; } } } return(res); }