private PsudoInstruction CompileCase(PsudoMethod method, string variable, int start, out int endLine)
        {
            int nextStart = codeLines.ToList().FindIndex(start + 1,
                                                         item => item.Contains(":") ||
                                                         Regex.IsMatch(item, @"^[\s]*\b(endcase)\b[\s]*", RegexOptions.IgnoreCase)
                                                         );

            if (nextStart < 0)
            {
                throw new Exception("CASE found with no ENDCASE");
            }

            string[] parts      = codeLines[start].Split(':');
            string   lineBackup = codeLines[start];

            // Do this to help the compiler
            codeLines[start] = parts[1].Trim();

            if (parts[0].Trim().ToLower().Contains("other"))
            {
                BlockInstruction ins = new BlockInstruction(start, method);

                ins.Instructions = CompileBlock(method, start, nextStart - 1);
                endLine          = nextStart;

                codeLines[start] = lineBackup;
                return(ins);
            }
            else
            {
                string decision         = variable + "==" + parts[0].Trim();
                DecisionInstruction ins = new DecisionInstruction(start, method, decision);

                ins.Instructions = CompileBlock(method, start, nextStart - 1);

                if (codeLines[nextStart].ToLower().Contains("endcase"))
                {
                    endLine = nextStart;
                    ins.FalseInstruction = new NoOpInstruction(endLine, method);
                }
                else
                {
                    ins.FalseInstruction = CompileCase(method, variable, nextStart, out endLine);
                }
                ins.EndInstruction = new NoOpInstruction(endLine, method);

                codeLines[start] = lineBackup;
                return(ins);
            }
        }
        internal static BlockInstruction Create(BinaryParsingReader reader)
        {
            BuiltinLanguageType blockType = (BuiltinLanguageType)reader.ReadVarInt7();
            BlockInstruction    result    = _perTypeBlock[(int)blockType + 128];

            if (null != result)
            {
                _reuseCount++;
            }
            else
            {
                result = new BlockInstruction()
                {
                    BlockType = blockType
                };
                _perTypeBlock[(int)blockType + 128] = result;
            }
            return(result);
        }
        internal Instruction ReadInstruction()
        {
            OpCodes     opcode = (OpCodes)this.ReadByte();
            Instruction result = Instruction.FixedOpCodes[(int)opcode];

            if (null != result)
            {
                return(result);
            }
            switch (opcode)
            {
            case OpCodes.Block:
                return(BlockInstruction.Create(this));

            case OpCodes.Loop:
                return(LoopInstruction.Create(this));

            case OpCodes.If:
                // block_type
                return(IfInstruction.Create(this));

            case OpCodes.Br:
            case OpCodes.BrIf:
                // varuint32
                return(BranchInstruction.Create(this, opcode));

            case OpCodes.BrTable:
                // custom
                return(BranchTableInstruction.Create(this));

            case OpCodes.Call:
            case OpCodes.CallIndirect:
                // varuint32 + varuint1
                return(CallInstruction.Create(this, opcode));

            case OpCodes.GetLocal:
            case OpCodes.SetLocal:
            case OpCodes.TeeLocal:
                // local_index
                return(LocalAccessorInstruction.Create(this, opcode));

            case OpCodes.GetGlobal:
            case OpCodes.SetGlobal:
                // global_index
                return(GlobalAccessorInstruction.Create(this, (OpCodes.GetGlobal == opcode)));

            case OpCodes.I32Load:
            case OpCodes.I64Load:
            case OpCodes.F32Load:
            case OpCodes.F64Load:
            case OpCodes.I32Load8_s:
            case OpCodes.I32Load8_u:
            case OpCodes.I32Load16_s:
            case OpCodes.I32Load16_u:
            case OpCodes.I64Load8_s:
            case OpCodes.I64Load8_u:
            case OpCodes.I64Load16_s:
            case OpCodes.I64Load16_u:
            case OpCodes.I64Load32_s:
            case OpCodes.I64Load32_u:
            case OpCodes.I32Store:
            case OpCodes.I64Store:
            case OpCodes.F32Store:
            case OpCodes.F64Store:
            case OpCodes.I32Store8:
            case OpCodes.I32Store16:
            case OpCodes.I64Store8:
            case OpCodes.I64Store16:
            case OpCodes.I64Store32:
                // memory_immediate
                return(MemoryAccessInstruction.Create(this, opcode));

            case OpCodes.CurrentMemory:
            case OpCodes.GrowMemory:
                // varuint1
                return(MemoryControlInstruction.Create(this, opcode));

            case OpCodes.I32Const:
                // varint32
                return(ConstantValueInstruction <int> .Create(this, OpCodes.I32Const, this.ReadVarInt32()));

            case OpCodes.I64Const:
                // varint64
                return(ConstantValueInstruction <long> .Create(this, OpCodes.I64Const, this.ReadVarInt64()));

            case OpCodes.F32Const:
                // uint32
                return(ConstantValueInstruction <float> .Create(this, OpCodes.F32Const, this.ReadVarFloat32()));

            case OpCodes.F64Const:
                // uint64
                return(ConstantValueInstruction <double> .Create(this, OpCodes.F64Const, this.ReadVarFloat64()));

            case OpCodes.F32eq:
            case OpCodes.F32ge:
            case OpCodes.F32gt:
            case OpCodes.F32le:
            case OpCodes.F32lt:
            case OpCodes.F32ne:
            case OpCodes.F64eq:
            case OpCodes.F64ge:
            case OpCodes.F64gt:
            case OpCodes.F64le:
            case OpCodes.F64lt:
            case OpCodes.F64ne:
            case OpCodes.I32eq:
            case OpCodes.I32ge_s:
            case OpCodes.I32ge_u:
            case OpCodes.I32gt_s:
            case OpCodes.I32gt_u:
            case OpCodes.I32le_s:
            case OpCodes.I32le_u:
            case OpCodes.I32lt_s:
            case OpCodes.I32lt_u:
            case OpCodes.I32ne:
            case OpCodes.I64eq:
            case OpCodes.I64ge_s:
            case OpCodes.I64ge_u:
            case OpCodes.I64gt_s:
            case OpCodes.I64gt_u:
            case OpCodes.I64le_s:
            case OpCodes.I64le_u:
            case OpCodes.I64lt_s:
            case OpCodes.I64lt_u:
            case OpCodes.I64ne:
                return(RelationalInstruction.GetInstruction(opcode));

            case OpCodes.F32Convert_sI32:
            case OpCodes.F32Convert_uI32:
            case OpCodes.F32Convert_sI64:
            case OpCodes.F32Convert_uI64:
            case OpCodes.F32demoteF64:
            case OpCodes.F64Convert_sI32:
            case OpCodes.F64Convert_uI32:
            case OpCodes.F64Convert_sI64:
            case OpCodes.F64Convert_uI64:
            case OpCodes.F64PromoteF32:
            case OpCodes.I32Trunc_sF32:
            case OpCodes.I32Trunc_uF32:
            case OpCodes.I32Trunc_sF64:
            case OpCodes.I32Trunc_uF64:
            case OpCodes.I32wrapI64:
            case OpCodes.I64Extend_sI32:
            case OpCodes.I64Extend_uI32:
            case OpCodes.I64Trunc_sF32:
            case OpCodes.I64Trunc_uF32:
            case OpCodes.I64Trunc_sF64:
            case OpCodes.I64Trunc_uF64:
                return(ConversionInstruction.GetInstruction(opcode));

            default:
                throw new NotSupportedException();
            }
        }
        protected PsudoInstruction CompileDecision(PsudoMethod method, int line, out int endLine)
        {
            if (Regex.IsMatch(codeLines[line], @"^[\s]*\b(if|elseif)\b[\s]*", RegexOptions.IgnoreCase))
            {
                string decision = codeLines[line].Trim();
                if (decision.ToLower().Contains("elseif"))
                {
                    decision = decision.Substring(6);
                }
                else
                {
                    decision = decision.Substring(2);
                }

                while (!decision.ToLower().Contains("then"))
                {
                    if (line + 1 == codeLines.Length ||
                        Regex.IsMatch(codeLines[line + 1], @"^[\s]*\b(else|elseif|endif)\b[\s]*", RegexOptions.IgnoreCase)
                        )
                    {
                        throw new Exception("IF found without THEN");
                    }
                    decision += " " + codeLines[line + 1];
                    line     += 1;
                }

                decision = decision.Trim();
                decision = decision.Substring(0, decision.Length - 4).Trim();

                DecisionInstruction ins = new DecisionInstruction(line, method, decision);
                int next   = -1;
                int end    = -1;
                int nested = 0;
                for (int num = line + 1; num < codeLines.Length; num++)
                {
                    string item = codeLines[num];
                    if (Regex.IsMatch(item, @"^[\s]*\b(if)\b[\s]*", RegexOptions.IgnoreCase))
                    {
                        nested++;
                    }
                    if (Regex.IsMatch(item, @"^[\s]*\b(endif)\b[\s]*", RegexOptions.IgnoreCase))
                    {
                        if (nested == 0)
                        {
                            if (next < 0)
                            {
                                next = num;
                            }
                            end = num;
                        }
                        else
                        {
                            nested--;
                        }
                    }
                    if (nested == 0 && next < 0)
                    {
                        if (Regex.IsMatch(item, @"^[\s]*\b(elseif|else)\b[\s]*", RegexOptions.IgnoreCase))
                        {
                            next = num;
                        }
                    }
                }

                if (end < 0)
                {
                    throw new Exception("IF found with no ENDIF");
                }

                ins.Instructions = CompileBlock(method, line + 1, next - 1);
                int temp;
                ins.FalseInstruction = CompileDecision(method, next, out temp);
                ins.EndInstruction   = CompileDecision(method, end, out temp);

                endLine = end;
                return(ins);
            }
            else if (Regex.IsMatch(codeLines[line], @"^[\s]*\b(else)\b[\s]*", RegexOptions.IgnoreCase))
            {
                BlockInstruction ins = new BlockInstruction(line, method);
                int next             = codeLines.ToList().FindIndex(line, item => Regex.IsMatch(item, @"^[\s]*\b(endif)\b[\s]*", RegexOptions.IgnoreCase));

                ins.Instructions = CompileBlock(method, line + 1, next - 1);
                endLine          = next;
                return(ins);
            }
            else if (Regex.IsMatch(codeLines[line], @"^[\s]*\b(endif)\b[\s]*", RegexOptions.IgnoreCase))
            {
                endLine = line;
                return(new NoOpInstruction(line, method));
            }
            else if (Regex.IsMatch(codeLines[line], @"^[\s]*\b(case of|case)\b[\s]*", RegexOptions.IgnoreCase))
            {
                // Trim of case/case of
                string variable = Regex.Replace(codeLines[line], @"\b(case of|case)\b", "").Trim();

                int start = codeLines.ToList().FindIndex(line + 1, item => item.Contains(":"));
                if (start < 0)
                {
                    throw new Exception("CASE Statement contains no options or options are formmed incorrectly");
                }
                return(CompileCase(method, variable, start, out endLine));
            }

            endLine = line;
            return(null);
        }