public static TemplexIndexer Make(TemplexBase listCandidate, int index) { return(new TemplexIndexer { ListCandidate = listCandidate, Index = index }); }
/// <summary> /// Creates a new <see cref="TemplexPropertyAccess"/> /// </summary> public static TemplexPropertyAccess Make(TemplexBase entityCandidate, string propName) { return(new TemplexPropertyAccess { EntityCandidate = entityCandidate, PropertyName = propName }); }
/// <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); }
/// <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 }); }
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); }