private static void outputNumericalValueOutput(ControlFlowGraph graph, SyntaxNode node, HashSet <SyntaxNode> history, StringBuilder builder)
        {
            if (!history.Contains(node))
            {
                history.Add(node);
                builder.AppendFormat("  {{ \"key\": \"{0}\",\n    \"value\": ", location(node));
                if (node is LocalDeclarationStatementSyntax || node is VariableDeclarationSyntax)
                {
                    VariableDeclarationSyntax s;
                    if (node is LocalDeclarationStatementSyntax)
                    {
                        s = (node as LocalDeclarationStatementSyntax).Declaration;
                    }
                    else
                    {
                        s = node as VariableDeclarationSyntax;
                    }
                    builder.Append("{ \"type\": \"variable_declaration\", \"declarations\": [");

                    bool firstVar = true;
                    foreach (var v in s.Variables)
                    {
                        if (firstVar)
                        {
                            firstVar = false;
                        }
                        else
                        {
                            builder.Append(",");
                        }
                        builder.AppendFormat(" {{ \"identifier\": \"{0}\", \"initializer\": ", v.Identifier);
                        if (v.Initializer == null)
                        {
                            builder.Append("null");
                        }
                        else
                        {
                            outputNumericalValueOutput(v.Initializer.Value, builder);
                        }
                        builder.Append(" }");
                    }
                    builder.Append(" ] }");
                }
                else if (node is AssignmentExpressionSyntax || (node is ExpressionStatementSyntax && (node as ExpressionStatementSyntax).Expression is AssignmentExpressionSyntax))
                {
                    AssignmentExpressionSyntax s;
                    if (node is AssignmentExpressionSyntax)
                    {
                        s = node as AssignmentExpressionSyntax;
                    }
                    else
                    {
                        s = (node as ExpressionStatementSyntax).Expression as AssignmentExpressionSyntax;
                    }
                    builder.AppendFormat("{{ \"type\": \"variable_assignment\", \"left\": \"{0}\", \"right\": ", s.Left);
                    outputNumericalValueOutput(s.Right, builder);
                    builder.Append(" }");
                }
                else if (node is BinaryExpressionSyntax)
                {
                    builder.Append("{ \"type\": \"comparison\", \"left\": ");
                    var s = node as BinaryExpressionSyntax;
                    outputNumericalValueOutput(s.Left, builder);
                    builder.AppendFormat(", \"op\": \"{0}\", \"right\": ", s.OperatorToken);
                    outputNumericalValueOutput(s.Right, builder);
                    builder.Append(" }");
                }
                else
                {
                    builder.Append("{ \"type\": \"other\" }");
                }
                builder.Append(",\n    \"successors\": [");
                bool firstSucc = true;
                foreach (var succ in graph.GetSuccessorsB(node))
                {
                    if (firstSucc)
                    {
                        firstSucc = false;
                    }
                    else
                    {
                        builder.Append(", ");
                    }
                    builder.AppendFormat("{{ \"key\": \"{0}\", \"value\": {1} }}", location(succ.Key), succ.Value);
                }
                builder.Append("] }");
                foreach (var succ in graph.GetSuccessors(node))
                {
                    if (!history.Contains(succ))
                    {
                        builder.Append(",\n");
                    }
                    outputNumericalValueOutput(graph, succ, history, builder);
                }
            }
        }
        private void analyze(ControlFlowGraph graph, SyntaxNode node, Dictionary <string, NumericalValue <int> > variables, Dictionary <SyntaxNode, Dictionary <string, NumericalValue <int> > > history)
        {
            #region Union usagesAfter with reachingDefinitions
            if (history.ContainsKey(node))
            {
                bool anyChanged = false;
                foreach (var pair in history[node])
                {
                    if (variables.ContainsKey(pair.Key))
                    {
                        var    i   = variables[pair.Key];
                        string old = i.ToString();
                        //Console.WriteLine("{0} vs {1} and {2}", old, i, pair.Value);
                        i.UnionWith(pair.Value);
                        if (!old.Equals(i.ToString()))
                        {
                            anyChanged = true;
                        }
                    }
                    else
                    {
                        variables.Add(pair.Key, pair.Value.Clone());
                        anyChanged = true;
                    }
                }
                if (history[node].Count == 0 && variables.Count != 0)
                {
                    anyChanged = true;
                }
                if (!anyChanged)
                {
                    return;
                }
                else
                {
                    var clone = new Dictionary <string, NumericalValue <int> >();
                    foreach (var v in variables)
                    {
                        clone.Add(v.Key, v.Value.Clone());
                    }
                    history[node] = clone;
                }
            }
            else
            {
                var clone = new Dictionary <string, NumericalValue <int> >();
                foreach (var v in variables)
                {
                    clone.Add(v.Key, v.Value.Clone());
                }
                history.Add(node, clone);
            }
            #endregion

            NumericalValue <int> rangeTrue  = null;
            NumericalValue <int> rangeFalse = null;
            string rangeVar = null;

            #region Process node
            if (node is LocalDeclarationStatementSyntax || node is VariableDeclarationSyntax)
            {
                VariableDeclarationSyntax s;
                if (node is LocalDeclarationStatementSyntax)
                {
                    s = (node as LocalDeclarationStatementSyntax).Declaration;
                }
                else
                {
                    s = node as VariableDeclarationSyntax;
                }

                foreach (var v in s.Variables)
                {
                    if (v.Initializer != null)
                    {
                        if (v.Initializer.Value is LiteralExpressionSyntax)
                        {
                            var valS = (v.Initializer.Value as LiteralExpressionSyntax).Token.ValueText;
                            int valI;
                            if (int.TryParse(valS, out valI))
                            {
                                var valNV = new NumericalValue <int>(valI);
                                if (variables.ContainsKey(v.Identifier.ToString()))
                                {
                                    variables[v.Identifier.ToString()].AssignValue(valNV);
                                }
                                else
                                {
                                    variables.Add(v.Identifier.ToString(), valNV);
                                }
                            }
                        }
                        else if (v.Initializer.Value is IdentifierNameSyntax)
                        {
                            var valNV = variables[v.Initializer.Value.ToString()];
                            if (variables.ContainsKey(v.Identifier.ToString()))
                            {
                                variables[v.Identifier.ToString()].AssignValue(valNV);
                            }
                            else
                            {
                                variables.Add(v.Identifier.ToString(), valNV);
                            }
                        }
                        else
                        {
                            var valNV = new NumericalValue <int>(int.MinValue, Inclusivity.INCLUSIVE, int.MaxValue, Inclusivity.INCLUSIVE);
                            if (variables.ContainsKey(v.Identifier.ToString()))
                            {
                                variables[v.Identifier.ToString()].AssignValue(valNV);
                            }
                            else
                            {
                                variables.Add(v.Identifier.ToString(), valNV);
                            }
                        }
                    }
                }
            }
            else if (node is ExpressionStatementSyntax && (node as ExpressionStatementSyntax).Expression is AssignmentExpressionSyntax)
            {
                var s = (node as ExpressionStatementSyntax).Expression as AssignmentExpressionSyntax;
                if (s.Right is LiteralExpressionSyntax)
                {
                    var valS = (s.Right as LiteralExpressionSyntax).Token.ValueText;
                    int valI;
                    if (int.TryParse(valS, out valI))
                    {
                        var valNV = new NumericalValue <int>(valI);
                        if (variables.ContainsKey(s.Left.ToString()))
                        {
                            variables[s.Left.ToString()].AssignValue(valNV);
                        }
                        else
                        {
                            variables.Add(s.Left.ToString(), valNV);
                        }
                    }
                }
                else if (s.Right is IdentifierNameSyntax)
                {
                    var valNV = variables[s.Right.ToString()];
                    if (variables.ContainsKey(s.Left.ToString()))
                    {
                        variables[s.Left.ToString()].AssignValue(valNV);
                    }
                    else
                    {
                        variables.Add(s.Left.ToString(), valNV);
                    }
                }
                else
                {
                    var valNV = new NumericalValue <int>(int.MinValue, Inclusivity.INCLUSIVE, int.MaxValue, Inclusivity.INCLUSIVE);
                    if (variables.ContainsKey(s.Left.ToString()))
                    {
                        variables[s.Left.ToString()].AssignValue(valNV);
                    }
                    else
                    {
                        variables.Add(s.Left.ToString(), valNV);
                    }
                }
            }
            else if (node is BinaryExpressionSyntax)
            {
                var n = node as BinaryExpressionSyntax;
                if (n.Right is LiteralExpressionSyntax)
                {
                    int value;
                    if (int.TryParse((n.Right as LiteralExpressionSyntax).Token.ValueText, out value))
                    {
                        if (n.OperatorToken.ToString().Equals("<"))
                        {
                            rangeTrue  = new NumericalValue <int>(int.MinValue, Inclusivity.INCLUSIVE, value, Inclusivity.EXCLUSIVE);
                            rangeFalse = new NumericalValue <int>(value, Inclusivity.INCLUSIVE, int.MaxValue, Inclusivity.INCLUSIVE);
                            rangeVar   = n.Left.ToString();
                        }
                        if (n.OperatorToken.ToString().Equals("<="))
                        {
                            rangeTrue  = new NumericalValue <int>(int.MinValue, Inclusivity.INCLUSIVE, value, Inclusivity.INCLUSIVE);
                            rangeFalse = new NumericalValue <int>(value, Inclusivity.EXCLUSIVE, int.MaxValue, Inclusivity.INCLUSIVE);
                            rangeVar   = n.Left.ToString();
                        }
                        if (n.OperatorToken.ToString().Equals(">"))
                        {
                            rangeTrue  = new NumericalValue <int>(value, Inclusivity.EXCLUSIVE, int.MaxValue, Inclusivity.INCLUSIVE);
                            rangeFalse = new NumericalValue <int>(int.MinValue, Inclusivity.INCLUSIVE, value, Inclusivity.INCLUSIVE);
                            rangeVar   = n.Left.ToString();
                        }
                        if (n.OperatorToken.ToString().Equals(">="))
                        {
                            rangeTrue  = new NumericalValue <int>(value, Inclusivity.INCLUSIVE, int.MaxValue, Inclusivity.INCLUSIVE);
                            rangeFalse = new NumericalValue <int>(int.MinValue, Inclusivity.INCLUSIVE, value, Inclusivity.EXCLUSIVE);
                            rangeVar   = n.Left.ToString();
                        }
                    }
                }
            }

            if (debug)
            {
                Console.WriteLine("({0}): {1} {2}", node.GetLocation().GetLineSpan().StartLinePosition, node, node.GetType());
                foreach (var pair in variables)
                {
                    Console.WriteLine("  {0} -> {1}", pair.Key, pair.Value);
                }
            }
            #endregion

            #region Recurse
            foreach (var succ in graph.GetSuccessorsB(node))
            {
                var variablesPrime = new Dictionary <string, NumericalValue <int> >();
                foreach (var v in variables)
                {
                    variablesPrime.Add(v.Key, v.Value.Clone());
                }
                if (succ.Value == 0)
                {
                    variablesPrime[rangeVar].IntersectWith(rangeFalse);
                }
                else if (succ.Value == 1)
                {
                    variablesPrime[rangeVar].IntersectWith(rangeTrue);
                }
                analyze(graph, succ.Key, variablesPrime, history);
            }
            #endregion
        }
        static void Main(string[] args)
        {
            /*{
             *  var n = new NumericalValue<int>();
             *  n.UnionWith(new NumericalValue<int>(0, Inclusivity.INCLUSIVE, 3, Inclusivity.INCLUSIVE));
             *  AssertEquals(n.ToString(), "[0, 3]");
             *  n.UnionWith(new NumericalValue<int>(0, Inclusivity.INCLUSIVE, 3, Inclusivity.INCLUSIVE));
             *  AssertEquals(n.ToString(), "[0, 3]");
             *  n.UnionWith(new NumericalValue<int>(1, Inclusivity.INCLUSIVE, 4, Inclusivity.EXCLUSIVE));
             *  AssertEquals(n.ToString(), "[0, 4)");
             *  n.UnionWith(new NumericalValue<int>(7, Inclusivity.INCLUSIVE, 10, Inclusivity.INCLUSIVE));
             *  AssertEquals(n.ToString(), "[0, 4) U [7, 10]");
             *  n.UnionWith(new NumericalValue<int>(6, Inclusivity.INCLUSIVE, 7, Inclusivity.EXCLUSIVE));
             *  AssertEquals(n.ToString(), "[0, 4) U [6, 10]");
             *  n.UnionWith(new NumericalValue<int>(3, Inclusivity.INCLUSIVE, 7, Inclusivity.EXCLUSIVE));
             *  AssertEquals(n.ToString(), "[0, 10]");
             * }
             * {
             *  var n = new NumericalValue<int>();
             *  n.UnionWith(new NumericalValue<int>(0, Inclusivity.INCLUSIVE, 4, Inclusivity.EXCLUSIVE));
             *  n.UnionWith(new NumericalValue<int>(6, Inclusivity.INCLUSIVE, 10, Inclusivity.INCLUSIVE));
             *  n.UnionWith(new NumericalValue<int>(-2, Inclusivity.INCLUSIVE, -2, Inclusivity.INCLUSIVE));
             *  n.UnionWith(new NumericalValue<int>(14, Inclusivity.EXCLUSIVE, 15, Inclusivity.EXCLUSIVE));
             *  AssertEquals(n.ToString(), "[-2, -2] U [0, 4) U [6, 10] U (14, 15)");
             *  n.IntersectWith(3, Inclusivity.INCLUSIVE, 6, Inclusivity.INCLUSIVE);
             *  AssertEquals(n.ToString(), "[3, 4) U [6, 6]");
             * }*/

            SyntaxTree tree = CSharpSyntaxTree.ParseText(
                @"using System;
            using System.Collections;
            using System.Linq;
            using System.Text;
 
            namespace HelloWorld
            {
                class ProgramUnderTest
                {

static void Main(string[] args) {}
int f() { return 4; }

private void Test() {
    int j = 3;
    for (int i = 0; i < 10; i = i + 1) {
        if (i > j) { j = i + 1; }
    }
    return;
/*
    int i = 0;
    i = 3;
    int j = f();
    if (j + 3 > 5) {
        i = j;
    } else {
        i = -1;
    }
    return;*/
}
                }
            }");

            var diagnostics = new List <NumericValueDiagnostic>();
            var compilation = CompileCode(tree);
            var model       = compilation.GetSemanticModel(tree);

            foreach (var c in tree.GetRoot().DescendantNodes().OfType <ClassDeclarationSyntax>())
            {
                foreach (var m in c.DescendantNodes().OfType <MethodDeclarationSyntax>())
                {
                    if (m.Identifier.ToString().Equals("Test"))
                    {
                        ControlFlowGraph controlFlowGraph = new ControlFlowGraph(m, model);
                        Console.WriteLine("digraph {0} {{", "Test");
                        HashSet <SyntaxNode> visitedNodes = new HashSet <SyntaxNode>();
                        printGraphViz(controlFlowGraph, controlFlowGraph.GetEntryPoint(), visitedNodes);
                        Console.WriteLine();
                        foreach (var node in visitedNodes)
                        {
                            if (node.GetLocation().ToString().Contains("[0..7)"))
                            {
                                Console.WriteLine("\"{0}\" [color=\"#55AAFF\"];", node.GetLocation().ToString());
                            }
                            Console.WriteLine("\"{0}\" [label=\"{1}\"];", node.GetLocation().ToString(), interpolateLabel(node.ToFullString()));
                        }
                        Console.WriteLine("}");

                        Console.Write("\n\n\n");

                        /*NumericalValueAnalysis numericalValueAnalysis = new NumericalValueAnalysis(controlFlowGraph);*/
                        StringBuilder builder = new StringBuilder();
                        builder.Append("{ \"nodes\": [\n");
                        outputNumericalValueOutput(controlFlowGraph, controlFlowGraph.GetEntryPoint(), new HashSet <SyntaxNode>(), builder);
                        builder.Append("\n] }");

                        Console.WriteLine("Builder: '\n{0}\n'", builder);
                        System.IO.File.WriteAllText("input_code.json", builder.ToString());

                        var process = new System.Diagnostics.Process();
                        process.StartInfo.FileName       = "numerical_value.exe";
                        process.StartInfo.Arguments      = "input_code.json diagnostics.json";
                        process.StartInfo.CreateNoWindow = true;
                        process.Start();
                        process.WaitForExit();

                        diagnostics.AddRange(Newtonsoft.Json.JsonConvert.DeserializeObject <List <NumericValueDiagnostic> >(System.IO.File.ReadAllText("diagnostics.json")));
                        foreach (var diagnostic in diagnostics)
                        {
                            Console.WriteLine("{0}: This is always {1}", diagnostic.location, diagnostic.always_true);
                        }
                    }
                }
            }


            Console.WriteLine();
            Console.Write("Press enter to continue...");
            Console.ReadLine();
        }
 public NumericalValueAnalysis(ControlFlowGraph graph)
 {
     analyze(graph, graph.GetEntryPoint(), new Dictionary <string, NumericalValue <int> >(), new Dictionary <SyntaxNode, Dictionary <string, NumericalValue <int> > >());
 }