Skip to content

Commit 8b6dd68

Browse files
committed
fix(parser): correct operator precedence for unary expressions
1 parent d5b629c commit 8b6dd68

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

src/parser.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,18 @@ test("parse: operator precedence", () => {
108108

109109
// 比较运算符优先级
110110
expect(generate(parse("a + b < c + d"))).toBe("a+b<c+d");
111+
112+
// 逻辑非 ! 优先于逻辑与 &&
113+
expect(generate(parse("!(a && b)"))).toBe("!(a&&b)");
114+
expect(generate(parse("!a && b"))).toBe("(!a)&&b");
115+
116+
// 逻辑非 ! 优先于逻辑或 ||
117+
expect(generate(parse("!(a || b)"))).toBe("!(a||b)");
118+
expect(generate(parse("!a || b"))).toBe("(!a)||b");
119+
120+
// 多个逻辑非
121+
expect(generate(parse("!!a"))).toBe("!!a");
122+
expect(generate(parse("!a && !b"))).toBe("(!a)&&(!b)");
111123
});
112124

113125
test("parse: right associativity", () => {

src/parser.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,11 +807,23 @@ function needsParens(child: ASTNode, parent: ASTNode, position: string): boolean
807807
}
808808
}
809809

810-
// 一元表达式作为二元表达式右侧且运算符是 ** 时需要括号
810+
// 二元表达式或条件表达式作为一元表达式的参数时需要括号
811+
if (
812+
(child.type === "BinaryExpr" || child.type === "ConditionalExpr") &&
813+
parent.type === "UnaryExpr" &&
814+
position === "argument"
815+
) {
816+
return true;
817+
}
818+
819+
// 一元表达式作为二元表达式的操作数时需要括号(为了保持原有的语义清晰)
811820
if (child.type === "UnaryExpr" && parent.type === "BinaryExpr") {
821+
// ** 运算符左侧不能有一元表达式
812822
if (parent.operator === "**" && position === "left") {
813823
return true;
814824
}
825+
// 逻辑运算符、位运算符等需要明确一元表达式的边界
826+
return true;
815827
}
816828

817829
return false;

0 commit comments

Comments
 (0)