desug.mli 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. (** Desugaring: split variable initialisations, prevent incorrect double
  2. evaluation, and transform for-loops to while-loops. *)
  3. (** {2 Split variable initialisations}
  4. Variable initialisations are splint into declarations and assignments, to
  5. generalize the AST format. This makes context analysis easier, since
  6. initialisations need not be considered. The assignments are placed in the
  7. function body, after local fuction declarations (which are not in the
  8. example):
  9. {v int foo = 0;
  10. int bar = foo; v}
  11. becomes:
  12. {v int foo;
  13. int bar;
  14. foo = 0;
  15. bar = foo; v}
  16. {3 Array initialisations}
  17. A more complex class of initialisations are array initialisations. Arrays
  18. can be initialised to a scalar value or to an array constant. For array
  19. constants that cover all array dimensions, separate assign statements are
  20. generated for each array index. For scalar values and aray constants that
  21. have a lower nesting level than the number of array dimensions, for-loops
  22. are generated. The following example shows all situation:
  23. {v int[3] a = [1, 2, 3];
  24. int[3] b = 4;
  25. int[2, 2] c = [[3, 4], 5]; v}
  26. The snippet above is transformed to code equivalent to the following:
  27. {v int[] a;
  28. int[] b;
  29. int[] c;
  30. a = __allocate(3);
  31. a[0] = 1;
  32. a[1] = 2;
  33. a[2] = 3;
  34. b = __allocate(3);
  35. for (int i = 0, 3) \{
  36. b[i] = 4;
  37. \}
  38. c = __allocate(4);
  39. c[0] = 3;
  40. c[1] = 4;
  41. for (int i = 0, 2) \{
  42. c[1, i] = 5;
  43. \} v}
  44. {2 Prevent incorrect double evaluation}
  45. In the following code:
  46. {v int twos = 0;
  47. int two() \{
  48. twos = twos + 1;
  49. return 2;
  50. \}
  51. void foo() \{
  52. int[2, two()] a = [[1, two()], [1, two()]];
  53. printInt(a[1, 1]);
  54. \} v}
  55. [two()] must be evaluated exactly three times in order to preserve correct
  56. behaviour. However, [a[1, 1]] will at a later stage be transformed into
  57. [a[(1 * two()) + 1]], thus incorrectly evaluating [two()] an additional
  58. time. Assigning a scalar value to an array create the same problem, since
  59. this is trwnsformed into a for-loop, where the scalar expression is
  60. evaluated during each iteration. The problem is solved by creating new
  61. so-called "constant variables" for all of these values, and initializing hem
  62. to the original expressions. The expressions are then replaced with usages
  63. of these variables. A constant variable is a variable that is known to only
  64. be assigned once in total. This is only true for some variables generated by
  65. the compiler. In the later {!Constprop} phase, these assignments are a found
  66. and those which assign constant values (e.g., integers), are propagated to
  67. uses of the variable. This way, only the non-constant expressions are
  68. defined in new variables in the resulting code.
  69. For the example above, the result will be (after array dimension reduction
  70. and constant propagation):
  71. {v ...
  72. void foo() \{
  73. int a$dim$$2 = two();
  74. int const$$1 = two();
  75. int const$$2 = two();
  76. int[2, a$dim$$2] a;
  77. a = __allocate(2 * a$dim$$2);
  78. a[0] = 1;
  79. a[1] = const$$1;
  80. a[a$dim$$2)] = 1;
  81. a[a$dim$$2) + 1] = const$$2;
  82. printInt(a[(1 * a$dim$$2) + 1]);
  83. \} v}
  84. {2 Transforming for-loops to while-loops}
  85. {v for(int i = <start>,<stop>,<step>) \{
  86. <body>
  87. \} v}
  88. is transformed into:
  89. {v i$1 = <start>;
  90. step$2 = <step>;
  91. stop$3 = <stop>;
  92. while((step$2 > 0) ? (i$1 < stop$3) : (i$1 > stop$3)) \{
  93. <body>
  94. i$1 = i$1 + step$2;
  95. \} v}
  96. Where [i$1], [step$2] and [stop$3] are fresh variables. Definitions of these
  97. new variables are added to the scope of the current function. Every
  98. occurrence of [i] in [<body>] is replaced with the fresh variable [i$1],
  99. this prevents problems with nested for-loops that use the same induction
  100. variable .*)
  101. (** Main phase function, called by {!Main}. *)
  102. val phase : Main.phase_func