Skip to content

v2.26.0 - Control-flow bodies no longer require braces

Choose a tag to compare

@gmpassos gmpassos released this 14 Aug 01:36
· 27 commits to master since this release
ce9676b

Control-flow bodies no longer require braces

for (var e in l) print('- $e'); is ordinary Dart, and it did not parse. Only
the plain if accepted an unbraced single-statement body — every loop, every
if/else and every else if demanded { }.

All seven remaining rules now accept either form, in Dart, Java 11, Kotlin,
C#, JavaScript and TypeScript
: for, for-in/for-each, while,
do/while, if/else, the else if chain, and the final else. A braced
body is still tried first, so nothing about existing sources changes.

singleLineStatement was also far too narrow — return …; or an expression
statement, nothing else — so even the if that already supported it rejected
if (x) break;, if (x) throw e; and a nested if. It is now each language's
full statement set minus declarations and bare blocks.

A dangling else binds to the nearest if, matching every target
language. Python gains the equivalent construct, the inline suite
(if x: return 1, def f(): pass, while c: i += 1; j += 1), at every
suite() position.

Go is deliberately excluded — its spec defines
Block = "{" StatementList "}" — and Lua has no such form. A single-statement
body translated to either is emitted braced / doend.

Not supported, on purpose: the empty statement as a body (while (c) ;),
for (;;), and ;-separated statements on an ordinary (non-suite) Python line.

A latent else-prefix miscompile, fixed first

BaseGrammarLexer.token() is a prefix matcher with no word-boundary guard, so
string('else') matches the start of an identifier like elseCount. That was
unreachable while every else arm followed a mandatory braced block, and would
have become a silent miscompile the moment bodies could be unbraced:

if (a) x();
elseCount = 1;   // `else` matches; `Count = 1;` becomes the else arm

The branch and loop rules of all six C-style grammars now use whole-word
keyword tokens. Also covers Kotlin's when entry labels and if expression.

New Dart syntax

  • Interpolation inside triple-quoted strings'''Hello $name''' yielded
    the literal text $name. Wrong output, not an error.
  • assert(c) / assert(c, m) as a real statement (it parsed as a call to a
    user function named assert). Each target emits its own idiom: Java
    assert c : m;, Python assert c, m, Kotlin assert(c) { m }, C#
    Debug.Assert, Lua's built-in, JS/TS/Go lowered to an explicit check. Wasm
    refuses to compile it rather than mis-compile it.
  • required named parameters on plain, constructor-typed and this.
    forms. ({required int a}) was a hard parse failure.
  • Annotations (@override, @Deprecated('x'), @pragma(...), @a.B(1))
    at every position Dart allows. There was no @ in any grammar in the repo,
    so a single @override broke the whole class body — which matters beyond
    hand-written sources, since lib/src/pub loads real pub packages. Parsed and
    discarded for now.
  • late on locals and fields (accepted and dropped).
  • const at use sites: const Foo(), const [], const {}.
  • Arrow and async bodies on local and anonymous functions.
  • catch (e, s) now binds the stack trace — it was parsed and thrown away,
    so any handler referencing s failed.
  • Compound assignment %= &= |= ^= <<= >>=.
  • Untyped getters (get twice => …) now parse.

Other fixes

  • Java and C#: if (a) {} else if (b) {} with no trailing else failed to
    parse — both made the final else non-optional, unlike every other language.
  • Python: a do/while translated to Python emitted literal
    do { … } while (c);. Now lowers to while True: … if not (c): break.
  • Lua: compound assignment was emitted verbatim (a += 1), which Lua does
    not have. Now lowers to a = a + 1.
  • const [1] silently misparsed as an index read on a variable named const.
  • set value(int v) {} silently became a method named value returning a
    type named set. Now a clean parse error at the set. Full setter support
    remains unimplemented.

Full changelog: https://github.com/ApolloVM/apollovm_dart/blob/v2.26.0/CHANGELOG.md