Beispiel #1
0
        public static ExpressionNode Parse(string buffer, int startOffset, int endOffset, ExpressionOptions options, int baseOffset)
        {
            List <ExpressionNode> splitList = null;
            var nodes = new List <ExpressionNode> ();

            int lastNodeEnd = startOffset;

            for (int offset = startOffset; offset <= endOffset; offset++)
            {
                char c = buffer [offset];

                //consume entities simply so the semicolon doesn't mess with list parsing
                //we don't need the value and the base XML editor will handle errors
                if (c == '&')
                {
                    offset++;
                    //FIXME: use proper entity name logic. this will do for now.
                    var name = ReadName(buffer, ref offset, endOffset);
                    if (offset > endOffset)
                    {
                        break;
                    }
                    if (buffer[offset] == ';')
                    {
                        continue;
                    }
                    c = buffer [offset];
                }

                if ((options.HasFlag(ExpressionOptions.Lists) && c == ';') || (c == ',' && options.HasFlag(ExpressionOptions.CommaLists)))
                {
                    CaptureLiteral(offset, nodes.Count == 0);
                    if (splitList == null)
                    {
                        splitList = new List <ExpressionNode> ();
                    }
                    FlushNodesToSplitList(offset);
                    lastNodeEnd = offset + 1;
                    continue;
                }

                int possibleLiteralEndOffset = offset;

                ExpressionNode node;
                switch (c)
                {
                case '@':
                    if (!TryConsumeParen())
                    {
                        continue;
                    }
                    if (options.HasFlag(ExpressionOptions.Items))
                    {
                        node = ParseItem(buffer, ref offset, endOffset, baseOffset);
                    }
                    else
                    {
                        node = new ExpressionError(baseOffset + offset, ExpressionErrorKind.ItemsDisallowed);
                    }
                    break;

                case '$':
                    if (!TryConsumeParen())
                    {
                        continue;
                    }
                    node = ParseProperty(buffer, ref offset, endOffset, baseOffset);
                    break;

                case '%':
                    if (!TryConsumeParen())
                    {
                        continue;
                    }
                    if (options.HasFlag(ExpressionOptions.Metadata))
                    {
                        node = ParseMetadata(buffer, ref offset, endOffset, baseOffset);
                    }
                    else
                    {
                        node = new ExpressionError(baseOffset + offset, ExpressionErrorKind.MetadataDisallowed);
                    }
                    break;

                default:
                    continue;
                }

                CaptureLiteral(possibleLiteralEndOffset, false);
                lastNodeEnd = offset + 1;

                nodes.Add(node);
                if (node is ExpressionError)
                {
                    //short circuit out without capturing the rest as text, since it's not useful
                    return(CreateResult(offset));
                }

                bool TryConsumeParen()
                {
                    if (offset < endOffset && buffer[offset + 1] == '(')
                    {
                        offset++;
                        offset++;
                        return(true);
                    }
                    return(false);
                }
            }

            CaptureLiteral(endOffset + 1, nodes.Count == 0);
            return(CreateResult(endOffset));

            void CaptureLiteral(int toOffset, bool isPure)
            {
                if (toOffset > lastNodeEnd)
                {
                    string s = buffer.Substring(lastNodeEnd, toOffset - lastNodeEnd);
                    nodes.Add(new ExpressionText(baseOffset + lastNodeEnd, s, isPure));
                }
            }

            void FlushNodesToSplitList(int offset)
            {
                if (nodes.Count == 0)
                {
                    splitList.Add(new ExpressionError(baseOffset + offset, ExpressionErrorKind.EmptyListEntry));
                }
                else if (nodes.Count == 1)
                {
                    splitList.Add(nodes [0]);
                    nodes.Clear();
                }
                else
                {
                    var start = nodes [0].Offset;
                    var l     = nodes [nodes.Count - 1].End - start;
                    splitList.Add(new ConcatExpression(start, l, nodes.ToArray()));
                    nodes.Clear();
                }
            }

            ExpressionNode CreateResult(int offset)
            {
                if (splitList != null)
                {
                    FlushNodesToSplitList(offset);
                }
                if (splitList != null)
                {
                    return(new ListExpression(baseOffset + startOffset, endOffset - startOffset + 1, splitList.ToArray()));
                }
                if (nodes.Count == 0)
                {
                    return(new ExpressionText(baseOffset + startOffset, "", true));
                }
                if (nodes.Count == 1)
                {
                    return(nodes [0]);
                }
                return(new ConcatExpression(baseOffset + startOffset, endOffset - startOffset + 1, nodes.ToArray()));
            }
        }
Beispiel #2
0
        static ExpressionNode ParseCondition(string buffer, ref int offset, int endOffset, int baseOffset, out bool hasError)
        {
            ConsumeSpace(buffer, ref offset, endOffset);

            ExpressionNode left = ParseConditionOperand(buffer, ref offset, endOffset, baseOffset, out hasError);

            if (hasError)
            {
                return(left);
            }

            ExpressionOperatorKind?pendingBoolOp   = null;
            ExpressionNode         pendingBoolExpr = null;

            while (offset <= endOffset && !hasError)
            {
                ConsumeSpace(buffer, ref offset, endOffset);
                if (offset > endOffset)
                {
                    break;
                }

                if (buffer[offset] == ')')
                {
                    break;
                }

                ExpressionNode operand;
                var            op = ReadOperator(buffer, baseOffset, ref offset, endOffset, out var opError, out hasError);
                if (opError != null)
                {
                    operand = opError;
                }
                else
                {
                    ConsumeSpace(buffer, ref offset, endOffset);
                    if (offset > endOffset)
                    {
                        operand = new ExpressionError(baseOffset + offset, ExpressionErrorKind.ExpectingValue, out hasError);
                    }
                    else
                    {
                        operand = ParseConditionOperand(buffer, ref offset, endOffset, baseOffset, out hasError);
                    }
                }

                if (op == ExpressionOperatorKind.Or || op == ExpressionOperatorKind.And)
                {
                    if (pendingBoolOp != null)
                    {
                        pendingBoolExpr = new ExpressionConditionOperator(pendingBoolOp, pendingBoolExpr, left);
                    }
                    else
                    {
                        pendingBoolExpr = left;
                    }
                    pendingBoolOp = op;
                    left          = operand;
                    continue;
                }
                else
                {
                    left = new ExpressionConditionOperator(op, left, operand);
                    if (pendingBoolOp != null)
                    {
                        left          = new ExpressionConditionOperator(pendingBoolOp, pendingBoolExpr, left);
                        pendingBoolOp = null;
                    }
                }
            }

            if (pendingBoolOp != null)
            {
                left = new ExpressionConditionOperator(pendingBoolOp, pendingBoolExpr, left);
            }

            return(left);
        }