07e65a3a88e03c6d9e6f1f6ac4a1cfa9a74a9b09 — Simon Ser 2 months ago 1010c7a
parser/arithm: fix && and ||

"&" and "|" have higher priority, so they were consuming the first character of
"&&" and "||", leaving a trailing "&" or "|".
2 files changed, 30 insertions(+), 3 deletions(-)

M parser/arithm.c
M test/arithm.sh
M parser/arithm.c => parser/arithm.c +24 -1
@@ 304,6 304,29 @@ static struct mrsh_arithm_expr *equal(struct mrsh_parser *state) {
 	return &bo->expr;
 }
 
+static bool parse_binop(struct mrsh_parser *state, const char *str) {
+	size_t len = strlen(str);
+
+	for (size_t i = 0; i < len; ++i) {
+		parser_peek(state, NULL, i + 1);
+
+		if (state->buf.data[i] != str[i]) {
+			return false;
+		}
+	}
+
+	// Make sure we don't parse "&&" as "&"
+	parser_peek(state, NULL, len + 1);
+	switch (state->buf.data[len]) {
+	case '|':
+	case '&':
+		return false;
+	}
+
+	parser_read(state, NULL, len);
+	return true;
+}
+
 static struct mrsh_arithm_expr *binop(struct mrsh_parser *state,
 		enum mrsh_arithm_binop_type type, const char *str,
 		struct mrsh_arithm_expr *(*term)(struct mrsh_parser *state)) {


@@ 311,7 334,7 @@ static struct mrsh_arithm_expr *binop(struct mrsh_parser *state,
 	if (left == NULL) {
 		return NULL;
 	}
-	if (!parse_str(state, str)) {
+	if (!parse_binop(state, str)) {
 		return left;
 	}
 	consume_whitespace(state);

M test/arithm.sh => test/arithm.sh +6 -2
@@ 17,8 17,8 @@ echo "2!=5 =" $((2!=5))
 echo "2&5 =" $((2&5))
 echo "2^5 =" $((2^5))
 echo "2|5 =" $((2|5))
-#echo "2&&5 =" $((2&&5))
-#echo "2||5 =" $((2||5))
+echo "2&&5 =" $((2&&5))
+echo "2||5 =" $((2||5))
 
 # Associativity
 # https://github.com/emersion/mrsh/issues/53


@@ 27,6 27,10 @@ echo "1+2+3 =" $((1+2+3))
 echo "1+2*3 =" $((1+2*3))
 echo "2*3+1 =" $((2*3+1))
 #echo "2*(3+1) =" $((2*(3+1)))
+#echo "2|(1||1)" $((2|(1||1))) # 3
+#echo "(2|1)||1" $(((2|1)||1)) # 1
+echo "2|1||1" $((2|1||1)) # 1
+echo "1||1|2" $((1||1|2)) # 1
 
 # Assignments
 echo "(a=42) =" $((a=42)) "->" $a