lots of tests
[pspp] / src / language / expressions / generate.py
index d989a14e390f001f882acadeacddcd76b6a09169..ffe780a3c35ab9cbfdd07f016dcc857890605a06 100644 (file)
@@ -72,6 +72,8 @@ def init_all_types():
         # Vectors.
         Type.new_leaf('vector', 'const struct vector *',
                       'vector', 'v', 'vector'),
+        Type.new_any('num_vec_elem', 'double', 'number', 'n',
+                     'number', 'ns', 'SYSMIS'),
 
         # Types as leaves or auxiliary data.
         Type.new_leaf('expr_node', 'const struct expr_node *',
@@ -240,7 +242,7 @@ class Op:
             for arg in self.args:
                 arg_name = 'arg_%s' % arg.name
                 if arg.idx is None:
-                    if arg.type_.name in ['number', 'boolean']:
+                    if arg.type_.name in ['number', 'boolean', 'integer']:
                         sysmis_cond += ['!is_valid (%s)' % arg_name]
                 elif arg.type_.name == 'number':
                     a = arg_name
@@ -369,7 +371,7 @@ def parse_input():
         return_type = Type.parse()
         if return_type is None:
             return_type = types['number']
-        if return_type.name not in ['number', 'string', 'boolean']:
+        if return_type.name not in ['number', 'string', 'boolean', 'num_vec_elem']:
             die('%s is not a valid return type' % return_type.name)
 
         if token == 'operator':
@@ -673,17 +675,14 @@ class Arg:
 
 def print_header():
     """Prints the output file header."""
-    out_file.write("""\
-/* %s
-   Generated from %s by generate.py.
-   Do not modify! */
-
-""" % (out_file_name, in_file_name))
+    sys.stdout.write("""\
+/* Generated by generate.py. Do not modify! */
+""")
 
 
 def print_trailer():
     """Prints the output file trailer."""
-    out_file.write("""\
+    sys.stdout.write("""\
 
 /*
    Local Variables:
@@ -695,7 +694,7 @@ def print_trailer():
 
 
 def generate_evaluate_h():
-    out_file.write('#include "helpers.h"\n\n')
+    sys.stdout.write('#include "helpers.h"\n\n')
 
     for op in order:
         if op.unimplemented:
@@ -718,26 +717,34 @@ def generate_evaluate_h():
         else:
             statements = '  return %s;\n' % op.expression
 
-        out_file.write('static inline %s\n' % op.returns.c_type)
-        out_file.write('eval_%s (%s)\n' % (op.opname, ', '.join(args)))
-        out_file.write('{\n')
-        out_file.write(statements)
-        out_file.write('}\n\n')
+        sys.stdout.write('static inline %s\n' % op.returns.c_type)
+        sys.stdout.write('eval_%s (%s)\n' % (op.opname, ', '.join(args)))
+        sys.stdout.write('{\n')
+        sys.stdout.write(statements)
+        sys.stdout.write('}\n\n')
 
 
 def generate_evaluate_inc():
     for op in order:
         if op.unimplemented:
-            out_file.write('case %s:\n' % op.opname)
-            out_file.write('  NOT_REACHED ();\n\n')
+            sys.stdout.write('case %s:\n' % op.opname)
+            sys.stdout.write('  NOT_REACHED ();\n\n')
             continue
 
         decls = []
         args = []
         for arg in op.args:
             type_ = arg.type_
-            c_type = type_.c_type
-            args += ['arg_%s' % arg.name]
+            if type_.c_type == 'int ':
+                c_type = 'double '
+                if op.absorb_miss:
+                    args += ['arg_%s == SYSMIS ? INT_MIN : arg_%s'
+                             % (arg.name, arg.name)]
+                else:
+                    args += ['arg_%s' % arg.name]
+            else:
+                c_type = type_.c_type
+                args += ['arg_%s' % arg.name]
             if arg.idx is None:
                 decl = '%sarg_%s' % (c_type, arg.name)
                 if type_.role == 'any':
@@ -778,29 +785,29 @@ def generate_evaluate_inc():
 
         stack = op.returns.stack
 
-        out_file.write('case %s:\n' % op.opname)
+        sys.stdout.write('case %s:\n' % op.opname)
         if decls:
-            out_file.write('  {\n')
+            sys.stdout.write('  {\n')
             for decl in decls:
-                out_file.write('    %s;\n' % decl)
+                sys.stdout.write('    %s;\n' % decl)
             if sysmis_cond is not None:
                 miss_ret = op.returns.missing_value
-                out_file.write('    *%s++ = force_sysmis ? %s : %s;\n'
+                sys.stdout.write('    *%s++ = force_sysmis ? %s : %s;\n'
                                % (stack, miss_ret, result))
             else:
-                out_file.write('    *%s++ = %s;\n' % (stack, result))
-            out_file.write('  }\n')
+                sys.stdout.write('    *%s++ = %s;\n' % (stack, result))
+            sys.stdout.write('  }\n')
         else:
-            out_file.write('  *%s++ = %s;\n' % (stack, result))
-        out_file.write('  break;\n\n')
+            sys.stdout.write('  *%s++ = %s;\n' % (stack, result))
+        sys.stdout.write('  break;\n\n')
 
 
 def generate_operations_h():
-    out_file.write('#include <stdlib.h>\n')
-    out_file.write('#include <stdbool.h>\n\n')
+    sys.stdout.write('#include <stdlib.h>\n')
+    sys.stdout.write('#include <stdbool.h>\n\n')
 
-    out_file.write('typedef enum')
-    out_file.write('  {\n')
+    sys.stdout.write('typedef enum')
+    sys.stdout.write('  {\n')
     atoms = []
     for type_ in types.values():
         if type_.role != 'auxonly':
@@ -812,10 +819,10 @@ def generate_operations_h():
     print_operations('operator', 'OP_function_last + 1',
                      [o.opname for o in opers])
     print_range('OP_composite', 'OP_function_first', 'OP_operator_last')
-    out_file.write(',\n\n')
+    sys.stdout.write(',\n\n')
     print_range('OP', 'OP_atom_first', 'OP_composite_last')
-    out_file.write('\n  }\n')
-    out_file.write('operation_type, atom_type;\n')
+    sys.stdout.write('\n  }\n')
+    sys.stdout.write('operation_type, atom_type;\n')
 
     print_predicate('is_operation', 'OP')
     for key in ('atom', 'composite', 'function', 'operator'):
@@ -823,37 +830,37 @@ def generate_operations_h():
 
 
 def print_operations(type_, first, names):
-    out_file.write('    /* %s types. */\n' % type_.title())
-    out_file.write('    %s = %s,\n' % (names[0], first))
+    sys.stdout.write('    /* %s types. */\n' % type_.title())
+    sys.stdout.write('    %s = %s,\n' % (names[0], first))
     for name in names[1:]:
-        out_file.write('    %s,\n' % name)
+        sys.stdout.write('    %s,\n' % name)
     print_range('OP_%s' % type_, names[0], names[-1])
-    out_file.write(',\n\n')
+    sys.stdout.write(',\n\n')
 
 
 def print_range(prefix, first, last):
-    out_file.write('    %s_first = %s,\n' % (prefix, first))
-    out_file.write('    %s_last = %s,\n' % (prefix, last))
-    out_file.write('    n_%s = %s_last - %s_first + 1'
+    sys.stdout.write('    %s_first = %s,\n' % (prefix, first))
+    sys.stdout.write('    %s_last = %s,\n' % (prefix, last))
+    sys.stdout.write('    n_%s = %s_last - %s_first + 1'
                    % (prefix, prefix, prefix))
 
 
 def print_predicate(function, category):
-    out_file.write('\nstatic inline bool\n')
-    out_file.write('%s (operation_type op)\n' % function)
-    out_file.write('{\n')
+    sys.stdout.write('\nstatic inline bool\n')
+    sys.stdout.write('%s (operation_type op)\n' % function)
+    sys.stdout.write('{\n')
     if function != 'is_operation':
-        out_file.write('  assert (is_operation (op));\n')
-    out_file.write('  return op >= %s_first && op <= %s_last;\n'
+        sys.stdout.write('  assert (is_operation (op));\n')
+    sys.stdout.write('  return op >= %s_first && op <= %s_last;\n'
                    % (category, category))
-    out_file.write('}\n')
+    sys.stdout.write('}\n')
 
 
 def generate_optimize_inc():
     for op in order:
         if not op.optimizable or op.unimplemented:
-            out_file.write('case %s:\n' % op.opname)
-            out_file.write('  NOT_REACHED ();\n\n')
+            sys.stdout.write('case %s:\n' % op.opname)
+            sys.stdout.write('  NOT_REACHED ();\n\n')
             continue
 
         decls = []
@@ -907,28 +914,28 @@ def generate_optimize_inc():
                       % (op.returns.c_type, miss_ret, result)]
             result = 'result'
 
-        out_file.write('case %s:\n' % op.opname)
+        sys.stdout.write('case %s:\n' % op.opname)
         alloc_func = 'expr_allocate_%s' % op.returns.name
         if decls:
-            out_file.write('  {\n')
+            sys.stdout.write('  {\n')
             for decl in decls:
-                out_file.write('    %s;\n' % decl)
-            out_file.write('    return %s (e, %s);\n' % (alloc_func, result))
-            out_file.write('  }\n')
+                sys.stdout.write('    %s;\n' % decl)
+            sys.stdout.write('    return %s (e, %s);\n' % (alloc_func, result))
+            sys.stdout.write('  }\n')
         else:
-            out_file.write('  return %s (e, %s);\n' % (alloc_func, result))
-        out_file.write('\n')
+            sys.stdout.write('  return %s (e, %s);\n' % (alloc_func, result))
+        sys.stdout.write('\n')
 
 
 def generate_parse_inc():
     members = ['""', '""', '0', '0', '0', '{}', '0', '0']
-    out_file.write('{%s},\n' % ', '.join(members))
+    sys.stdout.write('{%s},\n' % ', '.join(members))
 
     for type_ in types.values():
         if type_.role != 'auxonly':
             members = ('"%s"' % type_.name, '"%s"' % type_.human_name,
                        '0', 'OP_%s' % type_.name, '0', '{}', '0', '0')
-            out_file.write('{%s},\n' % ', '.join(members))
+            sys.stdout.write('{%s},\n' % ', '.join(members))
 
     for op in order:
         members = []
@@ -950,15 +957,16 @@ def generate_parse_inc():
 
         members += ['%s' % (op.array_arg().times if op.array_arg() else 0)]
 
-        out_file.write('{%s},\n' % ', '.join(members))
+        sys.stdout.write('{%s},\n' % ', '.join(members))
 
 
 def usage():
     print("""\
 %s, for generating expression parsers and evaluators from definitions
-usage: generate.py -o OUTPUT [-i INPUT] [-h]
+usage: generate.py -o OUTPUT_TYPE [-i INPUT] [-h] > OUTPUT
   -i INPUT    input file containing definitions (default: operations.def)
-  -o OUTPUT   output file
+  -o OUTPUT   output file type, one of: evaluate.h, evaluate.inc,
+              operations.h, optimize.inc, parse.inc    
   -h          display this help message
 """ % argv0)
     sys.exit(0)
@@ -990,21 +998,20 @@ if __name__ == '__main__':
             '(use --help for help)' % argv0)
 
     in_file = open(in_file_name, 'r')
-    out_file = open(out_file_name, 'w')
 
     init_all_types()
     parse_input()
 
     print_header()
-    if out_file_name.endswith('evaluate.h'):
+    if out_file_name == 'evaluate.h':
         generate_evaluate_h()
-    elif out_file_name.endswith('evaluate.inc'):
+    elif out_file_name == 'evaluate.inc':
         generate_evaluate_inc()
-    elif out_file_name.endswith('operations.h'):
+    elif out_file_name == 'operations.h':
         generate_operations_h()
-    elif out_file_name.endswith('optimize.inc'):
+    elif out_file_name == 'optimize.inc':
         generate_optimize_inc()
-    elif out_file_name.endswith('parse.inc'):
+    elif out_file_name == 'parse.inc':
         generate_parse_inc()
     else:
         die('%s: unknown output type' % argv0)