Example #1
0
        public static string MultilineCloseReplacement(Match m)
        {
            if (m is null)
            {
                throw new ArgumentNullException(nameof(m));
            }

            string x = m.ToString();

            if (!x.Contains(","))
            {
                return(x);
            }

            x = x.Trim();
            var    parts  = x.split(@"\s+", 2);
            var    parts2 = parts[1].split(",");
            string join   = Translator.NewLine;

            foreach (var part in parts2)
            {
                join += parts[0].Trim() + " " + part.Trim() + Translator.NewLine;
            }
            DebugClass.LogError("CLOSE: " + m.toString() + ", JOIN: " + join);
            return(join);
            //return x.ToUpper();
        }
        public static bool CanTranslate(Translator translator, ParseTree tree)
        {
            if (tree == null)
            {
                throw new ArgumentNullException(nameof(tree));
            }
            if (translator == null)
            {
                throw new ArgumentNullException(nameof(translator));
            }
            var name = VbToCsharpPattern.LookupNodeType(tree);

            if (name == null)
            {
                throw new NullReferenceException(nameof(name));
            }
            if (compiledPatterns == null)
            {
                throw new NullReferenceException(nameof(compiledPatterns));
            }

            var canTranslate = compiledPatterns.ContainsKey(name);

            if (canTranslate)
            {
                canTranslate = false;
                foreach (var pattern in compiledPatterns[name])
                {
                    if (pattern.CanTranslate(translator.GetChildren, tree))
                    {
                        canTranslate = true;
                        break;
                    }
                    ;
                }

                if (!canTranslate)
                {
                    DebugClass.LogError("PATTERN NODE: " + name + ", CASE: " + tree.getText());
                    foreach (var pattern in compiledPatterns[name])
                    {
                        foreach (var tokens in pattern.PatternTokens)
                        {
                            DebugClass.LogError("TOKENS: " + string.Join("@", tokens.Tokens));
                        }
                    }

                    if (name != "ImplicitCallStmt_InBlockContext")
                    {
                        throw new InvalidOperationException("Valid patterns for case, but none of them worked.");
                    }
                }
            }
            return(canTranslate);
        }
Example #3
0
        public static void Compile(IEnumerable <string> Files)
        {
            foreach (var fname in Files)
            {
                DebugClass.LogStandard("Parsing file: " + fname);

                var compileResult = VB6Compiler.Compile(fname);

                DebugClass.LogStandard(compileResult.CSharpCode);
            }
        }
Example #4
0
        public bool DoTokensMatch(Func <ParseTree, List <ParseTree> > GetChildren, ParseTree tree, bool justCheck = false)
        {
            if (GetChildren == null)
            {
                throw new ArgumentNullException(nameof(GetChildren));
            }

            if (tree == null)
            {
                throw new ArgumentNullException(nameof(tree));
            }

            // TODO: Doesn't handle recursion yet.

            /*
             * var testPattern = ".*" + string.Join(".*", PatternTokens) + ".*";
             * var rex = Regex.IsMatch(tree.getText(), testPattern);
             * DebugClass.Log("TOKENMATCHING: " + tree.getText() + " against " + testPattern + " match? " + rex);
             * return rex;
             */
            bool returnValue = true;

            foreach (var tokenInfo in PatternTokens)
            {
                if (finalCutDepthOfContent > tokenInfo.Path.Count)
                {
                    // In this case the tokens were part of the template, not the pattern so we should skip them.
                    continue;
                }
                var tokenCutPath = tokenInfo.Path.Skip(finalCutDepthOfContent).ToList();
                var node         = LookupNodeFromPath(GetChildren, tree, tokenCutPath, justCheck);
                if (node == null)
                {
                    DebugClass.LogError("UNMATCHED TOKENS 1: " + VbTreeNodeType + ":" + PrintPath(tokenCutPath) + ":" + PrintPath(tokenInfo.Path));
                    returnValue = false;
                    break;
                }
                var tokens       = GetTokens(node);
                var tokenStrings = tokens.Select(x => x.Item2).ToList();
                if (!tokenInfo.Tokens.SequenceEqual(tokenStrings))
                {
                    DebugClass.LogError("UNMATCHED TOKENS 2: " + VbTreeNodeType + ":" + PrintPath(tokenCutPath) + ":" + PrintPath(tokenInfo.Path));
                    DebugClass.LogError("PATH LENGTH COMPARISON: " + finalCutDepthOfContent + ":" + tokenInfo.Path.Count);
                    DebugClass.LogError(string.Join("@", tokenInfo.Tokens));
                    DebugClass.LogError(string.Join("@", tokenStrings));
                    //return false;
                    returnValue = false;
                }
            }
            return(returnValue);
        }
Example #5
0
        public ExpressionSyntax GetFirstGoodChild(string forwardType, ParseTree tree)
        {
            DebugClass.LogError("GetFirstGoodChild: " + forwardType);
            var list = GetGoodChildren(tree);

            if (list.Count > 1)
            {
                throw new InvalidOperationException("More than one good child.");
            }
            else if (list.Count > 0)
            {
                return(list[0]);
            }
            return(null);
        }
Example #6
0
        private static ParseTree LookupNodeFromPath(Func <ParseTree, List <ParseTree> > GetChildren, ParseTree root, List <IndexedPath> path,
                                                    bool justCheck = false)
        {
            var node = root;

            foreach (var indexedPath in path)
            {
                //var child = node.getChild(indexedPath.ChildIndex);

                var children = GetChildren(node);
                if (!(indexedPath.ChildIndex >= 0 && indexedPath.ChildIndex < children.Count))
                {
                    DebugClass.LogError("Did not find child: " + PrintPath(path) + " in " + root.getText());
                    if (justCheck)
                    {
                        return(null);
                    }
                    throw new InvalidOperationException("child outside bounds");
                }

                var child = children[indexedPath.ChildIndex];

                var last = indexedPath == path[path.Count - 1];
                if (!last && LookupNodeType(child) != indexedPath.NodeTypeName)
                {
                    if (justCheck)
                    {
                        return(null);
                    }

                    throw new InvalidOperationException("child type doesn't match");
                }

                node = child;
            }

            if (node == null)
            {
                if (justCheck)
                {
                    return(null);
                }

                throw new InvalidOperationException(nameof(node) + " was null");
            }

            return(node);
        }
Example #7
0
        private static void DebugDumpCSharpSyntax(SyntaxNode tree)
        {
            if (tree == null)
            {
                throw new ArgumentNullException(nameof(tree));
            }

            var callback = new CsharpVisitorCallback()
            {
                Callback = node => { DebugClass.LogError("Node: " + node.Kind() + ": " + node.ToFullString()); }
            };

            var walker = new CustomCSharpSyntaxWalker(callback);

            walker.Visit(tree);
        }
Example #8
0
        // This method looks up the depth of the $CONTENT identifier.
        // We use it to determine where to cut relative paths.

        // TODO: Parse wrapper only once, not one time per pattern. Well, it hardly matters for performance I think, so leave it.
        public void SetCutDepthAndCutPath()
        {
            var wrapperCompileResult = VB6Compiler.Compile("Test.bas", vbWrapperCode, false);
            var translator           = new Translator(wrapperCompileResult);

            DebugClass.LogError("SetCutDepthAndCutPath: " + vbWrapperCode);

            var visitorCallback = new VisitorCallback()
            {
                Callback = (node, parent) =>
                {
                    var identifier = node.getText().Trim('"').Trim();
                    //if (identifier == Content)
                    var path = translator.GetExtendedPathList(node);

                    DebugClass.LogError("SetCutDepthAndCutPath: " + VbCode + ": " + PrintPath(path));

                    if (identifier == Content)
                    {
                        // Exact match
                        if (path[path.Count - 1].NodeTypeName == "VsICSContext")
                        {
                            cutDepthOfContent = path.Count - 1;
                            DebugClass.LogError("SetCutDepth: MATCH");
                        }
                        // Bounded
                        if (!PathContains(path, "VsICSContext"))
                        {
                            cutDepthOfContent = path.Count;
                            DebugClass.LogError("SetCutDepth: BOUND MATCH");
                        }
                        cutPath = path.Take(cutDepthOfContent).ToList();
                    }
                }
            };

            // First time is to set cutDepthOfContent
            VB6Compiler.Visit(wrapperCompileResult, visitorCallback);
            // Second time is to set cutPath
            VB6Compiler.Visit(wrapperCompileResult, visitorCallback);
            if (cutDepthOfContent == -1)
            {
                throw new InvalidOperationException(nameof(cutDepthOfContent) + " not initialized");
            }
        }
        public static ExpressionSyntax TranslateExpression(Translator translator, ParseTree tree)
        {
            var result = Translate(translator, tree);

            DebugClass.LogError("Result: " + result);
            if (result is ExpressionSyntax es)
            {
                return(es);
            }
            else if (result is ExpressionStatementSyntax ess)
            {
                return(ess.Expression);
            }
            else
            {
                throw new InvalidOperationException("This shouldn't happen.");
            }
        }
Example #10
0
        void PopulateGrid()
        {
            DataTable  grdPatternsDataSource = new DataTable("Patterns");
            DataColumn c0 = new DataColumn("Node Type");
            DataColumn c1 = new DataColumn("Context");
            DataColumn c2 = new DataColumn("VB6 Pattern");
            DataColumn c3 = new DataColumn("C# Replacement");
            DataColumn c4 = new DataColumn("Matches#");

            grdPatternsDataSource.Columns.Add(c0);
            grdPatternsDataSource.Columns.Add(c1);
            grdPatternsDataSource.Columns.Add(c2);
            grdPatternsDataSource.Columns.Add(c3);
            grdPatternsDataSource.Columns.Add(c4);

            foreach (var patternText in TranslatorForPattern.TranslatorPatterns)
            {
                DataRow row = grdPatternsDataSource.NewRow();

                string nodeTypeName = "COMPILATION_ERROR";
                int    matchCount   = 0;
                try
                {
                    var pattern = patternText.Compile();
                    nodeTypeName = pattern.VbTreeNodeType;
                    matchCount   = GetMatches(pattern);
                }
                catch (VbParserException e)
                {
                    DebugClass.LogError("Pattern Compile Failed: " + patternText.LogValue() + ": " + e.toString());
                    throw;
                }

                row["Node Type"]      = nodeTypeName;
                row["Context"]        = patternText.VbWrapperCode;
                row["VB6 Pattern"]    = patternText.VbCode;
                row["C# Replacement"] = patternText.VbCode;
                row["Matches#"]       = matchCount;

                grdPatternsDataSource.Rows.Add(row);
            }

            grdPatterns.DataSource = grdPatternsDataSource;
        }
Example #11
0
        static void Main(string[] args)
        {
            Console.Error.WriteLine("Use -g option to start GUI, or --help to show help for command line.");

            Parser.Default.ParseArguments <CommandLineOptions>(args)
            .WithParsed <CommandLineOptions>(o =>
            {
                DebugClass.Init();

                if (o.Verbose || o.GUI)
                {
                    DebugClass.Enabled = true;
                }

                if (o.Compile || o.GUI)
                {
                    TranslatorForPattern.IntializeTranslatorForPattern();
                }

                if (o.Compile)
                {
                    //DebugClass.LogStandard("")
                    DebugClass.LogStandard("Compile");
                    if (o.Files == null)
                    {
                        DebugClass.LogStandard("No files specified!");
                    }
                    else
                    {
                        Compile(o.Files);
                    }
                }

                if (o.GUI)
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    var frm = new frmCompiler();
                    Application.Run(frm);
                    frm.Dispose();
                }
            });
        }
        public static void CompileAll()
        {
            var patterns = TranslatorPatterns;

            compiledPatterns = new Dictionary <string, List <VbToCsharpPattern> >();
            foreach (var patternText in patterns)
            {
                VbToCsharpPattern pattern = null;
                try
                {
                    pattern = patternText.Compile();
                }
                catch (VbParserException e)
                {
                    DebugClass.LogError("Pattern Compile Failed: " + patternText.LogValue() + ": " + e.toString());
                    throw;
                }

                DebugClass.LogError(
                    "Pattern: " + patternText.LogValue() + ", " +
                    nameof(pattern.VbTreeNodeType) + ": " + pattern.VbTreeNodeType);

                if (!compiledPatterns.ContainsKey(pattern.VbTreeNodeType))
                {
                    compiledPatterns[pattern.VbTreeNodeType] = new List <VbToCsharpPattern>();
                }
                compiledPatterns[pattern.VbTreeNodeType].Add(pattern);
            }

            foreach (var pat in compiledPatterns)
            {
                foreach (var pat2 in pat.Value)
                {
                    DebugClass.LogError("PATTERNSTATUS: " + pat2.VbCode + ": " + pat2.VbTreeNodeType + ": " + pat2.GetLogPath());
                    foreach (var tki in pat2.PatternTokens)
                    {
                        DebugClass.LogError("PATTERNTOKENS: " + VbToCsharpPattern.PrintPath(tki.Path));
                        DebugClass.LogError("PATTERNTOKENS: " +
                                            string.Join("@", tki.Tokens));
                    }
                }
            }
        }
        public string TranslatePropertyName(string ctrlType, string propertyName)
        {
            // TODO: Add control specific property mappings.
            // Actually it's probably so few that needs to be per control that
            // I can just put them in this method with a switch.
            if (vbToCSharpPropertyMapping.ContainsKey(propertyName))
            {
                return(vbToCSharpPropertyMapping[propertyName]);
            }

            if (!seenProperties.ContainsKey(propertyName))
            {
                DebugClass.LogError("// Control: " + ctrlType);
                DebugClass.LogError(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{{\"{0}\", \"{0}\"}},", propertyName));
                seenProperties[propertyName] = true;
            }

            //throw new System.NotImplementedException("Did not find property name in translatable properties.");
            return(propertyName);
        }
Example #14
0
        public VbToCsharpPattern(string vbWrapperCode, string vbCode, string csharpString)
        {
            this.vbWrapperCode = vbWrapperCode;
            this.VbCode        = vbCode;
            this.csharpString  = csharpString;

            VbParsePattern(vbCode);
            //CsharpParsedPattern = CSharpParsePattern(csharpString);
            DebugClass.LogError("ASGType: " + VbTreeNodeType);
            foreach (var path in VbPaths)
            {
                DebugClass.LogError("Path: " + PrintPath(path));
            }

            /*
             * foreach (var path in CSharpPaths)
             * {
             *  DebugClass.Log("Path: " + PrintPath(path));
             * }
             */
        }
        public StatementSyntax TranslateProperty(
            string ctrlType,
            string ctrlIdentifier,
            VisualBasic6Parser.Cp_SinglePropertyContext property
            )
        {
            var propertyName =
                vb6NodeTree
                .GetChildren(property)
                .Find(x => x is VisualBasic6Parser.ImplicitCallStmt_InStmtContext)
                .getText()
                .Trim();
            var propertyValueContext =
                vb6NodeTree
                .GetChildren(property)
                .Find(x => x is VisualBasic6Parser.Cp_PropertyValueContext);
            var literalContext =
                vb6NodeTree
                .GetChildren(propertyValueContext)
                .Find(x => x is VisualBasic6Parser.LiteralContext);

            var asg = (LiteralImpl)_compileResult.Program.getASGElementRegistry().getASGElement(literalContext);

            if (asg == null)
            {
                DebugClass.LogError("ASG missing for: " + ctrlIdentifier + " for property: " + propertyName);
                throw new System.NotImplementedException("Don't know how to handle ASG null.");
            }

            var valueNode = TranslatorForExpression.GetExpression(asg);

            var valueString = valueNode.NormalizeWhitespace().ToFullString();

            var translatedPropertyName = TranslatePropertyName(ctrlType, propertyName);

            return(SyntaxFactory.ParseStatement(ctrlIdentifier + "." + translatedPropertyName + " = " + valueString + ";"));
        }
Example #16
0
        public string[] GetIdentifiersAndSetTokens(Translator translator, CompileResult compileResult)
        {
            var identifiers   = new List <string>();
            var tokensPerNode = new List <TokenInfo>();
            //var tokens = new List<Tuple<int, string>>();

            var seen = new Dictionary <string, bool>();

            var visitorCallback = new VisitorCallback()
            {
                Callback = (node, parent) =>
                {
                    //if (node.GetType().Name == "AmbiguousIdentifierContext")
                    var identifier = node.getText().Trim('"').Trim();



                    //DebugClass.Log("GetIdentifier: " + identifier);
                    var path = translator.GetExtendedPathList(node);
                    if (IsInsideSubOrFunction(path))
                    {
                        if (identifier.Length == 1 &&
                            identifier.All(char.IsUpper))
                        {
                            if (!seen.ContainsKey(identifier))
                            {
                                seen[identifier] = true;
                                if (identifier != ReservedLetterForDiscardedResults)
                                {
                                    identifiers.Add(identifier);
                                }
                            }
                        }
                        else
                        {
                            // A general method will for each token add the parent node, and its path,
                            // then extract this path for each token, extract all tokens from path and
                            // check that the token exists in the extracted tokens.
                            // Does this account for the order? Partly, it accounts for the order
                            // within different nodes, but not multiple tokens within the same node.
                            // So to handle that we need to group tokens by node.

                            var tokens = GetTokens(node);
                            if (tokens.Count > 0)
                            {
                                tokenPath = tokenPath ?? path;
                                tokensPerNode.Add(new TokenInfo(path, tokens.Select(x => x.Item2).ToList()));
                                DebugClass.LogError("TOKENS" + string.Join("@", tokens));
                            }
                        }
                    }
                }
            };

            VB6Compiler.Visit(compileResult, visitorCallback);

            _patternTokens = tokensPerNode;

            if (cutDepthOfContent == -1)
            {
                throw new InvalidOperationException(nameof(cutDepthOfContent) + " not initialized");
            }

            return(identifiers.ToArray());
        }
Example #17
0
 public void AppendExtra(string name, string extra)
 {
     DebugClass.LogError(extra);
     AddExtraModule?.Invoke(name, extra);
 }
Example #18
0
        public void VbParsePattern(string pattern)
        {
            SetCutDepthAndCutPath();

            var code          = vbWrapperCode.Replace(Content, pattern);
            var compileResult = VB6Compiler.Compile("Test.bas", code, false);
            var translator    = new Translator(compileResult);

            PatternIdentifiers = GetIdentifiersAndSetTokens(translator, compileResult);

            var       paths = new List <IndexedPath> [PatternIdentifiers.Length];
            ParseTree root  = null;

            DebugClass.LogError("PATTERN: " + VbCode);

            var visitorCallback = new VisitorCallback()
            {
                Callback = (node, parent) =>
                {
                    DebugClass.LogError("Node: " + PrintPath(translator.GetExtendedPathList(node)) + ": " + node.getText());

                    if (root == null)
                    {
                        root = node;
                    }

                    var i = 0;
                    foreach (var identifier in PatternIdentifiers)
                    {
                        if (node.getText().Trim('"') == identifier &&
                            IsInsideSubOrFunction(translator.GetExtendedPathList(node)))
                        {
                            var path = translator.GetExtendedPathList(node);
                            if (paths[i] == null)
                            {
                                paths[i] = path;
                            }
                        }

                        i++;
                    }
                }
            };

            VB6Compiler.Visit(compileResult, visitorCallback);

            var lowestCommonDepth = -1;
            var cutDepth          = -1;

            var comparePath = paths.Length > 0 ? paths[0] : tokenPath;

            if (comparePath == null)
            {
                DebugClass.LogError("VB Code: " + VbCode);
                throw new InvalidOperationException(nameof(comparePath) + " is null");
            }
            int commonDepth = Math.Min(cutPath.Count, comparePath.Count);

            for (int i = 0; i < commonDepth; i++)
            {
                DebugClass.LogError("COMPARE PATHS: " + PrintPath(cutPath));
                foreach (var path in paths)
                {
                    DebugClass.LogError("COMPARE PATHS: " + PrintPath(path));
                }
                DebugClass.LogError("");
                if (cutPath[i].NodeTypeName != comparePath[i].NodeTypeName)
                {
                    break;
                }
                else
                {
                    lowestCommonDepth = Math.Min(comparePath.Count - 1, i + 1);
                }
            }

            if (lowestCommonDepth >= comparePath.Count)
            {
                DebugClass.LogError("VB Code: " + VbCode + ", Identifier: " + PatternIdentifiers[0]);
            }
            VbTreeNodeType = comparePath[lowestCommonDepth].NodeTypeName;

            // Skip uninteresting wrapper nodes
            while (VbTreeNodeType == "VsICSContext" ||
                   VbTreeNodeType == "ImplicitCallStmt_InStmtContext")
            {
                lowestCommonDepth++;
                VbTreeNodeType = comparePath[lowestCommonDepth].NodeTypeName;
            }

            // VbTreeNodeType == "ICS_B_ProcedureCallContext")
            while (VbTreeNodeType == "ArgsCallContext" ||
                   VbTreeNodeType == "AmbiguousIdentifierContext")
            {
                lowestCommonDepth--;
                VbTreeNodeType = comparePath[lowestCommonDepth].NodeTypeName;
            }

            cutDepth = lowestCommonDepth + 1;
            finalCutDepthOfContent = cutDepth;

            var cutPaths = new List <IndexedPath> [PatternIdentifiers.Length];
            var k        = 0;

            foreach (var path in paths)
            {
                var cutPath = new List <IndexedPath>();
                for (var i = cutDepth; i < path.Count; i++)
                {
                    cutPath.Add(path[i]);
                }

                cutPaths[k] = cutPath;
                k++;
            }

            VbPaths = cutPaths;
        }
Example #19
0
        public SyntaxNode Translate(Translator translator, ParseTree tree)
        {
            if (translator == null)
            {
                throw new ArgumentNullException(nameof(translator));
            }

            if (tree == null)
            {
                throw new ArgumentNullException(nameof(tree));
            }

            if (!DoTokensMatch(translator.GetChildren, tree))
            {
                throw new InvalidOperationException("Missing tokens. Fix CanTranslate.");
            }

            var replacement = csharpString;

            // Make a long string so we don't conflict
            foreach (var identifier in PatternIdentifiers)
            {
                replacement = Regex.Replace(replacement, "\\b" + identifier + "\\b", GetUniqueIdentifier(identifier));
            }

            var pathIndex = 0;

            foreach (var identifier in PatternIdentifiers)
            {
                var path = VbPaths[pathIndex];

                var node = LookupNodeFromPath(translator.GetChildren, tree, path);

                DebugClass.LogError(
                    "Extracting Identifier: " + identifier + " with path " +
                    PrintPath(path) + " for code " + tree.getText());
                var translated = translator.TranslateNode(node);

                var uid = GetUniqueIdentifier(identifier);
                if (translated != null)
                {
                    DebugDumpCSharpSyntax(translated);
                    DebugClass.LogError("Extracted: " + translated.NormalizeWhitespace().ToFullString());
                    replacement = replacement.replace(uid, translated.NormalizeWhitespace().ToFullString());
                }
                else
                {
                    DebugClass.LogError("UNTRANSLATED_ " + LookupNodeType(node) +
                                        ", ASG: " + translator.GetAsg <ASGElement>(node)?.GetType()?.Name +
                                        ", Identifier: " + identifier + ", Path: " + PrintPath(path) +
                                        "(" + node.getText().Trim() + ")");
                    replacement = replacement.replace(
                        uid,
                        "throw new NotImplementedException(\"UNTRANSLATED: " +
                        LookupNodeType(node) +
                        ":" + node.getText().Trim() + "\");");
                }

                //translations[i] = translated;
                pathIndex++;
            }

            SyntaxNode rewritten;

            if (Translator.IsStatement(tree))
            {
                rewritten = SyntaxFactory.ParseStatement(replacement);
            }
            else
            {
                rewritten = SyntaxFactory.ParseExpression(replacement);
            }

            return(rewritten.NormalizeWhitespace());
        }
Example #20
0
        public ExpressionSyntax GetExpression(ParseTree tree)
        {
            if (tree == null)
            {
                throw new ArgumentNullException(nameof(tree));
            }

            var asg = this.translator.Program.getASGElementRegistry().getASGElement(tree);

            if (TranslatorForPattern.CanTranslate(translator, tree))
            {
                return(TranslatorForPattern.TranslateExpression(this.translator, tree));
            }

            var goodChildren = GetGoodChildren(tree);

            if (goodChildren.Count == 1)
            {
                DebugClass.LogError("FORWARDED: " + VbToCsharpPattern.LookupNodeType(tree) + ": " + tree.getText());
                return(goodChildren[0]);
            }

            // TODO: optimize if too slow
            var methods = this.GetType().GetMethods();

            foreach (var method in methods)
            {
                if (method.Name.Equals("GetExpression", StringComparison.InvariantCulture))
                {
                    var methodParameters = method.GetParameters();

                    if (methodParameters.Length > 0 && asg != null && methodParameters[0].ParameterType == asg.GetType())
                    {
                        DebugClass.LogError("OBSOLETE: Invoking specific GetExpression on: " + tree.getText());
                        //statements.Add(SyntaxFactory.EmptyStatement().WithLeadingTrivia(SyntaxFactory.Comment("// Invoking GetExpression: " + asg.GetType().Name + ":" + asg.getCtx().depth())));
                        return((ExpressionSyntax)method.Invoke(this, new object[] { asg }));
                    }
                }
            }

            /*else if (tree is VisualBasic6Parser.TypeHintContext)
             * {
             *  return SyntaxFactory.CastExpression(
             *      SyntaxFactory.Token(SyntaxKind.OpenParenToken),
             *      SyntaxFactory.ParseTypeName("string"),
             *      SyntaxFactory.Token(SyntaxKind.CloseParenToken),
             *  );*/

            if (tree is TerminalNodeImpl)
            {
                return(null);
            }
            else if (tree is VisualBasic6Parser.CertainIdentifierContext ||
                     tree is VisualBasic6Parser.AmbiguousIdentifierContext ||
                     tree is VisualBasic6Parser.AmbiguousKeywordContext)
            {
                var name = tree.getText().Trim();
                if (!name.All(c => char.IsLetterOrDigit(c) || "_$".Contains(c)))
                {
                    throw new InvalidOperationException("Identifier was not alphanumeric: " + name);
                }
                return(SyntaxFactory.IdentifierName(name));
            }
            else if (tree is VisualBasic6Parser.ArgsCallContext)
            {
                return(GetFirstGoodChild(nameof(ConstantCallImpl), tree));
            }
            else if (tree is VisualBasic6Parser.BaseTypeContext btc)
            {
                return(HandleBaseTypeContext(btc));
            }
            else if (tree is VisualBasic6Parser.TypeHintContext)
            {
                // Ignore type hint context
                DebugClass.LogError("IGNORING TYPE HINT CONTEXT");
                return(null);
            }

            var explanation = "// " + VbToCsharpPattern.LookupNodeType(tree) + " not in [" + TranslatorForPattern.DocPatterns() + "]" + Translator.NewLine;

            DebugClass.LogError(nameof(GetExpression) + ": " + VbToCsharpPattern.LookupNodeType(tree) + ": " + tree.getText());
            DebugClass.LogError(explanation);
            if (asg != null)
            {
                DebugClass.LogError(nameof(GetExpression) + ": " + asg.GetType().Name);
            }
            // TODO: Reenable.
            throw new InvalidOperationException("Expression returned null");

            //return null;
        }
        public void ProcessProperties(
            string ctrlType,
            ParseTree node,
            List <StatementSyntax> statements,
            string ctrlIdentifier)
        {
            if (node is null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (statements is null)
            {
                throw new ArgumentNullException(nameof(statements));
            }

            if (ctrlIdentifier is null)
            {
                throw new ArgumentNullException(nameof(ctrlIdentifier));
            }

            foreach (var child in vb6NodeTree.GetChildren(node))
            {
                if (child is VisualBasic6Parser.Cp_PropertiesContext)
                {
                    // This is one of the properties
                    var simpleProperty =
                        vb6NodeTree.GetChildren(child).Find(x => x is VisualBasic6Parser.Cp_SinglePropertyContext);

                    var nestedControlProperty =
                        vb6NodeTree.GetChildren(child).Find(x => x is VisualBasic6Parser.ControlPropertiesContext);

                    var nestedProperty =
                        vb6NodeTree.GetChildren(child).Find(x => x is VisualBasic6Parser.Cp_NestedPropertyContext);

                    if (simpleProperty != null)
                    {
                        statements.Add(
                            TranslateProperty(
                                ctrlType,
                                ctrlIdentifier,
                                (VisualBasic6Parser.Cp_SinglePropertyContext)simpleProperty));
                    }
                    else if (nestedControlProperty != null)
                    {
                        statements.AddRange(TranslateControl(
                                                (VisualBasic6Parser.ControlPropertiesContext)nestedControlProperty));
                        var nestedControlName =
                            GetNameOfControl((VisualBasic6Parser.ControlPropertiesContext)nestedControlProperty);
                        var statementString         = ctrlIdentifier + ".Controls.Add(" + nestedControlName + ");";
                        var assignPropertyStatement =
                            SyntaxFactory.ParseStatement(statementString);
                        statements.Add(assignPropertyStatement);
                    }
                    else if (nestedProperty != null)
                    {
                        var nestedName = vb6NodeTree.GetChildren(nestedProperty)
                                         .Find(x =>
                                               x is VisualBasic6Parser.AmbiguousIdentifierContext ||
                                               x is VisualBasic6Parser.CertainIdentifierContext).getText().trim();
                        var translatedNestedName = TranslatePropertyName(ctrlType, nestedName);
                        ProcessProperties(translatedNestedName, nestedProperty, statements, ctrlIdentifier + "." + nestedName);
                    }
                    else
                    {
                        foreach (var grandchild in vb6NodeTree.GetChildren(child))
                        {
                            DebugClass.LogError("GRANDCHILD: " + grandchild.GetType().Name + " " + grandchild.getText());
                        }
                        throw new System.NotImplementedException("Property not handled for: " + ctrlIdentifier);
                    }
                }
            }
        }
        public void GetPatterns(VB6NodeTree nodeTree)
        {
            if (nodeTree == null)
            {
                throw new ArgumentNullException(nameof(nodeTree));
            }

            // Iterate over all nodes and add them to node hash based on their concatenated type strings
            foreach (var node in nodeTree.GetAllNodes())
            {
                var subtree = new VB6SubTree(nodeTree, node);

                //var nodeTreeHashString = GetNodeTreeHashString(subtree);
                var nodeHash = GetNodeHash(node);

                if (!nodeHashDict.ContainsKey(nodeHash))
                {
                    nodeHashDict[nodeHash] = new Dictionary <string, List <VB6SubTree> >();
                }
                var tokens = String.Join(" ", GetTokens(node));
                if (!nodeHashDict[nodeHash].ContainsKey(tokens))
                {
                    nodeHashDict[nodeHash][tokens] = new List <VB6SubTree>();
                }
                nodeHashDict[nodeHash][tokens].Add(subtree);
            }

            foreach (var key in nodeHashDict.Keys)
            {
                foreach (var key2 in nodeHashDict[key].Keys)
                {
                    var s = new List <string>();
                    foreach (var subtree in nodeHashDict[key][key2])
                    {
                        var node   = subtree.GetRoot();
                        var tokens = String.Join(" ", GetTokens(node));
                        s.Add(tokens);
                    }
                    var s2 = String.Join(", ", s);
                    DebugClass.LogError("NodeTreeHashString: " + key + " " + key2 + ": " + nodeHashDict[key][key2].Count + ": " + s2);
                }
            }

            // TODO: Is it possible to auto-generate this dictionary?
            // No stress, it's small, but would be nice for other languages.
            var replaceable = new Dictionary <string, bool>();

            replaceable["AmbiguousIdentifierContext"] = true;
            replaceable["CertainIdentifierContext"]   = true;
            replaceable["LiteralContext"]             = true;
            replaceable["FieldLengthContext"]         = true;

            // Iterate over all nodes and replace each token/text in pattern with pattern letter,
            // if there are two or more variations of this token under this node type name
            const string letters = "ABCDEFGHIJKLMNOPQRSTUVXYZ";

            foreach (var node in nodeTree.GetAllNodes())
            {
                var subtree     = new VB6SubTree(nodeTree, node);
                int letterIndex = 0;
                var text        = node.getText();
                var pattern     = text;

                foreach (var child in subtree.GetAllNodes())
                {
                    if (replaceable.ContainsKey(VbToCsharpPattern.LookupNodeType(child)))
                    {
                        //DebugClass.LogError("REPLACING: " + VbToCsharpPattern.LookupNodeType(child));
                        var tokens = GetTokens(child);
                        foreach (var token in tokens)
                        {
                            if (letterIndex < letters.Length)
                            {
                                var oldPattern = pattern;
                                pattern = pattern.Replace(token, letters[letterIndex].ToString(System.Globalization.CultureInfo.InvariantCulture));
                                if (pattern != oldPattern)
                                {
                                    letterIndex++;
                                }
                                //DebugClass.LogError("REPLACING: " + token);
                            }

                            if (letterIndex >= letters.Length)
                            {
                                break;
                            }
                        }
                        if (letterIndex >= letters.Length)
                        {
                            break;
                        }
                    }
                }
                if (pattern.Length >= 100)
                {
                    pattern = "PATTERN TOO LONG";
                }
                generatedPatterns[node] = pattern;
            }
        }