diff options
author | Andrei Alexeyev <akari@taisei-project.org> | 2020-04-02 21:41:22 +0300 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2020-04-04 13:31:07 +0300 |
commit | 2cfbb36a848d9a730a3318cec34789902ce27658 (patch) | |
tree | 603e3f15f21f25d527bdf90844ac862207a1554e | |
parent | d84daf3e95742910a0e3165c479c0726dcbb40ef (diff) | |
download | meson-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.py | 60 | ||||
-rw-r--r-- | test cases/common/230 arithmetic operators/meson.build | 8 |
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) |