davidedc / livecodelab

a web based livecoding environment
http://livecodelab.net/
MIT License
327 stars 63 forks source link

V2langupdate #269

Closed rumblesan closed 7 years ago

rumblesan commented 8 years ago

So this PR has further improvements to the v2 version of the language.

There's still functionality that's missing though, but I don't think it's that much.

The two examples I've found so far

foo = (a, b) => time / (a + b)
scale time % 2, 1 rotate sin foo 10, 2 move box

which needs more parens with the V2 language

foo = (a, b) => time / (a + b)
scale time % 2, 1 rotate sin(foo(10, 2)) move box

Arrays using square brackets also don't work. I don't think we ever actually discussed whether we'd have arrays. The only example that has them is the DJ Castro homage demo. It shouldn't be too hard for me to add them in though I think.

I'd like to get this merged soonish as it's been sitting in a branch for a little while now.

davidedc commented 8 years ago

Hi Guy,

Could you try this on the a) demos b) tutorials and c) the test suite of the v1 lang?

It's not like a) b) c) are set in stone - if there are reasonable discrepancies that's not a problem, but it was very much needed to go through the motions with this branch before, as significant anomalies came up if I recall correctly.

So we cut on that back and forth, could give a) b) c) a shot and see what's the score there please?

rumblesan commented 8 years ago

sorry should have said what I'd tested. All demos and tutorials work, with the exception of the dj castro one mentioned.

haven't run the v1 lang test suite, (totally forgot about it) but have run all the tests in the v2 suite.

will get the v1 suite running and let you know

rumblesan commented 8 years ago

so running the testPreprocessor function from the console, all 300 tests pass. I think that only tests the old language though right?

I can't run the visual tests, seems that localhost:8080/tests.html isn't created any more? or I'm not running it right?

davidedc commented 8 years ago

sorry I meant: see how v2 handles the v1 tests (by copy-paste I guess). I remember I collected several cases that had problems back then in an email dated 2 Nov 2015 . Visual tests never really took off I think, they worked in some basic form but they need more manpower than we have.

P.S. arrays were also used in the paper, there were some examples of reduce and reduceRight which I thought would appeal the functional community. I wouldn't mind to lose them - just being specific about the references we have to arrays.

rumblesan commented 8 years ago

so I've got that email, are those the v1 tests you mean? I can't seem to find any other test cases in the repo. So the big issue with v2 at the moment is still that only specific functions can be inlined without parens. so from those tests in the email that use sin and wave they don't work the same in v2 as v1. I had a thought the other day, so I think I have a way of sorting it though. need to have a play.

cool cool with the arrays. tbh I don't think it would be that difficult to add them into v2. want to focus on the function stuff first though as that feels bigger

davidedc commented 8 years ago

yes those in the email are some picks from the 300 v1 test cases (the preprocessor ones you mentioned): worth checking more of them to see how v2 behaves, exactly because they were meant to explore interesting constructs, the ones in the email were just a few I tried.

so, to be crisp, what's going to happen to arrays, we are going to lose them when we merge v2 or are you going to add them? If we lose them, will it be possible to use something else in the example that uses them?

Before we merge, I think we should get more presentable error messages (unless you tweaked them recently, didn't try the latest changes yet), is that poz?

rumblesan commented 8 years ago

OK, question about expected behaviour for you @davidedc

how would you expect the following to work?

foo = (a) -> a + 3
bar = foo 1 + foo 2
rumblesan commented 8 years ago

btw, this isn't meant to be a trick question. I just want to make sure that we're both on the same page :)

rumblesan commented 8 years ago

Also I'm starting to copy examples from the preprocessor tests, but shit me there's a lot of them haha

davidedc commented 8 years ago

I'm didn't try this, I'm going to guess, I think given that there are no special keywords that this would be parsed the normal coffeescript way, i.e. Foo(1 + foo(2)). Might be wrong but that's my guess. Don't try all the tests... and many of those are insane :-) it's just trying the simpler tests that one can see gaps sometimes.

rumblesan commented 8 years ago

interesting, see I would have had it working the same as foo(1) + foo(2) with function application having higher precedence that addition. don't really mind either way, as long as we're consistent though :)

I'll try to pick a good chunk of the examples in that case. pretty sure plenty will be covered by the existing tests as well

rumblesan commented 8 years ago

hold up, when did we make times inlinable?

rumblesan commented 8 years ago

wow, turns out that getting the parser to inline times loops wasn't actually that hard! small mercies haha

rumblesan commented 8 years ago

ok, another question here scale 2, wave 2 peg

which functions block should peg end up in?

my feeling is that wave 2 is just an argument to scale and shouldn't have it's own inlined block. So this code should be equivalent to

scale 2, wave 2
    peg

if peg was in the block of wave then my feeling is that it wouldn't make sense for it to be affected by the scaling.

in which case, what's the difference between wave and scale as far as the language is concerned? Should every function allow inlining? or is it actually just certain functions? and how should that be decided?

rumblesan commented 8 years ago

also when did we make if statements inlinable?

rumblesan commented 8 years ago

right, hows this one for an awkward one?

foo(bar(3))
foo bar(3)

how should we be handling passing argument values to functions without parens? should the second line here work like the first? because currently the bar gets inlined, and the foo gets no arguments. Is that correct?

davidedc commented 8 years ago
rumblesan commented 8 years ago

Having it work as foo(1 + foo(2)) is fine by me, I just hadn't realised that's what was happening and wanted to make sure it wasn't a bug. "context where the amount of spaces would be relevant" I'm not sure I get what you mean by this.

OK, so we do only want shape, matrix and some colour (fill/stroke) functions to work as inlinable functions? That works for me, though it then raises the question of do we want the user to be able to create inlinable functions?

I feel that inlinable if statements are asking for things to get messy, not so much in the code for the parser, but in the LCL code that gets written. I'll always prefer minimal inlining though, so I'm not without bias.

So the last point, if we decide that only matrix, shape and colour functions are inlinable, then the foo foo(3) problem isn't an issue.

I think some of this boils down again to functions we expect to return a value, and functions that are only called for their side effects. Back to investigating type systems maybe? hahaha

rumblesan commented 8 years ago

right, I think I've actually got everything working as expected now. I've even added in the <box 3, 4> notation now. I'm calling it a lazy lambda, because we're kind of using it for lazy evaluation. One thing I wondered though, should it be inlinable? I seem to remember the following being something we wanted to do

bigger = <size 1.1>
rotate bigger box

if so, how is this meant to be different from

bigger = () => size 1.1
rotate bigger box

the latter won't work because whilst bigger is a function, only the usual functions (rotate, box, etc) can be inlined. Should the lazy lambda be a way of defining new inlinable functions?

davidedc commented 8 years ago

Yes that's right, I think we've put also the "ball above box" example in the paper.

rumblesan commented 8 years ago

Right, in which case I think that this is everything now. I need to double check and go back through all the examples and make sure they all work ok, and I've not had much time to look at the performance of the generated code, but I think that this now has everything except array/lists, and I have a lot of questions about how those should work first

rumblesan commented 8 years ago

ah, so there is an issue actually, it's pieces of code like this foo (1 + 2) * 3 the parser assumes that this is calling foo with the value of 1 + 2, and then multiplying the result by 3.

for for hilarity, have a think about how this should work foo(bar(1), 2) is that foo applied to 2 arguments which are the result of bar(1) and 2? or is it foo applied to one argument, which is the result of bar (1), 2?

davidedc commented 8 years ago

I see... the spacing is relevant between function and parens/first argument. At the moment those type of snags are sorted out by coffeescript. Here are some cases:

http://coffeescript.org/#try:foo%20(1%20%2B%202)%20*%203%0Afoo(1%20%2B%202)%20*%203%0Afoo(bar(1)%2C%202)%0Afoo%20-1%0Afoo%20-%201%0A

rumblesan commented 8 years ago

wait what? I never realised that coffee script worked that way.

to be honest I'm really not keen on that. my immediate feeling as a programmed is that it's horrible. My feeling from the POV of trying to make a simple, beginner friendly language is that it's also not great.

Do you feel strongly that it's good for it to work this way?

davidedc commented 8 years ago

If we want to avoid the parentheses (and I think we really do, for any arity), the ruby/coffeescript way seems handy...

...but I could live with foo (1 + 2) * 3 meaning foo(1 + 2) * 3

what other behaviours you foresee that are different from the current coffeescript-based implementation?

rumblesan commented 7 years ago

ok, so I've now managed to do away with parentheses when calling a function.

totally!

sort of

foo 1, 2, 3 will work anywhere, regardless of what the function is.

foo 1, bar 2, 3 is the same as foo(1, bar(2, 3))

if you want foo(1, bar(2), 3) then you need to use parens around the bar application to make it a specific expression. e.g. foo 1, (bar 2), 3

That seems like an ok trade off to me to be honest, and I think it's about the best we can get. thoughts?

rumblesan commented 7 years ago

ok, so I'm pushing up the commit that removes v1 of the language. at this point I think that v2 is feature complete and enough of an improvement to merge.

I'm not including the webpack build setup as part of this PR, but I'll raise a separate one for that

davidedc commented 7 years ago

Yes that's the idea, correct. Let me download and play with this today.