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;
        }
Beispiel #4
0
        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));
        }
Beispiel #7
0
     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
                 });
             }
         }
     }