functions.txt 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. How to compile action language functions to Rust ?
  2. ==================================================
  3. General rules
  4. -------------
  5. - a function always receives mut refs (borrows) to the parent scope(s) that it accesses
  6. - a function incrementally constructs a new scope obj with its local variables
  7. -> this cannot include the mut ref to the parent scope(s),
  8. because if after returning, the scope obj may be stored into the scope obj of the parent
  9. - a function can return its own scope obj ('move')
  10. => closures
  11. 1) when a function A returns a function B declared in A's scope, A returns a closure obj. example:
  12. func(i: int) {
  13. return func {
  14. return i++;
  15. }
  16. }
  17. calling the above function would result in a tuple (scope{i}, funcptr)
  18. 2) when returning a closure:
  19. func {
  20. x = func(i: int) {
  21. return func {
  22. return i++;
  23. }
  24. }; // x is just a funcptr
  25. y = x(); // y is a closure obj (scope{i}, funcptr)
  26. return y;
  27. }
  28. the closure is just a value :)
  29. 3) a closure returning a closure:
  30. func {
  31. return func(i: int) { // <- funcptr
  32. return func {
  33. return i++;
  34. }
  35. }
  36. }
  37. calling the above function would result in a tuple (scope{}, fncptr)
  38. ^
  39. scope empty, but still treat this as a closure (no special cases!)
  40. => accessing variables from parent scopes
  41. 1) trivial case
  42. func {
  43. x = 0;
  44. f = func { // parent = &mut scope
  45. x += 1; // parent.x++;
  46. }
  47. f();
  48. }
  49. 2) more nesting
  50. a = func {
  51. x = 0;
  52. f = func { // parent1 = &mut a_partial
  53. g = func { // parent1 = &mut f_partial, parent2 = &mut a_partial
  54. x += 1; // parent2.x++;
  55. } // g = fn(parent1: &mut f_partial, parent2: &mut a_partial) { ... }
  56. g(); // fn(&mut scope, &mut parent1)
  57. }
  58. }
  59. 3) bringing it all together
  60. a = func {
  61. x = 0;
  62. f = func { // parent1 = &mut a_partial{x}
  63. g = func { // parent1 = &mut f_partial, parent2 = &mut a_partial{x}
  64. x += 1; // parent2.x++;
  65. }
  66. return g;
  67. }
  68. g = f(); // g is a closure obj: (scope_f, fn(&mut f_partial, &mut a_partial))
  69. g(); fn(&mut scope_f, &mut scope)
  70. }
  71. - a function has a mut ref for each of its partial ancestor scopes
  72. -> statically known!
  73. - a closure obj is always called with its first tuple element as its parent1-parameter
  74. -> can be statically known!
  75. - to call a function with multiple ancestors, those ancestors are simply the ancestors of the current scope
  76. -> statically known!
  77. => Implementation
  78. 1) extend action lang static analyzer to differentiate between closure objects and function pointers
  79. 2) profit! :)