alanrgan / rust-interpreter

0 stars 0 forks source link

Anchoring and Hoist #1

Open alanrgan opened 7 years ago

alanrgan commented 7 years ago

Anchor and Hoist

Anchor extends the value of an expression into a global 'anchor scope' from which these values can then be taken. Hoisting takes these values from the anchor scope either by name or by popping off a stack.

Syntax

anchor [ident :] expression
hoist ident

anchor is a statement hoist is an expression

Example

fn some_func() : int {
     let x: int = 5;
     anchor val: x; // named anchor
     anchor 4; // unnamed anchor, expression is pushed onto a stack
     return 3;
}

fn func2() {
    let y: int = hoist val;
}

fn main() {
    print(some_func()) // prints 3
    print(hoist val); // prints 5
    print(hoist); // prints 4
    let z: int = hoist val; // invalid, runtime error
}

Motivation

Anchors allow internal values or state from a function to be passed back into the calling function without interrupting the normal control flow. Conceptually it is like having multiple return types that are not bound to the function call itself.

Concerns

Hoisting should return an Option<T>, and hoisting a value that does not exist in a scope should return Nil.

alanrgan commented 7 years ago

How will anchors to the same identifier be handled? Anchors should act as a contract between a function and the caller. A function should guarantee that an anchored value is available directly after a call.

fn callback() {
    anchor bar: 300;
}

fn foo(cb: Func<_,_>) {
     let x: int = 5;
     anchor bar: x;
     cb(); // cannot assume that bar is not overwritten by the callback
}

One way to resolve this is to bind anchored values to the function that anchored it:

hoist foo::bar; // hoisting named value from function foo
hoist foo; // hoist unnamed value from foo
hoist ::bar; // hoist bar from current function scope
hoist; // hoist unnamed value from current function scope

So the above example can be mitigated:

fn callback() {
    anchor bar: 300;
}

fn foo(cb: Func<_,_>) {
     let x: int = 5;
     anchor bar: x;
     cb(); // cannot assume that bar is not overwritten by the callback
     // should be able use either cb::bar or callback::bar here
     // assert(hoist cb::bar, 300)
}

fn main() : int {
     foo(callback);
     assert(hoist ::bar, 5);
     assert(hoist callback::bar, 300);
}