From: Ben Pfaff Date: Fri, 4 Jun 2021 06:23:33 +0000 (-0700) Subject: !BLANKS and !CONCAT pass basic tests. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=7024f0edd9193b70c24fcf76d123b15f00a61180 !BLANKS and !CONCAT pass basic tests. --- diff --git a/doc/flow-control.texi b/doc/flow-control.texi index 77b4a3c42e..7a95758a78 100644 --- a/doc/flow-control.texi +++ b/doc/flow-control.texi @@ -338,6 +338,8 @@ are equivalent; for a quoted string of spaces, use In the examples below, @samp{_} stands in for a space to make the results visible. +@c Keep these examples in sync with the test for !BLANKS in +@c tests/language/control/define.at: @example !BLANKS(0) @expansion{} @r{empty} !BLANKS(1) @expansion{} _ @@ -351,6 +353,8 @@ Expands to the concatenation of all of the arguments. Before concatenation, each quoted string argument is unquoted, as if @code{!UNQUOTE} were applied. +@c Keep these examples in sync with the test for !CONCAT in +@c tests/language/control/define.at: @example !CONCAT(x, y) @expansion{} xy !CONCAT('x', 'y') @expansion{} xy @@ -512,9 +516,26 @@ to uppercase. @node Macro Settings @subsection Macro Settings -MPRINT -MEXPAND -MNEST +Some macro behavior is controlled through the SET command +(@pxref{SET}). This section describes these settings. + +Any SET command that changes these settings within a macro body only +takes effect following the macro. This is because PSPP expands a +macro's entire body at once, so that the SET command inside the body +only executes afterwards. + +The MEXPAND setting (@pxref{SET MEXPAND}) controls whether macros will +be expanded at all. By default, macro expansion is on. To avoid +expansion of macros called within a macro body, use @code{!OFFEXPAND} +and @code{!ONEXPAND} (@pxref{Controlling Macro Expansion}). + +When MPRINT (@pxref{SET MPRINT}) is turned on, PSPP logs an expansion +of each macro in the input. This feature can be useful for debugging +macro definitions. + +MNEST (@pxref{SET MNEST}) limits the depth of expansion of macro +calls, that is, the nesting level of macro expansion. + MITERATE PRESERVE...RESTORE diff --git a/doc/utilities.texi b/doc/utilities.texi index 62ca1a8f24..bd5b10c9e2 100644 --- a/doc/utilities.texi +++ b/doc/utilities.texi @@ -942,18 +942,21 @@ The following subcommands affect the interpretation of macros. Controls whether macros are expanded. The default is ON. @item MPRINT +@anchor{SET MPRINT} Controls whether the expansion of macros is included in output. This is separate from whether command syntax in general is included in output. The default is OFF. @item MITERATE +@anchor{SET MITERATE} Limits the number of iterations executed in @code{!DO} loops within macros. This does not affect other language constructs such as @cmd{LOOP}. This must be set to a positive integer. The default is 1000. @item MNEST -Limits the number of levels of nested macro expansion. This must be +@anchor{SET MNEST} +Limits the number of levels of nested macro expansions. This must be set to a positive integer. The default is 50. @end table diff --git a/src/language/lexer/macro.c b/src/language/lexer/macro.c index 584ee7f2fd..628b83af01 100644 --- a/src/language/lexer/macro.c +++ b/src/language/lexer/macro.c @@ -875,33 +875,19 @@ expand_macro_function (struct parse_macro_function_ctx *ctx, else if (parse_macro_function (ctx, &args, ss_cstr ("!concat"), 1, INT_MAX, input_consumed)) { - struct string s; - bool all_strings = true; + struct string s = DS_EMPTY_INITIALIZER; for (size_t i = 0; i < args.n; i++) { if (args.mts[i].token.type == T_STRING) ds_put_substring (&s, args.mts[i].token.string); else - { - all_strings = false; - ds_put_substring (&s, args.mts[i].representation); - } + ds_put_substring (&s, args.mts[i].representation); } - if (all_strings) - { - *output = (struct macro_token) { - .token = { .type = T_STRING, .string = s.ss }, - }; - output->representation = ss_cstr (token_to_string (&output->token)); - } - else - { - *output = (struct macro_token) { - .token = { .type = T_MACRO_ID /*XXX*/, .string = s.ss }, - }; - ss_alloc_substring (&output->representation, s.ss); - } + *output = (struct macro_token) { + .token = { .type = T_MACRO_ID /*XXX*/, .string = s.ss }, + }; + ss_alloc_substring (&output->representation, s.ss); } else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1, input_consumed)) @@ -927,6 +913,17 @@ expand_macro_function (struct parse_macro_function_ctx *ctx, else macro_token_copy (output, &args.mts[0]); } + else if (ctx->n_input > 0 + && ctx->input[0].token.type == T_MACRO_ID + && ss_equals_case (ctx->input[0].token.string, ss_cstr ("!null"))) + { + *input_consumed = 1; + *output = (struct macro_token) { + .token = { .type = T_MACRO_ID /* XXX*/ }, + }; + ss_alloc_substring (&output->token.string, ss_cstr ("")); + return true; + } else return false; diff --git a/tests/language/control/define.at b/tests/language/control/define.at index 8f1c8dea8d..7a005fc805 100644 --- a/tests/language/control/define.at +++ b/tests/language/control/define.at @@ -18,10 +18,12 @@ AT_BANNER([DEFINE]) m4_define([PSPP_CHECK_MACRO_EXPANSION], [AT_SETUP([macro expansion - $1]) + AT_KEYWORDS([m4_bpatsubst([$1], [!], [])]) AT_DATA([define.sps], [$2 DEBUG EXPAND. $3 ]) + AT_CAPTURE_FILE([define.sps]) AT_DATA([expout], [$4 ]) AT_CHECK([pspp --testing-mode define.sps | sed '/^$/d'], [$6], [expout]) @@ -351,4 +353,40 @@ PSPP_CHECK_MACRO_EXPANSION([default keyword arguments], [!k arg1=x. !k], [k(x) -k(a b c)]) \ No newline at end of file +k(a b c)]) + +dnl Keep this test in sync with the examples for !BLANKS in the manual. +PSPP_CHECK_MACRO_EXPANSION([!BLANKS], + [DEFINE !b() +!BLANKS(0). +!QUOTE(!BLANKS(0)). +!BLANKS(1). +!QUOTE(!BLANKS(1)). +!BLANKS(2). +!QUOTE(!BLANKS(2)). +!BLANKS(5). +!QUOTE(!BLANKS(5)). +!ENDDEFINE], + [!b.], + [. +''. + . +' '. + . +' '. + . +' '.]) + +dnl Keep this test in sync with the examples for !CONCAT in the manual. +PSPP_CHECK_MACRO_EXPANSION([!CONCAT], + [DEFINE !c() +!CONCAT(x, y). +!CONCAT('x', 'y'). +!CONCAT(12, 34). +!CONCAT(!NULL, 123). +!ENDDEFINE], + [!c.], + [xy. +xy. +1234. +123.])