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