{
struct string_array args;
- if (parse_macro_function (ctx, &args, ss_cstr ("!length"), 1, 1,
+ if (parse_macro_function (ctx, &args, ss_cstr ("!LENGTH"), 1, 1,
input_consumed))
ds_put_format (output, "%zu", strlen (args.strings[0]));
- else if (parse_macro_function (ctx, &args, ss_cstr ("!blanks"), 1, 1,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!BLANKS"), 1, 1,
input_consumed))
{
int n;
ds_put_byte_multiple (output, ' ', n);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!concat"), 1, INT_MAX,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!CONCAT"), 1, INT_MAX,
input_consumed))
{
for (size_t i = 0; i < args.n; i++)
if (!unquote_string (args.strings[i], ctx->segmenter_mode, output))
ds_put_cstr (output, args.strings[i]);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!head"), 1, 1,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!HEAD"), 1, 1,
input_consumed))
{
struct string tmp;
macro_tokens_uninit (&mts);
ds_destroy (&tmp);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!index"), 2, 2,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!INDEX"), 2, 2,
input_consumed))
{
const char *haystack = args.strings[0];
const char *needle = strstr (haystack, args.strings[1]);
ds_put_format (output, "%zu", needle ? needle - haystack + 1 : 0);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!QUOTE"), 1, 1,
input_consumed))
{
if (unquote_string (args.strings[0], ctx->segmenter_mode, NULL))
ds_put_byte (output, '\'');
}
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!substr"), 2, 3,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!SUBSTR"), 2, 3,
input_consumed))
{
int start;
macro_error (ctx->stack, NULL,
_("Third argument of !SUBSTR must be "
"non-negative integer (not \"%s\")."),
- args.strings[1]);
+ args.strings[2]);
string_array_destroy (&args);
return false;
}
struct substring s = ss_cstr (args.strings[0]);
ds_put_substring (output, ss_substr (s, start - 1, count));
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!tail"), 1, 1,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!TAIL"), 1, 1,
input_consumed))
{
struct string tmp;
macro_tokens_uninit (&mts);
ds_destroy (&tmp);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!UNQUOTE"), 1, 1,
input_consumed))
{
if (!unquote_string (args.strings[0], ctx->segmenter_mode, output))
ds_put_cstr (output, args.strings[0]);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!upcase"), 1, 1,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!UPCASE"), 1, 1,
input_consumed))
{
struct string tmp;
free (upper);
ds_destroy (&tmp);
}
- else if (parse_macro_function (ctx, &args, ss_cstr ("!eval"), 1, 1,
+ else if (parse_macro_function (ctx, &args, ss_cstr ("!EVAL"), 1, 1,
input_consumed))
{
struct macro_tokens mts = { .n = 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")))
+ && ss_equals_case (ctx->input[0].token.string, ss_cstr ("!NULL")))
{
*input_consumed = 1;
return true;
*tokens = p;
return value;
}
+ else if (p->token.type == T_RPAREN)
+ {
+ macro_error (ctx->stack, p, _("Expecting literal or function invocation "
+ "in macro expression."));
+ return NULL;
+ }
struct parse_macro_function_ctx fctx = {
.input = p,
macro_tokens_from_string__ (&mts, ss_cstr (s), segmenter_mode, stack);
if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
{
- macro_tokens_print (&mts, stdout);
macro_error (stack, mts.n > 0 ? &mts.mts[0] : NULL,
_("Macro expression must evaluate to "
"a number (not \"%s\")."), s);
(x = 1) (y = 2)
])
-AT_CLEANUP
\ No newline at end of file
+AT_CLEANUP
+
+AT_SETUP([bad token in macro body])
+AT_DATA([define.sps], [dnl
+DEFINE !x()
+x'123'
+!ENDDEFINE.
+])
+AT_CHECK([pspp define.sps], [1], [dnl
+define.sps:3: error: DEFINE: String of hex digits has 3 characters, which is
+not a multiple of 2.
+])
+AT_CLEANUP
+
+AT_SETUP([generic macro function syntax errors])
+AT_DATA([define.sps], [dnl
+DEFINE !a() !SUBSTR !ENDDEFINE.
+DEFINE !b() !SUBSTR x !ENDDEFINE.
+DEFINE !c() !SUBSTR(1,2,3,4) !ENDDEFINE.
+DEFINE !d() !SUBSTR(1x) !ENDDEFINE.
+DEFINE !e() !SUBSTR(1 !ENDDEFINE.
+dnl )
+DEBUG EXPAND.
+!a.
+!b.
+!c.
+!d.
+!e.
+])
+AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
+define.sps:1: In the expansion of `!a',
+define.sps:7: error: DEBUG EXPAND: `(' expected following !SUBSTR.
+
+!SUBSTR
+
+define.sps:2: At `x' in the expansion of `!b',
+define.sps:8: error: DEBUG EXPAND: `(' expected following !SUBSTR.
+
+!SUBSTR x
+
+define.sps:3: At `)' in the expansion of `!c',
+define.sps:9: error: DEBUG EXPAND: Wrong number of arguments to macro
+function !SUBSTR.
+
+!SUBSTR(1, 2, 3, 4)
+
+define.sps:4: At `x' in the expansion of `!d',
+define.sps:10: error: DEBUG EXPAND: `,' or `)' expected in call to macro
+function !SUBSTR.
+
+!SUBSTR(1 x)
+
+define.sps:5: In the expansion of `!e',
+define.sps:11: error: DEBUG EXPAND: Missing `)' in call to macro function !
+SUBSTR.
+
+!SUBSTR(1
+])
+AT_CLEANUP
+
+AT_SETUP([specific macro function syntax errors])
+AT_DATA([define.sps], [dnl
+DEFINE !a() !BLANKS(x). !ENDDEFINE.
+DEFINE !b() !SUBSTR(x, y). !ENDDEFINE.
+DEFINE !c() !SUBSTR(x, 1, z). !ENDDEFINE.
+DEBUG EXPAND.
+!a.
+!b.
+!c.
+])
+AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
+define.sps:1: In the expansion of `!a',
+define.sps:5: error: DEBUG EXPAND: Argument to !BLANKS must be non-negative
+integer (not "x").
+
+!BLANKS(x).
+
+define.sps:2: In the expansion of `!b',
+define.sps:6: error: DEBUG EXPAND: Second argument of !SUBSTR must be positive
+integer (not "y").
+
+!SUBSTR(x, y).
+
+define.sps:3: In the expansion of `!c',
+define.sps:7: error: DEBUG EXPAND: Third argument of !SUBSTR must be non-
+negative integer (not "z").
+
+!SUBSTR(x, 1, z).
+])
+AT_CLEANUP
+
+AT_SETUP([macro expression errors])
+AT_DATA([define.sps], [dnl
+DEFINE !a() !LET !x = (1. !ENDDEFINE dnl )
+
+DEFINE !b() !DO !x = x. !ENDDEFINE.
+DEFINE !c() !LET !x = (). !ENDDEFINE.
+DEBUG EXPAND.
+!a.
+!b.
+!c.
+])
+AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
+define.sps:1-2: At `.' in the expansion of `!a',
+define.sps:5: error: DEBUG EXPAND: Expecting ')' in macro expression.
+
+!LET !x = (1.
+
+At `x' in the expansion of `!DO',
+define.sps:2: inside the expansion of `!b',
+define.sps:6: error: DEBUG EXPAND: Macro expression must evaluate to a number
+(not "x").
+
+!DO !x = x.
+
+define.sps:3: At `)' in the expansion of `!c',
+define.sps:7: error: DEBUG EXPAND: Expecting literal or function invocation in
+macro expression.
+
+!LET !x = ( ).
+])
+AT_CLEANUP
+
+AT_SETUP([macro !IF errors])
+AT_KEYWORDS([IF])
+AT_DATA([define.sps], [dnl
+DEFINE !a() !IF 1 !ENDDEFINE.
+DEFINE !b() !IF 1 !THEN !ENDDEFINE.
+DEFINE !c() !IF 1 !THEN !ELSE !ENDDEFINE.
+DEBUG EXPAND.
+!a.
+!b.
+!c.
+])
+AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
+define.sps:1: In the expansion of `!a',
+define.sps:5: error: DEBUG EXPAND: !THEN expected in macro !IF construct.
+
+!IF 1
+
+define.sps:2: In the expansion of `!b',
+define.sps:6: error: DEBUG EXPAND: !ELSE or !IFEND expected in macro !IF
+construct.
+
+!IF 1 !THEN
+
+define.sps:3: In the expansion of `!c',
+define.sps:7: error: DEBUG EXPAND: !IFEND expected in macro !IF construct.
+
+!IF 1 !THEN !ELSE
+])
+AT_CLEANUP
+
+AT_SETUP([macro !LET errors])
+AT_KEYWORDS([LET])
+AT_DATA([define.sps], [dnl
+DEFINE !a() !LET !ENDDEFINE.
+DEFINE !b() !LET 0 !ENDDEFINE.
+DEFINE !c() !LET !x !ENDDEFINE.
+DEFINE !d() !LET !x y !ENDDEFINE.
+DEBUG EXPAND.
+!a.
+!b.
+!c.
+!d.
+])
+AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
+define.sps:1: In the expansion of `!a',
+define.sps:6: error: DEBUG EXPAND: Expected macro variable name following !LET.
+
+!LET
+
+define.sps:2: At `0' in the expansion of `!b',
+define.sps:7: error: DEBUG EXPAND: Expected macro variable name following !LET.
+
+!LET 0
+
+define.sps:3: In the expansion of `!c',
+define.sps:8: error: DEBUG EXPAND: Expected `=' following !LET.
+
+!LET !x
+
+define.sps:4: At `y' in the expansion of `!d',
+define.sps:9: error: DEBUG EXPAND: Expected `=' following !LET.
+
+!LET !x y
+])
+AT_CLEANUP
+
+AT_SETUP([macro !DO errors])
+AT_KEYWORDS([DO])
+AT_DATA([define.sps], [dnl
+DEFINE !a() !DO !ENDDEFINE.
+DEFINE !b() !DO 0 !ENDDEFINE.
+DEFINE !c() !DO !x !ENDDEFINE.
+DEFINE !d() !DO !x !in (x) !ENDDEFINE.
+DEFINE !e() !DO !x = x. !ENDDEFINE.
+DEFINE !f() !DO !x = 5 x !ENDDEFINE.
+DEFINE !g() !DO !x = 5 !TO 6 !BY 0 !ENDDEFINE.
+DEFINE !h() !DO !x !ENDDEFINE.
+DEFINE !i() !DO !x 0 !ENDDEFINE.
+DEFINE !j() !BREAK !ENDDEFINE.
+DEBUG EXPAND.
+!a.
+!b.
+!c.
+!d.
+!e.
+!f.
+!g.
+!h.
+!i.
+!j.
+])
+AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
+define.sps:1: In the expansion of `!a',
+define.sps:12: error: DEBUG EXPAND: Expected macro variable name following !DO.
+
+!DO
+
+define.sps:2: At `0' in the expansion of `!b',
+define.sps:13: error: DEBUG EXPAND: Expected macro variable name following !DO.
+
+!DO 0
+
+define.sps:3: In the expansion of `!c',
+define.sps:14: error: DEBUG EXPAND: Expected `=' or !IN in !DO loop.
+
+!DO !x
+
+define.sps:4: In the expansion of `!d',
+define.sps:15: error: DEBUG EXPAND: Missing !DOEND.
+
+!DO !x !in(x)
+
+At `x' in the expansion of `!DO',
+define.sps:5: inside the expansion of `!e',
+define.sps:16: error: DEBUG EXPAND: Macro expression must evaluate to a number
+(not "x").
+
+!DO !x = x.
+
+define.sps:6: At `x' in the expansion of `!f',
+define.sps:17: error: DEBUG EXPAND: Expected !TO in numerical !DO loop.
+
+!DO !x = 5 x
+
+define.sps:7: In the expansion of `!g',
+define.sps:18: error: DEBUG EXPAND: !BY value cannot be zero.
+
+!DO !x = 5 !TO 6 !BY 0
+
+define.sps:8: In the expansion of `!h',
+define.sps:19: error: DEBUG EXPAND: Expected `=' or !IN in !DO loop.
+
+!DO !x
+
+define.sps:9: At `0' in the expansion of `!i',
+define.sps:20: error: DEBUG EXPAND: Expected `=' or !IN in !DO loop.
+
+!DO !x 0
+
+define.sps:10: At `!BREAK' in the expansion of `!j',
+define.sps:21: error: DEBUG EXPAND: !BREAK outside !DO.
+
+!BREAK
+])
+AT_CLEANUP
+