예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        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;
                    }
                }
            }
        }
예제 #8
0
        /// <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);
        }
예제 #9
0
        /// <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);
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        /// <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);
        }
예제 #12
0
        /// <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);
        }
예제 #13
0
        /// <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);
        }
예제 #14
0
        /// <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);
        }
예제 #15
0
        /// <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);
        }
예제 #16
0
        /// <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);
        }
예제 #17
0
        /// <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;
             * }
             */
        }
예제 #18
0
        /// <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);
        }
예제 #19
0
        /// <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);
        }
예제 #20
0
        /// <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);
        }
예제 #21
0
        /// <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);
        }
예제 #22
0
        /// <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);
                }
            }
        }
예제 #23
0
        /// <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;
        }
예제 #24
0
        /// <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);
        }