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)
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| } | 
