Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
LanguageRuntime.cs
Go to the documentation of this file.
1 #region License
2 /* **********************************************************************************
3  * Copyright (c) Roman Ivantsov
4  * This source code is subject to terms and conditions of the MIT License
5  * for Irony. A copy of the license can be found in the License.txt file
6  * at the root of this distribution.
7  * By using this source code in any fashion, you are agreeing to be bound by the terms of the
8  * MIT License.
9  * You must not remove this notice from this software.
10  * **********************************************************************************/
11 #endregion
12 
13 using System;
14 using System.Collections.Generic;
15 using System.Linq;
16 using System.Text;
17 using Irony.Parsing;
18 using Irony.Interpreter.Ast;
19 
20 namespace Irony.Interpreter {
22  using Complex = Microsoft.Scripting.Math.Complex64;
23 
25  public string Text;
26  public ConsoleWriteEventArgs(string text) {
27  Text = text;
28  }
29  }
30 
31  public class TypeList : List<Type> { }
32 
33  public class Unassigned {
34  string _toString;
35 
36  public Unassigned() {
37  _toString = Resources.LabelUnassigned;
38  }
39  public Unassigned(string toString) {
40  _toString = toString;
41  }
42 
43  public override string ToString() {
44  return _toString;
45  }
46  }
47 
48 
49  //Note: mark the derived language-specific class as sealed - important for JIT optimizations
50  // details here: http://www.codeproject.com/KB/dotnet/JITOptimizations.aspx
51  public partial class LanguageRuntime {
52 
53  public LanguageRuntime(LanguageData language) {
54  Language = language;
55  Init();
56  }
57 
58  public readonly LanguageData Language;
59  public readonly TypeList BaseTypeSequence = new TypeList();
60  public readonly TypeConverterTable TypeConverters = new TypeConverterTable();
61  // This is the original operator implementations table containing implementations for base type
62  // pairs without arg converters. Each Evaluation context has its own
63  // implementation table which is initialized from this original copy.
64  // During execution the copied table in context can be extended on the fly
65  // to include extra implementations with arg conversions. If we used one shared table this
66  // will lead to the need to syncronize the access in multi-threading environment. Instead,
67  // each context (associated with its own thread) has its own instance. This instance is initialized
68  // from this original table in method CreateOperatorImplementationsTable().
69  private OperatorImplementationTable _baseOperatorImplementations;
70 
71 
72  //public readonly MetaObjectTable MetaObjects = new MetaObjectTable();
73  //public readonly FunctionBindingTable FunctionBindings = new FunctionBindingTable();
74  //Converter of the result for comparison operation; converts bool value to values
75  // specific for the language
76  public TypeConverter BoolResultConverter = null;
77  //An unassigned reserved object for a language implementation
79 
80  public bool IsAssigned(object value) {
81  return value != Unassigned;
82  }
83 
84  public virtual bool IsTrue(object value) {
85  return value != NullObject;
86  }
87 
88  public virtual object NullObject {
89  get { return null; }
90  }
92  var table = new OperatorImplementationTable();
93  foreach (var entry in _baseOperatorImplementations)
94  table.Add(entry.Key, entry.Value);
95  return table;
96  }
97 /*
98  public virtual FunctionBindingInfo GetFunctionBindingInfo(string name, AstNodeList parameters) {
99  return FunctionBindings.Find(name, parameters.Count);
100  }
101  //Utility methods for adding library functions
102  public FunctionBindingInfo AddFunction(string name, int paramCount) {
103  return null;
104  }
105  public FunctionBindingInfo AddFunction(string name, int paramCount, FunctionFlags flags) {
106  FunctionBindingInfo info = new FunctionBindingInfo(name, paramCount, null, flags);
107  FunctionBindings.Add(name, info);
108  return info;
109  }
110  */
111 
112  #region Operator implementations
113  // When an implementation for exact type pair is not found, we find implementation for base type and create
114  // implementation for exact types using type converters
116  Type baseType = GetBaseTypeForExpression(forKey.OpSymbol, forKey.Arg1Type, forKey.Arg2Type);
117  if (baseType == null) return null;
118  TypeConverter arg1Converter = GetConverter(forKey.Arg1Type, baseType);
119  TypeConverter arg2Converter = GetConverter(forKey.Arg2Type, baseType);
120  //Get base method for the operator and common type
121  var baseKey = OperatorDispatchKey.CreateFromTypes(forKey.OpSymbol, baseType, baseType);
122  OperatorImplementation baseImpl;
123  if (! _baseOperatorImplementations.TryGetValue(baseKey, out baseImpl))
124  throw new Exception(string.Format(Resources.ErrOpNotDefinedForTypes, forKey.OpSymbol, forKey.Arg1Type, forKey.Arg2Type));
125  var impl = new OperatorImplementation(forKey, baseType, baseImpl.BaseMethod, arg1Converter, arg2Converter, baseImpl.ResultConverter);
126  implementations[forKey] = impl;
127  return impl;
128  }
129 
130  /// <summary>
131  /// Returns the type to which arguments should be converted to perform the operation
132  /// for a given operator and arguments type.
133  /// </summary>
134  /// <param name="op">Operator</param>
135  /// <param name="type1">The type of the first argument.</param>
136  /// <param name="type2">The type of the second argument</param>
137  /// <returns></returns>
138  protected virtual Type GetBaseTypeForExpression(string op, Type type1, Type type2) {
139  //TODO: implement ability to customize in particular language
140  var allowSwitchToSigned = op == "-";
141  var isBoolOp = op == "&" || op == "|";
142  Type t;
143  //First check for boolean op; some languages allow ints to be interpreted as bools in expressions
144  t = typeof(bool);
145  if (isBoolOp || IsOneOf(t, type1, type2)) return t;
146  //Check implicit conversion to string
147  t = typeof(string);
148  if (IsOneOf(t, type1, type2)) return t;
149  t = typeof(Complex);
150  if (IsOneOf(t, type1, type2)) return t;
151  t = typeof(double);
152  if (IsOneOf(t, type1, type2)) return t;
153  t = typeof(float);
154  if (IsOneOf(t, type1, type2)) return t;
155  t = typeof(BigInteger);
156  if (IsOneOf(t, type1, type2)) return t;
157 
158  t = typeof(Int64);
159  if (IsOneOf(t, type1, type2)) return t;
160  t = typeof(UInt64);
161  if (IsOneOf(t, type1, type2))
162  //If we have "-" operation then the result can be negative, so we must do operation on signed type
163  return allowSwitchToSigned ? typeof(Int64) : t;
164 
165  t = typeof(Int32);
166  if (IsOneOf(t, type1, type2)) return t;
167  t = typeof(UInt32);
168  if (IsOneOf(t, type1, type2))
169  //If we have "-" operation then the result can be negative, so we must do operation on signed type
170  return allowSwitchToSigned ? typeof(Int32) : t;
171 
172  t = typeof(Int16);
173  if (IsOneOf(t, type1, type2)) return t;
174  t = typeof(UInt16);
175  if (IsOneOf(t, type1, type2))
176  //If we have "-" operation then the result can be negative, so we must do operation on signed type
177  return allowSwitchToSigned ? typeof(Int16) : t;
178 
179  t = typeof(sbyte);
180  if (IsOneOf(t, type1, type2)) return t;
181  t = typeof(byte);
182  if (IsOneOf(t, type1, type2))
183  //If we have "-" operation then the result can be negative, so we must do operation on signed type
184  return allowSwitchToSigned ? typeof(sbyte) : t;
185 
186  return null;
187  }//method
188 
189  private static bool IsOneOf(Type type, Type type1, Type type2) {
190  return type == type1 || type == type2;
191  }
192 
193  /// <summary>
194  /// Returns the "up-type" to use in operation instead of the type that caused overflow.
195  /// </summary>
196  /// <param name="type">The base type for operation that caused overflow.</param>
197  /// <returns>The type to use for operation.</returns>
198  /// <remarks>
199  /// Can be overwritten in language implementation to implement different type-conversion policy.
200  /// </remarks>
201  public virtual Type GetUpType(Type type) {
202  switch (type.Name) {
203  case "Byte":
204  case "SByte":
205  case "Int16":
206  case "UInt16":
207  case "Int32":
208  case "UInt32":
209  return typeof(Int64);
210  case "Int64":
211  case "UInt64":
212  return typeof(BigInteger);
213  case "Single":
214  return typeof(double);
215  }
216  return null;
217  }
218  public virtual bool HandleException(Exception ex, DynamicCallDispatcher dispatcher, OperatorImplementation failedTarget, EvaluationContext context) {
219  return false;
220  }
221  #endregion
222 
223  #region Converters
224  protected virtual TypeConverter GetConverter(Type fromType, Type toType) {
225  if (fromType == toType) return null;
226  var result = TypeConverters.Find(fromType, toType);
227  if (result != null) return result;
228  string err = string.Format(Resources.ErrCannotConvertValue, fromType, toType);
229  throw new Exception(err);
230  }
231  #endregion
232 
233 
234  public event EventHandler<ConsoleWriteEventArgs> ConsoleWrite;
235  protected void OnConsoleWrite(EvaluationContext context, string text) {
236  if (ConsoleWrite != null) {
238  ConsoleWrite(this, args);
239  }
240  context.Write(text);
241  }
242 
243  //Temporarily put it here
244  public static void Check(bool condition, string message, params object[] args) {
245  if (condition) return;
246  if (args != null)
247  message = string.Format(message, args);
248  throw new RuntimeException(message);
249  }
250 
251 
252 
253  }//class
254 
255 }//namespace
256 
readonly LanguageData Language
The struct is used as a key for the dictionary of operator implementations. Contains types of argumen...
A strongly-typed resource class, for looking up localized strings, etc.
OperatorImplementationTable CreateOperatorImplementationsTable()
virtual OperatorImplementation AddOperatorImplementation(OperatorImplementationTable implementations, OperatorDispatchKey forKey)
void OnConsoleWrite(EvaluationContext context, string text)
EventHandler< ConsoleWriteEventArgs > ConsoleWrite
static string LabelUnassigned
Looks up a localized string similar to (unassigned).
The DynamicCallDispatcher class is responsible for fast dispatching to the implementation based on ar...
static string ErrOpNotDefinedForTypes
Looks up a localized string similar to Operator '{0}' is not defined for types {1} and {2}...
static string ErrCannotConvertValue
Looks up a localized string similar to Cannot convert value from type {0} to type {1}...
static void Check(bool condition, string message, params object[] args)
Describes a language.
Definition: LanguageData.cs:23
virtual Type GetBaseTypeForExpression(string op, Type type1, Type type2)
Returns the type to which arguments should be converted to perform the operation for a given operator...
virtual bool IsTrue(object value)
virtual TypeConverter GetConverter(Type fromType, Type toType)
Microsoft.Scripting.Math.Complex64 Complex
LanguageRuntime(LanguageData language)
Microsoft.Scripting.Math.BigInteger BigInteger
virtual Type GetUpType(Type type)
Returns the "up-type" to use in operation instead of the type that caused overflow.
virtual bool HandleException(Exception ex, DynamicCallDispatcher dispatcher, OperatorImplementation failedTarget, EvaluationContext context)