ln.templates/TemplateReader.cs

152 lines
4.8 KiB
C#

using System;
using System.Collections.Generic;
using ln.templates.elements;
using System.IO;
using System.Text;
namespace ln.templates
{
public class TemplateReader
{
public ContainerElement RootElement { get; private set; } = new ContainerElement(null);
public ContainerElement CurrentElement { get; private set; }
public Expression FrameExpression { get; private set; }
public String Source { get; private set; }
public TemplateReader(String source)
{
Source = source;
Parse();
}
private void Parse()
{
CurrentElement = RootElement;
while (Source.Length > 0)
{
String t, op;
int i, j;
i = Source.IndexOf("<%");
if (i == -1)
{
t = Source;
op = null;
Source = "";
}
else
{
t = Source.Substring(0, i);
j = Source.IndexOf("%>", i + 1);
if (j == -1)
{
throw new FormatException(String.Format("missing '%>' in {0}", Source.Substring(i, 64)));
}
op = Source.Substring(i + 2, j - i - 2);
Source = Source.Substring(j + 2);
}
new TextElement(CurrentElement, t);
if (op != null)
ParseOP(op);
}
}
private void ParseOP(String op)
{
StringReader reader = new StringReader(op);
String opkey;
if (reader.Peek() == '=')
{
reader.Read();
opkey = "=";
}
else
{
opkey = reader.PopWord();
}
switch (opkey)
{
case "=":
new ExpressionElement(CurrentElement, new Expression(reader.ReadToEnd()));
break;
case "frame":
FrameExpression = new Expression(reader.ReadToEnd());
break;
case "iterate":
String iterName = reader.PopWord();
CurrentElement = new IteratorElement(CurrentElement, iterName, new Expression(reader.ReadToEnd()));
break;
case "if":
CurrentElement = new ConditionalElement(CurrentElement, new Expression(reader.ReadToEnd()));
break;
case "else":
if (CurrentElement is ConditionalElement)
{
ConditionalElement ce = CurrentElement as ConditionalElement;
CurrentElement = ce.AlternativeContainer;
}
break;
case "elseif":
if (CurrentElement is ConditionalElement)
{
ConditionalElement ce = CurrentElement as ConditionalElement;
CurrentElement = new ConditionalElement(null, new Expression(reader.ReadToEnd()));
ce.AlternativeContainer = CurrentElement;
}
break;
case "include":
new IncludeElement(CurrentElement, new Expression(reader.ReadToEnd()));
break;
case "set":
String setName = reader.PopWord();
new SetElement(CurrentElement, setName, new Expression(reader.ReadToEnd()));
break;
case "end":
CurrentElement = CurrentElement.Container;
break;
default:
throw new NotImplementedException(opkey);
}
}
}
static class StringHelper
{
public static int IndexOf(this String s,Func<char,bool> predicate)
{
for (int i=0;i<s.Length;i++)
{
if (predicate(s[i]))
return i;
}
return -1;
}
public static void SkipWhiteSpace(this TextReader reader)
{
while (char.IsWhiteSpace((char)reader.Peek()))
{
reader.Read();
}
}
public static String PopWord(this TextReader reader)
{
StringBuilder stringBuilder = new StringBuilder();
while ((reader.Peek()!=-1) && !char.IsWhiteSpace((char)reader.Peek()))
{
stringBuilder.Append((char)reader.Read());
}
reader.SkipWhiteSpace();
return stringBuilder.ToString();
}
}
}