JoeStrout / miniscript

source code of both C# and C++ implementations of the MiniScript scripting language
MIT License
280 stars 64 forks source link

Proposal: Function definitions as expressions #100

Open juh9870 opened 1 year ago

juh9870 commented 1 year ago

Currently, function definitions are statements. They might look like expressions, but that's an illusion. Here is an example:

funA = function(a,b)
  return a + b
end function

While it may seem like we are creating a function during the assignment, it's actually parsed as an assignment funA = function(a,b) and remembers that function was created and must be closed, so then it proceeds to parse the rest of the function declaration independently of the function declaration.

This behavior is very confusing, and can lead to some extremely unconventional code like

arr = [1, 2, function(b,c), 3, 4]
  return b + c
end function

This looks terrible and is actually quite confusing. Is 3, 4 part of a body? It seems so, but actually, it isn't, they are part of an array that the function is written into.

I suggest treating function declaration as one large expression, for example:

register({
  "on:click": function(e); e.doSomething(); end function,
  "on:scroll": function(e); e.doSomethingElse(); end function
})

Notice how we have ; inside an expression, but they are parsed as a function body, and so the overall expression remains valid

This change does not break any old syntax (except for the buggy example I have shown earlier), and only reduces the amount of "magic" happening during the parsing

Additionally, it may be worth addressing an issue that causes a function to have missing outer bindings if it's directly passed as an argument to some other function, instead of being written into a variable first:

callWith5 = function(cb)
    return cb(5)
end function

parent = function(a)
    callWith5 function(b)
        print outer.a + b
    end function
end function

parent(5) // should print 10, but instead throws an error about missing `a`