530 lines
12 KiB
Plaintext
530 lines
12 KiB
Plaintext
pub enum Closure(P, D = Any, S = Any) -> T {
|
|
Read(ReadClosure), // reads self (where Self is Closure) and/or environment
|
|
ReadRef(ReadRefClosure), // reads environment/self, return value tied to closure
|
|
Mut(MutClosure), // mutates self/environment
|
|
MutRef(MutRefClosure), // mutates self/environment, return value tied to closure
|
|
Cons(ConsClosure), // consumes self/environment
|
|
}
|
|
|
|
class Foo(bar: Bar) {}
|
|
|
|
class Bar(mut i: Int) {}
|
|
|
|
fn readClosure(cl: Closure(Int) -> String) -> String {
|
|
cl(42)
|
|
}
|
|
|
|
fn useReadClosure() {
|
|
let s = readClosure { i ->
|
|
'i: ' + i.toString()
|
|
}
|
|
assertEq('i: 42', s)
|
|
}
|
|
|
|
fn mutClosure(cl: mut Closure(Int) -> String) -> String {
|
|
cl(42)
|
|
}
|
|
|
|
fn useMutClosure() {
|
|
let mut x = 0
|
|
let cl: mut Closure(Int) -> String = mut { i ->
|
|
let result = 'Val: ' + (i + x)
|
|
x++
|
|
result
|
|
}
|
|
let s0 = mutClosure cl
|
|
assertEq('Val: 42', s0)
|
|
let s1 = mutClosure cl
|
|
assertEq('Val: 43', s1)
|
|
}
|
|
|
|
fn consClosure(cl: cons Closure(Int) -> String) -> String {
|
|
cl(42)
|
|
// cl(43) // Error! cl was already consumed
|
|
}
|
|
|
|
fn useConsClosure() {
|
|
let foo = Foo(Bar(10))
|
|
let cl: cons Closure(Int) -> String = cons { i ->
|
|
let fooBarI = foo.bar.i
|
|
drop(foo)
|
|
'Val: ' + (i + fooBarI)
|
|
}
|
|
let s = consClosure(cl)
|
|
// let err0 = consClosure(cl) // Error! cl may have been consumed
|
|
// let err1 = foo // Error! foo may have been consumed
|
|
assertEq('Val: 52', s)
|
|
}
|
|
|
|
fn readRefClosure(cl: Closure(foo: Foo) -> Bar ref foo) -> Int {
|
|
let foo = Foo(Bar(42))
|
|
let bar = cl(foo)
|
|
bar.i
|
|
}
|
|
|
|
fn useReadRefClosure() {
|
|
let i = readRefClosure { foo -> foo.bar }
|
|
assertEq(42, i)
|
|
}
|
|
|
|
fn mutRefClosure(cl: mut Closure(foo: Foo) -> Bar ref foo) -> Int {
|
|
let foo = Foo(Bar(42))
|
|
let bar = cl(foo)
|
|
bar.i
|
|
}
|
|
|
|
fn useMutRefClosure() {
|
|
let i = mutRefClosure mut { foo ->
|
|
foo.bar.i = 84
|
|
foo.bar
|
|
}
|
|
assertEq(84, i)
|
|
}
|
|
|
|
fn readClosureWithDelegate(cl: Closure(P = Int, D = Foo) -> String) -> String {
|
|
cl(42)
|
|
}
|
|
|
|
fn useReadClosureWithDelegate() {
|
|
let foo = Foo(Bar(42))
|
|
let cl = { i: Int ->
|
|
'Val: ' + (i + bar.i) // bar found in delegate
|
|
}
|
|
cl.delegate = &foo
|
|
let s = readClosureWithDelegate(cl)
|
|
assertEq('Val: 84', s)
|
|
}
|
|
|
|
class Baz(foo: Foo) {}
|
|
|
|
fn mutRefClosureWithDelegate(baz: &mut Baz, cl: Closure(Int, baz: &mut Baz)(D = Foo) -> &Bar ref baz) -> String {
|
|
let foo = Foo(Bar(1))
|
|
cl.delegate = &foo
|
|
let bar = cl(2, baz)
|
|
'Val: ' + bar.i
|
|
}
|
|
|
|
fn useMutRefClosureWithDelegate() {
|
|
let cl: Closure(Int, baz: &mut Baz)(D = Foo) -> &Bar ref baz = mut { i, baz ->
|
|
let iFromDelegate = bar.i
|
|
baz.foo.bar.i = iFromDelegate + i
|
|
&baz.foo.bar
|
|
}
|
|
let baz = Baz(Foo(Bar(20)))
|
|
let bar = mutRefClosureWithDelegate(cl)
|
|
assertEq(3, bar.i)
|
|
}
|
|
|
|
fn mutClosureWithDelegate(cl: Closure(P = (Int, Int), D = mut Foo) -> String {
|
|
let foo = Foo(Bar(42))
|
|
cl.delegate = &mut foo
|
|
cl(1, 2)
|
|
}
|
|
|
|
fn useMutClosureWithDelegate() {
|
|
let cl: Closure(P = (Int, Int), D = mut Foo) -> String = mut { x, y ->
|
|
bar.i = 3
|
|
'Val: ' + (x + y + bar.i)
|
|
}
|
|
let s = mutClosureWithDelegate(cl)
|
|
assertEq('Val: 6', s)
|
|
}
|
|
|
|
pub int ClosureBase {
|
|
params: Array<ClosureParam>
|
|
mut resolutionStrategy: ResolutionStrategy
|
|
ref fn getDelegate() -> Option<&Any>
|
|
ref fn getSelfObject() -> Option<&Any>
|
|
}
|
|
|
|
pub enum ResolutionStrategy {
|
|
DelegateFirst,
|
|
DelegateOnly,
|
|
SelfFirst,
|
|
SelfOnly,
|
|
None
|
|
}
|
|
|
|
pub int ConsClosure<T> : ClosureBase {
|
|
mut fn setDelegate(d: Any) -> Void
|
|
mut fn setSelf(s: Any) -> Void
|
|
mut fn call(...args: Array<Any>) -> T
|
|
def mut op () (...args: Array<Any) -> T = call(...args)
|
|
}
|
|
|
|
pub int MutClosure<T> : ClosureBase {
|
|
mut fn setDelegate(d: &mut Any) -> Void
|
|
mut fn setSelf(s: &mut Any) -> Void
|
|
mut fn call(...args: Array<Any>) -> T
|
|
def mut op () (...args: Array<Any>) -> T = call(...args)
|
|
}
|
|
|
|
pub int MutRefClosure<T> : ClosureBase {
|
|
mut fn setDelegate(d: &mut Any) -> Void
|
|
mut fn setSelf(s: &mut Any) -> Void
|
|
mut ref fn call(...args: Array<Any>) -> T // T ref self
|
|
def mut ref op () (...args: Array<Any>) -> T = call(...args)
|
|
}
|
|
|
|
pub int ReadClosure<T> : ClosureBase {
|
|
mut fn setDelegate(d: &Any) -> Void
|
|
mut fn setSelf(s: &Any) -> Void
|
|
fn call(...args: Array<Any>) -> T
|
|
def op () (...args: Array<Any>) -> T = call(...args)
|
|
}
|
|
|
|
pub int ReadRefClosure<T> : ClosureBase {
|
|
mut fn setDelegate(d: &Any) -> Void
|
|
mut fn setSelf(s: &Any) -> Void
|
|
ref fn call(...args: Array<Any>) -> T
|
|
def op () (...args) -> T = call(..args)
|
|
}
|
|
|
|
pub int ClosureParam {
|
|
clazz: Class<Any>
|
|
def op typeof () -> Class<Any> = clazz
|
|
}
|
|
|
|
// Example of how closures are compiled
|
|
|
|
fn main() {
|
|
let is = [1, 2, 3]
|
|
let cl0 = { acc: String, i: Int ->
|
|
acc + i
|
|
}
|
|
println is.reduce(cl0)
|
|
|
|
let x = 10
|
|
let cl1 = /* read */ { acc: String, i: Int ->
|
|
acc + (i + x)
|
|
}
|
|
println is.reduce(cl1)
|
|
|
|
let mut counter = 0
|
|
let cl2 = mut { acc: String, i: Int ->
|
|
let result = acc + (i + counter)
|
|
counter++
|
|
result
|
|
}
|
|
println is.reduce(cl2)
|
|
|
|
let mut foo = Foo(Bar(1))
|
|
let cl3 = cons { acc: String, i: Int ->
|
|
// do something pointless just for illustration
|
|
if foo.bar.y % 2 == 0 {
|
|
foo.bar = Bar(1)
|
|
}
|
|
let result = acc + (i + foo.bar.y)
|
|
foo.bar.y++
|
|
result
|
|
}
|
|
// foo.bar = Bar(42) // Error! foo moved into consuming cl3
|
|
println [1, 2, 3, 4].reduce(cl3) // "11243645"
|
|
}
|
|
|
|
// Compiled
|
|
|
|
@Synthetic
|
|
fn closure_main_cl0(acc: String, i: Int) = acc + i
|
|
|
|
@Synthetic
|
|
class Closure_main_cl1_env(x: &Int) -> String {}
|
|
|
|
@Synthetic
|
|
class Closure_main_cl1(env: Closure_main_cl1_env) : ReadClosure<String> {
|
|
impl fn call(...args: Array<Any>) -> String {
|
|
let acc: String = args[0]
|
|
let i: Int = args[1]
|
|
let x: Int = *env.x // because env.getX() -> &&Int
|
|
acc + (i + x)
|
|
}
|
|
}
|
|
|
|
@Synthetic
|
|
class Closure_main_cl2_env(counter: &mut Int) {}
|
|
|
|
@Synthetic
|
|
class Closure_main_cl2(env: Closure_main_cl2_env) : MutClosure<String> {
|
|
impl mut fn call(...args: Array<Any>) -> String {
|
|
let acc: String = args[0]
|
|
let i: Int = args[1]
|
|
let counter = &mut env.counter
|
|
let result = acc + (i + counter)
|
|
*counter++
|
|
result
|
|
}
|
|
}
|
|
|
|
@Synthetic
|
|
class Closure_main_cl3(mut foo: Foo) : ConsClosure<String> {
|
|
impl mut fn call(...args: Array<Any>) -> String {
|
|
let acc: String = args[0]
|
|
let i: Int = args[1]
|
|
if foo.bar.y % 3 == 0 {
|
|
foo.bar = Bar(1)
|
|
}
|
|
let result = acc + (i + foo.bar.y)
|
|
foo.bar.y++
|
|
result
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let is: List<Int> = ArrayList() {
|
|
add 1
|
|
add 2
|
|
add 3
|
|
}
|
|
let cl0 = &closure_main_cl0
|
|
println is.reduce(cl0)
|
|
|
|
let x = 10
|
|
let cl1_env = HashMap() {
|
|
put 'x', &x
|
|
}
|
|
let cl1: Closure<String> = Closure::ReadClosure(Closure_main_cl1(cl1_env))
|
|
println is.reduce(cl1)
|
|
|
|
let mut counter = 0
|
|
let cl2_env = Closure_main_cl2_env(&counter)
|
|
let cl2: Closure<String> = Closure::MutClosure(Closure_main_cl2(cl2_env))
|
|
println is.reduce(cl2)
|
|
|
|
let mut foo = Foo(Bar(1))
|
|
let cl3: Closure<String> = Closure::ConsClosure(Closure_main_cl3(foo)) // foo moved into closure
|
|
let tmp0: List<Int> = ArrayList() {
|
|
addAll 1, 2, 3, 4
|
|
}
|
|
println tmp0.reduce(cl3)
|
|
}
|
|
|
|
// Example
|
|
|
|
// original
|
|
class Foo {
|
|
mut fld current = 0
|
|
|
|
ref fn getClosure(base: Int) -> (mut Closure(Int) -> Int) {
|
|
return mut { given ->
|
|
let result = base + given + current
|
|
current++
|
|
result
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let foo = Foo()
|
|
let cl = foo.getClosure(10)
|
|
let nums = [cl(1), cl(2), cl(3), cl(4)]
|
|
assertEq([11, 13, 15, 17], nums)
|
|
}
|
|
|
|
// Compiles to
|
|
|
|
@Synthetic
|
|
class Closure_Foo_getClosure_0(base: &Int, current: &mut Int) : MutClosure(Int) -> Int {
|
|
impl mut fn call(given: Int) -> Int {
|
|
let result = *base + given + *current
|
|
*current++
|
|
result
|
|
}
|
|
}
|
|
|
|
class Foo {
|
|
mut fld current = 0
|
|
|
|
ref fn getClosure(base: Int) -> (mut Closure(Int) -> Int) {
|
|
return Closure_Foo_getClosure_0(&base, &mut current)
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
/* ... */
|
|
}
|
|
|
|
// Library code
|
|
|
|
pub int ReadClosure(P : () = ())<T, D = Any, S = Any> : Into[Self(P)<T, D, S>, Option<D>] {
|
|
mut fn setDelegate(d: D) -> Void
|
|
ref fn getDelegate() -> Option<&D>
|
|
mut fn setSelfObject(s: &S) -> Void
|
|
ref fn getSelfObject() -> Option<&S>
|
|
fn call(...params: P) -> T
|
|
def op () (...params: P) -> T = call(...params)
|
|
|
|
def cons fn intoDelegate() -> D {
|
|
Into[Self(P)<T, D, S>, Option<D>].into()
|
|
}
|
|
}
|
|
|
|
pub abstract class AbstractReadClosure(P : () = ())<T, D = Any, S = Any> : ReadClosure(P)<T, D, S> {
|
|
mut fld delegate: Option<D>
|
|
mut fld selfObject: Option<&S>
|
|
|
|
impl mut fn setDelegate(d: D) {
|
|
delegate = Some(d)
|
|
}
|
|
|
|
impl ref fn getDelegate() -> Option<&D> {
|
|
&delegate is Some(d) ? Some(d) : None
|
|
}
|
|
|
|
impl mut fn setSelfObject(s: &S) {
|
|
selfObject = Some(s)
|
|
}
|
|
|
|
impl ref fn getSelfObject() -> Option<&S> {
|
|
&selfObject is Some(s) ? Some(s) : None
|
|
}
|
|
|
|
impl Into[Self(P)<T, D, S>, D] {
|
|
cons fn into() -> Option<D> = delegate
|
|
}
|
|
}
|
|
|
|
// User code demonstration
|
|
|
|
class Foo(bar: Bar) {}
|
|
|
|
class Bar(num: Int) {}
|
|
|
|
class Baz(foo: Foo) {
|
|
pub ref fn getClosure() -> Closure<Int, D = Foo> {
|
|
return { foo.bar.num + bar.num }
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let baz0 = Baz(Foo(Bar(1)))
|
|
let cl = baz0.getClosure()
|
|
let delegate = Foo(Bar(2))
|
|
cl.delegate = delegate
|
|
let result0 = cl()
|
|
assertEq(3, result0)
|
|
let baz1 = Baz(Foo(Bar(2)))
|
|
cl.selfObject = &baz1
|
|
let result1 = cl()
|
|
assertEq(4, result1)
|
|
let movedDelegate = cl.intoDelegate()
|
|
assertEq(2, movedDelegate.bar.num)
|
|
}
|
|
|
|
// User code compiles to
|
|
|
|
class Foo(bar: Bar) {}
|
|
|
|
class Bar(num: Int) {}
|
|
|
|
@Synthetic
|
|
class Closure_Baz_getClosure_0: AbstractReadClosure()<Int, D = Foo> {
|
|
ctor(selfObject: &Baz) ref selfObject {
|
|
self.selfObject = Some(selfObject)
|
|
}
|
|
|
|
fn call() -> Int {
|
|
let t0 = selfObject.unwrap().foo.bar.num
|
|
let t1 = self.delegate.unwrap().bar.num
|
|
t0 + t1
|
|
}
|
|
}
|
|
|
|
class Baz(foo: Foo) {
|
|
pub ref fn getClosure() -> Closure<Int, D = Foo> {
|
|
return Closure_Baz_getClosure_0(&self)
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
// ...
|
|
}
|
|
|
|
// fn vs Closure syntax
|
|
|
|
int FnOrClosureTaker {
|
|
fn read(f: fn (Int) -> Int) -> Int
|
|
fn mut(f: mut fn (Int) -> Int) -> Int
|
|
fn cons(f: cons fn (Int) -> Int) -> Int
|
|
}
|
|
|
|
class FnOrClosureTakerImpl : FnOrClosureTaker {
|
|
impl fn read(f: fn (Int) -> Int) {
|
|
let i0 = f(0)
|
|
let i1 = f(1)
|
|
let i2 = f(2)
|
|
i0 + i1 + i2
|
|
}
|
|
|
|
impl fn mut(f: mut fn (Int) -> Int) {
|
|
/* same as read */
|
|
}
|
|
|
|
impl fn cons(f: cons fn (Int) -> Int) {
|
|
let i0 = f()
|
|
// let i1 = f() // Error! f already consumed
|
|
i0
|
|
}
|
|
}
|
|
|
|
mod User {
|
|
fn getReader() -> fn (Int) -> Int {
|
|
return { it * 2 }
|
|
}
|
|
|
|
fn useReader() {
|
|
let reader = getReader()
|
|
let fnOrClosureTaker: FnOrClosureTaker = FnOrClosureTakerImpl()
|
|
let result = fnOrClosureTaker.read(reader)
|
|
assertEq(6, result)
|
|
}
|
|
}
|
|
|
|
// compiles to
|
|
|
|
mod User {
|
|
fn getReader_closure_0(it: Int) -> Int {
|
|
it * 2
|
|
}
|
|
|
|
fn getReader() -> &fn (Int) -> Int {
|
|
&getReader_closure_0
|
|
}
|
|
|
|
// etc.
|
|
}
|
|
|
|
// New interfaces?
|
|
|
|
pub int ReadClosure(P : () = ())<D> -> T : fn (P) -> T {
|
|
ref fn getDelegate() -> Option<&D>
|
|
mut fn setDelegate(d: D) -> Void
|
|
fn call(...p: P) -> T
|
|
def op () alias call
|
|
}
|
|
|
|
pub int Iterator<T> {
|
|
mut fn next() -> Option<T>
|
|
}
|
|
|
|
pub int Iterable<T> : Into[Self<T>, Iterator<T>] {
|
|
ref fn iterator() -> Iterator<&T>
|
|
|
|
def cons fn intoIterator() = Into[Self, Iterator].into(self)
|
|
}
|
|
|
|
pub class MyIterable : Iterable<Int> {
|
|
fld items: List<Int> = [1, 2, 3]
|
|
|
|
impl ref fn iterator() -> Iterator<&Int> {
|
|
let mut index = 0
|
|
return mut {
|
|
if index >= items.length {
|
|
None
|
|
} else {
|
|
let next = items[index]
|
|
index++
|
|
Some(next)
|
|
}
|
|
}
|
|
}
|
|
} |