rokucommunity / rokucommunity/brighterscript

Add closure support

Open
#530 10 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
TypeScript
Stars
208
Forks
68
Avg merge
8h 39m
Merged PRs (30d)
39

Description

BrighterScript should support closures.

Here's a quick example:

sub onButtonClick(event)
    response = "" 'gets set by closure below

    checkEmail = (domain) => {
        inputValue = m.emailAddressTextEditBox.text
        if inputValue.endsWith(domain) then
            response ="valid"
        else
            response = "invalid"
        end if
    }

    checkEmail("@roku.com")

    return responseMessage
end sub

would transpile to:

sub onButtonClick(event)
    local = {
        event: event
    }
    local.response = "" 'gets set by closure below

    local.checkEmail = {
        type: "arrow-function",
        scopes: [local],
        m: m,
        func: function(__closure, domain)
            inputValue = __closure.m.emailAddressTextEditBox.text
            if inputValue.endsWith(domain) then
                __closure.scopes[0].response ="valid email"
            else
                __closure.scopes[0].response = "invalid email"
            end if
        end function
    }

    local.checkEmail.func(local.checkEmail, "@roku.com")
    
    return responseMessage
end sub

Considerations:

  1. the moment a closure is created, we force all local variables onto an AA, and there are no longer any true local variables. This allows the "local" scope to get "captured" and flow through any child closures
  2. since a closure needs type tracking, this can only be implemented in the alpha branch.
  3. Add a ArrowFunction interface type which can be used as function parameters and other types.
    sub Validate(validationFunction as ArrowFunction)
        validationFunction() 'transpiles to validationFunction.func(validationFunction)
    end sub
    
  4. In the initial release, we will restrict closures from being passed into any parameter/assignment not explicitly marked as ArrowFunction
    sub main()
        arrowFunc = () => { return true }
        name = "bob"
        name = arrowFunc' ERROR: arrow function cannot be assigned to non-closure existing variable
        logInfo(arrowFunc) 'ERROR: arrow function cannot be passed as parameter not explicitly marked as `ArrowFunction`
        callArrowFunc(arrowFunc) ' OK 
        arrowFunc = ()=> {return false} ' OK since previous var was also an arrow function
    end sub
    sub logInfo(anything as dynamic)
        print anything
    end sub
    sub callArrowFunc(func as ArrowFunction)
        func()
    end sub
    
  5. Nested closures should be supported. For example:
    sub onButtonClick(event)
        outerName = "outer"
        outerFunc = () =>{
            innerName = "inner"
            print outerName
            innerFunc = () => {
                print outerName; innerName
            }
            innerFunc()
        }
        outerFunc()
    end sub
    
    transpiles to:
    sub onButtonClick(event)
        local = {
            event: event
        }
        local.outerName = "outer"
        local.outerFunc = {
            scopes: [local],
            m: m,
            func: function(__closure)
                local = {}
                local.innerName = "inner"
                print __closure.scopes[0].outerName
                local.innerFunc = {
                    scopes: [__closure.scopes[0], local]
                    m: __closure.scopes[0], 
                    func: function(__closure)
                        print __closure.scopes[0].outerName; __closure.scopes[0].innerName
                    end function
                end function
                local.innerFunc.func(local.innerFunc)
            end func
        }
        local.outerFunc.func(local.outerFunc)
    end sub
    

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No implementation files or tests are named. Start on the alpha branch by locating the parser, type-tracking, and transpilation entry points, then compare their current behavior with the closure examples in this issue. Done means supporting captured and nested closures, ArrowFunction typing, and the stated assignment and parameter restrictions.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.