public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				context.Nodes.Push (new XProcessingInstruction (context.LocationMinus ("<?".Length)));
			}
			
			if (c == '?') {
				if (context.StateTag == NOMATCH) {
					context.StateTag = QUESTION;
					return null;
				}
			} else if (c == '>' && context.StateTag == QUESTION) {
				// if the '?' is followed by a '>', the state has ended
				// so attach a node to the DOM and end the state
				var xpi = (XProcessingInstruction) context.Nodes.Pop ();
				
				if (context.BuildTree) {
					xpi.End (context.Location);
					((XContainer) context.Nodes.Peek ()).AddChildNode (xpi); 
				}
				return Parent;
			} else {
				context.StateTag = NOMATCH;
			}
			
			return null;
		}
Example #2
0
        /// <summary>
        /// Gets properties that was not created from schema.
        /// </summary>
        /// <param name="parserContext">Source parser context.</param>
        /// <param name="schema">Source schema.</param>
        /// <param name="recursive">Recursive search in children schemas.</param>
        /// <returns>Properties that was not created from schema.</returns>
        public static IEnumerable <IProperty> GetPropertiesNotFromSchema(this IXmlParserContext parserContext, ISchema?schema = null, bool recursive = true)
        {
            // Use root schema.
            schema ??= parserContext.Schema;

            IEnumerable <IProperty> properties = schema.GetProperties();

            foreach (IProperty property in properties)
            {
                if (property.GetIsNotFromSchema())
                {
                    yield return(property);
                }

                if (recursive)
                {
                    if (parserContext.GetSchema(property) is { } subSchema)
                    {
                        foreach (IProperty subProperty in parserContext.GetPropertiesNotFromSchema(subSchema, recursive))
                        {
                            yield return(subProperty);
                        }
                    }
                }
            }
        }
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1)
            {
                context.Nodes.Push(new XProcessingInstruction(context.LocationMinus("<?".Length)));
            }

            if (c == '?')
            {
                if (context.StateTag == NOMATCH)
                {
                    context.StateTag = QUESTION;
                    return(null);
                }
            }
            else if (c == '>' && context.StateTag == QUESTION)
            {
                // if the '?' is followed by a '>', the state has ended
                // so attach a node to the DOM and end the state
                var xpi = (XProcessingInstruction)context.Nodes.Pop();

                if (context.BuildTree)
                {
                    xpi.End(context.Location);
                    ((XContainer)context.Nodes.Peek()).AddChildNode(xpi);
                }
                return(Parent);
            }
            else
            {
                context.StateTag = NOMATCH;
            }

            return(null);
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			//NOTE: This is (mostly) duplicated in HtmlTagState
			//handle inline tags implicitly closed by block-level elements
			if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState)
			{
				var ct = (XClosingTag) context.Nodes.Peek ();
				if (!ct.Name.HasPrefix && ct.Name.IsValid) {
					//Note: the node stack will always be at least 1 deep due to the XDocument
					var parent = context.Nodes.Peek (1) as XElement;
					//if it's not a matching closing tag
					if (parent != null && !string.Equals (ct.Name.Name, parent.Name.Name, StringComparison.OrdinalIgnoreCase)) {
						//attempt to implicitly close the parents
						while (parent != null && parent.ValidAndNoPrefix () && parent.IsImplicitlyClosedBy (ct)) {
							context.Nodes.Pop ();
							context.Nodes.Pop ();
							if (warnAutoClose) {
								context.LogWarning (string.Format ("Tag '{0}' implicitly closed by closing tag '{1}'.",
									parent.Name.Name, ct.Name.Name), parent.Region);
							}
							//parent.Region.End = element.Region.Start;
							//parent.Region.EndColumn = Math.Max (parent.Region.EndColumn - 1, 1);
							parent.Close (parent);
							context.Nodes.Push (ct);

							parent = context.Nodes.Peek (1) as XElement;
						}
					}
				} 
			}
			
			return base.PushChar (c, context, ref rollback);
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (c == '@' && context.StateTag == FREE) {
				context.StateTag = TRANSITION;
				return null;
			} else if (context.StateTag == TRANSITION) {
				rollback = String.Empty;
				switch (c) {
				case '{': // Code block @{
					return CodeBlockState;
				case '*': // Comment @*
					return ServerCommentState;
				case '(': // Explicit expression @(
					return ExpressionState;
				default:
					// If char preceding @ was a letter or a digit, don't switch to expression, e.g. [email protected]
					if (context.CurrentStateLength <= 2 || (!Char.IsLetterOrDigit (previousChar)
							&& (Char.IsLetter (c) || c == '_'))) // Statement, directive or implicit expression
						return SpeculativeState;
					else
						context.StateTag = FREE;
					break;
				}
			}

			previousChar = c;
			return base.PushChar (c, context, ref rollback);
		}
Example #6
0
        public void ReadInvalidXml()
        {
            string testXml = @"
<Person>
  <FirstName>z</FirstName>
  <Address>
    <City>NY</City>
    <Unknown>1</Unknown>
  </Address>
</Person>";

            IObjectSchema     personSchema     = new PersonSchema().GetObjectSchema();
            var               container        = XDocument.Parse(testXml).ParseXmlToContainer(personSchema);
            IXmlParserContext xmlParserContext = container.GetMetadata <IXmlParserContext>();

            var validationRules = personSchema.Properties.GetValidationRules().ToArray();
            var messages        = container.Validate(validationRules).ToArray();

            messages.Should().HaveCount(2);
            messages[0].FormattedMessage.Should().Be("FirstName length should be greater then 1 but was 1");
            messages[1].FormattedMessage.Should().Be("LastName is marked as required but is not exists.");

            IObjectSchema addressSchemaStatic = personSchema.GetProperty("Address") !.GetSchema() !.ToObjectSchema();

            addressSchemaStatic.Properties.Should().HaveCount(2);

            IObjectSchema addressSchemaReal = xmlParserContext.GetSchema(personSchema.GetProperty("Address")).ToObjectSchema();

            addressSchemaReal.Properties.Should().HaveCount(3);

            IProperty[] notFromSchema = addressSchemaReal.GetPropertiesNotFromSchema().ToArray();
            notFromSchema.Should().HaveCount(1);
            notFromSchema[0].Name.Should().Be("Unknown");
            notFromSchema[0].Type.Should().Be(typeof(string));
        }
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1)
            {
                context.Nodes.Push(new RazorComment(context.LocationMinus(2)));
                return(null);
            }

            switch (context.StateTag)
            {
            case NOMATCH:
                if (c == '*')
                {
                    context.StateTag = STAR;
                }
                break;

            case STAR:
                if (c == '@')
                {
                    StateEngineService.EndCodeFragment <RazorComment> (context);
                    return(Parent);
                }
                else
                {
                    context.StateTag = NOMATCH;
                }
                break;
            }

            return(null);
        }
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            if (c == '%' && context.StateTag == BRACKET)
            {
                context.StateTag = BRACKET_PERCENT;
                return(null);
            }
            else if (context.StateTag == BRACKET_PERCENT)
            {
                switch (c)
                {
                case '@':                 //DIRECTIVE <%@
                    return(DirectiveState);

                case '-':                 // SERVER COMMENT: <%--
                    return(ServerCommentState);

                case '=':                 //RENDER EXPRESSION <%=
                case '#':                 //DATABINDING EXPRESSION <%#
                case '$':                 //RESOURCE EXPRESSION <%$
                default:                  // RENDER BLOCK
                    rollback = "";
                    return(ExpressionState);
                }
            }

            return(base.PushChar(c, context, ref rollback));
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				context.Nodes.Push (new XCData (context.LocationMinus ("<![CDATA[".Length + 1)));
			}
			
			if (c == ']') {
				//make sure we know when there are two ']' chars together
				if (context.StateTag == NOMATCH)
					context.StateTag = SINGLE_BRACKET;
				else
					context.StateTag = DOUBLE_BRACKET;
				
			} else if (c == '>' && context.StateTag == DOUBLE_BRACKET) {
				// if the ']]' is followed by a '>', the state has ended
				// so attach a node to the DOM and end the state
				var cdata = (XCData) context.Nodes.Pop ();
				
				if (context.BuildTree) {
					cdata.End (context.Location);
					((XContainer) context.Nodes.Peek ()).AddChildNode (cdata); 
				}
				return Parent;
			} else {
				// not any part of a ']]>', so make sure matching is reset
				context.StateTag = NOMATCH;
			}
			
			return null;
		}
Example #10
0
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1)
            {
                bracketsBuilder.Clear();
                var block = context.Nodes.FirstOrDefault(n => n is RazorCodeBlock);
                if (block == null)
                {
                    var razorBlock = new RazorCodeBlock(context.LocationMinus(2));
                    context.Nodes.Push(razorBlock);
                    CorrespondingBlock = razorBlock;
                }
                else
                {
                    CorrespondingBlock = block as RazorCodeFragment;
                }
            }

            switch (c)
            {
            case '{':
                return(ParseOpeningBracket(c, context));

            case '}':
                return(ParseClosingBracket <RazorCodeBlock> (c, context, Parent));
            }

            return(base.PushChar(c, context, ref rollback));
        }
        internal static void AddExpressionNode(char c, IXmlParserContext context)
        {
            Debug.Assert(c != '@' && c != '-', "AspNetExpressionState should not be passed a directive or comment");

            switch (c)
            {
            //DATABINDING EXPRESSION <%#
            case '#':
                context.Nodes.Push(new WebFormsBindingExpression(context.LocationMinus(3)));
                break;

            //RESOURCE EXPRESSION <%$
            case '$':
                context.Nodes.Push(new WebFormsResourceExpression(context.LocationMinus(3)));
                break;

            //RENDER EXPRESSION <%=
            case '=':
                context.Nodes.Push(new WebFormsRenderExpression(context.LocationMinus(3)));
                break;

            //HTML ENCODED EXPRESSION <%:
            case ':':
                context.Nodes.Push(new WebFormsHtmlEncodedExpression(context.LocationMinus(3)));
                break;

            // RENDER BLOCK
            default:
                context.Nodes.Push(new WebFormsRenderBlock(context.LocationMinus(3)));
                break;
            }
        }
Example #12
0
        public static void EndCodeFragment <T> (IXmlParserContext context, DocumentLocation loc) where T : XNode
        {
            var top  = context.Nodes.Pop();
            var node = top as T;

            if (node == null)
            {
                if (top.IsEnded)
                {
                    node = context.Nodes.Pop() as T;
                }
                if (node == null)
                {
                    Debug.Fail("Unexpected node at the top of the stack");
                    LoggingService.LogError("Error in Razor StateEngine parser: unexpected node at the top of the stack.\n"
                                            + "Expected: {0}\n{1}", typeof(T), context.ToString());
                    return;
                }
            }
            node.End(loc);
            if (context.BuildTree)
            {
                var xObj      = context.Nodes.Peek();
                var container = xObj as XContainer;
                if (container != null)
                {
                    container.AddChildNode(node);
                }
            }
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				AddExpressionNode (c, context);
			}
			else if (c == '%') {
				context.StateTag = PERCENT;
			}
			else if (c == '>') {
				if (context.StateTag == PERCENT) {
					XNode expr = (XNode) context.Nodes.Pop ();
					expr.End (context.Location);
					if (context.BuildTree) {
						XObject ob = context.Nodes.Peek ();
						var xc = ob as XContainer;
						if (xc != null) {
							xc.AddChildNode (expr);
						}
					 	//FIXME: add to other kinds of node, e.g. if used within a tag
					}
					return Parent;
				} else {
					context.StateTag = NONE;
				}
			}
			
			return null;
		}
		internal static void AddExpressionNode (char c, IXmlParserContext context)
		{
			Debug.Assert (c != '@' && c!= '-', "AspNetExpressionState should not be passed a directive or comment");

			switch (c) {
			//DATABINDING EXPRESSION <%#
			case '#':
				context.Nodes.Push (new WebFormsBindingExpression (context.LocationMinus (3)));
				break;
			//RESOURCE EXPRESSION <%$
			case '$':
				context.Nodes.Push (new WebFormsResourceExpression (context.LocationMinus (3)));
				break;
			//RENDER EXPRESSION <%=
			case '=':
				context.Nodes.Push (new WebFormsRenderExpression (context.LocationMinus (3)));
				break;
			//HTML ENCODED EXPRESSION <%:
			case ':':
				context.Nodes.Push (new WebFormsHtmlEncodedExpression (context.LocationMinus (3)));
				break;
			// RENDER BLOCK
			default:
				context.Nodes.Push (new WebFormsRenderBlock (context.LocationMinus (3)));
				break;
			}
		}
Example #15
0
        public virtual XmlParserState ParseClosingBracket <T> (char c, IXmlParserContext context, XmlParserState stateToReturn) where T : XNode
        {
            bool isEnding  = false;
            var  rootState = RootState as RazorRootState;

            if (rootState.UseSimplifiedBracketTracker)
            {
                if (bracketsBuilder.Length > 0)
                {
                    bracketsBuilder.Remove(0, 1);
                }
                if (bracketsBuilder.Length == 0)
                {
                    isEnding = true;
                }
            }
            else if (!rootState.UseSimplifiedBracketTracker && CorrespondingBlock.IsEndingBracket(context.LocationMinus(1)))
            {
                isEnding = true;
            }

            if (isEnding)
            {
                StateEngineService.EndCodeFragment <T> (context);
                return(stateToReturn);
            }

            return(null);
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 0)
				context.StateTag = 0;
			
			if (c == '<') {
				if (context.StateTag == 0) {
					context.StateTag++;
					return null;
				}
			}
			if (context.StateTag > 0) {
				if (CLOSE[context.StateTag] == c) {
					context.StateTag++;
					if (context.StateTag == CLOSE.Length) {
						var el = (XElement) context.Nodes.Pop ();
						var closing = new XClosingTag (new XName ("script"), context.LocationMinus (CLOSE.Length));
						closing.End (context.Location);
						el.Close (closing);
						rollback = string.Empty;
						return Parent;
					}
				} else {
					context.StateTag = 0;
				}
			}
			return null;
		}
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1)
            {
                context.Nodes.Push(new WebFormsServerComment(context.LocationMinus(context.CurrentStateLength + "<%--".Length)));
            }

            switch (context.StateTag)
            {
            case NOMATCH:
                if (c == '-')
                {
                    context.StateTag = SINGLE_DASH;
                }
                break;

            case SINGLE_DASH:
                if (c == '-')
                {
                    context.StateTag = DOUBLE_DASH;
                }
                else
                {
                    context.StateTag = NOMATCH;
                }
                break;

            case DOUBLE_DASH:
                if (c == '%')
                {
                    context.StateTag = PERCENT;
                }
                else
                {
                    context.StateTag = NOMATCH;
                }
                break;

            case PERCENT:
                if (c == '>')
                {
                    var comment = (WebFormsServerComment)context.Nodes.Pop();
                    comment.End(context.Location);
                    if (context.BuildTree)
                    {
                        XObject ob = context.Nodes.Peek();
                        if (ob is XContainer)
                        {
                            ((XContainer)ob).AddChildNode(comment);
                        }
                        //FIXME: add to other kinds of node, e.g. if used within a tag
                    }
                    return(Parent);
                }
                break;
            }

            return(null);
        }
Example #18
0
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            var namedObject = context.Nodes.Peek() as INamedXObject;

            if (namedObject == null || namedObject.Name.Prefix != null)
            {
                throw new InvalidOperationException("Invalid state");
            }

            Debug.Assert(context.CurrentStateLength > 1 || IsValidNameStart(c),
                         "First character pushed to a XmlTagNameState must be a letter.");
            Debug.Assert(context.CurrentStateLength > 1 || context.KeywordBuilder.Length == 0,
                         "Keyword builder must be empty when state begins.");

            if (XmlChar.IsWhitespace(c) || c == '<' || c == '>' || c == '/' || c == '=')
            {
                rollback = string.Empty;
                if (context.KeywordBuilder.Length == 0)
                {
                    context.LogError("Zero-length name.");
                    namedObject.Name = XName.Empty;
                }
                else
                {
                    string s = context.KeywordBuilder.ToString();
                    int    i = s.IndexOf(':');
                    if (i < 0)
                    {
                        namedObject.Name = new XName(s);
                    }
                    else
                    {
                        namedObject.Name = new XName(s.Substring(0, i), s.Substring(i + 1));
                    }
                }

                return(Parent);
            }
            if (c == ':')
            {
                if (context.KeywordBuilder.ToString().IndexOf(':') > 0)
                {
                    context.LogError("Unexpected ':' in name.");
                }
                context.KeywordBuilder.Append(c);
                return(null);
            }

            if (XmlChar.IsNameChar(c))
            {
                context.KeywordBuilder.Append(c);
                return(null);
            }

            rollback = string.Empty;
            context.LogError("Unexpected character '" + c + "' in name");
            return(Parent);
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			// allow < in values
			if (context.StateTag != '\0' && context.CurrentStateLength > 1 && c == '<') {
				context.KeywordBuilder.Append (c);
				return null;
			}
			return base.PushChar (c, context, ref rollback);
		}
Example #20
0
 public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
 {
     // allow < in values
     if (context.StateTag != '\0' && context.CurrentStateLength > 1 && c == '<')
     {
         context.KeywordBuilder.Append(c);
         return(null);
     }
     return(base.PushChar(c, context, ref rollback));
 }
Example #21
0
        /// <summary>
        /// Gets schema for property.
        /// If property is null then returns null.
        /// </summary>
        /// <param name="context">Parser context.</param>
        /// <param name="property">Source property.</param>
        /// <returns>Optional schema attached to property.</returns>
        public static ISchema?GetSchema(this IXmlParserContext context, IProperty?property)
        {
            if (property == null)
            {
                return(null);
            }

            context.SchemaCache.TryGetValue(property, out var schema);
            return(schema);
        }
        protected virtual void Close(XElement element, IXmlParserContext context, int endOffset)
        {
            //have already checked that element is not null, i.e. top of stack is our element
            if (element.IsClosed)
            {
                context.Nodes.Pop();
            }

            element.End(endOffset);
        }
Example #23
0
        protected virtual void Close(XElement element, IXmlParserContext context, DocumentLocation location)
        {
            //have already checked that element is not null, i.e. top of stack is our element
            if (element.IsClosed)
            {
                context.Nodes.Pop();
            }

            element.End(location);
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				switch (c) {
				case '(':
					context.StateTag = NONE_EXPLICIT;
					context.Nodes.Push (new RazorExplicitExpression (context.LocationMinus (2)));
					return null;

				default:
					context.StateTag = NONE_IMPLICIT;
					if (!(context.PreviousState is RazorSpeculativeState))
						context.Nodes.Push (new RazorImplicitExpression (context.LocationMinus (2)));
					break;
				}
			}

			switch (c)
			{
				case '(':
					if (context.StateTag == NONE_EXPLICIT)
						context.StateTag = INSIDE_BRACKET_EXPLICIT;
					else if (context.StateTag == NONE_IMPLICIT)
						context.StateTag = INSIDE_BRACKET_IMPLICIT;
					context.KeywordBuilder.Append (c);
					break;

				case ')':
					if (context.StateTag == NONE_EXPLICIT) {
						StateEngineService.EndCodeFragment<RazorExplicitExpression> (context);
						return Parent;
					}
					else if (context.StateTag != NONE_IMPLICIT) {
						if (context.KeywordBuilder.Length > 0)
							context.KeywordBuilder.Remove (0, 1);
						if (context.KeywordBuilder.Length == 0)
							context.StateTag = (context.StateTag == INSIDE_BRACKET_IMPLICIT ? NONE_IMPLICIT : NONE_EXPLICIT);
					}
					break;

				default:
					// Space between function's name and open bracket not allowed in razor, e.g. @Html.Raw (foo) 
					if (!(Char.IsLetterOrDigit (c) || allowedChars.Any (ch => ch == c))
							&& context.StateTag == NONE_IMPLICIT) {
						StateEngineService.EndCodeFragment<RazorImplicitExpression> (context, 1);
						rollback = String.Empty;
						if (Parent is RazorSpeculativeState)
							return Parent.Parent;
						return Parent;
					}
					break;
			}

			return null;
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			var directive = context.Nodes.Peek () as WebFormsDirective;
			
			if (directive == null || directive.IsComplete) {
				directive = new WebFormsDirective (context.LocationMinus (4)); // 4 == <%@ + current char
				context.Nodes.Push (directive);
			}
			
			if (c == '<') {
				context.LogError ("Unexpected '<' in directive.");
				rollback = string.Empty;
				return Parent;
			}
			
			Debug.Assert (!directive.IsComplete);
			
			if (context.StateTag != ENDING && c == '%') {
				context.StateTag = ENDING;
				return null;
			}
			
			
			if (context.StateTag == ENDING) {
				if (c == '>') {
					//have already checked that directive is not null, i.e. top of stack is our directive
					context.Nodes.Pop ();
					
					if (!directive.IsNamed) {
						context.LogError ("Directive closed prematurely.");
					} else {
						directive.End (context.Location);
						if (context.BuildTree) {
							var container = (XContainer)context.Nodes.Peek ();
							container.AddChildNode (directive);
						}
					}
					return Parent;
				}
				//ending but not '>'? Error; go to end.
			} else if (char.IsLetter (c)) {
				rollback = string.Empty;
				if (!directive.IsNamed) {
					return NameState;
				} else {
					return AttributeState;
				}
			} else if (char.IsWhiteSpace (c))
				return null;
			
			rollback = string.Empty;
			context.LogError ("Unexpected character '" + c + "' in tag.");
			return Parent;
		}
Example #26
0
        /// <summary>
        /// Gets properties that was not created from schema for the property.
        /// </summary>
        /// <param name="parserContext">Source parser context.</param>
        /// <param name="property">Property to get schema..</param>
        /// <param name="recursive">Recursive search in children schemas.</param>
        /// <returns>Properties that was not created from schema.</returns>
        public static IEnumerable <IProperty> GetPropertiesNotFromSchema(this IXmlParserContext parserContext, IProperty property, bool recursive = true)
        {
            ISchema?schema = parserContext.GetSchema(property);

            if (schema == null)
            {
                return(Array.Empty <IProperty>());
            }

            return(parserContext.GetPropertiesNotFromSchema(schema, recursive: recursive));
        }
Example #27
0
        XmlParserState SwitchToStatement(IXmlParserContext context, ref string rollback)
        {
            string key = context.KeywordBuilder.ToString();
            var    stm = new RazorStatement(context.LocationMinus(key.Length + 2))
            {
                Name = key.Trim()
            };

            context.Nodes.Push(stm);
            rollback = String.Empty;
            return(EnsureSetAndAdopted <RazorStatementState> (ref statementState));
        }
Example #28
0
        /// <summary>
        /// Gets parser from context cache or <see cref="IXmlParserSettings.ParserRules"/>.
        /// </summary>
        /// <param name="context">Parser context.</param>
        /// <param name="property">Source property.</param>
        /// <returns>Parser.</returns>
        public static IValueParser GetParserCached(this IXmlParserContext context, IProperty property)
        {
            if (context.ParsersCache.TryGetValue(property, out IValueParser result))
            {
                return(result);
            }

            result = context.ParserSettings.ParserRules.GetParserRule(property, context.ParserSettings.PropertyComparer)?.Parser ?? EmptyParser.Instance;
            context.ParsersCache.TryAdd(property, result);

            return(result);
        }
Example #29
0
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1 && context.PreviousState is HtmlScriptBodyState)
            {
                return(Parent);
            }

            //NOTE: This is (mostly) duplicated in HtmlClosingTagState
            //handle "paragraph" tags implicitly closed by block-level elements
            if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState)
            {
                var element = (XElement)context.Nodes.Peek();

                if (!element.Name.HasPrefix && element.Name.IsValid)
                {
                    //Note: the node stack will always be at least 1 deep due to the XDocument
                    var parent = context.Nodes.Peek(1) as XElement;

                    while (parent != null && parent.ValidAndNoPrefix() && parent.IsImplicitlyClosedBy(element))
                    {
                        context.Nodes.Pop();
                        context.Nodes.Pop();
                        //parent.Region.End = element.Region.Start;
                        //parent.Region.EndColumn = Math.Max (parent.Region.EndColumn - 1, 1);
                        parent.Close(parent);
                        context.Nodes.Push(element);

                        parent = context.Nodes.Peek(1) as XElement;
                    }
                }
            }

            XmlParserState ret = base.PushChar(c, context, ref rollback);

            if (ret == Parent && c == '>')
            {
                var element = context.Nodes.Peek() as XElement;
                if (element != null && !element.Name.HasPrefix && element.Name.IsValid)
                {
                    if (element.Name.Name.Equals("script", StringComparison.OrdinalIgnoreCase))
                    {
                        return(scriptState);
                    }
                    if (ElementTypes.IsEmpty(element.Name.Name))
                    {
                        element.Close(element);
                        context.Nodes.Pop();
                    }
                }
            }

            return(ret);
        }
Example #30
0
        /// <summary>
        /// Gets validation rules for property.
        /// </summary>
        /// <param name="context">Parser context.</param>
        /// <param name="property">Source property.</param>
        /// <returns>Validation rules for property.</returns>
        public static IPropertyValidationRules GetValidatorsCached(this IXmlParserContext context, IProperty property)
        {
            if (context.ValidatorsCache.TryGetValue(property, out IPropertyValidationRules result))
            {
                return(result);
            }

            IValidationRule[] validationRules = context.ParserSettings.ValidationProvider.GetValidationRules(property).ToArray();
            result = new PropertyValidationRules(property, validationRules);
            context.ValidatorsCache.TryAdd(property, result);

            return(result);
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			string key;

			switch (context.StateTag) {
			case UNKNOWN:
				context.KeywordBuilder.Append (c);
				key = context.KeywordBuilder.ToString ();
				if (!RazorSymbols.CanBeStatementOrDirective (key)) {
					context.Nodes.Push (new RazorImplicitExpression (context.LocationMinus (key.Length + 1)));
					rollback = String.Empty;
					return EnsureSetAndAdopted<RazorExpressionState> (ref expressionState);
				}
				if (key == "using")
					context.StateTag = USING;
				else if (RazorSymbols.IsDirective (key))
					context.StateTag = POSSIBLE_DIRECTIVE;
				else if (RazorSymbols.IsStatement (key))
					context.StateTag = POSSIBLE_STATEMENT;

				break;

			// Using can be either statement: @using (resource) {}, or directive: @using System.IO
			case USING:
				if (c == '(' || c == '\n')
					return SwitchToStatement (context, ref rollback);
				else if (Char.IsLetterOrDigit(c))
					return SwitchToDirective (context, ref rollback);

				context.KeywordBuilder.Append (c);
				break;

			case POSSIBLE_STATEMENT:
				if (Char.IsWhiteSpace (c) || c == '{' || c == '(')
					return SwitchToStatement(context, ref rollback);

				context.KeywordBuilder.Append (c);
				context.StateTag = UNKNOWN;
				break;

			case POSSIBLE_DIRECTIVE:
				if (Char.IsWhiteSpace (c) || c == '{')
					return SwitchToDirective (context, ref rollback);

				context.KeywordBuilder.Append (c);
				context.StateTag = UNKNOWN;
				break;
			}

			return null;
		}
Example #32
0
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1)
            {
                context.Nodes.Push(new XComment(context.LocationMinus("<!--".Length + 1)));
            }

            if (c == '-')
            {
                //make sure we know when there are two '-' chars together
                if (context.StateTag == NOMATCH)
                {
                    context.StateTag = SINGLE_DASH;
                }
                else
                {
                    context.StateTag = DOUBLE_DASH;
                }
            }
            else if (context.StateTag == DOUBLE_DASH)
            {
                if (c == '>')
                {
                    // if the '--' is followed by a '>', the state has ended
                    // so attach a node to the DOM and end the state
                    var comment = (XComment)context.Nodes.Pop();

                    if (context.BuildTree)
                    {
                        comment.End(context.Location);
                        ((XContainer)context.Nodes.Peek()).AddChildNode(comment);
                    }

                    rollback = string.Empty;
                    return(Parent);
                }
                else
                {
                    context.LogWarning("The string '--' should not appear within comments.");
                    context.StateTag = NOMATCH;
                }
            }
            else
            {
                // not any part of a '-->', so make sure matching is reset
                context.StateTag = NOMATCH;
            }

            return(null);
        }
Example #33
0
        XmlParserState SwitchToDirective(IXmlParserContext context, ref string rollback)
        {
            string key  = context.KeywordBuilder.ToString();
            string name = key.Trim();
            var    dir  = new RazorDirective(context.LocationMinus(key.Length + 2))
            {
                Name = name,
                IsSimpleDirective = RazorSymbols.IsSimpleDirective(name)
            };

            context.Nodes.Push(dir);
            rollback = String.Empty;
            return(EnsureSetAndAdopted <RazorDirectiveState> (ref directiveState));
        }
Example #34
0
        // ParseOpeningBracket and ParseClosingBracket can use simplified method of tracking brackets.
        // It's fast, and works correctly when parsing char by char, but sometimes may incorrectly determine
        // the end of a block in nested subblocks when we click inside the block from another one,
        // because the parent block isn't parsed from end to end then.
        // The simplified version is used mostly for testing. In real environment finding matching brackets
        // precisely is necessary for code completion.

        public virtual XmlParserState ParseOpeningBracket(char c, IXmlParserContext context)
        {
            var rootState = RootState as RazorRootState;

            if (!rootState.UseSimplifiedBracketTracker && !CorrespondingBlock.FirstBracket.HasValue)
            {
                CorrespondingBlock.FindFirstBracket(context.Location);
            }
            else if (rootState.UseSimplifiedBracketTracker)
            {
                bracketsBuilder.Append(c);
            }
            return(null);
        }
Example #35
0
        protected virtual void Close(XElement element, IXmlParserContext context, DocumentLocation location)
        {
            //have already checked that element is not null, i.e. top of stack is our element
            if (element.IsClosed)
            {
                context.Nodes.Pop();
            }

            element.End(location);
            if (context.BuildTree)
            {
                var parent = (XContainer)context.Nodes.Peek(element.IsClosed ? 0 : 1);
                parent.AddChildNode(element);
            }
        }
 public override XmlParserState ParseClosingBracket <T> (char c, IXmlParserContext context, XmlParserState stateToReturn)
 {
     if (base.ParseClosingBracket <T> (c, context, stateToReturn) != null)
     {
         if (RazorSymbols.CanBeContinued(CorrespondingBlock.Name))
         {
             keys             = RazorSymbols.PossibleKeywordsAfter(CorrespondingBlock.Name);
             context.StateTag = POSSIBLE_CONTINUATION;
         }
         else
         {
             return(stateToReturn);
         }
     }
     return(null);
 }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				bracketsBuilder.Clear ();
				var directive = context.Nodes.FirstOrDefault (n => n is RazorDirective);
				if (directive == null) {
					if (context.PreviousState is XmlClosingTagState && CorrespondingDirective != null)
						context.Nodes.Push (CorrespondingDirective);
					else {
						Debug.Fail ("Directive should be pushed before changing the state to DirectiveState");
						return Parent;
					}
				} else
					CorrespondingBlock = directive as RazorDirective;
			}

			if (CorrespondingDirective.IsSimpleDirective) {
				if (c == '<')
					IsInsideGenerics = true;
				else if (c == '\n') {
					StateEngineService.EndCodeFragment<RazorDirective> (context);
					return Parent.Parent;
				}
				// using directives can be placed in one line, e.g. @using foo @using bar
				else if (CorrespondingDirective.Name == "using"
						&& !(Char.IsLetterOrDigit (c) || c == ' ' || c == '=' || c == '.')) {
					rollback = String.Empty;
					StateEngineService.EndCodeFragment<RazorDirective> (context, 1);
					return Parent.Parent;
				}
				return null;

			} else {
				switch (c) {
				case '{':
					if (context.StateTag != TRANSITION)
						return ParseOpeningBracket (c, context);
					break;

				case '}':
					return ParseClosingBracket<RazorDirective> (c, context, Parent.Parent);
				}
			}

			return base.PushChar (c, context, ref rollback);
		}
        private static void ValidateProperty(
            IXmlParserContext context,
            IMutablePropertyContainer container,
            IProperty property,
            XElement propertyElement)
        {
            var validationRules = context.GetValidatorsCached(property);

            if (validationRules.Rules.Count > 0)
            {
                IEnumerable <Message> messages = container.Validate(validationRules.Rules);
                foreach (Message message in messages)
                {
                    context.Messages.Add(message.WithText(string.Concat(message.OriginalMessage, GetXmlLineInfo(propertyElement))));
                }
            }
        }
        public override XmlParserState PushChar(char c, IXmlParserContext context, ref string rollback)
        {
            System.Diagnostics.Debug.Assert(((XAttribute)context.Nodes.Peek()).Value == null);

            if (c == '<')
            {
                //the parent state should report the error
                rollback = string.Empty;
                return(Parent);
            }

            if (context.CurrentStateLength == 1)
            {
                if (c == '"')
                {
                    context.StateTag = DOUBLEQUOTE;
                    return(null);
                }
                if (c == '\'')
                {
                    context.StateTag = SINGLEQUOTE;
                    return(null);
                }
                context.StateTag = UNQUOTED;
            }

            int maskedTag = context.StateTag & TagMask;

            if (maskedTag == UNQUOTED)
            {
                return(BuildUnquotedValue(c, context, ref rollback));
            }

            if ((c == '"' && maskedTag == DOUBLEQUOTE) || c == '\'' && maskedTag == SINGLEQUOTE)
            {
                //ending the value
                var att = (XAttribute)context.Nodes.Peek();
                att.Value = context.KeywordBuilder.ToString();
                return(Parent);
            }

            context.KeywordBuilder.Append(c);
            return(null);
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1 && context.PreviousState is HtmlScriptBodyState)
				return Parent;
			
			//NOTE: This is (mostly) duplicated in HtmlClosingTagState
			//handle "paragraph" tags implicitly closed by block-level elements
			if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState) {
				var element = (XElement) context.Nodes.Peek ();

				if (!element.Name.HasPrefix && element.Name.IsValid) {
					//Note: the node stack will always be at least 1 deep due to the XDocument
					var parent = context.Nodes.Peek (1) as XElement;

					while (parent != null && parent.ValidAndNoPrefix () && parent.IsImplicitlyClosedBy (element)) {
						context.Nodes.Pop ();
						context.Nodes.Pop ();
						//parent.Region.End = element.Region.Start;
						//parent.Region.EndColumn = Math.Max (parent.Region.EndColumn - 1, 1);
						parent.Close (parent);
						context.Nodes.Push (element);

						parent = context.Nodes.Peek (1) as XElement;
					}
				}
			}
						
			XmlParserState ret = base.PushChar (c, context, ref rollback);
			
			if (ret == Parent && c == '>') {
				var element = context.Nodes.Peek () as XElement;
				if (element != null && !element.Name.HasPrefix && element.Name.IsValid) {
					if (element.Name.Name.Equals ("script", StringComparison.OrdinalIgnoreCase)) {
						return scriptState;
					}
					if (ElementTypes.IsEmpty (element.Name.Name)) {
						element.Close (element);
						context.Nodes.Pop ();
					}
				}
			}
			
			return ret;
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				context.Nodes.Push (new WebFormsServerComment (context.LocationMinus (context.CurrentStateLength + "<%--".Length)));
			}
			
			switch (context.StateTag) {
			case NOMATCH:
				if (c == '-')
					context.StateTag = SINGLE_DASH;
				break;
				
			case SINGLE_DASH:
				if (c == '-')
					context.StateTag = DOUBLE_DASH;
				else
					context.StateTag = NOMATCH;
				break;
				
			case DOUBLE_DASH:
				if (c == '%')
					context.StateTag = PERCENT;
				else
					context.StateTag = NOMATCH;
				break;
				
			case PERCENT:
				if (c == '>') {
					var comment = (WebFormsServerComment) context.Nodes.Pop ();
					comment.End (context.Location);
					if (context.BuildTree) {
						XObject ob = context.Nodes.Peek ();
						if (ob is XContainer) {
							((XContainer)ob).AddChildNode (comment);
						}
					 	//FIXME: add to other kinds of node, e.g. if used within a tag
					}
					return Parent;
				}
				break;
			}
			
			return null;
		}
		XmlParserState BuildUnquotedValue (char c, IXmlParserContext context, ref string rollback)
		{
			if (char.IsLetterOrDigit (c) || c == '_' || c == '.') {
				context.KeywordBuilder.Append (c);
				return null;
			}

			if (context.KeywordBuilder.Length == 0) {
				string fullName = ((XAttribute)context.Nodes.Peek ()).Name.FullName;
				context.LogError ("The value of attribute '" + fullName + "' ended unexpectedly.");
				rollback = string.Empty;
				return Parent;
			}

			var att = (XAttribute)context.Nodes.Peek ();
			att.Value = context.KeywordBuilder.ToString ();
			rollback = string.Empty;
			return Parent;
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			var namedObject = context.Nodes.Peek () as INamedXObject;
			if (namedObject == null || namedObject.Name.Prefix != null)
				throw new InvalidOperationException ("Invalid state");
			
			Debug.Assert (context.CurrentStateLength > 1 || char.IsLetter (c) || c == '_', 
				"First character pushed to a XmlTagNameState must be a letter.");
			Debug.Assert (context.CurrentStateLength > 1 || context.KeywordBuilder.Length == 0,
				"Keyword builder must be empty when state begins.");
			
			if (XmlChar.IsWhitespace (c) || c == '<' || c == '>' || c == '/' || c == '=') {
				rollback = string.Empty;
				if (context.KeywordBuilder.Length == 0) {
					context.LogError ("Zero-length name.");
				} else {
					string s = context.KeywordBuilder.ToString ();
					int i = s.IndexOf (':');
					if (i < 0) {
						namedObject.Name = new XName (s);
					} else {
						namedObject.Name = new XName (s.Substring (0, i), s.Substring (i + 1));
					}
				}
				
				return Parent;
			}
			if (c == ':') {
				if (context.KeywordBuilder.ToString ().IndexOf (':') > 0)
					context.LogError ("Unexpected ':' in name.");
				context.KeywordBuilder.Append (c);
				return null;
			}
			
			if (XmlChar.IsNameChar (c)) {
				context.KeywordBuilder.Append (c);
				return null;
			}
			
			rollback = string.Empty;
			context.LogError ("Unexpected character '" + c +"' in name");
			return Parent;
		}
Example #44
0
        /// <summary>
        /// Copies input <paramref name="context"/> with possible changes.
        /// </summary>
        /// <param name="context">Source parser context.</param>
        /// <param name="parserSettings">Optional parser settings.</param>
        /// <param name="schema">Optional schema.</param>
        /// <param name="messages">Optional message list.</param>
        /// <param name="parsersCache">Optional parsers cache.</param>
        /// <param name="schemaCache">Optional schemas cache.</param>
        /// <param name="validatorsCache">Optional validators cache.</param>
        /// <returns>New <see cref="IXmlParserContext"/> instance.</returns>
        public static IXmlParserContext With(
            this IXmlParserContext context,
            IXmlParserSettings?parserSettings      = null,
            Schema.IMutableObjectSchema?schema     = null,
            IMutableMessageList <Message>?messages = null,
            ConcurrentDictionary <IProperty, IValueParser>?parsersCache = null,
            ConcurrentDictionary <IProperty, ISchema>?schemaCache       = null,
            ConcurrentDictionary <IProperty, IPropertyValidationRules>?validatorsCache = null)
        {
            context.AssertArgumentNotNull(nameof(context));

            return(new XmlParserContext(
                       parserSettings: parserSettings ?? context.ParserSettings,
                       schema: schema ?? context.Schema,
                       messages: messages ?? context.Messages,
                       parsersCache: parsersCache ?? context.ParsersCache,
                       schemaCache: schemaCache ?? context.SchemaCache,
                       validatorsCache: validatorsCache ?? context.ValidatorsCache));
        }
Example #45
0
        static int LengthFromOpenBracket(IXmlParserContext context)
        {
            switch (context.StateTag)
            {
            case BRACKET:
                return(1);

            case BRACKET_EXCLAM:
                return(2);

            case COMMENT:
                return(3);

            case CDATA:
            case DOCTYPE:
                return(3 + context.KeywordBuilder.Length);

            default:
                return(1);
            }
        }
        XmlParserState SwitchToContinuationStatement(IXmlParserContext context, string key)
        {
            string name   = key.Trim();
            int    length = key.Length;

            if (name == "else if")
            {
                length = key.Length - 1;
            }
            else if (name == "else")
            {
                length = key.Length + 1;
            }
            var stm = new RazorStatement(context.LocationMinus(length))
            {
                Name = name
            };

            context.Nodes.Push(stm);
            return(EnsureSetAndAdopted <RazorStatementState> (ref statementState));
        }
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			System.Diagnostics.Debug.Assert (((XAttribute) context.Nodes.Peek ()).Value == null);

			if (c == '<') {
				//the parent state should report the error
				rollback = string.Empty;
				return Parent;
			}

			if (context.CurrentStateLength == 1) {
				if (c == '"') {
					context.StateTag = DOUBLEQUOTE;
					return null;
				}
				if (c == '\'') {
					context.StateTag = SINGLEQUOTE;
					return null;
				}
				context.StateTag = UNQUOTED;
			}

			int maskedTag = context.StateTag & TagMask;

			if (maskedTag == UNQUOTED) {
				return BuildUnquotedValue (c, context, ref rollback);
			}

			if ((c == '"' && maskedTag == DOUBLEQUOTE) || c == '\'' && maskedTag == SINGLEQUOTE) {
				//ending the value
				var att = (XAttribute) context.Nodes.Peek ();
				att.Value = context.KeywordBuilder.ToString ();
				return Parent;
			}

			context.KeywordBuilder.Append (c);
			return null;
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				bracketsBuilder.Clear ();
				var block = context.Nodes.FirstOrDefault (n => n is RazorCodeBlock);
				if (block == null) {
					var razorBlock = new RazorCodeBlock (context.LocationMinus (2));
					context.Nodes.Push (razorBlock);
					CorrespondingBlock = razorBlock;
				} else
					CorrespondingBlock = block as RazorCodeFragment;
			}

			switch (c) {
			case '{':
				return ParseOpeningBracket (c, context);

			case '}':
				return ParseClosingBracket<RazorCodeBlock> (c, context, Parent);
			}

			return base.PushChar (c, context, ref rollback);
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				context.Nodes.Push (new XComment (context.LocationMinus ("<!--".Length + 1)));
			}
			
			if (c == '-') {
				//make sure we know when there are two '-' chars together
				if (context.StateTag == NOMATCH)
					context.StateTag = SINGLE_DASH;
				else
					context.StateTag = DOUBLE_DASH;
				
			} else if (context.StateTag == DOUBLE_DASH) {
				if (c == '>') {
					// if the '--' is followed by a '>', the state has ended
					// so attach a node to the DOM and end the state
					var comment = (XComment) context.Nodes.Pop ();
					
					if (context.BuildTree) {
						comment.End (context.Location);
						((XContainer) context.Nodes.Peek ()).AddChildNode (comment);
					}
					
					rollback = string.Empty;
					return Parent;
				} else {
					context.LogWarning ("The string '--' should not appear within comments.");
					context.StateTag = NOMATCH;
				}
			} else {
				// not any part of a '-->', so make sure matching is reset
				context.StateTag = NOMATCH;
			}
			
			return null;
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (context.CurrentStateLength == 1) {
				context.Nodes.Push (new RazorComment (context.LocationMinus (2)));
				return null;
			}

			switch (context.StateTag) {
			case NOMATCH:
				if (c == '*')
					context.StateTag = STAR;
				break;

			case STAR:
				if (c == '@') {
					StateEngineService.EndCodeFragment<RazorComment> (context);
					return Parent;
				} else
					context.StateTag = NOMATCH;
				break;
			}

			return null;
		}
		void SetTag (IXmlParserContext context, AttState value)
		{
			context.StateTag = (context.StateTag & ~TagMask) | ((int)value << XmlAttributeValueState.TagShift);
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			var maskedTag = (AttState) ((context.StateTag & TagMask) >> XmlAttributeValueState.TagShift);
			switch (maskedTag) {
			case AttState.Incoming:
				if (c == '<') {
					SetTag (context, AttState.Bracket);
					return null;
				}
				return base.PushChar (c, context, ref rollback);
			case AttState.Bracket:
				if (c == '%') {
					SetTag (context, AttState.Percent);
					return null;
				}
				rollback = "<";
				return Parent;
			case AttState.Percent:
				if (c == '-') {
					SetTag (context, AttState.PercentDash);
					return null;
				}
				if (c == '@') {
					context.LogError (GettextCatalog.GetString ("Invalid directive location"));
					rollback = "<%";
					return Parent;
				}
				WebFormsExpressionState.AddExpressionNode (c, context);
				SetTag (context, AttState.Expression);
				return null;
			case AttState.PercentDash:
				if (c == '-') {
					context.Nodes.Push (new WebFormsServerComment (context.LocationMinus (4)));
					SetTag (context, AttState.Comment);
					return null;
				}
				context.LogError (GettextCatalog.GetString ("Malformed server comment"));
				rollback = "<%-";
				return Parent;
			case AttState.Expression:
				if (c == '%')
					SetTag (context, AttState.EndPercent);
				return null;
			case AttState.EndPercent:
				if (c == '>') {
					//TODO: attach nodes
					var n = context.Nodes.Pop ();
					n.End (context.Location);
					SetTag (context, AttState.Incoming);
					//ensure attribute get closed if value is unquoted
					var baseState = (context.StateTag & XmlAttributeValueState.TagMask);
					if (baseState == FREE || baseState == UNQUOTED) {
						var att = (XAttribute)context.Nodes.Peek ();
						att.Value = "";
						return Parent;
					}
					return null;
				}
				SetTag (context, AttState.Expression);
				return null;
			case AttState.Comment:
				if (c == '-')
					SetTag (context, AttState.EndDash);
				return null;
			case AttState.EndDash:
				if (c == '-')
					SetTag (context, AttState.EndDashDash);
				else
					SetTag (context, AttState.Comment);
				return null;
			case AttState.EndDashDash:
				if (c == '%')
					SetTag (context, AttState.EndDashDashPercent);
				else if (c != '-')
					SetTag (context, AttState.Comment);
				return null;
			case AttState.EndDashDashPercent:
				if (c == '>') {
					//TODO: attach nodes
					var n = context.Nodes.Pop ();
					n.End (context.Location);
					SetTag (context, AttState.Incoming);
					return null;
				}
				SetTag (context, AttState.Comment);
				return null;
			default:
				return base.PushChar (c, context, ref rollback);
			}
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			var att = context.Nodes.Peek () as XAttribute;

			//state has just been entered
			if (context.CurrentStateLength == 1)  {
				if (context.PreviousState is XmlNameState) {
					//error parsing name
					if (!att.IsNamed) {
						context.Nodes.Pop ();
						rollback = string.Empty;
						return Parent;
					}
					context.StateTag = GETTINGEQ;
				}
				else if (context.PreviousState is XmlAttributeValueState) {
					//Got value, so end attribute
					context.Nodes.Pop ();
					att.End (context.LocationMinus (1));
					IAttributedXObject element = (IAttributedXObject) context.Nodes.Peek ();
					element.Attributes.AddAttribute (att);
					rollback = string.Empty;
					return Parent;
				}
				else {
					//starting a new attribute
					Debug.Assert (att == null);
					Debug.Assert (context.StateTag == NAMING);
					att = new XAttribute (context.LocationMinus (1));
					context.Nodes.Push (att);
					rollback = string.Empty;
					return XmlNameState;
				}
			}

			if (context.StateTag == GETTINGEQ) {
				if (char.IsWhiteSpace (c)) {
					return null;
				}
				if (c == '=') {
					context.StateTag = GETTINGVAL;
					return null;
				}
				context.LogError ("Expecting = in attribute, got '" + c + "'.");
			} else if (context.StateTag == GETTINGVAL) {
				if (char.IsWhiteSpace (c)) {
					return null;
				}
				rollback = string.Empty;
				return AttributeValueState;
			} else if (c != '<') {
				//parent handles message for '<'
				context.LogError ("Unexpected character '" + c + "' in attribute.");
			}

			if (att != null)
				context.Nodes.Pop ();
			
			rollback = string.Empty;
			return Parent;
		}
Example #54
0
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (c == '<') {
				if (context.StateTag != FREE)
					context.LogError ("Incomplete tag opening; encountered unexpected '<'.",
						new DomRegion (
							context.LocationMinus (LengthFromOpenBracket (context) + 1),
							context.LocationMinus (1)));
				context.StateTag = BRACKET;
				return null;
			}
			
			switch (context.StateTag) {
			case FREE:
				//FIXME: handle entities?
				return null;
				
			case BRACKET:
				if (c == '?') {
					rollback = string.Empty;
					return this.ProcessingInstructionState;
				} else if (c == '!') {
					context.StateTag = BRACKET_EXCLAM;
					return null;
				} else if (c == '/') {
					return this.ClosingTagState;
				} else if (char.IsLetter (c) || c == '_') {
					rollback = string.Empty;
					return TagState;
				}
				break;
				
			case BRACKET_EXCLAM:
				if (c == '[') {
					context.StateTag = CDATA;
					return null;
				} else if (c == '-') {
					context.StateTag = COMMENT;
					return null;
				} else if (c == 'D') {
					context.StateTag = DOCTYPE;
					return null;
				}
				break;
			
			case COMMENT:
				if (c == '-')
					return CommentState;
				break;
				
			case CDATA:
				string cdataStr = "CDATA[";
				if (c == cdataStr [context.KeywordBuilder.Length]) {
					context.KeywordBuilder.Append (c);
					if (context.KeywordBuilder.Length < cdataStr.Length)
						return null;
					return CDataState;
				}
				context.KeywordBuilder.Length = 0;
				break;
				
			case DOCTYPE:
				string docTypeStr = "OCTYPE";
				if (c == docTypeStr [context.KeywordBuilder.Length]) {
					context.KeywordBuilder.Append (c);
					if (context.KeywordBuilder.Length < docTypeStr.Length)
						return null;
					return DocTypeState;
				} else {
					context.KeywordBuilder.Length = 0;
				}
				break;
			}
			
			context.LogError ("Incomplete tag opening; encountered unexpected character '" + c + "'.",
				new DomRegion (
					context.LocationMinus (LengthFromOpenBracket (context)),
					context.Location));
			
			context.StateTag = FREE;
			return null;
		}
Example #55
0
		static int LengthFromOpenBracket (IXmlParserContext context)
		{
			switch (context.StateTag) {
			case BRACKET:
				return 1;
			case BRACKET_EXCLAM:
				return 2;
			case COMMENT:
				return 3;
			case CDATA:
			case DOCTYPE:
				return 3 + context.KeywordBuilder.Length;
			default:
				return 1;
			}
		}
		/// <summary>
		/// When the <see cref="Parser"/> advances by one character, it calls this method 
		/// on the currently active <see cref="XmlParserState"/> to determine the next state.
		/// </summary>
		/// <param name="c">The current character.</param>
		/// <param name = "context">The parser context.</param>
		/// <param name="rollback"> If set non-null, the parser will be rolled back that number 
		/// of characters (empty string means replay current char to the next state.
		/// Note that this will not change the DOM state.</param>
		/// <returns>
		/// The next state. A new or parent <see cref="XmlParserState"/> will change the parser state; 
		/// the current state or null will not.
		/// </returns>
		public abstract XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback);
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			if (c == '%' && context.StateTag == BRACKET) {
				context.StateTag = BRACKET_PERCENT;
				return null;
			}
			else if (context.StateTag == BRACKET_PERCENT) {
				switch (c) {
				case '@': //DIRECTIVE <%@
					return DirectiveState;
				
				case '-': // SERVER COMMENT: <%--
					return ServerCommentState;
				
				case '=': //RENDER EXPRESSION <%=
				case '#': //DATABINDING EXPRESSION <%#
				case '$': //RESOURCE EXPRESSION <%$
				default:  // RENDER BLOCK
					rollback = "";
					return ExpressionState;
				}
			}
			
			return base.PushChar (c, context, ref rollback);
			
		}
Example #58
0
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			XElement element = context.Nodes.Peek () as XElement;
			
			if (element == null || element.IsComplete) {
				element = new XElement (context.LocationMinus (2)); // 2 == < + current char
				context.Nodes.Push (element);
			}
			
			if (c == '<') {
				if (element.IsNamed) {
					context.LogError ("Unexpected '<' in tag '" + element.Name.FullName + "'.");
					Close (element, context, context.LocationMinus (1));
				} else {
					context.LogError ("Unexpected '<' in unnamed tag.");
				}
				
				rollback = string.Empty;
				return Parent;
			}
			
			Debug.Assert (!element.IsComplete);
			
			if (element.IsClosed && c != '>') {
				if (char.IsWhiteSpace (c)) {
					context.LogWarning ("Unexpected whitespace after '/' in self-closing tag.");
					return null;
				}
				context.LogError ("Unexpected character '" + c + "' after '/' in self-closing tag.");
				context.Nodes.Pop ();
				return Parent;
			}
			
			//if tag closed
			if (c == '>') {
				if (context.StateTag == MAYBE_SELF_CLOSING) {
					element.Close (element);
				}
				if (!element.IsNamed) {
					context.LogError ("Tag closed prematurely.");
				} else {
					Close (element, context, context.Location);
				}
				return Parent;
			}

			if (c == '/') {
				context.StateTag = MAYBE_SELF_CLOSING;
				return null;
			}

			if (context.StateTag == ATTEMPT_RECOVERY) {
				if (XmlChar.IsWhitespace (c)) {
					context.StateTag = RECOVERY_FOUND_WHITESPACE;
				}
				return null;
			}

			if (context.StateTag == RECOVERY_FOUND_WHITESPACE) {
				if (!XmlChar.IsFirstNameChar (c))
					return null;
			}

			context.StateTag = OK;

			if (!element.IsNamed && XmlChar.IsFirstNameChar (c)) {
				rollback = string.Empty;
				return NameState;
			}

			if (context.CurrentStateLength > 1 && XmlChar.IsFirstNameChar (c)) {
				rollback = string.Empty;
				return AttributeState;
			}
			
			if (XmlChar.IsWhitespace (c))
				return null;

			context.LogError ("Unexpected character '" + c + "' in tag.", context.LocationMinus (1));
			context.StateTag = ATTEMPT_RECOVERY;
			return null;
		}
Example #59
0
		protected virtual void Close (XElement element, IXmlParserContext context, TextLocation location)
		{
			//have already checked that element is not null, i.e. top of stack is our element
			if (element.IsClosed)
				context.Nodes.Pop ();

			element.End (location);
			if (context.BuildTree) {
				XContainer container = element.IsClosed? 
					  (XContainer) context.Nodes.Peek ()
					: (XContainer) context.Nodes.Peek (1);
										
				container.AddChildNode (element);
			}
		}
		public override XmlParserState PushChar (char c, IXmlParserContext context, ref string rollback)
		{
			var doc = context.Nodes.Peek () as XDocType;
			if (doc == null) {
				doc = new XDocType (context.LocationMinus ("<!DOCTYPE".Length + 1));
				context.Nodes.Push (doc);
			}
			
			if (!doc.RootElement.IsValid) {
				if (XmlChar.IsWhitespace (c))
					return null;
				else if (XmlChar.IsFirstNameChar (c)) {
					rollback = "";
					return nameState;
				}
			}
			else if (doc.PublicFpi == null) {
				if (context.StateTag == 0) {
					if (c == 's' || c == 'S') {
						context.StateTag = 1;
						return null;
					} else if (c == 'p' || c == 'P') {
						context.StateTag = -1;
						return null;
					} if (XmlChar.IsWhitespace (c)) {
						return null;
					}
				} else if (Math.Abs (context.StateTag) < 6) {
					if (context.StateTag > 0) {
						if ("YSTEM"[context.StateTag - 1] == c || "ystem"[context.StateTag - 1] == c) {
							context.StateTag++;
							if (context.StateTag == 6) {
								context.StateTag = 0;
								doc.PublicFpi = "";
							}
							return null;
						}
					} else {
						int absState = Math.Abs (context.StateTag) - 1;
						if ("UBLIC"[absState] == c || "ublic"[absState] == c) {
							context.StateTag--;
							return null;
						}
					}
				} else {
					if (context.KeywordBuilder.Length == 0) {
						if (XmlChar.IsWhitespace (c))
							return null;
						else if (c == '"') {
							context.KeywordBuilder.Append (c);
							return null;
						}
					} else {
						if (c == '"') {
							context.KeywordBuilder.Remove (0,1);
							doc.PublicFpi = context.KeywordBuilder.ToString ();
							context.KeywordBuilder.Length = 0;
							context.StateTag = 0;
						} else {
							context.KeywordBuilder.Append (c);
						}
						return null;
					}
				}
			}
			else if (doc.Uri == null) {
				if (context.KeywordBuilder.Length == 0) {
					if (XmlChar.IsWhitespace (c))
						return null;
					else if (c == '"') {
						context.KeywordBuilder.Append (c);
						return null;
					}
				} else {
					if (c == '"') {
						context.KeywordBuilder.Remove (0,1);
						doc.Uri = context.KeywordBuilder.ToString ();
						context.KeywordBuilder.Length = 0;
					} else {
						context.KeywordBuilder.Append (c);
					}
					return null;
				}
			}
			else if (doc.InternalDeclarationRegion.EndLine <= 0) {
				if (XmlChar.IsWhitespace (c))
						return null;
				switch (context.StateTag) {
				case 0:
					if (c == '[') {
						doc.InternalDeclarationRegion = new DocumentRegion (context.Location, DocumentLocation.Empty);
						context.StateTag = 1;
						return null;
					}
					break;
				case 1:
					if (c == '<') {
						context.StateTag = 2;
						return null;
					} else if (c == ']') {
						context.StateTag = 0;
						doc.InternalDeclarationRegion = new DocumentRegion (doc.InternalDeclarationRegion.Begin, context.Location);
						return null;
					}
					break;
				case 2:
					if (c == '>') {
						context.StateTag = 1;
					}
					return null;
				default:
					throw new InvalidOperationException ();
				}
			}
			
			doc = (XDocType)context.Nodes.Pop ();
			if (c == '<') {
				rollback = string.Empty;
				context.LogError ("Doctype ended prematurely.");
			} else if (c != '>') {
				context.LogError ("Unexpected character '" + c +"' in doctype.");
			}
			
			if (context.BuildTree) {
				doc.End (context.Location);
				((XContainer) context.Nodes.Peek ()).AddChildNode (doc); 
			}
			return Parent;
		}