/// <summary> /// Validates a tag based on the descriptor. /// </summary> /// <param name="name">The tag name.</param> /// <param name="descriptor">The tag descriptor.</param> /// <param name="arguments">The set of arguments.</param> /// <param name="parameters">The set of parameters.</param> public void ValidateTag(string name, TagDescriptor descriptor, object[] arguments, IDictionary <string, object> parameters) { if (descriptor == null || descriptor.IsImplicit) { // Can't validate the tag. return; } if (descriptor.RequiredArguments > 0 && arguments.Length < descriptor.RequiredArguments) { throw new InvalidOperationException(string.Format("The tag {0} requires at least {1} argument(s)", name, descriptor.RequiredArguments)); } if (arguments.Length > descriptor.MaxArguments) { throw new InvalidOperationException(string.Format("The tag {0} requires at most {1} argument(s)", name, descriptor.MaxArguments)); } bool hasParameters = parameters.Count > 0; if (descriptor.AllowMappedParameters != hasParameters) { throw new InvalidOperationException(string.Format("{0} parameters to tag {1}", hasParameters ? "Unexpected" : "Expected", name)); } }
public void ConvertBytesToVersionString() { Assert.Null(TagDescriptor <MockDirectory> .ConvertBytesToVersionString(null, 1)); Assert.Null(TagDescriptor <MockDirectory> .ConvertBytesToVersionString(Array.Empty <int>(), 1)); Assert.Equal("1.00", TagDescriptor <MockDirectory> .ConvertBytesToVersionString(new[] { 0, 1, 0, 0 }, 2)); Assert.Equal(".100", TagDescriptor <MockDirectory> .ConvertBytesToVersionString(new[] { 0, 1, 0, 0 }, 1)); Assert.Equal("2.10", TagDescriptor <MockDirectory> .ConvertBytesToVersionString(new[] { 0x30, 0x32, 0x31, 0x30 }, 2)); Assert.Equal(".210", TagDescriptor <MockDirectory> .ConvertBytesToVersionString(new[] { 0x30, 0x32, 0x31, 0x30 }, 1)); Assert.Equal("21.0", TagDescriptor <MockDirectory> .ConvertBytesToVersionString(new[] { 0x30, 0x32, 0x31, 0x30 }, 3)); }
/// <summary> /// Initialises a new instance of <see cref="Block"/> /// </summary> /// <param name="type">The block type.</param> /// <param name="name">The block name.</param> /// <param name="contents">The child contents.</param> /// <param name="descriptor">The tag descriptor.</param> protected Block(BlockType type, string name, IEnumerable <SyntaxTreeNode> contents, TagDescriptor descriptor) { Type = type; Name = name; Children = contents; Descriptor = descriptor; foreach (var node in contents) { node.Parent = this; } }
public void GetDescription_SimplifiedLongCollections() { var directory = new MockDirectory(); var descriptor = new TagDescriptor <MockDirectory>(directory); const int tagType = 1; directory.Set(tagType, Enumerable.Range(0, 16).Select(i => i).ToArray()); Assert.Equal("0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15", descriptor.GetDescription(tagType)); directory.Set(tagType, Enumerable.Range(0, 17).Select(i => i).ToArray()); Assert.Equal("[17 values]", descriptor.GetDescription(tagType)); }
/// <summary> /// Parses a block tag. /// </summary> public void AtBlockTag(HandlebarsSymbolType expectedPrefixSymbol = HandlebarsSymbolType.Hash) { var parent = Context.CurrentBlock; string tagName = null; TagDescriptor descriptor = null; // Start a new block. Context.StartBlock(BlockType.Tag); using (Context.StartBlock(BlockType.TagElement)) { // Accept the open tag. AcceptAndMoveNext(); // Output that tag as metacode. Output(SpanKind.MetaCode); if (Optional(HandlebarsSymbolType.Tilde)) { // Output the tilde. Output(SpanKind.MetaCode); } if (Required(expectedPrefixSymbol, true)) { // Accept the prefix symbol type. tag. AcceptAndMoveNext(); // Output that tag as metacode. Output(SpanKind.MetaCode); } // Accept everything until either the close of the tag, or the first element of whitespace. AcceptUntil(HandlebarsSymbolType.WhiteSpace, HandlebarsSymbolType.CloseTag, HandlebarsSymbolType.RawCloseTag); // Output the first part as an expression. Output(SpanKind.Expression); // Get the tag name and set it for the block. tagName = LastSpanContent(); descriptor = Context.TagProviders.GetDescriptor(tagName, expectedPrefixSymbol == HandlebarsSymbolType.Negate); Context.CurrentBlock.Name = tagName; Context.CurrentBlock.Descriptor = descriptor; while (CurrentSymbol.Type != HandlebarsSymbolType.CloseTag && CurrentSymbol.Type != HandlebarsSymbolType.RawCloseTag && CurrentSymbol.Type != HandlebarsSymbolType.Tilde) { if (CurrentSymbol.Type == HandlebarsSymbolType.WhiteSpace) { // Accept all the whitespace. AcceptAll(HandlebarsSymbolType.WhiteSpace); // Take all the whitespace, and output that. Output(SpanKind.WhiteSpace); } if (CurrentSymbol.Type == HandlebarsSymbolType.Assign) { // We're in a parameterised argument (e.g. one=two AcceptAndMoveNext(); // Accept everything until the next whitespace or closing tag. AcceptUntil(HandlebarsSymbolType.WhiteSpace, HandlebarsSymbolType.CloseTag, HandlebarsSymbolType.RawCloseTag, HandlebarsSymbolType.Tilde); // Output this as a map. Output(SpanKind.Map); } else { // Accept everything until the next whitespace or closing tag. AcceptUntil(HandlebarsSymbolType.Assign, HandlebarsSymbolType.WhiteSpace, HandlebarsSymbolType.CloseTag, HandlebarsSymbolType.RawCloseTag, HandlebarsSymbolType.Tilde); if (CurrentSymbol.Type != HandlebarsSymbolType.Assign) { // Output this as a parameter. Output(SpanKind.Parameter); } } } if (Optional(HandlebarsSymbolType.Tilde)) { // Output the tilde. Output(SpanKind.MetaCode); } // Accept the closing tag. AcceptAndMoveNext(); // Output this as metacode. Output(SpanKind.MetaCode); } // Special case, as we need to handle branching, so let's merge the last block into the parent block. if (tagName == "elseif" && parent != null && parent.Name == "if") { // Let's merge the current block with the parent and re-instate it. Context.MergeCurrentWithParent(); } else { Context.CurrentBlock.Name = tagName; Context.CurrentBlock.Descriptor = descriptor; } // Switch back to parsing the content of the block. ParseBlock(); }