From fada8eea237f9206ad8714b613ca40df294da19c Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Thu, 14 Feb 2019 16:44:33 +0100 Subject: [PATCH] WIP --- Expression.cs | 175 ++++++++++++++++++++++++++++++++++---------- Template.cs | 6 +- TemplateProvider.cs | 4 +- TemplateReader.cs | 1 + ln.templates.csproj | 1 - 5 files changed, 146 insertions(+), 41 deletions(-) diff --git a/Expression.cs b/Expression.cs index d2a731f..b35a72d 100644 --- a/Expression.cs +++ b/Expression.cs @@ -3,6 +3,8 @@ using System.Reflection; using System.IO; using System.Text; using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; namespace ln.templates { delegate bool ConditionDelegate(char ch); @@ -34,54 +36,99 @@ namespace ln.templates private void Compile() { - StringReader reader = new StringReader(Source); - List tokens = new List(); - while (reader.Peek() != -1) - ReadToken(reader, tokens); - TopEval = BuildEval(tokens); + try + { + StringReader reader = new StringReader(Source); + List tokens = new List(); + while (reader.Peek() != -1) + ReadToken(reader, tokens); + + Queue qtokens = new Queue(tokens); + + TopEval = BuildExpression(qtokens); + } catch (Exception e) + { + throw new Exception(String.Format("Failed to compile expression: {0}", Source), e); + } } - private Eval BuildEval(List tokens) + + private Eval BuildName(Token nameToken,Eval parent,Queue tokens) { - Eval currentEval = null; + if ((tokens.Count > 0) && (tokens.Peek().TokenType == TokenType.OPENLIST)) + { + tokens.Dequeue(); + + List pl = new List(); + 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 tokens) + { + Eval currentEval = BuildName(tokens.Dequeue(), null, tokens); while (tokens.Count > 0) { - Token token = tokens[0]; - tokens.RemoveAt(0); - + Token token = tokens.Peek(); switch (token.TokenType) { case TokenType.DOT: - token = tokens[0]; - tokens.RemoveAt(0); - if (token.TokenType != TokenType.NAME) - throw new ArgumentException("missing fieldname after ."); - currentEval = new Name(currentEval, token.Value); + tokens.Dequeue(); + currentEval = BuildName(tokens.Dequeue(), currentEval, tokens); break; - case TokenType.NAME: - currentEval = new Name(currentEval, token.Value); - break; - case TokenType.NUMBER: - currentEval = new Number(token.Value); - break; - case TokenType.STRING: - 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; - } + case TokenType.OPENINDEXER: + tokens.Dequeue(); + Eval index = BuildExpression(tokens); + token = tokens.Dequeue(); + if (token.TokenType != TokenType.ENDINDEXER) + throw new FormatException("Expected ']'"); + currentEval = new Indexer(currentEval, index); break; + default: + return currentEval; } } return currentEval; } + + private Eval BuildExpression(Queue 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 tokens) { if (reader.Peek() == -1) @@ -91,7 +138,7 @@ namespace ln.templates { reader.Read(); } - else if (char.IsLetter(ch)) + else if (char.IsLetter(ch) || (ch == '_')) { ReadName(reader, tokens); } @@ -108,10 +155,30 @@ namespace ln.templates reader.Read(); tokens.Add(new Token(TokenType.DOT, ".")); } - else if ((ch == '[')| (ch == ']')) + else if (ch == '[') { 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 { @@ -122,7 +189,7 @@ namespace ln.templates { StringBuilder sb = new StringBuilder(); int ch = 0; - while (char.IsLetterOrDigit((char)(ch = reader.Peek()))) + while (char.IsLetterOrDigit((char)(ch = reader.Peek())) || (ch == '_')) { 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 { 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 -