aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Alexeyev <akari@taisei-project.org>2020-04-02 21:41:22 +0300
committerJussi Pakkanen <jpakkane@gmail.com>2020-04-04 13:31:07 +0300
commit2cfbb36a848d9a730a3318cec34789902ce27658 (patch)
tree603e3f15f21f25d527bdf90844ac862207a1554e
parentd84daf3e95742910a0e3165c479c0726dcbb40ef (diff)
downloadmeson-2cfbb36a848d9a730a3318cec34789902ce27658.zip
meson-2cfbb36a848d9a730a3318cec34789902ce27658.tar.gz
meson-2cfbb36a848d9a730a3318cec34789902ce27658.tar.bz2
mparser: fix precedence of arithmetic operators
The arithmetic operators are now split into two groups: * The add/sub group: +, - * The mul/div group: *, /, % All operators within the same group are left-associative and have equal precedence. The mul/div group has a higher precedence than the add/sub group, as one would expect. Previously every operator had a different precedence and was right-associative, which resulted in surprising behavior. This is a potentially breaking change for projects that relied on the old incorrect behavior. Fixes #6870
-rw-r--r--mesonbuild/mparser.py60
-rw-r--r--test cases/common/230 arithmetic operators/meson.build8
2 files changed, 41 insertions, 27 deletions
diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py
index 8753b40..2cffc47 100644
--- a/mesonbuild/mparser.py
+++ b/mesonbuild/mparser.py
@@ -489,6 +489,13 @@ class Parser:
return True
return False
+ def accept_any(self, tids: T.Sequence[str]) -> str:
+ tid = self.current.tid
+ if tid in tids:
+ self.getsym()
+ return tid
+ return ''
+
def expect(self, s: str) -> bool:
if self.accept(s):
return True
@@ -562,36 +569,35 @@ class Parser:
return left
def e5(self) -> BaseNode:
- return self.e5add()
-
- def e5add(self) -> BaseNode:
- left = self.e5sub()
- if self.accept('plus'):
- return ArithmeticNode('add', left, self.e5add())
- return left
-
- def e5sub(self) -> BaseNode:
- left = self.e5mod()
- if self.accept('dash'):
- return ArithmeticNode('sub', left, self.e5sub())
- return left
-
- def e5mod(self) -> BaseNode:
- left = self.e5mul()
- if self.accept('percent'):
- return ArithmeticNode('mod', left, self.e5mod())
- return left
-
- def e5mul(self) -> BaseNode:
- left = self.e5div()
- if self.accept('star'):
- return ArithmeticNode('mul', left, self.e5mul())
+ return self.e5addsub()
+
+ def e5addsub(self) -> BaseNode:
+ op_map = {
+ 'plus': 'add',
+ 'dash': 'sub',
+ }
+ left = self.e5muldiv()
+ while True:
+ op = self.accept_any(tuple(op_map.keys()))
+ if op:
+ left = ArithmeticNode(op_map[op], left, self.e5muldiv())
+ else:
+ break
return left
- def e5div(self) -> BaseNode:
+ def e5muldiv(self) -> BaseNode:
+ op_map = {
+ 'percent': 'mod',
+ 'star': 'mul',
+ 'fslash': 'div',
+ }
left = self.e6()
- if self.accept('fslash'):
- return ArithmeticNode('div', left, self.e5div())
+ while True:
+ op = self.accept_any(tuple(op_map.keys()))
+ if op:
+ left = ArithmeticNode(op_map[op], left, self.e6())
+ else:
+ break
return left
def e6(self) -> BaseNode:
diff --git a/test cases/common/230 arithmetic operators/meson.build b/test cases/common/230 arithmetic operators/meson.build
new file mode 100644
index 0000000..a904bd0
--- /dev/null
+++ b/test cases/common/230 arithmetic operators/meson.build
@@ -0,0 +1,8 @@
+project('arithmetic operators')
+assert(5 - 3 - 1 == 1)
+assert(5 - (3 - 1) == 3)
+assert(5 - 1 * 3 - 3 == -1)
+assert(420 - 300 - 51 == 69)
+assert(1000 / 2 / 2 / 2 == 125)
+assert(4 * 9 / 3 % 8 - 3 - 10 / 2 == -4)
+assert(94 - 30 + (2 - (40 - 6 + 7) - 9) - 10 == 6)