vtereshkov / umka-lang

Umka: a statically typed embeddable scripting language
BSD 2-Clause "Simplified" License
1.08k stars 53 forks source link

Implement closures #103

Closed vtereshkov closed 1 year ago

vtereshkov commented 3 years ago

Allow capturing variables from outer function's stack/heap frame:

fn adder(x: int): fn (y: int): int {
    return fn (y: int): int {
        return x + y
    }
}

fn main() {
    add5 := adder(5)
    a := add5(7)
    printf(repr(a) + '\n')  // 12
}

This would require changing the internal representation of functions from

int64_t entry;

to

struct
{
    int64_t entry;
    void *upvalues;
}

The API functions umkaCall() and umkaGetFunc() will also have to be changed.

vtereshkov commented 3 years ago

Beware of extremely perverse cases like the following one taken from Crafting Interpreters.

fun outer() {
  var x = "value";
  fun middle() {
    fun inner() {
      print x;
    }

    print "create inner closure";
    return inner;
  }

  print "return from outer";
  return middle;
}

var mid = outer();
var in = mid();
in();
vtereshkov commented 1 year ago

The example from Crafting Interpreters rewritten in Umka:

fn outer(): fn(): fn() {
  x := "value"

  middle := fn(): fn() |x| {
    inner := fn() |x| {
      printf("%s\n", x)
    }

    printf("create inner closure\n")
    return inner
  }

  printf("return from outer\n")
  return middle
}

fn main() {
  mid := outer()
  inn := mid()
  inn()
}

Output:

return from outer
create inner closure
value