VoltLang / Volta

Compiler for the Volt Programming Language
151 stars 8 forks source link

[WIP] Support `do {...};` for breakable/restartable blocks #20

Closed ntrel closed 7 years ago

ntrel commented 8 years ago

For rationale, please see changes.md.

Warning: I'm in the process of building LLVM on Windows, so haven't linked Volta yet but my changes do at least compile.

ntrel commented 8 years ago

LLVM autotools build won't start, paths aren't set properly. I suppose I'll have to try cmake.

bhelyer commented 8 years ago

//T has-passed:no indicates that the test is failing, but it's known to fail, so it shouldn't be marked as a regression.

The test suite is very easy to run. From the Tesla root, volt -o runner src/*.volt ./runner Tesla expects the environmental variable VOLT to be set to the compiler.executable you want to test.

ntrel commented 8 years ago

Thanks, added //T has-passed:yes. So do.volt should be integrated with Tesla, I'll look into it. Having a lot of trouble getting LLVM to build on Windows even with cmake. Does it require clang and Visual Studio?

bhelyer commented 8 years ago

Don't bother adding has-passed:yes, that's assumed if the has-passed line isn't present.

It doesn't require clang, but it does need Visual Studio. (Or you can use cygwin and autotools). I've got some windows stuff I've been wanting to do myself, and I built LLVM, but I haven't sat down and put all the pieces together yet, so I'm afraid I can't be too helpful. Make sure your cmake is up to date, and that you're launching cmake (or cmake-gui) from the Visual Studio tools command prompt.

Wallbraker commented 8 years ago

Thanks for your pull request! :D Getting a working setup on windows is hard, maybe we should look into how other D based projects handles LLVM. Maybe getting Volta compiling with dub?

With regards to the pull requests itself.

The goal is to get a block statement that continue and break works in with very little syntax.

for (;true;) { ... }
while (true) { ... }
do { ... } while(true);

All of these gives the same thing, a spinning loop you can break out of. If we where to improve the syntax for spinning loop we get.

for { ... }
while { ... }
do { ... };

Personally I don't like the do syntax, we get sequence of }; at the end which is not in the language anywhere, and can be confused with do { ... }; while ();. The while loop on the other hand does not have that problem.

The while and for are also simpler to implement in the parser, as its just a case if inserting a true expression in the right place. The change you did for the implicit adding of break should probably be done in the cfg module instead.

Taking a further step back and looking at what we want to add into the language we might want to go a completely different route. By instead adding label blocks or labeled for/while/do statements.

foo: do {
    if (condition) {
        break foo; // Breaks out of foo, can break out of nested for/while/do/foreach statements.
    }
    continue; // Unspecified jcontinue/breaks jumps to the nearest.
} while(false);

Going from this syntax we get (this is just spit balling ideas):

// If we only had labled for/while statements getting breakable statements
// this is what we should write.
longform: do { ... } while (false);
// But we could shorten it.
shortform: { ... }

// But we can go even futher.
:{ ... }

We can easily implement the anon form completely in the parser by just expanding it into do { ... } while(false); and we wouldn't need to modify the rest of the compiler.

ntrel commented 8 years ago

Don't bother adding has-passed:yes, that's assumed if the has-passed line isn't present.

OK. Maybe we should remove the Volta/test directory in favour of Tesla.

It doesn't require clang, but it does need Visual Studio

OK, I'll keep trying to build LLVM.

Thanks for looking at this. I thought this PR might be a simple place to start but no worries if it gets rejected.

I don't like the do syntax, we get sequence of }; ... and can be confused with do { ... }; while ();.

Maybe, but in D the empty statement after while would cause an error, requiring {} instead.

The while loop on the other hand does not have that problem.

Yes, but I'm not sure it could implicitly break at the end, that might be unexpected. But while {...} could require break/continue as the last statement.

The change you did for the implicit adding of break should probably be done in the cfg module instead.

OK, I'll take a look.

:{ ... }

Maybe, but a single character changing the semantics of break[/continue] might be considered bad. It's a little cryptic - how do you google :{...}?

One option for breaks without labels could be scope break;.

ntrel commented 7 years ago

@ntrel:

while {...} could require break/continue as the last statement.

I was trying to unite infinite loops and breakable blocks with one construct with this PR, but perhaps it's better to separate them:

ntrel commented 7 years ago

One more idea, building on for { - endiscourage* do ... while (cond); in favour of:

for {
  ...
  continue if (cond);
}

continue if is more general than do ... while as continue if can appear in an if block too (e.g. for use here). Also the syntax is cleaner, ending on a }. It's also better for refactoring - if you don't want to test cond at the start of the loop, always write for {, no switching between infinite loops + break and do ... while whilst working on the code.

*We could allow do...while only in C/D compatibility mode.