Rather than reproduce the broken behaviour, throw an error on missing default.

Changed my mind. This looks saner. Now, if the 'default:' label is missing, an error will be thrown by default. It has to be explicitly disabled if normal C-like behaviour is desired (namely to jump to the 'break' label if no condition is met).
This commit is contained in:
Sei Lisa 2016-05-07 02:38:54 +02:00
parent b1b84a123e
commit 697e80cb16
2 changed files with 19 additions and 16 deletions

View file

@ -148,6 +148,12 @@ class EParseManyDefaults(EParse):
super(EParseManyDefaults, self).__init__(parser,
u"multiple 'default' labels inside 'switch' statement")
class EParseMissingDefault(EParse):
def __init__(self, parser):
super(EParseMissingDefault, self).__init__(parser,
u"Missing 'default:' label inside 'switch' statement; disable"
u" option 'errmissingdefault' to disable this error.")
class EParseInvalidBreak(EParse):
def __init__(self, parser):
super(EParseInvalidBreak, self).__init__(parser,
@ -1674,15 +1680,15 @@ list lazy_list_set(list L, integer i, list v)
]})
if switchcasedefault is None:
warning("No 'default:' label in switch statement")
if self.brokennodefault:
warning("Broken behaviour active - falling through")
if not self.brokennodefault:
switchcasedefault = brk
self.breakstack[-1][2] = True
if switchcasedefault is not None:
prelude.append({'nt':'JUMP', 't':None, 'name':switchcasedefault,
'scope':blkscope})
if self.errmissingdefault:
raise EParseMissingDefault(self)
switchcasedefault = brk
self.breakstack[-1][2] = True
# TODO: Check if this JUMP is necessary
# (it won't be if the default label is the next instruction)
# This is arguably better done after DCR.
prelude.append({'nt':'JUMP', 't':None, 'name':switchcasedefault,
'scope':blkscope})
last = self.breakstack.pop()
if last[2]:
blk.append({'nt':'@', 'name':brk, 'scope':blkscope})
@ -2317,7 +2323,7 @@ list lazy_list_set(list L, integer i, list v)
self.keywords |= frozenset(('switch', 'case', 'break'))
# Broken behaviour in the absence of a default: label in a switch stmt.
self.brokennodefault = 'brokennodefault' in options
self.errmissingdefault = 'errmissingdefault' in options
# Allow brackets for assignment of list elements e.g. mylist[5]=4
self.lazylists = 'lazylists' in options

View file

@ -228,11 +228,6 @@ Optimizer options (+ means active by default, - means inactive by default):
will go to the last label with that name). This flag
works around that limitation by replacing the names of
the labels in the output with unique ones.
brokennodefault + Mimic Firestorm's legacy broken behaviour when the
'default' label in a switch statement is absent. Rather
than jumping to the end of the switch in that case
(which is how it behaves when this option is not set),
it falls through and executes the first 'case' label.
Deprecated / compatibility syntax extensions options:
@ -247,6 +242,8 @@ Optimizer options (+ means active by default, - means inactive by default):
Like lazylists, it's implemented for compatibility with
Firestorm, but not recommended. Note that the operand to
switch() may be evaluated more than once.
errmissingdefault + Throw an error in case the 'default:' label of a switch
statement is missing.
funcoverride - Allow duplicate function definitions to override the
previous definition. For compatibility with Firestorm's
optimizer.
@ -305,7 +302,7 @@ def main():
# Default options
options = set(('extendedglobalexpr','extendedtypecast','extendedassignment',
'allowkeyconcat','allowmultistrings','skippreproc','optimize',
'optsigns','optfloats','constfold','dcr', 'brokennodefault',
'optsigns','optfloats','constfold','dcr','errmissingdefault',
))
try: