• R/O
  • SSH
  • HTTPS

yash: Commit


Commit MetaInfo

Revision3810 (tree)
Time2017-10-08 15:30:56
Authormagicant

Log Message

Substitute aliases anywhere in function definition

After alias substitution in which the alias value ends with a blank, the
next token is also subject to alias substitution. This POSIX requirement
applies anywhere including function definition commands. To support this
behavior (again), alias substitution function needs to be called from
many places in the function definition command parser, which is now
called after (rather than before) the simple command parser to eliminate
unneeded re-parsing and re-alias-substitution.

The is_literal_function_name function is introduced which decides if a
word is applicable for the function name used in a function definition
that does not begin with the "function" keyword. This replaces part of
the print_function_definition function, making the decision more correct
in terms of POSIXly-correctness and applicability of digits at the
beginning of the word.

Change Summary

Incremental Difference

--- yash/trunk/parser.c (revision 3809)
+++ yash/trunk/parser.c (revision 3810)
@@ -248,6 +248,8 @@
248248 __attribute__((pure,nonnull));
249249 static bool is_portable_name(const wchar_t *s)
250250 __attribute__((pure,nonnull));
251+static bool is_literal_function_name(const wordunit_T *wu)
252+ __attribute__((pure));
251253
252254
253255 /* Checks if the specified character can be used in a portable variable name.
@@ -356,7 +358,23 @@
356358 }
357359 }
358360
361+bool is_literal_function_name(const wordunit_T *wu)
362+{
363+ if (wu == NULL)
364+ return false;
365+ if (wu->next != NULL)
366+ return false;
367+ if (wu->wu_type != WT_STRING)
368+ return false;
359369
370+ const wchar_t *s = wu->wu_string;
371+ if (iswdigit(s[0]))
372+ return false;
373+
374+ return (posixly_correct ? is_portable_name : is_name)(s);
375+}
376+
377+
360378 /********** Parser **********/
361379
362380 /* Holds data that are used in parsing. */
@@ -485,8 +503,8 @@
485503 __attribute__((nonnull,malloc,warn_unused_result));
486504 static command_T *parse_function(parsestate_T *ps)
487505 __attribute__((nonnull,malloc,warn_unused_result));
488-static command_T *tryparse_function(parsestate_T *ps)
489- __attribute__((nonnull,malloc,warn_unused_result));
506+static command_T *try_reparse_as_function(parsestate_T *ps, command_T *c)
507+ __attribute__((nonnull,warn_unused_result));
490508 static void read_heredoc_contents(parsestate_T *ps, redir_T *redir)
491509 __attribute__((nonnull));
492510 static void read_heredoc_contents_without_expansion(
@@ -1111,24 +1129,16 @@
11111129 return NULL;
11121130 }
11131131
1114- command_T *result = tryparse_function(ps);
1115- if (result != NULL)
1116- return result;
1117-
11181132 /* parse as a simple command */
1119- redir_T **redirlastp;
1120- result = xmalloc(sizeof *result);
1133+ command_T *result = xmalloc(sizeof *result);
11211134 result->next = NULL;
11221135 result->refcount = 1;
11231136 result->c_lineno = ps->info->lineno;
11241137 result->c_type = CT_SIMPLE;
1125- redirlastp = parse_assignments_and_redirects(ps, result);
1138+ redir_T **redirlastp = parse_assignments_and_redirects(ps, result);
11261139 result->c_words = parse_words_and_redirects(ps, redirlastp, true);
11271140
1128- ensure_buffer(ps, 1);
1129- if (ps->src.contents[ps->index] == L'(')
1130- serror(ps, Ngt("invalid use of `%lc'"), (wint_t) L'(');
1131- return result;
1141+ return try_reparse_as_function(ps, result);
11321142 }
11331143
11341144 /* Parses assignments and redirections.
@@ -2415,60 +2425,62 @@
24152425 return result;
24162426 }
24172427
2418-/* Parses a function definition if any.
2419- * This function may process line continuations, which increase the line
2420- * number. */
2421-command_T *tryparse_function(parsestate_T *ps)
2428+/* Parses (part of) a function definition command that does not start with the
2429+ * "function" keyword. This function must be called just after a simple command
2430+ * has been parsed, which is given as `c'. If the next character is '(', it
2431+ * should signify a function definition, so this function continues parsing the
2432+ * rest of it. Otherwise, `c' is returned intact.
2433+ * If successful, `c' is directly modified to the function definition parsed. */
2434+command_T *try_reparse_as_function(parsestate_T *ps, command_T *c)
24222435 {
2423- size_t saveindex = ps->index;
2424- unsigned long lineno = ps->info->lineno;
2436+ // ensure_buffer(ps, 1);
2437+ if (ps->src.contents[ps->index] != L'(') // not a function definition?
2438+ return c;
24252439
2426- if (iswdigit(ps->src.contents[ps->index]))
2427- goto fail;
2440+ /* If this is a function definition, there must be exactly one command word
2441+ * before '('. */
2442+ assert(c->c_type == CT_SIMPLE);
2443+ if (c->c_redirs != NULL || c->c_assigns != NULL
2444+ || c->c_words[0] == NULL || c->c_words[1] != NULL) {
2445+ serror(ps, Ngt("invalid use of `%lc'"), (wint_t) L'(');
2446+ return c;
2447+ }
24282448
2429- size_t namelen = count_name_length(ps,
2430- posixly_correct ? is_portable_name_char : is_name_char);
2431- ps->index += namelen;
2432- if (namelen == 0 || !is_token_delimiter_char(ps->src.contents[ps->index]))
2433- goto fail;
2434- skip_blanks_and_comment(ps);
2449+ /* The name must be valid. */
2450+ wordunit_T *name = c->c_words[0];
2451+ if (!is_literal_function_name(name)) {
2452+ serror(ps, Ngt("invalid function name"));
2453+ return c;
2454+ }
24352455
2436- /* parse parentheses */
2437- if (ps->src.contents[ps->index] != L'(')
2438- goto fail;
2456+ /* Skip '('. */
24392457 ps->index++;
24402458 skip_blanks_and_comment(ps);
2459+
2460+ /* Parse ')'. */
2461+ psubstitute_alias_recursive(ps, 0);
2462+ // ensure_buffer(ps, 1);
24412463 if (ps->src.contents[ps->index] != L')') {
24422464 serror(ps, Ngt("`(' must be followed by `)' in a function definition"));
2443- return NULL;
2465+ return c;
24442466 }
24452467 ps->index++;
2468+parse_function_body:
24462469 skip_to_next_token(ps);
24472470
2448- /* parse function body */
24492471 const wchar_t *t = check_opening_token(ps);
24502472 if (t == NULL) {
2473+ if (psubstitute_alias(ps, 0))
2474+ goto parse_function_body;
24512475 serror(ps, Ngt("a function body must be a compound command"));
2452- return NULL;
2476+ return c;
24532477 }
2454- command_T *body = parse_compound_command(ps, t);
2455- command_T *result = xmalloc(sizeof *result);
2456- result->next = NULL;
2457- result->refcount = 1;
2458- result->c_type = CT_FUNCDEF;
2459- result->c_lineno = lineno;
2460- result->c_redirs = NULL;
2461- result->c_funcname = xmalloc(sizeof *result->c_funcname);
2462- result->c_funcname->next = NULL;
2463- result->c_funcname->wu_type = WT_STRING;
2464- result->c_funcname->wu_string =
2465- xwcsndup(&ps->src.contents[saveindex], namelen);
2466- result->c_funcbody = body;
2467- return result;
2478+ free(c->c_words);
24682479
2469-fail:
2470- ps->index = saveindex;
2471- return NULL;
2480+ c->c_type = CT_FUNCDEF;
2481+ c->c_funcname = name;
2482+ c->c_funcbody = parse_compound_command(ps, t);
2483+ return c;
24722484 }
24732485
24742486 /* Reads the contents of a here-document. */
@@ -3132,9 +3144,7 @@
31323144 {
31333145 assert(c->c_type == CT_FUNCDEF);
31343146
3135- if (c->c_funcname->next != NULL
3136- || c->c_funcname->wu_type != WT_STRING
3137- || !is_name(c->c_funcname->wu_string))
3147+ if (!is_literal_function_name(c->c_funcname))
31383148 wb_cat(&pr->buffer, L"function ");
31393149 print_word(pr, c->c_funcname, indent);
31403150 wb_cat(&pr->buffer, L"()");
Show on old repository browser