PageRenderTime 946ms CodeModel.GetById 29ms RepoModel.GetById 6ms app.codeStats 0ms

/SSharp.Core/DataTypes/List.cs

https://code.google.com/p/s-sharp/
C# | 133 lines | 78 code | 18 blank | 37 comment | 17 complexity | c9b1b8d005335af7d91e8e7726121b83 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using SSharp.Core.Evaluator;
  6. namespace SSharp.Core.DataTypes {
  7. /// <summary>
  8. /// Scheme lists are built from pairs and the empty list instance.
  9. /// </summary>
  10. public static class List {
  11. private static readonly Symbol dotSymbol = new Symbol(".");
  12. /// <summary>
  13. /// Creates a scheme list from an array.
  14. /// </summary>
  15. public static object Create(params object[] values) {
  16. return ParseDots(values);
  17. }
  18. /// <summary>
  19. /// Creates a scheme list from an IList.
  20. /// </summary>
  21. public static object Create(IEnumerable<object> values) {
  22. return ParseDots(values.ToArray());
  23. }
  24. /// <summary>
  25. /// Parses dots in the list, and returns the scheme list.
  26. /// </summary>
  27. private static object ParseDots(object[] values) {
  28. for (int i = 0; i < values.Length; i++) {
  29. if (dotSymbol.Equals(values[i])) {
  30. if (i > 0
  31. && values.Length == i + 2
  32. && !dotSymbol.Equals(values[i + 1])) {
  33. // if the dot is not the first element
  34. // and it is the one-before-last element
  35. // and the last element is not a dot
  36. // then this is the standard dotted syntax - list is something like (a b c d . e)
  37. // e is then used instead of the empty-list to end (a b c d)
  38. return BuildList(values.Take(i), values[i + 1]);
  39. }
  40. if (i > 0
  41. && values.Length > i + 3
  42. && !dotSymbol.Equals(values[i + 1])
  43. && dotSymbol.Equals(values[i + 2])
  44. && !values.Skip(i + 3).Contains(dotSymbol)) {
  45. // if the dot is not the first element
  46. // and it has at least three elements after it
  47. // and the element 2 after it is a dot
  48. // and no other element is a dot
  49. // then this is the infix dotted syntax - list is something like (a b . c . d e)
  50. // c is then moved to the front of the list to produce (c a b d e)
  51. return BuildList(
  52. new[] { values[i + 1] }
  53. .Concat(values.Take(i))
  54. .Concat(values.Skip(i + 3)),
  55. EmptyList.Instance);
  56. }
  57. throw new SyntaxError("List: incorrect use of .");
  58. }
  59. }
  60. return BuildList(values, EmptyList.Instance);
  61. }
  62. /// <summary>
  63. /// Builds a list, with the given last element (normally EmptyList.Instace)
  64. /// </summary>
  65. private static object BuildList(IEnumerable<object> values, object lastElement) {
  66. object result = lastElement;
  67. // loop backwards to generate a forward-pointing list.
  68. foreach (object value in values.Reverse()) {
  69. result = new Cons(value, result);
  70. }
  71. return result;
  72. }
  73. /// <summary>
  74. /// Creates an IList from a scheme list.
  75. /// If the list is not a valid list (e.g. it has a non-list cdr in some location), null is returned.
  76. /// </summary>
  77. public static IList<object> Unpack(object list) {
  78. if (list == null) {
  79. return null;
  80. }
  81. List<object> result = new List<object>();
  82. // go through all the consecutive car's and add them to the result list - until the cdr is not a cons.
  83. object cdr = list;
  84. Cons cons = cdr as Cons;
  85. while (cons != null) {
  86. result.Add(cons.car);
  87. cdr = cons.cdr;
  88. cons = cdr as Cons;
  89. }
  90. if (cdr is EmptyList) {
  91. // valid list
  92. return result;
  93. } else {
  94. // the last element is not () (and not a Cons) - it's not a valid list.
  95. return null;
  96. }
  97. }
  98. /// <summary>
  99. /// A singleton that represents the empty list, ()
  100. /// </summary>
  101. public class EmptyList {
  102. public static readonly EmptyList Instance = new EmptyList();
  103. private EmptyList() { }
  104. public override int GetHashCode() {
  105. return 0;
  106. }
  107. public override bool Equals(object obj) {
  108. return obj is EmptyList;
  109. }
  110. public override string ToString() {
  111. return "()";
  112. }
  113. }
  114. }
  115. }