示例#1
0
        public void TestMultipleAttenuation()
        {
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            KeyPair root = new KeyPair(rng);

            SymbolTable  symbols           = Biscuit.Token.Biscuit.DefaultSymbolTable();
            BlockBuilder authority_builder = new BlockBuilder(0, symbols);
            DateTime     date = DateTime.Now;

            authority_builder.AddFact(Utils.Fact("revocation_id", Arrays.AsList(Utils.Date(date))));

            Biscuit.Token.Biscuit biscuit = Biscuit.Token.Biscuit.Make(rng, root, Biscuit.Token.Biscuit.DefaultSymbolTable(), authority_builder.Build()).Right;

            BlockBuilder builder = biscuit.CreateBlock();

            builder.AddFact(Utils.Fact(
                                "right",
                                Arrays.AsList(Utils.Symbol("topic"), Utils.Symbol("tenant"), Utils.Symbol("namespace"), Utils.Symbol("topic"), Utils.Symbol("produce"))
                                ));

            string attenuatedB64 = biscuit.Attenuate(rng, new KeyPair(rng), builder.Build()).Right.SerializeBase64().Right;

            Console.WriteLine("attenuated: " + attenuatedB64);

            var attenuatedB64Biscuit = Biscuit.Token.Biscuit.FromBase64(attenuatedB64);

            Assert.IsTrue(attenuatedB64Biscuit.IsRight);

            string attenuated2B64 = biscuit.Attenuate(rng, new KeyPair(rng), builder.Build()).Right.SerializeBase64().Right;

            Console.WriteLine("attenuated2: " + attenuated2B64);
            var attenuated2B64Biscuit = Biscuit.Token.Biscuit.FromBase64(attenuated2B64);

            Assert.IsTrue(attenuated2B64Biscuit.IsRight);
        }
示例#2
0
        protected internal virtual GeneratorResults GenerateCodeCore(
            ITextDocument input,
            string className,
            string rootNamespace,
            string sourceFileName,
            string checksum,
            CancellationToken?cancelToken)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }

            try
            {
                className     = (className ?? Host.DefaultClassName) ?? DefaultClassName;
                rootNamespace = (rootNamespace ?? Host.DefaultNamespace) ?? DefaultNamespace;

                // Run the parser
                var parser = CreateParser(sourceFileName);
                Debug.Assert(parser != null);
                var results = parser.Parse(input);

                // Generate code
                var chunkGenerator = CreateChunkGenerator(className, rootNamespace, sourceFileName);
                chunkGenerator.DesignTimeMode = Host.DesignTimeMode;
                chunkGenerator.Visit(results);

                var codeGeneratorContext = new CodeGeneratorContext(chunkGenerator.Context, results.ErrorSink);
                codeGeneratorContext.Checksum = checksum;
                var codeGenerator       = CreateCodeGenerator(codeGeneratorContext);
                var codeGeneratorResult = codeGenerator.Generate();

                // Collect results and return
                return(new GeneratorResults(results, codeGeneratorResult, codeGeneratorContext.ChunkTreeBuilder.Root));
            }
            // During runtime we want code generation explosions to flow up into the calling code. At design time
            // we want to capture these exceptions to prevent IDEs from crashing.
            catch (Exception ex) when(Host.DesignTimeMode)
            {
                var errorSink = new ErrorSink();

                errorSink.OnError(
                    SourceLocation.Undefined,
                    RazorResources.FormatFatalException(sourceFileName, Environment.NewLine, ex.Message),
                    length: -1);
                var emptyBlock = new BlockBuilder();

                emptyBlock.Type = default(BlockType);

                return(new GeneratorResults(
                           document: emptyBlock.Build(),
                           tagHelperDescriptors: Enumerable.Empty <TagHelperDescriptor>(),
                           errorSink: errorSink,
                           codeGeneratorResult: new CodeGeneratorResult(
                               code: string.Empty,
                               designTimeLineMappings: new List <LineMapping>()),
                           chunkTree: new ChunkTree()));
            }
        }
示例#3
0
        public RazorSyntaxTree Execute(RazorCodeDocument document, RazorSyntaxTree syntaxTree)
        {
            var trees = GetImportedSyntaxTrees(document);

            if (trees.Count == 0)
            {
                return(syntaxTree);
            }

            var errors       = new List <RazorError>(syntaxTree.Diagnostics);
            var blockBuilder = new BlockBuilder(syntaxTree.Root);

            for (var i = 0; i < trees.Count; i++)
            {
                var tree = trees[i];

                blockBuilder.Children.Insert(i, tree.Root);

                errors.AddRange(tree.Diagnostics);
                foreach (var error in tree.Diagnostics)
                {
                    document.ErrorSink.OnError(error);
                }
            }

            return(RazorSyntaxTree.Create(blockBuilder.Build(), errors));
        }
        public override void VisitBlock(Block block)
        {
            if (CanRewrite(block))
            {
                SyntaxTreeNode newNode = RewriteBlock(_blocks.Peek(), block);
                block = newNode as Block;
                if (block == null)
                {
                    _blocks.Peek().Children.Add(newNode);
                    return;
                }
            }

            BlockBuilder builder = new BlockBuilder(block);

            builder.Children.Clear();
            _blocks.Push(builder);
            base.VisitBlock(block);
            Debug.Assert(ReferenceEquals(builder, _blocks.Peek()));

            if (_blocks.Count > 1)
            {
                _blocks.Pop();
                _blocks.Peek().Children.Add(builder.Build());
            }
        }
示例#5
0
        public void AddSpanAddsSpanToCurrentBlockBuilder()
        {
            // Arrange
            var factory = SpanFactory.CreateCsHtml();
            Mock <ParserVisitor> mockListener = new Mock <ParserVisitor>();
            var context = SetupTestContext("phoo");

            var builder = new SpanBuilder()
            {
                Kind = SpanKind.Code
            };

            builder.Accept(new CSharpSymbol(1, 0, 1, "foo", CSharpSymbolType.Identifier));
            var added = builder.Build();

            using (context.StartBlock(BlockType.Functions))
            {
                context.AddSpan(added);
            }

            var expected = new BlockBuilder()
            {
                Type = BlockType.Functions,
            };

            expected.Children.Add(added);

            // Assert
            ParserTestBase.EvaluateResults(context.CompleteParse(), expected.Build());
        }
示例#6
0
        public void TestGetRevocationIds()
        {
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            KeyPair root = new KeyPair(rng);

            SymbolTable  symbols           = Biscuit.Token.Biscuit.DefaultSymbolTable();
            BlockBuilder authority_builder = new BlockBuilder(0, symbols);

            Guid uuid1 = Guid.Parse("0b6d033d-83da-437f-a078-1a44890018bc");

            authority_builder.AddFact(Utils.Fact("revocation_id", Arrays.AsList(Utils.Strings(uuid1.ToString()))));

            Biscuit.Token.Biscuit biscuit = Biscuit.Token.Biscuit.Make(rng, root, Biscuit.Token.Biscuit.DefaultSymbolTable(), authority_builder.Build()).Right;

            BlockBuilder builder = biscuit.CreateBlock();

            builder.AddFact(Utils.Fact(
                                "right",
                                Arrays.AsList(Utils.Symbol("topic"), Utils.Symbol("tenant"), Utils.Symbol("namespace"), Utils.Symbol("topic"), Utils.Symbol("produce"))
                                ));
            Guid uuid2 = Guid.Parse("46a103de-ee65-4d04-936b-9111eac7dd3b");

            builder.AddFact(Utils.Fact("revocation_id", Arrays.AsList(Utils.Strings(uuid2.ToString()))));

            string attenuatedB64 = biscuit.Attenuate(rng, new KeyPair(rng), builder.Build()).Right.SerializeBase64().Right;

            Biscuit.Token.Biscuit b = Biscuit.Token.Biscuit.FromBase64(attenuatedB64).Right;

            Verifier    v1         = b.Verify(root.ToPublicKey()).Right;
            List <Guid> revokedIds = v1.GetRevocationIdentifiers().Right.Select(s => Guid.Parse(s)).ToList();

            Assert.IsTrue(revokedIds.Contains(uuid1));
            Assert.IsTrue(revokedIds.Contains(uuid2));
        }
示例#7
0
        public override void VisitBlock(Block block)
        {
            if (CanRewrite(block))
            {
                var newNode = RewriteBlock(_blocks.Peek(), block);
                if (newNode != null)
                {
                    _blocks.Peek().Children.Add(newNode);
                }
            }
            else
            {
                // Not rewritable.
                var builder = new BlockBuilder(block);
                builder.Children.Clear();
                _blocks.Push(builder);
                base.VisitBlock(block);
                Debug.Assert(ReferenceEquals(builder, _blocks.Peek()));

                if (_blocks.Count > 1)
                {
                    _blocks.Pop();
                    _blocks.Peek().Children.Add(builder.Build());
                }
            }
        }
        private static Block ConvertToMarkupAttributeBlock(
            Block block,
            Func <Block, Span, Span> createMarkupAttribute)
        {
            var blockBuilder = new BlockBuilder
            {
                ChunkGenerator = block.ChunkGenerator,
                Type           = block.Type
            };

            foreach (var child in block.Children)
            {
                SyntaxTreeNode markupAttributeChild;

                if (child.IsBlock)
                {
                    markupAttributeChild = ConvertToMarkupAttributeBlock((Block)child, createMarkupAttribute);
                }
                else
                {
                    markupAttributeChild = createMarkupAttribute(block, (Span)child);
                }

                blockBuilder.Children.Add(markupAttributeChild);
            }

            return(blockBuilder.Build());
        }
示例#9
0
        private static Block ConvertToMarkupAttributeBlock(Block block, bool isBoundNonStringAttribute)
        {
            var blockBuilder = new BlockBuilder
            {
                ChunkGenerator = block.ChunkGenerator,
                Type           = block.Type
            };

            foreach (var child in block.Children)
            {
                SyntaxTreeNode markupAttributeChild;

                if (child.IsBlock)
                {
                    markupAttributeChild = ConvertToMarkupAttributeBlock((Block)child, isBoundNonStringAttribute);
                }
                else
                {
                    var spanBuilder = new SpanBuilder((Span)child);
                    markupAttributeChild = CreateMarkupAttribute(spanBuilder, isBoundNonStringAttribute);
                }

                blockBuilder.Children.Add(markupAttributeChild);
            }

            return(blockBuilder.Build());
        }
示例#10
0
        //public override void VisitBlock(Block block)
        //{
        //    BlockBuilder parent = null;
        //    if (_blocks.Count > 0)
        //    {
        //        parent = _blocks.Peek();
        //    }
        //    BlockBuilder newBlock = new BlockBuilder(block);
        //    newBlock.Children.Clear();
        //    _blocks.Push(newBlock);
        //    if (block.Type == BlockType.Expression && parent != null)
        //    {
        //        VisitExpressionBlock(block, parent);
        //    }
        //    else
        //    {
        //        base.VisitBlock(block);
        //    }
        //    if (_blocks.Count > 1)
        //    {
        //        parent.Children.Add(_blocks.Pop().Build());
        //    }
        //}

        //public override void VisitSpan(Span span)
        //{
        //    Debug.Assert(_blocks.Count > 0);
        //    _blocks.Peek().Children.Add(span);
        //}

        protected override SyntaxTreeNode RewriteBlock(BlockBuilder parent, Block block)
        {
            BlockBuilder newBlock = new BlockBuilder(block);

            newBlock.Children.Clear();
            Span ws = block.Children.FirstOrDefault() as Span;
            IEnumerable <SyntaxTreeNode> newNodes = block.Children;

            if (ws.Content.All(Char.IsWhiteSpace))
            {
                // Add this node to the parent
                SpanBuilder builder = new SpanBuilder(ws);
                builder.ClearSymbols();
                FillSpan(builder, ws.Start, ws.Content);
                parent.Children.Add(builder.Build());

                // Remove the old whitespace node
                newNodes = block.Children.Skip(1);
            }

            foreach (SyntaxTreeNode node in newNodes)
            {
                newBlock.Children.Add(node);
            }
            return(newBlock.Build());
        }
示例#11
0
        public void Rewrite(RewritingContext context)
        {
            RewriteTags(context.SyntaxTree);

            ValidateRewrittenSyntaxTree(context);

            context.SyntaxTree = _currentBlock.Build();
        }
示例#12
0
        public static Block BuildEmptyBlock()
        {
            var builder = new BlockBuilder();

            builder.Name = "Test";
            builder.Type = BlockType.Comment;

            return(builder.Build());
        }
示例#13
0
        private static KeyValuePair <string, SyntaxTreeNode> ParseBlock(Block block)
        {
            // TODO: Accept more than just spans: https://github.com/aspnet/Razor/issues/96.
            // The first child will only ever NOT be a Span if a user is doing something like:
            // <input @checked />

            var childSpan = block.Children.First() as Span;

            if (childSpan == null)
            {
                throw new InvalidOperationException(RazorResources.TagHelpers_CannotHaveCSharpInTagDeclaration);
            }

            var builder = new BlockBuilder(block);

            // If there's only 1 child it means that it's plain text inside of the attribute.
            // i.e. <div class="plain text in attribute">
            if (builder.Children.Count == 1)
            {
                return(ParseSpan(childSpan));
            }

            var textSymbol = childSpan.Symbols.FirstHtmlSymbolAs(HtmlSymbolType.Text);
            var name       = textSymbol != null ? textSymbol.Content : null;

            if (name == null)
            {
                throw new InvalidOperationException(RazorResources.TagHelpers_AttributesMustHaveAName);
            }

            // Remove first child i.e. foo="
            builder.Children.RemoveAt(0);

            // Grabbing last child to check if the attribute value is quoted.
            var endNode = block.Children.Last();

            if (!endNode.IsBlock)
            {
                var endSpan   = (Span)endNode;
                var endSymbol = (HtmlSymbol)endSpan.Symbols.Last();

                // Checking to see if it's a quoted attribute, if so we should remove end quote
                if (IsQuote(endSymbol))
                {
                    builder.Children.RemoveAt(builder.Children.Count - 1);
                }
            }

            // We need to rebuild the code generators of the builder and its children (this is needed to
            // ensure we don't do special attribute code generation since this is a tag helper).
            block = RebuildCodeGenerators(builder.Build());

            return(new KeyValuePair <string, SyntaxTreeNode>(name, block));
        }
示例#14
0
        public void ConstructorWithBlockBuilderSetsParent()
        {
            // Arrange
            var builder = new BlockBuilder() { Type = BlockType.Comment };
            var span = new SpanBuilder() { Kind = SpanKind.Code }.Build();
            builder.Children.Add(span);

            // Act
            var block = builder.Build();

            // Assert
            Assert.Same(block, span.Parent);
        }
示例#15
0
        public static Block BuildWithChildren(params SyntaxTreeNode[] children)
        {
            var builder = new BlockBuilder();

            builder.Name = "Test";
            builder.Type = BlockType.Comment;

            foreach (var item in children)
            {
                builder.Children.Add(item);
            }

            return(builder.Build());
        }
示例#16
0
        public void ConstructorCopiesBasicValuesFromBlockBuilder()
        {
            // Arrange
            BlockBuilder builder = new BlockBuilder()
            {
                Name = "Foo", Type = BlockType.Helper
            };

            // Act
            Block actual = builder.Build();

            // Assert
            Assert.Equal("Foo", actual.Name);
            Assert.Equal(BlockType.Helper, actual.Type);
        }
示例#17
0
        protected override SyntaxTreeNode RewriteBlock(BlockBuilder parent, Block block)
        {
            var b     = new BlockBuilder(block);
            var abGen = block.CodeGenerator as AttributeBlockCodeGenerator;

            if (abGen != null)
            {
                b.CodeGenerator = new PreprocessedAttributeBlockCodeGenerator(abGen);
            }
            else
            {
                b.CodeGenerator = new PreprocessedDynamicAttributeBlockCodeGenerator((DynamicAttributeBlockCodeGenerator)b.CodeGenerator);
            }
            return(b.Build());
        }
示例#18
0
        public void TestEmptyVerifier()
        {
            byte[] seed = { 0, 0, 0, 0 };
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(seed);

            Console.WriteLine("preparing the authority block");

            KeyPair root = new KeyPair(rng);

            Biscuit.Token.Builder.BiscuitBuilder builder = Biscuit.Token.Biscuit.Builder(rng, root);

            builder.AddRight("/folder1/file1", "read");
            builder.AddRight("/folder1/file1", "write");
            builder.AddRight("/folder1/file2", "read");
            builder.AddRight("/folder1/file2", "write");
            builder.AddRight("/folder2/file3", "read");

            Console.WriteLine(builder.Build());
            Biscuit.Token.Biscuit b = builder.Build().Right;

            Console.WriteLine(b.Print());

            BlockBuilder block2 = b.CreateBlock();

            block2.ResourcePrefix("/folder1/");
            block2.CheckRight("read");

            KeyPair keypair2 = new KeyPair(rng);

            Biscuit.Token.Biscuit b2 = b.Attenuate(rng, keypair2, block2.Build()).Right;

            Verifier v1 = new Verifier();

            v1.Allow();

            Either <Error, long> res = v1.Verify();

            Assert.IsTrue(res.IsRight);

            v1.AddToken(b2, Option.Some(root.ToPublicKey())).Get();

            v1.AddResource("/folder2/file1");
            v1.AddOperation("write");

            res = v1.Verify();

            Assert.IsTrue(res.IsLeft);
        }
示例#19
0
        public Block Block(BlockType type, string name = null, params SyntaxTreeNode[] children)
        {
            _last = null;

            var builder = new BlockBuilder();

            builder.Type = type;
            builder.Name = name;

            foreach (var child in children)
            {
                builder.Children.Add(child);
            }

            return(builder.Build());
        }
示例#20
0
        public void ConstructorTransfersInstanceOfChunkGeneratorFromBlockBuilder()
        {
            // Arrange
            var expected = new ExpressionChunkGenerator();
            var builder  = new BlockBuilder()
            {
                Type           = BlockType.Helper,
                ChunkGenerator = expected
            };

            // Act
            var actual = builder.Build();

            // Assert
            Assert.Same(expected, actual.ChunkGenerator);
        }
示例#21
0
        public void ConstructorTransfersChildrenFromBlockBuilder()
        {
            // Arrange
            var expected = new SpanBuilder() { Kind = SpanKind.Code }.Build();
            var builder = new BlockBuilder()
            {
                Type = BlockType.Functions
            };
            builder.Children.Add(expected);

            // Act
            var block = builder.Build();

            // Assert
            Assert.Same(expected, block.Children.Single());
        }
示例#22
0
        public RazorSyntaxTree Execute(RazorCodeDocument document, RazorSyntaxTree syntaxTree)
        {
            Block expression;
            Span  route;

            if (!TryFindPageDirectiveBlocks(syntaxTree.Root, out expression, out route))
            {
                return(syntaxTree);
            }

            var builder = new BlockBuilder(syntaxTree.Root);

            builder.Children.Remove(expression);
            builder.Children.Remove(route);

            return(RazorSyntaxTree.Create(builder.Build(), syntaxTree.Diagnostics));
        }
示例#23
0
        protected virtual Block ConfigureAndAddSpanToBlock(BlockBuilder block, SpanConstructor span)
        {
            switch (block.Type)
            {
            case BlockType.Markup:
                span.With(new MarkupChunkGenerator());
                break;

            case BlockType.Statement:
                span.With(new StatementChunkGenerator());
                break;

            case BlockType.Expression:
                block.ChunkGenerator = new ExpressionChunkGenerator();
                span.With(new ExpressionChunkGenerator());
                break;
            }
            block.Children.Add(span);
            return(block.Build());
        }
        /// <summary>
        /// Ends the current block
        /// </summary>
        public void EndBlock()
        {
            EnusreNotTerminated();
            AssertOnOwnerTask();

            if (_blockStack.Count == 0)
            {
                throw new InvalidOperationException(RazorResources.EndBlock_Called_Without_Matching_StartBlock);
            }
            if (_blockStack.Count > 1)
            {
                BlockBuilder block = _blockStack.Pop();
                _blockStack.Peek().Children.Add(block.Build());
            }
            else
            {
                // If we're at 1, terminate the parser
                _terminated = true;
            }
        }
示例#25
0
        public void Compile()
        {
            Progress(BuildStep.Compiling);
            Backend.Begin(this);

            foreach (var upk in Input.Packages)
            {
                if (Backend.CanLink(upk))
                {
                    upk.Flags |= SourcePackageFlags.CanLink;
                }
            }

            using (Log.StartProfiler(TypeBuilder))
                TypeBuilder.Build();
            if (Log.HasErrors)
            {
                return;
            }

            Backend.ShaderBackend.Initialize(this, BundleBuilder);

            using (Log.StartProfiler(BlockBuilder))
                BlockBuilder.Build();
            if (Log.HasErrors)
            {
                return;
            }

            using (Log.StartProfiler(UxlProcessor))
                UxlProcessor.CompileDocuments();
            if (Log.HasErrors)
            {
                return;
            }

            Run(new ILAnalyzer(Pass));
            Run(ILVerifier);
        }
示例#26
0
        private void UnterminatedBlockCore(
            string keyword,
            string expectedTerminator,
            BlockType blockType,
            bool keywordIsMetaCode,
            Func <UnclassifiedCodeSpanConstructor, SpanConstructor> classifier
            )
        {
            const string blockBody =
                @"
    ' This block is not correctly terminated!";

            BlockBuilder expected = new BlockBuilder();

            expected.Type = blockType;
            if (keywordIsMetaCode)
            {
                expected.Children.Add(Factory.MetaCode(keyword).Accepts(AcceptedCharacters.None));
                expected.Children.Add(classifier(Factory.Code(blockBody)));
            }
            else
            {
                expected.Children.Add(classifier(Factory.Code(keyword + blockBody)));
            }

            ParseBlockTest(
                keyword + blockBody,
                expected.Build(),
                new RazorError(
                    String.Format(
                        RazorResources.ParseError_BlockNotTerminated,
                        keyword,
                        expectedTerminator
                        ),
                    SourceLocation.Zero
                    )
                );
        }
示例#27
0
        private void EofBlockCore(string keyword, string expectedTerminator, bool autoComplete, BlockType blockType, bool keywordIsMetaCode, Func <UnclassifiedCodeSpanConstructor, SpanConstructor> classifier)
        {
            BlockBuilder expected = new BlockBuilder();

            expected.Type = blockType;
            if (keywordIsMetaCode)
            {
                expected.Children.Add(Factory.MetaCode(keyword).Accepts(AcceptedCharacters.None));
                expected.Children.Add(
                    classifier(Factory.EmptyVB())
                    .With((SpanEditHandler)(
                              autoComplete ?
                              new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)
                {
                    AutoCompleteString = expectedTerminator
                } :
                              SpanEditHandler.CreateDefault())));
            }
            else
            {
                expected.Children.Add(
                    classifier(Factory.Code(keyword))
                    .With((SpanEditHandler)(
                              autoComplete ?
                              new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)
                {
                    AutoCompleteString = expectedTerminator
                } :
                              SpanEditHandler.CreateDefault())));
            }

            ParseBlockTest(keyword,
                           expected.Build(),
                           new RazorError(
                               String.Format(RazorResources.ParseError_BlockNotTerminated, keyword, expectedTerminator),
                               SourceLocation.Zero));
        }
        private static Block RebuildChunkGenerators(Block block, bool isBound)
        {
            var builder = new BlockBuilder(block);

            // Don't want to rebuild unbound dynamic attributes. They need to run through the conditional attribute
            // removal system at runtime. A conditional attribute at the parse tree rewriting level is defined by
            // having at least 1 child with a DynamicAttributeBlockChunkGenerator.
            if (!isBound &&
                block.Children.Any(
                    child => child.IsBlock &&
                    ((Block)child).ChunkGenerator is DynamicAttributeBlockChunkGenerator))
            {
                // The parent chunk generator must be removed because it's normally responsible for conditionally
                // generating the attribute prefix (class=") and suffix ("). The prefix and suffix concepts aren't
                // applicable for the TagHelper use case since the attributes are put into a dictionary like object as
                // name value pairs.
                builder.ChunkGenerator = ParentChunkGenerator.Null;

                return(builder.Build());
            }

            var isDynamic = builder.ChunkGenerator is DynamicAttributeBlockChunkGenerator;

            // We don't want any attribute specific logic here, null out the block chunk generator.
            if (isDynamic || builder.ChunkGenerator is AttributeBlockChunkGenerator)
            {
                builder.ChunkGenerator = ParentChunkGenerator.Null;
            }

            for (var i = 0; i < builder.Children.Count; i++)
            {
                var child = builder.Children[i];

                if (child.IsBlock)
                {
                    // The child is a block, recurse down into the block to rebuild its children
                    builder.Children[i] = RebuildChunkGenerators((Block)child, isBound);
                }
                else
                {
                    var childSpan = (Span)child;
                    ISpanChunkGenerator newChunkGenerator = null;
                    var literalGenerator = childSpan.ChunkGenerator as LiteralAttributeChunkGenerator;

                    if (literalGenerator != null)
                    {
                        if (literalGenerator.ValueGenerator == null || literalGenerator.ValueGenerator.Value == null)
                        {
                            newChunkGenerator = new MarkupChunkGenerator();
                        }
                        else
                        {
                            newChunkGenerator = literalGenerator.ValueGenerator.Value;
                        }
                    }
                    else if (isDynamic && childSpan.ChunkGenerator == SpanChunkGenerator.Null)
                    {
                        // Usually the dynamic chunk generator handles creating the null chunk generators underneath
                        // it. This doesn't make sense in terms of tag helpers though, we need to change null code
                        // generators to markup chunk generators.

                        newChunkGenerator = new MarkupChunkGenerator();
                    }

                    // If we have a new chunk generator we'll need to re-build the child
                    if (newChunkGenerator != null)
                    {
                        var childSpanBuilder = new SpanBuilder(childSpan)
                        {
                            ChunkGenerator = newChunkGenerator
                        };

                        builder.Children[i] = childSpanBuilder.Build();
                    }
                }
            }

            return(builder.Build());
        }
        private static TryParseResult TryParseBlock(
            string tagName,
            Block block,
            IEnumerable <TagHelperDescriptor> descriptors,
            ErrorSink errorSink)
        {
            // TODO: Accept more than just spans: https://github.com/aspnet/Razor/issues/96.
            // The first child will only ever NOT be a Span if a user is doing something like:
            // <input @checked />

            var childSpan = block.Children.First() as Span;

            if (childSpan == null || childSpan.Kind != SpanKind.Markup)
            {
                errorSink.OnError(
                    block.Start,
                    RazorResources.FormatTagHelpers_CannotHaveCSharpInTagDeclaration(tagName),
                    block.Length);

                return(null);
            }

            var builder = new BlockBuilder(block);

            // If there's only 1 child it means that it's plain text inside of the attribute.
            // i.e. <div class="plain text in attribute">
            if (builder.Children.Count == 1)
            {
                return(TryParseSpan(childSpan, descriptors, errorSink));
            }

            var nameSymbols = childSpan
                              .Symbols
                              .OfType <HtmlSymbol>()
                              .SkipWhile(symbol => !HtmlMarkupParser.IsValidAttributeNameSymbol(symbol)) // Skip prefix
                              .TakeWhile(nameSymbol => HtmlMarkupParser.IsValidAttributeNameSymbol(nameSymbol))
                              .Select(nameSymbol => nameSymbol.Content);

            var name = string.Concat(nameSymbols);

            if (string.IsNullOrEmpty(name))
            {
                errorSink.OnError(
                    childSpan.Start,
                    RazorResources.FormatTagHelpers_AttributesMustHaveAName(tagName),
                    childSpan.Length);

                return(null);
            }

            // Have a name now. Able to determine correct isBoundNonStringAttribute value.
            var result = CreateTryParseResult(name, descriptors);

            var firstChild = builder.Children[0] as Span;

            if (firstChild != null && firstChild.Symbols[0] is HtmlSymbol)
            {
                var htmlSymbol = firstChild.Symbols[firstChild.Symbols.Count - 1] as HtmlSymbol;
                switch (htmlSymbol.Type)
                {
                // Treat NoQuotes and DoubleQuotes equivalently. We purposefully do not persist NoQuotes
                // ValueStyles at code generation time to protect users from rendering dynamic content with spaces
                // that can break attributes.
                // Ex: <tag my-attribute=@value /> where @value results in the test "hello world".
                // This way, the above code would render <tag my-attribute="hello world" />.
                case HtmlSymbolType.Equals:
                case HtmlSymbolType.DoubleQuote:
                    result.AttributeValueStyle = HtmlAttributeValueStyle.DoubleQuotes;
                    break;

                case HtmlSymbolType.SingleQuote:
                    result.AttributeValueStyle = HtmlAttributeValueStyle.SingleQuotes;
                    break;

                default:
                    result.AttributeValueStyle = HtmlAttributeValueStyle.Minimized;
                    break;
                }
            }

            // Remove first child i.e. foo="
            builder.Children.RemoveAt(0);

            // Grabbing last child to check if the attribute value is quoted.
            var endNode = block.Children.Last();

            if (!endNode.IsBlock)
            {
                var endSpan = (Span)endNode;

                // In some malformed cases e.g. <p bar="false', the last Span (false' in the ex.) may contain more
                // than a single HTML symbol. Do not ignore those other symbols.
                var symbolCount = endSpan.Symbols.Count();
                var endSymbol   = symbolCount == 1 ? (HtmlSymbol)endSpan.Symbols.First() : null;

                // Checking to see if it's a quoted attribute, if so we should remove end quote
                if (endSymbol != null && IsQuote(endSymbol))
                {
                    builder.Children.RemoveAt(builder.Children.Count - 1);
                }
            }

            // We need to rebuild the chunk generators of the builder and its children (this is needed to
            // ensure we don't do special attribute chunk generation since this is a tag helper).
            block = RebuildChunkGenerators(builder.Build(), result.IsBoundAttribute);

            // If there's only 1 child at this point its value could be a simple markup span (treated differently than
            // block level elements for attributes).
            if (block.Children.Count() == 1)
            {
                var child = block.Children.First() as Span;
                if (child != null)
                {
                    // After pulling apart the block we just have a value span.
                    var spanBuilder = new SpanBuilder(child);

                    result.AttributeValueNode =
                        CreateMarkupAttribute(spanBuilder, result.IsBoundNonStringAttribute);

                    return(result);
                }
            }

            var isFirstSpan = true;

            result.AttributeValueNode = ConvertToMarkupAttributeBlock(
                block,
                (parentBlock, span) =>
            {
                // If the attribute was requested by a tag helper but the corresponding property was not a
                // string, then treat its value as code. A non-string value can be any C# value so we need
                // to ensure the SyntaxTreeNode reflects that.
                if (result.IsBoundNonStringAttribute)
                {
                    // For bound non-string attributes, we'll only allow a transition span to appear at the very
                    // beginning of the attribute expression. All later transitions would appear as code so that
                    // they are part of the generated output. E.g.
                    // key="@value" -> MyTagHelper.key = value
                    // key=" @value" -> MyTagHelper.key =  @value
                    // key="1 + @case" -> MyTagHelper.key = 1 + @case
                    // key="@int + @case" -> MyTagHelper.key = int + @case
                    // key="@(a + b) -> MyTagHelper.key = a + b
                    // key="4 + @(a + b)" -> MyTagHelper.key = 4 + @(a + b)
                    if (isFirstSpan && span.Kind == SpanKind.Transition)
                    {
                        // do nothing.
                    }
                    else
                    {
                        var spanBuilder = new SpanBuilder(span);

                        if (parentBlock.Type == BlockType.Expression &&
                            (spanBuilder.Kind == SpanKind.Transition ||
                             spanBuilder.Kind == SpanKind.MetaCode))
                        {
                            // Change to a MarkupChunkGenerator so that the '@' \ parenthesis is generated as part of the output.
                            spanBuilder.ChunkGenerator = new MarkupChunkGenerator();
                        }

                        spanBuilder.Kind = SpanKind.Code;
                        span             = spanBuilder.Build();
                    }
                }

                isFirstSpan = false;

                return(span);
            });

            return(result);
        }
        public void Rewrite(RewritingContext context)
        {
            RewriteTags(context.SyntaxTree, context);

            context.SyntaxTree = _currentBlock.Build();
        }