public void WriteFullUnit()
        {
            // Arrange
            string expectedTdilFileContent = new StringBuilder()
                                             .AppendLine("// Compiler generated file")
                                             .AppendLine("// Buddy Compiler version 0.1")
                                             .AppendLine("// Generated on {date}")
                                             .AppendLine()
                                             .AppendLine("Unit untitled ($prgName, $prgPath)")
                                             .AppendLine()
                                             .AppendLine("Main:")
                                             .AppendLine("s1")
                                             .AppendLine("s2")
                                             .AppendLine("goto Foo:(3,2)")
                                             .AppendLine("End")
                                             .AppendLine()
                                             .AppendLine("Foo:($p1, $p2)")
                                             .AppendLine("$p1 <-> $p2")
                                             .AppendLine("$p2 <-> $p1")
                                             .AppendLine("End")
                                             .AppendLine()
                                             .AppendLine("End")
                                             .AppendLine()
                                             .ToString();

            // Act
            DateTime       now            = DateTime.Now;
            TdilFileWriter tdilFileWriter = new TdilFileWriter("0.1");

            using (TdilUnitWriter unitWriter = tdilFileWriter.CreateUnit("untitled", new[] { "$prgName", "$prgPath" })) {
                // Main section
                using (TdilSectionWriter sectionWriter = unitWriter.CreateSection("Main")) {
                    sectionWriter.AppendLine("s1");
                    sectionWriter.AppendLine("s2");
                    sectionWriter.AppendLine("goto Foo:(3,2)");
                }

                // Foo section
                using (TdilSectionWriter sectionWriter = unitWriter.CreateSection("Foo", new[] { "$p1", "$p2" })) {
                    sectionWriter.AppendLine("$p1 <-> $p2");
                    sectionWriter.AppendLine("$p2 <-> $p1");
                }
            }

            string tdilFileContent = tdilFileWriter.WriteToString();

            // Assert
            // Insert date before
            expectedTdilFileContent = expectedTdilFileContent.Replace("{date}", now.ToString());

            Assert.AreEqual(expectedTdilFileContent, tdilFileContent, "expecedTdilFileContent != tdilFileContent");
        }
        public void WriteUnitWithAliasAndImports()
        {
            // Arrange
            string expectedTdilFileContent = new StringBuilder()
                                             .AppendLine("// Compiler generated file")
                                             .AppendLine("// Buddy Compiler version 0.1")
                                             .AppendLine("// Generated on {date}")
                                             .AppendLine()
                                             .AppendLine("#include \"Helper.tdil\"")
                                             .AppendLine("#include \"Math.tdil\"")
                                             .AppendLine()
                                             .AppendLine("#alias \"ListBox:Name\"")
                                             .AppendLine("#alias \"ListBox:Pinr\"")
                                             .AppendLine("#alias \"ListBox:Passwort\"")
                                             .AppendLine()
                                             .AppendLine("Unit untitled ($prgName, $prgPath)")
                                             .AppendLine()
                                             .AppendLine("Main:")
                                             .AppendLine("close(_Application, , default)")
                                             .AppendLine("End")
                                             .AppendLine()
                                             .AppendLine("End")
                                             .AppendLine()
                                             .ToString();

            // Act
            DateTime       now            = DateTime.Now;
            TdilFileWriter tdilFileWriter = new TdilFileWriter("0.1");

            // Imports
            tdilFileWriter.AddImport(new[] { "Helper.tdil", "Math.tdil" });

            // Alias
            tdilFileWriter.AddAlias(new[] { "ListBox:Name", "ListBox:Pinr", "ListBox:Passwort" });

            using (TdilUnitWriter unitWriter = tdilFileWriter.CreateUnit("untitled", new[] { "$prgName", "$prgPath" })) {
                // Main section
                using (TdilSectionWriter sectionWriter = unitWriter.CreateSection("Main")) {
                    sectionWriter.AppendLine("close(_Application, , default)");
                }
            }

            string tdilFileContent = tdilFileWriter.WriteToString();

            // Assert
            // Insert date before
            expectedTdilFileContent = expectedTdilFileContent.Replace("{date}", now.ToString());

            Assert.AreEqual(expectedTdilFileContent, tdilFileContent, "expecedTdilFileContent != tdilFileContent");
        }
        /// <summary>
        /// Compiles the given <paramref name="buddyText"/> into a TDIL file as string.
        /// </summary>
        /// <param name="buddyText">Buddy language text to compile</param>
        /// <returns>Compiled buddy text</returns>
        /// <exception cref="ArgumentNullException">If the given <paramref name="buddyText"/> is NULL or empty</exception>
        /// <exception cref="BuddyCompilerException">If something went wrong during the compilation process</exception>
        public virtual string Compile(string buddyText)
        {
            if (string.IsNullOrEmpty(buddyText))
            {
                throw new ArgumentNullException(nameof(buddyText));
            }

            StopwatchLog   compilerStopwatch = StopwatchLog.StartNew(LogCompilerPerformance);
            TdilFileWriter tdilFileWriter    = new TdilFileWriter("0.1.2");

            try {
                // TODO Remove workaround add 'Vorbedingung'
                if (!buddyText.Contains("Vorbedingung: -") && buddyText.Contains("Anwendung: "))
                {
                    int insertPoint = buddyText.IndexOf("Schritte:");
                    buddyText = buddyText.Insert(insertPoint, "Vorbedingung: -\r\n\r\n");
                }

                // TODO Remove workaround add final linefeeds
                if (!buddyText.EndsWith("\r\n"))
                {
                    buddyText += "\r\n";
                }

                // Process text
                StopwatchLog  textProcessorStopwatch = StopwatchLog.StartNew(LogBuddyTextProcessorPerformance);
                BuddyTextInfo buddyTextInfo          = _buddyTextProcessor.ProcessText(buddyText);
                textProcessorStopwatch.Dispose(buddyTextInfo);

                // In the case of an short form, create standard names
                if (buddyTextInfo.IsShortForm)
                {
                    buddyTextInfo.ApplicationText = "untitled";
                    buddyTextInfo.UseCaseText     = "untitled";
                    buddyTextInfo.ScenarioText    = "untitled";
                }

                // TODO Check if this is a workaround and remove it
                if (string.IsNullOrEmpty(buddyTextInfo.VersionText))
                {
                    buddyTextInfo.VersionText = "*";
                }

                // Little verification
                ushort expectedNoOfSteps = CalculateNoOfSteps(buddyText);
                if (expectedNoOfSteps != buddyTextInfo.Steps.Length)
                {
                    ThrowUncompilableDirectiveException(buddyText, expectedNoOfSteps, buddyTextInfo.Steps.Length);
                }

                string[] buddyTextSteps = buddyTextInfo.Steps;

                // Normalize directives
                string[] normalizedBuddyTextSteps;
                using (StopwatchLog.StartNew(LogNormalizingPerformance)) {
                    normalizedBuddyTextSteps = NormalizeSteps(buddyTextSteps, buddyTextInfo.Parameters);
                }

                // Create unit name
                UnitName unitName          = new UnitName(buddyTextInfo.ApplicationText, buddyTextInfo.VersionText, buddyTextInfo.UseCaseText, buddyTextInfo.ScenarioText);
                string   qualifiedUnitName = unitName.ToQualifiedString();

                using (CompilingContext compilingContext = new CompilingContext()) {
                    // Compile directives
                    string[] directiveSet = new string[1000];
                    int      pr           = 0;
                    using (StopwatchLog.StartNew(LogInstructionTranslationPerformance)) {
                        for (int i = -1; ++i != normalizedBuddyTextSteps.Length;)
                        {
                            string actionLine = normalizedBuddyTextSteps[i];
                            string directive  = _instructionTranslator.ToDirective(actionLine);
                            directiveSet[pr++] = directive;
                        }
                        Array.Resize(ref directiveSet, pr);
                    }

                    // Add alias references
                    string[] aliasReferenceSet = compilingContext.AliasReferenceSet;
                    tdilFileWriter.AddAlias(aliasReferenceSet);

                    // Add unit references
                    string[] unitReferenceSet   = compilingContext.UnitReferenceSet;
                    string[] qualifiedUnitNames = ToQualifiedUnitNames(unitReferenceSet);
                    tdilFileWriter.AddImport(qualifiedUnitNames);

                    // Write unit
                    using (StopwatchLog.StartNew(LogTdilUnitWritingPerformance)) {
                        using (TdilUnitWriter tdilUnitWriter = tdilFileWriter.CreateUnit(qualifiedUnitName)) {
                            string executeSectionName           = unitName.GetEncodedScenarioName();
                            BuddyTextParameter[] unitParameters = buddyTextInfo.Parameters;
                            string[]             parameterNames = new string[unitParameters.Length];
                            for (int l = -1; ++l != parameterNames.Length;)
                            {
                                parameterNames[l] = unitParameters[l].Name;
                            }

                            // Write main section
                            using (TdilSectionWriter tdilSectionWriter = tdilUnitWriter.CreateSection("Main")) {
                                // Declare parameters
                                for (int i = -1; ++i != unitParameters.Length;)
                                {
                                    BuddyTextParameter unitParameter = unitParameters[i];
                                    tdilSectionWriter.AppendLine("{0} = {1}", unitParameter.Name, unitParameter.DefaultValue);
                                }

                                // Add start statement
                                tdilSectionWriter.AppendLine("start(,, \"{{{0}}}\")", buddyTextInfo.ApplicationText);

                                // Add argument invocation line if there are some
                                string argInvLine = null;
                                if (parameterNames.Length != 0)
                                {
                                    string argSetLine = string.Join(", ", parameterNames);
                                    argInvLine = $"({argSetLine})";
                                }

                                tdilSectionWriter.AppendLine("gosub {0}:{1}", executeSectionName, argInvLine);

                                // Add close statement
                                tdilSectionWriter.AppendLine("close(_Application,, Default)");
                                tdilSectionWriter.AppendLine("kill(_Application,, 3000)");

                                tdilSectionWriter.AppendLine("close(\"AcroRd32\",, Default)");
                                tdilSectionWriter.AppendLine("kill(\"AcroRd32\",, 3000)");
                            }

                            // Write execute section
                            using (TdilSectionWriter tdilSectionWriter = tdilUnitWriter.CreateSection(executeSectionName, parameterNames)) {
                                for (int l = -1; ++l != directiveSet.Length;)
                                {
                                    tdilSectionWriter.AppendLine(directiveSet[l]);
                                }
                            }
                        }
                    }
                }
            } catch (BuddyCompilerException) {
                throw;
            } catch (Exception ex) {
                throw new BuddyCompilerException("Error on compiling buddy language unit.", ex);
            }

            string tdilFileContent = tdilFileWriter.WriteToString();

            compilerStopwatch.Dispose();

            return(tdilFileContent);
        }