Initial project's source code check-in.
This commit is contained in:
commit
b03b0b373f
4573 changed files with 981205 additions and 0 deletions
|
@ -0,0 +1,165 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class BinaryExpression : Expression
|
||||
{
|
||||
Expression lhs;
|
||||
Expression rhs;
|
||||
TokenType op;
|
||||
|
||||
public BinaryExpression(int line, int column, Expression lhs, TokenType op, Expression rhs)
|
||||
: base(line, column)
|
||||
{
|
||||
this.lhs = lhs;
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
public TokenType Operator
|
||||
{
|
||||
get { return op; }
|
||||
}
|
||||
|
||||
Expression LeftExpression
|
||||
{
|
||||
get { return lhs; }
|
||||
set { lhs = value; }
|
||||
}
|
||||
|
||||
Expression RightExpression
|
||||
{
|
||||
get { return rhs; }
|
||||
set { rhs = value; }
|
||||
}
|
||||
|
||||
public override object Eval(TemplateContext context)
|
||||
{
|
||||
// evaluate both parts
|
||||
object lv = LeftExpression.Eval(context);
|
||||
object rv = RightExpression.Eval(context);
|
||||
|
||||
// equality/not-equality
|
||||
if (op == TokenType.Equal)
|
||||
{
|
||||
if (lv == null && rv == null)
|
||||
return true;
|
||||
else if (lv != null)
|
||||
return lv.Equals(rv);
|
||||
}
|
||||
else if (op == TokenType.NotEqual)
|
||||
{
|
||||
if (lv == null && rv == null)
|
||||
return false;
|
||||
else if (lv != null)
|
||||
return !lv.Equals(rv);
|
||||
}
|
||||
|
||||
// arithmetic operation
|
||||
else if (op == TokenType.Mult
|
||||
|| op == TokenType.Div
|
||||
|| op == TokenType.Mod
|
||||
|| op == TokenType.Plus
|
||||
|| op == TokenType.Minus
|
||||
|| op == TokenType.Less
|
||||
|| op == TokenType.LessOrEqual
|
||||
|| op == TokenType.Greater
|
||||
|| op == TokenType.GreaterOrEqual)
|
||||
{
|
||||
if(!((lv is Decimal || lv is Int32) && (rv is Decimal || rv is Int32)))
|
||||
throw new ParserException("Arithmetic and logical operations can be applied to operands or integer and decimal types only.",
|
||||
Line, Column);
|
||||
|
||||
|
||||
bool dec = lv is Decimal || rv is Decimal;
|
||||
object val = null;
|
||||
if(op == TokenType.Mult)
|
||||
val = dec ? (Decimal)lv * (Decimal)rv : (Int32)lv * (Int32)rv;
|
||||
else if (op == TokenType.Div)
|
||||
val = dec ? (Decimal)lv / (Decimal)rv : (Int32)lv / (Int32)rv;
|
||||
else if (op == TokenType.Mod)
|
||||
val = dec ? (Decimal)lv % (Decimal)rv : (Int32)lv % (Int32)rv;
|
||||
else if (op == TokenType.Plus)
|
||||
val = dec ? (Decimal)lv + (Decimal)rv : (Int32)lv + (Int32)rv;
|
||||
else if (op == TokenType.Minus)
|
||||
val = dec ? (Decimal)lv - (Decimal)rv : (Int32)lv - (Int32)rv;
|
||||
else if (op == TokenType.Less)
|
||||
val = dec ? (Decimal)lv < (Decimal)rv : (Int32)lv < (Int32)rv;
|
||||
else if (op == TokenType.LessOrEqual)
|
||||
val = dec ? (Decimal)lv <= (Decimal)rv : (Int32)lv <= (Int32)rv;
|
||||
else if (op == TokenType.Greater)
|
||||
val = dec ? (Decimal)lv > (Decimal)rv : (Int32)lv > (Int32)rv;
|
||||
else if (op == TokenType.GreaterOrEqual)
|
||||
val = dec ? (Decimal)lv >= (Decimal)rv : (Int32)lv >= (Int32)rv;
|
||||
|
||||
if (val is Boolean)
|
||||
{
|
||||
bool ret = Convert.ToBoolean(val);
|
||||
return ret;
|
||||
}
|
||||
else if (dec)
|
||||
{
|
||||
decimal ret = Convert.ToDecimal(val);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret = Convert.ToInt32(val);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else if (op == TokenType.Or || op == TokenType.And)
|
||||
{
|
||||
if (!(lv is Boolean && rv is Boolean))
|
||||
throw new ParserException("Logical operation can be applied to operands of boolean type only", Line, Column);
|
||||
|
||||
if (op == TokenType.Or)
|
||||
return (Boolean)lv || (Boolean)rv;
|
||||
else if (op == TokenType.And)
|
||||
return (Boolean)lv && (Boolean)rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("(")
|
||||
.Append(LeftExpression.ToString()).Append(" ")
|
||||
.Append(Operator).Append(" ")
|
||||
.Append(RightExpression.ToString()).Append(")");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class CallTemplateStatement : Statement
|
||||
{
|
||||
public string templateName;
|
||||
public Dictionary<string, Expression> parameters = new Dictionary<string, Expression>();
|
||||
List<Statement> statements = new List<Statement>();
|
||||
|
||||
public CallTemplateStatement(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public string TemplateName
|
||||
{
|
||||
get { return templateName; }
|
||||
set { templateName = value; }
|
||||
}
|
||||
|
||||
public Dictionary<string, Expression> Parameters
|
||||
{
|
||||
get { return parameters; }
|
||||
}
|
||||
|
||||
public List<Statement> Statements
|
||||
{
|
||||
get { return statements; }
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
// locate template
|
||||
if (!context.Templates.ContainsKey(templateName))
|
||||
throw new ParserException(String.Format("Custom template \"{0}\" is not defined", templateName), Line, Column);
|
||||
|
||||
TemplateStatement tmp = context.Templates[templateName];
|
||||
|
||||
// create template-specific context
|
||||
TemplateContext tmpContext = new TemplateContext();
|
||||
tmpContext.ParentContext = context;
|
||||
tmpContext.Templates = context.Templates;
|
||||
|
||||
// evaluate inner statements
|
||||
StringWriter innerWriter = new StringWriter();
|
||||
foreach (Statement stm in Statements)
|
||||
stm.Eval(context, innerWriter);
|
||||
tmpContext.Variables["innerText"] = innerWriter.ToString();
|
||||
|
||||
// set context variables
|
||||
foreach (string name in parameters.Keys)
|
||||
tmpContext.Variables[name] = parameters[name].Eval(context);
|
||||
|
||||
// evaluate template statements
|
||||
foreach (Statement stm in tmp.Statements)
|
||||
stm.Eval(tmpContext, writer);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{").Append(templateName);
|
||||
|
||||
foreach (string name in parameters.Keys)
|
||||
sb.Append(" ").Append(name).Append("=\"").Append(parameters[name].ToString()).Append("\"");
|
||||
|
||||
sb.Append(" /}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class ElseIfStatement : Statement
|
||||
{
|
||||
Expression condition;
|
||||
List<Statement> trueStatements = new List<Statement>();
|
||||
|
||||
public ElseIfStatement(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public Expression Condition
|
||||
{
|
||||
get { return condition; }
|
||||
set { condition = value; }
|
||||
}
|
||||
|
||||
public List<Statement> TrueStatements
|
||||
{
|
||||
get { return trueStatements; }
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
foreach (Statement stm in TrueStatements)
|
||||
stm.Eval(context, writer);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{elseif ")
|
||||
.Append(Condition.ToString()).Append("}");
|
||||
foreach (Statement stm in TrueStatements)
|
||||
{
|
||||
sb.Append(stm);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal abstract class Expression
|
||||
{
|
||||
int line;
|
||||
int column;
|
||||
|
||||
public Expression(int line, int column)
|
||||
{
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public int Line
|
||||
{
|
||||
get { return line; }
|
||||
}
|
||||
|
||||
public int Column
|
||||
{
|
||||
get { return column; }
|
||||
}
|
||||
|
||||
public abstract object Eval(TemplateContext context);
|
||||
}
|
||||
}
|
118
WebsitePanel/Sources/WebsitePanel.Templates/AST/ForStatement.cs
Normal file
118
WebsitePanel/Sources/WebsitePanel.Templates/AST/ForStatement.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class ForStatement : Statement
|
||||
{
|
||||
string indexIdentifier;
|
||||
Expression startIndex;
|
||||
Expression endIndex;
|
||||
List<Statement> statements = new List<Statement>();
|
||||
|
||||
public ForStatement(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public string IndexIdentifier
|
||||
{
|
||||
get { return indexIdentifier; }
|
||||
set { indexIdentifier = value; }
|
||||
}
|
||||
|
||||
public Expression StartIndex
|
||||
{
|
||||
get { return startIndex; }
|
||||
set { startIndex = value; }
|
||||
}
|
||||
|
||||
public Expression EndIndex
|
||||
{
|
||||
get { return endIndex; }
|
||||
set { endIndex = value; }
|
||||
}
|
||||
|
||||
public List<Statement> Statements
|
||||
{
|
||||
get { return statements; }
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
// evaluate indicies
|
||||
object objStartIdx = StartIndex.Eval(context);
|
||||
object objEndIdx = EndIndex.Eval(context);
|
||||
|
||||
// check indicies
|
||||
if (!(objStartIdx is Int32))
|
||||
throw new ParserException("Start index expression should evaluate to integer.", StartIndex.Line, StartIndex.Column);
|
||||
if (!(objEndIdx is Int32))
|
||||
throw new ParserException("End index expression should evaluate to integer.", StartIndex.Line, StartIndex.Column);
|
||||
|
||||
int startIdx = Convert.ToInt32(objStartIdx);
|
||||
int endIdx = Convert.ToInt32(objEndIdx);
|
||||
int step = startIdx < endIdx ? 1 : -1;
|
||||
endIdx += step;
|
||||
|
||||
int i = startIdx;
|
||||
do
|
||||
{
|
||||
context.Variables[IndexIdentifier] = i;
|
||||
|
||||
// evaluate statements
|
||||
foreach (Statement stm in Statements)
|
||||
stm.Eval(context, writer);
|
||||
|
||||
i += step;
|
||||
}
|
||||
while (i != endIdx);
|
||||
|
||||
// cleanup vars
|
||||
context.Variables.Remove(IndexIdentifier);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{for ")
|
||||
.Append(IndexIdentifier).Append(" = ")
|
||||
.Append(StartIndex).Append(" to ").Append(EndIndex).Append("}");
|
||||
foreach (Statement stm in Statements)
|
||||
{
|
||||
sb.Append(stm);
|
||||
}
|
||||
sb.Append("{/for}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class ForeachStatement : Statement
|
||||
{
|
||||
string elementIdentifier;
|
||||
string indexIdentifier;
|
||||
Expression collection;
|
||||
List<Statement> statements = new List<Statement>();
|
||||
|
||||
public ForeachStatement(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public string ElementIdentifier
|
||||
{
|
||||
get { return elementIdentifier; }
|
||||
set { elementIdentifier = value; }
|
||||
}
|
||||
|
||||
public string IndexIdentifier
|
||||
{
|
||||
get { return indexIdentifier; }
|
||||
set { indexIdentifier = value; }
|
||||
}
|
||||
|
||||
public Expression Collection
|
||||
{
|
||||
get { return collection; }
|
||||
set { collection = value; }
|
||||
}
|
||||
|
||||
public List<Statement> Statements
|
||||
{
|
||||
get { return statements; }
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
// evaluate collection expression
|
||||
object coll = Collection.Eval(context);
|
||||
if(!(coll is IEnumerable))
|
||||
throw new ParserException("Collection expression should evaluate into the value implementing IEnumerable interface.",
|
||||
Collection.Line, Collection.Column);
|
||||
|
||||
int idx = 0;
|
||||
foreach(object obj in ((IEnumerable)coll))
|
||||
{
|
||||
context.Variables[ElementIdentifier] = obj;
|
||||
if(IndexIdentifier != null)
|
||||
context.Variables[IndexIdentifier] = idx;
|
||||
idx++;
|
||||
|
||||
// evaluate statements
|
||||
foreach(Statement stm in Statements)
|
||||
stm.Eval(context, writer);
|
||||
}
|
||||
|
||||
// cleanup context
|
||||
context.Variables.Remove(ElementIdentifier);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{foreach ")
|
||||
.Append(ElementIdentifier).Append(" in ").Append(Collection);
|
||||
if (IndexIdentifier != null)
|
||||
sb.Append(" index ").Append(IndexIdentifier);
|
||||
sb.Append("}");
|
||||
foreach (Statement stm in Statements)
|
||||
{
|
||||
sb.Append(stm);
|
||||
}
|
||||
sb.Append("{/foreach}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class IdentifierExpression : Expression
|
||||
{
|
||||
List<IdentifierPart> parts = new List<IdentifierPart>();
|
||||
|
||||
public IdentifierExpression(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public List<IdentifierPart> Parts
|
||||
{
|
||||
get { return parts; }
|
||||
}
|
||||
|
||||
public override object Eval(TemplateContext context)
|
||||
{
|
||||
object val = null;
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
// get variable from context
|
||||
if (i == 0 && !parts[i].IsMethod)
|
||||
{
|
||||
val = EvalContextVariable(parts[i], context);
|
||||
}
|
||||
// call built-in function
|
||||
else if (i == 0 && parts[i].IsMethod)
|
||||
{
|
||||
BuiltinFunctions target = new BuiltinFunctions();
|
||||
target.Context = context;
|
||||
target.Line = parts[i].Line;
|
||||
target.Column = parts[i].Column;
|
||||
val = EvalMethod(target, parts[i], context);
|
||||
}
|
||||
// call public property
|
||||
else if(i > 0 && !parts[i].IsMethod) // property
|
||||
{
|
||||
val = EvalProperty(val, parts[i], context);
|
||||
}
|
||||
// call public method
|
||||
else if (i > 0 && parts[i].IsMethod) // property
|
||||
{
|
||||
val = EvalMethod(val, parts[i], context);
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private object EvalContextVariable(IdentifierPart variable, TemplateContext context)
|
||||
{
|
||||
object val = null;
|
||||
TemplateContext lookupContext = context;
|
||||
|
||||
while (lookupContext != null)
|
||||
{
|
||||
if (lookupContext.Variables.ContainsKey(variable.Name))
|
||||
{
|
||||
val = lookupContext.Variables[variable.Name];
|
||||
break; // found local scope var - stop looking
|
||||
}
|
||||
|
||||
// look into parent scope
|
||||
lookupContext = lookupContext.ParentContext;
|
||||
}
|
||||
|
||||
// get from context
|
||||
if (val == null)
|
||||
return null;
|
||||
|
||||
// evaluate index expression if required
|
||||
val = EvalIndexer(val, variable, context);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private object EvalIndexer(object target, IdentifierPart indexer, TemplateContext context)
|
||||
{
|
||||
if (indexer.Index == null)
|
||||
return target;
|
||||
|
||||
object index = null;
|
||||
index = indexer.Index.Eval(context);
|
||||
|
||||
if (index == null)
|
||||
throw new ParserException("Indexer expression evaluated to NULL", Line, Column);
|
||||
|
||||
if (target == null)
|
||||
throw new ParserException("Cannot call indexer on NULL object", Line, Column);
|
||||
|
||||
// get from index if required
|
||||
if(target is IDictionary)
|
||||
{
|
||||
// dictionary
|
||||
return ((IDictionary)target)[index];
|
||||
}
|
||||
else if (target is Array)
|
||||
{
|
||||
// array
|
||||
if(index is Int32)
|
||||
return ((Array)target).GetValue((Int32)index);
|
||||
else
|
||||
throw new ParserException("Array index expression must evaluate to integer.", Line, Column);
|
||||
}
|
||||
else if (target is IList)
|
||||
{
|
||||
// list
|
||||
if(index is Int32)
|
||||
return ((IList)target)[(Int32)index];
|
||||
else
|
||||
throw new ParserException("IList index expression must evaluate to integer.", Line, Column);
|
||||
}
|
||||
else
|
||||
{
|
||||
// call "get_Item" method
|
||||
MethodInfo methodInfo = target.GetType().GetMethod("get_Item",
|
||||
BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
|
||||
if (methodInfo != null)
|
||||
return methodInfo.Invoke(target, new object[] { index });
|
||||
}
|
||||
throw new ParserException("Cannot call indexer", Line, Column);
|
||||
}
|
||||
|
||||
private object EvalProperty(object target, IdentifierPart property, TemplateContext context)
|
||||
{
|
||||
object val = target;
|
||||
|
||||
// check for null
|
||||
if (val == null)
|
||||
throw new ParserException("Cannot read property value of NULL object", Line, Column);
|
||||
|
||||
// get property
|
||||
string propName = property.Name;
|
||||
PropertyInfo prop = val.GetType().GetProperty(propName,
|
||||
BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
if (prop == null)
|
||||
{
|
||||
// build the list of available properties
|
||||
StringBuilder propsList = new StringBuilder();
|
||||
int vi = 0;
|
||||
PropertyInfo[] props = val.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
||||
foreach (PropertyInfo p in props)
|
||||
{
|
||||
if (vi++ > 0)
|
||||
propsList.Append(",");
|
||||
propsList.Append(p.Name);
|
||||
}
|
||||
throw new ParserException("Public property could not be found: " + propName + "."
|
||||
+ " Supported properties: " + propsList.ToString(), Line, Column);
|
||||
}
|
||||
|
||||
// read property
|
||||
try
|
||||
{
|
||||
val = prop.GetValue(val, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ParserException("Cannot read property value: " + ex.Message, Line, Column);
|
||||
}
|
||||
|
||||
// evaluate index expression if required
|
||||
val = EvalIndexer(val, property, context);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private object EvalMethod(object target, IdentifierPart method, TemplateContext context)
|
||||
{
|
||||
object val = target;
|
||||
|
||||
// check for null
|
||||
if (val == null)
|
||||
throw new ParserException("Cannot perform method of NULL object", Line, Column);
|
||||
|
||||
// evaluate method parameters
|
||||
object[] prms = new object[method.MethodParameters.Count];
|
||||
Type[] prmTypes = new Type[method.MethodParameters.Count];
|
||||
|
||||
for (int i = 0; i < prms.Length; i++)
|
||||
{
|
||||
prms[i] = method.MethodParameters[i].Eval(context);
|
||||
if (prms[i] != null)
|
||||
prmTypes[i] = prms[i].GetType();
|
||||
else
|
||||
prmTypes[i] = typeof(object); // "null" parameter was specified
|
||||
}
|
||||
|
||||
// find method
|
||||
string methodName = method.Name;
|
||||
MethodInfo methodInfo = val.GetType().GetMethod(methodName,
|
||||
BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public,
|
||||
null, prmTypes, null);
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
// failed to find exact signature
|
||||
// try to iterate
|
||||
methodInfo = val.GetType().GetMethod(methodName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
|
||||
}
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
// build the list of available methods
|
||||
StringBuilder methodsList = new StringBuilder();
|
||||
int vi = 0;
|
||||
MethodInfo[] methods = val.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
|
||||
foreach (MethodInfo mi in methods)
|
||||
{
|
||||
if (vi++ > 0)
|
||||
methodsList.Append(",");
|
||||
methodsList.Append(mi.Name);
|
||||
}
|
||||
throw new ParserException("Public method could not be found: " + methodName + "."
|
||||
+ " Available methods: " + methodsList.ToString(), Line, Column);
|
||||
}
|
||||
|
||||
// call method
|
||||
try
|
||||
{
|
||||
val = methodInfo.Invoke(val, prms);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ParserException("Cannot call method: " + ex.Message, Line, Column);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < Parts.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
sb.Append(".");
|
||||
sb.Append(Parts[i]);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class IdentifierPart
|
||||
{
|
||||
string name;
|
||||
Expression index;
|
||||
bool isMethod;
|
||||
List<Expression> methodParameters = new List<Expression>();
|
||||
int line;
|
||||
int column;
|
||||
|
||||
public IdentifierPart(string name, int line, int column)
|
||||
{
|
||||
this.name = name;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
public Expression Index
|
||||
{
|
||||
get { return index; }
|
||||
set { index = value; }
|
||||
}
|
||||
|
||||
public bool IsMethod
|
||||
{
|
||||
get { return isMethod; }
|
||||
set { isMethod = value; }
|
||||
}
|
||||
|
||||
public List<Expression> MethodParameters
|
||||
{
|
||||
get { return methodParameters; }
|
||||
}
|
||||
|
||||
public int Line
|
||||
{
|
||||
get { return line; }
|
||||
}
|
||||
|
||||
public int Column
|
||||
{
|
||||
get { return column; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(name);
|
||||
if (Index != null)
|
||||
sb.Append("[").Append(Index).Append("]");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
138
WebsitePanel/Sources/WebsitePanel.Templates/AST/IfStatement.cs
Normal file
138
WebsitePanel/Sources/WebsitePanel.Templates/AST/IfStatement.cs
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class IfStatement : Statement
|
||||
{
|
||||
Expression condition;
|
||||
List<ElseIfStatement> elseIfStatements = new List<ElseIfStatement>();
|
||||
List<Statement> trueStatements = new List<Statement>();
|
||||
List<Statement> falseStatements = new List<Statement>();
|
||||
|
||||
public IfStatement(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public Expression Condition
|
||||
{
|
||||
get { return condition; }
|
||||
set { condition = value; }
|
||||
}
|
||||
|
||||
public List<ElseIfStatement> ElseIfStatements
|
||||
{
|
||||
get { return elseIfStatements; }
|
||||
}
|
||||
|
||||
public List<Statement> TrueStatements
|
||||
{
|
||||
get { return trueStatements; }
|
||||
}
|
||||
|
||||
public List<Statement> FalseStatements
|
||||
{
|
||||
get { return falseStatements; }
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
// evaluate test condition
|
||||
bool result = EvalCondition(Condition, context);
|
||||
|
||||
if (result)
|
||||
{
|
||||
foreach (Statement stm in TrueStatements)
|
||||
stm.Eval(context, writer);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// process else if statements
|
||||
foreach (ElseIfStatement stm in ElseIfStatements)
|
||||
{
|
||||
if (EvalCondition(stm.Condition, context))
|
||||
{
|
||||
stm.Eval(context, writer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// process else
|
||||
foreach (Statement stm in FalseStatements)
|
||||
stm.Eval(context, writer);
|
||||
}
|
||||
}
|
||||
|
||||
private bool EvalCondition(Expression expr, TemplateContext context)
|
||||
{
|
||||
object val = expr.Eval(context);
|
||||
if (val is Boolean)
|
||||
return (Boolean)val;
|
||||
else if (val is Int32)
|
||||
return ((Int32)val) != 0;
|
||||
else if (val is Decimal)
|
||||
return ((Decimal)val) != 0;
|
||||
else if (val != null)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{if ")
|
||||
.Append(Condition.ToString()).Append("}");
|
||||
|
||||
// true statements
|
||||
foreach (Statement stm in TrueStatements)
|
||||
sb.Append(stm);
|
||||
|
||||
// elseif statements
|
||||
foreach (Statement stm in ElseIfStatements)
|
||||
sb.Append(stm);
|
||||
|
||||
// false statements
|
||||
if(FalseStatements.Count > 0)
|
||||
{
|
||||
sb.Append("{else}");
|
||||
foreach (Statement stm in FalseStatements)
|
||||
sb.Append(stm);
|
||||
}
|
||||
|
||||
sb.Append("{/if}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class LiteralExpression : Expression
|
||||
{
|
||||
object val;
|
||||
|
||||
public LiteralExpression(int line, int column, object val)
|
||||
: base(line, column)
|
||||
{
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public object Value
|
||||
{
|
||||
get { return val; }
|
||||
set { val = value; }
|
||||
}
|
||||
|
||||
public override object Eval(TemplateContext context)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return val != null ? val.ToString() : "null";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class PrintStatement : Statement
|
||||
{
|
||||
Expression printExpression;
|
||||
string formatter;
|
||||
|
||||
public PrintStatement(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public Expression PrintExpression
|
||||
{
|
||||
get { return printExpression; }
|
||||
set { printExpression = value; }
|
||||
}
|
||||
|
||||
public string Formatter
|
||||
{
|
||||
get { return formatter; }
|
||||
set { formatter = value; }
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
writer.Write(PrintExpression.Eval(context));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return printExpression.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class SetStatement : Statement
|
||||
{
|
||||
Expression valueExpression;
|
||||
string name;
|
||||
|
||||
public SetStatement(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public Expression ValueExpression
|
||||
{
|
||||
get { return valueExpression; }
|
||||
set { valueExpression = value; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
set { name = value; }
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
context.Variables[Name] = ValueExpression.Eval(context);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{set name=\"")
|
||||
.Append(Name).Append("\" value=\"")
|
||||
.Append(ValueExpression.ToString())
|
||||
.Append("\"/}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
59
WebsitePanel/Sources/WebsitePanel.Templates/AST/Statement.cs
Normal file
59
WebsitePanel/Sources/WebsitePanel.Templates/AST/Statement.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal abstract class Statement
|
||||
{
|
||||
int line;
|
||||
int column;
|
||||
|
||||
public Statement(int line, int column)
|
||||
{
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public int Line
|
||||
{
|
||||
get { return line; }
|
||||
}
|
||||
|
||||
public int Column
|
||||
{
|
||||
get { return column; }
|
||||
}
|
||||
|
||||
public abstract void Eval(TemplateContext context, StringWriter writer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class TemplateStatement : Statement
|
||||
{
|
||||
public string name;
|
||||
List<Statement> statements = new List<Statement>();
|
||||
|
||||
public TemplateStatement(int line, int column)
|
||||
: base(line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
set { name = value; }
|
||||
}
|
||||
|
||||
public List<Statement> Statements
|
||||
{
|
||||
get { return statements; }
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{template ")
|
||||
.Append("name=\"").Append(Name).Append("\"}");
|
||||
foreach (Statement stm in Statements)
|
||||
{
|
||||
sb.Append(stm);
|
||||
}
|
||||
sb.Append("{/template}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class TextStatement : Statement
|
||||
{
|
||||
string text;
|
||||
|
||||
public TextStatement(string text, int line, int column) : base(line, column)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public override void Eval(TemplateContext context, System.IO.StringWriter writer)
|
||||
{
|
||||
writer.Write(text);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates.AST
|
||||
{
|
||||
internal class UnaryExpression : Expression
|
||||
{
|
||||
Expression rhs;
|
||||
TokenType op;
|
||||
|
||||
public UnaryExpression(int line, int column, TokenType op, Expression rhs)
|
||||
: base(line, column)
|
||||
{
|
||||
this.op = op;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
public TokenType Operator
|
||||
{
|
||||
get { return op; }
|
||||
}
|
||||
|
||||
Expression RightExpression
|
||||
{
|
||||
get { return rhs; }
|
||||
set { rhs = value; }
|
||||
}
|
||||
|
||||
public override object Eval(TemplateContext context)
|
||||
{
|
||||
// evaluate right side
|
||||
object val = rhs.Eval(context);
|
||||
|
||||
if (op == TokenType.Minus && val is Decimal)
|
||||
return -(Decimal)val;
|
||||
else if (op == TokenType.Minus && val is Int32)
|
||||
return -(Int32)val;
|
||||
else if (op == TokenType.Not && val is Boolean)
|
||||
return !(Boolean)val;
|
||||
|
||||
throw new ParserException("Unary operator can be applied to integer, decimal and boolean expressions.", Line, Column);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(Operator).Append("(").Append(RightExpression).Append(")");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
248
WebsitePanel/Sources/WebsitePanel.Templates/BuiltinFunctions.cs
Normal file
248
WebsitePanel/Sources/WebsitePanel.Templates/BuiltinFunctions.cs
Normal file
|
@ -0,0 +1,248 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
internal class BuiltinFunctions
|
||||
{
|
||||
public int Line { get; set; }
|
||||
public int Column { get; set; }
|
||||
public TemplateContext Context { get; set; }
|
||||
|
||||
public bool IsDefined(string variable)
|
||||
{
|
||||
return Context.Variables.ContainsKey(variable);
|
||||
}
|
||||
|
||||
public object IfDefined(string variable, object val)
|
||||
{
|
||||
return IsDefined(variable) ? val : "";
|
||||
}
|
||||
|
||||
public new bool Equals(object objA, object objB)
|
||||
{
|
||||
return Object.Equals(objA, objB);
|
||||
}
|
||||
|
||||
public bool NotEquals(object objA, object objB)
|
||||
{
|
||||
return !Equals(objA, objB);
|
||||
}
|
||||
|
||||
public bool IsEven(object number)
|
||||
{
|
||||
try
|
||||
{
|
||||
Int32 num = Convert.ToInt32(number);
|
||||
return num % 2 == 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new ParserException("Cannot convert IsEven() function parameter to integer", Line, Column);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOdd(object number)
|
||||
{
|
||||
try
|
||||
{
|
||||
Int32 num = Convert.ToInt32(number);
|
||||
return num % 2 == 1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new ParserException("Cannot convert IsOdd() function parameter to integer", Line, Column);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEmpty(string str)
|
||||
{
|
||||
return String.IsNullOrEmpty(str);
|
||||
}
|
||||
|
||||
public bool IsNotEmpty(string str)
|
||||
{
|
||||
return !IsEmpty(str);
|
||||
}
|
||||
|
||||
public bool IsNumber(object val)
|
||||
{
|
||||
try
|
||||
{
|
||||
int number = Convert.ToInt32(val);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string ToUpper(string str)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
return str.ToUpper();
|
||||
}
|
||||
|
||||
public string ToLower(string str)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
return str.ToLower();
|
||||
}
|
||||
|
||||
public int Len(string str)
|
||||
{
|
||||
return String.IsNullOrEmpty(str) ? 0 : str.Length;
|
||||
}
|
||||
|
||||
public string ToList(object collection, string propertyName, string delimiter)
|
||||
{
|
||||
IEnumerable list = collection as IEnumerable;
|
||||
if (list == null)
|
||||
throw new ParserException("Supplied collection must implement IEnumerable", Line, Column);
|
||||
|
||||
// get property descriptor
|
||||
List<string> items = new List<string>();
|
||||
foreach (object item in list)
|
||||
{
|
||||
PropertyInfo prop = null;
|
||||
if(!String.IsNullOrEmpty(propertyName))
|
||||
{
|
||||
prop = item.GetType().GetProperty(propertyName,
|
||||
BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
|
||||
}
|
||||
|
||||
if (prop != null)
|
||||
items.Add(prop.GetValue(item, null).ToString());
|
||||
else
|
||||
items.Add(item.ToString());
|
||||
}
|
||||
return String.Join(delimiter, items.ToArray());
|
||||
}
|
||||
|
||||
public bool IsNull(object val)
|
||||
{
|
||||
return val == null;
|
||||
}
|
||||
|
||||
public object IIf(bool condition, object trueValue, object falseValue)
|
||||
{
|
||||
return condition ? trueValue : falseValue;
|
||||
}
|
||||
|
||||
public object Format(object val, string format)
|
||||
{
|
||||
if (val == null || !(val is IFormattable))
|
||||
return val;
|
||||
|
||||
if (val is Int32)
|
||||
return ((Int32)val).ToString(format);
|
||||
else if (val is Decimal)
|
||||
return ((Decimal)val).ToString(format);
|
||||
else
|
||||
return val.ToString();
|
||||
}
|
||||
|
||||
public string Trim(string str)
|
||||
{
|
||||
return str != null ? str.Trim() : null;
|
||||
}
|
||||
|
||||
public int Compare(object obj1, object obj2)
|
||||
{
|
||||
if (obj1 == null || obj2 == null)
|
||||
throw new ParserException("Function argument cannot be NULL", Line, Column);
|
||||
|
||||
if (!(obj1 is IComparable) || !(obj2 is IComparable))
|
||||
throw new ParserException("Function arguments must implement IComparable", Line, Column);
|
||||
|
||||
return ((IComparable)obj1).CompareTo(obj2);
|
||||
}
|
||||
|
||||
public bool CompareNoCase(string str1, string str2)
|
||||
{
|
||||
return String.Compare(str1, str2, true) == 0;
|
||||
}
|
||||
|
||||
public string StripNewLines(string str)
|
||||
{
|
||||
return str != null ? str.Replace("\r\n", " ") : null;
|
||||
}
|
||||
|
||||
public string TypeOf(object obj)
|
||||
{
|
||||
return obj != null ? obj.GetType().Name : null;
|
||||
}
|
||||
|
||||
public Int32 CInt(object val)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(val);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new ParserException("Value cannot be converted to Int32", Line, Column);
|
||||
}
|
||||
}
|
||||
|
||||
public Double CDouble(object val)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToDouble(val);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new ParserException("Value cannot be converted to Double", Line, Column);
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime CDate(object val)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToDateTime(val);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new ParserException("Value cannot be converted to DateTime", Line, Column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
708
WebsitePanel/Sources/WebsitePanel.Templates/Lexer.cs
Normal file
708
WebsitePanel/Sources/WebsitePanel.Templates/Lexer.cs
Normal file
|
@ -0,0 +1,708 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
internal class Lexer
|
||||
{
|
||||
// error codes
|
||||
const string LEXER_ERROR_UNEXPECTED_SYMBOL = "TEMPLATES_LEXER_UNEXPECTED_SYMBOL";
|
||||
const string LEXER_ERROR_UNKNOWN_ESCAPE = "TEMPLATES_LEXER_UNKNOWN_ESCAPE";
|
||||
const string LEXER_ERROR_UNTERMINATED_STRING = "TEMPLATES_LEXER_UNTERMINATED_STRING";
|
||||
const string LEXER_ERROR_UNKNOWN_CLOSING_TAG = "TEMPLATES_LEXER_UNKNOWN_TAG";
|
||||
|
||||
// other constants
|
||||
const char EOF = (char)0;
|
||||
|
||||
// private fields
|
||||
static Dictionary<string, TokenType> keywords;
|
||||
static Dictionary<string, TokenType> startTags;
|
||||
static Dictionary<string, TokenType> closingTags;
|
||||
string data;
|
||||
int pos;
|
||||
int column;
|
||||
int line;
|
||||
int savePos;
|
||||
int saveColumn;
|
||||
int saveLine;
|
||||
|
||||
bool printStart; // inside #...# print statement
|
||||
bool tagOpen;
|
||||
bool tagClose;
|
||||
bool tagBody; // inside <ad:.. > tag
|
||||
bool expressionBody; // inside #...# expression
|
||||
bool attributeBody; // inside "..." tag attribute
|
||||
|
||||
static Lexer()
|
||||
{
|
||||
keywords = new Dictionary<string, TokenType>(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
{"null", TokenType.Null},
|
||||
{"true", TokenType.True},
|
||||
{"false", TokenType.False},
|
||||
{"empty", TokenType.Empty},
|
||||
{"or", TokenType.Or},
|
||||
{"and", TokenType.And},
|
||||
{"not", TokenType.Not},
|
||||
{"is", TokenType.Equal},
|
||||
{"isnot", TokenType.NotEqual},
|
||||
{"lt", TokenType.Less},
|
||||
{"lte", TokenType.LessOrEqual},
|
||||
{"gt", TokenType.Greater},
|
||||
{"gte", TokenType.GreaterOrEqual}
|
||||
};
|
||||
|
||||
startTags = new Dictionary<string, TokenType>(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
{"if", TokenType.If},
|
||||
{"elseif", TokenType.ElseIf},
|
||||
{"else", TokenType.Else},
|
||||
{"foreach", TokenType.Foreach},
|
||||
{"for", TokenType.For},
|
||||
{"set", TokenType.Set},
|
||||
{"template", TokenType.Template},
|
||||
};
|
||||
|
||||
closingTags = new Dictionary<string, TokenType>(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
{"if", TokenType.EndIf},
|
||||
{"foreach", TokenType.EndForeach},
|
||||
{"for", TokenType.EndFor},
|
||||
{"template", TokenType.EndTemplate}
|
||||
};
|
||||
}
|
||||
|
||||
public Lexer(TextReader reader)
|
||||
{
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
this.data = reader.ReadToEnd();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public Lexer(string data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
|
||||
this.data = data;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
pos = 0;
|
||||
column = 1;
|
||||
line = 1;
|
||||
tagBody = false;
|
||||
}
|
||||
|
||||
public Token Next()
|
||||
{
|
||||
StartRead();
|
||||
|
||||
if (expressionBody)
|
||||
return ReadExpression();
|
||||
else if (tagOpen)
|
||||
return ReadStartTag();
|
||||
else if (tagClose)
|
||||
return ReadClosingTag();
|
||||
else if (tagBody)
|
||||
return ReadTagBody();
|
||||
else
|
||||
return ReadText();
|
||||
}
|
||||
|
||||
private Token ReadText()
|
||||
{
|
||||
StartRead();
|
||||
start:
|
||||
switch (LA(0))
|
||||
{
|
||||
case EOF:
|
||||
if (savePos == pos)
|
||||
return CreateToken(TokenType.EOF);
|
||||
else
|
||||
break;
|
||||
case '#':
|
||||
if (LA(1) == '#')
|
||||
{
|
||||
// ## escape
|
||||
Consume(2);
|
||||
goto start;
|
||||
}
|
||||
else if (printStart)
|
||||
{
|
||||
Consume(); // eat #
|
||||
printStart = false;
|
||||
expressionBody = true;
|
||||
return CreateToken(TokenType.Print);
|
||||
}
|
||||
else
|
||||
{
|
||||
// START reading "print" statement
|
||||
printStart = true;
|
||||
break;// return CreateToken(TokenType.Print);
|
||||
}
|
||||
case '<':
|
||||
if (LA(1) == 'a' && LA(2) == 'd' && LA(3) == ':')
|
||||
{
|
||||
// opening tag
|
||||
tagOpen = true;
|
||||
break;
|
||||
}
|
||||
else if (LA(1) == '/' && LA(2) == 'a' && LA(3) == 'd' && LA(4) == ':')
|
||||
{
|
||||
// closing tag
|
||||
tagClose = true;
|
||||
break;
|
||||
}
|
||||
Consume(); // eat <
|
||||
goto start;
|
||||
case '\n':
|
||||
case '\r':
|
||||
ReadWhitespace();
|
||||
goto start;
|
||||
default:
|
||||
Consume();
|
||||
goto start;
|
||||
}
|
||||
|
||||
return CreateToken(TokenType.Text);
|
||||
}
|
||||
|
||||
private Token ReadStartTag()
|
||||
{
|
||||
Consume(4); // eat "<ad:"
|
||||
tagOpen = false;
|
||||
tagBody = true;
|
||||
|
||||
// read tag name
|
||||
string name = ReadTagName();
|
||||
|
||||
// check for standard tags
|
||||
if (startTags.ContainsKey(name))
|
||||
return CreateToken(startTags[name], name);
|
||||
|
||||
return CreateToken(TokenType.OpenTag, name);
|
||||
}
|
||||
|
||||
private Token ReadClosingTag()
|
||||
{
|
||||
Consume(5); // eat "</ad:"
|
||||
tagClose = false;
|
||||
|
||||
// read tag name
|
||||
string name = ReadTagName();
|
||||
|
||||
if (LA(0) == '>')
|
||||
{
|
||||
Consume();
|
||||
if (closingTags.ContainsKey(name))
|
||||
return CreateToken(closingTags[name], name);
|
||||
else
|
||||
return CreateToken(TokenType.CloseTag, name);
|
||||
}
|
||||
|
||||
return CreateToken(TokenType.Text);
|
||||
}
|
||||
|
||||
private string ReadTagName()
|
||||
{
|
||||
int startPos = pos; // save current position
|
||||
|
||||
Consume(); // consume first character of the word
|
||||
|
||||
while (true)
|
||||
{
|
||||
char ch = LA(0);
|
||||
if (Char.IsLetterOrDigit(ch))
|
||||
Consume();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return data.Substring(startPos, pos - startPos);
|
||||
}
|
||||
|
||||
private Token ReadTagBody()
|
||||
{
|
||||
StartRead();
|
||||
start:
|
||||
char ch = LA(0);
|
||||
switch (ch)
|
||||
{
|
||||
case EOF:
|
||||
return CreateToken(TokenType.EOF);
|
||||
case '>':
|
||||
Consume();
|
||||
tagBody = false;
|
||||
return Next();
|
||||
case '=':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Assign);
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
ReadWhitespace();
|
||||
goto start;
|
||||
|
||||
case '"':
|
||||
if (attributeBody)
|
||||
{
|
||||
// end of attribute
|
||||
Consume(); // eat "
|
||||
attributeBody = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// start of attribute
|
||||
attributeBody = true;
|
||||
if (LA(1) == '#')
|
||||
{
|
||||
Consume(2); // eat "#
|
||||
expressionBody = true;
|
||||
return Next();
|
||||
}
|
||||
else
|
||||
{
|
||||
attributeBody = false;
|
||||
|
||||
if (Char.IsNumber(LA(1)))
|
||||
{
|
||||
Consume(); // eat "
|
||||
Token num = ReadNumber();
|
||||
Consume(); // eat "
|
||||
return num;
|
||||
}
|
||||
else
|
||||
return ReadString();
|
||||
}
|
||||
}
|
||||
goto start;
|
||||
case '\'':
|
||||
return ReadString();
|
||||
|
||||
default:
|
||||
if (ch == '/' && LA(1) == '>')
|
||||
{
|
||||
// "empty" tag
|
||||
Consume(2);
|
||||
tagBody = false;
|
||||
return CreateToken(TokenType.EmptyTag);
|
||||
}
|
||||
else if (Char.IsLetter(ch) || ch == '_')
|
||||
{
|
||||
return ReadAttribute();
|
||||
}
|
||||
else
|
||||
{
|
||||
string symbol = ch.ToString();
|
||||
ParserException ex = new ParserException(String.Format("Unexpected symbol: '{0}'", symbol),
|
||||
saveLine, saveColumn, pos, 1);
|
||||
ex.Data["code"] = LEXER_ERROR_UNEXPECTED_SYMBOL;
|
||||
ex.Data["symbol"] = symbol;
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Token ReadExpression()
|
||||
{
|
||||
StartRead();
|
||||
start:
|
||||
char ch = LA(0);
|
||||
switch (ch)
|
||||
{
|
||||
case EOF:
|
||||
return CreateToken(TokenType.EOF);
|
||||
case ':':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Colon);
|
||||
case '.':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Dot);
|
||||
case ',':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Comma);
|
||||
case '(':
|
||||
Consume();
|
||||
return CreateToken(TokenType.LParen);
|
||||
case ')':
|
||||
Consume();
|
||||
return CreateToken(TokenType.RParen);
|
||||
case '[':
|
||||
Consume();
|
||||
return CreateToken(TokenType.LBracket);
|
||||
case ']':
|
||||
Consume();
|
||||
return CreateToken(TokenType.RBracket);
|
||||
case '#': // end of expression
|
||||
Consume();
|
||||
printStart = false;
|
||||
expressionBody = false;
|
||||
return Next();
|
||||
case '+':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Plus);
|
||||
case '-':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Minus);
|
||||
case '*':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Mult);
|
||||
case '/':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Div);
|
||||
case '%':
|
||||
Consume();
|
||||
return CreateToken(TokenType.Mod);
|
||||
case '<':
|
||||
if (LA(1) == '=')
|
||||
{
|
||||
Consume(2);
|
||||
return CreateToken(TokenType.LessOrEqual);
|
||||
}
|
||||
else
|
||||
{
|
||||
Consume();
|
||||
return CreateToken(TokenType.Less);
|
||||
}
|
||||
case '>':
|
||||
if (LA(1) == '=')
|
||||
{
|
||||
Consume(2);
|
||||
return CreateToken(TokenType.GreaterOrEqual);
|
||||
}
|
||||
else
|
||||
{
|
||||
Consume();
|
||||
return CreateToken(TokenType.Greater);
|
||||
}
|
||||
case '=':
|
||||
if (LA(1) == '=')
|
||||
{
|
||||
Consume(2);
|
||||
return CreateToken(TokenType.Equal);
|
||||
}
|
||||
else
|
||||
{
|
||||
Consume();
|
||||
return CreateToken(TokenType.Assign);
|
||||
}
|
||||
case '!':
|
||||
if (LA(1) == '=')
|
||||
{
|
||||
Consume(2);
|
||||
return CreateToken(TokenType.NotEqual);
|
||||
}
|
||||
else
|
||||
{
|
||||
Consume();
|
||||
return CreateToken(TokenType.Not);
|
||||
}
|
||||
case '|':
|
||||
if (LA(1) == '|')
|
||||
{
|
||||
Consume(2);
|
||||
return CreateToken(TokenType.Or);
|
||||
}
|
||||
else
|
||||
{
|
||||
Consume();
|
||||
return CreateToken(TokenType.BinOr);
|
||||
}
|
||||
case '&':
|
||||
if (LA(1) == '&')
|
||||
{
|
||||
Consume(2);
|
||||
return CreateToken(TokenType.And);
|
||||
}
|
||||
else
|
||||
{
|
||||
Consume();
|
||||
return CreateToken(TokenType.BinAnd);
|
||||
}
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
ReadWhitespace();
|
||||
goto start;
|
||||
|
||||
case '"':
|
||||
case '\'':
|
||||
return ReadString();
|
||||
|
||||
default:
|
||||
if (Char.IsNumber(ch))
|
||||
return ReadNumber();
|
||||
else if (Char.IsLetter(ch) || ch == '_')
|
||||
return ReadIdentifier();
|
||||
else
|
||||
{
|
||||
string symbol = ch.ToString();
|
||||
ParserException ex = new ParserException(String.Format("Unexpected symbol: '{0}'", symbol),
|
||||
saveLine, saveColumn, pos, 1);
|
||||
ex.Data["code"] = LEXER_ERROR_UNEXPECTED_SYMBOL;
|
||||
ex.Data["symbol"] = symbol;
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Token ReadAttribute()
|
||||
{
|
||||
StartRead();
|
||||
|
||||
Consume(); // consume first character of the word
|
||||
|
||||
while (true)
|
||||
{
|
||||
char ch = LA(0);
|
||||
if (Char.IsLetterOrDigit(ch) || ch == '_')
|
||||
Consume();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
string tokenData = data.Substring(savePos, pos - savePos);
|
||||
return CreateToken(TokenType.Attribute, tokenData);
|
||||
}
|
||||
|
||||
private Token ReadIdentifier()
|
||||
{
|
||||
StartRead();
|
||||
|
||||
Consume(); // consume first character of the word
|
||||
|
||||
while (true)
|
||||
{
|
||||
char ch = LA(0);
|
||||
if (Char.IsLetterOrDigit(ch) || ch == '_')
|
||||
Consume();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
string tokenData = data.Substring(savePos, pos - savePos);
|
||||
|
||||
if (keywords.ContainsKey(tokenData))
|
||||
return CreateToken(keywords[tokenData]);
|
||||
else
|
||||
return CreateToken(TokenType.Identifier, tokenData);
|
||||
}
|
||||
|
||||
private Token ReadNumber()
|
||||
{
|
||||
StartRead();
|
||||
Consume(); // consume first digit or -
|
||||
|
||||
bool hasDot = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
char ch = LA(0);
|
||||
if (Char.IsNumber(ch))
|
||||
Consume();
|
||||
|
||||
// if "." and didn't see "." yet, and next char
|
||||
// is number, than starting to read decimal number
|
||||
else if (ch == '.' && !hasDot && Char.IsNumber(LA(1)))
|
||||
{
|
||||
Consume();
|
||||
hasDot = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return CreateToken(hasDot ? TokenType.Decimal : TokenType.Integer);
|
||||
}
|
||||
|
||||
private Token ReadString()
|
||||
{
|
||||
StartRead();
|
||||
|
||||
char startSymbol = LA(0);
|
||||
Consume(); // consume first string character
|
||||
|
||||
while (true)
|
||||
{
|
||||
char ch = LA(0);
|
||||
if (ch == startSymbol)
|
||||
{
|
||||
Consume();
|
||||
string tokenData = data.Substring(savePos + 1, pos - savePos - 2);
|
||||
return CreateToken(TokenType.String, tokenData);
|
||||
}
|
||||
else if(ch == '\\')
|
||||
{
|
||||
if (LA(1) == 'n' || LA(1) == 'r' || LA(1) == '\'' || LA(1) == '"')
|
||||
{
|
||||
// string escape
|
||||
Consume(2);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParserException ex = new ParserException("Unknown escape sequence. Supported escapes: \\n, \\r, \\\", \\'",
|
||||
line, column, pos, 2);
|
||||
ex.Data["code"] = LEXER_ERROR_UNKNOWN_ESCAPE;
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
else if (ch == EOF)
|
||||
{
|
||||
ParserException ex = new ParserException("Unterminated string constant", saveLine, saveColumn,
|
||||
savePos, pos - savePos);
|
||||
ex.Data["code"] = LEXER_ERROR_UNTERMINATED_STRING;
|
||||
throw ex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// consume next string symbol
|
||||
Consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadWhitespace()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
char ch = LA(0);
|
||||
switch (ch)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
Consume();
|
||||
break;
|
||||
case '\n':
|
||||
Consume();
|
||||
NewLine();
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
Consume();
|
||||
if (LA(0) == '\n')
|
||||
Consume();
|
||||
NewLine();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Helper Methods
|
||||
private char LA(int count)
|
||||
{
|
||||
if (pos + count >= data.Length)
|
||||
return EOF;
|
||||
else
|
||||
{
|
||||
//Debug.Write(data[pos + count]);
|
||||
return data[pos + count];
|
||||
}
|
||||
}
|
||||
|
||||
private char Consume()
|
||||
{
|
||||
char ret = data[pos];
|
||||
pos++;
|
||||
column++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private char Consume(int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
throw new ArgumentOutOfRangeException("count", "'count' cannot be less than 0");
|
||||
|
||||
char ret = ' ';
|
||||
while (count > 0)
|
||||
{
|
||||
ret = Consume();
|
||||
count--;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void NewLine()
|
||||
{
|
||||
line++;
|
||||
column = 1;
|
||||
}
|
||||
|
||||
private void StartRead()
|
||||
{
|
||||
saveLine = line;
|
||||
saveColumn = column;
|
||||
savePos = pos;
|
||||
}
|
||||
|
||||
private Token CreateToken(TokenType type, string value)
|
||||
{
|
||||
return new Token(type, value, saveLine, saveColumn, savePos, value.Length);
|
||||
}
|
||||
|
||||
private Token CreateToken(TokenType type)
|
||||
{
|
||||
string tokenData = data.Substring(savePos, pos - savePos);
|
||||
|
||||
if (type == TokenType.String)
|
||||
{
|
||||
// process escapes
|
||||
tokenData = tokenData.Replace("\\n", "\n")
|
||||
.Replace("\\r", "\r")
|
||||
.Replace("\\\"", "\"")
|
||||
.Replace("\\'", "'");
|
||||
}
|
||||
else if (type == TokenType.Text)
|
||||
{
|
||||
tokenData = tokenData.Replace("##", "#");
|
||||
}
|
||||
|
||||
return new Token(type, tokenData, saveLine, saveColumn, savePos, tokenData.Length);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
712
WebsitePanel/Sources/WebsitePanel.Templates/Parser.cs
Normal file
712
WebsitePanel/Sources/WebsitePanel.Templates/Parser.cs
Normal file
|
@ -0,0 +1,712 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
|
||||
using WebsitePanel.Templates.AST;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
internal class Parser
|
||||
{
|
||||
Lexer lexer;
|
||||
Token current;
|
||||
List<Statement> statements;
|
||||
|
||||
public Parser(Lexer lexer)
|
||||
{
|
||||
this.lexer = lexer;
|
||||
this.statements = new List<Statement>();
|
||||
}
|
||||
|
||||
Token Consume()
|
||||
{
|
||||
Token old = current;
|
||||
current = lexer.Next();
|
||||
return old;
|
||||
}
|
||||
|
||||
Token Consume(TokenType type)
|
||||
{
|
||||
Token old = current;
|
||||
current = lexer.Next();
|
||||
|
||||
if (old.TokenType != type)
|
||||
throw new ParserException("Unexpected token: " + current.TokenType.ToString() + ". Was expecting: " + type,
|
||||
current.Line, current.Column);
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
Token Current
|
||||
{
|
||||
get { return current; }
|
||||
}
|
||||
|
||||
public List<Statement> Parse()
|
||||
{
|
||||
statements.Clear();
|
||||
|
||||
Consume();
|
||||
|
||||
while (true)
|
||||
{
|
||||
Statement stm = ParseStatement();
|
||||
if (stm == null)
|
||||
break;
|
||||
else
|
||||
statements.Add(stm);
|
||||
}
|
||||
|
||||
foreach (Statement stm in statements)
|
||||
Debug.Write(stm);
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
|
||||
private Statement ParseStatement()
|
||||
{
|
||||
switch (Current.TokenType)
|
||||
{
|
||||
case TokenType.EOF:
|
||||
return null;
|
||||
case TokenType.Print:
|
||||
return ParsePrintStatement();
|
||||
case TokenType.Set:
|
||||
return ParseSetStatement();
|
||||
case TokenType.If:
|
||||
return ParseIfStatement();
|
||||
case TokenType.Foreach:
|
||||
return ParseForeachStatement();
|
||||
case TokenType.For:
|
||||
return ParseForStatement();
|
||||
case TokenType.Template:
|
||||
return ParseTemplateStatement();
|
||||
case TokenType.OpenTag:
|
||||
return ParseCallTemplateStatement();
|
||||
case TokenType.Text:
|
||||
TextStatement text = new TextStatement(Current.Data, Current.Line, Current.Column);
|
||||
Consume();
|
||||
return text;
|
||||
default:
|
||||
throw new ParserException("Invalid token: " + Current.TokenType.ToString(), Current.Line, Current.Column);
|
||||
}
|
||||
}
|
||||
|
||||
private Statement ParsePrintStatement()
|
||||
{
|
||||
Consume(TokenType.Print);
|
||||
PrintStatement stm = new PrintStatement(current.Line, current.Column);
|
||||
stm.PrintExpression = ParseExpression();
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseSetStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
SetStatement stm = new SetStatement(current.Line, current.Column);
|
||||
Consume(TokenType.Set);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// look for "test" attribute
|
||||
if (attrName == "name")
|
||||
{
|
||||
stm.Name = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
else if (attrName == "value")
|
||||
{
|
||||
stm.ValueExpression = ParseExpression();
|
||||
}
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// check statement
|
||||
if (stm.Name == null)
|
||||
throw new ParserException("\"name\" attribute was not specified", stm.Line, stm.Column);
|
||||
if (stm.ValueExpression == null)
|
||||
throw new ParserException("\"value\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// it must be an "empty" tag
|
||||
Consume(TokenType.EmptyTag);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseIfStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
IfStatement stm = new IfStatement(current.Line, current.Column);
|
||||
Consume(TokenType.If);
|
||||
|
||||
if(Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
// look for "test" attribute
|
||||
if (Current.Data == "test")
|
||||
{
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
stm.Condition = ParseExpression();
|
||||
}
|
||||
|
||||
// check statement
|
||||
if (stm.Condition == null)
|
||||
throw new ParserException("\"test\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
bool falseBlock = false;
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EndIf)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Else)
|
||||
{
|
||||
Consume(); // else
|
||||
falseBlock = true;
|
||||
continue;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.ElseIf)
|
||||
{
|
||||
stm.ElseIfStatements.Add(ParseElseIfStatement());
|
||||
}
|
||||
else
|
||||
{
|
||||
// parse statement
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected closing </ad:if> tag", stm.Line, stm.Column);
|
||||
|
||||
if (falseBlock)
|
||||
stm.FalseStatements.Add(blockStm);
|
||||
else
|
||||
stm.TrueStatements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
Consume(TokenType.EndIf);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private ElseIfStatement ParseElseIfStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
ElseIfStatement stm = new ElseIfStatement(current.Line, current.Column);
|
||||
Consume(TokenType.ElseIf);
|
||||
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
// look for "test" attribute
|
||||
if (Current.Data == "test")
|
||||
{
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
stm.Condition = ParseExpression();
|
||||
}
|
||||
|
||||
// check statement
|
||||
if (stm.Condition == null)
|
||||
throw new ParserException("\"test\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.ElseIf
|
||||
|| Current.TokenType == TokenType.Else
|
||||
|| Current.TokenType == TokenType.EndIf)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected <ad:elseif>, <ad:else> or </ad:if> tags", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.TrueStatements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseForeachStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
ForeachStatement stm = new ForeachStatement(current.Line, current.Column);
|
||||
Consume(TokenType.Foreach);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// look for "test" attribute
|
||||
if (attrName == "collection")
|
||||
{
|
||||
stm.Collection = ParseExpression();
|
||||
}
|
||||
else if (attrName == "var")
|
||||
{
|
||||
stm.ElementIdentifier = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
else if (attrName == "index")
|
||||
{
|
||||
stm.IndexIdentifier = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// check statement
|
||||
if (stm.Collection == null)
|
||||
throw new ParserException("\"collection\" attribute was not specified", stm.Line, stm.Column);
|
||||
if (stm.ElementIdentifier == null)
|
||||
throw new ParserException("\"var\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EndForeach)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected {/foreach} statement", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.Statements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
Consume(TokenType.EndForeach);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseForStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
ForStatement stm = new ForStatement(current.Line, current.Column);
|
||||
Consume(TokenType.For);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// look for "test" attribute
|
||||
if (attrName == "from")
|
||||
{
|
||||
stm.StartIndex = ParseExpression();
|
||||
}
|
||||
else if (attrName == "to")
|
||||
{
|
||||
stm.EndIndex = ParseExpression();
|
||||
}
|
||||
else if (attrName == "index")
|
||||
{
|
||||
stm.IndexIdentifier = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// check statement
|
||||
if (stm.StartIndex == null)
|
||||
throw new ParserException("\"from\" attribute was not specified", stm.Line, stm.Column);
|
||||
if (stm.EndIndex == null)
|
||||
throw new ParserException("\"to\" attribute was not specified", stm.Line, stm.Column);
|
||||
if (stm.IndexIdentifier == null)
|
||||
throw new ParserException("\"index\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EndFor)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected </ad:for> tag", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.Statements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
Consume(TokenType.EndFor);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseTemplateStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
TemplateStatement stm = new TemplateStatement(current.Line, current.Column);
|
||||
Consume(TokenType.Template);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// look for "test" attribute
|
||||
if (attrName == "name")
|
||||
{
|
||||
stm.Name = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// check statement
|
||||
if (stm.Name == null)
|
||||
throw new ParserException("\"name\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EndTemplate)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected {/template} tag", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.Statements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
Consume(TokenType.EndTemplate);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseCallTemplateStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
CallTemplateStatement stm = new CallTemplateStatement(current.Line, current.Column);
|
||||
stm.TemplateName = Current.Data;
|
||||
Consume(TokenType.OpenTag);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// save parameter
|
||||
stm.Parameters.Add(attrName, ParseExpression());
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EmptyTag)
|
||||
{
|
||||
// />
|
||||
Consume(TokenType.EmptyTag);
|
||||
break;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.CloseTag
|
||||
&& Current.Data == stm.TemplateName)
|
||||
{
|
||||
Consume(TokenType.CloseTag);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected closing tag", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.Statements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Expression ParseExpression()
|
||||
{
|
||||
return ParseLogicalExpression();
|
||||
}
|
||||
|
||||
private Expression ParseLogicalExpression()
|
||||
{
|
||||
Expression lhs = ParseRelationalExpression();
|
||||
return ParseLogicalExpressionRest(lhs);
|
||||
}
|
||||
|
||||
private Expression ParseLogicalExpressionRest(Expression lhs)
|
||||
{
|
||||
if (Current.TokenType == TokenType.And || Current.TokenType == TokenType.Or)
|
||||
{
|
||||
Consume(); // &&, ||
|
||||
Expression rhs = ParseRelationalExpression();
|
||||
BinaryExpression lhsChild = new BinaryExpression(lhs.Line, lhs.Column, lhs, TokenType.And, rhs);
|
||||
return ParseLogicalExpressionRest(lhsChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
|
||||
private Expression ParseRelationalExpression()
|
||||
{
|
||||
Expression lhs = ParseAdditiveExpression();
|
||||
|
||||
if (Current.TokenType == TokenType.Less
|
||||
|| Current.TokenType == TokenType.LessOrEqual
|
||||
|| Current.TokenType == TokenType.Greater
|
||||
|| Current.TokenType == TokenType.GreaterOrEqual
|
||||
|| Current.TokenType == TokenType.Equal
|
||||
|| Current.TokenType == TokenType.NotEqual)
|
||||
{
|
||||
Token tok = Consume(); // <, >, <=, >=, ==, !=
|
||||
Expression rhs = ParseRelationalExpression(); // recursion
|
||||
return new BinaryExpression(lhs.Line, lhs.Column, lhs, tok.TokenType, rhs);
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
private Expression ParseAdditiveExpression()
|
||||
{
|
||||
Expression lhs = ParseMultiplyExpression();
|
||||
return ParseAdditiveExpressionRest(lhs);
|
||||
}
|
||||
|
||||
private Expression ParseAdditiveExpressionRest(Expression lhs)
|
||||
{
|
||||
if (Current.TokenType == TokenType.Plus
|
||||
|| Current.TokenType == TokenType.Minus)
|
||||
{
|
||||
Token tok = Consume(); // +, -
|
||||
Expression rhs = ParseMultiplyExpression();
|
||||
BinaryExpression lhsChild = new BinaryExpression(lhs.Line, lhs.Column, lhs, tok.TokenType, rhs);
|
||||
return ParseAdditiveExpressionRest(lhsChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
|
||||
private Expression ParseMultiplyExpression()
|
||||
{
|
||||
Expression lhs = ParseUnaryExpression();
|
||||
return ParseMultiplyExpressionRest(lhs);
|
||||
}
|
||||
|
||||
private Expression ParseMultiplyExpressionRest(Expression lhs)
|
||||
{
|
||||
if (Current.TokenType == TokenType.Mult
|
||||
|| Current.TokenType == TokenType.Div
|
||||
|| Current.TokenType == TokenType.Mod)
|
||||
{
|
||||
Token tok = Consume(); // *, /, %
|
||||
Expression rhs = ParseUnaryExpression();
|
||||
BinaryExpression lhsChild = new BinaryExpression(lhs.Line, lhs.Column, lhs, tok.TokenType, rhs);
|
||||
return ParseMultiplyExpressionRest(lhsChild);
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
private Expression ParseUnaryExpression()
|
||||
{
|
||||
if (Current.TokenType == TokenType.Minus ||
|
||||
Current.TokenType == TokenType.Not)
|
||||
{
|
||||
Token tok = Consume(); // -, !
|
||||
Expression rhs = ParseUnaryExpression();
|
||||
UnaryExpression exp = new UnaryExpression(Current.Line, Current.Column, tok.TokenType, rhs);
|
||||
return exp;
|
||||
}
|
||||
|
||||
return ParsePrimaryExpression();
|
||||
}
|
||||
|
||||
private Expression ParsePrimaryExpression()
|
||||
{
|
||||
if (Current.TokenType == TokenType.String)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, Current.Data);
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Null)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, null);
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.True)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, true);
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.False)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, false);
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Integer)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, Int32.Parse(Current.Data));
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Decimal)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column,
|
||||
Decimal.Parse(Current.Data, NumberFormatInfo.InvariantInfo));
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Identifier)
|
||||
{
|
||||
IdentifierExpression id = new IdentifierExpression(Current.Line, Current.Column);
|
||||
while (Current.TokenType == TokenType.Identifier)
|
||||
{
|
||||
id.Parts.Add(ParseIdentifierPart());
|
||||
|
||||
if (Current.TokenType != TokenType.Dot)
|
||||
break;
|
||||
else
|
||||
{
|
||||
Consume(); // .
|
||||
if(Current.TokenType != TokenType.Identifier)
|
||||
throw new ParserException("Wrong usage of period. Identifier was expected.", Current.Line, Current.Column);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.LParen)
|
||||
{
|
||||
Consume(); // eat (
|
||||
Expression exp = ParseExpression();
|
||||
Consume(TokenType.RParen); // eat )
|
||||
|
||||
return exp;
|
||||
}
|
||||
else
|
||||
throw new ParserException("Invalid token in expression: " + Current.TokenType + ". Was expecting identifier, string or number", Current.Line, Current.Column);
|
||||
}
|
||||
|
||||
private IdentifierPart ParseIdentifierPart()
|
||||
{
|
||||
IdentifierPart part = new IdentifierPart(Current.Data, Current.Line, Current.Column);
|
||||
Consume(); // consume identifier
|
||||
|
||||
// check for indexer
|
||||
if (Current.TokenType == TokenType.LBracket)
|
||||
{
|
||||
Consume(); // [
|
||||
part.Index = ParseExpression();
|
||||
Consume(TokenType.RBracket); // ]
|
||||
}
|
||||
// check for method call
|
||||
else if (Current.TokenType == TokenType.LParen)
|
||||
{
|
||||
Consume(); // (
|
||||
part.IsMethod = true;
|
||||
|
||||
// parse parameters
|
||||
while (Current.TokenType != TokenType.RParen)
|
||||
{
|
||||
part.MethodParameters.Add(ParseExpression());
|
||||
if (Current.TokenType == TokenType.RParen)
|
||||
break; // )
|
||||
|
||||
Consume(TokenType.Comma); // ,
|
||||
}
|
||||
Consume(TokenType.RParen); // )
|
||||
}
|
||||
|
||||
return part;
|
||||
}
|
||||
}
|
||||
}
|
105
WebsitePanel/Sources/WebsitePanel.Templates/ParserException.cs
Normal file
105
WebsitePanel/Sources/WebsitePanel.Templates/ParserException.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public class ParserException : Exception
|
||||
{
|
||||
int line;
|
||||
int column;
|
||||
int position;
|
||||
int length;
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="column"></param>
|
||||
public ParserException(string message, int line, int column)
|
||||
: base(message)
|
||||
{
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="column"></param>
|
||||
/// <param name="position"></param>
|
||||
/// <param name="length"></param>
|
||||
public ParserException(string message, int line, int column, int position, int length)
|
||||
: base(message)
|
||||
{
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.position = position;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public int Line
|
||||
{
|
||||
get { return line; }
|
||||
set { line = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public int Column
|
||||
{
|
||||
get { return column; }
|
||||
set { column = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public int Position
|
||||
{
|
||||
get { return position; }
|
||||
set { position = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public int Length
|
||||
{
|
||||
get { return length; }
|
||||
set { length = value; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
142
WebsitePanel/Sources/WebsitePanel.Templates/Program.cs
Normal file
142
WebsitePanel/Sources/WebsitePanel.Templates/Program.cs
Normal file
|
@ -0,0 +1,142 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
|
||||
using WebsitePanel.Templates.AST;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
string data = LoadTestTemplate("cf3.txt");
|
||||
|
||||
//TestLexer(data);
|
||||
TestTemplates(data);
|
||||
}
|
||||
|
||||
private static void TestTemplates(string data)
|
||||
{
|
||||
Template tmp1 = new Template(data);
|
||||
tmp1["a"] = 2;
|
||||
tmp1["b"] = 5;
|
||||
tmp1["d"] = 2;
|
||||
tmp1["str"] = "string 111";
|
||||
|
||||
tmp1["str1"] = "Hello, World";
|
||||
tmp1["str2"] = "";
|
||||
tmp1["str3"] = null;
|
||||
|
||||
tmp1["arr"] = new string[] { "s1", "s2", "s3" };
|
||||
tmp1["customer"] = new Customer()
|
||||
{
|
||||
OrderNumbers = new string[] { "order-1", "order-2", "order-3" }
|
||||
};
|
||||
tmp1["integersDict"] = new Dictionary<int, string>()
|
||||
{
|
||||
{101, "str1"},
|
||||
{102, "str2"},
|
||||
{103, "str3"}
|
||||
};
|
||||
|
||||
tmp1["customersDict"] = new Dictionary<string, Customer>()
|
||||
{
|
||||
{"customer1", new Customer()
|
||||
{
|
||||
Name = "John Smith",
|
||||
OrderNumbers = new string[] { "o-1", "o-2" }
|
||||
} },
|
||||
{"customer2", new Customer()
|
||||
{
|
||||
Name = "Jack Brown",
|
||||
OrderNumbers = new string[] { "order-1", "order-2", "order-3", "order-4" }
|
||||
}}
|
||||
};
|
||||
|
||||
tmp1["customersList"] = new List<Customer>()
|
||||
{
|
||||
new Customer()
|
||||
{
|
||||
Name = "John Smith",
|
||||
OrderNumbers = new string[] { "o-1", "o-2" }
|
||||
},
|
||||
new Customer()
|
||||
{
|
||||
Name = "Jack Brown",
|
||||
OrderNumbers = new string[] { "o-1", "o-2" }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// check syntax
|
||||
//tmp1.CheckSyntax();
|
||||
|
||||
string result = tmp1.Evaluate();
|
||||
|
||||
Console.Write(result);
|
||||
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
private static void TestLexer(string data)
|
||||
{
|
||||
List<Token> tokens = new List<Token>();
|
||||
Lexer lex = new Lexer(data);
|
||||
|
||||
while (true)
|
||||
{
|
||||
Token token = lex.Next();
|
||||
tokens.Add(token);
|
||||
|
||||
Debug.WriteLine(String.Format("{0} [{1},{2}]: {3}", token.TokenType, token.Line, token.Column, token.Data));
|
||||
|
||||
if (token.TokenType == TokenType.EOF)
|
||||
break;
|
||||
}
|
||||
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
private static string LoadTestTemplate(string name)
|
||||
{
|
||||
return File.ReadAllText("../Tests/" + name);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Customer
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string[] OrderNumbers { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("WebsitePanel.Templates")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyProduct("WebsitePanel.Templates")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("731594ac-9e10-4a64-ac76-0b2ac6b50ada")]
|
176
WebsitePanel/Sources/WebsitePanel.Templates/Template.cs
Normal file
176
WebsitePanel/Sources/WebsitePanel.Templates/Template.cs
Normal file
|
@ -0,0 +1,176 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using WebsitePanel.Templates.AST;
|
||||
using System.Collections;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
/// <summary>
|
||||
/// Template allows to process block of texts containing special directives such as variables,
|
||||
/// conditional statements and loops.
|
||||
/// </summary>
|
||||
public class Template
|
||||
{
|
||||
string data;
|
||||
Lexer lexer = null;
|
||||
Parser parser = null;
|
||||
List<AST.Statement> statements = null;
|
||||
TemplateContext context = new TemplateContext();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of Template with specified template text.
|
||||
/// </summary>
|
||||
/// <param name="data">Template text.</param>
|
||||
public Template(string data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of Template with specified StringReader containing template text.
|
||||
/// </summary>
|
||||
/// <param name="reader">StringReader containing template text.</param>
|
||||
public Template(StringReader reader)
|
||||
{
|
||||
if(reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
this.data = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies template syntax and throws <see cref="ParserException">ParserException</see> when error is found.
|
||||
/// </summary>
|
||||
/// <exception cref="ParserException">Thrown when error is found.</exception>
|
||||
public void CheckSyntax()
|
||||
{
|
||||
// create lexer
|
||||
lexer = new Lexer(data);
|
||||
|
||||
// create parser
|
||||
parser = new Parser(lexer);
|
||||
|
||||
// parse template
|
||||
parser.Parse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates template and returns the result as a string.
|
||||
/// </summary>
|
||||
/// <returns>String containing evaluated template.</returns>
|
||||
public string Evaluate()
|
||||
{
|
||||
// create writer to hold result
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
// evaluate
|
||||
Evaluate(writer);
|
||||
|
||||
// return result
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates template and returns the result as a string.
|
||||
/// </summary>
|
||||
/// <returns>String containing evaluated template.</returns>
|
||||
public string Evaluate(Hashtable items)
|
||||
{
|
||||
// copy items from hashtable
|
||||
foreach (string keyName in items.Keys)
|
||||
{
|
||||
this[keyName] = items[keyName];
|
||||
}
|
||||
|
||||
// evaluate
|
||||
return Evaluate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates template to the StringWriter.
|
||||
/// </summary>
|
||||
/// <param name="writer">StringWriter to write evaluation results.</param>
|
||||
public void Evaluate(StringWriter writer)
|
||||
{
|
||||
if(writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (lexer == null)
|
||||
{
|
||||
// create lexer
|
||||
lexer = new Lexer(data);
|
||||
|
||||
// create parser
|
||||
parser = new Parser(lexer);
|
||||
|
||||
// parse template
|
||||
statements = parser.Parse();
|
||||
}
|
||||
|
||||
// index custom templates
|
||||
int i = 0;
|
||||
while (i < statements.Count)
|
||||
{
|
||||
TemplateStatement tmpStatement = statements[i] as TemplateStatement;
|
||||
if (tmpStatement != null)
|
||||
{
|
||||
context.Templates.Add(tmpStatement.Name, tmpStatement);
|
||||
statements.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// evaluate template statements
|
||||
foreach (AST.Statement stm in statements)
|
||||
{
|
||||
// eval next statement
|
||||
stm.Eval(context, writer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of template context variable.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the context variable. Variable names are case-insensitive.</param>
|
||||
/// <returns>Returns the value of the context variable.</returns>
|
||||
public object this[string name]
|
||||
{
|
||||
get { return context.Variables.ContainsKey(name) ? context.Variables[name] : null; }
|
||||
set { context.Variables[name] = value; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using WebsitePanel.Templates.AST;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
internal class TemplateContext
|
||||
{
|
||||
Dictionary<string, object> variables = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
|
||||
Dictionary<string, TemplateStatement> templates = new Dictionary<string, TemplateStatement>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
public TemplateContext ParentContext { get; set; }
|
||||
|
||||
public Dictionary<string, object> Variables
|
||||
{
|
||||
get { return variables; }
|
||||
}
|
||||
|
||||
public Dictionary<string, TemplateStatement> Templates
|
||||
{
|
||||
get { return templates; }
|
||||
set { templates = value; }
|
||||
}
|
||||
}
|
||||
}
|
10
WebsitePanel/Sources/WebsitePanel.Templates/Tests/cf1.txt
Normal file
10
WebsitePanel/Sources/WebsitePanel.Templates/Tests/cf1.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
#hello.world# this is a static text and #var#
|
||||
escape: ##eeff55; #test.# a <ad:if test="#var1 == 2#">
|
||||
branch 1
|
||||
<ad:elseif test="#method1(a, b + 3)#">
|
||||
branch 3
|
||||
</ad:if>
|
||||
|
||||
<<<ad:foreach collection="#collection is "test"#" var="cust" index="i">
|
||||
#i#: #cust.lastname#, #cust.firstname#
|
||||
</ad:foreach>
|
49
WebsitePanel/Sources/WebsitePanel.Templates/Tests/cf2.txt
Normal file
49
WebsitePanel/Sources/WebsitePanel.Templates/Tests/cf2.txt
Normal file
|
@ -0,0 +1,49 @@
|
|||
#isdefined("c")#
|
||||
<ad:if test="#isdefined("a") and IsDefined("b")#">
|
||||
A and B are defined
|
||||
</ad:if>
|
||||
|
||||
ID: #a#
|
||||
|
||||
First name: #b# Last name: #str#
|
||||
|
||||
<ad:if test="#not(a is 2)#">
|
||||
a = 2
|
||||
<ad:else>
|
||||
b = 2
|
||||
</ad:if>
|
||||
|
||||
<ad:set name="var1" value="#b#" />
|
||||
<ad:set name="var2" value=" hello, world" />
|
||||
|
||||
Total: #arr[1]#
|
||||
|
||||
<ad:foreach collection="#arr#" var="item" index="i">
|
||||
<p><ad:ShowBillingPeriod tmp="#item#">#i+10#</ad:ShowBillingPeriod></p>
|
||||
</ad:foreach>
|
||||
|
||||
<ad:for from="0" to="#arr.Length - 1#" index="j">
|
||||
#j# = #arr[j].ToString()#
|
||||
</ad:for>
|
||||
|
||||
<ad:for index="k" from="0" to="10">
|
||||
#k.ToString("0.00")#
|
||||
</ad:for>
|
||||
|
||||
<ad:for from="0" to="#customer.OrderNumbers.Length - 1#" index="j">
|
||||
#j# = #customer.OrderNumbers[j].ToString()#
|
||||
</ad:for>
|
||||
|
||||
#integersDict[101]#
|
||||
#integersDict[102]#
|
||||
|
||||
Customer 1: #customersDict["customer1"].OrderNumbers.Length#
|
||||
Customer 2: #customersDict["customer2"].OrderNumbers.Length#
|
||||
|
||||
<ad:foreach collection="#customersList#" var="cust">
|
||||
customer: #cust.name#
|
||||
</ad:foreach>
|
||||
|
||||
#customersList[1].name#
|
||||
|
||||
<ad:template name="ShowBillingPeriod">#innerText#: <b>#tmp#</b></ad:template>
|
106
WebsitePanel/Sources/WebsitePanel.Templates/Tests/cf3.txt
Normal file
106
WebsitePanel/Sources/WebsitePanel.Templates/Tests/cf3.txt
Normal file
|
@ -0,0 +1,106 @@
|
|||
## just a comment...
|
||||
|
||||
A = #a#
|
||||
B = #b#
|
||||
D = #d#
|
||||
|
||||
*** isdefined ***
|
||||
#isdefined("c")#
|
||||
<ad:if test="#isdefined("a") and IsDefined("b")#">
|
||||
A and B are defined
|
||||
</ad:if>
|
||||
|
||||
*** ifdefined ***
|
||||
#ifdefined("a", "a IS defined")#
|
||||
#ifdefined("c", "c IS NOT defined")#
|
||||
#ifdefined("d", (3+2)/5)#
|
||||
|
||||
*** equals ***
|
||||
A equals B: #equals(a, b)#
|
||||
D equals A: #equals(d, a)#
|
||||
|
||||
*** notequals ***
|
||||
A notequals B: #notequals(a, b)#
|
||||
D notequals A: #notequals(d, a)#
|
||||
|
||||
*** iseven ***
|
||||
A is even: #iseven(a)#
|
||||
B is even: #iseven(b)#
|
||||
|
||||
*** isodd ***
|
||||
A is odd: #isodd(a)#
|
||||
B is odd: #isodd(b)#
|
||||
|
||||
*** isempty ***
|
||||
str1 is empty: #isempty(str1)#
|
||||
str2 is empty: #isempty(str2)#
|
||||
str3 is empty: #isempty(str3)#
|
||||
|
||||
*** isnumber ***
|
||||
A is number: #isnumber(A)#
|
||||
str1 is number: #isnumber(str1)#
|
||||
|
||||
*** toupper ***
|
||||
str1: #ToUpper(str1)#
|
||||
str2: #ToUpper(str2)#
|
||||
str3: #ToUpper(str3)#
|
||||
|
||||
*** tolower ***
|
||||
str1: #ToLower(str1)#
|
||||
str2: #ToLower(str2)#
|
||||
str3: #ToLower(str3)#
|
||||
|
||||
*** len ***
|
||||
str1: #len(str1)#
|
||||
str2: #len(str2)#
|
||||
str3: #len(str3)#
|
||||
|
||||
*** isnull ***
|
||||
a: #isnull(a)#
|
||||
str1: #isnull(str1)#
|
||||
str3: #isnull(str3)#
|
||||
|
||||
*** not ***
|
||||
not(isnull(a)): #not(isnull(a))#
|
||||
not(isempty(str2)): #not(isempty(str2))#
|
||||
|
||||
*** iif ***
|
||||
#iif(a == b, "a = b", "a != b")#
|
||||
#iif(a == d, "a = d", "a != d")#
|
||||
#iif(a % 2 is 0, "even", "odd")#
|
||||
|
||||
*** format ***
|
||||
format(a, "0.00"): #format(a, "0.00")#
|
||||
format(b, "C"): #format(b, "C")#
|
||||
|
||||
*** Trim ***
|
||||
trim(" hello "): #trim(" hello ")#
|
||||
trim(str1): #trim(str1)#
|
||||
|
||||
*** Compare ***
|
||||
compare(a,b): #compare(a,b)#
|
||||
compare(a,d): #compare(a,d)#
|
||||
compare(b,d): #compare(b,d)#
|
||||
|
||||
*** CompareNoCase ***
|
||||
CompareNoCase(str1, "hello, world"): #CompareNoCase(str1, "hello, world")#
|
||||
|
||||
*** StripNewLines ***
|
||||
StripNewLines(str1) : #StripNewLines(str1)#
|
||||
|
||||
*** TypeOf **
|
||||
typeof(a): #typeof(a)#
|
||||
typeof(str1): #typeof(str1)#
|
||||
|
||||
*** cint ***
|
||||
cint("1"): #typeof(cint("1"))#
|
||||
|
||||
*** cdouble ***
|
||||
cdouble("1.222"): #typeof(cdouble("1.222"))#
|
||||
|
||||
*** cdate ***
|
||||
cdate("2010-10-12"): #cdate("2010-10-12")#
|
||||
|
||||
*** ToList ***
|
||||
tolist(arr, null, ", "): #tolist(arr, null, ", ")#
|
||||
tolist(customersDict.Values, "Name", ", "): #tolist(customersDict.Values, "Name", ", ")#
|
26
WebsitePanel/Sources/WebsitePanel.Templates/Tests/tmp1.txt
Normal file
26
WebsitePanel/Sources/WebsitePanel.Templates/Tests/tmp1.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
Hello {$name+null},
|
||||
|
||||
{if 1 !=0.2 +"str1"
|
||||
&&""||'fff'}
|
||||
This is some text...
|
||||
{{/if}
|
||||
|
||||
Best regards,
|
||||
Support team
|
||||
|
||||
function setSelectionRange(textElem, selectionStart, selectionEnd) {
|
||||
if (textElem.setSelectionRange) { // FF
|
||||
// textElem.focus(); // needed?
|
||||
window.setTimeout(function(x,posL,posR){ // bug 265159
|
||||
return function(){x.setSelectionRange(posL,posR);};}
|
||||
(textElem,selectionStart,selectionEnd),100);
|
||||
} else if (textElem.createTextRange) { // IE
|
||||
var range = textElem.createTextRange();
|
||||
range.collapse(true);
|
||||
range.moveEnd('character', selectionEnd);
|
||||
range.moveStart('character', selectionStart);
|
||||
range.select();
|
||||
}
|
||||
}
|
||||
|
||||
{/if}
|
12
WebsitePanel/Sources/WebsitePanel.Templates/Tests/tmp2.txt
Normal file
12
WebsitePanel/Sources/WebsitePanel.Templates/Tests/tmp2.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
Hello {$2+a},
|
||||
{if ff}
|
||||
|
||||
{if -a.b[2+2].d[0]-2/3 #}
|
||||
This is some text...
|
||||
{/if}
|
||||
|
||||
{/idf1 }
|
||||
|
||||
{rest}
|
||||
Best regards,
|
||||
Support team
|
22
WebsitePanel/Sources/WebsitePanel.Templates/Tests/tmp3.txt
Normal file
22
WebsitePanel/Sources/WebsitePanel.Templates/Tests/tmp3.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
{foreach elem in arr1 index idx}
|
||||
{$elem} - {$idx % 2}
|
||||
{/foreach}
|
||||
|
||||
{for i = 0 to b*4}{if i >= 4},{/if} {$i}{/for}
|
||||
|
||||
{$arr1[1]}
|
||||
{$ arr1[1]
|
||||
.length}
|
||||
{$a+b-1}
|
||||
{$ a*(b/1) / 2-a+b+3/2 }
|
||||
|
||||
{if a}a!!!{/if}
|
||||
{if b==null}b is not set{/if}
|
||||
|
||||
Hello {$2+a},
|
||||
{if a+(b+1)/2*4 == 42/3}
|
||||
conditional expression
|
||||
{/if}
|
||||
|
||||
Best regards,
|
||||
Support team
|
86
WebsitePanel/Sources/WebsitePanel.Templates/Token.cs
Normal file
86
WebsitePanel/Sources/WebsitePanel.Templates/Token.cs
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
internal class Token
|
||||
{
|
||||
TokenType tokenType;
|
||||
int line;
|
||||
int column;
|
||||
int position;
|
||||
int length;
|
||||
string data;
|
||||
|
||||
public Token(TokenType tokenType, string data, int line, int column, int position, int length)
|
||||
{
|
||||
this.tokenType = tokenType;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.position = position;
|
||||
this.data = data;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public TokenType TokenType
|
||||
{
|
||||
get { return this.tokenType; }
|
||||
set { this.tokenType = value; }
|
||||
}
|
||||
|
||||
public string Data
|
||||
{
|
||||
get { return this.data; }
|
||||
set { this.data = value; }
|
||||
}
|
||||
|
||||
public int Column
|
||||
{
|
||||
get { return this.column; }
|
||||
}
|
||||
|
||||
public int Line
|
||||
{
|
||||
get { return this.line; }
|
||||
}
|
||||
|
||||
public int Position
|
||||
{
|
||||
get { return this.position; }
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return this.length; }
|
||||
}
|
||||
}
|
||||
}
|
106
WebsitePanel/Sources/WebsitePanel.Templates/TokenType.cs
Normal file
106
WebsitePanel/Sources/WebsitePanel.Templates/TokenType.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
internal enum TokenType
|
||||
{
|
||||
EOF,
|
||||
Text,
|
||||
|
||||
Attribute, // tag attribute
|
||||
Identifier, // object.prop1.prop2
|
||||
|
||||
// literals
|
||||
Integer, // 1234
|
||||
Decimal, // 12.34, 12,33
|
||||
String, // "test\nstring with escapes and 'quotes' inside"
|
||||
// 'single "quoted" string'
|
||||
Null, // null
|
||||
Empty, // empty
|
||||
True, // true
|
||||
False, // false
|
||||
|
||||
// symbols
|
||||
LParen, // (
|
||||
RParen, // )
|
||||
LBracket, // [
|
||||
RBracket, // ]
|
||||
LBrace, // {
|
||||
RBrace, // }
|
||||
Colon, // :
|
||||
Dot, // .
|
||||
Comma, // ,
|
||||
|
||||
// operators
|
||||
Plus, // +
|
||||
Minus, // -
|
||||
Div, // /
|
||||
Mult, // *
|
||||
Mod, // %
|
||||
BinOr, // |
|
||||
BinAnd, // &
|
||||
Or, // ||, OR
|
||||
And, // &&, AND
|
||||
Not, // !, NOT
|
||||
Assign, // =
|
||||
|
||||
// comparisons
|
||||
Greater, // >
|
||||
GreaterOrEqual, // >=
|
||||
Less, // <
|
||||
LessOrEqual,// <=
|
||||
Equal, // ==
|
||||
NotEqual, // !=
|
||||
|
||||
// start statements
|
||||
Set, // {set}
|
||||
Template, // {template}
|
||||
Print, // {$ exp }
|
||||
If, // {if exp}
|
||||
ElseIf, // {elseif exp}
|
||||
Else, // {else}
|
||||
Foreach, // {foreach identifier in exp [index identifier]}
|
||||
For, // {for identifier = exp to exp}
|
||||
|
||||
// end statements
|
||||
EndTemplate,// {/template}
|
||||
EndIf, // {/if}
|
||||
EndForeach, // {/foreach}
|
||||
EndFor, // {/for}
|
||||
|
||||
// custom tags
|
||||
OpenTag, // <ad:Custom>
|
||||
CloseTag, // </ad:Custom>
|
||||
EmptyTag // .../>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{387FA0EF-3927-45FF-8F8F-BCCD735540C6}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>WebsitePanel.Templates</RootNamespace>
|
||||
<AssemblyName>WebsitePanel.Templates</AssemblyName>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<StartupObject>
|
||||
</StartupObject>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningsAsErrors>618</WarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<WarningsAsErrors>618</WarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AST\BinaryExpression.cs" />
|
||||
<Compile Include="AST\CallTemplateStatement.cs" />
|
||||
<Compile Include="AST\ElseIfStatement.cs" />
|
||||
<Compile Include="AST\Expression.cs" />
|
||||
<Compile Include="AST\ForeachStatement.cs" />
|
||||
<Compile Include="AST\ForStatement.cs" />
|
||||
<Compile Include="AST\IdentifierExpression.cs" />
|
||||
<Compile Include="AST\IdentifierPart.cs" />
|
||||
<Compile Include="AST\IfStatement.cs" />
|
||||
<Compile Include="AST\LiteralExpression.cs" />
|
||||
<Compile Include="AST\PrintStatement.cs" />
|
||||
<Compile Include="AST\SetStatement.cs" />
|
||||
<Compile Include="AST\Statement.cs" />
|
||||
<Compile Include="AST\TemplateStatement.cs" />
|
||||
<Compile Include="AST\TextStatement.cs" />
|
||||
<Compile Include="AST\UnaryExpression.cs" />
|
||||
<Compile Include="BuiltinFunctions.cs" />
|
||||
<Compile Include="Lexer.cs" />
|
||||
<Compile Include="Parser.cs" />
|
||||
<Compile Include="ParserException.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Template.cs" />
|
||||
<Compile Include="TemplateContext.cs" />
|
||||
<Compile Include="Token.cs" />
|
||||
<Compile Include="TokenType.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Tests\cf1.txt" />
|
||||
<Content Include="Tests\cf2.txt" />
|
||||
<Content Include="Tests\cf3.txt" />
|
||||
<Content Include="Tests\tmp3.txt" />
|
||||
<Content Include="Tests\tmp2.txt" />
|
||||
<Content Include="Tests\tmp1.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
3
WebsitePanel/Sources/WebsitePanel.Templates/app.config
Normal file
3
WebsitePanel/Sources/WebsitePanel.Templates/app.config
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
|
Loading…
Add table
Add a link
Reference in a new issue