Пример #1
0
 public static TemplexIndexer Make(TemplexBase listCandidate, int index)
 {
     return(new TemplexIndexer
     {
         ListCandidate = listCandidate,
         Index = index
     });
 }
Пример #2
0
 /// <summary>
 /// Creates a new <see cref="TemplexPropertyAccess"/>
 /// </summary>
 public static TemplexPropertyAccess Make(TemplexBase entityCandidate, string propName)
 {
     return(new TemplexPropertyAccess
     {
         EntityCandidate = entityCandidate,
         PropertyName = propName
     });
 }
Пример #3
0
        /// <summary>
        /// Parses the string into an <see cref="TemplexBase"/>
        /// </summary>
        /// <param name="express"></param>
        /// <returns></returns>
        public static TemplexBase Parse(string express)
        {
            string preprocessedExpression = Preprocess(express);

            if (string.IsNullOrWhiteSpace(preprocessedExpression))
            {
                return(null);
            }

            IEnumerable <string> tokenStream        = Tokenize(preprocessedExpression);
            TemplexBase          templateExpression = ParseTokenStream(tokenStream);

            return(templateExpression);
        }
Пример #4
0
 /// <summary>
 /// Divides left by right after converting both to their common numeric type. Throws a meaningful exception if right is equal to 0
 /// </summary>
 public static object Divide(object left, object right, Type commonType, TemplexBase rightExp)
 {
     try
     {
         return(commonType.Name switch
         {
             _sbyte => Convert.ToSByte(left) / Convert.ToSByte(right),
             _byte => Convert.ToByte(left) / Convert.ToByte(right),
             _short => Convert.ToInt16(left) / Convert.ToInt16(right),
             _ushort => Convert.ToUInt16(left) / Convert.ToUInt16(right),
             _int => Convert.ToInt32(left) / Convert.ToInt32(right),
             _uint => Convert.ToUInt32(left) / Convert.ToUInt32(right),
             _long => Convert.ToInt64(left) / Convert.ToInt64(right),
             _ulong => Convert.ToUInt64(left) / Convert.ToUInt64(right),
             _float => Convert.ToSingle(left) / Convert.ToSingle(right),
             _double => Convert.ToDouble(left) / Convert.ToDouble(right),
             _decimal => Convert.ToDecimal(left) / Convert.ToDecimal(right),
             _ => throw new Exception($"Unknown numeric type {commonType.Name}"),// Developer mistake
         });
     }
Пример #5
0
        private static TemplateTree ParseTokenStream(IEnumerable <string> tokenStream)
        {
            // Structure expressions (like *if and *foreach) cause the state to be pushed in this stack
            var stack = new Stack <(StructureBase, TemplateTree)>();

            // State
            var currentTemplate = new TemplateTree();
            var currentStruct   = default(StructureBase);

            bool insideCurlies = false;

            foreach (var token in tokenStream)
            {
                if (token == "{{")
                {
                    insideCurlies = true;
                }
                else if (token == "}}")
                {
                    insideCurlies = false;
                }
                else if (insideCurlies)
                {
                    var tokenTrim = token.Trim();
                    if (tokenTrim.StartsWith("*")) // Inside the curlies, starts with an asterisk *: Structure component
                    {
                        // If it's an *end component, pop the state stack
                        if (tokenTrim.ToLower() == StructureBase._end || tokenTrim.ToLower().StartsWith(StructureBase._end + " "))
                        {
                            if (stack.Count == 0)
                            {
                                throw new TemplateException("Unexpected expression {{" + token + "}}");
                            }

                            // Pop the previous state
                            (currentStruct, currentTemplate) = stack.Pop();
                        }
                        else // If it's anything other then *end, push the state in the stack
                        {
                            // Parse the token and add it to the current template
                            var templateStructure = StructureBase.Parse(tokenTrim);
                            currentTemplate.Contents.Add(templateStructure);

                            // Start of a structural block
                            // Push the current state into the stack
                            stack.Push((currentStruct, currentTemplate));

                            // Start a fresh state
                            currentStruct          = templateStructure;
                            currentTemplate        = new TemplateTree();
                            currentStruct.Template = currentTemplate;
                        }
                    }
                    else // Inside the curlies, does not start with an asterisk *: An expression
                    {
                        currentTemplate.Contents.Add(TemplexBase.Parse(token));
                    }
                }
                else // Outside the curlies: Plain markup
                {
                    currentTemplate.Contents.Add(TemplateMarkup.Make(token));
                }
            }

            // All scopes that weren't explicitly closed, do so implicitly at the end of the template
            // Keep popping until you're back at the root
            while (stack.Count > 0)
            {
                (_, currentTemplate) = stack.Pop();
            }

            return(currentTemplate);
        }