PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/Backend/Runtime/Function.cs

https://bitbucket.org/AdamMil/boaold
C# | 220 lines | 160 code | 38 blank | 22 comment | 38 complexity | 3859a67c961070044c356d7fb9a46c03 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 Boa.AST;
  22. namespace Boa.Runtime
  23. {
  24. public enum FunctionType { Unmarked, Static, Class, Method };
  25. public struct CallArg
  26. { public CallArg(object value, object type) { Value=value; Type=type; }
  27. public object Value, Type;
  28. public static readonly object DictType="<dict>", ListType="<list>";
  29. }
  30. public abstract class Function : IFancyCallable
  31. { public Function(string name, string[] names, object[] defaults, bool list, bool dict, int required)
  32. { Name=name; ParamNames=names; Defaults=defaults; HasList=list; HasDict=dict; NumRequired=required;
  33. Type=FunctionType.Unmarked;
  34. }
  35. public string FuncName { get { return Name==null ? "<lambda>" : Name; } }
  36. public object __call__(params object[] args) { return Call(args); }
  37. public abstract object Call(params object[] args);
  38. public abstract object Call(object[] args, string[] names, object[] values);
  39. public abstract Function MakeMarked(FunctionType type);
  40. public override string ToString() { return Name==null ? "<lambda>" : string.Format("<function '{0}'>", Name); }
  41. public string Name, __doc__;
  42. public string[] ParamNames;
  43. public object[] Defaults;
  44. public int NumRequired;
  45. public FunctionType Type;
  46. public bool HasList, HasDict;
  47. protected object[] FixArgs(object[] args)
  48. { if(args.Length<NumRequired) throw Ops.TooFewArgs(FuncName, NumRequired, args.Length);
  49. if(HasList)
  50. { if(!HasDict && ParamNames.Length==1) return new object[] { new Tuple(args) };
  51. }
  52. else if(args.Length==ParamNames.Length) return args;
  53. else if(args.Length>ParamNames.Length) throw Ops.TooManyArgs(FuncName, ParamNames.Length, args.Length);
  54. object[] newargs = new object[ParamNames.Length];
  55. int plen=ParamNames.Length, offset=HasList ? 1 : 0;
  56. if(HasDict) newargs[--plen] = new Dict();
  57. int pos=plen-offset, ai=Math.Min(pos, args.Length);
  58. for(int i=0; i<ai; i++) newargs[i] = args[i];
  59. for(; ai<pos; ai++) newargs[ai] = Defaults[ai-NumRequired];
  60. if(HasList)
  61. { Tuple tup;
  62. if(ai>=args.Length) tup = new Tuple();
  63. else
  64. { object[] items = new object[args.Length-ai];
  65. Array.Copy(args, ai, items, 0, items.Length);
  66. tup = new Tuple(items);
  67. }
  68. newargs[plen-1] = tup;
  69. }
  70. return newargs;
  71. }
  72. protected unsafe object[] MakeArgs(object[] positional, string[] names, object[] values)
  73. { object[] newargs = new object[ParamNames.Length];
  74. bool* done = stackalloc bool[newargs.Length];
  75. Dict dict = null;
  76. int pi=0, js=0, plen=newargs.Length;
  77. for(int i=0; i<newargs.Length; i++) done[i] = false;
  78. // do the positional arguments first
  79. if(positional!=null)
  80. for(int end=Math.Min(plen-(HasDict?1:0)-(HasList?1:0), positional.Length); pi<end; pi++)
  81. { newargs[pi] = positional[pi];
  82. done[pi] = true;
  83. }
  84. // do named arguments
  85. for(int i=0; i<names.Length; i++)
  86. { string name = names[i];
  87. for(int j=js; j<plen; j++)
  88. if(ParamNames[j]==names[i])
  89. { if(done[j]) throw Ops.TypeError("'{0}()' got duplicate values for parameter '{1}'", FuncName, name);
  90. newargs[j] = values[i];
  91. done[j] = true;
  92. if(j==js)
  93. { do j++; while(j<plen && done[j]);
  94. if(j<plen) js=j;
  95. }
  96. goto next;
  97. }
  98. if(HasDict)
  99. { if(dict==null) dict = new Dict();
  100. dict[name] = values[i];
  101. }
  102. else throw Ops.TypeError("'{0}()' got an unexpected keyword parameter '{1}'", FuncName, name);
  103. next:;
  104. }
  105. if(HasDict)
  106. { if(done[--plen])
  107. { if(dict!=null)
  108. throw Ops.TypeError("'{0}()' got duplicate values for parameter '{1}'", FuncName, names[plen-1]);
  109. }
  110. else newargs[plen] = (dict==null ? new Dict() : dict);
  111. }
  112. if(HasList)
  113. { Tuple tup;
  114. if(pi==0) tup = new Tuple(positional==null ? Misc.EmptyArray : positional);
  115. else
  116. { object[] items = new object[positional.Length-pi];
  117. Array.Copy(positional, pi, items, 0, items.Length);
  118. tup = new Tuple(items);
  119. }
  120. newargs[--plen] = tup;
  121. }
  122. for(; pi<plen; pi++) newargs[pi] = Defaults[pi-NumRequired];
  123. for(pi=0; pi<NumRequired; pi++)
  124. if(!done[pi]) throw Ops.TypeError("No value given for parameter '{0}'", ParamNames[pi]);
  125. return newargs;
  126. }
  127. }
  128. #region Compiled functions
  129. public delegate object CallTargetN(params object[] args);
  130. public abstract class CompiledFunction : Function
  131. { public CompiledFunction(string name, string[] names, object[] defaults, bool list, bool dict, int required)
  132. : base(name, names, defaults, list, dict, required) { }
  133. public override object Call(params object[] args) { return DoCall(FixArgs(args)); }
  134. public override object Call(object[] positional, string[] names, object[] values)
  135. { return DoCall(MakeArgs(positional, names, values));
  136. }
  137. protected abstract object DoCall(object[] args);
  138. }
  139. public sealed class CompiledFunctionN : CompiledFunction
  140. { public CompiledFunctionN(string name, string[] names, object[] defaults, bool list, bool dict, int required,
  141. CallTargetN target)
  142. : base(name, names, defaults, list, dict, required) { Target=target; }
  143. public override Function MakeMarked(FunctionType type)
  144. { Function f = new CompiledFunctionN(Name, ParamNames, Defaults, HasList, HasDict, NumRequired, Target);
  145. f.Type = type;
  146. return f;
  147. }
  148. protected override object DoCall(object[] args) { return Target(args); }
  149. CallTargetN Target;
  150. }
  151. #endregion
  152. public sealed class InterpretedFunction : Function
  153. { public InterpretedFunction(string name, string[] names, object[] defaults, bool list, bool dict, int required,
  154. Name[] globals, Frame frame, Statement body, string docstring)
  155. : base(name, names, defaults, list, dict, required)
  156. { Globals=globals; Frame=frame; Body=body; __doc__=docstring;
  157. }
  158. public override object Call(params object[] args) { return DoCall(FixArgs(args)); }
  159. public override object Call(object[] positional, string[] names, object[] values)
  160. { return DoCall(MakeArgs(positional, names, values));
  161. }
  162. public override Function MakeMarked(FunctionType type)
  163. { Function f = new InterpretedFunction(Name, ParamNames, Defaults, HasList, HasDict, NumRequired,
  164. Globals, Frame, Body, __doc__);
  165. f.Type = type;
  166. return f;
  167. }
  168. public Name[] Globals;
  169. public Frame Frame;
  170. public Statement Body;
  171. object DoCall(object[] args)
  172. { Frame localFrame = new Frame(Frame);
  173. for(int i=0; i<args.Length; i++) localFrame.Set(ParamNames[i], args[i]);
  174. if(Globals!=null) for(int i=0; i<Globals.Length; i++) localFrame.MarkGlobal(Globals[i].String);
  175. try { Body.Execute(localFrame); }
  176. catch(ReturnException e) { return e.Value; }
  177. return null;
  178. }
  179. }
  180. } // namespace Boa.Runtime