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, super(EParseManyDefaults, self).__init__(parser,
u"multiple 'default' labels inside 'switch' statement") 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): class EParseInvalidBreak(EParse):
def __init__(self, parser): def __init__(self, parser):
super(EParseInvalidBreak, self).__init__(parser, super(EParseInvalidBreak, self).__init__(parser,
@ -1674,15 +1680,15 @@ list lazy_list_set(list L, integer i, list v)
]}) ]})
if switchcasedefault is None: if switchcasedefault is None:
warning("No 'default:' label in switch statement") if self.errmissingdefault:
if self.brokennodefault: raise EParseMissingDefault(self)
warning("Broken behaviour active - falling through") switchcasedefault = brk
if not self.brokennodefault: self.breakstack[-1][2] = True
switchcasedefault = brk # TODO: Check if this JUMP is necessary
self.breakstack[-1][2] = True # (it won't be if the default label is the next instruction)
if switchcasedefault is not None: # This is arguably better done after DCR.
prelude.append({'nt':'JUMP', 't':None, 'name':switchcasedefault, prelude.append({'nt':'JUMP', 't':None, 'name':switchcasedefault,
'scope':blkscope}) 'scope':blkscope})
last = self.breakstack.pop() last = self.breakstack.pop()
if last[2]: if last[2]:
blk.append({'nt':'@', 'name':brk, 'scope':blkscope}) 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')) self.keywords |= frozenset(('switch', 'case', 'break'))
# Broken behaviour in the absence of a default: label in a switch stmt. # 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 # Allow brackets for assignment of list elements e.g. mylist[5]=4
self.lazylists = 'lazylists' in options 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 will go to the last label with that name). This flag
works around that limitation by replacing the names of works around that limitation by replacing the names of
the labels in the output with unique ones. 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: 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 Like lazylists, it's implemented for compatibility with
Firestorm, but not recommended. Note that the operand to Firestorm, but not recommended. Note that the operand to
switch() may be evaluated more than once. 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 funcoverride - Allow duplicate function definitions to override the
previous definition. For compatibility with Firestorm's previous definition. For compatibility with Firestorm's
optimizer. optimizer.
@ -305,7 +302,7 @@ def main():
# Default options # Default options
options = set(('extendedglobalexpr','extendedtypecast','extendedassignment', options = set(('extendedglobalexpr','extendedtypecast','extendedassignment',
'allowkeyconcat','allowmultistrings','skippreproc','optimize', 'allowkeyconcat','allowmultistrings','skippreproc','optimize',
'optsigns','optfloats','constfold','dcr', 'brokennodefault', 'optsigns','optfloats','constfold','dcr','errmissingdefault',
)) ))
try: try: