better tests
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 23 Dec 2021 23:58:21 +0000 (15:58 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 23 Dec 2021 23:58:21 +0000 (15:58 -0800)
src/language/expressions/evaluate.c
src/language/expressions/generate.py
src/language/expressions/operations.def
src/language/expressions/optimize.c
src/language/expressions/parse.c
src/language/expressions/private.h
tests/language/expressions/evaluate.at

index 10d239841e2a5371f7c5d36dda4c42f0639014dd..bdd21e1dbe97ae98579ba1f5d24372b14ac34b06 100644 (file)
@@ -108,12 +108,15 @@ expr_evaluate_str (struct expression *e, const struct ccase *c, int case_idx,
 #include "language/lexer/lexer.h"
 #include "language/command.h"
 
+static bool default_optimize = true;
+
 int
 cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
 {
-  bool optimize = true;
+  bool optimize = default_optimize;
   int retval = CMD_FAILURE;
   bool dump_postfix = false;
+  bool set_defaults = false;
 
   struct ccase *c = NULL;
 
@@ -128,9 +131,13 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
     {
       struct dictionary *d = NULL;
       if (lex_match_id (lexer, "NOOPTIMIZE"))
-        optimize = 0;
+        optimize = false;
+      else if (lex_match_id (lexer, "OPTIMIZE"))
+        optimize = true;
       else if (lex_match_id (lexer, "POSTFIX"))
         dump_postfix = 1;
+      else if (lex_match_id (lexer, "SET"))
+        set_defaults = true;
       else if (lex_match (lexer, T_LPAREN))
         {
           struct variable *v;
@@ -184,6 +191,13 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
         break;
     }
 
+  if (set_defaults)
+    {
+      retval = CMD_SUCCESS;
+      default_optimize = optimize;
+      goto done;
+    }
+
   if (!lex_force_match (lexer, T_SLASH))
     goto done;
 
@@ -303,7 +317,7 @@ expr_debug_print_postfix (const struct expression *e)
         case OP_integer:
           ds_put_format (&s, "i<%d>", op->integer);
           break;
-        case OP_exprnode:
+        case OP_expr_node:
           ds_put_cstr (&s, "expr_node");
           break;
         default:
index ed041f7efd1699fc9e74fe36c1a397053a4499ae..d989a14e390f001f882acadeacddcd76b6a09169 100644 (file)
@@ -73,9 +73,12 @@ def init_all_types():
         Type.new_leaf('vector', 'const struct vector *',
                       'vector', 'v', 'vector'),
 
+        # Types as leaves or auxiliary data.
+        Type.new_leaf('expr_node', 'const struct expr_node *',
+                      'expr_node', 'e', 'expr_node'),
+
         # Types that appear only as auxiliary data.
         Type.new_auxonly('expression', 'struct expression *', 'e'),
-        Type.new_auxonly('expr_node', 'const struct expr_node *', 'n'),
         Type.new_auxonly('case', 'const struct ccase *', 'c'),
         Type.new_auxonly('case_idx', 'size_t', 'case_idx'),
         Type.new_auxonly('dataset', 'struct dataset *', 'ds'),
@@ -88,7 +91,6 @@ def init_all_types():
 
         # Used only for debugging purposes.
         Type.new_atom('operation'),
-        Type.new_atom('exprnode'),
     ]:
         types[t.name] = t
 
@@ -120,14 +122,14 @@ class Type:
 
         'c_type' is the type used for C objects of this type.
 
+        'atom' should be the name of the member of "union
+        operation_data" that holds a value of this type.
+
         'mangle' should be a short string for name mangling purposes,
         to allow overloading functions with the same name but
         different argument types.  Use the same 'mangle' for two
         different types if those two types should not be overloaded.
 
-        'atom' should be the name of the member of "union
-        operation_data" that holds a value of this type.
-
         'human_name' should be a name to use when describing this type
         to the user (see Op.prototype()).
 
@@ -891,10 +893,7 @@ def generate_optimize_inc():
         for aux in op.aux:
             type_ = aux['TYPE']
             if type_.role == 'leaf':
-                func = 'get_%s_arg' % type_.atom
-                args += '%s (node, %s)' % (func, arg_idx)
-                arg_idx += 1
-            elif type_.name == 'expr_node':
+                assert type_.name == 'expr_node'
                 args += ['node']
             elif type_.role == 'auxonly':
                 args += [type_.auxonly_value]
index cbdc247c56162ee75738d6a2a751f21f517f11eb..7360f426c100816fa44da84a157916886018a39f 100644 (file)
@@ -770,7 +770,23 @@ absorb_miss no_opt no_abbrev string function VALUELABEL (var v)
 
 // Artificial.
 operator SQUARE (x) = x * x;
-absorb_miss boolean operator NUM_TO_BOOLEAN (x)
+
+absorb_miss boolean operator OPERAND_TO_BOOLEAN (x, expr_node parent)
+  expression e;
+  expr_node n;
+{
+  if (x == 0. || x == 1. || x == SYSMIS)
+    return x;
+
+  msg_at (SE, expr_location (e, parent),
+          _("The operands of %s must have value 0 or 1."),
+          operations[parent->type].name);
+  msg_at (SN, expr_location (e, n),
+          _("This operand with unexpected value %g will be treated as 0."), x);
+  return 0.;
+}
+
+absorb_miss boolean operator EXPR_TO_BOOLEAN (x)
   expression e;
   expr_node n;
 {
@@ -778,8 +794,8 @@ absorb_miss boolean operator NUM_TO_BOOLEAN (x)
     return x;
 
   msg_at (SE, expr_location (e, n),
-          _("This logical expression must evaluate to 0 or 1.  "
-            "Treating unexpected value %g as 0."), x);
+          _("This expression, which must be 0 or 1, evaluated to %g.  "
+            "It will be treated as 0."), x);
   return 0.;
 }
 
index 30c3a89a1031b87d6b28e9ba55e1040bdc347c48..7d683d0181f55d5dcff4355eaadc0d4548d76c5f 100644 (file)
@@ -67,26 +67,34 @@ expr_optimize (struct expr_node *node, struct expression *e)
     }
 
   op = &operations[node->type];
+
+  struct expr_node *new;
   if (n_sysmis && (op->flags & OPF_ABSORB_MISS) == 0)
     {
       /* Most operations produce SYSMIS given any SYSMIS
          argument. */
       assert (op->returns == OP_number || op->returns == OP_boolean);
-      if (op->returns == OP_number)
-        return expr_allocate_number (e, SYSMIS);
-      else
-        return expr_allocate_boolean (e, SYSMIS);
+      new = (op->returns == OP_number
+             ? expr_allocate_number (e, SYSMIS)
+             : expr_allocate_boolean (e, SYSMIS));
     }
   else if (!n_nonconst && (op->flags & OPF_NONOPTIMIZABLE) == 0)
     {
       /* Evaluate constant expressions. */
-      return evaluate_tree (node, e);
+      new = evaluate_tree (node, e);
     }
   else
     {
       /* A few optimization possibilities are still left. */
-      return optimize_tree (node, e);
+      new = optimize_tree (node, e);
     }
+
+  if (new != node && !new->location)
+    {
+      const struct msg_location *loc = expr_location (e, node);
+      new->location = CONST_CAST (struct msg_location *, loc);
+    }
+  return new;
 }
 
 static int
@@ -185,6 +193,14 @@ get_format_arg (struct expr_node *n, size_t arg_idx)
   return &n->args[arg_idx]->format;
 }
 
+static const struct expr_node *
+get_expr_node_arg (struct expr_node *n, size_t arg_idx)
+{
+  assert (arg_idx < n->n_args);
+  assert (n->args[arg_idx]->type == OP_expr_node);
+  return n->args[arg_idx]->expr_node;
+}
+
 static struct expr_node *
 evaluate_tree (struct expr_node *node, struct expression *e)
 {
@@ -279,6 +295,7 @@ flatten_atom (struct expr_node *n, struct expression *e)
     case OP_no_format:
     case OP_ni_format:
     case OP_pos_int:
+    case OP_expr_node:
       /* These are passed as aux data following the
          operation. */
       break;
@@ -323,6 +340,10 @@ flatten_composite (struct expr_node *n, struct expression *e)
           emit_integer (e, arg->integer);
           break;
 
+        case OP_expr_node:
+          allocate_aux (e, OP_expr_node)->expr_node = arg->expr_node;
+          break;
+
         default:
           /* Nothing to do. */
           break;
@@ -334,7 +355,7 @@ flatten_composite (struct expr_node *n, struct expression *e)
   if (op->flags & OPF_MIN_VALID)
     emit_integer (e, n->min_valid);
   if (op->flags & OPF_EXPR_NODE)
-    allocate_aux (e, OP_exprnode)->node = n;
+    allocate_aux (e, OP_expr_node)->expr_node = n;
 }
 
 void
index 7eccdac2b12810b28b29bd5d8aa9c7016a47fa08..5a81f6bd3ef67ddf4c5f38015b6c14b077e37af5 100644 (file)
@@ -101,7 +101,8 @@ expr_parse_bool (struct lexer *lexer, struct dataset *ds)
 
   atom_type actual_type = expr_node_returns (n);
   if (actual_type == OP_number)
-    n = expr_allocate_unary (e, OP_NUM_TO_BOOLEAN, n);
+    n = expr_allocate_binary (e, OP_EXPR_TO_BOOLEAN, n,
+                              expr_allocate_expr_node (e, n));
   else if (actual_type != OP_boolean)
     {
       msg_at (SE, expr_location (e, n),
@@ -210,6 +211,7 @@ atom_type_stack (atom_type type)
     case OP_integer:
     case OP_pos_int:
     case OP_vector:
+    case OP_expr_node:
       return &not_on_stack;
 
     default:
@@ -449,7 +451,8 @@ type_coercion__ (struct expression *e, struct expr_node *node, size_t arg_idx,
         {
           /* Convert numeric to boolean. */
           if (do_coercion)
-            *argp = expr_allocate_unary (e, OP_NUM_TO_BOOLEAN, arg);
+            *argp = expr_allocate_binary (e, OP_OPERAND_TO_BOOLEAN, arg,
+                                          expr_allocate_expr_node (e, node));
           return true;
         }
       break;
@@ -1562,6 +1565,15 @@ expr_allocate_format (struct expression *e, const struct fmt_spec *format)
   return n;
 }
 
+struct expr_node *
+expr_allocate_expr_node (struct expression *e,
+                         const struct expr_node *expr_node)
+{
+  struct expr_node *n = pool_alloc (e->expr_pool, sizeof *n);
+  *n = (struct expr_node) { .type = OP_expr_node, .expr_node = expr_node };
+  return n;
+}
+
 /* Allocates a unary composite node that represents the value of
    variable V in expression E. */
 static struct expr_node *
index 19cac31be748b1fda85a2c5bae36346d4d5d28a7..235c2ecf207771ec0e8c6500f72cd965ebb7bac3 100644 (file)
@@ -117,6 +117,9 @@ struct expr_node
             struct expr_node **args; /* Arguments. */
             size_t min_valid;   /* Min valid array args to get valid result. */
           };
+
+        /* OP_exprnode. */
+        const struct expr_node *expr_node;
       };
   };
 
@@ -128,7 +131,7 @@ union operation_data
     const struct variable *variable;
     const struct vector *vector;
     struct fmt_spec *format;
-    const struct expr_node *node;
+    const struct expr_node *expr_node;
     int integer;
   };
 
@@ -172,6 +175,8 @@ struct expr_node *expr_allocate_variable (struct expression *e,
                                         const struct variable *);
 struct expr_node *expr_allocate_format (struct expression *e,
                                  const struct fmt_spec *);
+struct expr_node *expr_allocate_expr_node (struct expression *,
+                                           const struct expr_node *);
 struct expr_node *expr_allocate_vector (struct expression *e,
                                       const struct vector *);
 
index 2d3f361f67d3070530c35f86f1ea8b3f0c35aa54..8af9d3ca4dc62562a16a94d1bb4e3a6172b6ca8a 100644 (file)
@@ -81,54 +81,249 @@ for opt in '' 'NOOPT '; do
 done
 AT_CLEANUP
 
-CHECK_EXPR_EVAL([coercion to/from Boolean],
-  [[0 AND 1], [false]],
-  [[$true AND 1], [true]],
-  [[1 OR $false], [true]],
-  [[1 OR $sysmis], [true]],
-  [[2 OR $sysmis], [sysmis],
-   [error: DEBUG EVALUATE: An operand of the logical disjunction (`OR') operator was found to have a value other than 0 (false), 1 (true), or the system-missing value.  The result was forced to 0.]],
-  [[2 AND $sysmis], [false],
-   [error: DEBUG EVALUATE: An operand of the logical conjunction (`AND') operator was found to have a value other than 0 (false), 1 (true), or the system-missing value.  The result was forced to 0.]],
-  [['string' AND $sysmis], [error],
-   [error: DEBUG EVALUATE: Type mismatch while applying logical conjunction (`AND') operator: cannot convert string to boolean.]],
-  [[0 AND $sysmis], [false]],
-  [[(1>2) + 1], [1.00]],
-  [[$true + $false], [1.00]])
-
-CHECK_EXPR_EVAL([addition and subtraction],
-  [[1 + 2], [3.00]],
-  [[1 + $true], [2.00]],
-  [[$sysmis + 1], [sysmis]],
-  [[7676 + $sysmis], [sysmis]],
-  [[('foo') + 5], [error],
-   [error: DEBUG EVALUATE: Type mismatch while applying addition (`+') operator: cannot convert string to number.]],
-  dnl Arithmetic concatenation requires CONCAT:
-  [[('foo') + ('bar')], [error],
-   [error: DEBUG EVALUATE: Type mismatch while applying addition (`+') operator: cannot convert string to number.]],
-  dnl Lexical concatenation succeeds:
-  [['foo' + 'bar'], ["foobar"]],
-  [[1 +3 - 2 +4 -5], [1.00]],
-  [[1 - $true], [0.00]],
-  [[$true - 4/3], [-0.33]],
-  [['string' - 1e10], [error],
-   [error: DEBUG EVALUATE: Type mismatch while applying subtraction (`-') operator: cannot convert string to number.]],
-  [[9.5 - ''], [error],
-   [error: DEBUG EVALUATE: Type mismatch while applying subtraction (`-') operator: cannot convert string to number.]],
-  [[1 - 2], [-1.00]],
-  [[52 -23], [29.00]])
-
-CHECK_EXPR_EVAL([multiplication and division],
-  [[5 * 10], [50.00]],
-  [[10 * $true], [10.00]],
-  [[$true * 5], [5.00]],
-  [[1.5 * $true], [1.50]],
-  [[5 * $sysmis], [sysmis]],
-  [[$sysmis * 15], [sysmis]],
-  [[2 * 5 / 10], [1.00]],
-  [[1 / 2], [0.50]],
-  [[2 / 5], [0.40]],
-  [[12 / 3 / 2], [2.00]])
+AT_SETUP([expressions - coercion to and from Boolean])
+AT_KEYWORDS([expression expressions evaluate])
+AT_DATA([evaluate-base.sps], [
+DEBUG EVALUATE SET opt.
+DEBUG EVALUATE/0 AND 1.
+DEBUG EVALUATE/$true AND 1.
+DEBUG EVALUATE/1 OR $false.
+DEBUG EVALUATE/1 OR $sysmis.
+DEBUG EVALUATE/2 OR $sysmis.
+DEBUG EVALUATE/1 AND 3.
+])
+
+for opt in OPT NOOPT; do
+    sed "s/opt/$opt/" < evaluate-base.sps > evaluate.sps
+    AT_CHECK([pspp --testing-mode evaluate.sps], [1], [dnl
+0 AND 1 => false
+
+$true AND 1 => true
+
+1 OR $false => true
+
+1 OR $sysmis => true
+
+evaluate.sps:7.16-7.27: error: DEBUG EVALUATE: The operands of OR must have
+value 0 or 1.
+    7 | DEBUG EVALUATE/2 OR $sysmis.
+      |                ^~~~~~~~~~~~
+
+evaluate.sps:7.16: note: DEBUG EVALUATE: This operand with unexpected value 2
+will be treated as 0.
+    7 | DEBUG EVALUATE/2 OR $sysmis.
+      |                ^
+
+2 OR $sysmis => sysmis
+
+evaluate.sps:8.16-8.22: error: DEBUG EVALUATE: The operands of AND must have
+value 0 or 1.
+    8 | DEBUG EVALUATE/1 AND 3.
+      |                ^~~~~~~
+
+evaluate.sps:8.22: note: DEBUG EVALUATE: This operand with unexpected value 3
+will be treated as 0.
+    8 | DEBUG EVALUATE/1 AND 3.
+      |                      ^
+
+1 AND 3 => false
+])
+done
+AT_CLEANUP
+
+AT_SETUP([expressions - addition and subtraction])
+AT_KEYWORDS([expression expressions evaluate])
+AT_DATA([evaluate-base.sps], [
+DEBUG EVALUATE SET opt.
+DEBUG EVALUATE /1 + $true.
+DEBUG EVALUATE /$sysmis + 1.
+DEBUG EVALUATE /7676 + $sysmis.
+DEBUG EVALUATE /1 +3 - 2 +4 - 5.
+DEBUG EVALUATE /$true - 4/3.
+DEBUG EVALUATE /1 - 2.
+DEBUG EVALUATE /52 -23.
+
+DEBUG EVALUATE /('foo') + 5.
+DEBUG EVALUATE /('foo') + ('bar').   /* Concatenation requires CONCAT.
+DEBUG EVALUATE /'foo' + 'bar'.       /* Lexical concatenation succeeds.
+
+DEBUG EVALUATE /'string' - 1e10.
+DEBUG EVALUATE /9.5 - ''.
+
+DEBUG EVALUATE /F2.0 + 3.
+])
+
+for opt in OPT NOOPT; do
+    sed "s/opt/$opt/" < evaluate-base.sps > evaluate.sps
+    AT_CHECK([pspp --testing-mode evaluate.sps], [1], [dnl
+1 + $true => 2.00
+
+$sysmis + 1 => sysmis
+
+7676 + $sysmis => sysmis
+
+1 +3 - 2 +4 - 5 => 1.00
+
+$true - 4/3 => -0.33
+
+1 - 2 => -1.00
+
+52 -23 => 29.00
+
+evaluate.sps:11.18-11.27: error: DEBUG EVALUATE: Both operands of + must be
+numeric.
+   11 | DEBUG EVALUATE /('foo') + 5.
+      |                  ^~~~~~~~~~
+
+evaluate.sps:11.18-11.22: note: DEBUG EVALUATE: This operand has type 'string'.
+   11 | DEBUG EVALUATE /('foo') + 5.
+      |                  ^~~~~
+
+evaluate.sps:11.27: note: DEBUG EVALUATE: This operand has type 'number'.
+   11 | DEBUG EVALUATE /('foo') + 5.
+      |                           ^
+
+('foo') + 5 => error
+
+evaluate.sps:12.18-12.32: error: DEBUG EVALUATE: Both operands of + must be
+numeric.
+   12 | DEBUG EVALUATE /('foo') + ('bar').   /* Concatenation requires CONCAT.
+      |                  ^~~~~~~~~~~~~~~
+
+evaluate.sps:12.18-12.22: note: DEBUG EVALUATE: This operand has type 'string'.
+   12 | DEBUG EVALUATE /('foo') + ('bar').   /* Concatenation requires CONCAT.
+      |                  ^~~~~
+
+evaluate.sps:12.28-12.32: note: DEBUG EVALUATE: This operand has type 'string'.
+   12 | DEBUG EVALUATE /('foo') + ('bar').   /* Concatenation requires CONCAT.
+      |                            ^~~~~
+
+('foo') + ('bar') => error
+
+'foo' + 'bar' => "foobar"
+
+evaluate.sps:15.17-15.31: error: DEBUG EVALUATE: Both operands of - must be
+numeric.
+   15 | DEBUG EVALUATE /'string' - 1e10.
+      |                 ^~~~~~~~~~~~~~~
+
+evaluate.sps:15.17-15.24: note: DEBUG EVALUATE: This operand has type 'string'.
+   15 | DEBUG EVALUATE /'string' - 1e10.
+      |                 ^~~~~~~~
+
+evaluate.sps:15.26-15.31: note: DEBUG EVALUATE: This operand has type 'number'.
+   15 | DEBUG EVALUATE /'string' - 1e10.
+      |                          ^~~~~~
+
+'string' - 1e10 => error
+
+evaluate.sps:16.17-16.24: error: DEBUG EVALUATE: Both operands of - must be
+numeric.
+   16 | DEBUG EVALUATE /9.5 - ''.
+      |                 ^~~~~~~~
+
+evaluate.sps:16.17-16.19: note: DEBUG EVALUATE: This operand has type 'number'.
+   16 | DEBUG EVALUATE /9.5 - ''.
+      |                 ^~~
+
+evaluate.sps:16.23-16.24: note: DEBUG EVALUATE: This operand has type 'string'.
+   16 | DEBUG EVALUATE /9.5 - ''.
+      |                       ^~
+
+9.5 - '' => error
+
+evaluate.sps:18.17-18.24: error: DEBUG EVALUATE: Both operands of + must be
+numeric.
+   18 | DEBUG EVALUATE /F2.0 + 3.
+      |                 ^~~~~~~~
+
+evaluate.sps:18.17-18.20: note: DEBUG EVALUATE: This operand has type 'format'.
+   18 | DEBUG EVALUATE /F2.0 + 3.
+      |                 ^~~~
+
+evaluate.sps:18.24: note: DEBUG EVALUATE: This operand has type 'number'.
+   18 | DEBUG EVALUATE /F2.0 + 3.
+      |                        ^
+
+F2.0 + 3 => error
+])
+done
+AT_CLEANUP
+
+AT_SETUP([expressions - multiplication and division])
+AT_KEYWORDS([expression expressions evaluate])
+AT_DATA([evaluate-base.sps], [
+DEBUG EVALUATE SET opt.
+DEBUG EVALUATE /5 * 10.
+DEBUG EVALUATE /10 * $true.
+DEBUG EVALUATE /$true * 5.
+DEBUG EVALUATE /1.5 * $true.
+DEBUG EVALUATE /$sysmis * 15.
+DEBUG EVALUATE /8.5 / $sysmis.
+DEBUG EVALUATE /2 * 5 / 10.
+DEBUG EVALUATE /1 / 2.
+DEBUG EVALUATE /2 / 5.
+DEBUG EVALUATE /12 / 3 / 2.
+
+DEBUG EVALUATE /'x' * 1.
+DEBUG EVALUATE /2 / 'x'.
+])
+
+for opt in OPT NOOPT; do
+    sed "s/opt/$opt/" < evaluate-base.sps > evaluate.sps
+    AT_CHECK([pspp --testing-mode evaluate.sps], [1], [dnl
+5 * 10 => 50.00
+
+10 * $true => 10.00
+
+$true * 5 => 5.00
+
+1.5 * $true => 1.50
+
+$sysmis * 15 => sysmis
+
+8.5 / $sysmis => sysmis
+
+2 * 5 / 10 => 1.00
+
+1 / 2 => 0.50
+
+2 / 5 => 0.40
+
+12 / 3 / 2 => 2.00
+
+evaluate.sps:14.17-14.23: error: DEBUG EVALUATE: Both operands of * must be
+numeric.
+   14 | DEBUG EVALUATE /'x' * 1.
+      |                 ^~~~~~~
+
+evaluate.sps:14.17-14.19: note: DEBUG EVALUATE: This operand has type 'string'.
+   14 | DEBUG EVALUATE /'x' * 1.
+      |                 ^~~
+
+evaluate.sps:14.23: note: DEBUG EVALUATE: This operand has type 'number'.
+   14 | DEBUG EVALUATE /'x' * 1.
+      |                       ^
+
+'x' * 1 => error
+
+evaluate.sps:15.17-15.23: error: DEBUG EVALUATE: Both operands of / must be
+numeric.
+   15 | DEBUG EVALUATE /2 / 'x'.
+      |                 ^~~~~~~
+
+evaluate.sps:15.17: note: DEBUG EVALUATE: This operand has type 'number'.
+   15 | DEBUG EVALUATE /2 / 'x'.
+      |                 ^
+
+evaluate.sps:15.21-15.23: note: DEBUG EVALUATE: This operand has type 'string'.
+   15 | DEBUG EVALUATE /2 / 'x'.
+      |                     ^~~
+
+2 / 'x' => error
+])
+done
+AT_CLEANUP
 
 CHECK_EXPR_EVAL([exponentiation],
   [[2**8], [256.00]],