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; }
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); }
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 }
public CodeBlock(CodeLine line, string method, CodeStatementCollection statements, BlockKind kind, CodeBlock parent) : this(line, method, statements, kind, parent, null, null) { }
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; }
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)); }
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)); }
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); }