public AsmTokenizer(string text, AsmKind asmKind, AsmTokenKindProvider tokenKindProvider)
 {
     _text              = text;
     _asmKind           = asmKind;
     _tokenKindProvider = tokenKindProvider;
     _position          = 0;
     _nextPosition      = 0;
     _commentStartChar  = asmKind == AsmKind.Intel ? '#' : ';';
     _c = (char)0;
     NextChar();
 }
        private string ProcessImpl(string input, AsmKind asmKind, bool colourize = true)
        {
            _fileList.Clear();
            _fileName.Clear();
            _tokens.Clear();

            AsmTokenKindProvider asmTokenProvider = default;

            switch (asmKind)
            {
            case AsmKind.Intel:
                asmTokenProvider = (AsmTokenKindProvider)X86AsmTokenKindProvider.Instance;
                break;

            case AsmKind.ARM:
                asmTokenProvider = (AsmTokenKindProvider)ARM64AsmTokenKindProvider.Instance;
                break;

            case AsmKind.Wasm:
                asmTokenProvider = (AsmTokenKindProvider)WasmAsmTokenKindProvider.Instance;
                break;
            }


            var tokenizer = new AsmTokenizer(input, asmKind, asmTokenProvider);

            // Adjust token size
            var pseudoTokenSizeMax = input.Length / 7;

            if (pseudoTokenSizeMax > _tokens.Capacity)
            {
                _tokens.Capacity = pseudoTokenSizeMax;
            }

            // Read all tokens
            while (tokenizer.TryGetNextToken(out var nextToken))
            {
                _tokens.Add(nextToken);
            }

            // Process all tokens
            var output = new StringBuilder();

            for (int i = 0; i < _tokens.Count; i++)
            {
                var token = _tokens[i];
                var slice = token.Slice(input);
                if (token.Kind == AsmTokenKind.Directive && i + 1 < _tokens.Count)
                {
                    if (slice == FileDirective)
                    {
                        // File is followed by an index and a string or just a string with an implied index = 0
                        i++;
                        int index = 0;

                        SkipSpaces(_tokens, ref i);

                        if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
                        {
                            var numberAsStr = _tokens[i].ToString(input);
                            index = int.Parse(numberAsStr);
                            i++;
                        }

                        SkipSpaces(_tokens, ref i);

                        if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.String)
                        {
                            var      filename = _tokens[i].ToString(input).Trim('"');
                            string[] fileLines;

                            try
                            {
                                fileLines = System.IO.File.ReadAllLines(filename);
                            }
                            catch
                            {
                                fileLines = null;
                            }


                            _fileName.Add(index, filename);
                            _fileList.Add(index, fileLines);
                        }
                        continue;
                    }

                    if (slice == LocDirective)
                    {
                        // .loc {fileno} {lineno} [column] [options] -
                        int fileno = 0;
                        int colno  = 0;
                        int lineno = 0;        // NB 0 indicates no information given
                        i++;
                        SkipSpaces(_tokens, ref i);
                        if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
                        {
                            var numberAsStr = _tokens[i].ToString(input);
                            fileno = int.Parse(numberAsStr);
                            i++;
                        }
                        SkipSpaces(_tokens, ref i);
                        if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
                        {
                            var numberAsStr = _tokens[i].ToString(input);
                            lineno = int.Parse(numberAsStr);
                            i++;
                        }
                        SkipSpaces(_tokens, ref i);
                        if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
                        {
                            var numberAsStr = _tokens[i].ToString(input);
                            colno = int.Parse(numberAsStr);
                            i++;
                        }

                        // Skip until end of line
                        for (; i < _tokens.Count; i++)
                        {
                            var tokenToSkip = _tokens[i];
                            if (tokenToSkip.Kind == AsmTokenKind.NewLine)
                            {
                                break;
                            }
                        }

                        // If the file number is 0, skip the line
                        if (fileno == 0)
                        {
                        }
                        // If the line number is 0, then we can update the file tracking, but still not output a line
                        else if (lineno == 0)
                        {
                            if (colourize)
                            {
                                output.Append("<color=").Append(ColorLineDirective).Append(">");
                            }
                            output.Append("=== ").Append(System.IO.Path.GetFileName(_fileName[fileno]));
                            if (colourize)
                            {
                                output.Append("</color>");
                            }
                            output.Append("\n");
                        }
                        // We have a source line and number -- can we load file and extract this line?
                        else
                        {
                            if (_fileList.ContainsKey(fileno) && _fileList[fileno] != null && lineno - 1 < _fileList[fileno].Length)
                            {
                                if (colourize)
                                {
                                    output.Append("<color=").Append(ColorLineDirective).Append(">");
                                }
                                output.Append("=== ").Append(System.IO.Path.GetFileName(_fileName[fileno])).Append("(").Append(lineno).Append(", ").Append(colno + 1).Append(")").Append(_fileList[fileno][lineno - 1]);
                                if (colourize)
                                {
                                    output.Append("</color>");
                                }
                                output.Append("\n");
                            }
                            else
                            {
                                if (colourize)
                                {
                                    output.Append("<color=").Append(ColorLineDirective).Append($">");
                                }
                                output.Append("=== ").Append(System.IO.Path.GetFileName(_fileName[fileno])).Append("(").Append(lineno).Append(", ").Append(colno + 1).Append(")");
                                if (colourize)
                                {
                                    output.Append("</color>");
                                }
                                output.Append("\n");
                            }
                        }
                        continue;
                    }
                }

                if (colourize)
                {
                    switch (token.Kind)
                    {
                    case AsmTokenKind.Directive:
                        output.Append("<color=").Append(ColorDirective).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        break;

                    case AsmTokenKind.Identifier:
                        output.Append("<color=").Append(ColorIdentifier).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        break;

                    case AsmTokenKind.Qualifier:
                        output.Append("<color=").Append(ColorQualifier).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        break;

                    case AsmTokenKind.Instruction:
                        output.Append("<color=").Append(ColorInstruction).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        AlignInstruction(output, slice.Length, asmKind);
                        break;

                    case AsmTokenKind.InstructionSIMD:
                        output.Append("<color=").Append(ColorInstructionSIMD).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        AlignInstruction(output, slice.Length, asmKind);
                        break;

                    case AsmTokenKind.Register:
                        output.Append("<color=").Append(ColorRegister).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        break;

                    case AsmTokenKind.Number:
                        output.Append("<color=").Append(ColorNumber).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        break;

                    case AsmTokenKind.String:
                        output.Append("<color=").Append(ColorString).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        break;

                    case AsmTokenKind.Comment:
                        output.Append("<color=").Append(ColorComment).Append(">");
                        output.Append(input, slice.Position, slice.Length);
                        output.Append("</color>");
                        break;

                    default:
                        output.Append(input, slice.Position, slice.Length);
                        break;
                    }
                }
                else
                {
                    output.Append(input, slice.Position, slice.Length);
                }
            }

            return(output.ToString());
        }