Feature #4276
closedAllow use of quotes in symbol syntactic sugar for hashes
Description
Current syntactic sugar allows this:
hash = {Alabama: "AL"}
This feature request is to also allow symbols delimited by quotes (and thus able to contain a whitespace) to use an equivalent syntactic sugar:
hash2 = {"Rhode Island": "RI"}
Updated by nobu (Nobuyoshi Nakada) about 11 years ago
Hi,
At Thu, 13 Jan 2011 10:17:23 +0900,
Tyler Benster wrote in [ruby-core:34453]:Current syntactic sugar allows this:
hash = {Alabama: "AL"}
This feature request is to also allow symbols delimited by quotes (and thus able to contain a whitespace) to use an equivalent syntactic sugar:
hash2 = {"Rhode Island": "RI"}
I've forgotten to post the patch.
diff --git i/parse.y w/parse.y
index 06f96ce..0cacdd5 100644
--- i/parse.y
+++ w/parse.y
@@ -380,6 +380,8 @@ static NODE *ret_args_gen(struct parser_params*,NODE*);
static NODE *arg_blk_pass(NODE*,NODE*);
static NODE *new_yield_gen(struct parser_params*,NODE*);
#define new_yield(node) new_yield_gen(parser, (node))
+static NODE *dsym_node_gen(struct parser_params*,NODE*);
+#define dsym_node(node) dsym_node_gen(parser, (node))
static NODE *gettable_gen(struct parser_params*,ID);
#define gettable(id) gettable_gen(parser,(id))
@@ -678,12 +680,12 @@ static void token_info_pop(struct parser_params*, const char *token);
keyword__FILE__
keyword__ENCODING__
-%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
+%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL tLABEL_END
%token <node> tINTEGER tFLOAT tSTRING_CONTENT tCHAR
%token <node> tNTH_REF tBACK_REF
%token <num> tREGEXP_END
-%type <node> singleton strings string string1 xstring regexp
+%type <node> singleton strings string string1 xstring regexp string_body
%type <node> string_contents xstring_contents regexp_contents string_content
%type <node> words qwords word_list qword_list word
%type <node> literal numeric dsym cpath
@@ -3841,12 +3843,18 @@ string : tCHAR
}
;
-string1 : tSTRING_BEG string_contents tSTRING_END
+string_body : tSTRING_BEG string_contents
{
- /*%%%*/
$$ = $2;
+ }
+ ;
+
+string1 : string_body tSTRING_END
+ {
+ /*%%%*/
+ $$ = $1;
/*%
- $$ = dispatch1(string_literal, $2);
+ $$ = dispatch1(string_literal, $1);
%*/
}
;
@@ -4199,26 +4207,7 @@ dsym : tSYMBEG xstring_contents tSTRING_END
{
lex_state = EXPR_END;
/*%%%*/
- if (!($$ = $2)) {
- $$ = NEW_LIT(ID2SYM(rb_intern("")));
- }
- else {
- VALUE lit;
-
- switch (nd_type($$)) {
- case NODE_DSTR:
- nd_set_type($$, NODE_DSYM);
- break;
- case NODE_STR:
- lit = $$->nd_lit;
- $$->nd_lit = ID2SYM(rb_intern_str(lit));
- nd_set_type($$, NODE_LIT);
- break;
- default:
- $$ = NEW_NODE(NODE_DSYM, Qnil, 1, NEW_LIST($$));
- break;
- }
- }
+ $$ = dsym_node($2);
/*%
$$ = dispatch1(dyna_symbol, $2);
%*/
@@ -4761,6 +4750,15 @@ assoc : arg_value tASSOC arg_value
$$ = dispatch2(assoc_new, $1, $2);
%*/
}
+ | string_body tLABEL_END arg_value
+ {
+ /*%%%*/
+ $$ = list_append(NEW_LIST(dsym_node($1)), $3);
+ /*%
+ $$ = dispatch1(dyna_symbol, $1);
+ $$ = dispatch2(assoc_new, $$, $3);
+ %*/
+ }
;
operation : tIDENTIFIER
@@ -5334,6 +5332,7 @@ rb_parser_compile_file(volatile VALUE vparser, const char *f, VALUE file, int st
#define STR_FUNC_QWORDS 0x08
#define STR_FUNC_SYMBOL 0x10
#define STR_FUNC_INDENT 0x20
+#define STR_FUNC_LABEL 0x40
enum string_type {
str_squote = (0),
@@ -5925,6 +5924,8 @@ parser_tokadd_string(struct parser_params *parser,
#define NEW_STRTERM(func, term, paren) \
rb_node_newnode(NODE_STRTERM, (func), (term) | ((paren) << (CHAR_BIT * 2)), 0)
+#define IS_LABEL_SUFFIX(n) (peek_n(':',(n)) && !peek_n(':', (n)+1))
+#define MAYBE_LABEL() (IS_LABEL_POSSIBLE() ? STR_FUNC_LABEL : 0)
static int
parser_parse_string(struct parser_params *parser, NODE *quote)
@@ -5946,6 +5947,10 @@ parser_parse_string(struct parser_params *parser, NODE *quote)
quote->nd_func = -1;
return ' ';
}
+ if ((func & STR_FUNC_LABEL) && IS_LABEL_SUFFIX(0)) {
+ lex_state = EXPR_BEG;
+ return tLABEL_END;
+ }
if (!(func & STR_FUNC_REGEXP)) return tSTRING_END;
set_yylval_num(regx_options());
return tREGEXP_END;
@@ -6533,7 +6538,6 @@ parser_prepare(struct parser_params *parser)
#define IS_BEG() (lex_state == EXPR_BEG || lex_state == EXPR_MID || lex_state == EXPR_VALUE || lex_state == EXPR_CLASS)
#define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c))
#define IS_LABEL_POSSIBLE() ((lex_state == EXPR_BEG && !cmd_state) || IS_ARG())
-#define IS_LABEL_SUFFIX(n) (peek_n(':',(n)) && !peek_n(':', (n)+1))
#ifndef RIPPER
#define ambiguous_operator(op, syn) ( \
@@ -6849,7 +6853,7 @@ parser_yylex(struct parser_params *parser)
return '>';
case '"':
- lex_strterm = NEW_STRTERM(str_dquote, '"', 0);
+ lex_strterm = NEW_STRTERM(str_dquote | MAYBE_LABEL(), '"', 0);
return tSTRING_BEG;
case '`':
@@ -6868,7 +6872,7 @@ parser_yylex(struct parser_params *parser)
return tXSTRING_BEG;
case '\'':
- lex_strterm = NEW_STRTERM(str_squote, '\'', 0);
+ lex_strterm = NEW_STRTERM(str_squote | MAYBE_LABEL(), '\'', 0);
return tSTRING_BEG;
case '?':
@@ -8987,6 +8991,32 @@ new_args_gen(struct parser_params *parser, NODE *m, NODE *o, ID r, NODE *p, ID b
ruby_sourceline = saved_line;
return node;
}
+
+static NODE*
+dsym_node_gen(struct parser_params *parser, NODE *node)
+{
+ if (!node) {
+ node = NEW_LIT(ID2SYM(rb_intern("")));
+ }
+ else {
+ VALUE lit;
+
+ switch (nd_type(node)) {
+ case NODE_DSTR:
+ nd_set_type(node, NODE_DSYM);
+ break;
+ case NODE_STR:
+ lit = node->nd_lit;
+ node->nd_lit = ID2SYM(rb_intern_str(lit));
+ nd_set_type(node, NODE_LIT);
+ break;
+ default:
+ node = NEW_NODE(NODE_DSYM, Qnil, 1, NEW_LIST(node));
+ break;
+ }
+ }
+ return node;
+}
#endif /* !RIPPER */
static void
Nobu Nakada
Updated by nahi (Hiroshi Nakamura) over 10 years ago
- Description updated (diff)
- Category set to core
- Status changed from Open to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
Updated by mame (Yusuke Endoh) over 9 years ago
- Target version set to 2.6
Updated by bitsweat (Jeremy Daer) over 9 years ago
This would improve a lot of my code that's punctuated with { foo: bar, :'hoge' => piyo }
. Switching syntax is a mental and visual interruption.
I hope Ruby 2 supports this quoted-symbol syntax from the first day it's released, so everyone can rely on it. Please consider this patch for preview2!
Updated by drbrain (Eric Hodel) over 9 years ago
Sorry, this feature is too late for 2.0.0
Updated by nobu (Nobuyoshi Nakada) over 9 years ago
One of the reason I didn't introduce this was, a few bundled scripts had compatibility issue when once I tried.
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
- Has duplicate Feature #9047: Alternate hash key syntax for symbols added
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
- Description updated (diff)
Updated by nobu (Nobuyoshi Nakada) about 8 years ago
Updated with the test in [Feature #4935]: https://github.com/ruby/ruby/pull/684
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) about 8 years ago
Great, from the test it seems to allow interpolation. Could you please confirm I understood it correctly?
Updated by matz (Yukihiro Matsumoto) about 8 years ago
- Status changed from Assigned to Feedback
I am not against the idea, but I want to make sure that key will be symbol, since some may expect
{"foo bar": 12}
to be a hash with string key, especially who is familiar with JSON.
Matz.
Updated by nobu (Nobuyoshi Nakada) about 8 years ago
Rodrigo Rosenfeld Rosas wrote:
Great, from the test it seems to allow interpolation. Could you please confirm I understood it correctly?
Yes, it is allowed inside double quotes, but not single quotes.
Other terminators (e.g., %(...)
) cause syntax errors.
Updated by Ajedi32 (Andrew M) about 8 years ago
Yukihiro Matsumoto wrote:
I am not against the idea, but I want to make sure that key will be symbol,
Yes, I believe that was the intention. E.g.
# Currently, Hashes have syntactic sugar which allows:
{:key => "Value"} == {key: "Value"} #=> true
# This feature request is to allow:
{:"some key" => "Value"} == {"some key": "Value"} #=> true
Updated by nobu (Nobuyoshi Nakada) almost 8 years ago
OK, I commit the previous patch.
Yell if you don't like it.
Updated by nobu (Nobuyoshi Nakada) almost 8 years ago
- Status changed from Feedback to Closed
- % Done changed from 0 to 100
Applied in changeset r47649.
parse.y: quoted ID key
- parse.y (assoc): allow quoted ID as a key of a hash literal.
[ruby-core:34453] [Feature #4276]
Updated by nobu (Nobuyoshi Nakada) almost 8 years ago
Just a note: last evening at RubyKaigi 2014, talked to matz about this issue, and got his approval to introduce this to see if anyone rants.
Updated by etienne (Étienne Barrié) over 7 years ago
Hi, any reason it doesn't work with inner hashes or arrays?
{ foo: {} } # => {:foo=>{}}
{ 'foo': {} }
# SyntaxError: (irb):2: syntax error, unexpected '{'
{ 'foo': [] }
SyntaxError: (irb):1: syntax error, unexpected '['
Updated by nobu (Nobuyoshi Nakada) over 7 years ago
- Related to Bug #10653: do-end block in ternary operator is syntax error added