private static Expression Parse(IEnumerator <Token> tokens, bool isCompoundArgument) { Stack <Expression> stack = new Stack <Expression>(); CommandInvocationExpression lastCommand = null; ConditionalExpression lastCondition = null; SeriesExpression lastSeries = null; Expression temp = null; while (tokens.MoveNext()) { var tok = tokens.Current; /*System.Diagnostics.Debug.WriteLine("BEFORE:"); * System.Diagnostics.Debug.WriteLine("Token: {0} | \"{1}\" | {2} | {3} | {4}", tok.Type, tok.Content, lastCommand, lastSeries, lastCondition); * * System.Diagnostics.Debug.WriteLine("Stack dump:"); * * foreach (var stuff in stack) * System.Diagnostics.Debug.WriteLine("\t<{0}> ({1})", stuff, stuff.GetType());//*/ switch (tok.Type) { case TokenTypes.Toggler: if (tok.Content != "+" && tok.Content != "-") { throw new FormatException("Invalid toggler token!"); } lastCommand = new CommandInvocationExpression(toggle: tok.Content == "+" ? Toggler.On : Toggler.Off); // Conditionals have higher priority than series. if (lastCondition != null) { if (lastCondition.PrimaryAction == null) { lastCondition.PrimaryAction = lastCommand; } else if (lastCondition.SecondaryAction == null) { lastCondition.SecondaryAction = lastCommand; } else { throw new ArgumentException("No series and a full conditional preceeds a toggler."); } } else if (lastSeries != null) { lastSeries.AddExpression(lastCommand); } else if (stack.Count > 0) { throw new FormatException("Toggler follows in a non-empty stack, but there are no preceding series or conditions."); } stack.Push(lastCommand); break; case TokenTypes.CommandName: if (lastCommand == null) { stack.Push(lastCommand = new CommandInvocationExpression(commandName: tok.Content)); } else if (lastCommand.CommandName == null) { // This means there was a toggler before. lastCommand.CommandName = tok.Content; break; // So the code below already executed. } else { throw new FormatException("Last command execution expression already contains a command name."); } if (lastCondition != null) { if (lastCondition.PrimaryAction == null) { lastCondition.PrimaryAction = lastCommand; } else if (lastCondition.SecondaryAction == null) { lastCondition.SecondaryAction = lastCommand; } else { throw new ArgumentException("No series and a full conditional preceeds a command name."); } } else if (lastSeries != null) { lastSeries.AddExpression(lastCommand); } break; case TokenTypes.Argument: //if (lastCommand == null) // lastCommand = stack.Peek() as CommandExecutionExpression; if (lastCommand == null) { throw new FormatException("An argument seems to not be preceded by a command."); } lastCommand.AddArgument(ConstantExpression.Fetch(tok.Content)); break; case TokenTypes.Separator: var didNothing = true; if (lastCommand != null) { lastCommand.Seal(); lastCommand = null; didNothing = false; temp = stack.Pop(); } if (lastCondition != null) { lastCondition.Seal(); lastCondition = null; didNothing = false; temp = stack.Pop(); } if (didNothing) { throw new FormatException("Separator does not follow anything."); } if (lastSeries == null) { if (temp != null) { //temp = stack.Pop(); lastSeries = new SeriesExpression(new Expression[] { temp }); stack.Push(lastSeries); } else { throw new FormatException("A separator does not have any commands to separate."); } } //else // stack.Pop(); // Make it ready to receive more commands. break; case TokenTypes.Include: case TokenTypes.Exclude: if (lastCondition != null) { if (lastCommand != null) { stack.Pop().Seal(); } stack.Pop().Seal(); lastCondition = new ConditionalExpression(tok.Type == TokenTypes.Include, lastCondition); stack.Push(lastCondition); lastCommand = null; } else if (lastCommand != null) { stack.Pop().Seal(); lastCondition = new ConditionalExpression(tok.Type == TokenTypes.Include, lastCommand); stack.Push(lastCondition); lastCommand = null; } else { throw new FormatException("Inclusion does not follow a command."); } if (lastSeries != null) { lastSeries.exprs[lastSeries.exprs.Count - 1] = lastCondition; } break; case TokenTypes.Otherwise: if (lastCondition == null) { throw new FormatException("Otherwise token does not follow a conditional."); } else if (lastCondition.PrimaryAction == null) { throw new FormatException("Otherwise follows a conditional with no primary action."); } else if (lastCondition.SecondaryAction != null) { throw new FormatException("Otherwise follows a conditional which already contains a secondary action."); } if (lastCommand == null) { throw new FormatException("Otherwise token does not follow a command (which would be the primary action)."); } lastCommand = null; stack.Pop().Seal(); // Pop the primary action. break; case TokenTypes.CompoundArgumentStart: if (lastCommand == null) { throw new FormatException("A compound argument seems to not be preceded by a command."); } lastCommand.AddArgument(Parse(tokens, true)); break; case TokenTypes.CompoundArgumentEnd: if (lastCommand == null) { throw new FormatException("A compound argument seems to end with no command."); } if (isCompoundArgument) { return(SealAllAndReturnLast(stack)); } else { throw new FormatException("A compound argument end token doesn't seem to end any argument."); } } /*System.Diagnostics.Debug.WriteLine("AFTER:"); * System.Diagnostics.Debug.WriteLine("Token: {0} | \"{1}\" | {2} | {3} | {4}", tok.Type, tok.Content, lastCommand, lastSeries, lastCondition); * * System.Diagnostics.Debug.WriteLine("Stack dump:"); * * foreach (var stuff in stack) * System.Diagnostics.Debug.WriteLine("\t<{0}> ({1})", stuff, stuff.GetType()); * * System.Diagnostics.Debug.WriteLine("");//*/ } /*System.Diagnostics.Debug.WriteLine("END Stack dump:"); * * foreach (var stuff in stack) * System.Diagnostics.Debug.WriteLine("\t<{0}> ({1})", stuff, stuff.GetType());//*/ return(SealAllAndReturnLast(stack)); }