/// <summary> /// Applies the token to the parsing state. Will pop the operator stack executing all the operators storing each of the operands /// When we reach an opening bracket it will pass the stored operands to the opening bracket to be processed. /// </summary> /// <param name="token">The token to apply.</param> /// <param name="state">The state to apply the token to.</param> /// <exception cref="OperandExpectedException">When there are delimeters but no operands between them.</exception> /// <exception cref="BracketUnmatchedException">When there was no matching closing bracket.</exception> public override void Apply(Token token, ParseState state) { Stack <Operand> bracketOperands = new Stack <Operand>(); StringSegment previousSeperator = token.SourceMap; bool hasSeperators = false; while (state.Operators.Count > 0) { var currentOperator = state.Operators.Pop(); if (BracketOpenDefinitions.Contains(currentOperator.Definition)) { var operand = state.Operands.Count > 0 ? state.Operands.Peek() : null; var firstSegment = currentOperator.SourceMap; var secondSegment = previousSeperator; if (operand != null && operand.SourceMap.IsBetween(firstSegment, secondSegment)) { bracketOperands.Push(state.Operands.Pop()); } else if (hasSeperators && (operand == null || !operand.SourceMap.IsBetween(firstSegment, secondSegment))) { //if we have seperators then we should have something between the last seperator and the open bracket. throw new OperandExpectedException(StringSegment.Between(firstSegment, secondSegment)); } //pass our all bracket operands to the open bracket method, he will know //what we should do. var closeBracketOperator = new Operator(this, token.SourceMap, () => { }); ((BracketOpenDefinition)currentOperator.Definition).ApplyBracketOperands( currentOperator, bracketOperands, closeBracketOperator, state); return; } else if (ListDelimeterDefinition != null && currentOperator.Definition == ListDelimeterDefinition) { hasSeperators = true; var operand = state.Operands.Pop(); //if our operator is not between two delimeters, then we are missing an operator var firstSegment = currentOperator.SourceMap; var secondSegment = previousSeperator; if (!operand.SourceMap.IsBetween(firstSegment, secondSegment)) { throw new OperandExpectedException(StringSegment.Between(firstSegment, secondSegment)); } bracketOperands.Push(operand); previousSeperator = currentOperator.SourceMap; } else { //regular operator, execute it currentOperator.Execute(); } } //We have pop'd through all the operators and not found an open bracket throw new BracketUnmatchedException(token.SourceMap); }
/// <summary> /// Applies the bracket operands. Adds the evaluated operand within the bracket to the state. /// </summary> /// <param name="bracketOpen">The operator that opened the bracket.</param> /// <param name="bracketOperands">The list of operands within the brackets.</param> /// <param name="bracketClose">The operator that closed the bracket.</param> /// <param name="state">The current parse state.</param> /// <exception cref="OperandExpectedException">When brackets are empty.</exception> /// <exception cref="OperandUnexpectedException">When there is more than one element in the brackets</exception> public virtual void ApplyBracketOperands(Operator bracketOpen, Stack <Operand> bracketOperands, Operator bracketClose, ParseState state) { if (bracketOperands.Count == 0) { var insideBrackets = StringSegment.Between(bracketOpen.SourceMap, bracketClose.SourceMap); throw new OperandExpectedException(insideBrackets); } else if (bracketOperands.Count > 1) { var operandSpan = StringSegment.Encompass(bracketOperands.Skip(1).Select(x => x.SourceMap)); throw new OperandUnexpectedException(operandSpan); } var bracketOperand = bracketOperands.Pop(); var sourceMap = StringSegment.Encompass(new[] { bracketOpen.SourceMap, bracketOperand.SourceMap, bracketClose.SourceMap }); state.Operands.Push(new Operand(bracketOperand.Expression, sourceMap)); }