private void HandlePossibleConflict(ref OperatorData prevOpData, Operator <TTerm, TAfterString, TUserState> op, ref Reply <TTerm> reply, CharStream <TUserState> stream) { // "possible" conflict, because it's not a conflict when the // after-string-parser fails without changing the parser state. var state = stream.State; var ok = stream.Skip(op.String); Debug.Assert(ok); var stateTag = stream.StateTag; var asReply = op.AfterStringParser.Invoke(stream); if (asReply.Status == ReplyStatus.Ok) { stream.BacktrackTo(ref state); ReportConflict(ref prevOpData, op, asReply.Result, ref reply, stream); } else if (asReply.Status == ReplyStatus.Error && stateTag == stream.StateTag) { // backtrack and ignore the operator stream.BacktrackTo(ref state); reply.Error = ErrorMessageList.Merge(reply.Error, ExpectedInfixOrPostfixOperator); } else { // report AfterStringParser error instead of conflict reply.Error = asReply.Error; reply.Status = asReply.Status; } }
private void HandleMissingTernary2ndStringError(ref OperatorData opData, ref Reply <TTerm> reply, CharStream <TUserState> stream) { var firstStringIndex = opData.IndexToken.GetIndex(stream); var firstStringColumn = firstStringIndex - opData.LineBegin + 1; var firstStringPos = new Position(stream.Name, firstStringIndex, opData.Line, firstStringColumn); var secondStringPos = stream.Position; var error1 = ExpectedInfixOrPostfixOperator; var error2 = MissingTernary2ndStringErrorFormatter.Invoke(Tuple.Create(firstStringPos, secondStringPos, (TernaryOperator <TTerm, TAfterString, TUserState>)opData.Operator, opData.AfterStringValue)); reply.Error = ErrorMessageList.Merge(reply.Error, ErrorMessageList.Merge(error1, error2)); reply.Status = ReplyStatus.Error; }
private void ReportConflict(ref OperatorData prevOpData, Operator <TTerm, TAfterString, TUserState> op, TAfterString afterStringValue, ref Reply <TTerm> reply, CharStream <TUserState> stream) { var prevOpIndex = prevOpData.IndexToken.GetIndex(stream); var prevOpColumn = prevOpIndex - prevOpData.LineBegin + 1; var prevOpPos = new Position(stream.Name, prevOpIndex, prevOpData.Line, prevOpColumn); var error = _OperatorConflictErrorFormatter.Invoke( Tuple.Create(prevOpPos, prevOpData.Operator, prevOpData.AfterStringValue), Tuple.Create(stream.Position, op, afterStringValue)); reply.Error = ErrorMessageList.Merge(reply.Error, error); reply.Status = ReplyStatus.Error; }
public override Reply <TResult> Invoke(CharStream <TUserState> stream) { var tag = stream.StateTag; var eReply = EndParser.Invoke(stream); if (eReply.Status == ReplyStatus.Error && tag == stream.StateTag) { var reply = CharParser1.Invoke(stream); if (reply.Status == ReplyStatus.Ok) { return(ParseRestOfString(stream, reply.Result, reply.Error)); } else { var error = tag == stream.StateTag ? ErrorMessageList.Merge(eReply.Error, reply.Error) : reply.Error; return(new Reply <TResult> { Status = reply.Status, Error = error }); } } else if (eReply.Status == ReplyStatus.Ok) { var result = Mapping.Invoke("", eReply.Result); return(new Reply <TResult> { Status = ReplyStatus.Ok, Result = result, Error = eReply.Error }); } else { return(new Reply <TResult> { Status = eReply.Status, Error = eReply.Error }); } }
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); }
ParseExpression(ref OperatorData prevOpData, // prevOpData is passed as ref for performance reasons, but is not mutated ref Reply <TTerm> reply, CharStream <TUserState> stream) { Operator <TTerm, TAfterString, TUserState> op; if (PrefixOpCount != 0 && ((op = PeekOp(stream, LhsOps)) != null)) { op = ParsePrefixOp(ref prevOpData, op, ref reply, stream); // ParsePrefixOp returns ErrorOp when it backtracks and we should try to parse a term if (op == null) { goto Break; } if (op != ErrorOp) { goto CheckNextOp; } } var error = reply.Error; var stateTag = stream.StateTag; reply = TermParser.Invoke(stream); // <-- this is where we parse the terms if (stateTag == stream.StateTag) { error = ErrorMessageList.Merge(error, reply.Error); if (PrefixOpCount != 0) { error = ErrorMessageList.Merge(error, Errors.ExpectedPrefixOperator); } reply.Error = error; } if (reply.Status != ReplyStatus.Ok) { goto ReturnNull; } op = PeekOp(stream, RhsOps); CheckNextOp: if (op != null) { var prevOp = prevOpData.Operator; if (prevOp.Precedence > op.Precedence) { goto Break; } if (prevOp.Precedence < op.Precedence) { goto Continue; } // prevOp.Precedence == op.Precedence if (op.Type == OperatorType.Infix) { var assoc = prevOp.Associativity & op.Associativity; if (assoc == Associativity.Left || prevOp.Type == OperatorType.Prefix) { goto Break; } if (assoc == Associativity.Right) { goto Continue; } } else { if (prevOp.Type == OperatorType.Infix) { goto Continue; } Debug.Assert(prevOp.Type == OperatorType.Prefix && op.Type == OperatorType.Postfix); if ((prevOp.Associativity | op.Associativity) != Associativity.None) { goto Break; } } HandlePossibleConflict(ref prevOpData, op, ref reply, stream); } else { error = ErrorMessageList.Merge(reply.Error, ExpectedInfixOrPostfixOperator); reply.Error = error; } ReturnNull: op = null; Break: return(op); Continue: return(ParseExpressionContinue(ref prevOpData, op, ref reply, stream)); }
protected Reply <string> ParseRestOfString(CharStream <TUserState> stream, char firstChar, ErrorMessageList error) { #if LOW_TRUST var sb = new StringBuilder(16); sb.Append(firstChar); #else _16CharBuffer buffer_; // produces more efficient code on .NET than stackalloc char[16] char * buffer = (char *)(&buffer_); buffer[0] = firstChar; char[] chars = null; uint n = 1; #endif for (;;) { var tag = stream.StateTag; var reply = CharParser.Invoke(stream); if (reply.Status == ReplyStatus.Ok) { if (tag == stream.StateTag) { throw Internal.ParserCombinatorInInfiniteLoopHelper.CreateException("manyChars", stream); } error = reply.Error; #if LOW_TRUST sb.Append(reply.Result); #else var i = n % 16; if (i != 0) { buffer[i] = reply.Result; ++n; } else { if (chars == null) { chars = new char[32]; } else if (n == chars.Length) { var newChars = new char[2 * chars.Length]; Array.Copy(chars, newChars, chars.Length); chars = newChars; } for (i = 0; i < 16; ++i) { chars[n - 16 + i] = buffer[i]; } buffer[0] = reply.Result; ++n; } #endif } else if (reply.Status == ReplyStatus.Error && tag == stream.StateTag) { string str; #if LOW_TRUST str = sb.ToString(); #else if (n <= 16) { str = new String(buffer, 0, (int)n); } else { for (uint i = (n - 1) & 0x7ffffff0u; i < n; ++i) { chars[i] = buffer[i % 16]; } str = new string(chars, 0, (int)n); } #endif error = ErrorMessageList.Merge(error, reply.Error); return(new Reply <string> { Status = ReplyStatus.Ok, Result = str, Error = error }); } else { error = tag == stream.StateTag ? ErrorMessageList.Merge(error, reply.Error) : reply.Error; return(new Reply <string> { Status = reply.Status, Error = error }); } } }