public void Build(TokenList tokens) { // store the "list each [variable] in [list_expression]" tokens token = tokens.Current; Token eachToken = tokens.Peek(1); iteratorToken = tokens.Peek(2); Token inToken = tokens.Peek(3); listToken = tokens.Peek(4); // the first token of the list expression tokens.Advance(4); // make sure the "each" token is actually the word "each" if (eachToken.Value != "each" || eachToken.TokenType != TokenType.Word) throw new TokenParserException("\"list\" must be followed by the word \"each\".", eachToken); // validate the various tokens if (iteratorToken.TokenType != TokenType.Word) throw new TokenParserException("You must specify a word here that can be used as a variable, e.g. \"list each item in whatever\"", iteratorToken); if (TokenParser.IsReservedWord(iteratorToken.Value)) throw new TokenParserException("You can't use \"" + iteratorToken.Value + "\" as a variable name. It is the keyword for either an expression or an instruction.", iteratorToken); if (inToken.Value != "in" || inToken.TokenType != TokenType.Word) throw new TokenParserException("\"list each [something] must be followed by the word \"in\".", inToken); // build the list expression and the subsequent instruction list to loop through expr = TokenParser.BuildExpression(tokens); instructions = new InstructionList(); instructions.IsLoopBlock = true; instructions.Build(tokens); }
public static List<ExpressionArgument> BuildArgumentList(TokenList tokens) { List<ExpressionArgument> args = new List<ExpressionArgument>(); if (tokens.Current.TokenType != TokenType.GroupStart) return args; tokens.Advance(); // past the opening bracket while (tokens.Current.TokenType != TokenType.GroupEnd) { Token token = tokens.Current; IExpression expr = BuildExpression(tokens); if (tokens.Next == null) throw new TokenParserException("Oops, looks like someone didn't finish writing the script. It ended while I was putting together a list of arguments for a function call.", tokens.Peek(-2)); args.Add(new ExpressionArgument(expr, token)); token = tokens.Current; if (token.TokenType == TokenType.GroupEnd) continue; if (token.TokenType == TokenType.OtherSymbolic && token.Value == ",") { tokens.Advance(); if (tokens.Current.TokenType == TokenType.GroupEnd) throw new TokenParserException("There is a comma here to indicate that I should expect an argument following it, but instead there is a closing bracket.", tokens.Current); } else throw new TokenParserException("The list of function arguments needs to either end with a closing bracket, or have a comma to indicate that another argument is next.", token); } tokens.Advance(); return args; }
public static IInstruction BuildInstruction(TokenList tokens) { Token token = tokens.Current; // special case: if free text is found, create a "show" instruction to process it if (token.TokenType == TokenType.FreeText) return new ShowInstruction(BuildExpression(tokens)); // find the relevant creator/processor for the instruction if (token.TokenType == TokenType.Word || token.TokenType == TokenType.OtherSymbolic) { if (instructionCreators.ContainsKey(token.Value)) { IInstruction instruction = instructionCreators[token.Value].Create(); instruction.Build(tokens); return instruction; } } if (token.TokenType == TokenType.GroupStart || token.TokenType == TokenType.GroupEnd) throw new TokenParserException("Not sure why there is a bracket here.", token); if (token.Value == "end" && token.TokenType == TokenType.Word && tokens.Next == null) throw new TokenParserException("The end of the script has been reached prematurely.", tokens.Peek(-1)); if (expressionCreators.ContainsKey(token.Value)) throw new TokenParserException("\"" + token.Value + "\" can't stand by itself, as it is only designed to equate to a value. If you want to display the value, precede the keyword with a \"show\" instruction.", token); throw new TokenParserException("I have no idea what \"" + token.Value + "\" means.", token); }
public void Build(TokenList tokens) { // store the "list each [variable] in [list_expression]" tokens token = tokens.Current; Token eachToken = tokens.Peek(1); iteratorToken = tokens.Peek(2); Token inToken = tokens.Peek(3); listToken = tokens.Peek(4); // the first token of the list expression tokens.Advance(4); // make sure the "each" token is actually the word "each" if (eachToken.Value != "each" || eachToken.TokenType != TokenType.Word) { throw new TokenParserException("\"list\" must be followed by the word \"each\".", eachToken); } // validate the various tokens if (iteratorToken.TokenType != TokenType.Word) { throw new TokenParserException("You must specify a word here that can be used as a variable, e.g. \"list each item in whatever\"", iteratorToken); } if (TokenParser.IsReservedWord(iteratorToken.Value)) { throw new TokenParserException("You can't use \"" + iteratorToken.Value + "\" as a variable name. It is the keyword for either an expression or an instruction.", iteratorToken); } if (inToken.Value != "in" || inToken.TokenType != TokenType.Word) { throw new TokenParserException("\"list each [something] must be followed by the word \"in\".", inToken); } // build the list expression and the subsequent instruction list to loop through expr = TokenParser.BuildExpression(tokens); instructions = new InstructionList(); instructions.IsLoopBlock = true; instructions.Build(tokens); }
public static IExpression BuildExpression(TokenList tokens, Stack<int?> precedenceStack) { if (tokens.Current == null) throw new TokenParserException("The script seems to have ended prematurely. Shouldn't there be something here?", tokens.Peek(-2)); Token token = tokens.Current; IExpression expr = null; bool endGroupedExpression = false; switch (token.TokenType) { case TokenType.Number: expr = new NumericExpression(tokens, precedenceStack); break; case TokenType.QuotedString: expr = new StringExpression(tokens, precedenceStack); break; case TokenType.FreeText: expr = new StringExpression(tokens, precedenceStack); return expr; case TokenType.Word: if (expressionCreators.ContainsKey(token.Value)) { // find the appropriate handler for this keyword expr = expressionCreators[token.Value].Create(); } else // we don't recognise the word, so we can assume it's a variable and validate it at run-time { // don't allow instruction keywords to be used as variable names if (instructionCreators.ContainsKey(token.Value)) throw new TokenParserException("This word is the name of an instruction. You can't use it here in this context.", token); else expr = new VariableExpression(); } // if applicable, have the expression prepare itself according to its own rules if (expr is IFlexibleSyntaxExpression) ((IFlexibleSyntaxExpression)expr).PrepareExpression(tokens, precedenceStack); else // otherwise just advance to the next token tokens.Advance(); // chain together any properties and argument lists expr = BuildDeepExpression(expr, tokens); break; case TokenType.PropertyDesignator: // property designators are handled elsewhere. if we found one here, it's a parsing error. if (tokens.Previous.TokenType == TokenType.Word) throw new TokenParserException("This type of expression doesn't allow you to specify a property.", tokens.Next); throw new TokenParserException("You've got a property designator in a spot where it doesn't belong.", tokens.Next); case TokenType.GroupStart: expr = BuildGroupedExpression(tokens); break; case TokenType.GroupEnd: endGroupedExpression = true; break; default: throw new TokenParserException("This part of the script should equate to a value but instead I got \"" + token.Value + "\", which doesn't really mean anything in this context.", token); } if (!endGroupedExpression) { int? precedence = precedenceStack.Peek(); while (NextHasGreaterPrecedence(precedence, tokens)) expr = BuildBinaryExpression(tokens, expr, precedenceStack); } return expr; }
public static IInstruction BuildInstruction(TokenList tokens) { Token token = tokens.Current; // special case: if free text is found, create a "show" instruction to process it if (token.TokenType == TokenType.FreeText) { return(new ShowInstruction(BuildExpression(tokens))); } // find the relevant creator/processor for the instruction if (token.TokenType == TokenType.Word || token.TokenType == TokenType.OtherSymbolic) { if (instructionCreators.ContainsKey(token.Value)) { IInstruction instruction = instructionCreators[token.Value].Create(); instruction.Build(tokens); return(instruction); } } if (token.TokenType == TokenType.GroupStart || token.TokenType == TokenType.GroupEnd) { throw new TokenParserException("Not sure why there is a bracket here.", token); } if (token.Value == "end" && token.TokenType == TokenType.Word && tokens.Next == null) { throw new TokenParserException("The end of the script has been reached prematurely.", tokens.Peek(-1)); } if (expressionCreators.ContainsKey(token.Value)) { throw new TokenParserException("\"" + token.Value + "\" can't stand by itself, as it is only designed to equate to a value. If you want to display the value, precede the keyword with a \"show\" instruction.", token); } throw new TokenParserException("I have no idea what \"" + token.Value + "\" means.", token); }
public static List <ExpressionArgument> BuildArgumentList(TokenList tokens) { List <ExpressionArgument> args = new List <ExpressionArgument>(); if (tokens.Current.TokenType != TokenType.GroupStart) { return(args); } tokens.Advance(); // past the opening bracket while (tokens.Current.TokenType != TokenType.GroupEnd) { Token token = tokens.Current; IExpression expr = BuildExpression(tokens); if (tokens.Next == null) { throw new TokenParserException("Oops, looks like someone didn't finish writing the script. It ended while I was putting together a list of arguments for a function call.", tokens.Peek(-2)); } args.Add(new ExpressionArgument(expr, token)); token = tokens.Current; if (token.TokenType == TokenType.GroupEnd) { continue; } if (token.TokenType == TokenType.OtherSymbolic && token.Value == ",") { tokens.Advance(); if (tokens.Current.TokenType == TokenType.GroupEnd) { throw new TokenParserException("There is a comma here to indicate that I should expect an argument following it, but instead there is a closing bracket.", tokens.Current); } } else { throw new TokenParserException("The list of function arguments needs to either end with a closing bracket, or have a comma to indicate that another argument is next.", token); } } tokens.Advance(); return(args); }
public static IExpression BuildExpression(TokenList tokens, Stack <int?> precedenceStack) { if (tokens.Current == null) { throw new TokenParserException("The script seems to have ended prematurely. Shouldn't there be something here?", tokens.Peek(-2)); } Token token = tokens.Current; IExpression expr = null; bool endGroupedExpression = false; switch (token.TokenType) { case TokenType.Number: expr = new NumericExpression(tokens, precedenceStack); break; case TokenType.QuotedString: expr = new StringExpression(tokens, precedenceStack); break; case TokenType.FreeText: expr = new StringExpression(tokens, precedenceStack); return(expr); case TokenType.Word: if (expressionCreators.ContainsKey(token.Value)) { // find the appropriate handler for this keyword expr = expressionCreators[token.Value].Create(); } else // we don't recognise the word, so we can assume it's a variable and validate it at run-time { // don't allow instruction keywords to be used as variable names if (instructionCreators.ContainsKey(token.Value)) { throw new TokenParserException("This word is the name of an instruction. You can't use it here in this context.", token); } else { expr = new VariableExpression(); } } // if applicable, have the expression prepare itself according to its own rules if (expr is IFlexibleSyntaxExpression) { ((IFlexibleSyntaxExpression)expr).PrepareExpression(tokens, precedenceStack); } else // otherwise just advance to the next token { tokens.Advance(); } // chain together any properties and argument lists expr = BuildDeepExpression(expr, tokens); break; case TokenType.PropertyDesignator: // property designators are handled elsewhere. if we found one here, it's a parsing error. if (tokens.Previous.TokenType == TokenType.Word) { throw new TokenParserException("This type of expression doesn't allow you to specify a property.", tokens.Next); } throw new TokenParserException("You've got a property designator in a spot where it doesn't belong.", tokens.Next); case TokenType.GroupStart: expr = BuildGroupedExpression(tokens); break; case TokenType.GroupEnd: endGroupedExpression = true; break; default: throw new TokenParserException("This part of the script should equate to a value but instead I got \"" + token.Value + "\", which doesn't really mean anything in this context.", token); } if (!endGroupedExpression) { int?precedence = precedenceStack.Peek(); while (NextHasGreaterPrecedence(precedence, tokens)) { expr = BuildBinaryExpression(tokens, expr, precedenceStack); } } return(expr); }