MustacheSharp/mustache-sharp/FormatParser.cs

151 lines
5.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace mustache
{
/// <summary>
/// Parses a format string and returns the text generator.
/// </summary>
internal sealed class FormatParser
{
private const string key = @"[_\w][_\w\d]*";
private const string compoundKey = key + @"(\." + key + ")*";
/// <summary>
/// Initializes a new instance of a FormatParser.
/// </summary>
public FormatParser()
{
}
/// <summary>
/// Builds a text generator based on the given format.
/// </summary>
/// <param name="format">The format to parse.</param>
/// <returns>The text generator.</returns>
public IGenerator Build(string format)
{
TagDefinition definition = new TagDefinition("builtins");
definition.HasBody = true;
CompoundGenerator generator = new CompoundGenerator();
TagScope tagScope = new TagScope();
registerTags(definition, tagScope);
Match match = findNextTag(definition, format, 0);
buildCompoundGenerator(definition, tagScope, generator, format, 0, match);
return generator;
}
private static void registerTags(TagDefinition definition, TagScope scope)
{
foreach (TagDefinition childTag in definition.ChildTags)
{
scope.AddTag(childTag);
}
}
private static Match findNextTag(TagDefinition definition, string format, int formatIndex)
{
List<string> matches = new List<string>();
matches.Add(getKeyRegex());
matches.Add(getClosingTagRegex(definition));
matches.Add(getCommentTagRegex());
foreach (TagDefinition childTag in definition.ChildTags)
{
matches.Add(getTagRegex(childTag));
}
string match = "{{(" + String.Join("|", matches) + ")}}";
Regex regex = new Regex(match);
return regex.Match(format, formatIndex);
}
private static string getClosingTagRegex(TagDefinition definition)
{
StringBuilder regexBuilder = new StringBuilder();
regexBuilder.Append(@"(?<close>(/");
regexBuilder.Append(definition.Name);
regexBuilder.Append(@"\s*?))");
return regexBuilder.ToString();
}
private static string getCommentTagRegex()
{
return @"(?<comment>#!.*?)";
}
private static string getKeyRegex()
{
return @"((?<key>" + compoundKey + @")(,(?<alignment>(-)?[\d]+))?(:(?<format>.*?))?)";
}
private static string getTagRegex(TagDefinition definition)
{
StringBuilder regexBuilder = new StringBuilder();
regexBuilder.Append(@"(?<open>(#(?<name>");
regexBuilder.Append(definition.Name);
regexBuilder.Append(@")");
foreach (TagParameter parameter in definition.Parameters)
{
regexBuilder.Append(@"\s+?");
regexBuilder.Append(@"(?<argument>");
regexBuilder.Append(compoundKey);
regexBuilder.Append(@")");
}
regexBuilder.Append(@"\s*?))");
return regexBuilder.ToString();
}
private static int buildCompoundGenerator(TagDefinition tagDefinition, TagScope scope, CompoundGenerator generator, string format, int formatIndex, Match match)
{
bool done = false;
while (!done)
{
string leading = format.Substring(formatIndex, match.Index - formatIndex);
formatIndex = match.Index + match.Length;
if (match.Groups["comment"].Success)
{
// TODO - process comment
}
else if (match.Groups["close"].Success)
{
// TODO - process closing tag
done = true;
}
else if (match.Groups["open"].Success)
{
string tagName = match.Groups["name"].Value;
TagDefinition nextDefinition = scope.Find(tagName);
if (nextDefinition == null)
{
// TODO - handle missing tag definition
}
if (nextDefinition.HasBody)
{
CompoundGenerator nextGenerator = new CompoundGenerator();
TagScope nextScope = new TagScope(scope);
registerTags(nextDefinition, nextScope);
Match nextMatch = findNextTag(nextDefinition, format, formatIndex);
formatIndex = buildCompoundGenerator(nextDefinition, nextScope, nextGenerator, format, formatIndex, nextMatch);
// TODO - grab the generated text and parameters and pass it to the tag's processor
// TODO - a parameter can be a key or a default value
}
else
{
// TODO - grab all of the parameters and pass them to the tag's generator
// TODO - a parameter can be a key or a default value
}
}
else if (match.Groups["key"].Success)
{
string alignment = match.Groups["alignment"].Value;
string formatting = match.Groups["format"].Value;
// TODO - create a key generator
}
}
return formatIndex;
}
}
}