Initial project's source code check-in.

This commit is contained in:
ptsurbeleu 2011-07-13 16:07:32 -07:00
commit b03b0b373f
4573 changed files with 981205 additions and 0 deletions

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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);
}
}

View 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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View 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();
}
}
}

View file

@ -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";
}
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}
}

View 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);
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}
}

View 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);
}
}
}
}

View 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
}
}

View 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;
}
}
}

View 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; }
}
}
}

View 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; }
}
}

View file

@ -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")]

View 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; }
}
}
}

View file

@ -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; }
}
}
}

View 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>

View 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>

View 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", ", ")#

View 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}

View 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

View 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

View 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; }
}
}
}

View 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 // .../>
}
}

View file

@ -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>

View file

@ -0,0 +1,3 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>