WIP
parent
09be9fb80f
commit
fada8eea23
175
Expression.cs
175
Expression.cs
|
@ -3,6 +3,8 @@ using System.Reflection;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
namespace ln.templates
|
namespace ln.templates
|
||||||
{
|
{
|
||||||
delegate bool ConditionDelegate(char ch);
|
delegate bool ConditionDelegate(char ch);
|
||||||
|
@ -34,54 +36,99 @@ namespace ln.templates
|
||||||
|
|
||||||
private void Compile()
|
private void Compile()
|
||||||
{
|
{
|
||||||
StringReader reader = new StringReader(Source);
|
try
|
||||||
List<Token> tokens = new List<Token>();
|
{
|
||||||
while (reader.Peek() != -1)
|
StringReader reader = new StringReader(Source);
|
||||||
ReadToken(reader, tokens);
|
List<Token> tokens = new List<Token>();
|
||||||
TopEval = BuildEval(tokens);
|
while (reader.Peek() != -1)
|
||||||
|
ReadToken(reader, tokens);
|
||||||
|
|
||||||
|
Queue<Token> qtokens = new Queue<Token>(tokens);
|
||||||
|
|
||||||
|
TopEval = BuildExpression(qtokens);
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new Exception(String.Format("Failed to compile expression: {0}", Source), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Eval BuildEval(List<Token> tokens)
|
|
||||||
|
private Eval BuildName(Token nameToken,Eval parent,Queue<Token> tokens)
|
||||||
{
|
{
|
||||||
Eval currentEval = null;
|
if ((tokens.Count > 0) && (tokens.Peek().TokenType == TokenType.OPENLIST))
|
||||||
|
{
|
||||||
|
tokens.Dequeue();
|
||||||
|
|
||||||
|
List<Eval> pl = new List<Eval>();
|
||||||
|
while (tokens.Peek().TokenType != TokenType.ENDLIST)
|
||||||
|
{
|
||||||
|
pl.Add(BuildExpression(tokens));
|
||||||
|
|
||||||
|
if (tokens.Peek().TokenType == TokenType.ENDLIST)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (tokens.Peek().TokenType != TokenType.COMMA)
|
||||||
|
throw new FormatException("Expected ',' between parameters to call statement");
|
||||||
|
|
||||||
|
tokens.Dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.Dequeue();
|
||||||
|
|
||||||
|
return new MethodCall(parent, nameToken.Value, pl.ToArray());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Name(parent, nameToken.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Eval BuildPath(Queue<Token> tokens)
|
||||||
|
{
|
||||||
|
Eval currentEval = BuildName(tokens.Dequeue(), null, tokens);
|
||||||
|
|
||||||
while (tokens.Count > 0)
|
while (tokens.Count > 0)
|
||||||
{
|
{
|
||||||
Token token = tokens[0];
|
Token token = tokens.Peek();
|
||||||
tokens.RemoveAt(0);
|
|
||||||
|
|
||||||
switch (token.TokenType)
|
switch (token.TokenType)
|
||||||
{
|
{
|
||||||
case TokenType.DOT:
|
case TokenType.DOT:
|
||||||
token = tokens[0];
|
tokens.Dequeue();
|
||||||
tokens.RemoveAt(0);
|
currentEval = BuildName(tokens.Dequeue(), currentEval, tokens);
|
||||||
if (token.TokenType != TokenType.NAME)
|
|
||||||
throw new ArgumentException("missing fieldname after .");
|
|
||||||
currentEval = new Name(currentEval, token.Value);
|
|
||||||
break;
|
break;
|
||||||
case TokenType.NAME:
|
case TokenType.OPENINDEXER:
|
||||||
currentEval = new Name(currentEval, token.Value);
|
tokens.Dequeue();
|
||||||
break;
|
Eval index = BuildExpression(tokens);
|
||||||
case TokenType.NUMBER:
|
token = tokens.Dequeue();
|
||||||
currentEval = new Number(token.Value);
|
if (token.TokenType != TokenType.ENDINDEXER)
|
||||||
break;
|
throw new FormatException("Expected ']'");
|
||||||
case TokenType.STRING:
|
currentEval = new Indexer(currentEval, index);
|
||||||
currentEval = new CString(token.Value);
|
|
||||||
break;
|
|
||||||
case TokenType.BRACKET:
|
|
||||||
if (token.Value.Equals("["))
|
|
||||||
{
|
|
||||||
currentEval = new Indexer(currentEval, BuildEval(tokens));
|
|
||||||
} else if (token.Value.Equals("]"))
|
|
||||||
{
|
|
||||||
return currentEval;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return currentEval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return currentEval;
|
return currentEval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Eval BuildExpression(Queue<Token> tokens)
|
||||||
|
{
|
||||||
|
Token next = tokens.Peek();
|
||||||
|
|
||||||
|
switch (next.TokenType)
|
||||||
|
{
|
||||||
|
case TokenType.NAME:
|
||||||
|
return BuildPath(tokens);
|
||||||
|
case TokenType.NUMBER:
|
||||||
|
return new Number(tokens.Dequeue().Value);
|
||||||
|
case TokenType.STRING:
|
||||||
|
return new CString(tokens.Dequeue().Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FormatException(String.Format("unexpected Token: {0}", next.Value));
|
||||||
|
}
|
||||||
|
|
||||||
private void ReadToken(TextReader reader, List<Token> tokens)
|
private void ReadToken(TextReader reader, List<Token> tokens)
|
||||||
{
|
{
|
||||||
if (reader.Peek() == -1)
|
if (reader.Peek() == -1)
|
||||||
|
@ -91,7 +138,7 @@ namespace ln.templates
|
||||||
{
|
{
|
||||||
reader.Read();
|
reader.Read();
|
||||||
}
|
}
|
||||||
else if (char.IsLetter(ch))
|
else if (char.IsLetter(ch) || (ch == '_'))
|
||||||
{
|
{
|
||||||
ReadName(reader, tokens);
|
ReadName(reader, tokens);
|
||||||
}
|
}
|
||||||
|
@ -108,10 +155,30 @@ namespace ln.templates
|
||||||
reader.Read();
|
reader.Read();
|
||||||
tokens.Add(new Token(TokenType.DOT, "."));
|
tokens.Add(new Token(TokenType.DOT, "."));
|
||||||
}
|
}
|
||||||
else if ((ch == '[')| (ch == ']'))
|
else if (ch == '[')
|
||||||
{
|
{
|
||||||
reader.Read();
|
reader.Read();
|
||||||
tokens.Add(new Token(TokenType.BRACKET, new string(new char[] { ch })));
|
tokens.Add(new Token(TokenType.OPENINDEXER, new string(new char[] { ch })));
|
||||||
|
}
|
||||||
|
else if (ch == ']')
|
||||||
|
{
|
||||||
|
reader.Read();
|
||||||
|
tokens.Add(new Token(TokenType.ENDINDEXER, new string(new char[] { ch })));
|
||||||
|
}
|
||||||
|
else if (ch == '(')
|
||||||
|
{
|
||||||
|
reader.Read();
|
||||||
|
tokens.Add(new Token(TokenType.OPENLIST, new string(new char[] { ch })));
|
||||||
|
}
|
||||||
|
else if (ch == ')')
|
||||||
|
{
|
||||||
|
reader.Read();
|
||||||
|
tokens.Add(new Token(TokenType.ENDLIST, new string(new char[] { ch })));
|
||||||
|
}
|
||||||
|
else if (ch == ',')
|
||||||
|
{
|
||||||
|
reader.Read();
|
||||||
|
tokens.Add(new Token(TokenType.COMMA, new string(new char[] { ch })));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -122,7 +189,7 @@ namespace ln.templates
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
int ch = 0;
|
int ch = 0;
|
||||||
while (char.IsLetterOrDigit((char)(ch = reader.Peek())))
|
while (char.IsLetterOrDigit((char)(ch = reader.Peek())) || (ch == '_'))
|
||||||
{
|
{
|
||||||
sb.Append((char)reader.Read());
|
sb.Append((char)reader.Read());
|
||||||
}
|
}
|
||||||
|
@ -176,7 +243,7 @@ namespace ln.templates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum TokenType { NAME, DOT, NUMBER, STRING, BRACKET }
|
enum TokenType { NAME, DOT, NUMBER, STRING, OPENINDEXER, ENDINDEXER, OPENLIST, ENDLIST, COMMA }
|
||||||
class Token
|
class Token
|
||||||
{
|
{
|
||||||
public TokenType TokenType;
|
public TokenType TokenType;
|
||||||
|
@ -336,6 +403,40 @@ namespace ln.templates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MethodCall : Eval
|
||||||
|
{
|
||||||
|
Eval[] Parameters;
|
||||||
|
String Name;
|
||||||
|
|
||||||
|
public MethodCall(Eval parent, String name,params Eval[] p)
|
||||||
|
: base(parent)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Parameters = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object Evaluate(Context context)
|
||||||
|
{
|
||||||
|
object p = Parent.Evaluate(context);
|
||||||
|
|
||||||
|
object[] pvalues = new object[Parameters.Length];
|
||||||
|
Type[] ptypes = new Type[Parameters.Length];
|
||||||
|
|
||||||
|
for (int i=0;i<pvalues.Length;i++)
|
||||||
|
{
|
||||||
|
pvalues[i] = Parameters[i].Evaluate(context);
|
||||||
|
if (pvalues[i] == null)
|
||||||
|
ptypes[i] = null;
|
||||||
|
else
|
||||||
|
ptypes[i] = pvalues[i].GetType();
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodInfo methodInfo = p.GetType().GetRuntimeMethod(Name, ptypes);
|
||||||
|
|
||||||
|
return methodInfo.Invoke(p, pvalues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Number : Eval
|
class Number : Eval
|
||||||
{
|
{
|
||||||
object value;
|
object value;
|
||||||
|
|
|
@ -70,7 +70,11 @@ namespace ln.templates
|
||||||
|
|
||||||
if (FrameExpression != null)
|
if (FrameExpression != null)
|
||||||
{
|
{
|
||||||
Template frame = context.Provider.FindTemplate(FrameExpression.Evaluate(null) as string);
|
Template frame = context.Provider.FindTemplate(FrameExpression.Evaluate(context.ExpressionContext) as string);
|
||||||
|
if (frame == null)
|
||||||
|
{
|
||||||
|
throw new NullReferenceException(String.Format("FindTemplate() returned null for {0}",FrameExpression.Source));
|
||||||
|
}
|
||||||
return frame.Generate(new Context(context, writer.ToString()));
|
return frame.Generate(new Context(context, writer.ToString()));
|
||||||
}
|
}
|
||||||
return writer.ToString();
|
return writer.ToString();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
namespace ln.templates
|
namespace ln.templates
|
||||||
{
|
{
|
||||||
public abstract class TemplateProvider
|
public interface TemplateProvider
|
||||||
{
|
{
|
||||||
public abstract Template FindTemplate(string templatePath);
|
Template FindTemplate(string templatePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ namespace ln.templates
|
||||||
{
|
{
|
||||||
t = Source;
|
t = Source;
|
||||||
op = null;
|
op = null;
|
||||||
|
Source = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Web" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
Loading…
Reference in New Issue