mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 23:58:20 +00:00
Fix wrong output leading to incorrect tokenization of minus signs
When the tree has a unary minus node (NEG) whose child is a product node (*), and the left operand of the product node starts with a minus sign but is not a NEG node, this produced at least two minus signs in sequence without any spaces. Normally, OptSigns hides this problem, but when it is disabled, or when the left factor is a pre-decrement (--V) node, the problem is visible. Fix by creating a function that detects all kinds of leading minus signs, and use it in place of the comparison with NEG. Fixes #31. Reported by @KrsityKu, who also provided a repro.
This commit is contained in:
parent
0083da6b01
commit
d70c914738
4 changed files with 61 additions and 4 deletions
|
@ -194,6 +194,20 @@ class outscript(object):
|
||||||
return self.symtab[scope][node]['NewName']
|
return self.symtab[scope][node]['NewName']
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
def LeadMinus(self, node):
|
||||||
|
"""Tells whether a node starts with a minus sign"""
|
||||||
|
# TODO: This may add redundant parentheses around --V.
|
||||||
|
# More exactly, the line marked "!!!".
|
||||||
|
# They are necessary to prevent wrong output (---v instead of -(--v))
|
||||||
|
# but not always are they actually necessary. See regr/issue-31.lsl
|
||||||
|
return (node.nt == 'NEG'
|
||||||
|
or node.nt == '--V' # !!!
|
||||||
|
or not self.optsigns
|
||||||
|
and node.nt == 'CONST'
|
||||||
|
and node.t in {'integer', 'float'}
|
||||||
|
and copysign(1, node.value) == -1
|
||||||
|
)
|
||||||
|
|
||||||
def OutIndented(self, node):
|
def OutIndented(self, node):
|
||||||
if node.nt != '{}':
|
if node.nt != '{}':
|
||||||
self.indentlevel += 1
|
self.indentlevel += 1
|
||||||
|
@ -235,7 +249,9 @@ class outscript(object):
|
||||||
if lnt in self.op_priority:
|
if lnt in self.op_priority:
|
||||||
if self.op_priority[lnt] < base_pri:
|
if self.op_priority[lnt] < base_pri:
|
||||||
lparen = True
|
lparen = True
|
||||||
elif lnt == 'NEG' and base_pri > self.op_priority['-']:
|
elif (self.LeadMinus(child[0]) and base_pri >
|
||||||
|
self.op_priority['-']
|
||||||
|
):
|
||||||
lparen = True
|
lparen = True
|
||||||
|
|
||||||
# This situation has ugly cases due to the strange precedence
|
# This situation has ugly cases due to the strange precedence
|
||||||
|
@ -261,13 +277,17 @@ class outscript(object):
|
||||||
and lnode.nt not in ('~', '!')
|
and lnode.nt not in ('~', '!')
|
||||||
):
|
):
|
||||||
break
|
break
|
||||||
if lnode.nt == 'NEG' and base_pri > self.op_priority['-']:
|
if (self.LeadMinus(lnode) and base_pri >
|
||||||
|
self.op_priority['-']
|
||||||
|
):
|
||||||
lparen = True
|
lparen = True
|
||||||
|
|
||||||
if rnt in self.op_priority:
|
if rnt in self.op_priority:
|
||||||
if self.op_priority[rnt] <= base_pri:
|
if self.op_priority[rnt] <= base_pri:
|
||||||
rparen = True
|
rparen = True
|
||||||
elif rnt == 'NEG' and self.op_priority['-'] < base_pri:
|
elif (self.LeadMinus(child[1]) and self.op_priority['-'] <
|
||||||
|
base_pri
|
||||||
|
):
|
||||||
rparen = True
|
rparen = True
|
||||||
# see above
|
# see above
|
||||||
elif rnt in ('~', '!'):
|
elif rnt in ('~', '!'):
|
||||||
|
@ -278,7 +298,9 @@ class outscript(object):
|
||||||
lnode = lnode.ch[0]
|
lnode = lnode.ch[0]
|
||||||
if lnode.nt not in self.op_priority and lnode.nt not in ('~', '!'):
|
if lnode.nt not in self.op_priority and lnode.nt not in ('~', '!'):
|
||||||
break
|
break
|
||||||
if lnode.nt == 'NEG' and base_pri > self.op_priority['-']:
|
if (self.LeadMinus(lnode) and base_pri >
|
||||||
|
self.op_priority['-']
|
||||||
|
):
|
||||||
# TODO: Improve right operand parenthesis removal
|
# TODO: Improve right operand parenthesis removal
|
||||||
# for minus signs.
|
# for minus signs.
|
||||||
# Shouldn't this look into the RHS node?
|
# Shouldn't this look into the RHS node?
|
||||||
|
|
20
unit_tests/regression.suite/issue-31.lsl
Normal file
20
unit_tests/regression.suite/issue-31.lsl
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
default{timer(){
|
||||||
|
integer ia = llGetUnixTime();
|
||||||
|
integer ib = llGetUnixTime();
|
||||||
|
integer ic = -5;
|
||||||
|
integer id = ia*2;
|
||||||
|
integer ie = -ic*ia;
|
||||||
|
float fa = llGetTime();
|
||||||
|
float fb = llGetTime();
|
||||||
|
float fc = -5.5;
|
||||||
|
float fd = fa*2;
|
||||||
|
float fe = -fc*fa;
|
||||||
|
// FIXME: This is broken in the output module.
|
||||||
|
// The output should parenthesize the first two factors in the products,
|
||||||
|
// just as they are in the source. Fortunately they are equivalent.
|
||||||
|
// FIXME: The output is not optimal.
|
||||||
|
// It would suffice to add a space without parenthesizing the --ia,
|
||||||
|
// just like in the source.
|
||||||
|
llOwnerSay((string)[(- --ia*ib)*ib, (-++ia*ib)*ib, --ia*ib, ie]);
|
||||||
|
llOwnerSay((string)[(- --fa*fb)*fb, (-++fa*fb)*fb, --fa*fb, fe]);
|
||||||
|
}}
|
14
unit_tests/regression.suite/issue-31.out
Normal file
14
unit_tests/regression.suite/issue-31.out
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
default
|
||||||
|
{
|
||||||
|
timer()
|
||||||
|
{
|
||||||
|
integer ia = llGetUnixTime();
|
||||||
|
integer ib = llGetUnixTime();
|
||||||
|
integer ie = -(-5) * ia;
|
||||||
|
float fa = llGetTime();
|
||||||
|
float fb = llGetTime();
|
||||||
|
float fe = -(-5.5) * fa;
|
||||||
|
llOwnerSay((string)[-(--ia) * ib * ib, -++ia * ib * ib, (--ia) * ib, ie]);
|
||||||
|
llOwnerSay((string)[-(--fa) * fb * fb, -++fa * fb * fb, (--fa) * fb, fe]);
|
||||||
|
}
|
||||||
|
}
|
1
unit_tests/regression.suite/issue-31.run
Normal file
1
unit_tests/regression.suite/issue-31.run
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main.py -O -optsigns -
|
Loading…
Add table
Add a link
Reference in a new issue