public static ExpressionNode Parse(HandlebarsParserState state, HandlebarsBlockStack blockStack, SourceLocation location, string expression, IMemberLocator memberLocator = null)
        {
            int recursionLevel = 0;

	        memberLocator = memberLocator ?? MemberLocator.Default;

            expression = expression.Trim();

            if (expression == "this")
            {
                return SyntaxTreeExpression.Self(blockStack.GetCurrentModelType(), location);
            }
            if (expression.StartsWith("../"))
            {
                var blockNode = blockStack.FirstNode();
                while (expression.StartsWith("../"))
                {
                    var parentBlockNode = blockStack.GetParentNode(blockNode);
                    if (parentBlockNode != null)
                    {
                        blockNode = parentBlockNode;
                        expression = expression.Substring(3);
                        location = location.MoveIndex(3);
                    }
                    recursionLevel++;
                }
                return ParseAgainstModel(blockStack.GetCurrentModelType(blockNode), expression, ExpressionScope.ModelOfParentScope, recursionLevel, memberLocator, location);
            }

            return ParseAgainstModel(blockStack.GetCurrentModelType(), expression, ExpressionScope.CurrentModelOnStack, recursionLevel, memberLocator, location);
        }
		private static ExpressionNode ParseAgainstModel(Type modelType, string expression, ExpressionScope expressionScope, int recursionLevel, IMemberLocator memberLocator, SourceLocation location)
        {
            var dotIndex = expression.IndexOf('.');
            if (dotIndex >= 0)
            {
				var subModel = ParseAgainstModel(modelType, expression.Substring(0, dotIndex), expressionScope, recursionLevel, memberLocator, location.SetLength(dotIndex));
                return SyntaxTreeExpression.SubModel(
                    subModel,
                    ParseAgainstModel(subModel.ResultType, expression.Substring(dotIndex + 1), ExpressionScope.CurrentModelOnStack, 0, memberLocator, location.MoveIndex(dotIndex + 1)),
					location
                );
            }

            if (expression.EndsWith("()"))
            {
                var func = memberLocator.FindMember(modelType, expression.Substring(0, expression.Length - 2), MemberTypes.Method);
                if (func != null) return SyntaxTreeExpression.Function(modelType, func.Name, location, expressionScope);
            }

            var prop = memberLocator.FindMember(modelType, expression, MemberTypes.Property | MemberTypes.Field);
            if (prop != null)
            {
                switch (prop.MemberType)
                {
                    case MemberTypes.Property: return SyntaxTreeExpression.Property(modelType, prop.Name, location, expressionScope, recursionLevel);
                    case MemberTypes.Field: return SyntaxTreeExpression.Field(modelType, prop.Name, location, expressionScope, recursionLevel);
                }
            }

            if (IsLateBoundAcceptingType(modelType))
                return SyntaxTreeExpression.LateBound(expression, location, memberLocator, false, expressionScope, recursionLevel);

            throw new VeilParserException(String.Format("Unable to parse model expression '{0}' againt model '{1}'", expression, modelType.Name), location);
        }
		private static ExpressionNode ParseAgainstModel(Type modelType, string expression, ExpressionScope expressionScope, IMemberLocator memberLocator, SourceLocation location)
        {
            var dotIndex = expression.IndexOf('.');
            if (dotIndex >= 0)
            {
				var subModel = ParseAgainstModel(modelType, expression.Substring(0, dotIndex), expressionScope, memberLocator, location.SetLength(dotIndex));
                return SyntaxTreeExpression.SubModel(
                    subModel,
                    ParseAgainstModel(subModel.ResultType, expression.Substring(dotIndex + 1), ExpressionScope.CurrentModelOnStack, memberLocator, location.MoveIndex(dotIndex + 1)),
					location
                );
            }

            if (expression.EndsWith("()"))
            {
                var func = memberLocator.FindMethod(modelType, expression.Substring(0, expression.Length - 2));
                if (func != null) return SyntaxTreeExpression.Function(modelType, func.Name, location, expressionScope);
            }

            var prop = memberLocator.FindProperty(modelType, expression);
		    if (prop != null)
		        return SyntaxTreeExpression.Property(modelType, prop.Name, location, expressionScope);

            var field = memberLocator.FindField(modelType, expression);
		    if (field != null)
		        return SyntaxTreeExpression.Field(modelType, field.Name, location, expressionScope);

            if (IsLateBoundAcceptingType(modelType)) 
				return SyntaxTreeExpression.LateBound(expression, location, memberLocator, false, expressionScope);

            throw new VeilParserException(
                $"Unable to parse model expression '{expression}' againt model '{modelType.Name}'", location);
        }
예제 #4
0
        /// <summary>
        /// Write a string literal to the TextWriter
        /// </summary>
        /// <param name="content">The string to be written</param>
        public static WriteLiteralNode WriteString(string content, SourceLocation location)
        {
            return new WriteLiteralNode
            {
				Location = location,
                LiteralContent = content
            };
        }
예제 #5
0
 public void WriteLiteral(string s, SourceLocation location)
 {
     if (TrimNextLiteral)
     {
         s = s.TrimStart();
         TrimNextLiteral = false;
     }
     AddNodeToCurrentBlock(SyntaxTree.WriteString(s, location));
 }
		/// <summary>
		/// Evaluate a field on the model object
		/// </summary>
		/// <param name="modelType">The type of the scoped model</param>
		/// <param name="fieldName">The name of the field</param>
		/// <param name="scope">The scope this expression evaluated in</param>
		public static FieldExpressionNode Field(Type modelType, string fieldName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack)
		{
			return new FieldExpressionNode
			{
				Location = location,
				FieldInfo = modelType.GetField(fieldName),
				Scope = scope
			};
		}
		/// <summary>
		/// Evaluate a property on the model object
		/// </summary>
		/// <param name="modelType">The type of the scoped model</param>
		/// <param name="propertyName">The name of the property</param>
		/// <param name="scope">The scope this expression evaluated in</param>
		public static PropertyExpressionNode Property(Type modelType, string propertyName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack)
		{
			return new PropertyExpressionNode
			{
				Location = location,
				PropertyInfo = modelType.GetProperty(propertyName),
				Scope = scope
			};
		}
		/// <summary>
		/// Evaluate a function call on the model
		/// </summary>
		/// <param name="modelType">The type of the scoped model</param>
		/// <param name="functionName">The name of the function</param>
		/// <param name="scope">The scope this expression evaluated in</param>
		public static FunctionCallExpressionNode Function(Type modelType, string functionName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack)
		{
			return new FunctionCallExpressionNode
			{
				Location = location,
				MethodInfo = modelType.GetMethod(functionName, new Type[0]),
				Scope = scope
			};
		}
		/// <summary>
		/// Evaluate the model itself e.g. Value types
		/// </summary>
		/// <param name="modelType">The type of the scoped model</param>
		/// <param name="scope">The scope this expression evaluated in</param>
		public static SelfExpressionNode Self(Type modelType, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack)
		{
			return new SelfExpressionNode
			{
				Location = location,
				ModelType = modelType,
				Scope = scope
			};
		}
예제 #10
0
        /// <summary>
        /// Evaluate an expression and write the value to the TextWriter
        /// </summary>
        /// <param name="expression">The expression to be written</param>
        /// <param name="htmlEncode">Indicates whether the content should be html encoded before being written</param>
        public static WriteExpressionNode WriteExpression(ExpressionNode expression, SourceLocation location, bool htmlEncode = false)
        {
            return new WriteExpressionNode
            {
				Location = location,
                Expression = expression,
                HtmlEncode = htmlEncode
            };
        }
예제 #11
0
        /// <summary>
        /// Create a sequential block of nodes
        /// </summary>
        public static BlockNode Block(SourceLocation location, params SyntaxTreeNode[] nodes)
        {
            var block = new BlockNode
            {
	            Location = location
            };
            block.AddRange(nodes);
            return block;
        }
		/// <summary>
		/// Evaluate an expression on a sub model, can be nested to traverse any depth of sub models
		/// </summary>
		/// <param name="modelExpression">An expression referencing the model to traverse to</param>
		/// <param name="subModelExpression">An expression to evaluate in the scope of the model that has been traversed to</param>
		/// <param name="scope">The scope this expression evaluated in</param>
		public static SubModelExpressionNode SubModel(ExpressionNode modelExpression, ExpressionNode subModelExpression, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack)
		{
			return new SubModelExpressionNode
			{
				Location = location,
				ModelExpression = modelExpression,
				SubModelExpression = subModelExpression,
				Scope = scope
			};
		}
예제 #13
0
        /// <summary>
        /// Evaluates an expression and chooses between two blocks based on the truthy-ness of the result
        /// </summary>
        /// <param name="expression">The expression to evaluate</param>
        /// <param name="trueBlock">The block to execute when the expression is true</param>
        /// <param name="falseBlock">The block to evaluate when the expression is false</param>
        /// <returns></returns>
        public static ConditionalNode Conditional(ExpressionNode expression, SourceLocation location, BlockNode trueBlock, BlockNode falseBlock = null)
        {
            return new ConditionalNode
            {
				Location = location,
                Expression = expression,
                TrueBlock = trueBlock,
                FalseBlock = falseBlock
            };
        }
예제 #14
0
        /// <summary>
        /// Iterate a collection and execute the body block scoped to each item in the collection.
        /// Optionally execute an empty block when there are no items to iterate
        /// </summary>
        /// <param name="collectionExpression">expression to load the collection</param>
        /// <param name="body">Block to execute in the scope of each item</param>
        /// <param name="emptyBody">Block to execute when there are no items in the collection</param>
        public static IterateNode Iterate(ExpressionNode collectionExpression, SourceLocation location, BlockNode body, BlockNode emptyBody = null)
        {
            return new IterateNode
            {
				Location = location,
                Collection = collectionExpression,
                Body = body,
                EmptyBody = emptyBody ?? SyntaxTree.Block(location)
            };
        }
예제 #15
0
        protected async Task GetErrorPage(StreamWriter writer, Exception error, SourceLocation location)
        {
            var fileSystem = new EmbeddedResourceFileSystem(typeof(WebInitializer).Assembly);
            string content;
            using (var reader = new StreamReader(fileSystem.OpenRead(PathInfo.Create("Core/error_partial.html"))))
            {
                content = await reader.ReadToEndAsync();
            }

            var templateInfo = new StringTemplateInfo("error", content);

            var view = await ((IViewEngine)Resolver.GetService(typeof(IViewEngine)))
	            .CreateViewAsync(templateInfo, typeof(ErrorViewModel)).ConfigureAwait(false);

            if (location == null)
            {
                var modelWithoutLocation = new ErrorViewModel
                {
                    ErrorMessage = error.Message,
                    Details = error.StackTrace
                };
                view.Render(modelWithoutLocation, new RenderingContext(writer));
                return;
            }

            var templateRepository = (ITemplateRepository)this.Resolver.GetService(typeof(ITemplateRepository));
            var sourceTemplate = await templateRepository.GetTemplateAsync(location.TemplateId).ConfigureAwait(false);
            string sourceTemplateSource;

            using (var reader = new StreamReader(sourceTemplate.Open()))
            {
                sourceTemplateSource = await reader.ReadToEndAsync().ConfigureAwait(false);
            }

            var model = new ErrorViewModel
            {
                TemplateId = location.TemplateId,
                ErrorMessage = error.Message,
                Details = error.StackTrace,
                Before = sourceTemplateSource.Substring(0, location.Index),
                Node = sourceTemplateSource.Substring(location.Index, location.Length),
                After = sourceTemplateSource.Substring(location.Index + location.Length),
                Text = HttpUtility.JavaScriptStringEncode(sourceTemplateSource),
                Range = GetRange(sourceTemplateSource, location)
            };

            view.Render(model, new RenderingContext(writer));
        }
        public static ExpressionNode Parse(HandlebarsParserState state, HandlebarsBlockStack blockStack, SourceLocation location, string expression, IMemberLocator memberLocator = null)
        {
	        memberLocator = memberLocator ?? MemberLocator.Default;

            expression = expression.Trim();

            if (expression == "this")
            {
                return SyntaxTreeExpression.Self(blockStack.GetCurrentModelType(), location, ExpressionScope.CurrentModelOnStack);
            }
            if (expression.StartsWith("../"))
            {
                return ParseAgainstModel(blockStack.GetParentModelType(), expression.Substring(3), ExpressionScope.ModelOfParentScope, memberLocator, location.MoveIndex(3));
            }

            return ParseAgainstModel(blockStack.GetCurrentModelType(), expression, ExpressionScope.CurrentModelOnStack, memberLocator, location);
        }
예제 #17
0
	    private static void AssertLocation(string input, string templateId, SourceLocation location, string enclosedText, int index)
	    {
	        Assert.Equal(enclosedText, input.Substring(location.Index, location.Length));
	        Assert.Equal(index, location.Index);
	        Assert.Equal(enclosedText.Length, location.Length);
	        Assert.Equal(templateId, location.TemplateId);
	    }
예제 #18
0
        /// <summary>
        /// Execute another template in the scope of the provided model
        /// </summary>
        /// <param name="templateName">The name of the template to execute. It will be loaded from the <see cref="IVeilContext"/></param>
        /// <param name="modelExpression">An expression for the model to be used as the root scope when executing the template</param>
        public static IncludeTemplateNode Include(string templateName, ExpressionNode modelExpression, SourceLocation location)
        {
            return new IncludeTemplateNode
            {
				Location = location,
                ModelExpression = modelExpression,
                TemplateName = templateName
            };
        }
예제 #19
0
	    /// <summary>
	    /// Evaluate whether the collectionExpression has Count > 0
	    /// Can only be used on types that implement <see cref="System.Collections.ICollection"/>
	    /// </summary>
	    /// <param name="collectionExpression">An expression referencing a Collection</param>
	    /// <param name="location"></param>
	    /// <param name="recursionLevel"></param>
	    public static CollectionHasItemsExpressionNode HasItems(ExpressionNode collectionExpression, SourceLocation location, int recursionLevel = 0)
		{
			return new CollectionHasItemsExpressionNode
			{
				Location = location,
				CollectionExpression = collectionExpression,
				Scope = collectionExpression.Scope,
                RecursionLevel = recursionLevel
			};
		}
예제 #20
0
	    /// <summary>
        /// Create an exception with the supplied message
        /// </summary>
        public VeilParserException(string message, SourceLocation location)
            : base(message)
        {
	        Location = location;
        }
예제 #21
0
 /// <summary>
 /// Evaluate whether the collectionExpression has Count > 0
 /// Can only be used on types that implement <see cref="System.Collections.ICollection"/>
 /// </summary>
 /// <param name="collectionExpression">An expression referencing a Collection</param>
 /// <param name="location"></param>
 /// <param name="recursionLevel"></param>
 public static CollectionHasItemsExpressionNode HasItems(ExpressionNode collectionExpression, SourceLocation location, int recursionLevel = 0)
 {
     return(new CollectionHasItemsExpressionNode
     {
         Location = location,
         CollectionExpression = collectionExpression,
         Scope = collectionExpression.Scope,
         RecursionLevel = recursionLevel
     });
 }
예제 #22
0
        public static HelperExpressionNode Helper(string expression, IHelperHandler helperHandler, SourceLocation location)
        {
            var parts = expression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            return(Helper(parts, helperHandler, location));
        }
예제 #23
0
 /// <summary>
 /// Evaluate an expression on a sub model, can be nested to traverse any depth of sub models
 /// </summary>
 /// <param name="modelExpression">An expression referencing the model to traverse to</param>
 /// <param name="subModelExpression">An expression to evaluate in the scope of the model that has been traversed to</param>
 /// <param name="location"></param>
 /// <param name="scope">The scope this expression evaluated in</param>
 public static SubModelExpressionNode SubModel(ExpressionNode modelExpression, ExpressionNode subModelExpression, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack)
 {
     return(new SubModelExpressionNode
     {
         Location = location,
         ModelExpression = modelExpression,
         SubModelExpression = subModelExpression,
         Scope = scope
     });
 }
		public static HelperExpressionNode Helper(string expression, IHelperHandler helperHandler, SourceLocation location)
		{
			var parts = expression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			return Helper(parts, helperHandler, location);
		}
		/// <summary>
		/// Evaluate a property at runtime against an unknown model type
		/// </summary>
		/// <param name="itemName">The name of the proeprty that will be searched for</param>
		/// <param name="isCaseSenstiive">Indcates whether the expression should be evaluated with case sensitivity</param>
		/// <param name="scope">The scope this expression evaluated in</param>
		public static LateBoundExpressionNode LateBound(string itemName, SourceLocation location, IMemberLocator memberLocator = null, bool isCaseSenstiive = true, ExpressionScope scope = ExpressionScope.CurrentModelOnStack)
		{
			return new LateBoundExpressionNode
			{
				Location = location,
                MemberLocator = memberLocator ?? MemberLocator.Default,
				ItemName = itemName,
				Scope = scope
			};
		}
예제 #26
0
        public static HelperExpressionNode Helper(string[] parameter, IHelperHandler helperHandler, SourceLocation location)
        {
            var data = new Dictionary <string, string>();

            if (parameter.Length > 1)
            {
                foreach (var value in parameter.Skip(1))
                {
                    var tmp = value.Split(new[] { '=' }, 2);
                    data.Add(tmp[0], tmp.Length == 2 ? tmp[1] : string.Empty);
                }
            }

            return(new HelperExpressionNode
            {
                Location = location,
                Name = parameter[0],
                Parameters = data,
                HelperHandler = helperHandler
            });
        }
예제 #27
0
        /// <summary>
        /// Scopes a node to a new model
        /// </summary>
        /// <param name="modelToScopeTo">An expression that evaluates to the model to scope to</param>
        /// <param name="node">The node to execute in the new scope</param>
        public static ScopedNode ScopeNode(ExpressionNode modelToScopeTo, SyntaxTreeNode node, SourceLocation location)
        {
            return new ScopedNode
            {
				Location = location,
                ModelToScope = modelToScopeTo,
                Node = node
            };
        }
예제 #28
0
 /// <summary>
 /// Evaluate a function call on the model
 /// </summary>
 /// <param name="modelType">The type of the scoped model</param>
 /// <param name="functionName">The name of the function</param>
 /// <param name="location"></param>
 /// <param name="scope">The scope this expression evaluated in</param>
 public static FunctionCallExpressionNode Function(Type modelType, string functionName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack)
 {
     return(new FunctionCallExpressionNode
     {
         Location = location,
         MethodInfo = modelType.GetMethod(functionName, new Type[0]),
         Scope = scope
     });
 }
예제 #29
0
        private static ErrorRange GetRange(string sourceTemplateSource, SourceLocation location)
        {
            int lineNumber = 0;
            int idx = 0;
            int lastIdx = 0;
            while ((idx = sourceTemplateSource.IndexOf('\n', idx)) >= 0 && idx < location.Index)
            {
                lineNumber++;
                idx++;
                lastIdx = idx;
            }

            int startLineNumber = lineNumber;
            int startIdx = lastIdx;
            while ((idx = sourceTemplateSource.IndexOf('\n', idx)) >= 0 && idx < location.Index + location.Length)
            {
                lineNumber++;
                idx++;
                lastIdx = idx;                
            }

            return new ErrorRange
            {
                StartRow = startLineNumber,
                StartColumn = location.Index - startIdx,
                EndRow = lineNumber,
                EndColumn = location.Index - lastIdx + location.Length
            };
        }
        public static HelperExpressionNode Helper(string[] parameter, IHelperHandler helperHandler, SourceLocation location)
		{
			var data = new Dictionary<string, string>();

			if (parameter.Length > 1)
			{
				foreach (var value in parameter.Skip(1))
				{
					var tmp = value.Split(new[] {'='}, 2);
					data.Add(tmp[0], tmp.Length == 2 ? tmp[1] : string.Empty);
				}
			}

			return new HelperExpressionNode
			{
				Location = location,
				Name = parameter[0],
				Parameters = data,
                HelperHandler = helperHandler
			};
		}
예제 #31
0
        /// <summary>
        /// Defines an optional point in a template that can be overridden when the template is extended.
        /// If the point is not overridden then the specified content is used by default
        /// </summary>
        /// <param name="overrideName">The name of the override which must match that specified in the overriding template</param>
        /// <param name="defaultContent">The content to use when the point is not overridden</param>
        public static OverridePointNode Override(string overrideName, SyntaxTreeNode defaultContent, SourceLocation location)
        {
            return new OverridePointNode
            {
				Location = location,
                OverrideName = overrideName,
                IsRequired = false,
                DefaultContent = defaultContent
            };
        }
예제 #32
0
 /// <summary>
 /// Evaluate a property on the model object
 /// </summary>
 /// <param name="modelType">The type of the scoped model</param>
 /// <param name="propertyName">The name of the property</param>
 /// <param name="location"></param>
 /// <param name="scope">The scope this expression evaluated in</param>
 /// <param name="recursionLevel"></param>
 public static PropertyExpressionNode Property(Type modelType, string propertyName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack, int recursionLevel = 0)
 {
     return(new PropertyExpressionNode
     {
         Location = location,
         PropertyInfo = modelType.GetProperty(propertyName),
         Scope = scope,
         RecursionLevel = recursionLevel
     });
 }
예제 #33
0
        /// <summary>
        /// Flushes the TextWriter.
        /// Used to optimize responses in web applications.
        /// </summary>
        public static FlushNode Flush(SourceLocation location)
        {
            return new FlushNode
            {
	            Location = location
            };
        }
예제 #34
0
 public ExpressionNode ParseExpression(string expression, SourceLocation location)
 {
     return HandlebarsExpressionParser.Parse(this, BlockStack, location, expression, _memberLocator);
 }
		/// <summary>
		/// Evaluate whether the collectionExpression has Count > 0
		/// Can only be used on types that implement <see cref="System.Collections.ICollection"/>
		/// </summary>
		/// <param name="collectionExpression">An expression referencing a Collection</param>
		public static CollectionHasItemsExpressionNode HasItems(ExpressionNode collectionExpression, SourceLocation location)
		{
			return new CollectionHasItemsExpressionNode
			{
				Location = location,
				CollectionExpression = collectionExpression,
				Scope = collectionExpression.Scope
			};
		}
예제 #36
0
	    public static SyntaxTreeNode Helper(HelperExpressionNode helperExpression, BlockNode block, SourceLocation location)
	    {
		    return new HelperBlockNode
		    {
				Location = location,
				HelperExpression = helperExpression,
				Block = block
		    };
	    }