diff --git a/Library/Parser/Context/ParserContext.cs b/Library/Parser/Context/ParserContext.cs index eded944..d8a1a79 100644 --- a/Library/Parser/Context/ParserContext.cs +++ b/Library/Parser/Context/ParserContext.cs @@ -1,346 +1,382 @@ -#region License -//============================================================================= -// Vici Core - Productivity Library for .NET 3.5 -// -// Copyright (c) 2008-2012 Philippe Leybaert -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//============================================================================= -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.Reflection; - -namespace Vici.Core.Parser -{ - public class ParserContext : IParserContext - { - private readonly Dictionary _variables; - private readonly Dictionary _types; - private readonly object _rootObject; - - private readonly IParserContext _parentContext; - - public ParserContextBehavior Behavior { get; private set; } - - private AssignmentPermissions _assignmentPermissions = AssignmentPermissions.None; - private StringComparison _stringComparison = StringComparison.Ordinal; - private IFormatProvider _formatProvider = NumberFormatInfo.InvariantInfo; - - public ParserContext(ParserContextBehavior behavior) - { - Behavior = behavior; - - if ((behavior & ParserContextBehavior.CaseInsensitiveVariables) == ParserContextBehavior.CaseInsensitiveVariables) - { - _variables = new Dictionary(StringComparer.OrdinalIgnoreCase); - _types = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - else - { - _variables = new Dictionary(); - _types = new Dictionary(); - - } - } - - public ParserContext() : this(ParserContextBehavior.Default) - { - } - - public ParserContext(object rootObject, ParserContextBehavior behavior) : this(behavior) - { - _rootObject = rootObject; - } - - public ParserContext(object rootObject) : this(rootObject, ParserContextBehavior.Default) - { - } - - protected ParserContext(ParserContext parentContext) : this(parentContext.Behavior) - { - _parentContext = parentContext; - - _assignmentPermissions = parentContext._assignmentPermissions; - _stringComparison = parentContext._stringComparison; - _formatProvider = parentContext._formatProvider; - } - - public virtual IParserContext CreateLocal() - { - return new ParserContext(this); - } - - private bool TestBehavior(ParserContextBehavior behavior) - { - return ((Behavior & behavior) == behavior); - } - -// public bool ReturnNullWhenNullReference -// { -// get { return _returnNullWhenNullReference; } -// set { _returnNullWhenNullReference = value; } -// } -// -// public bool NullIsFalse -// { -// get { return _nullIsFalse; } -// set { _nullIsFalse = value; } -// } -// -// public bool NotNullIsTrue -// { -// get { return _notNullIsTrue; } -// set { _notNullIsTrue = value; } -// } -// -// public bool EmptyStringIsFalse -// { -// get { return _emptyStringIsFalse; } -// set { _emptyStringIsFalse = value; } -// } -// -// public bool NonEmptyStringIsTrue -// { -// get { return _nonEmptyStringIsTrue; } -// set { _nonEmptyStringIsTrue = value; } -// } - -// public bool CaseSensitiveVariables -// { -// get { return _caseSensitiveVariables; } -// set -// { -// if (value != _caseSensitiveVariables) -// { -// if (value) -// { -// _variables = new Dictionary(); -// _types = new Dictionary(); -// } -// else -// { -// _variables = new Dictionary(StringComparer.InvariantCultureIgnoreCase); -// _types = new Dictionary(StringComparer.InvariantCultureIgnoreCase); -// -// } -// _caseSensitiveVariables = value; -// } -// } -// } - - public AssignmentPermissions AssignmentPermissions - { - get { return _assignmentPermissions; } - set { _assignmentPermissions = value; } - } - - public StringComparison StringComparison - { - get { return _stringComparison; } - set { _stringComparison = value; } - } - -// public bool EmptyCollectionIsFalse -// { -// get { return _emptyCollectionIsFalse; } -// set { _emptyCollectionIsFalse = value; } -// } -// -// public bool NotZeroIsTrue -// { -// get { return _notZeroIsTrue; } -// set { _notZeroIsTrue = value; } -// } -// - public IFormatProvider FormatProvider - { - get { return _formatProvider; } - set { _formatProvider = value; } - } - - public void SetLocal(string name, T data) - { - SetLocal(name, data, typeof (T)); - } - - public void SetLocal(string name, IValueWithType data) - { - SetLocal(name, data.Value, data.Type); - } - - public void SetLocal(string name, object data, Type type) - { - _variables[name] = data; - _types[name] = type; - } - - public void Set(string name, object data, Type type) - { - if (_parentContext != null && _parentContext.Exists(name)) - _parentContext.Set(name, data, type); - - SetLocal(name, data, type); - } - - public void Set(string name, T data) - { - Set(name, data, typeof (T)); - } - - public void Set(string name, IValueWithType data) - { - Set(name, data.Value, data.Type); - } - - public void AddType(string name, Type type) - { - Set(name, ContextFactory.CreateType(type)); - } - - public void AddFunction(string name, Type type, string methodName) - { - Set(name, ContextFactory.CreateFunction(type, methodName)); - } - - public void AddFunction(string name, Type type, string methodName, object targetObject) - { - Set(name, ContextFactory.CreateFunction(type, methodName, targetObject)); - } - - public void AddFunction(string name, MethodInfo methodInfo) - { - Set(name, ContextFactory.CreateFunction(methodInfo)); - } - - public void AddFunction(string name, MethodInfo methodInfo, object targetObject) - { - Set(name, ContextFactory.CreateFunction(methodInfo, targetObject)); - } - - public virtual bool Exists(string varName) - { - if (_variables.ContainsKey(varName)) - return true; - - if (_rootObject != null && PropertyHelper.Exists(_rootObject, varName)) - return true; - - if (_parentContext == null || !_parentContext.Exists(varName)) - return false; - - return true; - } - - public virtual bool Get(string varName, out object value, out Type type) - { - if (_variables.ContainsKey(varName)) - { - value = _variables[varName]; - type = _types[varName]; - } - else if (_rootObject != null && PropertyHelper.TryGetValue(_rootObject,varName,out value, out type)) - { - return true; - } - else - { - if (_parentContext == null || !_parentContext.Get(varName, out value, out type)) - { - value = null; - type = typeof(object); - - return false; - } - } - - if (type == typeof(object) && value != null) - type = value.GetType(); - - return true; - } - - public bool ToBoolean(object value) - { - if (value != null) - { - if (value is bool) - return ((bool) value); - - if (TestBehavior(ParserContextBehavior.ZeroIsFalse)) - { - if (value is int || value is uint || value is short || value is ushort || value is long || value is ulong || value is byte || value is sbyte) - return Convert.ToInt64(value) != 0; - - if (value is decimal) - return (decimal) value != 0m; - - if (value is float || value is double) - return Convert.ToDouble(value) == 0.0; - } - - if (TestBehavior(ParserContextBehavior.EmptyCollectionIsFalse)) - { - if (value is ICollection) - return ((ICollection) value).Count > 0; - - if (value is IEnumerable) - { - IEnumerator enumerator = ((IEnumerable) value).GetEnumerator(); - - if (enumerator.MoveNext()) - return true; - - return false; - } - } - - if (TestBehavior(ParserContextBehavior.NonEmptyStringIsTrue) && (value is string) && ((string) value).Length > 0) - return true; - - if (TestBehavior(ParserContextBehavior.EmptyStringIsFalse) && (value is string) && ((string) value).Length == 0) - return false; - - if (TestBehavior(ParserContextBehavior.NotNullIsTrue)) - return true; - } - else - { - if (TestBehavior(ParserContextBehavior.NullIsFalse)) - return false; - } - - if (_parentContext != null) - return _parentContext.ToBoolean(value); - - if (value == null) - throw new NullReferenceException(); - else - throw new ArgumentException("Type " + value.GetType().Name + " cannot be evaluated as boolean"); - } - - public string Format(string formatString, params object[] parameters) - { - return string.Format(FormatProvider, formatString, parameters); - } - } +#region License +//============================================================================= +// Vici Core - Productivity Library for .NET 3.5 +// +// Copyright (c) 2008-2012 Philippe Leybaert +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//============================================================================= +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; + +namespace Vici.Core.Parser +{ + public class ParserContext : IParserContext + { + private readonly Dictionary _variables; + private readonly Dictionary _types; + private readonly object _rootObject; + + private readonly IParserContext _parentContext; + + public ParserContextBehavior Behavior { get; private set; } + + private AssignmentPermissions _assignmentPermissions = AssignmentPermissions.None; + private StringComparison _stringComparison = StringComparison.Ordinal; + private IFormatProvider _formatProvider = NumberFormatInfo.InvariantInfo; + + /// + /// The optional custom resolver for when variables can be resolved from the contexts + /// + private Func> _customResolver; + + public ParserContext(ParserContextBehavior behavior) + { + Behavior = behavior; + + if ((behavior & ParserContextBehavior.CaseInsensitiveVariables) == ParserContextBehavior.CaseInsensitiveVariables) + { + _variables = new Dictionary(StringComparer.OrdinalIgnoreCase); + _types = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + else + { + _variables = new Dictionary(); + _types = new Dictionary(); + + } + } + + public ParserContext() : this(ParserContextBehavior.Default) + { + } + + public ParserContext(object rootObject, ParserContextBehavior behavior) : this(behavior) + { + _rootObject = rootObject; + } + + public ParserContext(object rootObject) : this(rootObject, ParserContextBehavior.Default) + { + } + + protected ParserContext(ParserContext parentContext) : this(parentContext.Behavior) + { + _parentContext = parentContext; + + _assignmentPermissions = parentContext._assignmentPermissions; + _stringComparison = parentContext._stringComparison; + _formatProvider = parentContext._formatProvider; + } + + public virtual IParserContext CreateLocal() + { + return new ParserContext(this); + } + + private bool TestBehavior(ParserContextBehavior behavior) + { + return ((Behavior & behavior) == behavior); + } + +// public bool ReturnNullWhenNullReference +// { +// get { return _returnNullWhenNullReference; } +// set { _returnNullWhenNullReference = value; } +// } +// +// public bool NullIsFalse +// { +// get { return _nullIsFalse; } +// set { _nullIsFalse = value; } +// } +// +// public bool NotNullIsTrue +// { +// get { return _notNullIsTrue; } +// set { _notNullIsTrue = value; } +// } +// +// public bool EmptyStringIsFalse +// { +// get { return _emptyStringIsFalse; } +// set { _emptyStringIsFalse = value; } +// } +// +// public bool NonEmptyStringIsTrue +// { +// get { return _nonEmptyStringIsTrue; } +// set { _nonEmptyStringIsTrue = value; } +// } + +// public bool CaseSensitiveVariables +// { +// get { return _caseSensitiveVariables; } +// set +// { +// if (value != _caseSensitiveVariables) +// { +// if (value) +// { +// _variables = new Dictionary(); +// _types = new Dictionary(); +// } +// else +// { +// _variables = new Dictionary(StringComparer.InvariantCultureIgnoreCase); +// _types = new Dictionary(StringComparer.InvariantCultureIgnoreCase); +// +// } +// _caseSensitiveVariables = value; +// } +// } +// } + + public AssignmentPermissions AssignmentPermissions + { + get { return _assignmentPermissions; } + set { _assignmentPermissions = value; } + } + + public StringComparison StringComparison + { + get { return _stringComparison; } + set { _stringComparison = value; } + } + + /// + /// Get or set a custom resolver. + /// + public Func> CustomResolver + { + get + { + return _customResolver; + } + set + { + _customResolver = value; + } + } + +// public bool EmptyCollectionIsFalse +// { +// get { return _emptyCollectionIsFalse; } +// set { _emptyCollectionIsFalse = value; } +// } +// +// public bool NotZeroIsTrue +// { +// get { return _notZeroIsTrue; } +// set { _notZeroIsTrue = value; } +// } +// + public IFormatProvider FormatProvider + { + get { return _formatProvider; } + set { _formatProvider = value; } + } + + public void SetLocal(string name, T data) + { + SetLocal(name, data, typeof (T)); + } + + public void SetLocal(string name, IValueWithType data) + { + SetLocal(name, data.Value, data.Type); + } + + public void SetLocal(string name, object data, Type type) + { + _variables[name] = data; + _types[name] = type; + } + + public void Set(string name, object data, Type type) + { + if (_parentContext != null && _parentContext.Exists(name)) + _parentContext.Set(name, data, type); + + SetLocal(name, data, type); + } + + public void Set(string name, T data) + { + Set(name, data, typeof (T)); + } + + public void Set(string name, IValueWithType data) + { + Set(name, data.Value, data.Type); + } + + public void AddType(string name, Type type) + { + Set(name, ContextFactory.CreateType(type)); + } + + public void AddFunction(string name, Type type, string methodName) + { + Set(name, ContextFactory.CreateFunction(type, methodName)); + } + + public void AddFunction(string name, Type type, string methodName, object targetObject) + { + Set(name, ContextFactory.CreateFunction(type, methodName, targetObject)); + } + + public void AddFunction(string name, MethodInfo methodInfo) + { + Set(name, ContextFactory.CreateFunction(methodInfo)); + } + + public void AddFunction(string name, MethodInfo methodInfo, object targetObject) + { + Set(name, ContextFactory.CreateFunction(methodInfo, targetObject)); + } + + public virtual bool Exists(string varName) + { + if (_variables.ContainsKey(varName)) + return true; + + if (_rootObject != null && PropertyHelper.Exists(_rootObject, varName)) + return true; + + if (_parentContext == null || !_parentContext.Exists(varName)) + return false; + + return true; + } + + public virtual bool Get(string varName, out object value, out Type type) + { + if (_variables.ContainsKey(varName)) + { + value = _variables[varName]; + type = _types[varName]; + } + else if (_rootObject != null && PropertyHelper.TryGetValue(_rootObject,varName,out value, out type)) + { + return true; + } + else + { + // if doesn't have parent context, or parent context can't help... + if (_parentContext == null || !_parentContext.Get(varName, out value, out type)) + { + // if we have a custom resolver... + if (CustomResolver != null) + { + Tuple result = CustomResolver(varName); + + // if we got a result back... + if (result != null) + { + value = result.Value1; + type = result.Value2; + + return true; + } + } + + value = null; + type = typeof(object); + + return false; + } + } + + if (type == typeof(object) && value != null) + type = value.GetType(); + + return true; + } + + public bool ToBoolean(object value) + { + if (value != null) + { + if (value is bool) + return ((bool) value); + + if (TestBehavior(ParserContextBehavior.ZeroIsFalse)) + { + if (value is int || value is uint || value is short || value is ushort || value is long || value is ulong || value is byte || value is sbyte) + return Convert.ToInt64(value) != 0; + + if (value is decimal) + return (decimal) value != 0m; + + if (value is float || value is double) + return Convert.ToDouble(value) == 0.0; + } + + if (TestBehavior(ParserContextBehavior.EmptyCollectionIsFalse)) + { + if (value is ICollection) + return ((ICollection) value).Count > 0; + + if (value is IEnumerable) + { + IEnumerator enumerator = ((IEnumerable) value).GetEnumerator(); + + if (enumerator.MoveNext()) + return true; + + return false; + } + } + + if (TestBehavior(ParserContextBehavior.NonEmptyStringIsTrue) && (value is string) && ((string) value).Length > 0) + return true; + + if (TestBehavior(ParserContextBehavior.EmptyStringIsFalse) && (value is string) && ((string) value).Length == 0) + return false; + + if (TestBehavior(ParserContextBehavior.NotNullIsTrue)) + return true; + } + else + { + if (TestBehavior(ParserContextBehavior.NullIsFalse)) + return false; + } + + if (_parentContext != null) + return _parentContext.ToBoolean(value); + + if (value == null) + throw new NullReferenceException(); + else + throw new ArgumentException("Type " + value.GetType().Name + " cannot be evaluated as boolean"); + } + + public string Format(string formatString, params object[] parameters) + { + return string.Format(FormatProvider, formatString, parameters); + } + } } \ No newline at end of file diff --git a/Library/Parser/ExpressionParser/Expression/ContainerClasses/InstanceMethod.cs b/Library/Parser/ExpressionParser/Expression/ContainerClasses/InstanceMethod.cs index c00603a..ce7248e 100644 --- a/Library/Parser/ExpressionParser/Expression/ContainerClasses/InstanceMethod.cs +++ b/Library/Parser/ExpressionParser/Expression/ContainerClasses/InstanceMethod.cs @@ -1,58 +1,70 @@ -#region License -//============================================================================= -// Vici Core - Productivity Library for .NET 3.5 -// -// Copyright (c) 2008-2012 Philippe Leybaert -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//============================================================================= -#endregion - -using System; -using System.Reflection; - -namespace Vici.Core.Parser -{ - internal class InstanceMethod : MethodDefinition - { - private readonly object _object; - - public InstanceMethod(MethodInfo methodInfo, object @object) : base(methodInfo) - { - _object = @object; - } - - public InstanceMethod(Type type, string methodName, object @object) : base(type, methodName) - { - _object = @object; - } - - public override object Invoke(Type[] types, object[] parameters, out Type returnType) - { - MethodInfo methodInfo = GetMethodInfo(types); - - if (methodInfo == null) - throw new MissingMethodException(MethodName); - - returnType = methodInfo.ReturnType; - - return LazyBinder.Invoke(methodInfo, _object, parameters); - } - } +#region License +//============================================================================= +// Vici Core - Productivity Library for .NET 3.5 +// +// Copyright (c) 2008-2012 Philippe Leybaert +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//============================================================================= +#endregion + +using System; +using System.Reflection; + +namespace Vici.Core.Parser +{ + internal class InstanceMethod : MethodDefinition + { + private readonly object _object; + + public InstanceMethod(MethodInfo methodInfo, object @object) : base(methodInfo) + { + _object = @object; + } + + /// + /// Create an instance with an array of possible methods. + /// + /// An array of methods + /// The instance object + public InstanceMethod(MethodInfo[] methodInfo, object @object) + : base(methodInfo) + { + _object = @object; + } + + + public InstanceMethod(Type type, string methodName, object @object) : base(type, methodName) + { + _object = @object; + } + + public override object Invoke(Type[] types, object[] parameters, out Type returnType) + { + MethodInfo methodInfo = GetMethodInfo(types); + + if (methodInfo == null) + throw new MissingMethodException(MethodName); + + returnType = methodInfo.ReturnType; + + return LazyBinder.Invoke(methodInfo, _object, parameters); + } + } } \ No newline at end of file diff --git a/Library/Parser/ExpressionParser/Expression/ContainerClasses/MethodDefinition.cs b/Library/Parser/ExpressionParser/Expression/ContainerClasses/MethodDefinition.cs index efd9743..edb9698 100644 --- a/Library/Parser/ExpressionParser/Expression/ContainerClasses/MethodDefinition.cs +++ b/Library/Parser/ExpressionParser/Expression/ContainerClasses/MethodDefinition.cs @@ -1,84 +1,107 @@ -#region License -//============================================================================= -// Vici Core - Productivity Library for .NET 3.5 -// -// Copyright (c) 2008-2012 Philippe Leybaert -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//============================================================================= -#endregion - -using System; -using System.Reflection; - -namespace Vici.Core.Parser -{ - internal abstract class MethodDefinition : IMethodDefinition - { - protected readonly Type _type; - protected readonly string _methodName; - protected readonly MethodInfo _methodInfo; - - protected MethodDefinition(MethodInfo methodInfo) - { - _methodInfo = methodInfo; - } - - protected MethodDefinition(Type type, string methodName) - { - _type = type; - _methodName = methodName; - } - - public string MethodName - { - get { return _methodName; } - } - - public Type Type - { - get { return _type; } - } - - public MethodInfo GetMethodInfo(Type[] parameterTypes) - { - if (_methodInfo != null) - return _methodInfo; - - Type t = _type; - - while (t != null) - { - MethodInfo methodInfo = t.Inspector().GetMethod(_methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, parameterTypes); - - if (methodInfo != null) - return methodInfo; - - t = t.Inspector().BaseType; - } - - return null; - - - //return _methodInfo ?? _type.GetMethod(_methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, binder ?? LazyBinder.Default, parameterTypes, null); - } - - public abstract object Invoke(Type[] types, object[] parameters, out Type returnType); - } +#region License +//============================================================================= +// Vici Core - Productivity Library for .NET 3.5 +// +// Copyright (c) 2008-2012 Philippe Leybaert +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//============================================================================= +#endregion + +using System; +using System.Reflection; + +namespace Vici.Core.Parser +{ + internal abstract class MethodDefinition : IMethodDefinition + { + protected readonly Type _type; + protected readonly string _methodName; + + /// + /// THe array of suitable methods + /// + protected readonly MethodInfo[] _methodInfo; + + protected MethodDefinition(MethodInfo methodInfo) + { + _methodInfo = new MethodInfo[1] { methodInfo }; + } + + /// + /// Create an instance with an array of suitable methods. + /// + /// The array of methods + protected MethodDefinition(MethodInfo[] methodInfo) + { + _methodInfo = methodInfo; + } + + protected MethodDefinition(Type type, string methodName) + { + _type = type; + _methodName = methodName; + } + + public string MethodName + { + get { return _methodName; } + } + + public Type Type + { + get { return _type; } + } + + public MethodInfo GetMethodInfo(Type[] parameterTypes) + { + // If method information was provided then we use them + if (_methodInfo != null) + { + // only a single method, lets run with that one + if (_methodInfo.Length == 1) + { + return _methodInfo[0]; + } + + // more than one method, now need to select the best... + return LazyBinder.SelectBestMethod(_methodInfo, parameterTypes); + } + + Type t = _type; + + while (t != null) + { + MethodInfo methodInfo = t.Inspector().GetMethod(_methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, parameterTypes); + + if (methodInfo != null) + return methodInfo; + + t = t.Inspector().BaseType; + } + + return null; + + + //return _methodInfo ?? _type.GetMethod(_methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, binder ?? LazyBinder.Default, parameterTypes, null); + } + + public abstract object Invoke(Type[] types, object[] parameters, out Type returnType); + } } \ No newline at end of file diff --git a/Library/Parser/ExpressionParser/Expression/ContainerClasses/StaticMethod.cs b/Library/Parser/ExpressionParser/Expression/ContainerClasses/StaticMethod.cs index 7376ef8..aa4412d 100644 --- a/Library/Parser/ExpressionParser/Expression/ContainerClasses/StaticMethod.cs +++ b/Library/Parser/ExpressionParser/Expression/ContainerClasses/StaticMethod.cs @@ -1,54 +1,63 @@ -#region License -//============================================================================= -// Vici Core - Productivity Library for .NET 3.5 -// -// Copyright (c) 2008-2012 Philippe Leybaert -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//============================================================================= -#endregion - -using System; -using System.Reflection; - -namespace Vici.Core.Parser -{ - internal class StaticMethod : MethodDefinition - { - public StaticMethod(MethodInfo methodInfo) : base(methodInfo) - { - } - - public StaticMethod(Type type, string methodName) : base(type, methodName) - { - } - - public override object Invoke(Type[] types, object[] parameters, out Type returnType) - { - MethodInfo methodInfo = GetMethodInfo(types); - - if (methodInfo == null) - throw new MissingMethodException(MethodName); - - returnType = methodInfo.ReturnType; - - return methodInfo.Invoke(null, parameters); - } - } +#region License +//============================================================================= +// Vici Core - Productivity Library for .NET 3.5 +// +// Copyright (c) 2008-2012 Philippe Leybaert +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//============================================================================= +#endregion + +using System; +using System.Reflection; + +namespace Vici.Core.Parser +{ + internal class StaticMethod : MethodDefinition + { + public StaticMethod(MethodInfo methodInfo) : base(methodInfo) + { + } + + /// + /// Create an instance with an array of matching methods. + /// + /// The array of methods + public StaticMethod(MethodInfo[] methodInfo) + : base(methodInfo) + { + } + + public StaticMethod(Type type, string methodName) : base(type, methodName) + { + } + + public override object Invoke(Type[] types, object[] parameters, out Type returnType) + { + MethodInfo methodInfo = GetMethodInfo(types); + + if (methodInfo == null) + throw new MissingMethodException(MethodName); + + returnType = methodInfo.ReturnType; + + return methodInfo.Invoke(null, parameters); + } + } } \ No newline at end of file diff --git a/Library/Parser/ExpressionParser/Expression/FieldExpression.cs b/Library/Parser/ExpressionParser/Expression/FieldExpression.cs index dd317f8..897bd95 100644 --- a/Library/Parser/ExpressionParser/Expression/FieldExpression.cs +++ b/Library/Parser/ExpressionParser/Expression/FieldExpression.cs @@ -1,157 +1,206 @@ -#region License -//============================================================================= -// Vici Core - Productivity Library for .NET 3.5 -// -// Copyright (c) 2008-2012 Philippe Leybaert -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//============================================================================= -#endregion - -using System; -using System.Reflection; -using System.Collections.Generic; - -namespace Vici.Core.Parser -{ - public class FieldExpression : Expression - { - private readonly Expression _target; - private readonly string _member; - - public FieldExpression(TokenPosition position, Expression target, string member) : base(position) - { - _target = target; - _member = member; - } - - public override ValueExpression Evaluate(IParserContext context) - { - return Evaluate(context, false, null); - } - - private ValueExpression Evaluate(IParserContext context, bool assign, object newValue) - { - ValueExpression targetValue = _target.Evaluate(context); - object targetObject; - Type targetType; - - if (targetValue.Value is ClassName) - { - targetType = ((ClassName) targetValue.Value).Type; - targetObject = null; - } - else - { - targetType = targetValue.Type; - targetObject = targetValue.Value; - - if (targetObject == null) - return new ValueExpression(TokenPosition, null, targetType); - } - - if (targetObject is IDynamicObject) - { - object value; - Type type; - - if (((IDynamicObject)targetObject).TryGetValue(_member, out value, out type)) - return new ValueExpression(TokenPosition, value,type); - } - - MemberInfo[] members = FindMemberInHierarchy(targetType, _member);// targetType.GetMember(_member); - - if (members.Length == 0) - { - PropertyInfo indexerPropInfo = targetType.Inspector().GetIndexer(new[] { typeof(string) }); - - if (indexerPropInfo != null) - { - return new ValueExpression(TokenPosition, indexerPropInfo.GetValue(targetObject, new object[] { _member }), indexerPropInfo.PropertyType); - } - - throw new UnknownPropertyException("Unknown property " + _member + " for object " + _target + " (type " + targetType.Name + ")", this); - } - - if (members.Length >= 1 && members[0] is MethodInfo) - { - if (targetObject == null) - return Exp.Value(TokenPosition, new StaticMethod(targetType, _member)); - else - return Exp.Value(TokenPosition, new InstanceMethod(targetType, _member, targetObject)); - } - - MemberInfo member = members[0]; - - if (members.Length > 1 && targetObject != null) // CoolStorage, ActiveRecord and Dynamic Proxy frameworks sometimes return > 1 member - { - foreach (MemberInfo mi in members) - if (mi.DeclaringType == targetObject.GetType()) - member = mi; - } - - if (assign) - { - if (member is FieldInfo) - ((FieldInfo) member).SetValue(targetObject, newValue); - - if (member is PropertyInfo) - ((PropertyInfo) member).SetValue(targetObject, newValue, null); - - // Fall through to get the new property/field value below - } - - if (member is FieldInfo) - return new ValueExpression(TokenPosition, ((FieldInfo) member).GetValue(targetObject), ((FieldInfo) member).FieldType); - - if (member is PropertyInfo) - return new ValueExpression(TokenPosition, ((PropertyInfo)member).GetValue(targetObject, null), ((PropertyInfo)member).PropertyType); - - throw new ExpressionEvaluationException(_member + " is not a field or property", this); - } - - private static MemberInfo[] FindMemberInHierarchy(Type type, string name) - { - Type t = type; - - while (t != null) - { - MemberInfo[] members = t.Inspector().GetMember(name); - - if (members.Length > 0) - return members; - - t = t.Inspector().BaseType; - } - - return new MemberInfo[0]; - } - - public override string ToString() - { - return "(" + _target + "." + _member + ")"; - } - - - public ValueExpression Assign(IParserContext context, object value) - { - return Evaluate(context, true, value); - } - } +#region License +//============================================================================= +// Vici Core - Productivity Library for .NET 3.5 +// +// Copyright (c) 2008-2012 Philippe Leybaert +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//============================================================================= +#endregion + +using System; +using System.Reflection; +using System.Collections.Generic; + +namespace Vici.Core.Parser +{ + public class FieldExpression : Expression + { + private readonly Expression _target; + private readonly string _member; + + /// + /// An array of generic Types + /// + private readonly Type[] _genericTypes; + + /// + /// Create a field expression. + /// + /// + /// + /// + /// An optional collection of genericTypes + public FieldExpression(TokenPosition position, Expression target, string member, Type[] genericTypes = null) + : base(position) + { + _target = target; + _member = member; + _genericTypes = genericTypes; + } + + public override ValueExpression Evaluate(IParserContext context) + { + return Evaluate(context, false, null); + } + + private ValueExpression Evaluate(IParserContext context, bool assign, object newValue) + { + ValueExpression targetValue = _target.Evaluate(context); + object targetObject; + Type targetType; + + if (targetValue.Value is ClassName) + { + targetType = ((ClassName) targetValue.Value).Type; + targetObject = null; + } + else + { + targetType = targetValue.Type; + targetObject = targetValue.Value; + + if (targetObject == null) + return new ValueExpression(TokenPosition, null, targetType); + } + + if (targetObject is IDynamicObject) + { + object value; + Type type; + + if (((IDynamicObject)targetObject).TryGetValue(_member, out value, out type)) + return new ValueExpression(TokenPosition, value,type); + } + + // Resolve the matching members + MemberInfo[] members = FindMemberInHierarchy(targetType, _member, _genericTypes);// targetType.GetMember(_member); + + if (members.Length == 0) + { + PropertyInfo indexerPropInfo = targetType.Inspector().GetIndexer(new[] { typeof(string) }); + + if (indexerPropInfo != null) + { + return new ValueExpression(TokenPosition, indexerPropInfo.GetValue(targetObject, new object[] { _member }), indexerPropInfo.PropertyType); + } + + throw new UnknownPropertyException("Unknown property " + _member + " for object " + _target + " (type " + targetType.Name + ")", this); + } + + + // Use the existing reflected members which have already had the generic(s) if any applied + if (members.Length >= 1 && members[0] is MethodInfo) + { + MethodInfo[] methodInfo = members.ConvertAll((p) => p as MethodInfo); + + if (targetObject == null) + return Exp.Value(TokenPosition, new StaticMethod(methodInfo)); + else + return Exp.Value(TokenPosition, new InstanceMethod(methodInfo, targetObject)); + } + + MemberInfo member = members[0]; + + if (members.Length > 1 && targetObject != null) // CoolStorage, ActiveRecord and Dynamic Proxy frameworks sometimes return > 1 member + { + foreach (MemberInfo mi in members) + if (mi.DeclaringType == targetObject.GetType()) + member = mi; + } + + if (assign) + { + if (member is FieldInfo) + ((FieldInfo) member).SetValue(targetObject, newValue); + + if (member is PropertyInfo) + ((PropertyInfo) member).SetValue(targetObject, newValue, null); + + // Fall through to get the new property/field value below + } + + if (member is FieldInfo) + return new ValueExpression(TokenPosition, ((FieldInfo) member).GetValue(targetObject), ((FieldInfo) member).FieldType); + + if (member is PropertyInfo) + return new ValueExpression(TokenPosition, ((PropertyInfo)member).GetValue(targetObject, null), ((PropertyInfo)member).PropertyType); + + throw new ExpressionEvaluationException(_member + " is not a field or property", this); + } + + private static MemberInfo[] FindMemberInHierarchy(Type type, string name) + { + Type t = type; + + while (t != null) + { + MemberInfo[] members = t.Inspector().GetMember(name); + + if (members.Length > 0) + return members; + + t = t.Inspector().BaseType; + } + + return new MemberInfo[0]; + } + + /// + /// Find matching members for a type, matching on a name and specified generic types. + /// + /// The type to search + /// The name of the member + /// An array of types + /// An array of matching instances. + private static MemberInfo[] FindMemberInHierarchy(Type type, string name, Type[] genericNames) + { + // if we don't have any generics specified, then use the default model + if (genericNames == null || genericNames.Length == 0) + { + return FindMemberInHierarchy(type, name); + + } + + Type t = type; + + MemberInfo[] members = t.Inspector().GetMember(name, genericNames); + + // if we have members return it + if (members.Length > 0) + { + return members; + } + + // return empty array + return new MemberInfo[0]; + } + + public override string ToString() + { + return "(" + _target + "." + _member + ")"; + } + + + public ValueExpression Assign(IParserContext context, object value) + { + return Evaluate(context, true, value); + } + } } \ No newline at end of file diff --git a/Library/Parser/ExpressionParser/Expression/GenericVariableExpression.cs b/Library/Parser/ExpressionParser/Expression/GenericVariableExpression.cs new file mode 100644 index 0000000..6b24d1f --- /dev/null +++ b/Library/Parser/ExpressionParser/Expression/GenericVariableExpression.cs @@ -0,0 +1,204 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Vici.Core.Parser +{ + + /// + /// Represents a Generic Variable + /// + public class GenericVariableExpression : Expression + { + /// + /// The name of the variable + /// + private readonly string _varName; + + /// + /// The list of generic types + /// + private readonly Type[] _genericTypes; + + + /// + /// Create an instance + /// + /// The token position + /// The variable name + public GenericVariableExpression(TokenPosition position, string varName) + : base(position) + { + // now then, the varName is of the form...actual variable name < ,,,,> + int genericStart = varName.IndexOf('<'); + + _varName = varName.Left(varName.IndexOf('<')); + + // now we need to strip the ','s out of the + string[] genericNames = varName.Substring(genericStart + 1, (varName.Length - 1) - (genericStart + 1)).Split(','); + + // now have a list of types as strings, we need to construct a list of Types + List resolvedTypes = new List(); + + foreach (string genericName in genericNames) + { + resolvedTypes.Add(GetTypeFromSimpleName(genericName)); + } + + _genericTypes = resolvedTypes.ToArray(); + } + + /// + /// For a type name, return the associated Type. + /// + /// The name of the type + /// A + /// Accomodates those types which the compiler knows about e.g. int and uses a fully qualified name for that type. + private Type GetTypeFromSimpleName(string typeName) + { + if (typeName == null) + throw new ArgumentNullException("typeName"); + + bool isArray = false, isNullable = false; + + if (typeName.IndexOf("[]") != -1) + { + isArray = true; + typeName = typeName.Remove(typeName.IndexOf("[]"), 2); + } + + if (typeName.IndexOf("?") != -1) + { + isNullable = true; + typeName = typeName.Remove(typeName.IndexOf("?"), 1); + } + + typeName = typeName.ToLower(); + + string parsedTypeName = null; + switch (typeName) + { + case "bool": + case "boolean": + parsedTypeName = "System.Boolean"; + break; + case "byte": + parsedTypeName = "System.Byte"; + break; + case "char": + parsedTypeName = "System.Char"; + break; + case "datetime": + parsedTypeName = "System.DateTime"; + break; + case "datetimeoffset": + parsedTypeName = "System.DateTimeOffset"; + break; + case "decimal": + parsedTypeName = "System.Decimal"; + break; + case "double": + parsedTypeName = "System.Double"; + break; + case "float": + parsedTypeName = "System.Single"; + break; + case "int16": + case "short": + parsedTypeName = "System.Int16"; + break; + case "int32": + case "int": + parsedTypeName = "System.Int32"; + break; + case "int64": + case "long": + parsedTypeName = "System.Int64"; + break; + case "object": + parsedTypeName = "System.Object"; + break; + case "sbyte": + parsedTypeName = "System.SByte"; + break; + case "string": + parsedTypeName = "System.String"; + break; + case "timespan": + parsedTypeName = "System.TimeSpan"; + break; + case "uint16": + case "ushort": + parsedTypeName = "System.UInt16"; + break; + case "uint32": + case "uint": + parsedTypeName = "System.UInt32"; + break; + case "uint64": + case "ulong": + parsedTypeName = "System.UInt64"; + break; + } + + if (parsedTypeName != null) + { + if (isArray) + parsedTypeName = parsedTypeName + "[]"; + + if (isNullable) + parsedTypeName = String.Concat("System.Nullable`1[", parsedTypeName, "]"); + } + else + parsedTypeName = typeName; + + return Type.GetType(parsedTypeName); + } + + /// + /// Get the variable name + /// + public string VarName + { + get { return _varName; } + } + + /// + /// Get the array of generic types. + /// + public Type[] Generics + { + get { return _genericTypes; } + } + + public override ValueExpression Evaluate(IParserContext context) + { + // we aren't a variable, so such be treated as such + //if (!context.Get(VarName, out value, out type)) + // return new ValueExpression(TokenPosition, null,typeof(object)); + + if (_genericTypes.Length != 0) + { + throw new ArgumentException("this is an error"); + } + else + { + object value; + Type type; + + if (!context.Get(VarName, out value, out type)) + return new ValueExpression(TokenPosition, null, typeof(object)); + + return new ValueExpression(TokenPosition, value, type); + } + + } + + public override string ToString() + { + return _varName; + } + + } +} diff --git a/Library/Parser/Parsers/CSharp/Parser/CSharpEvaluator.cs b/Library/Parser/Parsers/CSharp/Parser/CSharpEvaluator.cs index 93c7f5f..f6476f4 100644 --- a/Library/Parser/Parsers/CSharp/Parser/CSharpEvaluator.cs +++ b/Library/Parser/Parsers/CSharp/Parser/CSharpEvaluator.cs @@ -1,345 +1,369 @@ -#region License -//============================================================================= -// Vici Core - Productivity Library for .NET 3.5 -// -// Copyright (c) 2008-2012 Philippe Leybaert -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//============================================================================= -#endregion - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; - -namespace Vici.Core.Parser -{ - public static class CSharpEvaluator - { - private static readonly NumberFormatInfo _numberFormat; - - static CSharpEvaluator() - { - _numberFormat = new NumberFormatInfo - { - NumberDecimalSeparator = ".", - NumberGroupSeparator = ",", - NumberGroupSizes = new[] {3} - }; - } - - public static Expression TypeCast(string token, TokenPosition position, Expression[] terms) - { - return new TypeCastExpression(position, new VariableExpression(position, token.Substring(1, token.Length - 2).Trim()), terms[0]); - } - - public static Expression IsAsOperator(string token, TokenPosition position, Expression[] terms) - { - if (token == "as") - return new AsExpression(position, terms[0], terms[1]); - - if (token == "is") - return new IsExpression(position, terms[0], terms[1]); - - return null; - } - - public static Expression InOperator(string token, TokenPosition position, Expression[] terms) - { - VariableExpression varExpression = terms[0] as VariableExpression; - - return new InExpression(position, varExpression, terms[1]); - } - - - public static Expression Ternary(string token, TokenPosition position, Expression[] terms) - { - return new ConditionalExpression(position, terms[0], terms[1], terms[2]); - } - - private static char UnEscape(string s, TokenPosition position) - { - if (s.Length == 1) - return s[0]; - - if (s.Length == 2) - { - switch (s[1]) - { - case '\\': - case '\"': - case '\'': - return s[1]; - case '0': - return (char)0; - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - case 'v': - return '\v'; - default: - throw new UnknownTokenException(position,s); - } - } - else - { - return (char)Convert.ToUInt16(s.Substring(2), 16); - } - } - - public static Expression TypeOf(string token, TokenPosition position, Expression[] terms) - { - return new TypeOfExpression(position); - } - - public static Expression CharLiteral(string token, TokenPosition position, Expression[] terms) - { - return Exp.Value(position, UnEscape(token.Substring(1, token.Length - 2), position)); - } - - public static Expression Number(string token, TokenPosition position, Expression[] terms) - { - string s = token; - - Type type = null; - - if (!char.IsDigit(s[s.Length - 1])) - { - string suffix = "" + char.ToUpper(s[s.Length - 1]); - - s = s.Remove(s.Length - 1); - - if (!char.IsDigit(s[s.Length - 1])) - { - suffix = char.ToUpper(s[s.Length - 1]) + suffix; - - s = s.Remove(s.Length - 1); - } - - switch (suffix) - { - case "M": - type = typeof(decimal); - break; - case "D": - type = typeof(double); - break; - case "F": - type = typeof(float); - break; - case "L": - type = typeof(long); - break; - case "U": - type = typeof(uint); - break; - case "LU": - case "UL": - type = typeof(ulong); - break; - } - } - - if (type != null) - return new ValueExpression(position, Convert.ChangeType(s, type, _numberFormat), type); - - if (s.LastIndexOf('.') >= 0) - { - return Exp.Value(position, Convert.ToDouble(s, _numberFormat)); - } - else - { - long n = Convert.ToInt64(s); - - if (n > Int32.MaxValue || n < Int32.MinValue) - return Exp.Value(position, n); - else - return Exp.Value(position, (int)n); - } - } - - public static Expression VarName(string token, TokenPosition position, Expression[] terms) - { - return new VariableExpression(position, token); - } - - public static Expression Function(string token, TokenPosition position, Expression[] terms) - { - Expression[] parameters = new Expression[terms.Length - 1]; - - Array.Copy(terms, 1, parameters, 0, parameters.Length); - - if (token == "[") - { - return new IndexExpression(position, terms[0], parameters); - } - else - { - return new CallExpression(position, terms[0], parameters); - } - } - - public static Expression Coalesce(string token, TokenPosition position, Expression[] terms) - { - return new CoalesceExpression(position, terms[0], terms[1]); - } - - public static Expression DefaultValueOperator(string token, TokenPosition position, Expression[] terms) - { - return new DefaultValueExpression(position, terms[0], terms[1]); - } - - public static Expression ShortcutOperator(string token, TokenPosition position, Expression[] terms) - { - if (token == "&&") - return new AndAlsoExpression(position, terms[0], terms[1]); - - if (token == "||") - return new OrElseExpression(position, terms[0], terms[1]); - - return null; - } - - public static Expression Unary(string token, TokenPosition position, Expression[] terms) - { - if (token == "!") - return new NegationExpression(position, terms[0]); - - if (token == "-") - return new UnaryMinusExpression(position, terms[0]); - - if (token == "~") - return new BitwiseComplementExpression(position, terms[0]); - - return null; - } - - public static Expression StatementSeperator(string token, TokenPosition position, Expression[] terms) - { - return new SequenceExpression(position,terms); - } - - public static Expression Operator(string token, TokenPosition position, Expression[] terms) - { - return Exp.Op(position, token, terms[0], terms[1]); - } - - public static Expression Assignment(string token, TokenPosition position, Expression[] terms) - { - return new AssignmentExpression(position, terms[0], terms[1]); - } - - public static Expression StringLiteral(string token, TokenPosition position, Expression[] terms) - { - string s = token.Substring(1, token.Length - 2); - - if (s.IndexOf('\\') < 0) - return Exp.Value(position, s); - - StringBuilder output = new StringBuilder(token.Length); - - bool inEscape = false; - string hexString = null; - - for (int i = 0; i < s.Length; i++) - { - char c = s[i]; - - if (inEscape) - { - if (c == 'x') - { - hexString = ""; - continue; - } - - if (hexString == null && (c != 'x' || c != 'X')) - { - output.Append(UnEscape("\\" + c, position)); - inEscape = false; - continue; - } - - if (hexString == null) - { - inEscape = false; - } - else - { - if (((char.ToLower(c) < 'a' || char.ToLower(c) > 'f') && (c < '0' || c > '9')) || hexString.Length == 4) - { - output.Append(UnEscape("\\x" + hexString, position)); - inEscape = false; - hexString = null; - } - else - { - hexString += c; - continue; - } - } - } - - if (c != '\\') - { - output.Append(c); - - continue; - } - - inEscape = true; - } - - return Exp.Value(position, output.ToString()); - } - - public static Expression DotOperator(string token, TokenPosition position, Expression[] terms) - { - VariableExpression varExpression = terms[1] as VariableExpression; - - if (varExpression == null) - throw new UnknownPropertyException("Unkown member " + terms[1], terms[1]); - - return new FieldExpression(position, terms[0], varExpression.VarName); - } - - public static Expression Constructor(string token, TokenPosition position, Expression[] terms) - { - string className = token.Substring(3).Trim(); - - return new ConstructorExpression(position, new VariableExpression(position, className), terms); - } - - public static Expression NumericRange(string token, TokenPosition position, Expression[] terms) - { - return new RangeExpression(position, terms[0], terms[1]); - } - } +#region License +//============================================================================= +// Vici Core - Productivity Library for .NET 3.5 +// +// Copyright (c) 2008-2012 Philippe Leybaert +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//============================================================================= +#endregion + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace Vici.Core.Parser +{ + public static class CSharpEvaluator + { + private static readonly NumberFormatInfo _numberFormat; + + static CSharpEvaluator() + { + _numberFormat = new NumberFormatInfo + { + NumberDecimalSeparator = ".", + NumberGroupSeparator = ",", + NumberGroupSizes = new[] {3} + }; + } + + public static Expression TypeCast(string token, TokenPosition position, Expression[] terms) + { + return new TypeCastExpression(position, new VariableExpression(position, token.Substring(1, token.Length - 2).Trim()), terms[0]); + } + + public static Expression IsAsOperator(string token, TokenPosition position, Expression[] terms) + { + if (token == "as") + return new AsExpression(position, terms[0], terms[1]); + + if (token == "is") + return new IsExpression(position, terms[0], terms[1]); + + return null; + } + + public static Expression InOperator(string token, TokenPosition position, Expression[] terms) + { + VariableExpression varExpression = terms[0] as VariableExpression; + + return new InExpression(position, varExpression, terms[1]); + } + + + public static Expression Ternary(string token, TokenPosition position, Expression[] terms) + { + return new ConditionalExpression(position, terms[0], terms[1], terms[2]); + } + + private static char UnEscape(string s, TokenPosition position) + { + if (s.Length == 1) + return s[0]; + + if (s.Length == 2) + { + switch (s[1]) + { + case '\\': + case '\"': + case '\'': + return s[1]; + case '0': + return (char)0; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + default: + throw new UnknownTokenException(position,s); + } + } + else + { + return (char)Convert.ToUInt16(s.Substring(2), 16); + } + } + + public static Expression TypeOf(string token, TokenPosition position, Expression[] terms) + { + return new TypeOfExpression(position); + } + + public static Expression CharLiteral(string token, TokenPosition position, Expression[] terms) + { + return Exp.Value(position, UnEscape(token.Substring(1, token.Length - 2), position)); + } + + public static Expression Number(string token, TokenPosition position, Expression[] terms) + { + string s = token; + + Type type = null; + + if (!char.IsDigit(s[s.Length - 1])) + { + string suffix = "" + char.ToUpper(s[s.Length - 1]); + + s = s.Remove(s.Length - 1); + + if (!char.IsDigit(s[s.Length - 1])) + { + suffix = char.ToUpper(s[s.Length - 1]) + suffix; + + s = s.Remove(s.Length - 1); + } + + switch (suffix) + { + case "M": + type = typeof(decimal); + break; + case "D": + type = typeof(double); + break; + case "F": + type = typeof(float); + break; + case "L": + type = typeof(long); + break; + case "U": + type = typeof(uint); + break; + case "LU": + case "UL": + type = typeof(ulong); + break; + } + } + + if (type != null) + return new ValueExpression(position, Convert.ChangeType(s, type, _numberFormat), type); + + if (s.LastIndexOf('.') >= 0) + { + return Exp.Value(position, Convert.ToDouble(s, _numberFormat)); + } + else + { + long n = Convert.ToInt64(s); + + if (n > Int32.MaxValue || n < Int32.MinValue) + return Exp.Value(position, n); + else + return Exp.Value(position, (int)n); + } + } + + public static Expression VarName(string token, TokenPosition position, Expression[] terms) + { + return new VariableExpression(position, token); + } + + /// + /// Create a instance. + /// + /// The token + /// The tokens position + /// A + /// A + public static Expression GenericVarName(string token, TokenPosition position, Expression[] terms) + { + return new GenericVariableExpression(position, token); + } + + + public static Expression Function(string token, TokenPosition position, Expression[] terms) + { + Expression[] parameters = new Expression[terms.Length - 1]; + + Array.Copy(terms, 1, parameters, 0, parameters.Length); + + if (token == "[") + { + return new IndexExpression(position, terms[0], parameters); + } + else + { + return new CallExpression(position, terms[0], parameters); + } + } + + public static Expression Coalesce(string token, TokenPosition position, Expression[] terms) + { + return new CoalesceExpression(position, terms[0], terms[1]); + } + + public static Expression DefaultValueOperator(string token, TokenPosition position, Expression[] terms) + { + return new DefaultValueExpression(position, terms[0], terms[1]); + } + + public static Expression ShortcutOperator(string token, TokenPosition position, Expression[] terms) + { + if (token == "&&") + return new AndAlsoExpression(position, terms[0], terms[1]); + + if (token == "||") + return new OrElseExpression(position, terms[0], terms[1]); + + return null; + } + + public static Expression Unary(string token, TokenPosition position, Expression[] terms) + { + if (token == "!") + return new NegationExpression(position, terms[0]); + + if (token == "-") + return new UnaryMinusExpression(position, terms[0]); + + if (token == "~") + return new BitwiseComplementExpression(position, terms[0]); + + return null; + } + + public static Expression StatementSeperator(string token, TokenPosition position, Expression[] terms) + { + return new SequenceExpression(position,terms); + } + + public static Expression Operator(string token, TokenPosition position, Expression[] terms) + { + return Exp.Op(position, token, terms[0], terms[1]); + } + + public static Expression Assignment(string token, TokenPosition position, Expression[] terms) + { + return new AssignmentExpression(position, terms[0], terms[1]); + } + + public static Expression StringLiteral(string token, TokenPosition position, Expression[] terms) + { + string s = token.Substring(1, token.Length - 2); + + if (s.IndexOf('\\') < 0) + return Exp.Value(position, s); + + StringBuilder output = new StringBuilder(token.Length); + + bool inEscape = false; + string hexString = null; + + for (int i = 0; i < s.Length; i++) + { + char c = s[i]; + + if (inEscape) + { + if (c == 'x') + { + hexString = ""; + continue; + } + + if (hexString == null && (c != 'x' || c != 'X')) + { + output.Append(UnEscape("\\" + c, position)); + inEscape = false; + continue; + } + + if (hexString == null) + { + inEscape = false; + } + else + { + if (((char.ToLower(c) < 'a' || char.ToLower(c) > 'f') && (c < '0' || c > '9')) || hexString.Length == 4) + { + output.Append(UnEscape("\\x" + hexString, position)); + inEscape = false; + hexString = null; + } + else + { + hexString += c; + continue; + } + } + } + + if (c != '\\') + { + output.Append(c); + + continue; + } + + inEscape = true; + } + + return Exp.Value(position, output.ToString()); + } + + public static Expression DotOperator(string token, TokenPosition position, Expression[] terms) + { + // now the thing to remember here is that expression isn't always a straight forward field, but instead + // it can be a generic representation... + if ((terms[1] as GenericVariableExpression) != null) + { + GenericVariableExpression genExpression = terms[1] as GenericVariableExpression; + + return new FieldExpression(position, terms[0], genExpression.VarName, genExpression.Generics); + } + else + { + VariableExpression varExpression = terms[1] as VariableExpression; + + if (varExpression == null) + throw new UnknownPropertyException("Unkown member " + terms[1], terms[1]); + + return new FieldExpression(position, terms[0], varExpression.VarName); + } + } + + public static Expression Constructor(string token, TokenPosition position, Expression[] terms) + { + string className = token.Substring(3).Trim(); + + return new ConstructorExpression(position, new VariableExpression(position, className), terms); + } + + public static Expression NumericRange(string token, TokenPosition position, Expression[] terms) + { + return new RangeExpression(position, terms[0], terms[1]); + } + } } \ No newline at end of file diff --git a/Library/Parser/Parsers/CSharp/Tokenizer/CSharpTokenizer.cs b/Library/Parser/Parsers/CSharp/Tokenizer/CSharpTokenizer.cs index 74f2d44..25f2ab7 100644 --- a/Library/Parser/Parsers/CSharp/Tokenizer/CSharpTokenizer.cs +++ b/Library/Parser/Parsers/CSharp/Tokenizer/CSharpTokenizer.cs @@ -1,78 +1,80 @@ -#region License -//============================================================================= -// Vici Core - Productivity Library for .NET 3.5 -// -// Copyright (c) 2008-2012 Philippe Leybaert -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//============================================================================= -#endregion - -using System; -using System.Collections.Generic; - -namespace Vici.Core.Parser -{ - public class CSharpTokenizer : ExpressionTokenizer - { - public CSharpTokenizer() - { - AddTokenMatcher(new CharMatcher('('), TokenType.LeftParen); - AddTokenMatcher(new CharMatcher(')'), TokenType.RightParen); - AddTokenMatcher(new CharMatcher('['), TokenType.LeftParen); - AddTokenMatcher(new CharMatcher(']'), TokenType.RightParen); - AddTokenMatcher(new CharMatcher(','), TokenType.ArgumentSeparator); - AddTokenMatcher(new StringMatcher("&&"), TokenType.Operator, 10, CSharpEvaluator.ShortcutOperator); - AddTokenMatcher(new StringMatcher("||"), TokenType.Operator, 9, CSharpEvaluator.ShortcutOperator); - AddTokenMatcher(new StringMatcher("??"), TokenType.Operator, 8, CSharpEvaluator.Coalesce); - AddTokenMatcher(new StringMatcher("?:"), TokenType.Operator, 8, CSharpEvaluator.DefaultValueOperator); - AddTernaryTokenMatcher(new CharMatcher('?'), new CharMatcher(':'), 7, OperatorAssociativity.Right, CSharpEvaluator.Ternary); - AddTokenMatcher(new AnyOfStringMatcher("==","!="), TokenType.Operator, 14,CSharpEvaluator.Operator); - AddTokenMatcher(new CharMatcher('.'), TokenType.Operator, 20,CSharpEvaluator.DotOperator); - AddTokenMatcher(new AnyCharMatcher("!-~"), TokenType.UnaryOperator, 19, OperatorAssociativity.Right, CSharpEvaluator.Unary); - AddTokenMatcher(new AnyCharMatcher("*/%"), TokenType.Operator, 18,CSharpEvaluator.Operator); - AddTokenMatcher(new AnyCharMatcher("+-"), TokenType.Operator, 17,CSharpEvaluator.Operator); - AddTokenMatcher(new AnyOfStringMatcher("<<",">>"), TokenType.Operator, 16,CSharpEvaluator.Operator); - AddTokenMatcher(new AnyOfStringMatcher("<=",">=","<",">"), TokenType.Operator, 15,CSharpEvaluator.Operator); - AddTokenMatcher(new AnyOfStringMatcher("as","is"), TokenType.Operator, 15,CSharpEvaluator.IsAsOperator); - AddTokenMatcher(new StringMatcher("foreach"), TokenType.ForEach); - AddTokenMatcher(new StringMatcher("if"), TokenType.If); - AddTokenMatcher(new StringMatcher("else"), TokenType.Else); - AddTokenMatcher(new StringMatcher("return"), TokenType.Return); - AddTokenMatcher(new StringMatcher("function"), TokenType.FunctionDefinition); - AddTokenMatcher(new StringMatcher("in"), TokenType.Operator,2,CSharpEvaluator.InOperator); - AddTokenMatcher(new AnyCharMatcher("&|"), TokenType.Operator, 13,CSharpEvaluator.Operator); - AddTokenMatcher(new CharMatcher('^'), TokenType.Operator, 12, CSharpEvaluator.Operator); - AddTokenMatcher(new CharMatcher('='), TokenType.Operator, 6, OperatorAssociativity.Right, CSharpEvaluator.Assignment); - AddTokenMatcher(new StringMatcher("..."), TokenType.Operator, 1, CSharpEvaluator.NumericRange); - AddTokenMatcher(new CompositeMatcher(new StringMatcher("new"), new WhiteSpaceMatcher(), new VariableMatcher()), TokenType.Term, CSharpEvaluator.Constructor); - AddTokenMatcher(new StringMatcher("typeof"), TokenType.Term, CSharpEvaluator.TypeOf); - AddTokenMatcher(new VariableMatcher(), TokenType.Term, CSharpEvaluator.VarName); - AddTokenMatcher(new StringLiteralMatcher(), TokenType.Term, CSharpEvaluator.StringLiteral); - AddTokenMatcher(new CharLiteralMatcher(), TokenType.Term, CSharpEvaluator.CharLiteral); - AddTokenMatcher(new WhiteSpaceMatcher(), TokenType.WhiteSpace); - AddTokenMatcher(new IntegerLiteralMatcher(), TokenType.Term, CSharpEvaluator.Number); - AddTokenMatcher(new DecimalLiteralMatcher(), TokenType.Term, CSharpEvaluator.Number); - AddTokenMatcher(new TypeCastMatcher(), TokenType.UnaryOperator, 19, OperatorAssociativity.Right, CSharpEvaluator.TypeCast); - AddTokenMatcher(new CharMatcher(';'), TokenType.StatementSeparator); - AddTokenMatcher(new CharMatcher('{'), TokenType.OpenBrace); - AddTokenMatcher(new CharMatcher('}'), TokenType.CloseBrace); - } - } -} +#region License +//============================================================================= +// Vici Core - Productivity Library for .NET 3.5 +// +// Copyright (c) 2008-2012 Philippe Leybaert +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//============================================================================= +#endregion + +using System; +using System.Collections.Generic; + +namespace Vici.Core.Parser +{ + public class CSharpTokenizer : ExpressionTokenizer + { + public CSharpTokenizer() + { + AddTokenMatcher(new CharMatcher('('), TokenType.LeftParen); + AddTokenMatcher(new CharMatcher(')'), TokenType.RightParen); + AddTokenMatcher(new CharMatcher('['), TokenType.LeftParen); + AddTokenMatcher(new CharMatcher(']'), TokenType.RightParen); + AddTokenMatcher(new CharMatcher(','), TokenType.ArgumentSeparator); + AddTokenMatcher(new StringMatcher("&&"), TokenType.Operator, 10, CSharpEvaluator.ShortcutOperator); + AddTokenMatcher(new StringMatcher("||"), TokenType.Operator, 9, CSharpEvaluator.ShortcutOperator); + AddTokenMatcher(new StringMatcher("??"), TokenType.Operator, 8, CSharpEvaluator.Coalesce); + AddTokenMatcher(new StringMatcher("?:"), TokenType.Operator, 8, CSharpEvaluator.DefaultValueOperator); + AddTernaryTokenMatcher(new CharMatcher('?'), new CharMatcher(':'), 7, OperatorAssociativity.Right, CSharpEvaluator.Ternary); + AddTokenMatcher(new AnyOfStringMatcher("==","!="), TokenType.Operator, 14,CSharpEvaluator.Operator); + AddTokenMatcher(new CharMatcher('.'), TokenType.Operator, 20,CSharpEvaluator.DotOperator); + AddTokenMatcher(new AnyCharMatcher("!-~"), TokenType.UnaryOperator, 19, OperatorAssociativity.Right, CSharpEvaluator.Unary); + AddTokenMatcher(new AnyCharMatcher("*/%"), TokenType.Operator, 18,CSharpEvaluator.Operator); + AddTokenMatcher(new AnyCharMatcher("+-"), TokenType.Operator, 17,CSharpEvaluator.Operator); + AddTokenMatcher(new AnyOfStringMatcher("<<",">>"), TokenType.Operator, 16,CSharpEvaluator.Operator); + AddTokenMatcher(new AnyOfStringMatcher("<=",">=","<",">"), TokenType.Operator, 15,CSharpEvaluator.Operator); + AddTokenMatcher(new AnyOfStringMatcher("as","is"), TokenType.Operator, 15,CSharpEvaluator.IsAsOperator); + AddTokenMatcher(new StringMatcher("foreach"), TokenType.ForEach); + AddTokenMatcher(new StringMatcher("if"), TokenType.If); + AddTokenMatcher(new StringMatcher("else"), TokenType.Else); + AddTokenMatcher(new StringMatcher("return"), TokenType.Return); + AddTokenMatcher(new StringMatcher("function"), TokenType.FunctionDefinition); + AddTokenMatcher(new StringMatcher("in"), TokenType.Operator,2,CSharpEvaluator.InOperator); + AddTokenMatcher(new AnyCharMatcher("&|"), TokenType.Operator, 13,CSharpEvaluator.Operator); + AddTokenMatcher(new CharMatcher('^'), TokenType.Operator, 12, CSharpEvaluator.Operator); + AddTokenMatcher(new CharMatcher('='), TokenType.Operator, 6, OperatorAssociativity.Right, CSharpEvaluator.Assignment); + AddTokenMatcher(new StringMatcher("..."), TokenType.Operator, 1, CSharpEvaluator.NumericRange); + AddTokenMatcher(new CompositeMatcher(new StringMatcher("new"), new WhiteSpaceMatcher(), new VariableMatcher()), TokenType.Term, CSharpEvaluator.Constructor); + AddTokenMatcher(new StringMatcher("typeof"), TokenType.Term, CSharpEvaluator.TypeOf); + AddTokenMatcher(new VariableMatcher(), TokenType.Term, CSharpEvaluator.VarName); + AddTokenMatcher(new StringLiteralMatcher(), TokenType.Term, CSharpEvaluator.StringLiteral); + AddTokenMatcher(new CharLiteralMatcher(), TokenType.Term, CSharpEvaluator.CharLiteral); + AddTokenMatcher(new WhiteSpaceMatcher(), TokenType.WhiteSpace); + AddTokenMatcher(new IntegerLiteralMatcher(), TokenType.Term, CSharpEvaluator.Number); + AddTokenMatcher(new DecimalLiteralMatcher(), TokenType.Term, CSharpEvaluator.Number); + AddTokenMatcher(new TypeCastMatcher(), TokenType.UnaryOperator, 19, OperatorAssociativity.Right, CSharpEvaluator.TypeCast); + AddTokenMatcher(new CharMatcher(';'), TokenType.StatementSeparator); + AddTokenMatcher(new CharMatcher('{'), TokenType.OpenBrace); + AddTokenMatcher(new CharMatcher('}'), TokenType.CloseBrace); + + AddTokenMatcher(new GenericVariableMatcher(), TokenType.Term, CSharpEvaluator.GenericVarName); + } + } +} diff --git a/Library/Parser/Parsers/CSharp/Tokenizer/Tokens/GenericVariableMatcher.cs b/Library/Parser/Parsers/CSharp/Tokenizer/Tokens/GenericVariableMatcher.cs new file mode 100644 index 0000000..6478b15 --- /dev/null +++ b/Library/Parser/Parsers/CSharp/Tokenizer/Tokens/GenericVariableMatcher.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Vici.Core.Parser +{ + /// + /// Match a token against the pattern for a generic variable + /// + /// A generic variable is of the form: + /// variablename + /// + public class GenericVariableMatcher : ITokenMatcher, ITokenProcessor + { + /// + /// The characters considered valid for the start of a variable name + /// + private const string VALID_FIRSTCHARS = "abcdefghijkklmnopqrstuvwxyzABCDEFGHIJKKLMNOPQRSTUVWXYZ_@$"; + + /// + /// The characters considered valid for non first variable names + /// + private const string VALID_NEXTCHARS = "abcdefghijkklmnopqrstuvwxyzABCDEFGHIJKKLMNOPQRSTUVWXYZ_@$0123456789"; + + /// + /// The characters considered valie for a generic placeholder (and separator) + /// + private const string VALID_GENERICCHARS = "abcdefghijkklmnopqrstuvwxyzABCDEFGHIJKKLMNOPQRSTUVWXYZ_@$0123456789,?"; + + /// + /// Have we seen a starting character ? + /// + private bool _sawFirst; + + /// + /// Have we seen the open < for the generic + /// + private bool _sawOpen; + + /// + /// Have we seen the closing > for the generic + /// + private bool _sawClose; + + public void ResetState() + { + _sawFirst = false; + _sawOpen = false; + _sawClose = false; + + } + + ITokenProcessor ITokenMatcher.CreateTokenProcessor() + { + return new GenericVariableMatcher(); + } + + TokenizerState ITokenProcessor.ProcessChar(char c, string fullExpression, int currentIndex) + { + // if we have seen the close of the generic then we must be done + if (_sawClose) + { + return TokenizerState.Success; + } + + // if we having seen anything to kick things off then flag this + if (!_sawFirst) + { + _sawFirst = true; + + return VALID_FIRSTCHARS.IndexOf(c) >= 0 ? TokenizerState.Valid : TokenizerState.Fail; + } + + // if we haven't started on the generic place holders + if (!_sawOpen) + { + // do we have the character indicating generic placeholders will follow + if (c == '<') + { + _sawOpen = true; + + return TokenizerState.Valid; + } + + // is this a valid character for a type placeholder + return VALID_NEXTCHARS.IndexOf(c) >= 0 ? TokenizerState.Valid : TokenizerState.Success; + } + + + // got this far, must be in the generic part... + if (c == '>') + { + _sawClose = true; + + return TokenizerState.Valid; + } + + return VALID_GENERICCHARS.IndexOf(c) >= 0 ? TokenizerState.Valid : TokenizerState.Fail; + } + + public string TranslateToken(string originalToken, ITokenProcessor tokenProcessor) + { + return originalToken; + } + } +} diff --git a/Library/TypeInspector.cs b/Library/TypeInspector.cs index bd953c9..6332247 100644 --- a/Library/TypeInspector.cs +++ b/Library/TypeInspector.cs @@ -162,6 +162,31 @@ public MemberInfo[] GetMember(string propertyName) #endif } + /// + /// Get a member matching with the specified property name and generic types. + /// + /// The property name + /// The generic types + /// An array of matching instances. + public MemberInfo[] GetMember(string propertyName, Type[] genericTypes) + { + MethodInfo[] methods; +#if NETFX_CORE + IEnumerable methods = WalkAndFindMultiple(t => t.GetTypeInfo().DeclaredMembers.Where(m => m.Name == propertyName && m.IsGenericMethod && p.GetGenericArguments().Count() == genericTypes.Length)); +#else + methods = _t.GetMethods().Where(p => p.IsGenericMethod == true && p.GetGenericArguments().Count() == genericTypes.Length && p.Name == propertyName).ToArray(); +#endif + // now then, we need to make generic methods for each matching member + List members = new List(); + + foreach (MethodInfo method in methods) + { + members.Add(method.MakeGenericMethod(genericTypes)); + } + + return members.ToArray(); + } + public PropertyInfo GetIndexer(Type[] types) { #if NETFX_CORE diff --git a/Library/Vici.Core.csproj b/Library/Vici.Core.csproj index 8858d19..3c4ce3c 100644 --- a/Library/Vici.Core.csproj +++ b/Library/Vici.Core.csproj @@ -1,290 +1,292 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {472E40CE-377D-4C5D-B755-FA11DCDA2347} - Library - Properties - Vici.Core - Vici.Core - v3.5 - 512 - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - - - - 3.5 - - - 3.5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {472E40CE-377D-4C5D-B755-FA11DCDA2347} + Library + Properties + Vici.Core + Vici.Core + v3.5 + 512 + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/Test/Tests/Parser/CSharpParserFixture.cs b/Test/Tests/Parser/CSharpParserFixture.cs index a4dc3d0..0d60a9e 100644 --- a/Test/Tests/Parser/CSharpParserFixture.cs +++ b/Test/Tests/Parser/CSharpParserFixture.cs @@ -67,6 +67,45 @@ public DataClass(string string1, int int1) public int this[int i] { get { return i * 2; } } public int this[int x, int y] { get { return x + y; } } + /// + /// Test method #1 for generics + /// + /// + /// + /// + public string Get(int x) + { + return typeof(T)+":"+x.ToString(); + } + + /// + /// Test method #2 for generics + /// + /// + /// + /// + public string Get(string x) + { + return typeof(T)+":"+x; + } + + /// + /// Test Method #3 for generics + /// + /// + /// + /// + /// + public string Get(int x) + { + return typeof(T1) + "," + typeof(T2) + ":"+x; + } + + public static string StaticGet(int x) + { + return "Static:"+typeof(T1) + "," + typeof(T2) + ":" + x; + } + } [TestInitialize] @@ -871,5 +910,86 @@ function max(a,b) Assert.AreEqual("22", output); } + + /// + /// Some tests for the generic implementation + /// + [TestMethod()] + public void Generics() + { + // Verify that correct generic methods are selected based upon type + Assert.AreEqual("System.Int32:50", _parser.Evaluate("Data.Get(50)")); + Assert.AreEqual("System.Int32:fred", _parser.Evaluate("Data.Get(\"fred\")")); + + // Verify that multiple generic parameters are handled correctly + Assert.AreEqual("System.Int32,System.String:1234",_parser.Evaluate("Data.Get(1234)")); + + // Verify that statics work... + Assert.AreEqual("Static:System.Int32,System.String:1234", _parser.Evaluate("DataClass.StaticGet(1234)")); + + // Verify that nullables work + Assert.AreEqual("System.Nullable`1[System.Int32],System.String:50", _parser.Evaluate("Data.Get(50)")); + } + + /// + /// Verify custom resolver is invoked and returns value which is used. + /// + [TestMethod()] + public void CustomResolverWhenExists() + { + // verify that when we have a custom resolver it is called AND + // the value returned is used in the calculations + + CSharpContext context = new CSharpContext(); + + int testReturnVar = 12345; + Boolean called = false; + + context.CustomResolver = (name) => + { + called = true; return name == "existVar" ? + new Tuple(testReturnVar, typeof(int)) : null; + }; + + int actual = _parser.Evaluate("existVar;", context); + + Assert.IsTrue(called); + Assert.AreEqual(testReturnVar, actual); + } + + /// + /// Verify that when a custom resolver is specified but it doesn't resolve then we get + /// the expected exception for the expression parsing. + /// + [TestMethod()] + public void CustomResolverWhenDoesntExist() + { + CSharpContext context = new CSharpContext(); + + int testReturnVar = 12345; + Boolean called = false; + Boolean exceptionRaised = true; + + context.CustomResolver = (name) => + { + called = true; return name == "existVar" ? + new Tuple(testReturnVar, typeof(int)) : null; + }; + + // Note that we don't use the ExpectedException Attribute - we + // want to know that the custom resolver was called. + try + { + int actual = _parser.Evaluate("notExistVar;", context); + } + catch (System.NullReferenceException nullException) + { + exceptionRaised = true; + } + + Assert.IsTrue(called); + Assert.IsTrue(exceptionRaised); + } + } } \ No newline at end of file