14 using System.Collections.Generic;
19 namespace Irony.Interpreter {
21 #region OperatorDispatchKey class
35 int h1 = (arg1Type == null ? 0 : arg1Type.GetHashCode());
36 int h2 = (arg2Type == null ? 0 : arg2Type.GetHashCode());
38 HashCode = unchecked((h1 << 1) + h2 + opSymbol.GetHashCode());
45 return "(" + Arg1Type +
" " + OpSymbol +
" " + Arg2Type +
")";
52 return new OperatorDispatchKey(opSymbol, (arg1 == null ? null : arg1.GetType()), (arg2 == null ? null : arg2.GetType()));
58 #region IEquatable<DispatchKey> Members
60 return HashCode == other.HashCode && OpSymbol == other.OpSymbol && Arg1Type == other.Arg1Type && Arg2Type == other.Arg2Type;
71 this[key] = converter;
76 TryGetValue(key, out result);
82 #region OperatorImplementation
109 Arg1Converter = arg1Converter;
110 Arg2Converter = arg2Converter;
111 ResultConverter = resultConverter;
112 BaseMethod = baseMethod;
113 SetupEvaluationMethod();
117 if (ResultConverter == null) {
119 if (Arg1Converter == null && Arg2Converter == null)
120 Evaluate = EvaluateConvNone;
121 else if (Arg1Converter != null && Arg2Converter == null)
122 Evaluate = EvaluateConvLeft;
123 else if (Arg1Converter == null && Arg2Converter != null)
124 Evaluate = EvaluateConvRight;
126 Evaluate = EvaluateConvBoth;
129 if (Arg1Converter == null && Arg2Converter == null)
130 Evaluate = EvaluateConvNoneConvResult;
131 else if (Arg1Converter != null && Arg2Converter == null)
132 Evaluate = EvaluateConvLeftConvResult;
133 else if (Arg1Converter == null && Arg2Converter != null)
134 Evaluate = EvaluateConvRightConvResult;
136 Evaluate = EvaluateConvBothConvResult;
140 private object EvaluateConvNone(
object arg1,
object arg2) {
141 return BaseMethod(arg1, arg2);
143 private object EvaluateConvLeft(
object arg1,
object arg2) {
144 return BaseMethod(Arg1Converter(arg1), arg2);
146 private object EvaluateConvRight(
object arg1,
object arg2) {
147 return BaseMethod(arg1, Arg2Converter(arg2));
149 private object EvaluateConvBoth(
object arg1,
object arg2) {
150 return BaseMethod(Arg1Converter(arg1), Arg2Converter(arg2));
153 private object EvaluateConvNoneConvResult(
object arg1,
object arg2) {
154 return ResultConverter(BaseMethod(arg1, arg2));
156 private object EvaluateConvLeftConvResult(
object arg1,
object arg2) {
157 return ResultConverter(BaseMethod(Arg1Converter(arg1), arg2));
159 private object EvaluateConvRightConvResult(
object arg1,
object arg2) {
160 return ResultConverter(BaseMethod(arg1, Arg2Converter(arg2)));
162 private object EvaluateConvBothConvResult(
object arg1,
object arg2) {
163 return ResultConverter(BaseMethod(Arg1Converter(arg1), Arg2Converter(arg2)));
170 #region OperatorDispatcher
182 _runtime = _context.Runtime;
183 OperatorImplementations = _runtime.CreateOperatorImplementationsTable();
187 var arg1 = _context.Data[1];
188 var arg2 = _context.Data[0];
189 var key = OperatorDispatchKey.CreateFromArgs(op, arg1, arg2);
191 if (!OperatorImplementations.TryGetValue(key, out opImpl))
192 opImpl = _runtime.AddOperatorImplementation(OperatorImplementations, key);
193 if (opImpl != null) {
195 var result = opImpl.Evaluate(arg1, arg2);
196 _context.Data.Replace(2, result);
198 }
catch (OverflowException) {
199 if (TryConvertArgsOnOverflow(opImpl.BaseType)) {
200 ExecuteBinaryOperator(op);
213 private bool TryConvertArgsOnOverflow(Type baseType) {
215 Type upType = _runtime.GetUpType(baseType);
218 var arg2 = _context.Data.Pop();
219 var arg1 = _context.Data.Pop();
220 var arg1Conv = ConvertValue(arg1, upType);
221 var arg2Conv = ConvertValue(arg2, upType);
222 _context.Data.Push(arg1Conv);
223 _context.Data.Push(arg2Conv);
227 private object ConvertValue(
object value, Type toType) {
228 var key = OperatorDispatchKey.CreateForTypeConverter(value.GetType(), toType);
230 if (_runtime.TypeConverters.TryGetValue(key, out converter)) {
231 var result = converter.Invoke(value);
234 throw new Exception(
string.Format(
"Failed to convert value '%1' to type %2.", value, toType));
The struct is used as a key for the dictionary of operator implementations. Contains types of argumen...
delegate object UnaryOperatorMethod(object arg1, object arg2)
void SetupEvaluationMethod()
DynamicCallDispatcher(EvaluationContext context)
delegate object BinaryOperatorMethod(object arg1, object arg2)
override int GetHashCode()
readonly OperatorDispatchKey Key
static OperatorDispatchKey CreateFromTypes(string opSymbol, Type arg1Type, Type arg2Type)
The DynamicCallDispatcher class is responsible for fast dispatching to the implementation based on ar...
override string ToString()
void ExecuteBinaryOperator(string op)
void Add(Type fromType, Type toType, TypeConverter converter)
static OperatorDispatchKey CreateForTypeConverter(Type fromType, Type toType)
readonly OperatorImplementationTable OperatorImplementations
BinaryOperatorMethod Evaluate
bool Equals(OperatorDispatchKey other)
delegate object TypeConverter(object arg)
TypeConverter Find(Type fromType, Type toType)
OperatorImplementation(OperatorDispatchKey key, Type baseType, BinaryOperatorMethod baseMethod, TypeConverter arg1Converter, TypeConverter arg2Converter, TypeConverter resultConverter)
readonly BinaryOperatorMethod BaseMethod
static OperatorDispatchKey CreateFromArgs(string opSymbol, object arg1, object arg2)
static string ErrOpNotImplemented
Looks up a localized string similar to Operator '{0} not imlemented..