Esempio n. 1
0
 public CodeBlock(CodeLine line, string method, CodeStatementCollection statements, BlockKind kind, CodeBlock parent, string endLabel, string exitLabel)
 {
     this.line = line;
     this.method = method;
     this.statements = statements;
     Type = BlockType.Expect;
     this.kind = kind;
     this.parent = parent;
     level = int.MaxValue;
     this.endLabel = endLabel;
     this.exitLabel = exitLabel;
 }
Esempio n. 2
0
        void PushLabel(CodeLine line, string name, string realname, bool fallthrough)
        {
            var last = CloseTopLabelBlock();

            if (fallthrough && last != null)
                last.Statements.Add(LocalLabelInvoke(name));

            var method = LocalMethod(name);
            var block = new CodeBlock(line, method.Name, method.Statements, CodeBlock.BlockKind.Label, blocks.Count == 0 ? null : blocks.Peek())
            {
                Type = CodeBlock.BlockType.Within,
                Name = realname
            };
            CloseTopSingleBlock();
            blocks.Push(block);

            methods.Add(method.Name, method);
        }
Esempio n. 3
0
        void Statements(List<CodeLine> lines)
        {
            for (int i = 0; i < lines.Count; i++)
            {
                #region Line

                string code = lines[i].Code;

                if (string.IsNullOrEmpty(code))
                    continue;

                line = lines[i].LineNumber;
                fileName = lines[i].FileName;

                #endregion

                #region Blocks

                var parent = blocks.Count > 0 ? blocks.Peek().Statements : main.Statements;
                string codeTrim = code.TrimStart(Spaces);
                int blocksCount = -1;

                if (codeTrim.Length > 0)
                {
                    CodeBlock block;
                    char sym = codeTrim[0];
                    bool skip = false;

                    switch (sym)
                    {
                        case BlockOpen:
                            if (blocks.Count == 0)
                            {
                                block = new CodeBlock(lines[i], Scope, new CodeStatementCollection(), CodeBlock.BlockKind.Dummy, blocks.Count == 0 ? null : blocks.Peek());
                                CloseTopSingleBlock();
                                blocks.Push(block);
                            }
                            block = blocks.Peek();
                            if (block.Type == CodeBlock.BlockType.Expect)
                                block.Type = CodeBlock.BlockType.Within;
                            skip = true;
                            break;

                        case BlockClose:
                            if (blocks.Count == 0)
                                throw new ParseException(ExUnexpected, lines[i]);
                            CloseBlock();
                            skip = true;
                            break;

                        default:
                            if (blocks.Count > 0 && blocks.Peek().Type == CodeBlock.BlockType.Expect)
                            {
                                blocksCount = blocks.Count;
                                block = blocks.Peek();
                                block.Type = CodeBlock.BlockType.Within;
                                block.Level = blocksCount;
                            }
                            break;
                    }

                    if (skip)
                    {
                        code = codeTrim.Substring(1);
                        if (code.Length == 0)
                            continue;
                        lines[i].Code = code;
                    }
                }

                codeTrim = null;

                #endregion

                #region Tokens

                var token = GetToken(code);

                try
                {
                    switch (token)
                    {
                        case Token.Assign:
                            var assign = ParseAssign(code);
                            assign.LinePragma = lines[i];
                            parent.Add(assign);
                            break;

                        case Token.Command:
                            var command = new CodeExpressionStatement(OptimiseExpression(ParseCommand(code)));

                            if (command.Expression == null)
                                continue;

                            command.LinePragma = lines[i];
                            parent.Add(command);
                            break;

                        case Token.Label:
                            var label = new CodeExpressionStatement(ParseLabel(lines[i]));
                            label.LinePragma = lines[i];
                            parent.Add(label);
                            break;

                        case Token.Hotkey:
                            var hotkey = ParseHotkey(lines, i);
                            hotkey.LinePragma = lines[i];
                            parent.Add(hotkey);
                            break;

                        case Token.Flow:
                            {
                                var result = ParseFlow(lines, i);
                                if (result != null)
                                {
                                    for (int n = 0; n < result.Length; n++)
                                        result[n].LinePragma = lines[i];
                                    parent.AddRange(result);
                                }
                            }
                            break;

                        case Token.Expression:
                            {
                                int n = i + 1;
                                if (IsFunction(code, n < lines.Count ? lines[n].Code : string.Empty))
                                    ParseFunction(lines[i]);
                                else
                                {
                                    var statements = ParseMultiExpression(code);

                                    for (n = 0; n < statements.Length; n++)
                                    {
                                        var expr = OptimiseLoneExpression(statements[n].Expression);

                                        if (expr == null)
                                            continue;
                                        else
                                            statements[n] = new CodeExpressionStatement(expr);

                                        statements[n].LinePragma = lines[n];
                                        parent.Add(statements[n]);
                                    }
                                }
                            }
                            break;

                        case Token.Directive:
                            ParseDirective(code);
                            break;

                        case Token.Unknown:
                        default:
                            throw new ParseException(ExUnexpected, lines[i]);
                    }
                }
#if !DEBUG
                catch (ParseException e)
                {
                    throw new ParseException(e.Message, lines[i]);
                }
#endif
                finally { }

                #endregion

                #region Blocks

                if (blocks.Count == blocksCount && blocks.Peek().IsSingle)
                    CloseBlock(blocksCount, blocks.Count > blocksCount && blocksCount != -1);

                #endregion
            }

            #region Blocks

            CloseTopSingleBlocks();
            CloseTopLabelBlock();
            CloseTopSingleBlocks();
            CloseSingleLoopBlocks();

            if (blocks.Count > 0)
                throw new ParseException(ExUnclosedBlock, blocks.Peek().Line);

            #endregion
        }
Esempio n. 4
0
 public CodeBlock(CodeLine line, string method, CodeStatementCollection statements, BlockKind kind, CodeBlock parent)
     : this(line, method, statements, kind, parent, null, null)
 {
 }
Esempio n. 5
0
        private CodeStatement[] ParseFlow(List<CodeLine> lines, int index)
        {
            #region Variables

            var line = lines[index];
            string code = line.Code.TrimStart(Spaces);
            string[] parts = { string.Empty, string.Empty };

            var delimiters = new char[Spaces.Length + 1];
            delimiters[0] = Multicast;
            Spaces.CopyTo(delimiters, 1);
            int[] d = { code.IndexOfAny(delimiters), code.IndexOfAny(new[] { BlockOpen, ParenOpen }) };

            if (d[0] == -1 && d[1] == -1)
                parts[0] = code;
            else if (d[1] != -1 && (d[1] < d[0] || d[0] == -1))
            {
                parts[0] = code.Substring(0, d[1]);
                parts[1] = code.Substring(d[1], code.Length - d[1]).TrimStart(Spaces);
            }
            else
            {
                parts[0] = code.Substring(0, d[0]);
                parts[1] = code.Substring(d[0] + 1, code.Length - d[0] - 1).TrimStart(Spaces);
            }

            if (parts.Length > 1 && IsEmptyStatement(parts[1]))
                parts = new[] { parts[0] };

            #endregion Variables

            switch (parts[0].ToLowerInvariant())
            {
                #region If/Else

                case FlowIf:
                    {
                        if (parts.Length < 1)
                            throw new ParseException("If requires a parameter");

                        bool blockOpen = false;
                        CodeExpression condition = ParseFlowParameter(parts[1], true, out blockOpen, false);
                        var ifelse = new CodeConditionStatement
                        {
                            Condition = condition
                        };

                        var block = new CodeBlock(line, Scope, ifelse.TrueStatements, CodeBlock.BlockKind.IfElse, blocks.Count == 0 ? null : blocks.Peek());
                        block.Type = blockOpen ? CodeBlock.BlockType.Within : CodeBlock.BlockType.Expect;
                        CloseTopSingleBlock();
                        blocks.Push(block);

                        elses.Push(ifelse.FalseStatements);
                        return new CodeStatement[] { ifelse };
                    }

                case FlowElse:
                    {
                        if (elses.Count == 0)
                            throw new ParseException("Else with no preceeding if block");

                        string next = line.Code.TrimStart(Spaces).Substring(FlowElse.Length).TrimStart(Spaces);

                        if (!IsEmptyStatement(next))
                            lines.Insert(index + 1, new CodeLine(lines[index].FileName, lines[index].LineNumber, next));

                        var type = parts.Length > 1 && parts[1][0] == BlockOpen ? CodeBlock.BlockType.Within : CodeBlock.BlockType.Expect;
                        var block = new CodeBlock(lines[index], Scope, elses.Pop(), CodeBlock.BlockKind.IfElse, blocks.Count == 0 ? null : blocks.Peek())
                        {
                            Type = type
                        };
                        CloseTopSingleBlock();
                        blocks.Push(block);
                    }
                    break;

                #endregion If/Else

                #region Goto

                case FlowGosub:
                    {
                        if (parts.Length < 1)
                            throw new ParseException("No label specified");
                        return new CodeStatement[] { new CodeExpressionStatement(LocalLabelInvoke(parts[1])) };
                    }

                case FlowGoto:
                    {
                        if (parts.Length < 1)
                            throw new ParseException("No label specified");
                        return new CodeStatement[] { new CodeExpressionStatement(LocalLabelInvoke(parts[1])), new CodeMethodReturnStatement() };
                    }

                #endregion Goto

                #region Loops

                case FlowLoop:
                    {
                        bool blockOpen = false;
                        CodeMethodInvokeExpression iterator;
                        bool skip = true;
                        bool checkBrace = true;
                        bool byref = false;

                        #region Loop types

                        if (parts.Length > 1)
                        {
                            string[] sub = parts[1].Split(new[] { Multicast }, 2);
                            sub = new[] { sub[0].Trim(), sub.Length > 1 ? sub[1].Trim() : string.Empty };

                            switch (sub[0].ToUpperInvariant())
                            {
                                case "READ":
                                    byref = true;
                                    iterator = (CodeMethodInvokeExpression) InternalMethods.LoopRead;
                                    break;

                                case "PARSE":
                                    checkBrace = false;
                                    byref = true;
                                    iterator = (CodeMethodInvokeExpression) InternalMethods.LoopParse;
                                    break;

                                case "HKEY_LOCAL_MACHINE":
                                case "HKLM":
                                case "HKEY_USERS":
                                case "HKU":
                                case "HKEY_CURRENT_USER":
                                case "HKCU":
                                case "HKEY_CLASSES_ROOT":
                                case "HKCR":
                                case "HKEY_CURRENT_CONFIG":
                                case "HKCC":
                                    iterator = (CodeMethodInvokeExpression) InternalMethods.LoopRegistry;
                                    break;

                                case "EACH":
                                    byref = true;
                                    iterator = (CodeMethodInvokeExpression) InternalMethods.LoopEach;
                                    break;

                                default:
                                    {
                                        var file = false;

                                        if (parts[1].IndexOf(Multicast) != -1)
                                            file = true;

                                        // TODO: check file/iteration loop types

                                        skip = false;
                                        iterator = (CodeMethodInvokeExpression) (file ? InternalMethods.LoopFile : InternalMethods.Loop);
                                    }
                                    break;
                            }

                            if (skip)
                                parts[1] = sub[1];

                            if (checkBrace)
                            {
                                // TODO: check expression parameters before stripping comments
                                int x = parts.Length == 1 ? 0 : 1;
                                string part = StripComment(parts[x]).TrimEnd(Spaces);
                                int l = part.Length - 1;
                                if (part.Length > 0 && part[l] == BlockOpen)
                                {
                                    blockOpen = true;
                                    parts[x] = part.Substring(0, l);
                                }
                            }

                            if (skip && parts[1].Length == 0)
                                throw new ParseException("Loop type must have an argument");

                            foreach (var arg in SplitCommandParameters(parts[1]))
                                iterator.Parameters.Add(ParseCommandParameter(arg));

                            if (LegacyLoop && byref)
                                iterator.Parameters[0] = VarId(iterator.Parameters[0]);
                        }
                        else
                        {
                            iterator = (CodeMethodInvokeExpression) InternalMethods.Loop;
                            iterator.Parameters.Add(new CodePrimitiveExpression(int.MaxValue));
                        }

                        #endregion Loop types

                        string id = InternalID;

                        var init = new CodeVariableDeclarationStatement();
                        init.Name = id;
                        init.Type = new CodeTypeReference(typeof(IEnumerable));
                        init.InitExpression = new CodeMethodInvokeExpression(iterator, "GetEnumerator", new CodeExpression[] { });

                        var condition = new CodeMethodInvokeExpression();
                        condition.Method.TargetObject = new CodeVariableReferenceExpression(id);
                        condition.Method.MethodName = "MoveNext";

                        var loop = new CodeIterationStatement();
                        loop.InitStatement = init;
                        loop.IncrementStatement = new CodeCommentStatement(string.Empty); // for C# display
                        loop.TestExpression = condition;

                        var block = new CodeBlock(line, Scope, loop.Statements, CodeBlock.BlockKind.Loop, blocks.Count == 0 ? null : blocks.Peek(), InternalID, InternalID);
                        block.Type = blockOpen ? CodeBlock.BlockType.Within : CodeBlock.BlockType.Expect;
                        CloseTopSingleBlock();
                        blocks.Push(block);

                        return new CodeStatement[] { loop, new CodeLabeledStatement(block.ExitLabel) };
                    }

                case FlowWhile:
                    {
                        bool blockOpen = false;
                        CodeExpression condition = parts.Length > 1 ? ParseFlowParameter(parts[1], true, out blockOpen, true) : new CodePrimitiveExpression(true);
                        var loop = new CodeIterationStatement();
                        loop.TestExpression = condition;
                        loop.InitStatement = new CodeCommentStatement(string.Empty);

                        var block = new CodeBlock(line, Scope, loop.Statements, CodeBlock.BlockKind.Loop, blocks.Count == 0 ? null : blocks.Peek(), InternalID, InternalID);
                        block.Type = blockOpen ? CodeBlock.BlockType.Within : CodeBlock.BlockType.Expect;
                        CloseTopSingleBlock();
                        blocks.Push(block);

                        return new CodeStatement[] { loop, new CodeLabeledStatement(block.ExitLabel) };
                    }

                case FlowBreak:
                    int b = 1;
                    if (parts.Length > 1)
                    {
                        parts[1] = StripCommentSingle(parts[1]);
                        if (!int.TryParse(parts[1], out b) || b < 1)
                            throw new ParseException("Break parameter must be a static integer greater than zero.");
                    }
                    string exit = PeekLoopLabel(true, b);
                    if (exit == null)
                        throw new ParseException("Cannot break outside a loop");
                    return new CodeStatement[] { new CodeGotoStatement(exit) };

                case FlowContinue:
                    int c = 1;
                    if (parts.Length > 1)
                    {
                        parts[1] = StripCommentSingle(parts[1]);
                        if (!int.TryParse(parts[1], out c) || c < 1)
                            throw new ParseException("Continue parameter must be a static integer greater than zero.");
                    }
                    string cont = PeekLoopLabel(false, c);
                    if (cont == null)
                        throw new ParseException("Cannot continue outside a loop");
                    return new CodeStatement[] { new CodeGotoStatement(cont) };

                #endregion Loops

                #region Return

                case FlowReturn:
                    if (Scope == mainScope)
                    {
                        if (parts.Length > 1)
                            throw new ParseException("Cannot have return parameter for entry point method");
                        return new CodeStatement[] { new CodeMethodReturnStatement() };
                    }
                    else
                    {
                        var result = parts.Length > 1 ? ParseSingleExpression(parts[1]) : new CodePrimitiveExpression(null);
                        return new CodeStatement[] { new CodeMethodReturnStatement(result) };
                    }

                #endregion Return

                #region Function

                case FunctionLocal:
                case FunctionGlobal:
                case FunctionStatic:
                    // TODO: function local/global/static scoping modifiers
                    break;

                #endregion Function

                default:
                    throw new ParseException(ExUnexpected);
            }

            return null;
        }
Esempio n. 6
0
        public void ParseFunction(CodeLine line)
        {
            CloseTopLabelBlock();
            string code = line.Code;
            int i;
            var buf = new StringBuilder();

            #region Name

            string name;

            for (i = 0; i < code.Length; i++)
            {
                char sym = code[i];

                if (IsIdentifier(sym))
                    buf.Append(sym);
                else if (sym == ParenOpen)
                {
                    i++;
                    break;
                }
                else
                    throw new ParseException(ExUnexpected);
            }

            if (buf.Length == 0)
                throw new ParseException(ExUnexpected);

            name = buf.ToString();
            buf.Length = 0;

            if (IsLocalMethodReference(name))
                throw new ParseException("Duplicate function");

            #endregion

            #region Parameters

            CodeBlock.BlockType blockType = CodeBlock.BlockType.Expect;

            bool str = false;
            bool stop = false;

            for (; i < code.Length; i++)
            {
                char sym = code[i];

                switch (sym)
                {
                    case StringBound:
                        str = !str;
                        goto default;

                    case ParenClose:
                        if (str)
                            goto default;
                        else
                            stop = true;
                        break;

                    default:
                        buf.Append(sym);
                        break;
                }

                if (stop)
                    break;
            }

            if (!stop)
                throw new ParseException("Expected closing parenthesis");

            string param = buf.ToString();
            buf.Length = 0;
            i++;

            #region Opening brace

            for (; i < code.Length; i++)
            {
                char sym = code[i];

                if (sym == BlockOpen)
                {
                    blockType = CodeBlock.BlockType.Within;
                    break;
                }
                else if (IsCommentAt(code, i))
                    break;
                else if (!IsSpace(sym))
                    throw new ParseException(ExUnexpected);
            }

            #endregion

            #endregion

            #region Block

            var method = LocalMethod(name);
            method.Attributes = MemberAttributes.Static | MemberAttributes.AccessMask;

            var block = new CodeBlock(line, method.Name, method.Statements, CodeBlock.BlockKind.Function, blocks.Count == 0 ? null : blocks.Peek());
            block.Type = blockType;
            CloseTopSingleBlock();
            blocks.Push(block);

            var fix = ParseFunctionParameters(param);
            if (fix != null)
                method.Statements.Add(fix);

            #endregion

            methods.Add(method.Name, method);

            var type = typeof(Rusty.Core.GenericFunction);
            var typeref = new CodeTypeReference();
            typeref.UserData.Add(RawData, type);
            var del = new CodeDelegateCreateExpression(typeref, new CodeTypeReferenceExpression(className), method.Name);
            var obj = VarAssign(VarRef(mainScope + ScopeVar + method.Name), del);
            prepend.Add(new CodeExpressionStatement(obj));
        }
Esempio n. 7
0
 public CodeBlock(CodeLine line, string method, CodeStatementCollection statements, BlockKind kind, CodeBlock parent, string endLabel, string exitLabel)
 {
     this.line       = line;
     this.method     = method;
     this.statements = statements;
     Type            = BlockType.Expect;
     this.kind       = kind;
     this.parent     = parent;
     level           = int.MaxValue;
     this.endLabel   = endLabel;
     this.exitLabel  = exitLabel;
 }
Esempio n. 8
0
 public CodeBlock(CodeLine line, string method, CodeStatementCollection statements, BlockKind kind, CodeBlock parent)
     : this(line, method, statements, kind, parent, null, null)
 {
 }
Esempio n. 9
0
        public void ParseFunction(CodeLine line)
        {
            CloseTopLabelBlock();
            string code = line.Code;
            int    i;
            var    buf = new StringBuilder();

            #region Name

            string name;

            for (i = 0; i < code.Length; i++)
            {
                char sym = code[i];

                if (IsIdentifier(sym))
                {
                    buf.Append(sym);
                }
                else if (sym == ParenOpen)
                {
                    i++;
                    break;
                }
                else
                {
                    throw new ParseException(ExUnexpected);
                }
            }

            if (buf.Length == 0)
            {
                throw new ParseException(ExUnexpected);
            }

            name       = buf.ToString();
            buf.Length = 0;

            if (IsLocalMethodReference(name))
            {
                throw new ParseException("Duplicate function");
            }

            #endregion

            #region Parameters

            CodeBlock.BlockType blockType = CodeBlock.BlockType.Expect;

            bool str  = false;
            bool stop = false;

            for (; i < code.Length; i++)
            {
                char sym = code[i];

                switch (sym)
                {
                case StringBound:
                    str = !str;
                    goto default;

                case ParenClose:
                    if (str)
                    {
                        goto default;
                    }
                    else
                    {
                        stop = true;
                    }
                    break;

                default:
                    buf.Append(sym);
                    break;
                }

                if (stop)
                {
                    break;
                }
            }

            if (!stop)
            {
                throw new ParseException("Expected closing parenthesis");
            }

            string param = buf.ToString();
            buf.Length = 0;
            i++;

            #region Opening brace

            for (; i < code.Length; i++)
            {
                char sym = code[i];

                if (sym == BlockOpen)
                {
                    blockType = CodeBlock.BlockType.Within;
                    break;
                }
                else if (IsCommentAt(code, i))
                {
                    break;
                }
                else if (!IsSpace(sym))
                {
                    throw new ParseException(ExUnexpected);
                }
            }

            #endregion

            #endregion

            #region Block

            var method = LocalMethod(name);
            method.Attributes = MemberAttributes.Static | MemberAttributes.AccessMask;

            var block = new CodeBlock(line, method.Name, method.Statements, CodeBlock.BlockKind.Function, blocks.Count == 0 ? null : blocks.Peek());
            block.Type = blockType;
            CloseTopSingleBlock();
            blocks.Push(block);

            var fix = ParseFunctionParameters(param);
            if (fix != null)
            {
                method.Statements.Add(fix);
            }

            #endregion

            methods.Add(method.Name, method);

            var type    = typeof(Rusty.Core.GenericFunction);
            var typeref = new CodeTypeReference();
            typeref.UserData.Add(RawData, type);
            var del = new CodeDelegateCreateExpression(typeref, new CodeTypeReferenceExpression(className), method.Name);
            var obj = VarAssign(VarRef(mainScope + ScopeVar + method.Name), del);
            prepend.Add(new CodeExpressionStatement(obj));
        }
Esempio n. 10
0
        private CodeStatement[] ParseFlow(List <CodeLine> lines, int index)
        {
            #region Variables

            var      line  = lines[index];
            string   code  = line.Code.TrimStart(Spaces);
            string[] parts = { string.Empty, string.Empty };

            var delimiters = new char[Spaces.Length + 1];
            delimiters[0] = Multicast;
            Spaces.CopyTo(delimiters, 1);
            int[] d = { code.IndexOfAny(delimiters), code.IndexOfAny(new[] { BlockOpen, ParenOpen }) };

            if (d[0] == -1 && d[1] == -1)
            {
                parts[0] = code;
            }
            else if (d[1] != -1 && (d[1] < d[0] || d[0] == -1))
            {
                parts[0] = code.Substring(0, d[1]);
                parts[1] = code.Substring(d[1], code.Length - d[1]).TrimStart(Spaces);
            }
            else
            {
                parts[0] = code.Substring(0, d[0]);
                parts[1] = code.Substring(d[0] + 1, code.Length - d[0] - 1).TrimStart(Spaces);
            }

            if (parts.Length > 1 && IsEmptyStatement(parts[1]))
            {
                parts = new[] { parts[0] }
            }
            ;

            #endregion Variables

            switch (parts[0].ToLowerInvariant())
            {
                #region If/Else

            case FlowIf:
            {
                if (parts.Length < 1)
                {
                    throw new ParseException("If requires a parameter");
                }

                bool           blockOpen = false;
                CodeExpression condition = ParseFlowParameter(parts[1], true, out blockOpen, false);
                var            ifelse    = new CodeConditionStatement
                {
                    Condition = condition
                };

                var block = new CodeBlock(line, Scope, ifelse.TrueStatements, CodeBlock.BlockKind.IfElse, blocks.Count == 0 ? null : blocks.Peek());
                block.Type = blockOpen ? CodeBlock.BlockType.Within : CodeBlock.BlockType.Expect;
                CloseTopSingleBlock();
                blocks.Push(block);

                elses.Push(ifelse.FalseStatements);
                return(new CodeStatement[] { ifelse });
            }

            case FlowElse:
            {
                if (elses.Count == 0)
                {
                    throw new ParseException("Else with no preceeding if block");
                }

                string next = line.Code.TrimStart(Spaces).Substring(FlowElse.Length).TrimStart(Spaces);

                if (!IsEmptyStatement(next))
                {
                    lines.Insert(index + 1, new CodeLine(lines[index].FileName, lines[index].LineNumber, next));
                }

                var type  = parts.Length > 1 && parts[1][0] == BlockOpen ? CodeBlock.BlockType.Within : CodeBlock.BlockType.Expect;
                var block = new CodeBlock(lines[index], Scope, elses.Pop(), CodeBlock.BlockKind.IfElse, blocks.Count == 0 ? null : blocks.Peek())
                {
                    Type = type
                };
                CloseTopSingleBlock();
                blocks.Push(block);
            }
            break;

                #endregion If/Else

                #region Goto

            case FlowGosub:
            {
                if (parts.Length < 1)
                {
                    throw new ParseException("No label specified");
                }
                return(new CodeStatement[] { new CodeExpressionStatement(LocalLabelInvoke(parts[1])) });
            }

            case FlowGoto:
            {
                if (parts.Length < 1)
                {
                    throw new ParseException("No label specified");
                }
                return(new CodeStatement[] { new CodeExpressionStatement(LocalLabelInvoke(parts[1])), new CodeMethodReturnStatement() });
            }

                #endregion Goto

                #region Loops

            case FlowLoop:
            {
                bool blockOpen = false;
                CodeMethodInvokeExpression iterator;
                bool skip       = true;
                bool checkBrace = true;
                bool byref      = false;

                #region Loop types

                if (parts.Length > 1)
                {
                    string[] sub = parts[1].Split(new[] { Multicast }, 2);
                    sub = new[] { sub[0].Trim(), sub.Length > 1 ? sub[1].Trim() : string.Empty };

                    switch (sub[0].ToUpperInvariant())
                    {
                    case "READ":
                        byref    = true;
                        iterator = (CodeMethodInvokeExpression)InternalMethods.LoopRead;
                        break;

                    case "PARSE":
                        checkBrace = false;
                        byref      = true;
                        iterator   = (CodeMethodInvokeExpression)InternalMethods.LoopParse;
                        break;

                    case "HKEY_LOCAL_MACHINE":
                    case "HKLM":
                    case "HKEY_USERS":
                    case "HKU":
                    case "HKEY_CURRENT_USER":
                    case "HKCU":
                    case "HKEY_CLASSES_ROOT":
                    case "HKCR":
                    case "HKEY_CURRENT_CONFIG":
                    case "HKCC":
                        iterator = (CodeMethodInvokeExpression)InternalMethods.LoopRegistry;
                        break;

                    case "EACH":
                        byref    = true;
                        iterator = (CodeMethodInvokeExpression)InternalMethods.LoopEach;
                        break;

                    default:
                    {
                        var file = false;

                        if (parts[1].IndexOf(Multicast) != -1)
                        {
                            file = true;
                        }

                        // TODO: check file/iteration loop types

                        skip     = false;
                        iterator = (CodeMethodInvokeExpression)(file ? InternalMethods.LoopFile : InternalMethods.Loop);
                    }
                    break;
                    }

                    if (skip)
                    {
                        parts[1] = sub[1];
                    }

                    if (checkBrace)
                    {
                        // TODO: check expression parameters before stripping comments
                        int    x    = parts.Length == 1 ? 0 : 1;
                        string part = StripComment(parts[x]).TrimEnd(Spaces);
                        int    l    = part.Length - 1;
                        if (part.Length > 0 && part[l] == BlockOpen)
                        {
                            blockOpen = true;
                            parts[x]  = part.Substring(0, l);
                        }
                    }

                    if (skip && parts[1].Length == 0)
                    {
                        throw new ParseException("Loop type must have an argument");
                    }

                    foreach (var arg in SplitCommandParameters(parts[1]))
                    {
                        iterator.Parameters.Add(ParseCommandParameter(arg));
                    }

                    if (LegacyLoop && byref)
                    {
                        iterator.Parameters[0] = VarId(iterator.Parameters[0]);
                    }
                }
                else
                {
                    iterator = (CodeMethodInvokeExpression)InternalMethods.Loop;
                    iterator.Parameters.Add(new CodePrimitiveExpression(int.MaxValue));
                }

                #endregion Loop types

                string id = InternalID;

                var init = new CodeVariableDeclarationStatement();
                init.Name           = id;
                init.Type           = new CodeTypeReference(typeof(IEnumerable));
                init.InitExpression = new CodeMethodInvokeExpression(iterator, "GetEnumerator", new CodeExpression[] { });

                var condition = new CodeMethodInvokeExpression();
                condition.Method.TargetObject = new CodeVariableReferenceExpression(id);
                condition.Method.MethodName   = "MoveNext";

                var loop = new CodeIterationStatement();
                loop.InitStatement      = init;
                loop.IncrementStatement = new CodeCommentStatement(string.Empty);                                 // for C# display
                loop.TestExpression     = condition;

                var block = new CodeBlock(line, Scope, loop.Statements, CodeBlock.BlockKind.Loop, blocks.Count == 0 ? null : blocks.Peek(), InternalID, InternalID);
                block.Type = blockOpen ? CodeBlock.BlockType.Within : CodeBlock.BlockType.Expect;
                CloseTopSingleBlock();
                blocks.Push(block);

                return(new CodeStatement[] { loop, new CodeLabeledStatement(block.ExitLabel) });
            }

            case FlowWhile:
            {
                bool           blockOpen = false;
                CodeExpression condition = parts.Length > 1 ? ParseFlowParameter(parts[1], true, out blockOpen, true) : new CodePrimitiveExpression(true);
                var            loop      = new CodeIterationStatement();
                loop.TestExpression = condition;
                loop.InitStatement  = new CodeCommentStatement(string.Empty);

                var block = new CodeBlock(line, Scope, loop.Statements, CodeBlock.BlockKind.Loop, blocks.Count == 0 ? null : blocks.Peek(), InternalID, InternalID);
                block.Type = blockOpen ? CodeBlock.BlockType.Within : CodeBlock.BlockType.Expect;
                CloseTopSingleBlock();
                blocks.Push(block);

                return(new CodeStatement[] { loop, new CodeLabeledStatement(block.ExitLabel) });
            }

            case FlowBreak:
                int b = 1;
                if (parts.Length > 1)
                {
                    parts[1] = StripCommentSingle(parts[1]);
                    if (!int.TryParse(parts[1], out b) || b < 1)
                    {
                        throw new ParseException("Break parameter must be a static integer greater than zero.");
                    }
                }
                string exit = PeekLoopLabel(true, b);
                if (exit == null)
                {
                    throw new ParseException("Cannot break outside a loop");
                }
                return(new CodeStatement[] { new CodeGotoStatement(exit) });

            case FlowContinue:
                int c = 1;
                if (parts.Length > 1)
                {
                    parts[1] = StripCommentSingle(parts[1]);
                    if (!int.TryParse(parts[1], out c) || c < 1)
                    {
                        throw new ParseException("Continue parameter must be a static integer greater than zero.");
                    }
                }
                string cont = PeekLoopLabel(false, c);
                if (cont == null)
                {
                    throw new ParseException("Cannot continue outside a loop");
                }
                return(new CodeStatement[] { new CodeGotoStatement(cont) });

                #endregion Loops

                #region Return

            case FlowReturn:
                if (Scope == mainScope)
                {
                    if (parts.Length > 1)
                    {
                        throw new ParseException("Cannot have return parameter for entry point method");
                    }
                    return(new CodeStatement[] { new CodeMethodReturnStatement() });
                }
                else
                {
                    var result = parts.Length > 1 ? ParseSingleExpression(parts[1]) : new CodePrimitiveExpression(null);
                    return(new CodeStatement[] { new CodeMethodReturnStatement(result) });
                }

                #endregion Return

                #region Function

            case FunctionLocal:
            case FunctionGlobal:
            case FunctionStatic:
                // TODO: function local/global/static scoping modifiers
                break;

                #endregion Function

            default:
                throw new ParseException(ExUnexpected);
            }

            return(null);
        }