/// <summary> /// Renders a single ForStatement with the given indentation /// </summary> /// <returns>The VHDL lines in the statement.</returns> /// <param name="method">The method the statement belongs to.</param> /// <param name="s">The statement to render.</param> /// <param name="indentation">The indentation to use.</param> private IEnumerable <string> RenderStatement(AST.Method method, AST.ForStatement s, int indentation) { var edges = s.GetStaticForLoopValues(); var endval = edges.Item2; endval--; var indent = new string(' ', indentation); yield return($"{indent}for {s.LoopIndex.Name} in {edges.Item1} to {endval} loop"); var incr = edges.Item3; if (incr != 1) { throw new Exception($"Expected the for loop to have an increment of 1, it has {incr}"); } foreach (var n in RenderStatement(method, s.LoopBody, indentation + 4)) { yield return(n); } yield return($"{indent}end loop;"); }
/// <summary> /// Renders a single ForStatement with the given indentation /// </summary> /// <returns>The VHDL lines in the statement.</returns> /// <param name="method">The method the statement belongs to.</param> /// <param name="s">The statement to render.</param> /// <param name="indentation">The indentation to use.</param> private IEnumerable <string> RenderStatement(AST.Method method, AST.ForStatement s, int indentation) { var edges = s.GetStaticForLoopValues(); var endval = edges.Item2; var incr = edges.Item3; var indent = new string(' ', indentation); yield return($"{indent}for (size_t {s.LoopIndex.Name} = {edges.Item1}; {s.LoopIndex.Name} < {endval}; {s.LoopIndex.Name} += {incr}) {{"); foreach (var n in RenderStatement(method, s.LoopBody, indentation + 4)) { yield return(n); } yield return($"{indent}}}"); }
/// <summary> /// Creates a new variable instnace /// </summary> /// <param name="source">The source item</param> public ForLoop(AST.ForStatement source) { Source = source ?? throw new ArgumentNullException(nameof(source)); }
/// <summary> /// Returns the start, end and increment integer values for a statically sized for loop /// </summary> /// <returns>The static for loop start, end and increment values.</returns> /// <param name="self">The statement to extract the values for.</param> public static Tuple <int, int, int> GetStaticForLoopValues(this AST.ForStatement self) { int start, end, incr; if (!(self.Initializer is AST.PrimitiveExpression)) { throw new Exception($"Unable to statically expand loop initializer: {self.Initializer.SourceExpression}"); } if (!(self.Condition is AST.BinaryOperatorExpression)) { throw new Exception($"Unable to statically expand loop initializer: {self.Condition.SourceExpression}"); } if (((BinaryOperatorExpression)self.Condition).Operator != ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.LessThan) { throw new Exception($"Can only statically expand loops with a less-than operator: {self.Condition.SourceExpression}"); } start = ResolveIntegerValue(self.Initializer); var cond_left = ((BinaryOperatorExpression)self.Condition).Left.GetUnwrapped(); var cond_right = ((BinaryOperatorExpression)self.Condition).Right.GetUnwrapped(); if (cond_left.GetTarget() != self.LoopIndex) { throw new Exception($"Can only statically expand loops where the left side of the condition is the loop variable"); } if (cond_right is PrimitiveExpression || cond_right.GetTarget() != null) { end = ResolveIntegerValue(cond_right); } else if (cond_right is BinaryOperatorExpression) { var boe = cond_right as BinaryOperatorExpression; if (boe.Operator != ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Add && boe.Operator != ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Subtract) { throw new Exception($"Can only statically expand loops if the condition is a simple add/subtract operation: {boe.SourceExpression}"); } var lefttarget = boe.Left.GetTarget(); if (lefttarget == null) { throw new Exception($"Can only statically expand loops if the condition is a simple add/subtract operation: {boe.SourceExpression}"); } var left_opr = ResolveIntegerValue(boe.Left); var right_opr = ResolveIntegerValue(boe.Right); if (boe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Add) { end = left_opr + right_opr; } else { end = left_opr - right_opr; } } else { throw new Exception($"Can only statically expand loops if the condition is a simple add/subtract operation: {self.Condition.SourceExpression}"); } if (self.Increment is UnaryOperatorExpression) { var uoe = self.Increment as UnaryOperatorExpression; if (uoe.Operand.GetTarget() != self.LoopIndex) { throw new Exception($"The item in the loop increment must be the loop variable: {self.Increment.SourceExpression}"); } if (uoe.Operator != ICSharpCode.Decompiler.CSharp.Syntax.UnaryOperatorType.PostIncrement) { throw new Exception($"The item in the loop increment must be the loop variable with post increment: {self.Increment.SourceExpression}"); } incr = 1; } else if (self.Increment is AssignmentExpression) { var boe = self.Increment as AssignmentExpression; if (boe.Left.GetTarget() != self.LoopIndex) { throw new Exception($"The item in the loop increment must be the loop variable: {self.Increment.SourceExpression}"); } if (boe.Operator == ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Assign && boe.Right.GetUnwrapped() is BinaryOperatorExpression) { var boee = boe.Right.GetUnwrapped() as BinaryOperatorExpression; if (boee.Operator != ICSharpCode.Decompiler.CSharp.Syntax.BinaryOperatorType.Add) { throw new Exception($"The item in the loop increment must be a simple addition: {self.Increment.SourceExpression}"); } if (boee.Left.GetTarget() != self.LoopIndex) { throw new Exception($"The item in the loop increment must be the loop variable: {self.Increment.SourceExpression}"); } incr = ResolveIntegerValue(boee.Right); } else { if (boe.Operator != ICSharpCode.Decompiler.CSharp.Syntax.AssignmentOperatorType.Add) { throw new Exception($"The item in the loop increment must be a simple addition: {self.Increment.SourceExpression}"); } incr = ResolveIntegerValue(boe.Right); } } else { throw new Exception($"Can only statically expand loops if the increment is a simple constant: {self.Condition.SourceExpression}"); } return(new Tuple <int, int, int>(start, end, incr)); }