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

/System.Xronos/Builtins/SpecialForms.FnForm.cs

https://bitbucket.org/stefanrusek/xronos
C# | 151 lines | 105 code | 23 blank | 23 comment | 13 complexity | 7ba44007aa176269a3074322ce6ead9c MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) 2008 Stefan Rusek and Benjamin Pollack
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. *
  23. * ***************************************************************************/
  24. using System;
  25. using System.Collections.Generic;
  26. using System.Linq;
  27. using System.Text;
  28. using System.Xronos.Language;
  29. using Microsoft.Linq.Expressions;
  30. using System.Reflection;
  31. using System.Reflection.Emit;
  32. using System.Collections;
  33. using System.Xronos.Scripting.MetaObjects;
  34. namespace System.Xronos.Builtins
  35. {
  36. public static partial class SpecialForms
  37. {
  38. internal partial class FnForm : SpecialFormBase
  39. {
  40. class RestFunction { }
  41. static Dictionary<string, Type> cache = new Dictionary<string, Type>();
  42. protected override Expression Compile(Compiler compiler, ISequence rest, Scope scope)
  43. {
  44. var name = rest.first() as Symbol;
  45. if (name == null)
  46. name = Symbol.Create("__UnnamedMethod");
  47. else
  48. rest = rest.rest();
  49. int c = -1;
  50. var list = new List<LambdaExpression>();
  51. if (rest.first() is IPersistentVector)
  52. {
  53. list.Add(ParseFunction(compiler, name, ref c, RT.seq(rest), scope));
  54. }
  55. else
  56. {
  57. while (rest != null)
  58. {
  59. list.Add(ParseFunction(compiler, name, ref c, RT.seq(rest.first()), scope));
  60. rest = rest.rest();
  61. }
  62. }
  63. return GetDelegateFunction(name, list);
  64. }
  65. private Expression GetDelegateFunction(Symbol name, List<LambdaExpression> list)
  66. {
  67. var map = new List<Expression>();
  68. foreach (var item in list)
  69. {
  70. var arity = item.Parameters.Count - 1;
  71. while (map.Count < arity)
  72. map.Add(Expression.Constant(null, typeof(FunctionMapEntry)));
  73. var temp = Expression.Parameter(typeof(FunctionMapEntry));
  74. map.Add(Expression.Block(new[] { temp },
  75. Expression.Assign(temp, Expression.New(typeof(FunctionMapEntry))),
  76. Expression.Assign(Expression.Field(temp, "Arity"), Expression.Constant(arity)),
  77. Expression.Assign(Expression.Field(temp, "Delegate"), item),
  78. Expression.Assign(Expression.Field(temp, "IsRest"), Expression.Constant(item.Annotations().Contains<RestFunction>())),
  79. temp));
  80. }
  81. return Expression.New(typeof(DelegateFunction).GetConstructors()[0], Expression.NewArrayInit(typeof(FunctionMapEntry), map));
  82. }
  83. private LambdaExpression ParseFunction(Compiler compiler, Symbol self, ref int c, ISequence cons, Scope scope)
  84. {
  85. var paramNames = (IList)cons.first();
  86. if (c >= paramNames.Count)
  87. throw new InvalidProgramException("Functions must be written in order of increasing numbers of parameters");
  88. c = paramNames.Count;
  89. var annotations = Annotations.Empty;
  90. var paramExprs = new List<ParameterExpression>();
  91. scope = new Scope(scope);
  92. {
  93. var param = Expression.Parameter(typeof(object), self.ToString());
  94. paramExprs.Add(param);
  95. scope[self] = param;
  96. }
  97. foreach (var item in paramNames)
  98. {
  99. var name = (Symbol)item;
  100. if (name.Namespace == null && name.Name == "&")
  101. {
  102. annotations = annotations.Add(new RestFunction());
  103. continue;
  104. }
  105. var param = Expression.Parameter(annotations.Contains<RestFunction>() ? typeof(ISequence) : typeof(object), name.ToString());
  106. paramExprs.Add(param);
  107. scope[name] = param;
  108. }
  109. if (annotations.Contains<RestFunction>() && !paramNames[paramNames.Count - 2].Equals(Symbol.Create("&")))
  110. throw new ReaderException("& cannot appear before any but the last parameter");
  111. var label = Expression.Label();
  112. var vars = new List<Expression>(from p in paramExprs select (Expression)p);
  113. vars.RemoveAt(0);
  114. scope.LoopLabel = label;
  115. scope.LoopVariables = vars;
  116. return Lambda(
  117. Expression.Convert(
  118. LoopForm.BuildOuterLoop(compiler, null, label, DoForm.CompileDo(compiler, null, cons.rest(), null, scope), scope),
  119. typeof(object)),
  120. self.ToString(), annotations, paramExprs.ToArray());
  121. }
  122. public LambdaExpression Lambda(Expression body, string name, Annotations annotations, ParameterExpression[] parameters)
  123. {
  124. return Expression.Lambda(body, name, parameters).Annotate(annotations);
  125. }
  126. }
  127. }
  128. }