mirror of
https://github.com/stedolan/jq.git
synced 2024-05-11 05:55:39 +00:00
Resolve shift/reduce conflict of 'def' vs '|'
This was an important conflict. In the following expression:
def a: 0; . | a
Bison needs to decide between these two equally valid
parses:
(def a: 0; .) | a
def a: 0; (. | a)
For jq we want the second one, because the first results in
"a/0 is not defined". In the current parser the first parse
is a reduce and the second parse is a shift. Since Bison
prefers to shift in shift/reduce conflicts, we accidentally
got the correct behavior.
This commit adds a precedence level FUNCDEF which is lower
precedence than '|', meaning we explicitly choose the
correct parse.
Of course many unit tests already cover this case, but I
added one specifically for it.
This commit is contained in:
6
parser.h
6
parser.h
@@ -105,7 +105,8 @@ struct lexer_param;
|
|||||||
QQSTRING_TEXT = 296,
|
QQSTRING_TEXT = 296,
|
||||||
QQSTRING_INTERP_START = 297,
|
QQSTRING_INTERP_START = 297,
|
||||||
QQSTRING_INTERP_END = 298,
|
QQSTRING_INTERP_END = 298,
|
||||||
QQSTRING_END = 299
|
QQSTRING_END = 299,
|
||||||
|
FUNCDEF = 300
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
/* Tokens. */
|
/* Tokens. */
|
||||||
@@ -151,6 +152,7 @@ struct lexer_param;
|
|||||||
#define QQSTRING_INTERP_START 297
|
#define QQSTRING_INTERP_START 297
|
||||||
#define QQSTRING_INTERP_END 298
|
#define QQSTRING_INTERP_END 298
|
||||||
#define QQSTRING_END 299
|
#define QQSTRING_END 299
|
||||||
|
#define FUNCDEF 300
|
||||||
|
|
||||||
/* Value type. */
|
/* Value type. */
|
||||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||||
@@ -162,7 +164,7 @@ union YYSTYPE
|
|||||||
jv literal;
|
jv literal;
|
||||||
block blk;
|
block blk;
|
||||||
|
|
||||||
#line 166 "parser.h" /* yacc.c:1909 */
|
#line 168 "parser.h" /* yacc.c:1909 */
|
||||||
};
|
};
|
||||||
# define YYSTYPE_IS_TRIVIAL 1
|
# define YYSTYPE_IS_TRIVIAL 1
|
||||||
# define YYSTYPE_IS_DECLARED 1
|
# define YYSTYPE_IS_DECLARED 1
|
||||||
|
|||||||
5
parser.y
5
parser.y
@@ -91,8 +91,9 @@ struct lexer_param;
|
|||||||
%token QQSTRING_END
|
%token QQSTRING_END
|
||||||
|
|
||||||
/* see Exp '?' rule */
|
/* see Exp '?' rule */
|
||||||
%expect 34
|
%expect 9
|
||||||
|
|
||||||
|
%precedence FUNCDEF
|
||||||
%right '|'
|
%right '|'
|
||||||
%left ','
|
%left ','
|
||||||
%right "//"
|
%right "//"
|
||||||
@@ -306,7 +307,7 @@ FuncDef FuncDefs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Exp:
|
Exp:
|
||||||
FuncDef Exp %prec ';' {
|
FuncDef Exp %prec FUNCDEF {
|
||||||
$$ = block_bind_referenced($1, $2, OP_IS_CALL_PSEUDO);
|
$$ = block_bind_referenced($1, $2, OP_IS_CALL_PSEUDO);
|
||||||
} |
|
} |
|
||||||
|
|
||||||
|
|||||||
@@ -553,6 +553,11 @@ def f(a;b;c;d;e;f): [a+1,b,c,d,e,f]; f(.[0];.[1];.[0];.[0];.[0];.[0])
|
|||||||
[1,2]
|
[1,2]
|
||||||
[2,2,1,1,1,1]
|
[2,2,1,1,1,1]
|
||||||
|
|
||||||
|
# Test precedence of 'def' vs '|'
|
||||||
|
def a: 0; . | a
|
||||||
|
null
|
||||||
|
0
|
||||||
|
|
||||||
# Many arguments
|
# Many arguments
|
||||||
def f(a;b;c;d;e;f;g;h;i;j): [j,i,h,g,f,e,d,c,b,a]; f(.[0];.[1];.[2];.[3];.[4];.[5];.[6];.[7];.[8];.[9])
|
def f(a;b;c;d;e;f;g;h;i;j): [j,i,h,g,f,e,d,c,b,a]; f(.[0];.[1];.[2];.[3];.[4];.[5];.[6];.[7];.[8];.[9])
|
||||||
[0,1,2,3,4,5,6,7,8,9]
|
[0,1,2,3,4,5,6,7,8,9]
|
||||||
|
|||||||
Reference in New Issue
Block a user