start updating expression tests
[pspp] / src / language / expressions / operations.def
index cc24f98751ef84db7861baadaef01e90b33321d9..cbdc247c56162ee75738d6a2a751f21f517f11eb 100644 (file)
@@ -277,10 +277,22 @@ function VARIANCE.2 (a[n])
 
 // Time construction & extraction functions.
 function TIME.HMS (h, m, s)
+  expression e;
+  expr_node n;
 {
   if ((h > 0. || m > 0. || s > 0.) && (h < 0. || m < 0. || s < 0.))
     {
-      msg (SW, _("TIME.HMS cannot mix positive and negative arguments."));
+      msg_at (SW, expr_location (e, n),
+              _("TIME.HMS cannot accept a mix of positive and negative "
+                "arguments."));
+      double args[] = { h, m, s };
+      for (size_t i = 0; i < 3; i++)
+        if (args[i] > 0)
+          msg_at (SN, expr_location (e, n->args[i]),
+                  _("This argument has positive value %g."), args[i]);
+        else if (args[i] < 0)
+          msg_at (SN, expr_location (e, n->args[i]),
+                  _("This argument has negative value %g."), args[i]);
       return SYSMIS;
     }
   else
@@ -293,21 +305,92 @@ function CTIME.MINUTES (time) = time / MIN_S;
 function CTIME.SECONDS (time) = time;
 
 // Date construction functions.
-function DATE.DMY (d, m, y) = expr_ymd_to_date (y, m, d);
-function DATE.MDY (m, d, y) = expr_ymd_to_date (y, m, d);
-function DATE.MOYR (m, y) = expr_ymd_to_date (y, m, 1);
-function DATE.QYR (q, y)
+function DATE.DMY (integer d, integer m, integer y)
+  expression e;
+  expr_node n;
+= expr_ymd_to_date (y, m, d, e, n, 3, 2, 1);
+
+function DATE.MDY (integer m, integer d, integer y)
+  expression e;
+  expr_node n;
+= expr_ymd_to_date (y, m, d, e, n, 3, 1, 2);
+
+function DATE.MOYR (integer m, integer y)
+  expression e;
+  expr_node n;
+= expr_ymd_to_date (y, m, 1, e, n, 2, 1, 0);
+
+function DATE.QYR (integer q, integer y)
+  expression e;
+  expr_node n;
 {
-  if (q < 1.0 || q > 4.0 || q != (int) q)
+  if (q < 1 || q > 4)
     {
-      msg (SW, _("The first argument to DATE.QYR must be 1, 2, 3, or 4."));
+      msg_at (SW, expr_location (e, n->args[0]),
+              _("Argument 1 to DATE.QYR must be 1, 2, 3, or 4 (not %d)."), q);
       return SYSMIS;
     }
-   return expr_ymd_to_date (y, q * 3 - 2, 1);
+  return expr_ymd_to_date (y, q * 3 - 2, 1, e, n, 2, 0, 0);
+}
+
+function DATE.WKYR (integer w, integer y)
+  expression e;
+  expr_node n;
+{
+  if (w < 1 || w > 53)
+    {
+      msg_at (SE, expr_location (e, n->args[0]),
+              _("The week argument to DATE.WKYR is outside the acceptable "
+                "range of 1 to 53.  The result will be system-missing."));
+      return SYSMIS;
+    }
+  else
+    {
+      double yr_1_1 = expr_ymd_to_ofs (y, 1, 1, e, n, 2, 0, 0);
+      if (yr_1_1 != SYSMIS)
+        return DAY_S * (yr_1_1 + WEEK_DAY * (w - 1));
+      else
+        return SYSMIS;
+    }
+}
+
+function DATE.YRDAY (integer y, integer yd)
+  expression e;
+  expr_node n;
+{
+  if (yd < 1 || yd > 366)
+    {
+      msg_at (SE, expr_location (e, n->args[1]),
+              _("DATE.YRDAY day argument %d is outside the acceptable "
+                "range of 1 to 366.  The result will be system-missing."), yd);
+      return SYSMIS;
+    }
+  else
+    {
+      double yr_1_1 = expr_ymd_to_ofs (y, 1, 1, e, n, 1, 0, 0);
+      if (yr_1_1 != SYSMIS)
+        return DAY_S * (yr_1_1 + yd - 1.);
+      else
+        return SYSMIS;
+    }
+}
+
+function YRMODA (integer y, integer m, integer d)
+  expression e;
+  expr_node n;
+{
+  if (y >= 0 && y <= 99)
+    y += 1900;
+  else if (y > 47516)
+    {
+      msg_at (SE, expr_location (e, n->args[0]),
+              _("The year argument to YRMODA is greater than 47516.  "
+                "The result will be system-missing."));
+      return SYSMIS;
+    }
+
+  return expr_ymd_to_ofs (y, m, d, e, n, 1, 2, 3);
 }
-function DATE.WKYR (w, y) = expr_wkyr_to_date (w, y);
-function DATE.YRDAY (y, yday) = expr_yrday_to_date (y, yday);
-function YRMODA (y, m, d) = expr_yrmoda (y, m, d);
 
 // Date extraction functions.
 function XDATE.TDAY (date) = floor (date / DAY_S);
@@ -330,11 +413,18 @@ function XDATE.YEAR (date >= DAY_S) = calendar_offset_to_year (date / DAY_S);
 
 // Date arithmetic functions.
 no_abbrev function DATEDIFF (date2 >= DAY_S, date1 >= DAY_S, string unit)
-     = expr_date_difference (date1, date2, unit);
+  expression e;
+  expr_node n;
+= expr_date_difference (date1, date2, unit, e, n);
+
 no_abbrev function DATESUM (date, quantity, string unit)
-     = expr_date_sum (date, quantity, unit, ss_cstr ("closest"));
+  expression e;
+  expr_node n;
+= expr_date_sum_closest (date, quantity, unit, e, n);
 no_abbrev function DATESUM (date, quantity, string unit, string method)
-     = expr_date_sum (date, quantity, unit, method);
+  expression e;
+  expr_node n;
+= expr_date_sum (date, quantity, unit, method, e, n);
 
 
 // String functions.
@@ -592,6 +682,8 @@ string function RTRIM (string s, string c)
 }
 
 function NUMBER (string s, ni_format f)
+  expression e;
+  expr_node n;
 {
   union value out;
   char *error;
@@ -605,8 +697,9 @@ function NUMBER (string s, ni_format f)
                             settings_get_fmt_settings (), &out);
   else
     {
-      msg (SE, "Cannot parse `%.*s' as format %s: %s",
-           (int) s.length, s.string, fmt_name (f->type), error);
+      msg_at (SE, expr_location (e, n->args[0]),
+              _("Cannot parse `%.*s' as format %s: %s"),
+              (int) s.length, s.string, fmt_name (f->type), error);
       free (error);
     }
   return out.f;
@@ -677,17 +770,31 @@ absorb_miss no_opt no_abbrev string function VALUELABEL (var v)
 
 // Artificial.
 operator SQUARE (x) = x * x;
-boolean operator NUM_TO_BOOLEAN (x)
+absorb_miss boolean operator NUM_TO_BOOLEAN (x)
+  expression e;
+  expr_node n;
 {
   if (x == 0. || x == 1. || x == SYSMIS)
     return x;
 
-  msg (SE, _("A logical expression was found to have a value other than 0 "
-             "(false), 1 (true), or the system-missing value.  The result "
-             "was forced to 0."));
+  msg_at (SE, expr_location (e, n),
+          _("This logical expression must evaluate to 0 or 1.  "
+            "Treating unexpected value %g as 0."), x);
   return 0.;
 }
 
+operator NUM_TO_INTEGER (x)
+  expression e;
+  expr_node n;
+{
+  if (x == floor (x) && x > INT_MIN && x <= INT_MAX)
+    return x;
+
+  msg_at (SE, expr_location (e, n),
+          _("Treating unexpected non-integer value %g as missing."), x);
+  return SYSMIS;
+}
+
 operator BOOLEAN_TO_NUM (boolean x) = x;
 
 // Beta distribution.
@@ -968,6 +1075,8 @@ no_opt boolean function VALUE (num_var v)
 no_opt operator VEC_ELEM_NUM (idx)
      vector v;
      case c;
+     expression e;
+     expr_node n;
 {
   if (idx >= 1 && idx <= vector_get_n_vars (v))
     {
@@ -978,13 +1087,15 @@ no_opt operator VEC_ELEM_NUM (idx)
   else
     {
       if (idx == SYSMIS)
-        msg (SE, _("SYSMIS is not a valid index value for vector "
+        msg_at (SE, expr_location (e, n->args[0]),
+                _("SYSMIS is not a valid index value for %zu-element vector "
                    "%s.  The result will be set to SYSMIS."),
-             vector_get_name (v));
+                vector_get_n_vars (v), vector_get_name (v));
       else
-        msg (SE, _("%g is not a valid index value for vector %s.  "
-                   "The result will be set to SYSMIS."),
-             idx, vector_get_name (v));
+        msg_at (SE, expr_location (e, n->args[0]),
+                _("%g is not a valid index value for %zu-element vector %s.  "
+                  "The result will be set to SYSMIS."),
+                idx, vector_get_n_vars (v), vector_get_name (v));
       return SYSMIS;
     }
 }
@@ -993,6 +1104,7 @@ absorb_miss no_opt string operator VEC_ELEM_STR (idx)
      expression e;
      vector v;
      case c;
+     expr_node n;
 {
   if (idx >= 1 && idx <= vector_get_n_vars (v))
     {
@@ -1003,13 +1115,15 @@ absorb_miss no_opt string operator VEC_ELEM_STR (idx)
   else
     {
       if (idx == SYSMIS)
-        msg (SE, _("SYSMIS is not a valid index value for vector "
+        msg_at (SE, expr_location (e, n->args[0]),
+                _("SYSMIS is not a valid index value for %zu-element vector "
                    "%s.  The result will be set to the empty string."),
-             vector_get_name (v));
+                vector_get_n_vars (v), vector_get_name (v));
       else
-        msg (SE, _("%g is not a valid index value for vector %s.  "
-                   "The result will be set to the empty string."),
-             idx, vector_get_name (v));
+        msg_at (SE, expr_location (e, n->args[0]),
+                _("%g is not a valid index value for %zu-element vector %s.  "
+                  "The result will be set to the empty string."),
+                idx, vector_get_n_vars (v), vector_get_name (v));
       return empty_string;
     }
 }