ParsePrefixOp(ref OperatorData prevOpData, Operator <TTerm, TAfterString, TUserState> op, ref Reply <TTerm> reply, CharStream <TUserState> stream) { var opData = new OperatorData(); opData.Line = stream.Line; opData.LineBegin = stream.LineBegin; opData.IndexToken = stream.IndexToken; opData.Operator = op; var userState = stream.UserState; #if DEBUG var ok = stream.Skip(op.String); Debug.Assert(ok); #else stream.Skip((uint)op.String.Length); #endif var stateTag = stream.StateTag; var asReply = op.AfterStringParser.Invoke(stream); if (asReply.Status == ReplyStatus.Ok) { opData.AfterStringValue = asReply.Result; var prevOp = prevOpData.Operator; if (prevOp.Precedence != op.Precedence || prevOp.Type != OperatorType.Prefix || (prevOp.Associativity | op.Associativity) != Associativity.None) { reply.Error = asReply.Error; var nextOp = ParseExpression(ref opData, ref reply, stream); if (reply.Status == ReplyStatus.Ok) { reply.Result = op.Mapping1.Invoke(opData.AfterStringValue, reply.Result); } return(nextOp); } // backtrack to the beginning of the operator stream.Seek(opData.IndexToken); stream.SetLine_WithoutCheckAndWithoutIncrementingTheStateTag(opData.Line); stream.SetLineBegin_WithoutCheckAndWithoutIncrementingTheStateTag(opData.LineBegin); stream.UserState = userState; stream.StateTag = stateTag - 1; ReportConflict(ref prevOpData, op, asReply.Result, ref reply, stream); return(null); } else if (asReply.Status == ReplyStatus.Error && stateTag == stream.StateTag) { // backtrack to the beginning of the operator stream.Seek(opData.IndexToken); stream.StateTag = stateTag - 1; return(ErrorOp); } else { reply.Error = asReply.Error; reply.Status = asReply.Status; return(null); } }
ParseExpressionContinue(ref OperatorData prevOpData, Operator <TTerm, TAfterString, TUserState> op, ref Reply <TTerm> reply, CharStream <TUserState> stream) { var opData = new OperatorData(); for (;;) { opData.Line = stream.Line; opData.LineBegin = stream.LineBegin; opData.IndexToken = stream.IndexToken; opData.Operator = op; #if DEBUG var ok = stream.Skip(op.String); Debug.Assert(ok); #else stream.Skip((uint)op.String.Length); #endif var stateTag = stream.StateTag; var asReply = op.AfterStringParser.Invoke(stream); if (asReply.Status == ReplyStatus.Ok) { opData.AfterStringValue = asReply.Result; reply.Error = asReply.Error; if (op.Type == OperatorType.Infix) { var result1 = reply.Result; if (!op.IsTernary) { var nextOp = ParseExpression(ref opData, ref reply, stream); if (reply.Status == ReplyStatus.Ok) { reply.Result = op.Mapping2.Invoke(opData.AfterStringValue, result1, reply.Result); } op = nextOp; if (op == null) { break; } goto CheckNextOp; } else { ParseExpression(ref ZeroPrecedenceOperatorData, ref reply, stream); if (reply.Status != ReplyStatus.Ok) { goto ReturnNull; } var result2 = reply.Result; if (stream.Skip(op.TernaryRightString)) { stateTag = stream.StateTag; asReply = op.AfterTernaryRightStringParser.Invoke(stream); if (asReply.Status == ReplyStatus.Ok) { reply.Error = asReply.Error; var nextOp = ParseExpression(ref opData, ref reply, stream); if (reply.Status == ReplyStatus.Ok) { reply.Result = op.Mapping3.Invoke(opData.AfterStringValue, asReply.Result, result1, result2, reply.Result); } op = nextOp; if (op == null) { break; } goto CheckNextOp; } else if (asReply.Status != ReplyStatus.Error || stateTag != stream.StateTag) { reply.Error = asReply.Error; reply.Status = asReply.Status; goto ReturnNull; } else { // backtrack stream.Skip(-op.TernaryRightString.Length); stream.StateTag -= 2; } } HandleMissingTernary2ndStringError(ref opData, ref reply, stream); goto ReturnNull; } } else { Debug.Assert(op.Type == OperatorType.Postfix); reply.Result = op.Mapping1.Invoke(opData.AfterStringValue, reply.Result); var lastOp = op; op = PeekOp(stream, RhsOps); // we check for adjacent postfix operators here ... if (op != null) { if (op.Type == OperatorType.Postfix && lastOp.Precedence <= op.Precedence) { if (lastOp.Precedence < op.Precedence || (lastOp.Associativity | op.Associativity) != Associativity.None) { continue; } // ... so we can report conflicting postfix operators HandlePossibleConflict(ref opData, op, ref reply, stream); goto ReturnNull; } } else { reply.Error = ErrorMessageList.Merge(reply.Error, ExpectedInfixOrPostfixOperator); break; } } CheckNextOp: var prevOp = prevOpData.Operator; if (prevOp.Precedence < op.Precedence) { continue; } if (prevOp.Precedence > op.Precedence) { break; } // prevOp.Precedence == op.Precedence if (op.Type == OperatorType.Infix) { var assoc = prevOp.Associativity & op.Associativity; if (assoc == Associativity.Left || prevOp.Type == OperatorType.Prefix) { break; } if (assoc == Associativity.Right) { continue; } } else // op.OperatorType == OperatorType.Postfix { if (prevOp.Type == OperatorType.Infix) { continue; } Debug.Assert(prevOp.Type == OperatorType.Prefix); if ((prevOp.Associativity | op.Associativity) != Associativity.None) { break; } } HandlePossibleConflict(ref prevOpData, op, ref reply, stream); } else // asReply.Status != ReplyStatus.Ok { if (asReply.Status == ReplyStatus.Error && stateTag == stream.StateTag) { // backtrack stream.Seek(opData.IndexToken); stream.StateTag -= 2; reply.Error = ErrorMessageList.Merge(reply.Error, ExpectedInfixOrPostfixOperator); } else { reply.Error = asReply.Error; reply.Status = asReply.Status; } } ReturnNull: op = null; break; } return(op); }