PageRenderTime 49ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/Backend/AST/TypeGenerator.cs

https://bitbucket.org/AdamMil/boaold
C# | 246 lines | 201 code | 23 blank | 22 comment | 31 complexity | d72ee7d759c9921effb88fbdb7549c3e MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Boa is the reference implementation for a language similar to Python,
  3. also called Boa. This implementation is both interpreted and compiled,
  4. targeting the Microsoft .NET Framework.
  5. http://www.adammil.net/
  6. Copyright (C) 2004-2005 Adam Milazzo
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. using System;
  20. using System.Collections;
  21. using System.Collections.Specialized;
  22. using System.Reflection;
  23. using System.Reflection.Emit;
  24. using Boa.Runtime;
  25. namespace Boa.AST
  26. {
  27. public sealed class TypeGenerator
  28. { public TypeGenerator(AssemblyGenerator assembly, TypeBuilder typeBuilder)
  29. { Assembly=assembly; TypeBuilder=typeBuilder;
  30. }
  31. public Slot ModuleField
  32. { get
  33. { if(moduleField==null) moduleField = DefineStaticField(Boa.Runtime.Module.FieldName, typeof(Boa.Runtime.Module));
  34. return moduleField;
  35. }
  36. }
  37. public CodeGenerator DefineChainedConstructor(ConstructorInfo parent)
  38. { ParameterInfo[] pi = parent.GetParameters();
  39. Type[] types = GetParamTypes(pi);
  40. ConstructorBuilder cb = TypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, types);
  41. for(int i=0; i<pi.Length; i++)
  42. { ParameterBuilder pb = cb.DefineParameter(i+1, pi[i].Attributes, pi[i].Name);
  43. if(pi[i].IsDefined(typeof(ParamArrayAttribute), false))
  44. pb.SetCustomAttribute(
  45. new CustomAttributeBuilder(typeof(ParamArrayAttribute).GetConstructor(Type.EmptyTypes), Misc.EmptyArray));
  46. }
  47. CodeGenerator cg = new CodeGenerator(this, cb, cb.GetILGenerator());
  48. cg.EmitThis();
  49. for(int i=0; i<pi.Length; i++) cg.EmitArgGet(i);
  50. cg.ILG.Emit(OpCodes.Call, parent);
  51. return cg;
  52. }
  53. public CodeGenerator DefineDefaultConstructor(MethodAttributes attrs)
  54. { ConstructorBuilder cb = TypeBuilder.DefineDefaultConstructor(attrs);
  55. return new CodeGenerator(this, cb, cb.GetILGenerator());
  56. }
  57. public Slot DefineField(string name, Type type) { return DefineField(name, type, FieldAttributes.Public); }
  58. public Slot DefineField(string name, Type type, FieldAttributes access)
  59. { return new FieldSlot(new ThisSlot(TypeBuilder), TypeBuilder.DefineField(name, type, access));
  60. }
  61. public CodeGenerator DefineMethod(string name, Type retType, Type[] paramTypes)
  62. { return DefineMethod(MethodAttributes.Public|MethodAttributes.Static, name, retType, paramTypes);
  63. }
  64. public CodeGenerator DefineMethod(MethodAttributes attrs, string name, Type retType, Type[] paramTypes)
  65. { MethodBuilder mb = TypeBuilder.DefineMethod(name, attrs, retType, paramTypes);
  66. return new CodeGenerator(this, mb, mb.GetILGenerator());
  67. }
  68. public CodeGenerator DefineMethodOverride(Type type, string name) { return DefineMethodOverride(type, name, false); }
  69. public CodeGenerator DefineMethodOverride(Type type, string name, bool final)
  70. { return DefineMethodOverride(type.GetMethod(name, BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public),
  71. final);
  72. }
  73. public CodeGenerator DefineMethodOverride(MethodInfo baseMethod) { return DefineMethodOverride(baseMethod, false); }
  74. public CodeGenerator DefineMethodOverride(MethodInfo baseMethod, bool final)
  75. { MethodAttributes attrs = baseMethod.Attributes & ~(MethodAttributes.Abstract|MethodAttributes.NewSlot) |
  76. MethodAttributes.HideBySig;
  77. if(final) attrs |= MethodAttributes.Final;
  78. MethodBuilder mb = TypeBuilder.DefineMethod(baseMethod.Name, attrs, baseMethod.ReturnType,
  79. GetParamTypes(baseMethod.GetParameters()));
  80. // TODO: figure out how to use this properly
  81. //TypeBuilder.DefineMethodOverride(mb, baseMethod);
  82. return new CodeGenerator(this, mb, mb.GetILGenerator());
  83. }
  84. public TypeGenerator DefineNestedType(string name, Type parent) { return DefineNestedType(0, name, parent); }
  85. public TypeGenerator DefineNestedType(TypeAttributes attrs, string name, Type parent)
  86. { if(nestedTypes==null) nestedTypes = new ArrayList();
  87. TypeAttributes ta = attrs | TypeAttributes.Class | TypeAttributes.NestedPublic;
  88. TypeGenerator ret = new TypeGenerator(Assembly, TypeBuilder.DefineNestedType(name, ta, parent));
  89. nestedTypes.Add(ret);
  90. return ret;
  91. }
  92. public Slot DefineStaticField(string name, Type type)
  93. { return new StaticSlot(TypeBuilder.DefineField(name, type, FieldAttributes.Public|FieldAttributes.Static));
  94. }
  95. public Type FinishType()
  96. { if(initGen!=null)
  97. { initGen.EmitReturn();
  98. initGen.Finish();
  99. }
  100. Type ret = TypeBuilder.CreateType();
  101. if(nestedTypes!=null) foreach(TypeGenerator tg in nestedTypes) tg.FinishType();
  102. return ret;
  103. }
  104. public Slot GetConstant(object value)
  105. { Slot slot;
  106. bool hash = Convert.GetTypeCode(value)!=TypeCode.Object || !(value is List || value is Dict);
  107. if(hash) slot = (Slot)constants[value];
  108. else
  109. { if(constobjs==null) { constobjs = new ArrayList(); constslots = new ArrayList(); }
  110. else
  111. { int index = constobjs.IndexOf(value);
  112. if(index!=-1) return (Slot)constslots[index];
  113. }
  114. slot = null;
  115. }
  116. if(slot==null)
  117. { FieldBuilder fb = TypeBuilder.DefineField("c$"+constants.Count, typeof(object), FieldAttributes.Static);
  118. slot = new StaticSlot(fb);
  119. if(hash) constants[value] = slot;
  120. else { constobjs.Add(value); constslots.Add(slot); }
  121. EmitConstantInitializer(value);
  122. initGen.EmitFieldSet(fb);
  123. }
  124. return slot;
  125. }
  126. public CodeGenerator GetInitializer()
  127. { if(initGen==null)
  128. { ConstructorBuilder cb = TypeBuilder.DefineTypeInitializer();
  129. initGen = new CodeGenerator(this, cb, cb.GetILGenerator());
  130. }
  131. return initGen;
  132. }
  133. public AssemblyGenerator Assembly;
  134. public TypeBuilder TypeBuilder;
  135. void EmitConstantInitializer(object value)
  136. { CodeGenerator cg = GetInitializer();
  137. switch(Convert.GetTypeCode(value))
  138. { case TypeCode.Double:
  139. cg.ILG.Emit(OpCodes.Ldc_R8, (double)value);
  140. cg.ILG.Emit(OpCodes.Box, typeof(double));
  141. break;
  142. case TypeCode.Int32:
  143. cg.EmitInt((int)value);
  144. cg.ILG.Emit(OpCodes.Box, typeof(int));
  145. break;
  146. case TypeCode.Int64:
  147. cg.ILG.Emit(OpCodes.Ldc_I8, (long)value);
  148. cg.ILG.Emit(OpCodes.Box, typeof(long));
  149. break;
  150. case TypeCode.Object:
  151. if(value is Tuple)
  152. { Tuple tup = (Tuple)value;
  153. cg.EmitObjectArray(tup.items);
  154. cg.EmitNew(typeof(Tuple), new Type[] { typeof(object[]) });
  155. }
  156. else if(value is List)
  157. { List list = (List)value;
  158. cg.EmitInt(list.Count);
  159. cg.EmitNew(typeof(List), new Type[] { typeof(int) });
  160. MethodInfo mi = typeof(List).GetMethod("append");
  161. foreach(object o in list)
  162. { cg.ILG.Emit(OpCodes.Dup);
  163. cg.EmitConstant(o);
  164. cg.EmitCall(mi);
  165. }
  166. }
  167. else if(value is Dict)
  168. { Dict dict = (Dict)value;
  169. cg.EmitInt(dict.Count);
  170. cg.EmitNew(typeof(Dict), new Type[] { typeof(int) });
  171. MethodInfo mi = typeof(Dict).GetMethod("Add");
  172. foreach(DictionaryEntry e in dict)
  173. { cg.ILG.Emit(OpCodes.Dup);
  174. cg.EmitConstant(e.Key);
  175. cg.EmitConstant(e.Value);
  176. cg.EmitCall(mi);
  177. }
  178. }
  179. else if(value is Slice)
  180. { Slice slice = (Slice)value;
  181. cg.EmitConstant(slice.start);
  182. cg.EmitConstant(slice.stop);
  183. cg.EmitConstant(slice.step);
  184. cg.EmitNew(typeof(Slice), new Type[] { typeof(object), typeof(object), typeof(object) });
  185. }
  186. else if(value is Complex)
  187. { Complex c = (Complex)value;
  188. cg.EmitDouble(c.real);
  189. cg.EmitDouble(c.imag);
  190. cg.EmitNew(typeof(Complex), new Type[] { typeof(double), typeof(double) });
  191. cg.ILG.Emit(OpCodes.Box, typeof(Complex));
  192. }
  193. else if(value is Integer)
  194. { Integer iv = (Integer)value;
  195. cg.EmitInt(iv.Sign);
  196. cg.EmitNewArray(typeof(uint), iv.length);
  197. for(int i=0; i<iv.length; i++)
  198. { cg.ILG.Emit(OpCodes.Dup);
  199. cg.EmitInt(i);
  200. cg.EmitInt((int)iv.data[i]);
  201. cg.ILG.Emit(OpCodes.Stelem_I4);
  202. }
  203. cg.EmitNew(typeof(Integer), new Type[] { typeof(short), typeof(uint[]) });
  204. cg.ILG.Emit(OpCodes.Box, typeof(Integer));
  205. }
  206. else goto default;
  207. break;
  208. default: throw new NotImplementedException("constant: "+value.GetType());
  209. }
  210. }
  211. Type[] GetParamTypes(ParameterInfo[] pi)
  212. { Type[] paramTypes = new Type[pi.Length];
  213. for(int i=0; i<pi.Length; i++) paramTypes[i] = pi[i].ParameterType;
  214. return paramTypes;
  215. }
  216. HybridDictionary constants = new HybridDictionary();
  217. ArrayList nestedTypes, constobjs, constslots;
  218. CodeGenerator initGen;
  219. Slot moduleField;
  220. }
  221. } // namespace Boa.AST