@@ -51,7 +51,7 @@ static ListNode parseZeroOrOneList(Parser parser, int minItems) {
5151 if (expr .elements .size () > 1 ) {
5252 parser .throwError ("syntax error" );
5353 }
54- } else if (token .type == LexerTokenType .EOF || ParserTables . LIST_TERMINATORS . contains ( token . text ) || token .text .equals ("," )) {
54+ } else if (token .type == LexerTokenType .EOF || isListTerminator ( parser , token ) || token .text .equals ("," )) {
5555 // No argument
5656 expr = new ListNode (parser .tokenIndex );
5757 } else {
@@ -105,7 +105,7 @@ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlo
105105 // Check for infix operators after the regex (like . for concatenation)
106106 while (true ) {
107107 token = TokenUtils .peek (parser );
108- if (token .type == LexerTokenType .EOF || ParserTables . LIST_TERMINATORS . contains ( token . text )) {
108+ if (token .type == LexerTokenType .EOF || isListTerminator ( parser , token )) {
109109 break ;
110110 }
111111 int tokenPrecedence = parser .getPrecedence (token .text );
@@ -122,7 +122,7 @@ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlo
122122
123123 expr .elements .add (left );
124124 token = TokenUtils .peek (parser );
125- if (token .type != LexerTokenType .EOF && !ParserTables . LIST_TERMINATORS . contains ( token . text )) {
125+ if (token .type != LexerTokenType .EOF && !isListTerminator ( parser , token )) {
126126 // Consume comma
127127 PrototypeArgs .consumeCommaIfPresent (parser , false );
128128 }
@@ -175,7 +175,7 @@ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlo
175175 TokenUtils .consume (parser );
176176 expr .elements .addAll (parseList (parser , ")" , 0 ));
177177 } else {
178- while (token .type != LexerTokenType .EOF && !ParserTables . LIST_TERMINATORS . contains ( token . text )) {
178+ while (token .type != LexerTokenType .EOF && !isListTerminator ( parser , token )) {
179179 // Argument without parentheses
180180 expr .elements .add (parser .parseExpression (parser .getPrecedence ("," )));
181181 token = TokenUtils .peek (parser );
@@ -212,6 +212,31 @@ static LexerToken consumeCommas(Parser parser) {
212212 return token ;
213213 }
214214
215+ /**
216+ * Checks if a token is a list terminator, with special handling for autoquoting.
217+ * Keywords like "and", "or", "xor" should not terminate a list if followed by "=>",
218+ * as they should be treated as hash keys in that context.
219+ */
220+ static boolean isListTerminator (Parser parser , LexerToken token ) {
221+ if (!ParserTables .LIST_TERMINATORS .contains (token .text )) {
222+ return false ;
223+ }
224+
225+ // Special case: and/or/xor before => should be treated as barewords, not terminators
226+ if (token .text .equals ("and" ) || token .text .equals ("or" ) || token .text .equals ("xor" )) {
227+ // Look ahead to see if => follows
228+ int saveIndex = parser .tokenIndex ;
229+ TokenUtils .consume (parser ); // consume and/or/xor
230+ LexerToken nextToken = TokenUtils .peek (parser );
231+ parser .tokenIndex = saveIndex ; // restore
232+ if (nextToken .text .equals ("=>" )) {
233+ return false ; // Not a terminator, it's a hash key
234+ }
235+ }
236+
237+ return true ;
238+ }
239+
215240 /**
216241 * Parses a generic list with a specified closing delimiter. This method is
217242 * used for parsing various constructs like parentheses, hash literals, and
@@ -269,8 +294,22 @@ public static boolean looksLikeEmptyList(Parser parser) {
269294 LexerToken token1 = parser .tokens .get (parser .tokenIndex ); // Next token including spaces
270295 LexerToken nextToken = TokenUtils .peek (parser ); // After spaces
271296
272- if (token .type == LexerTokenType .EOF || ParserTables .LIST_TERMINATORS .contains (token .text )
273- || token .text .equals ("->" )) {
297+ // Check if this is a list terminator, but we need to restore position for the check
298+ boolean isTerminator = false ;
299+ if (ParserTables .LIST_TERMINATORS .contains (token .text )) {
300+ // Special case: check if and/or/xor followed by =>
301+ if (token .text .equals ("and" ) || token .text .equals ("or" ) || token .text .equals ("xor" )) {
302+ if (nextToken .text .equals ("=>" )) {
303+ isTerminator = false ; // Not a terminator, it's a hash key
304+ } else {
305+ isTerminator = true ;
306+ }
307+ } else {
308+ isTerminator = true ;
309+ }
310+ }
311+
312+ if (token .type == LexerTokenType .EOF || isTerminator || token .text .equals ("->" )) {
274313 isEmptyList = true ;
275314 } else if (token .text .equals ("-" )) {
276315 // -d, -e, -f, -l, -p, -x
0 commit comments