Lichen

Changeset

850:6024d7e1d83a
2018-07-12 Paul Boddie raw files shortlog changelog graph Support trailing data after attributes in objects, employed by float instances to store their double-precision numeric data which needs more space than single attributes on some systems. In order to initialise such instances statically, specific object types must be indicated instead of the generic __obj type. This then requires casting to __ref of direct references to objects. Added an underflow error. Added initial testing of floating point numbers. trailing-data
encoders.py (file) generator.py (file) lib/__builtins__/core.py (file) lib/__builtins__/float.py (file) lib/native/__init__.py (file) lib/native/float.py (file) lib/native/int.py (file) templates/native/common.c (file) templates/native/common.h (file) templates/native/float.c (file) templates/native/float.h (file) templates/native/int.c (file) templates/native/int.h (file) templates/ops.c (file) templates/progops.c (file) templates/progops.h (file) templates/types.h (file) tests/numbers.py (file)
     1.1 --- a/encoders.py	Wed Jul 11 23:53:09 2018 +0200
     1.2 +++ b/encoders.py	Thu Jul 12 00:15:16 2018 +0200
     1.3 @@ -505,6 +505,15 @@
     1.4  
     1.5      return "__constvalue%s" % n
     1.6  
     1.7 +def encode_trailing_area(path):
     1.8 +
     1.9 +    """
    1.10 +    Encode any reference to trailing data members for instances of the type
    1.11 +    given by 'path'.
    1.12 +    """
    1.13 +
    1.14 +    return "__TRAILING_%s" % encode_path(path)
    1.15 +
    1.16  
    1.17  
    1.18  # Track all encoded paths, detecting and avoiding conflicts.
     2.1 --- a/generator.py	Wed Jul 11 23:53:09 2018 +0200
     2.2 +++ b/generator.py	Thu Jul 12 00:15:16 2018 +0200
     2.3 @@ -29,6 +29,7 @@
     2.4                       encode_path, encode_pcode, encode_pos, encode_ppos, \
     2.5                       encode_predefined_reference, encode_size, \
     2.6                       encode_symbol, encode_tablename, \
     2.7 +                     encode_trailing_area, \
     2.8                       encode_type_attribute, decode_type_attribute, \
     2.9                       is_type_attribute
    2.10  from os import listdir, mkdir, remove
    2.11 @@ -42,6 +43,7 @@
    2.12      # NOTE: These must be synchronised with the library.
    2.13  
    2.14      dict_type = "__builtins__.dict.dict"
    2.15 +    float_type = "__builtins__.float.float"
    2.16      function_type = "__builtins__.core.function"
    2.17      int_type = "__builtins__.int.int"
    2.18      list_type = "__builtins__.list.list"
    2.19 @@ -64,6 +66,12 @@
    2.20          dict_type, list_type, tuple_type
    2.21          )
    2.22  
    2.23 +    # Data types with a trailing data member of the given native types.
    2.24 +
    2.25 +    trailing_data_types = {
    2.26 +        float_type : "double",
    2.27 +        }
    2.28 +
    2.29      def __init__(self, importer, optimiser, output):
    2.30  
    2.31          """
    2.32 @@ -219,6 +227,7 @@
    2.33  
    2.34                  if kind != "<instance>":
    2.35                      structure = []
    2.36 +                    trailing = []
    2.37                      attrs = self.get_static_attributes(kind, path, attrnames)
    2.38  
    2.39                      # Set a special instantiator on the class.
    2.40 @@ -244,12 +253,13 @@
    2.41                          attrs["__args__"] = path
    2.42  
    2.43                      self.populate_structure(Reference(kind, path), attrs, kind, structure)
    2.44 +                    self.populate_trailing(Reference(kind, path), attrs, trailing)
    2.45  
    2.46                      if kind == "<class>":
    2.47                          self.write_instance_structure(f_decls, path, structure_size)
    2.48  
    2.49 -                    self.write_structure(f_decls, f_defs, path, table_name, structure,
    2.50 -                        kind == "<class>" and path)
    2.51 +                    self.write_structure(f_decls, f_defs, path, table_name,
    2.52 +                                         structure, trailing, ref)
    2.53  
    2.54                  # Record function instance details for function generation below.
    2.55  
    2.56 @@ -297,7 +307,7 @@
    2.57                  function_instance_attrs["__args__"] = path
    2.58  
    2.59                  structure = self.populate_function(path, function_instance_attrs)
    2.60 -                self.write_structure(f_decls, f_defs, path, table_name, structure)
    2.61 +                self.write_structure(f_decls, f_defs, path, table_name, structure, [], Reference("<function>", path))
    2.62  
    2.63                  # Functions with defaults need to declare instance structures.
    2.64  
    2.65 @@ -411,6 +421,12 @@
    2.66                                        self.optimiser.locations,
    2.67                                        "code", "pos", encode_code, encode_pos)
    2.68  
    2.69 +            # Generate trailing data macros of the form...
    2.70 +            # #define __TRAILING_typename nativetype trailing;
    2.71 +
    2.72 +            for name, member_type in self.trailing_data_types.items():
    2.73 +                print >>f_consts, "#define %s %s trailing;" % (encode_symbol("TRAILING", name), member_type)
    2.74 +
    2.75              # Generate macros for calls.
    2.76  
    2.77              all_max_parameters = list(all_max_parameters)
    2.78 @@ -617,7 +633,16 @@
    2.79          # Set the data, if provided.
    2.80  
    2.81          if data is not None:
    2.82 -            attrs["__data__"] = data
    2.83 +
    2.84 +            # Data retained by special attribute.
    2.85 +
    2.86 +            if attrs.has_key("__data__"):
    2.87 +                attrs["__data__"] = data
    2.88 +
    2.89 +            # Data retained by a trailing data area.
    2.90 +
    2.91 +            elif attrs.has_key("__trailing__"):
    2.92 +                attrs["__trailing__"] = data
    2.93  
    2.94              # Also set a key for dynamic attribute lookup, if a string.
    2.95  
    2.96 @@ -658,9 +683,12 @@
    2.97          # the constant in the program.
    2.98  
    2.99          structure = []
   2.100 +        trailing = []
   2.101          table_name = encode_tablename("<instance>", cls)
   2.102          self.populate_structure(ref, attrs, ref.get_kind(), structure)
   2.103 -        self.write_structure(f_decls, f_defs, structure_name, table_name, structure)
   2.104 +        self.populate_trailing(ref, attrs, trailing)
   2.105 +        self.write_structure(f_decls, f_defs, structure_name, table_name,
   2.106 +                             structure, trailing, ref)
   2.107  
   2.108          # Define a macro for the constant.
   2.109  
   2.110 @@ -819,38 +847,51 @@
   2.111          # Write an instance-specific type definition for instances of classes.
   2.112          # See: templates/types.h
   2.113  
   2.114 +        trailing_area = path in self.trailing_data_types and encode_trailing_area(path) or ""
   2.115 +
   2.116          print >>f_decls, """\
   2.117  typedef struct {
   2.118      const __table * table;
   2.119      __pos pos;
   2.120      __attr attrs[%s];
   2.121 +%s
   2.122  } %s;
   2.123 -""" % (structure_size, encode_symbol("obj", path))
   2.124 +""" % (structure_size, trailing_area, encode_symbol("obj", path))
   2.125  
   2.126 -    def write_structure(self, f_decls, f_defs, structure_name, table_name, structure, path=None):
   2.127 +    def write_structure(self, f_decls, f_defs, structure_name, table_name,
   2.128 +                        structure, trailing, ref):
   2.129  
   2.130          """
   2.131          Write the declarations to 'f_decls' and definitions to 'f_defs' for
   2.132          the object having the given 'structure_name', the given 'table_name',
   2.133 -        and the given 'structure' details used to populate the definition.
   2.134 +        the given 'structure' details and any 'trailing' member details, used to
   2.135 +        populate the definition.
   2.136          """
   2.137  
   2.138 +        origin = ref.get_origin()
   2.139 +        pos = ref.has_kind("<class>") and encode_pos(encode_type_attribute(origin)) or str(self.instancepos)
   2.140 +
   2.141 +        obj_type = ref.has_kind("<instance>") and encode_symbol("obj", origin) or "__obj"
   2.142 +        obj_name = encode_path(structure_name)
   2.143 +
   2.144          if f_decls:
   2.145 -            print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name)
   2.146 -
   2.147 -        is_class = path and self.importer.get_object(path).has_kind("<class>")
   2.148 -        pos = is_class and encode_pos(encode_type_attribute(path)) or str(self.instancepos)
   2.149 +            print >>f_decls, "extern %s %s;\n" % (obj_type, obj_name)
   2.150  
   2.151          print >>f_defs, """\
   2.152 -__obj %s = {
   2.153 +%s %s = {
   2.154      &%s,
   2.155      %s,
   2.156      {
   2.157          %s
   2.158 -    }};
   2.159 +    },
   2.160 +    %s
   2.161 +    };
   2.162  """ % (
   2.163 -            encode_path(structure_name), table_name, pos,
   2.164 -            ",\n        ".join(structure))
   2.165 +            obj_type, obj_name,
   2.166 +            table_name,
   2.167 +            pos,
   2.168 +            ",\n        ".join(structure),
   2.169 +            trailing and ",\n    ".join(trailing) or "")
   2.170  
   2.171      def get_argument_limits(self, path):
   2.172  
   2.173 @@ -910,6 +951,12 @@
   2.174                  continue
   2.175              const = consts.get(attrname)
   2.176              attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname))
   2.177 +
   2.178 +        # Instances with trailing data.
   2.179 +
   2.180 +        if name in self.trailing_data_types:
   2.181 +            attrs["__trailing__"] = Reference("<var>", "%s.__trailing__" % name)
   2.182 +
   2.183          return attrs
   2.184  
   2.185      def populate_table(self, path, table):
   2.186 @@ -1101,6 +1148,21 @@
   2.187  
   2.188                  structure.append(self.encode_member(origin, attrname, attr, kind))
   2.189  
   2.190 +    def populate_trailing(self, ref, attrs, trailing):
   2.191 +
   2.192 +        """
   2.193 +        For the structure having the given 'ref', whose members are provided by
   2.194 +        the 'attrs' mapping, adding entries to the 'trailing' member collection.
   2.195 +        """
   2.196 +
   2.197 +        structure_ref = self.get_target_structure(ref)
   2.198 +
   2.199 +        # Instances with trailing data.
   2.200 +
   2.201 +        if structure_ref.get_kind() == "<instance>" and \
   2.202 +           structure_ref.get_origin() in self.trailing_data_types:
   2.203 +            trailing.append(encode_literal_constant_value(attrs["__trailing__"]))
   2.204 +
   2.205      def get_target_structure(self, ref):
   2.206  
   2.207          "Return the target structure type and reference for 'ref'."
   2.208 @@ -1154,22 +1216,22 @@
   2.209  
   2.210          if kind == "<instance>" and origin == self.none_type:
   2.211              attr_path = encode_predefined_reference(self.none_value)
   2.212 -            return "{.value=&%s} /* %s */" % (attr_path, name)
   2.213 +            return "{.value=(__ref) &%s} /* %s */" % (attr_path, name)
   2.214  
   2.215          # Predefined constant members.
   2.216  
   2.217          if (path, name) in self.predefined_constant_members:
   2.218              attr_path = encode_predefined_reference("%s.%s" % (path, name))
   2.219 -            return "{.value=&%s} /* %s */" % (attr_path, name)
   2.220 +            return "{.value=(__ref) &%s} /* %s */" % (attr_path, name)
   2.221  
   2.222          # General undetermined members.
   2.223  
   2.224          if kind in ("<var>", "<instance>"):
   2.225              attr_path = encode_predefined_reference(self.none_value)
   2.226 -            return "{.value=&%s} /* %s */" % (attr_path, name)
   2.227 +            return "{.value=(__ref) &%s} /* %s */" % (attr_path, name)
   2.228  
   2.229          else:
   2.230 -            return "{.value=&%s}" % encode_path(origin)
   2.231 +            return "{.value=(__ref) &%s}" % encode_path(origin)
   2.232  
   2.233      def append_defaults(self, path, structure):
   2.234  
     3.1 --- a/lib/__builtins__/core.py	Wed Jul 11 23:53:09 2018 +0200
     3.2 +++ b/lib/__builtins__/core.py	Thu Jul 12 00:15:16 2018 +0200
     3.3 @@ -3,7 +3,7 @@
     3.4  """
     3.5  Core objects.
     3.6  
     3.7 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     3.8 +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
     3.9  
    3.10  This program is free software; you can redistribute it and/or modify it under
    3.11  the terms of the GNU General Public License as published by the Free Software
    3.12 @@ -189,6 +189,15 @@
    3.13  
    3.14      pass
    3.15  
    3.16 +class UnderflowError(ArithmeticError):
    3.17 +
    3.18 +    """
    3.19 +    Indicates that an arithmetic operation produced a result that could not be
    3.20 +    represented.
    3.21 +    """
    3.22 +
    3.23 +    pass
    3.24 +
    3.25  class ZeroDivisionError(ArithmeticError):
    3.26  
    3.27      "An error occurring when an attempt was made to divide an operand by zero."
     4.1 --- a/lib/__builtins__/float.py	Wed Jul 11 23:53:09 2018 +0200
     4.2 +++ b/lib/__builtins__/float.py	Thu Jul 12 00:15:16 2018 +0200
     4.3 @@ -1,9 +1,9 @@
     4.4  #!/usr/bin/env python
     4.5  
     4.6  """
     4.7 -Floating point objects.
     4.8 +Floating point number objects.
     4.9  
    4.10 -Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
    4.11 +Copyright (C) 2015, 2016, 2018 Paul Boddie <paul@boddie.org.uk>
    4.12  
    4.13  This program is free software; you can redistribute it and/or modify it under
    4.14  the terms of the GNU General Public License as published by the Free Software
    4.15 @@ -19,36 +19,189 @@
    4.16  this program.  If not, see <http://www.gnu.org/licenses/>.
    4.17  """
    4.18  
    4.19 +from __builtins__.unicode import utf8string
    4.20 +from native import isinstance as _isinstance, \
    4.21 +                   int_float, is_int, \
    4.22 +                   float_add, float_div, float_eq, float_ge, float_gt, \
    4.23 +                   float_le, float_lt, float_mod, float_mul, float_ne, \
    4.24 +                   float_neg, float_pow, float_str, float_sub, 
    4.25 +
    4.26  class float:
    4.27 +
    4.28 +    "A floating point number abstraction."
    4.29 +
    4.30      def __init__(self, number_or_string=None):
    4.31 -        # Note member.
    4.32 -        self.__data__ = 0.0
    4.33 +
    4.34 +        "Initialise the integer with the given 'number_or_string'."
    4.35 +
    4.36 +        # NOTE: To be implemented.
    4.37 +
    4.38 +        pass
    4.39 +
    4.40 +    def __hash__(self):
    4.41 +
    4.42 +        "Return a value for hashing purposes."
    4.43 +
    4.44 +        return self
    4.45 +
    4.46 +    def _binary_op(self, op, other):
    4.47 +
    4.48 +        "Perform 'op' on this float and 'other' if appropriate."
    4.49 +
    4.50 +        if _isinstance(other, float):
    4.51 +            return op(self, other)
    4.52 +        elif is_int(other):
    4.53 +            return op(self, int_float(other))
    4.54 +        else:
    4.55 +            return NotImplemented
    4.56 +
    4.57 +    def _binary_op_rev(self, op, other):
    4.58 +
    4.59 +        "Perform 'op' on 'other' and this float if appropriate."
    4.60 +
    4.61 +        if _isinstance(other, float):
    4.62 +            return op(other, self)
    4.63 +        elif is_int(other):
    4.64 +            return op(int_float(other), self)
    4.65 +        else:
    4.66 +            return NotImplemented
    4.67 +
    4.68 +    def __iadd__(self, other):
    4.69 +
    4.70 +        "Return a new float for the addition of this float and 'other'."
    4.71  
    4.72 -    def __iadd__(self, other): pass
    4.73 -    def __isub__(self, other): pass
    4.74 -    def __add__(self, other): pass
    4.75 -    def __radd__(self, other): pass
    4.76 -    def __sub__(self, other): pass
    4.77 -    def __rsub__(self, other): pass
    4.78 -    def __mul__(self, other): pass
    4.79 -    def __rmul__(self, other): pass
    4.80 -    def __div__(self, other): pass
    4.81 -    def __rdiv__(self, other): pass
    4.82 +        return self._binary_op(float_add, other)
    4.83 +
    4.84 +    def __isub__(self, other):
    4.85 +
    4.86 +        "Return a new float for the subtraction from this float of 'other'."
    4.87 +
    4.88 +        return self._binary_op(float_sub, other)
    4.89 +
    4.90 +    def __imul__(self, other):
    4.91 +
    4.92 +        "Return a new float for the multiplication of this float and 'other'."
    4.93 +
    4.94 +        return self._binary_op(float_mul, other)
    4.95 +
    4.96 +    def __idiv__(self, other):
    4.97 +
    4.98 +        "Return a new float for the division of this float by 'other'."
    4.99 +
   4.100 +        return self._binary_op(float_div, other)
   4.101 +
   4.102 +    def __imod__(self, other):
   4.103 +
   4.104 +        "Return a new float for the modulo of this float by 'other'."
   4.105 +
   4.106 +        return self._binary_op(float_mod, other)
   4.107 +
   4.108 +    def __ipow__(self, other):
   4.109 +
   4.110 +        "Return a new float for the exponentiation of this float by 'other'."
   4.111 +
   4.112 +        return self._binary_op(float_pow, other)
   4.113 +
   4.114 +    __add__ = __radd__ = __iadd__
   4.115 +    __sub__ = __isub__
   4.116 +
   4.117 +    def __rsub__(self, other):
   4.118 +
   4.119 +        "Return a new float for the subtraction of this float from 'other'."
   4.120 +
   4.121 +        return self._binary_op_rev(float_sub, other)
   4.122 +
   4.123 +    __mul__ = __rmul__ = __imul__
   4.124 +    __div__ = __idiv__
   4.125 +
   4.126 +    def __rdiv__(self, other):
   4.127 +
   4.128 +        "Return a new float for the division of 'other' by this float."
   4.129 +
   4.130 +        return self._binary_op_rev(float_div, other)
   4.131 +
   4.132 +    # NOTE: To be implemented.
   4.133 +
   4.134      def __floordiv__(self, other): pass
   4.135      def __rfloordiv__(self, other): pass
   4.136 -    def __mod__(self, other): pass
   4.137 -    def __rmod__(self, other): pass
   4.138 -    def __pow__(self, other): pass
   4.139 -    def __rpow__(self, other): pass
   4.140 -    def __lt__(self, other): pass
   4.141 -    def __gt__(self, other): pass
   4.142 -    def __le__(self, other): pass
   4.143 -    def __ge__(self, other): pass
   4.144 -    def __eq__(self, other): pass
   4.145 -    def __ne__(self, other): pass
   4.146 -    def __neg__(self): pass
   4.147 -    def __pos__(self): pass
   4.148 -    def __str__(self): pass
   4.149 -    def __bool__(self): pass
   4.150 +    def __ifloordiv__(self, other): pass
   4.151 +
   4.152 +    __mod__ = __imod__
   4.153 +
   4.154 +    def __rmod__(self, other):
   4.155 +
   4.156 +        "Return a new float for the modulo of 'other' by this float."
   4.157 +
   4.158 +        return self._binary_op_rev(float_mod, other)
   4.159 +
   4.160 +    __pow__ = __ipow__
   4.161 +
   4.162 +    def __rpow__(self, other):
   4.163 +
   4.164 +        "Return a new float for the exponentiation of 'other' by this float."
   4.165 +
   4.166 +        return self._binary_op_rev(float_pow, other)
   4.167 +
   4.168 +    def __lt__(self, other):
   4.169 +
   4.170 +        "Return whether this float is less than 'other'."
   4.171 +
   4.172 +        return self._binary_op(float_lt, other)
   4.173 +
   4.174 +    def __gt__(self, other):
   4.175 +
   4.176 +        "Return whether this float is greater than 'other'."
   4.177 +
   4.178 +        return self._binary_op(float_gt, other)
   4.179 +
   4.180 +    def __le__(self, other):
   4.181 +
   4.182 +        "Return whether this float is less than or equal to 'other'."
   4.183 +
   4.184 +        return self._binary_op(float_le, other)
   4.185 +
   4.186 +    def __ge__(self, other):
   4.187 +
   4.188 +        "Return whether this float is greater than or equal to 'other'."
   4.189 +
   4.190 +        return self._binary_op(float_ge, other)
   4.191 +
   4.192 +    def __eq__(self, other):
   4.193 +
   4.194 +        "Return whether this float is equal to 'other'."
   4.195 +
   4.196 +        return self._binary_op(float_eq, other)
   4.197 +
   4.198 +    def __ne__(self, other):
   4.199 +
   4.200 +        "Return whether this float is not equal to 'other'."
   4.201 +
   4.202 +        return self._binary_op(float_ne, other)
   4.203 +
   4.204 +    def __neg__(self):
   4.205 +
   4.206 +        "Apply the unary negation operator."
   4.207 +
   4.208 +        return float_neg(self)
   4.209 +
   4.210 +    def __pos__(self):
   4.211 +
   4.212 +        "Apply the unary positive operator."
   4.213 +
   4.214 +        return self
   4.215 +
   4.216 +    def __str__(self):
   4.217 +
   4.218 +        "Return a string representation."
   4.219 +
   4.220 +        return utf8string(float_str(self))
   4.221 +
   4.222 +    __repr__ = __str__
   4.223 +
   4.224 +    def __bool__(self):
   4.225 +
   4.226 +        "Return whether this float is non-zero."
   4.227 +
   4.228 +        return float_ne(self, 0)
   4.229  
   4.230  # vim: tabstop=4 expandtab shiftwidth=4
     5.1 --- a/lib/native/__init__.py	Wed Jul 11 23:53:09 2018 +0200
     5.2 +++ b/lib/native/__init__.py	Thu Jul 12 00:15:16 2018 +0200
     5.3 @@ -3,7 +3,7 @@
     5.4  """
     5.5  Native library functions.
     5.6  
     5.7 -Copyright (C) 2011, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     5.8 +Copyright (C) 2011, 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
     5.9  
    5.10  This program is free software; you can redistribute it and/or modify it under
    5.11  the terms of the GNU General Public License as published by the Free Software
    5.12 @@ -21,13 +21,19 @@
    5.13  
    5.14  from native.buffer import buffer_str
    5.15  
    5.16 +from native.float import float_add, float_div, float_mod, float_mul, \
    5.17 +                         float_neg, float_pow, float_sub, \
    5.18 +                         float_eq, float_ge, float_gt, float_le, float_lt, \
    5.19 +                         float_ne, \
    5.20 +                         float_int, float_str
    5.21 +
    5.22  from native.identity import is_, is_not
    5.23  
    5.24  from native.int import int_add, int_div, int_mod, int_mul, int_neg, int_pow, \
    5.25                         int_sub, int_and, int_not, int_or, int_xor, \
    5.26                         int_lshift, int_rshift, \
    5.27                         int_eq, int_ge, int_gt, int_le, int_lt, int_ne, \
    5.28 -                       int_str, is_int
    5.29 +                       int_float, int_str, is_int
    5.30  
    5.31  from native.introspection import object_getattr, isinstance, issubclass
    5.32  
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/lib/native/float.py	Thu Jul 12 00:15:16 2018 +0200
     6.3 @@ -0,0 +1,45 @@
     6.4 +#!/usr/bin/env python
     6.5 +
     6.6 +"""
     6.7 +Native library functions for floating point numbers.
     6.8 +
     6.9 +None of these are actually defined here. Instead, native implementations are
    6.10 +substituted when each program is built. It is, however, important to declare
    6.11 +non-core exceptions used by the native functions because they need to be
    6.12 +identified as being needed by the program.
    6.13 +
    6.14 +Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
    6.15 +
    6.16 +This program is free software; you can redistribute it and/or modify it under
    6.17 +the terms of the GNU General Public License as published by the Free Software
    6.18 +Foundation; either version 3 of the License, or (at your option) any later
    6.19 +version.
    6.20 +
    6.21 +This program is distributed in the hope that it will be useful, but WITHOUT
    6.22 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    6.23 +FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    6.24 +details.
    6.25 +
    6.26 +You should have received a copy of the GNU General Public License along with
    6.27 +this program.  If not, see <http://www.gnu.org/licenses/>.
    6.28 +"""
    6.29 +
    6.30 +def float_add(self, other): return 0.0
    6.31 +def float_div(self, other): return 0.0
    6.32 +def float_mod(self, other): return 0.0
    6.33 +def float_mul(self, other): return 0.0
    6.34 +def float_neg(self): return 0.0
    6.35 +def float_pow(self, other): return 0.0
    6.36 +def float_sub(self, other): return 0.0
    6.37 +
    6.38 +def float_eq(self, other): return True or False
    6.39 +def float_ge(self, other): return True or False
    6.40 +def float_gt(self, other): return True or False
    6.41 +def float_le(self, other): return True or False
    6.42 +def float_lt(self, other): return True or False
    6.43 +def float_ne(self, other): return True or False
    6.44 +
    6.45 +def float_str(self): return ""
    6.46 +def float_int(self): return 0
    6.47 +
    6.48 +# vim: tabstop=4 expandtab shiftwidth=4
     7.1 --- a/lib/native/int.py	Wed Jul 11 23:53:09 2018 +0200
     7.2 +++ b/lib/native/int.py	Thu Jul 12 00:15:16 2018 +0200
     7.3 @@ -8,7 +8,7 @@
     7.4  non-core exceptions used by the native functions because they need to be
     7.5  identified as being needed by the program.
     7.6  
     7.7 -Copyright (C) 2011, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     7.8 +Copyright (C) 2011, 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
     7.9  
    7.10  This program is free software; you can redistribute it and/or modify it under
    7.11  the terms of the GNU General Public License as published by the Free Software
    7.12 @@ -53,5 +53,6 @@
    7.13  def int_ne(self, other): return True or False
    7.14  
    7.15  def int_str(self): return ""
    7.16 +def int_float(self): return 0.0
    7.17  
    7.18  # vim: tabstop=4 expandtab shiftwidth=4
     8.1 --- a/templates/native/common.c	Wed Jul 11 23:53:09 2018 +0200
     8.2 +++ b/templates/native/common.c	Thu Jul 12 00:15:16 2018 +0200
     8.3 @@ -44,6 +44,14 @@
     8.4      return attr;
     8.5  }
     8.6  
     8.7 +__attr __new_float(double n)
     8.8 +{
     8.9 +    /* Create a new float and set the trailing data. */
    8.10 +    __attr attr = __NEWINSTANCE(__builtins___float_float);
    8.11 +    __set_trailing_data(attr, __builtins___float_float, n);
    8.12 +    return attr;
    8.13 +}
    8.14 +
    8.15  __fragment *__fragment_append(__fragment *data, __attr value)
    8.16  {
    8.17      __fragment *newdata = data;
     9.1 --- a/templates/native/common.h	Wed Jul 11 23:53:09 2018 +0200
     9.2 +++ b/templates/native/common.h	Thu Jul 12 00:15:16 2018 +0200
     9.3 @@ -1,6 +1,6 @@
     9.4  /* Common operations for native functions.
     9.5  
     9.6 -Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     9.7 +Copyright (C) 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
     9.8  
     9.9  This program is free software; you can redistribute it and/or modify it under
    9.10  the terms of the GNU General Public License as published by the Free Software
    9.11 @@ -21,11 +21,15 @@
    9.12  
    9.13  #include "types.h"
    9.14  
    9.15 -/* Utility functions. */
    9.16 +/* Utility macro for the special integer representation. */
    9.17  
    9.18  #define __new_int(VALUE) __INTVALUE(VALUE)
    9.19 +
    9.20 +/* Utility functions. */
    9.21 +
    9.22  __attr __new_str(char *s, int size);
    9.23  __attr __new_list(__fragment *f);
    9.24 +__attr __new_float(double n);
    9.25  __fragment *__fragment_append(__fragment *data, __attr value);
    9.26  
    9.27  #endif /* __NATIVE_COMMON_H__ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/templates/native/float.c	Thu Jul 12 00:15:16 2018 +0200
    10.3 @@ -0,0 +1,345 @@
    10.4 +/* Native functions for floating point operations.
    10.5 +
    10.6 +Copyright (C) 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
    10.7 +
    10.8 +This program is free software; you can redistribute it and/or modify it under
    10.9 +the terms of the GNU General Public License as published by the Free Software
   10.10 +Foundation; either version 3 of the License, or (at your option) any later
   10.11 +version.
   10.12 +
   10.13 +This program is distributed in the hope that it will be useful, but WITHOUT
   10.14 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   10.15 +FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   10.16 +details.
   10.17 +
   10.18 +You should have received a copy of the GNU General Public License along with
   10.19 +this program.  If not, see <http://www.gnu.org/licenses/>.
   10.20 +*/
   10.21 +
   10.22 +#include <fenv.h>   /* feclearexcept, fetestexcept */
   10.23 +#include <math.h>   /* pow */
   10.24 +#include <stdio.h>  /* snprintf */
   10.25 +#include <errno.h>  /* errno */
   10.26 +#include "native/common.h"
   10.27 +#include "types.h"
   10.28 +#include "exceptions.h"
   10.29 +#include "ops.h"
   10.30 +#include "progconsts.h"
   10.31 +#include "progops.h"
   10.32 +#include "progtypes.h"
   10.33 +#include "main.h"
   10.34 +
   10.35 +/* Conversion from a pair of consecutive attributes to a double-precision
   10.36 +   floating point number. */
   10.37 +
   10.38 +static double __TOFLOAT(__attr attr)
   10.39 +{
   10.40 +    return __get_trailing_data(attr, __builtins___float_float);
   10.41 +}
   10.42 +
   10.43 +/* Numeric formatting using snprintf.
   10.44 +   NOTE: This might be moved elsewhere and used by other types. */
   10.45 +
   10.46 +static __attr format_number(double n, int size)
   10.47 +{
   10.48 +    char *s = (char *) __ALLOCATE(size, sizeof(char));
   10.49 +    int digits;
   10.50 +
   10.51 +    /* Allocation should raise a memory error if it fails, so this loop should
   10.52 +       terminate via the return statement or an allocation failure. */
   10.53 +
   10.54 +    while (1)
   10.55 +    {
   10.56 +        digits = snprintf(s, size, "%f", n);
   10.57 +
   10.58 +        if (digits < size)
   10.59 +        {
   10.60 +            s = (char *) __REALLOCATE(s, (digits + 1) * sizeof(char));
   10.61 +            return __new_str(s, digits);
   10.62 +        }
   10.63 +
   10.64 +        size = digits + 1;
   10.65 +        s = (char *) __REALLOCATE(s, size * sizeof(char));
   10.66 +    }
   10.67 +
   10.68 +    return __NULL;
   10.69 +}
   10.70 +
   10.71 +/* Floating point exception handling. */
   10.72 +
   10.73 +static void init_env(fenv_t *envp, int excepts)
   10.74 +{
   10.75 +    fegetenv(envp);
   10.76 +    feclearexcept(excepts);
   10.77 +}
   10.78 +
   10.79 +static int test_env(fenv_t *envp, int excepts)
   10.80 +{
   10.81 +    if (fetestexcept(excepts))
   10.82 +    {
   10.83 +        fesetenv(envp);
   10.84 +        return 1;
   10.85 +    }
   10.86 +    return 0;
   10.87 +}
   10.88 +
   10.89 +static int have_result(fenv_t *envp, int excepts)
   10.90 +{
   10.91 +    return !fetestexcept(excepts);
   10.92 +}
   10.93 +
   10.94 +static __attr make_result(fenv_t *envp, double result)
   10.95 +{
   10.96 +    fesetenv(envp);
   10.97 +    return __new_float(result);
   10.98 +}
   10.99 +
  10.100 +/* Floating point operations. */
  10.101 +
  10.102 +__attr __fn_native_float_float_add(__attr __self, __attr self, __attr other)
  10.103 +{
  10.104 +    /* self and other interpreted as float */
  10.105 +    double i = __TOFLOAT(self);
  10.106 +    double j = __TOFLOAT(other);
  10.107 +    double result;
  10.108 +
  10.109 +    /* Preserve environment, clear exception state. */
  10.110 +    fenv_t env;
  10.111 +    init_env(&env, FE_OVERFLOW);
  10.112 +
  10.113 +    result = i + j;
  10.114 +
  10.115 +    /* Test for result, restore state, return the new float. */
  10.116 +    if (have_result(&env, FE_OVERFLOW))
  10.117 +        return make_result(&env, result);
  10.118 +
  10.119 +    /* Restore state, raise exception. */
  10.120 +    if (test_env(&env, FE_OVERFLOW))
  10.121 +        __raise_overflow_error();
  10.122 +    return __NULL;
  10.123 +}
  10.124 +
  10.125 +__attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other)
  10.126 +{
  10.127 +    /* self and other interpreted as float */
  10.128 +    double i = __TOFLOAT(self);
  10.129 +    double j = __TOFLOAT(other);
  10.130 +    double result;
  10.131 +
  10.132 +    /* Preserve environment, clear exception state. */
  10.133 +    fenv_t env;
  10.134 +    init_env(&env, FE_OVERFLOW);
  10.135 +
  10.136 +    result = i - j;
  10.137 +
  10.138 +    /* Test for result, restore state, return the new float. */
  10.139 +    if (have_result(&env, FE_OVERFLOW))
  10.140 +        return make_result(&env, result);
  10.141 +
  10.142 +    /* Restore state, raise exception. */
  10.143 +    if (test_env(&env, FE_OVERFLOW))
  10.144 +        __raise_overflow_error();
  10.145 +    return __NULL;
  10.146 +}
  10.147 +
  10.148 +__attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other)
  10.149 +{
  10.150 +    /* self and other interpreted as float */
  10.151 +    double i = __TOFLOAT(self);
  10.152 +    double j = __TOFLOAT(other);
  10.153 +    double result;
  10.154 +
  10.155 +    /* Preserve environment, clear exception state. */
  10.156 +    fenv_t env;
  10.157 +    init_env(&env, FE_OVERFLOW | FE_UNDERFLOW);
  10.158 +
  10.159 +    result = i * j;
  10.160 +
  10.161 +    /* Test for result, restore state, return the new float. */
  10.162 +    if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW))
  10.163 +        return make_result(&env, result);
  10.164 +
  10.165 +    /* Restore state, raise exception. */
  10.166 +    if (test_env(&env, FE_OVERFLOW))
  10.167 +        __raise_overflow_error();
  10.168 +    if (test_env(&env, FE_UNDERFLOW))
  10.169 +        __raise_underflow_error();
  10.170 +    return __NULL;
  10.171 +}
  10.172 +
  10.173 +__attr __fn_native_float_float_div(__attr __self, __attr self, __attr other)
  10.174 +{
  10.175 +    /* self and other interpreted as float */
  10.176 +    double i = __TOFLOAT(self);
  10.177 +    double j = __TOFLOAT(other);
  10.178 +    double result;
  10.179 +
  10.180 +    /* Preserve environment, clear exception state. */
  10.181 +    fenv_t env;
  10.182 +    init_env(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO);
  10.183 +
  10.184 +    result = i / j;
  10.185 +
  10.186 +    /* Test for result, restore state, return the new float. */
  10.187 +    if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO))
  10.188 +        return make_result(&env, result);
  10.189 +
  10.190 +    /* Restore state, raise exception. */
  10.191 +    if (test_env(&env, FE_OVERFLOW))
  10.192 +        __raise_overflow_error();
  10.193 +    if (test_env(&env, FE_UNDERFLOW))
  10.194 +        __raise_underflow_error();
  10.195 +    if (test_env(&env, FE_DIVBYZERO))
  10.196 +        __raise_zero_division_error();
  10.197 +    return __NULL;
  10.198 +}
  10.199 +
  10.200 +__attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other)
  10.201 +{
  10.202 +    /* self and other interpreted as float */
  10.203 +    double i = __TOFLOAT(self);
  10.204 +    double j = __TOFLOAT(other);
  10.205 +    double result;
  10.206 +
  10.207 +    /* Preserve environment, clear exception state. */
  10.208 +    fenv_t env;
  10.209 +    init_env(&env, FE_OVERFLOW | FE_DIVBYZERO);
  10.210 +
  10.211 +    result = fmod(i, j);
  10.212 +
  10.213 +    /* Test for result, restore state, return the new float. */
  10.214 +    if (have_result(&env, FE_OVERFLOW | FE_DIVBYZERO))
  10.215 +        return make_result(&env, result);
  10.216 +
  10.217 +    /* Restore state, raise exception. */
  10.218 +    if (test_env(&env, FE_OVERFLOW))
  10.219 +        __raise_overflow_error();
  10.220 +    if (test_env(&env, FE_DIVBYZERO))
  10.221 +        __raise_zero_division_error();
  10.222 +    return __NULL;
  10.223 +}
  10.224 +
  10.225 +__attr __fn_native_float_float_neg(__attr __self, __attr self)
  10.226 +{
  10.227 +    /* self interpreted as float */
  10.228 +    double i = __TOFLOAT(self);
  10.229 +    double result;
  10.230 +
  10.231 +    /* Preserve environment, clear exception state. */
  10.232 +    fenv_t env;
  10.233 +    init_env(&env, FE_OVERFLOW);
  10.234 +
  10.235 +    result = -i;
  10.236 +
  10.237 +    /* Test for result, restore state, return the new float. */
  10.238 +    if (have_result(&env, FE_OVERFLOW))
  10.239 +        return make_result(&env, result);
  10.240 +
  10.241 +    /* Restore state, raise exception. */
  10.242 +    if (test_env(&env, FE_OVERFLOW))
  10.243 +        __raise_overflow_error();
  10.244 +    return __NULL;
  10.245 +}
  10.246 +
  10.247 +__attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other)
  10.248 +{
  10.249 +    /* self and other interpreted as float */
  10.250 +    double i = __TOFLOAT(self);
  10.251 +    double j = __TOFLOAT(other);
  10.252 +    double result;
  10.253 +
  10.254 +    errno = 0;
  10.255 +    result = pow(i, j);
  10.256 +
  10.257 +    /* Test for overflow. */
  10.258 +
  10.259 +    if (errno == ERANGE)
  10.260 +        __raise_overflow_error();
  10.261 +
  10.262 +    /* Return the result. */
  10.263 +    return __new_float(result);
  10.264 +}
  10.265 +
  10.266 +__attr __fn_native_float_float_le(__attr __self, __attr self, __attr other)
  10.267 +{
  10.268 +    /* self and other interpreted as float */
  10.269 +    double i = __TOFLOAT(self);
  10.270 +    double j = __TOFLOAT(other);
  10.271 +
  10.272 +    /* Return a boolean result. */
  10.273 +    return i <= j ? __builtins___boolean_True : __builtins___boolean_False;
  10.274 +}
  10.275 +
  10.276 +__attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other)
  10.277 +{
  10.278 +    /* self and other interpreted as float */
  10.279 +    double i = __TOFLOAT(self);
  10.280 +    double j = __TOFLOAT(other);
  10.281 +
  10.282 +    /* Return a boolean result. */
  10.283 +    return i < j ? __builtins___boolean_True : __builtins___boolean_False;
  10.284 +}
  10.285 +
  10.286 +__attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other)
  10.287 +{
  10.288 +    /* self and other interpreted as float */
  10.289 +    double i = __TOFLOAT(self);
  10.290 +    double j = __TOFLOAT(other);
  10.291 +
  10.292 +    /* Return a boolean result. */
  10.293 +    return i >= j ? __builtins___boolean_True : __builtins___boolean_False;
  10.294 +}
  10.295 +
  10.296 +__attr __fn_native_float_float_gt(__attr __self, __attr self, __attr other)
  10.297 +{
  10.298 +    /* self and other interpreted as float */
  10.299 +    double i = __TOFLOAT(self);
  10.300 +    double j = __TOFLOAT(other);
  10.301 +
  10.302 +    /* Return a boolean result. */
  10.303 +    return i > j ? __builtins___boolean_True : __builtins___boolean_False;
  10.304 +}
  10.305 +
  10.306 +__attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other)
  10.307 +{
  10.308 +    /* self and other interpreted as float */
  10.309 +    double i = __TOFLOAT(self);
  10.310 +    double j = __TOFLOAT(other);
  10.311 +
  10.312 +    /* Return a boolean result. */
  10.313 +    return i == j ? __builtins___boolean_True : __builtins___boolean_False;
  10.314 +}
  10.315 +
  10.316 +__attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other)
  10.317 +{
  10.318 +    /* self and other interpreted as float */
  10.319 +    double i = __TOFLOAT(self);
  10.320 +    double j = __TOFLOAT(other);
  10.321 +
  10.322 +    /* Return a boolean result. */
  10.323 +    return i != j ? __builtins___boolean_True : __builtins___boolean_False;
  10.324 +}
  10.325 +
  10.326 +__attr __fn_native_float_float_str(__attr __self, __attr self)
  10.327 +{
  10.328 +    /* self interpreted as float */
  10.329 +    double i = __TOFLOAT(self);
  10.330 +
  10.331 +    /* Return a new string. */
  10.332 +    return format_number(i, 64);
  10.333 +}
  10.334 +
  10.335 +__attr __fn_native_float_float_int(__attr __self, __attr self)
  10.336 +{
  10.337 +    /* self interpreted as float */
  10.338 +    double i = __TOFLOAT(self);
  10.339 +
  10.340 +    /* NOTE: Test for conversion failure. */
  10.341 +    return __new_int((int) i);
  10.342 +}
  10.343 +
  10.344 +/* Module initialisation. */
  10.345 +
  10.346 +void __main_native_float()
  10.347 +{
  10.348 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/templates/native/float.h	Thu Jul 12 00:15:16 2018 +0200
    11.3 @@ -0,0 +1,48 @@
    11.4 +/* Native functions for floating point operations.
    11.5 +
    11.6 +Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk>
    11.7 +
    11.8 +This program is free software; you can redistribute it and/or modify it under
    11.9 +the terms of the GNU General Public License as published by the Free Software
   11.10 +Foundation; either version 3 of the License, or (at your option) any later
   11.11 +version.
   11.12 +
   11.13 +This program is distributed in the hope that it will be useful, but WITHOUT
   11.14 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   11.15 +FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   11.16 +details.
   11.17 +
   11.18 +You should have received a copy of the GNU General Public License along with
   11.19 +this program.  If not, see <http://www.gnu.org/licenses/>.
   11.20 +*/
   11.21 +
   11.22 +#ifndef __NATIVE_FLOAT_H__
   11.23 +#define __NATIVE_FLOAT_H__
   11.24 +
   11.25 +#include "types.h"
   11.26 +
   11.27 +/* Floating point operations. */
   11.28 +
   11.29 +__attr __fn_native_float_float_add(__attr __self, __attr self, __attr other);
   11.30 +__attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other);
   11.31 +__attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other);
   11.32 +__attr __fn_native_float_float_div(__attr __self, __attr self, __attr other);
   11.33 +__attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other);
   11.34 +__attr __fn_native_float_float_neg(__attr __self, __attr self);
   11.35 +__attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other);
   11.36 +
   11.37 +__attr __fn_native_float_float_le(__attr __self, __attr self, __attr other);
   11.38 +__attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other);
   11.39 +__attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other);
   11.40 +__attr __fn_native_float_float_gt(__attr __self, __attr self, __attr other);
   11.41 +__attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other);
   11.42 +__attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other);
   11.43 +
   11.44 +__attr __fn_native_float_float_str(__attr __self, __attr self);
   11.45 +__attr __fn_native_float_float_int(__attr __self, __attr self);
   11.46 +
   11.47 +/* Module initialisation. */
   11.48 +
   11.49 +void __main_native_float();
   11.50 +
   11.51 +#endif /* __NATIVE_FLOAT_H__ */
    12.1 --- a/templates/native/int.c	Wed Jul 11 23:53:09 2018 +0200
    12.2 +++ b/templates/native/int.c	Thu Jul 12 00:15:16 2018 +0200
    12.3 @@ -1,6 +1,6 @@
    12.4  /* Native functions for integer operations.
    12.5  
    12.6 -Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    12.7 +Copyright (C) 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
    12.8  
    12.9  This program is free software; you can redistribute it and/or modify it under
   12.10  the terms of the GNU General Public License as published by the Free Software
   12.11 @@ -290,6 +290,14 @@
   12.12      return __new_str(s, strlen(s));
   12.13  }
   12.14  
   12.15 +__attr __fn_native_int_int_float(__attr __self, __attr self)
   12.16 +{
   12.17 +    /* self interpreted as int */
   12.18 +    int i = __TOINT(self);
   12.19 +
   12.20 +    return __new_float((double) i);
   12.21 +}
   12.22 +
   12.23  /* Module initialisation. */
   12.24  
   12.25  void __main_native_int()
    13.1 --- a/templates/native/int.h	Wed Jul 11 23:53:09 2018 +0200
    13.2 +++ b/templates/native/int.h	Thu Jul 12 00:15:16 2018 +0200
    13.3 @@ -1,6 +1,6 @@
    13.4  /* Native functions for integer operations.
    13.5  
    13.6 -Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    13.7 +Copyright (C) 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
    13.8  
    13.9  This program is free software; you can redistribute it and/or modify it under
   13.10  the terms of the GNU General Public License as published by the Free Software
   13.11 @@ -48,6 +48,7 @@
   13.12  __attr __fn_native_int_int_ne(__attr __self, __attr _data, __attr other);
   13.13  
   13.14  __attr __fn_native_int_int_str(__attr __self, __attr _data);
   13.15 +__attr __fn_native_int_int_float(__attr __self, __attr _data);
   13.16  
   13.17  /* Module initialisation. */
   13.18  
    14.1 --- a/templates/ops.c	Wed Jul 11 23:53:09 2018 +0200
    14.2 +++ b/templates/ops.c	Thu Jul 12 00:15:16 2018 +0200
    14.3 @@ -1,6 +1,6 @@
    14.4  /* Common operations.
    14.5  
    14.6 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    14.7 +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
    14.8  
    14.9  This program is free software; you can redistribute it and/or modify it under
   14.10  the terms of the GNU General Public License as published by the Free Software
   14.11 @@ -30,7 +30,7 @@
   14.12      if (!__INTEGER(attr))
   14.13          return attr.value;
   14.14      else
   14.15 -        return &__common_integer_obj;
   14.16 +        return (__ref) &__common_integer_obj;
   14.17  }
   14.18  
   14.19  /* Basic structure tests. */
    15.1 --- a/templates/progops.c	Wed Jul 11 23:53:09 2018 +0200
    15.2 +++ b/templates/progops.c	Thu Jul 12 00:15:16 2018 +0200
    15.3 @@ -156,6 +156,11 @@
    15.4      __Raise(__new___builtins___core_TypeError(__NULL));
    15.5  }
    15.6  
    15.7 +void __raise_underflow_error()
    15.8 +{
    15.9 +    __Raise(__new___builtins___core_UnderflowError(__NULL));
   15.10 +}
   15.11 +
   15.12  void __raise_zero_division_error()
   15.13  {
   15.14      __Raise(__new___builtins___core_ZeroDivisionError(__NULL));
   15.15 @@ -303,7 +308,7 @@
   15.16  
   15.17      __ref value = __VALUE(attr);
   15.18  
   15.19 -    return value == &__predefined___builtins___boolean_True ? 1 :
   15.20 -           value == &__predefined___builtins___boolean_False ? 0 :
   15.21 -           __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == &__predefined___builtins___boolean_True;
   15.22 +    return value == (__ref) &__predefined___builtins___boolean_True ? 1 :
   15.23 +           value == (__ref) &__predefined___builtins___boolean_False ? 0 :
   15.24 +           __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == (__ref) &__predefined___builtins___boolean_True;
   15.25  }
    16.1 --- a/templates/progops.h	Wed Jul 11 23:53:09 2018 +0200
    16.2 +++ b/templates/progops.h	Thu Jul 12 00:15:16 2018 +0200
    16.3 @@ -1,6 +1,6 @@
    16.4  /* Operations depending on program specifics.
    16.5  
    16.6 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    16.7 +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
    16.8  
    16.9  This program is free software; you can redistribute it and/or modify it under
   16.10  the terms of the GNU General Public License as published by the Free Software
   16.11 @@ -38,25 +38,22 @@
   16.12  #define __newliteral___builtins___list_list(NUM, ...) __newdata_list(NUM, __ARGS(__VA_ARGS__))
   16.13  #define __newliteral___builtins___tuple_tuple(NUM, ...) __newdata_tuple(NUM, __ARGS(__VA_ARGS__))
   16.14  
   16.15 +/* Potentially superfluous operations. */
   16.16 +
   16.17  #ifdef __HAVE___builtins___dict_dict
   16.18  __attr __newdata_dict(unsigned int number, __attr args[]);
   16.19  #define __newliteral___builtins___dict_dict(NUM, ...) __newdata_dict(NUM, __ARGS(__VA_ARGS__))
   16.20 -#endif /* __HAVE___builtins___dict_dict */
   16.21 +#endif
   16.22  
   16.23  /* Helpers for raising errors within common operations. */
   16.24  
   16.25  void __raise_eof_error();
   16.26 -
   16.27  void __raise_io_error(__attr value);
   16.28 -
   16.29  void __raise_memory_error();
   16.30 -
   16.31  void __raise_os_error(__attr value, __attr arg);
   16.32 -
   16.33  void __raise_overflow_error();
   16.34 -
   16.35 +void __raise_underflow_error();
   16.36  void __raise_zero_division_error();
   16.37 -
   16.38  void __raise_type_error();
   16.39  
   16.40  /* Helper for raising exception instances. */
   16.41 @@ -76,17 +73,21 @@
   16.42  /* Generic operations depending on specific program details. */
   16.43  
   16.44  void __SETDEFAULT(__ref obj, int pos, __attr value);
   16.45 -
   16.46  __attr __GETDEFAULT(__ref obj, int pos);
   16.47 -
   16.48  int __BOOL(__attr attr);
   16.49  
   16.50  /* Convenience definitions. */
   16.51  
   16.52 -#define __INSTANCESIZE(CLS) sizeof(__obj_##CLS)
   16.53 +#define __OBJTYPE(CLS) __obj_##CLS
   16.54 +#define __INSTANCESIZE(CLS) sizeof(__OBJTYPE(CLS))
   16.55  #define __INSTANCETABLE(CLS) (__InstanceTable_##CLS)
   16.56  #define __NEWINSTANCE(CLS) __new(&__INSTANCETABLE(CLS), &CLS, __INSTANCESIZE(CLS), 0)
   16.57  #define __NEWINSTANCEIM(CLS) __new(&__INSTANCETABLE(CLS), &CLS, __INSTANCESIZE(CLS), 1)
   16.58  #define __ISINSTANCE(ATTR, TYPE) __BOOL(__fn_native_introspection_isinstance(__NULL, ATTR, TYPE))
   16.59  
   16.60 +/* Operations for accessing trailing data. */
   16.61 +
   16.62 +#define __get_trailing_data(ATTR, TYPE) (((__OBJTYPE(TYPE) *) ((ATTR).value))->trailing)
   16.63 +#define __set_trailing_data(ATTR, TYPE, VALUE) ((__OBJTYPE(TYPE) *) ((ATTR).value))->trailing = VALUE;
   16.64 +
   16.65  #endif /* __PROGOPS_H__ */
    17.1 --- a/templates/types.h	Wed Jul 11 23:53:09 2018 +0200
    17.2 +++ b/templates/types.h	Thu Jul 12 00:15:16 2018 +0200
    17.3 @@ -1,6 +1,6 @@
    17.4  /* Runtime types.
    17.5  
    17.6 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    17.7 +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
    17.8  
    17.9  This program is free software; you can redistribute it and/or modify it under
   17.10  the terms of the GNU General Public License as published by the Free Software
   17.11 @@ -85,7 +85,6 @@
   17.12          __ppos pos;             /* parameter table position for key */
   17.13      };
   17.14      __attr (*fn)();             /* callable details */
   17.15 -    float floatvalue;          	/* floating point value */
   17.16      char * strvalue;            /* string value */
   17.17      __fragment * seqvalue;      /* sequence data */
   17.18      void * datavalue;           /* object-specific data */
   17.19 @@ -96,6 +95,11 @@
   17.20      const __table * table;      /* attribute table */
   17.21      __ppos pos;                 /* position of attribute indicating class */
   17.22      __attr attrs[];             /* attributes */
   17.23 +
   17.24 +    /* Specialisations of this type may add other members.
   17.25 +       See generator.py for type generation, progops.h for definitions, and
   17.26 +       the generated progtypes.h for the final details. */
   17.27 +
   17.28  } __obj;
   17.29  
   17.30  #define __INSTANCE_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + sizeof(__table *) + sizeof(__ppos))
   17.31 @@ -117,7 +121,7 @@
   17.32  
   17.33  /* Attribute value setting. */
   17.34  
   17.35 -#define __ATTRVALUE(VALUE) ((__attr) {.value=VALUE})
   17.36 +#define __ATTRVALUE(VALUE) ((__attr) {.value=(__ref) VALUE})
   17.37  #define __NULL __ATTRVALUE(0)
   17.38  #define __SETNULL(ATTR) ((ATTR).value = 0)
   17.39  
    18.1 --- a/tests/numbers.py	Wed Jul 11 23:53:09 2018 +0200
    18.2 +++ b/tests/numbers.py	Thu Jul 12 00:15:16 2018 +0200
    18.3 @@ -55,6 +55,21 @@
    18.4  print "# hash((sys.maxint - 1, 0)):",
    18.5  print hash((sys.maxint - 1, 0))
    18.6  
    18.7 +# Floating point numbers.
    18.8 +
    18.9 +i = 2.0 ** 29
   18.10 +print i                                 # 536870912.0
   18.11 +j = -2.0 ** 29
   18.12 +print j                                 # -536870912.0
   18.13 +print i + j                             # 0
   18.14 +print i - j                             # -1073741824.0
   18.15 +print i * i                             # 2.8823037615171174e+17
   18.16 +
   18.17 +try:
   18.18 +    print i ** i
   18.19 +except OverflowError:
   18.20 +    print "i ** i: overflow occurred"
   18.21 +
   18.22  # Test combining numbers with strings.
   18.23  
   18.24  s = "Number is " + str(123)