• R/O
  • SSH
  • HTTPS

yash: Commit


Commit MetaInfo

Revision3920 (tree)
Time2018-11-25 14:25:43
Authormagicant

Log Message

Parse double-bracket command

Change Summary

Incremental Difference

--- yash/branches/double_bracket/builtins/test.c (revision 3919)
+++ yash/branches/double_bracket/builtins/test.c (revision 3920)
@@ -1,6 +1,6 @@
11 /* Yash: yet another shell */
22 /* test.c: test builtin */
3-/* (C) 2007-2012 magicant */
3+/* (C) 2007-2018 magicant */
44
55 /* This program is free software: you can redistribute it and/or modify
66 * it under the terms of the GNU General Public License as published by
@@ -59,10 +59,6 @@
5959 __attribute__((nonnull));
6060 static bool test_long_term(struct test_state *state)
6161 __attribute__((nonnull));
62-static bool is_unary_primary(const wchar_t *word)
63- __attribute__((nonnull,pure));
64-static bool is_binary_primary(const wchar_t *word)
65- __attribute__((nonnull,pure));
6662 static bool is_term_delimiter(const wchar_t *word)
6763 __attribute__((nonnull,pure));
6864 static int compare_integers(const wchar_t *left, const wchar_t *right)
--- yash/branches/double_bracket/builtins/test.h (revision 3919)
+++ yash/branches/double_bracket/builtins/test.h (revision 3920)
@@ -1,6 +1,6 @@
11 /* Yash: yet another shell */
22 /* test.h: test builtin */
3-/* (C) 2007-2012 magicant */
3+/* (C) 2007-2018 magicant */
44
55 /* This program is free software: you can redistribute it and/or modify
66 * it under the terms of the GNU General Public License as published by
@@ -20,6 +20,8 @@
2020 #define YASH_TEST_H
2121
2222
23+#include <stddef.h>
24+
2325 extern int test_builtin(int argc, void **argv)
2426 __attribute__((nonnull));
2527 #if YASH_ENABLE_HELP
@@ -26,7 +28,12 @@
2628 extern const char test_help[], test_syntax[];
2729 #endif
2830
31+extern _Bool is_unary_primary(const wchar_t *word)
32+ __attribute__((nonnull,pure));
33+extern _Bool is_binary_primary(const wchar_t *word)
34+ __attribute__((nonnull,pure));
2935
36+
3037 #endif /* YASH_TEST_H */
3138
3239
--- yash/branches/double_bracket/parser.c (revision 3919)
+++ yash/branches/double_bracket/parser.c (revision 3920)
@@ -39,6 +39,9 @@
3939 #include "plist.h"
4040 #include "strbuf.h"
4141 #include "util.h"
42+#if YASH_ENABLE_DOUBLE_BRACKET
43+# include "builtins/test.h"
44+#endif
4245 #if YASH_ENABLE_LINEEDIT
4346 # include "lineedit/lineedit.h"
4447 #endif
@@ -297,6 +300,9 @@
297300 TT_IF, TT_THEN, TT_ELSE, TT_ELIF, TT_FI, TT_DO, TT_DONE, TT_CASE, TT_ESAC,
298301 TT_WHILE, TT_UNTIL, TT_FOR, TT_LBRACE, TT_RBRACE, TT_BANG, TT_IN,
299302 TT_FUNCTION,
303+#if YASH_ENABLE_DOUBLE_BRACKET
304+ TT_DOUBLE_LBRACKET,
305+#endif
300306 } tokentype_T;
301307
302308 static wchar_t *skip_name(const wchar_t *s, bool predicate(wchar_t))
@@ -386,9 +392,9 @@
386392 {
387393 /* List of keywords:
388394 * case do done elif else esac fi for function if in then until while
389- * { } !
395+ * { } [[ !
390396 * The following words are currently not keywords:
391- * select [[ ]] */
397+ * select ]] */
392398 switch (s[0]) {
393399 case L'c':
394400 if (s[1] == L'a' && s[2] == L's' && s[3] == L'e' && s[4]== L'\0')
@@ -450,6 +456,12 @@
450456 if (s[1] == L'\0')
451457 return TT_RBRACE;
452458 break;
459+#if YASH_ENABLE_DOUBLE_BRACKET
460+ case L'[':
461+ if (s[1] == L'[' && s[2] == L'\0')
462+ return TT_DOUBLE_LBRACKET;
463+ break;
464+#endif /* YASH_ENABLE_DOUBLE_BRACKET */
453465 case L'!':
454466 if (s[1] == L'\0')
455467 return TT_BANG;
@@ -552,6 +564,8 @@
552564
553565 static void serror(parsestate_T *restrict ps, const char *restrict format, ...)
554566 __attribute__((nonnull(1,2),format(printf,2,3)));
567+static void print_errmsg_token(parsestate_T *ps, const char *message)
568+ __attribute__((nonnull));
555569 static const char *get_errmsg_unexpected_tokentype(tokentype_T tokentype)
556570 __attribute__((const));
557571 static void print_errmsg_token_unexpected(parsestate_T *ps)
@@ -653,6 +667,20 @@
653667 __attribute__((nonnull,malloc,warn_unused_result));
654668 static void **parse_case_patterns(parsestate_T *ps)
655669 __attribute__((nonnull,malloc,warn_unused_result));
670+#if YASH_ENABLE_DOUBLE_BRACKET
671+static command_T *parse_double_bracket(parsestate_T *ps)
672+ __attribute__((nonnull,malloc,warn_unused_result));
673+static dbexp_T *parse_double_bracket_ors(parsestate_T *ps)
674+ __attribute__((nonnull,malloc,warn_unused_result));
675+static dbexp_T *parse_double_bracket_ands(parsestate_T *ps)
676+ __attribute__((nonnull,malloc,warn_unused_result));
677+static dbexp_T *parse_double_bracket_nots(parsestate_T *ps)
678+ __attribute__((nonnull,malloc,warn_unused_result));
679+static dbexp_T *parse_double_bracket_primary(parsestate_T *ps)
680+ __attribute__((nonnull,malloc,warn_unused_result));
681+static wordunit_T *parse_double_bracket_operand(parsestate_T *ps)
682+ __attribute__((nonnull,malloc,warn_unused_result));
683+#endif /* YASH_ENABLE_DOUBLE_BRACKET */
656684 static command_T *parse_function(parsestate_T *ps)
657685 __attribute__((nonnull,malloc,warn_unused_result));
658686 static command_T *try_reparse_as_function(parsestate_T *ps, command_T *c)
@@ -830,6 +858,16 @@
830858 ps->error = true;
831859 }
832860
861+void print_errmsg_token(parsestate_T *ps, const char *message)
862+{
863+ assert(ps->index <= ps->next_index);
864+ size_t length = ps->next_index - ps->index;
865+ wchar_t token[length + 1];
866+ wcsncpy(token, &ps->src.contents[ps->index], length);
867+ token[length] = L'\0';
868+ serror(ps, message, token);
869+}
870+
833871 const char *get_errmsg_unexpected_tokentype(tokentype_T tokentype)
834872 {
835873 switch (tokentype) {
@@ -866,14 +904,7 @@
866904
867905 void print_errmsg_token_unexpected(parsestate_T *ps)
868906 {
869- assert(ps->index <= ps->next_index);
870- size_t length = ps->next_index - ps->index;
871- wchar_t token[length + 1];
872- wcsncpy(token, &ps->src.contents[ps->index], length);
873- token[length] = L'\0';
874-
875- const char *message = get_errmsg_unexpected_tokentype(ps->tokentype);
876- serror(ps, message, token);
907+ print_errmsg_token(ps, get_errmsg_unexpected_tokentype(ps->tokentype));
877908 }
878909
879910 void print_errmsg_token_missing(parsestate_T *ps, const wchar_t *t)
@@ -2337,6 +2368,11 @@
23372368 case TT_CASE:
23382369 result = parse_case(ps);
23392370 break;
2371+#if YASH_ENABLE_DOUBLE_BRACKET
2372+ case TT_DOUBLE_LBRACKET:
2373+ result = parse_double_bracket(ps);
2374+ break;
2375+#endif
23402376 default:
23412377 return NULL;
23422378 }
@@ -2691,6 +2727,195 @@
26912727 return pl_toary(&wordlist);
26922728 }
26932729
2730+#if YASH_ENABLE_DOUBLE_BRACKET
2731+
2732+/* Parses a double-bracket command.
2733+ * The current token must be the starting "[[".
2734+ * Never returns NULL. The resultant `c_dbexp' may contain NULL sub-expression
2735+ * in case of syntax error. */
2736+command_T *parse_double_bracket(parsestate_T *ps)
2737+{
2738+ if (posixly_correct)
2739+ serror(ps, Ngt("The [[ ... ]] syntax is not supported "
2740+ "in the POSIXly-correct mode"));
2741+
2742+ assert(ps->tokentype == TT_DOUBLE_LBRACKET);
2743+ next_token(ps);
2744+ psubstitute_alias_recursive(ps, 0);
2745+
2746+ command_T *result = xmalloc(sizeof *result);
2747+ result->next = NULL;
2748+ result->refcount = 1;
2749+ result->c_type = CT_BRACKET;
2750+ result->c_lineno = ps->info->lineno;
2751+ result->c_redirs = NULL;
2752+ result->c_dbexp = parse_double_bracket_ors(ps);
2753+
2754+ if (is_single_string_word(ps->token) &&
2755+ wcscmp(ps->token->wu_string, L"]]") == 0) {
2756+ next_token(ps);
2757+ psubstitute_alias_recursive(ps, 0);
2758+ } else if (!ps->error) {
2759+ if (ps->tokentype == TT_NEWLINE)
2760+ serror(ps, Ngt("`%ls' is missing"), L"]]");
2761+ else
2762+ print_errmsg_token(ps,
2763+ Ngt("invalid word `%ls' between `[[' and `]]'"));
2764+ }
2765+
2766+ return result;
2767+}
2768+
2769+/* Parses one or more "and" expressions separated by "||"s in the double-bracket
2770+ * command. May return NULL on error. */
2771+dbexp_T *parse_double_bracket_ors(parsestate_T *ps)
2772+{
2773+ dbexp_T *lhs = parse_double_bracket_ands(ps);
2774+ if (lhs == NULL || ps->tokentype != TT_PIPEPIPE)
2775+ return lhs;
2776+ next_token(ps);
2777+ psubstitute_alias_recursive(ps, 0);
2778+
2779+ dbexp_T *result = xmalloc(sizeof *result);
2780+ result->type = DBE_OR;
2781+ result->operator = NULL;
2782+ result->lhs.subexp = lhs;
2783+ result->rhs.subexp = parse_double_bracket_ors(ps);
2784+ return result;
2785+}
2786+
2787+/* Parses one or more "!" expressions separated by "&&"s in the double-bracket
2788+ * command. May return NULL on error. */
2789+dbexp_T *parse_double_bracket_ands(parsestate_T *ps)
2790+{
2791+ dbexp_T *lhs = parse_double_bracket_nots(ps);
2792+ if (lhs == NULL || ps->tokentype != TT_AMPAMP)
2793+ return lhs;
2794+ next_token(ps);
2795+ psubstitute_alias_recursive(ps, 0);
2796+
2797+ dbexp_T *result = xmalloc(sizeof *result);
2798+ result->type = DBE_AND;
2799+ result->operator = NULL;
2800+ result->lhs.subexp = lhs;
2801+ result->rhs.subexp = parse_double_bracket_ands(ps);
2802+ return result;
2803+}
2804+
2805+/* Parses a primary expression optionally prefixed by any number of "!"s in the
2806+ * double-bracket command. May return NULL on error. */
2807+dbexp_T *parse_double_bracket_nots(parsestate_T *ps)
2808+{
2809+ if (ps->tokentype != TT_BANG)
2810+ return parse_double_bracket_primary(ps);
2811+ next_token(ps);
2812+ psubstitute_alias_recursive(ps, 0);
2813+
2814+ dbexp_T *result = xmalloc(sizeof *result);
2815+ result->type = DBE_NOT;
2816+ result->operator = NULL;
2817+ result->lhs.subexp = NULL;
2818+ result->rhs.subexp = parse_double_bracket_nots(ps);
2819+ return result;
2820+}
2821+
2822+/* Parses a primary expression in the double-bracket command. May return NULL on
2823+ * error. The "(...)" operator is considered as a primary in this function. */
2824+dbexp_T *parse_double_bracket_primary(parsestate_T *ps)
2825+{
2826+ if (ps->tokentype == TT_LPAREN) {
2827+ /* parse "(...)" */
2828+ next_token(ps);
2829+ psubstitute_alias_recursive(ps, 0);
2830+
2831+ dbexp_T *subexp = parse_double_bracket_ors(ps);
2832+ if (ps->tokentype == TT_RPAREN) {
2833+ next_token(ps);
2834+ psubstitute_alias_recursive(ps, 0);
2835+ } else if (!ps->error) {
2836+ if (ps->tokentype == TT_NEWLINE ||
2837+ (is_single_string_word(ps->token) &&
2838+ wcscmp(ps->token->wu_string, L"]]") == 0))
2839+ serror(ps, Ngt("`%ls' is missing"), L")");
2840+ else
2841+ print_errmsg_token(ps,
2842+ Ngt("invalid word `%ls' between `[[' and `]]'"));
2843+ }
2844+ return subexp;
2845+ }
2846+
2847+ dbexptype_T type;
2848+ wchar_t *op;
2849+ wordunit_T *lhs, *rhs;
2850+
2851+ if (is_single_string_word(ps->token) &&
2852+ is_unary_primary(ps->token->wu_string)) {
2853+ type = DBE_UNARY;
2854+ lhs = NULL;
2855+ goto parse_primary_operator;
2856+ }
2857+
2858+ lhs = parse_double_bracket_operand(ps);
2859+ if (lhs == NULL)
2860+ return NULL;
2861+
2862+ if (ps->tokentype == TT_LESS || ps->tokentype == TT_GREATER) {
2863+ type = DBE_BINARY;
2864+ op = xwcsndup(&ps->src.contents[ps->index], ps->next_index - ps->index);
2865+ } else if (is_single_string_word(ps->token) &&
2866+ is_binary_primary(ps->token->wu_string)) {
2867+ type = DBE_BINARY;
2868+parse_primary_operator:
2869+ op = ps->token->wu_string, ps->token->wu_string = NULL;
2870+ } else {
2871+ type = DBE_STRING;
2872+ op = NULL;
2873+ rhs = lhs, lhs = NULL;
2874+ goto return_result;
2875+ }
2876+ next_token(ps);
2877+ psubstitute_alias_recursive(ps, 0);
2878+
2879+ rhs = parse_double_bracket_operand(ps);
2880+
2881+return_result:;
2882+ dbexp_T *result = xmalloc(sizeof *result);
2883+ result->type = type;
2884+ result->operator = op;
2885+ result->lhs.word = lhs;
2886+ result->rhs.word = rhs;
2887+ return result;
2888+}
2889+
2890+/* Parses a operand token of a primary conditional expression in the double-
2891+ * bracket command. Returns NULL on error. */
2892+wordunit_T *parse_double_bracket_operand(parsestate_T *ps)
2893+{
2894+ if (is_single_string_word(ps->token) &&
2895+ wcscmp(ps->token->wu_string, L"]]") == 0) {
2896+ serror(ps, Ngt("conditional expression "
2897+ "is missing or incomplete between `[[' and `]]'"));
2898+ return NULL;
2899+ }
2900+ if (ps->token == NULL) {
2901+ if (ps->tokentype == TT_NEWLINE)
2902+ serror(ps, Ngt("unexpected linebreak "
2903+ "in the middle of the [[ ... ]] command"));
2904+ else
2905+ print_errmsg_token(ps, Ngt("`%ls' is not a valid operand "
2906+ "in the conditional expression"));
2907+ return NULL;
2908+ }
2909+
2910+ wordunit_T *result = ps->token;
2911+ ps->token = NULL;
2912+ next_token(ps);
2913+ psubstitute_alias_recursive(ps, 0);
2914+ return result;
2915+}
2916+
2917+#endif /* YASH_ENABLE_DOUBLE_BRACKET */
2918+
26942919 /* Parses a function definition that starts with the "function" keyword.
26952920 * The current token must be "function". Never returns NULL. */
26962921 command_T *parse_function(parsestate_T *ps)
Show on old repository browser