Skip to content

Commit

Permalink
Use {} for empty if and else blocks
Browse files Browse the repository at this point in the history
Fixes #1244
  • Loading branch information
edemaine committed May 11, 2024
1 parent c191141 commit bbe3b4a
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 26 deletions.
51 changes: 34 additions & 17 deletions source/parser.hera
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
hasAwait,
hasYield,
insertTrimmingSpace,
isEmptyBareBlock,
isWhitespaceOrEmpty,
lastAccessInCallExpression,
literalValue,
Expand Down Expand Up @@ -250,12 +249,15 @@ StatementExpression
IfStatement ->
// Forbid expressionizing `if condition` with no then or else clause,
// because it might be a postfix `if`
if (!$1.else && isEmptyBareBlock($1.then)) return $skip
if (!$1.else && $1.then.implicit) return $skip
return $1
IterationExpression ->
// Forbid expressionizing `while condition` with no block,
// because it might be a postfix `while`
if (isEmptyBareBlock($1.block)) return $skip
// But allow empty `do` and `comptime` which can't be postfix
if ($1.block.implicit && $1.subtype !== "DoStatement" && $1.subtype !== "ComptimeStatement") {
return $skip
}
return $1
SwitchStatement
ThrowStatement
Expand Down Expand Up @@ -335,7 +337,7 @@ ForbiddenImplicitCalls
OmittedNegation _? Identifier:id ->
if (state.operators.has(id.name)) return $0
return $skip
PostfixStatement EmptyStatementBareBlock
PostfixStatement NoBlock
# `x ... y` is reserved for a range, but `x ...y` is an implicit call
"... "

Expand Down Expand Up @@ -2444,36 +2446,51 @@ EmptyBlock
children: [$1, expressions, $2],
bare: false,
empty: true,
implicit: true,
}

# NOTE: We allow loop bodies to be empty, in which case they get a ; body
BlockOrEmptyStatement
Block
NoBlock EmptyStatementBareBlock -> $2

# NOTE: We allow if/else bodies to be empty, in which case they get a {} body
# (`;` would also make sense, but TypeScript doesn't allow them.)
BlockOrEmpty
Block
EmptyStatementBareBlock
NoBlock EmptyBlock -> $2

EmptyBareBlock
# Implied empty block with no braces. Used in case statements.
"" ->
const expressions = []
EmptyStatementBareBlock
# Implied empty block with empty statement (;). Used for empty loop bodies.
InsertEmptyStatement:s ->
const expressions = [["", s]]
return {
type: "BlockStatement",
expressions,
children: [expressions],
bare: true,
empty: true,
implicit: true,
semicolon: s.children[0],
}

EmptyStatementBareBlock
# Implied empty block with empty statement (;). Used for empty loop bodies.
&EOS !IndentedFurther InsertEmptyStatement:s ->
const expressions = [["", s]]
EmptyBareBlock
# Implied empty block with no braces. Used in case statements.
"" ->
const expressions = []
return {
type: "BlockStatement",
expressions,
children: [expressions],
bare: true,
semicolon: s.children[0],
empty: true,
implicit: true,
}

NoBlock
# Check that there isn't a block here. Used for empty loop bodies.
&EOS !IndentedFurther

# A nonempty block that must include braces
# This version allows same-line postfixes like `while cond`.
BracedBlock
Expand Down Expand Up @@ -4066,7 +4083,7 @@ IterationExpression

# NOTE: Added from CoffeeScript
LoopStatement
LoopClause:clause BlockOrEmpty:block ->
LoopClause:clause BlockOrEmptyStatement:block ->
return {
...clause,
type: "IterationStatement",
Expand Down Expand Up @@ -4131,7 +4148,7 @@ ComptimeStatement
# https://262.ecma-international.org/#prod-WhileStatement
WhileStatement
# NOTE: Condition provides optional parens
WhileClause:clause BlockOrEmpty:block ->
WhileClause:clause BlockOrEmptyStatement:block ->
return {
...clause,
children: [...clause.children, block],
Expand All @@ -4157,7 +4174,7 @@ WhileClause
# https://262.ecma-international.org/#prod-ForInOfStatement
# NOTE: Merged into single rule
ForStatement
ForClause:clause BlockOrEmpty:block ->
ForClause:clause BlockOrEmptyStatement:block ->
block = blockWithPrefix(clause.blockPrefix, block)

return {
Expand Down
2 changes: 2 additions & 0 deletions source/parser/types.civet
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ export type BlockStatement =
children: Children
expressions: StatementTuple[]
bare: boolean // has no braces
empty?: boolean // empty block
implicit?: boolean // implicit empty block
implicitlyReturned?: boolean // fat arrow function with no braces
root?: boolean
parent?: Parent
Expand Down
8 changes: 8 additions & 0 deletions test/do.civet
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ describe "do", ->
{}
"""

testCase """
empty assigned
---
x = do
---
let ref;{ref = void 0;};x = ref
"""

testCase """
expression
---
Expand Down
18 changes: 9 additions & 9 deletions test/if.civet
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe "if", ->
---
if x
---
if (x);
if (x) {}
"""

testCase """
Expand All @@ -66,7 +66,7 @@ describe "if", ->
if x
else console.log 'no'
---
if (x);
if (x) {}
else console.log('no')
"""

Expand All @@ -80,7 +80,7 @@ describe "if", ->
if (x) {
console.log('yes')
}
else;
else {}
"""

testCase """
Expand All @@ -89,8 +89,8 @@ describe "if", ->
if x
else
---
if (x);
else;
if (x) {}
else {}
"""

testCase """
Expand All @@ -101,9 +101,9 @@ describe "if", ->
else
// no
---
if (x);
if (x) {}
// yes
else;
else {}
// no
"""

Expand All @@ -115,7 +115,7 @@ describe "if", ->
else
console.log 'no'
---
if (x);
if (x) {}
// yes
else {
console.log('no')
Expand Down Expand Up @@ -230,7 +230,7 @@ describe "if", ->
---
if x then
---
if (x);
if (x) {}
"""

testCase """
Expand Down

0 comments on commit bbe3b4a

Please sign in to comment.