/// <summary>
        /// Processes the HTML element that represents a new object.
        /// </summary>
        private ResolvedControl ProcessObjectElement(DothtmlElementNode element, DataContextStack dataContext)
        {
            object[] constructorParameters;

            var controlMetadata = controlResolver.ResolveControl(element.TagPrefix, element.TagName, out constructorParameters);
            var control         = new ResolvedControl(controlMetadata, element, dataContext)
            {
                ContructorParameters = constructorParameters
            };

            var dataContextAttribute = element.Attributes.FirstOrDefault(a => a.AttributeName == "DataContext");

            if (dataContextAttribute != null)
            {
                ProcessAttribute(dataContextAttribute, control, dataContext);
            }
            if (control.Properties.ContainsKey(DotvvmBindableObject.DataContextProperty) && control.Properties[DotvvmBindableObject.DataContextProperty] is ResolvedPropertyBinding)
            {
                dataContext = new DataContextStack(
                    ((ResolvedPropertyBinding)control.Properties[DotvvmBindableObject.DataContextProperty]).Binding.GetExpression().Type,
                    dataContext);
                control.DataContextTypeStack = dataContext;
            }
            if (controlMetadata.DataContextConstraint != null && !controlMetadata.DataContextConstraint.IsAssignableFrom(dataContext.DataContextType))
            {
                throw new DotvvmCompilationException($"The control '{controlMetadata.Name}' requires a DataContext of type '{controlMetadata.DataContextConstraint.FullName}'!", element.Tokens);
            }

            // set properties from attributes
            foreach (var attribute in element.Attributes.Where(a => a.AttributeName != "DataContext"))
            {
                ProcessAttribute(attribute, control, dataContext);
            }

            var typeChange = DataContextChangeAttribute.GetDataContextExpression(dataContext, control);

            if (typeChange != null)
            {
                dataContext = new DataContextStack(typeChange, dataContext);
            }

            ProcessControlContent(element.Content, control);

            // check required properties
            var missingProperties = control.Metadata.Properties.Values.Where(p => p.MarkupOptions.Required && !control.Properties.ContainsKey(p));

            if (missingProperties.Any())
            {
                throw new DotvvmCompilationException($"The control '{ control.Metadata.Name }' is missing required properties: { string.Join(", ", missingProperties.Select(p => "'" + p.Name + "'")) }.", control.DothtmlNode.Tokens);
            }
            return(control);
        }
        /// <summary>
        /// Processes the element which contains property value.
        /// </summary>
        private ResolvedPropertySetter ProcessElementProperty(ResolvedControl control, DotvvmProperty property, IEnumerable <DothtmlNode> elementContent)
        {
            var dataContext = control.DataContextTypeStack;
            var typeChange  = DataContextChangeAttribute.GetDataContextExpression(dataContext, control, property);

            if (typeChange != null)
            {
                dataContext = new DataContextStack(typeChange, dataContext);
            }
            // the element is a property
            if (IsTemplateProperty(property))
            {
                // template
                return(new ResolvedPropertyTemplate(property, ProcessTemplate(elementContent, dataContext)));
            }
            else if (IsCollectionProperty(property))
            {
                // collection of elements
                var collection = FilterNodes <DothtmlElementNode>(elementContent, property)
                                 .Select(childObject => ProcessObjectElement(childObject, dataContext));
                return(new ResolvedPropertyControlCollection(property, collection.ToList()));
            }
            else if (property.PropertyType == typeof(string))
            {
                // string property
                var strings = FilterNodes <DothtmlLiteralNode>(elementContent, property);
                var value   = string.Concat(strings.Select(s => s.Value));
                return(new ResolvedPropertyValue(property, value));
            }
            else if (IsControlProperty(property))
            {
                // new object
                var children = FilterNodes <DothtmlElementNode>(elementContent, property).ToList();
                if (children.Count > 1)
                {
                    throw new DotvvmCompilationException($"The property '{property.MarkupOptions.Name}' can have only one child element!");
                }
                else if (children.Count == 1)
                {
                    return(new ResolvedPropertyControl(property, ProcessObjectElement(children[0], dataContext)));
                }
                else
                {
                    return(new ResolvedPropertyControl(property, null));
                }
            }
            else
            {
                throw new DotvvmCompilationException($"The property '{property.FullName}' is not supported!");
            }
        }
        /// <summary>
        /// Processes the HTML attribute.
        /// </summary>
        private void ProcessAttribute(DothtmlAttributeNode attribute, ResolvedControl control, DataContextStack dataContext)
        {
            if (attribute.AttributePrefix == "html")
            {
                if (!control.Metadata.HasHtmlAttributesCollection)
                {
                    throw new DotvvmCompilationException($"control { control.Metadata.Name } does not have html attribute collection", attribute.Tokens);
                }
                control.SetHtmlAttribute(attribute.AttributeName, ProcessAttributeValue(attribute.ValueNode, dataContext));
                return;
            }

            if (!string.IsNullOrEmpty(attribute.AttributePrefix))
            {
                throw new DotvvmCompilationException("Attributes with XML namespaces are not supported!", attribute.Tokens);
            }

            // find the property
            var property = FindProperty(control.Metadata, attribute.AttributeName);

            if (property != null)
            {
                if (property.IsBindingProperty)
                {
                    var typeChange = DataContextChangeAttribute.GetDataContextExpression(dataContext, control, property);
                    if (typeChange != null)
                    {
                        dataContext = new DataContextStack(typeChange, dataContext);
                    }
                }

                if (!property.MarkupOptions.MappingMode.HasFlag(MappingMode.Attribute))
                {
                    throw new DotvvmCompilationException($"The property '{ property.FullName }' cannot be used as attribute", attribute.Tokens);
                }

                // set the property
                if (attribute.ValueNode == null)
                {
                    throw new DotvvmCompilationException($"The attribute '{property.Name}' on the control '{control.Metadata.Name}' must have a value!", attribute.Tokens);
                }
                else if (attribute.ValueNode is DothtmlValueBindingNode)
                {
                    // binding
                    var bindingNode = (attribute.ValueNode as DothtmlValueBindingNode).BindingNode;
                    if (!property.MarkupOptions.AllowBinding)
                    {
                        throw new DotvvmCompilationException($"The property '{ property.FullName }' cannot contain binding.", bindingNode.Tokens);
                    }
                    var resolvedBinding = ProcessBinding(bindingNode, dataContext);
                    control.SetProperty(new ResolvedPropertyBinding(property, resolvedBinding));
                }
                else
                {
                    // hard-coded value in markup
                    if (!property.MarkupOptions.AllowHardCodedValue)
                    {
                        throw new DotvvmCompilationException($"The property '{ property.FullName }' cannot contain hard coded value.", attribute.ValueNode.Tokens);
                    }

                    var textValue = attribute.ValueNode as DothtmlValueTextNode;

                    var value = ReflectionUtils.ConvertValue(textValue.Text, property.PropertyType);
                    control.SetPropertyValue(property, value);
                }
            }
            else if (control.Metadata.HasHtmlAttributesCollection)
            {
                // if the property is not found, add it as an HTML attribute
                control.SetHtmlAttribute(attribute.AttributeName, ProcessAttributeValue(attribute.ValueNode, dataContext));
            }
            else
            {
                throw new DotvvmCompilationException($"The control '{control.Metadata.Type}' does not have a property '{attribute.AttributeName}' and does not allow HTML attributes!");
            }
        }