# HG changeset patch # User Paul Boddie # Date 1531347316 -7200 # Node ID 6024d7e1d83adf026d6f0dfcd9c52b7aefb4d9e6 # Parent 81587921b9b4d486a285a2a9df61e5142fffe961 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. diff -r 81587921b9b4 -r 6024d7e1d83a encoders.py --- a/encoders.py Wed Jul 11 23:53:09 2018 +0200 +++ b/encoders.py Thu Jul 12 00:15:16 2018 +0200 @@ -505,6 +505,15 @@ return "__constvalue%s" % n +def encode_trailing_area(path): + + """ + Encode any reference to trailing data members for instances of the type + given by 'path'. + """ + + return "__TRAILING_%s" % encode_path(path) + # Track all encoded paths, detecting and avoiding conflicts. diff -r 81587921b9b4 -r 6024d7e1d83a generator.py --- a/generator.py Wed Jul 11 23:53:09 2018 +0200 +++ b/generator.py Thu Jul 12 00:15:16 2018 +0200 @@ -29,6 +29,7 @@ encode_path, encode_pcode, encode_pos, encode_ppos, \ encode_predefined_reference, encode_size, \ encode_symbol, encode_tablename, \ + encode_trailing_area, \ encode_type_attribute, decode_type_attribute, \ is_type_attribute from os import listdir, mkdir, remove @@ -42,6 +43,7 @@ # NOTE: These must be synchronised with the library. dict_type = "__builtins__.dict.dict" + float_type = "__builtins__.float.float" function_type = "__builtins__.core.function" int_type = "__builtins__.int.int" list_type = "__builtins__.list.list" @@ -64,6 +66,12 @@ dict_type, list_type, tuple_type ) + # Data types with a trailing data member of the given native types. + + trailing_data_types = { + float_type : "double", + } + def __init__(self, importer, optimiser, output): """ @@ -219,6 +227,7 @@ if kind != "": structure = [] + trailing = [] attrs = self.get_static_attributes(kind, path, attrnames) # Set a special instantiator on the class. @@ -244,12 +253,13 @@ attrs["__args__"] = path self.populate_structure(Reference(kind, path), attrs, kind, structure) + self.populate_trailing(Reference(kind, path), attrs, trailing) if kind == "": self.write_instance_structure(f_decls, path, structure_size) - self.write_structure(f_decls, f_defs, path, table_name, structure, - kind == "" and path) + self.write_structure(f_decls, f_defs, path, table_name, + structure, trailing, ref) # Record function instance details for function generation below. @@ -297,7 +307,7 @@ function_instance_attrs["__args__"] = path structure = self.populate_function(path, function_instance_attrs) - self.write_structure(f_decls, f_defs, path, table_name, structure) + self.write_structure(f_decls, f_defs, path, table_name, structure, [], Reference("", path)) # Functions with defaults need to declare instance structures. @@ -411,6 +421,12 @@ self.optimiser.locations, "code", "pos", encode_code, encode_pos) + # Generate trailing data macros of the form... + # #define __TRAILING_typename nativetype trailing; + + for name, member_type in self.trailing_data_types.items(): + print >>f_consts, "#define %s %s trailing;" % (encode_symbol("TRAILING", name), member_type) + # Generate macros for calls. all_max_parameters = list(all_max_parameters) @@ -617,7 +633,16 @@ # Set the data, if provided. if data is not None: - attrs["__data__"] = data + + # Data retained by special attribute. + + if attrs.has_key("__data__"): + attrs["__data__"] = data + + # Data retained by a trailing data area. + + elif attrs.has_key("__trailing__"): + attrs["__trailing__"] = data # Also set a key for dynamic attribute lookup, if a string. @@ -658,9 +683,12 @@ # the constant in the program. structure = [] + trailing = [] table_name = encode_tablename("", cls) self.populate_structure(ref, attrs, ref.get_kind(), structure) - self.write_structure(f_decls, f_defs, structure_name, table_name, structure) + self.populate_trailing(ref, attrs, trailing) + self.write_structure(f_decls, f_defs, structure_name, table_name, + structure, trailing, ref) # Define a macro for the constant. @@ -819,38 +847,51 @@ # Write an instance-specific type definition for instances of classes. # See: templates/types.h + trailing_area = path in self.trailing_data_types and encode_trailing_area(path) or "" + print >>f_decls, """\ typedef struct { const __table * table; __pos pos; __attr attrs[%s]; +%s } %s; -""" % (structure_size, encode_symbol("obj", path)) +""" % (structure_size, trailing_area, encode_symbol("obj", path)) - def write_structure(self, f_decls, f_defs, structure_name, table_name, structure, path=None): + def write_structure(self, f_decls, f_defs, structure_name, table_name, + structure, trailing, ref): """ Write the declarations to 'f_decls' and definitions to 'f_defs' for the object having the given 'structure_name', the given 'table_name', - and the given 'structure' details used to populate the definition. + the given 'structure' details and any 'trailing' member details, used to + populate the definition. """ + origin = ref.get_origin() + pos = ref.has_kind("") and encode_pos(encode_type_attribute(origin)) or str(self.instancepos) + + obj_type = ref.has_kind("") and encode_symbol("obj", origin) or "__obj" + obj_name = encode_path(structure_name) + if f_decls: - print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name) - - is_class = path and self.importer.get_object(path).has_kind("") - pos = is_class and encode_pos(encode_type_attribute(path)) or str(self.instancepos) + print >>f_decls, "extern %s %s;\n" % (obj_type, obj_name) print >>f_defs, """\ -__obj %s = { +%s %s = { &%s, %s, { %s - }}; + }, + %s + }; """ % ( - encode_path(structure_name), table_name, pos, - ",\n ".join(structure)) + obj_type, obj_name, + table_name, + pos, + ",\n ".join(structure), + trailing and ",\n ".join(trailing) or "") def get_argument_limits(self, path): @@ -910,6 +951,12 @@ continue const = consts.get(attrname) attrs[attrname] = const or Reference("", "%s.%s" % (name, attrname)) + + # Instances with trailing data. + + if name in self.trailing_data_types: + attrs["__trailing__"] = Reference("", "%s.__trailing__" % name) + return attrs def populate_table(self, path, table): @@ -1101,6 +1148,21 @@ structure.append(self.encode_member(origin, attrname, attr, kind)) + def populate_trailing(self, ref, attrs, trailing): + + """ + For the structure having the given 'ref', whose members are provided by + the 'attrs' mapping, adding entries to the 'trailing' member collection. + """ + + structure_ref = self.get_target_structure(ref) + + # Instances with trailing data. + + if structure_ref.get_kind() == "" and \ + structure_ref.get_origin() in self.trailing_data_types: + trailing.append(encode_literal_constant_value(attrs["__trailing__"])) + def get_target_structure(self, ref): "Return the target structure type and reference for 'ref'." @@ -1154,22 +1216,22 @@ if kind == "" and origin == self.none_type: attr_path = encode_predefined_reference(self.none_value) - return "{.value=&%s} /* %s */" % (attr_path, name) + return "{.value=(__ref) &%s} /* %s */" % (attr_path, name) # Predefined constant members. if (path, name) in self.predefined_constant_members: attr_path = encode_predefined_reference("%s.%s" % (path, name)) - return "{.value=&%s} /* %s */" % (attr_path, name) + return "{.value=(__ref) &%s} /* %s */" % (attr_path, name) # General undetermined members. if kind in ("", ""): attr_path = encode_predefined_reference(self.none_value) - return "{.value=&%s} /* %s */" % (attr_path, name) + return "{.value=(__ref) &%s} /* %s */" % (attr_path, name) else: - return "{.value=&%s}" % encode_path(origin) + return "{.value=(__ref) &%s}" % encode_path(origin) def append_defaults(self, path, structure): diff -r 81587921b9b4 -r 6024d7e1d83a lib/__builtins__/core.py --- a/lib/__builtins__/core.py Wed Jul 11 23:53:09 2018 +0200 +++ b/lib/__builtins__/core.py Thu Jul 12 00:15:16 2018 +0200 @@ -3,7 +3,7 @@ """ Core objects. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -189,6 +189,15 @@ pass +class UnderflowError(ArithmeticError): + + """ + Indicates that an arithmetic operation produced a result that could not be + represented. + """ + + pass + class ZeroDivisionError(ArithmeticError): "An error occurring when an attempt was made to divide an operand by zero." diff -r 81587921b9b4 -r 6024d7e1d83a lib/__builtins__/float.py --- a/lib/__builtins__/float.py Wed Jul 11 23:53:09 2018 +0200 +++ b/lib/__builtins__/float.py Thu Jul 12 00:15:16 2018 +0200 @@ -1,9 +1,9 @@ #!/usr/bin/env python """ -Floating point objects. +Floating point number objects. -Copyright (C) 2015, 2016 Paul Boddie +Copyright (C) 2015, 2016, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,36 +19,189 @@ this program. If not, see . """ +from __builtins__.unicode import utf8string +from native import isinstance as _isinstance, \ + int_float, is_int, \ + float_add, float_div, float_eq, float_ge, float_gt, \ + float_le, float_lt, float_mod, float_mul, float_ne, \ + float_neg, float_pow, float_str, float_sub, + class float: + + "A floating point number abstraction." + def __init__(self, number_or_string=None): - # Note member. - self.__data__ = 0.0 + + "Initialise the integer with the given 'number_or_string'." + + # NOTE: To be implemented. + + pass + + def __hash__(self): + + "Return a value for hashing purposes." + + return self + + def _binary_op(self, op, other): + + "Perform 'op' on this float and 'other' if appropriate." + + if _isinstance(other, float): + return op(self, other) + elif is_int(other): + return op(self, int_float(other)) + else: + return NotImplemented + + def _binary_op_rev(self, op, other): + + "Perform 'op' on 'other' and this float if appropriate." + + if _isinstance(other, float): + return op(other, self) + elif is_int(other): + return op(int_float(other), self) + else: + return NotImplemented + + def __iadd__(self, other): + + "Return a new float for the addition of this float and 'other'." - def __iadd__(self, other): pass - def __isub__(self, other): pass - def __add__(self, other): pass - def __radd__(self, other): pass - def __sub__(self, other): pass - def __rsub__(self, other): pass - def __mul__(self, other): pass - def __rmul__(self, other): pass - def __div__(self, other): pass - def __rdiv__(self, other): pass + return self._binary_op(float_add, other) + + def __isub__(self, other): + + "Return a new float for the subtraction from this float of 'other'." + + return self._binary_op(float_sub, other) + + def __imul__(self, other): + + "Return a new float for the multiplication of this float and 'other'." + + return self._binary_op(float_mul, other) + + def __idiv__(self, other): + + "Return a new float for the division of this float by 'other'." + + return self._binary_op(float_div, other) + + def __imod__(self, other): + + "Return a new float for the modulo of this float by 'other'." + + return self._binary_op(float_mod, other) + + def __ipow__(self, other): + + "Return a new float for the exponentiation of this float by 'other'." + + return self._binary_op(float_pow, other) + + __add__ = __radd__ = __iadd__ + __sub__ = __isub__ + + def __rsub__(self, other): + + "Return a new float for the subtraction of this float from 'other'." + + return self._binary_op_rev(float_sub, other) + + __mul__ = __rmul__ = __imul__ + __div__ = __idiv__ + + def __rdiv__(self, other): + + "Return a new float for the division of 'other' by this float." + + return self._binary_op_rev(float_div, other) + + # NOTE: To be implemented. + def __floordiv__(self, other): pass def __rfloordiv__(self, other): pass - def __mod__(self, other): pass - def __rmod__(self, other): pass - def __pow__(self, other): pass - def __rpow__(self, other): pass - def __lt__(self, other): pass - def __gt__(self, other): pass - def __le__(self, other): pass - def __ge__(self, other): pass - def __eq__(self, other): pass - def __ne__(self, other): pass - def __neg__(self): pass - def __pos__(self): pass - def __str__(self): pass - def __bool__(self): pass + def __ifloordiv__(self, other): pass + + __mod__ = __imod__ + + def __rmod__(self, other): + + "Return a new float for the modulo of 'other' by this float." + + return self._binary_op_rev(float_mod, other) + + __pow__ = __ipow__ + + def __rpow__(self, other): + + "Return a new float for the exponentiation of 'other' by this float." + + return self._binary_op_rev(float_pow, other) + + def __lt__(self, other): + + "Return whether this float is less than 'other'." + + return self._binary_op(float_lt, other) + + def __gt__(self, other): + + "Return whether this float is greater than 'other'." + + return self._binary_op(float_gt, other) + + def __le__(self, other): + + "Return whether this float is less than or equal to 'other'." + + return self._binary_op(float_le, other) + + def __ge__(self, other): + + "Return whether this float is greater than or equal to 'other'." + + return self._binary_op(float_ge, other) + + def __eq__(self, other): + + "Return whether this float is equal to 'other'." + + return self._binary_op(float_eq, other) + + def __ne__(self, other): + + "Return whether this float is not equal to 'other'." + + return self._binary_op(float_ne, other) + + def __neg__(self): + + "Apply the unary negation operator." + + return float_neg(self) + + def __pos__(self): + + "Apply the unary positive operator." + + return self + + def __str__(self): + + "Return a string representation." + + return utf8string(float_str(self)) + + __repr__ = __str__ + + def __bool__(self): + + "Return whether this float is non-zero." + + return float_ne(self, 0) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 81587921b9b4 -r 6024d7e1d83a lib/native/__init__.py --- a/lib/native/__init__.py Wed Jul 11 23:53:09 2018 +0200 +++ b/lib/native/__init__.py Thu Jul 12 00:15:16 2018 +0200 @@ -3,7 +3,7 @@ """ Native library functions. -Copyright (C) 2011, 2015, 2016, 2017 Paul Boddie +Copyright (C) 2011, 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -21,13 +21,19 @@ from native.buffer import buffer_str +from native.float import float_add, float_div, float_mod, float_mul, \ + float_neg, float_pow, float_sub, \ + float_eq, float_ge, float_gt, float_le, float_lt, \ + float_ne, \ + float_int, float_str + from native.identity import is_, is_not from native.int import int_add, int_div, int_mod, int_mul, int_neg, int_pow, \ int_sub, int_and, int_not, int_or, int_xor, \ int_lshift, int_rshift, \ int_eq, int_ge, int_gt, int_le, int_lt, int_ne, \ - int_str, is_int + int_float, int_str, is_int from native.introspection import object_getattr, isinstance, issubclass diff -r 81587921b9b4 -r 6024d7e1d83a lib/native/float.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/native/float.py Thu Jul 12 00:15:16 2018 +0200 @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +""" +Native library functions for floating point numbers. + +None of these are actually defined here. Instead, native implementations are +substituted when each program is built. It is, however, important to declare +non-core exceptions used by the native functions because they need to be +identified as being needed by the program. + +Copyright (C) 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +def float_add(self, other): return 0.0 +def float_div(self, other): return 0.0 +def float_mod(self, other): return 0.0 +def float_mul(self, other): return 0.0 +def float_neg(self): return 0.0 +def float_pow(self, other): return 0.0 +def float_sub(self, other): return 0.0 + +def float_eq(self, other): return True or False +def float_ge(self, other): return True or False +def float_gt(self, other): return True or False +def float_le(self, other): return True or False +def float_lt(self, other): return True or False +def float_ne(self, other): return True or False + +def float_str(self): return "" +def float_int(self): return 0 + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 81587921b9b4 -r 6024d7e1d83a lib/native/int.py --- a/lib/native/int.py Wed Jul 11 23:53:09 2018 +0200 +++ b/lib/native/int.py Thu Jul 12 00:15:16 2018 +0200 @@ -8,7 +8,7 @@ non-core exceptions used by the native functions because they need to be identified as being needed by the program. -Copyright (C) 2011, 2015, 2016, 2017 Paul Boddie +Copyright (C) 2011, 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -53,5 +53,6 @@ def int_ne(self, other): return True or False def int_str(self): return "" +def int_float(self): return 0.0 # vim: tabstop=4 expandtab shiftwidth=4 diff -r 81587921b9b4 -r 6024d7e1d83a templates/native/common.c --- a/templates/native/common.c Wed Jul 11 23:53:09 2018 +0200 +++ b/templates/native/common.c Thu Jul 12 00:15:16 2018 +0200 @@ -44,6 +44,14 @@ return attr; } +__attr __new_float(double n) +{ + /* Create a new float and set the trailing data. */ + __attr attr = __NEWINSTANCE(__builtins___float_float); + __set_trailing_data(attr, __builtins___float_float, n); + return attr; +} + __fragment *__fragment_append(__fragment *data, __attr value) { __fragment *newdata = data; diff -r 81587921b9b4 -r 6024d7e1d83a templates/native/common.h --- a/templates/native/common.h Wed Jul 11 23:53:09 2018 +0200 +++ b/templates/native/common.h Thu Jul 12 00:15:16 2018 +0200 @@ -1,6 +1,6 @@ /* Common operations for native functions. -Copyright (C) 2016, 2017 Paul Boddie +Copyright (C) 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -21,11 +21,15 @@ #include "types.h" -/* Utility functions. */ +/* Utility macro for the special integer representation. */ #define __new_int(VALUE) __INTVALUE(VALUE) + +/* Utility functions. */ + __attr __new_str(char *s, int size); __attr __new_list(__fragment *f); +__attr __new_float(double n); __fragment *__fragment_append(__fragment *data, __attr value); #endif /* __NATIVE_COMMON_H__ */ diff -r 81587921b9b4 -r 6024d7e1d83a templates/native/float.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/native/float.c Thu Jul 12 00:15:16 2018 +0200 @@ -0,0 +1,345 @@ +/* Native functions for floating point operations. + +Copyright (C) 2016, 2017, 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +*/ + +#include /* feclearexcept, fetestexcept */ +#include /* pow */ +#include /* snprintf */ +#include /* errno */ +#include "native/common.h" +#include "types.h" +#include "exceptions.h" +#include "ops.h" +#include "progconsts.h" +#include "progops.h" +#include "progtypes.h" +#include "main.h" + +/* Conversion from a pair of consecutive attributes to a double-precision + floating point number. */ + +static double __TOFLOAT(__attr attr) +{ + return __get_trailing_data(attr, __builtins___float_float); +} + +/* Numeric formatting using snprintf. + NOTE: This might be moved elsewhere and used by other types. */ + +static __attr format_number(double n, int size) +{ + char *s = (char *) __ALLOCATE(size, sizeof(char)); + int digits; + + /* Allocation should raise a memory error if it fails, so this loop should + terminate via the return statement or an allocation failure. */ + + while (1) + { + digits = snprintf(s, size, "%f", n); + + if (digits < size) + { + s = (char *) __REALLOCATE(s, (digits + 1) * sizeof(char)); + return __new_str(s, digits); + } + + size = digits + 1; + s = (char *) __REALLOCATE(s, size * sizeof(char)); + } + + return __NULL; +} + +/* Floating point exception handling. */ + +static void init_env(fenv_t *envp, int excepts) +{ + fegetenv(envp); + feclearexcept(excepts); +} + +static int test_env(fenv_t *envp, int excepts) +{ + if (fetestexcept(excepts)) + { + fesetenv(envp); + return 1; + } + return 0; +} + +static int have_result(fenv_t *envp, int excepts) +{ + return !fetestexcept(excepts); +} + +static __attr make_result(fenv_t *envp, double result) +{ + fesetenv(envp); + return __new_float(result); +} + +/* Floating point operations. */ + +__attr __fn_native_float_float_add(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + double result; + + /* Preserve environment, clear exception state. */ + fenv_t env; + init_env(&env, FE_OVERFLOW); + + result = i + j; + + /* Test for result, restore state, return the new float. */ + if (have_result(&env, FE_OVERFLOW)) + return make_result(&env, result); + + /* Restore state, raise exception. */ + if (test_env(&env, FE_OVERFLOW)) + __raise_overflow_error(); + return __NULL; +} + +__attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + double result; + + /* Preserve environment, clear exception state. */ + fenv_t env; + init_env(&env, FE_OVERFLOW); + + result = i - j; + + /* Test for result, restore state, return the new float. */ + if (have_result(&env, FE_OVERFLOW)) + return make_result(&env, result); + + /* Restore state, raise exception. */ + if (test_env(&env, FE_OVERFLOW)) + __raise_overflow_error(); + return __NULL; +} + +__attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + double result; + + /* Preserve environment, clear exception state. */ + fenv_t env; + init_env(&env, FE_OVERFLOW | FE_UNDERFLOW); + + result = i * j; + + /* Test for result, restore state, return the new float. */ + if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW)) + return make_result(&env, result); + + /* Restore state, raise exception. */ + if (test_env(&env, FE_OVERFLOW)) + __raise_overflow_error(); + if (test_env(&env, FE_UNDERFLOW)) + __raise_underflow_error(); + return __NULL; +} + +__attr __fn_native_float_float_div(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + double result; + + /* Preserve environment, clear exception state. */ + fenv_t env; + init_env(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO); + + result = i / j; + + /* Test for result, restore state, return the new float. */ + if (have_result(&env, FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO)) + return make_result(&env, result); + + /* Restore state, raise exception. */ + if (test_env(&env, FE_OVERFLOW)) + __raise_overflow_error(); + if (test_env(&env, FE_UNDERFLOW)) + __raise_underflow_error(); + if (test_env(&env, FE_DIVBYZERO)) + __raise_zero_division_error(); + return __NULL; +} + +__attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + double result; + + /* Preserve environment, clear exception state. */ + fenv_t env; + init_env(&env, FE_OVERFLOW | FE_DIVBYZERO); + + result = fmod(i, j); + + /* Test for result, restore state, return the new float. */ + if (have_result(&env, FE_OVERFLOW | FE_DIVBYZERO)) + return make_result(&env, result); + + /* Restore state, raise exception. */ + if (test_env(&env, FE_OVERFLOW)) + __raise_overflow_error(); + if (test_env(&env, FE_DIVBYZERO)) + __raise_zero_division_error(); + return __NULL; +} + +__attr __fn_native_float_float_neg(__attr __self, __attr self) +{ + /* self interpreted as float */ + double i = __TOFLOAT(self); + double result; + + /* Preserve environment, clear exception state. */ + fenv_t env; + init_env(&env, FE_OVERFLOW); + + result = -i; + + /* Test for result, restore state, return the new float. */ + if (have_result(&env, FE_OVERFLOW)) + return make_result(&env, result); + + /* Restore state, raise exception. */ + if (test_env(&env, FE_OVERFLOW)) + __raise_overflow_error(); + return __NULL; +} + +__attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + double result; + + errno = 0; + result = pow(i, j); + + /* Test for overflow. */ + + if (errno == ERANGE) + __raise_overflow_error(); + + /* Return the result. */ + return __new_float(result); +} + +__attr __fn_native_float_float_le(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + + /* Return a boolean result. */ + return i <= j ? __builtins___boolean_True : __builtins___boolean_False; +} + +__attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + + /* Return a boolean result. */ + return i < j ? __builtins___boolean_True : __builtins___boolean_False; +} + +__attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + + /* Return a boolean result. */ + return i >= j ? __builtins___boolean_True : __builtins___boolean_False; +} + +__attr __fn_native_float_float_gt(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + + /* Return a boolean result. */ + return i > j ? __builtins___boolean_True : __builtins___boolean_False; +} + +__attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + + /* Return a boolean result. */ + return i == j ? __builtins___boolean_True : __builtins___boolean_False; +} + +__attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other) +{ + /* self and other interpreted as float */ + double i = __TOFLOAT(self); + double j = __TOFLOAT(other); + + /* Return a boolean result. */ + return i != j ? __builtins___boolean_True : __builtins___boolean_False; +} + +__attr __fn_native_float_float_str(__attr __self, __attr self) +{ + /* self interpreted as float */ + double i = __TOFLOAT(self); + + /* Return a new string. */ + return format_number(i, 64); +} + +__attr __fn_native_float_float_int(__attr __self, __attr self) +{ + /* self interpreted as float */ + double i = __TOFLOAT(self); + + /* NOTE: Test for conversion failure. */ + return __new_int((int) i); +} + +/* Module initialisation. */ + +void __main_native_float() +{ +} diff -r 81587921b9b4 -r 6024d7e1d83a templates/native/float.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/native/float.h Thu Jul 12 00:15:16 2018 +0200 @@ -0,0 +1,48 @@ +/* Native functions for floating point operations. + +Copyright (C) 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +*/ + +#ifndef __NATIVE_FLOAT_H__ +#define __NATIVE_FLOAT_H__ + +#include "types.h" + +/* Floating point operations. */ + +__attr __fn_native_float_float_add(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_div(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_neg(__attr __self, __attr self); +__attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other); + +__attr __fn_native_float_float_le(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_gt(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other); +__attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other); + +__attr __fn_native_float_float_str(__attr __self, __attr self); +__attr __fn_native_float_float_int(__attr __self, __attr self); + +/* Module initialisation. */ + +void __main_native_float(); + +#endif /* __NATIVE_FLOAT_H__ */ diff -r 81587921b9b4 -r 6024d7e1d83a templates/native/int.c --- a/templates/native/int.c Wed Jul 11 23:53:09 2018 +0200 +++ b/templates/native/int.c Thu Jul 12 00:15:16 2018 +0200 @@ -1,6 +1,6 @@ /* Native functions for integer operations. -Copyright (C) 2016, 2017 Paul Boddie +Copyright (C) 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -290,6 +290,14 @@ return __new_str(s, strlen(s)); } +__attr __fn_native_int_int_float(__attr __self, __attr self) +{ + /* self interpreted as int */ + int i = __TOINT(self); + + return __new_float((double) i); +} + /* Module initialisation. */ void __main_native_int() diff -r 81587921b9b4 -r 6024d7e1d83a templates/native/int.h --- a/templates/native/int.h Wed Jul 11 23:53:09 2018 +0200 +++ b/templates/native/int.h Thu Jul 12 00:15:16 2018 +0200 @@ -1,6 +1,6 @@ /* Native functions for integer operations. -Copyright (C) 2016, 2017 Paul Boddie +Copyright (C) 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -48,6 +48,7 @@ __attr __fn_native_int_int_ne(__attr __self, __attr _data, __attr other); __attr __fn_native_int_int_str(__attr __self, __attr _data); +__attr __fn_native_int_int_float(__attr __self, __attr _data); /* Module initialisation. */ diff -r 81587921b9b4 -r 6024d7e1d83a templates/ops.c --- a/templates/ops.c Wed Jul 11 23:53:09 2018 +0200 +++ b/templates/ops.c Thu Jul 12 00:15:16 2018 +0200 @@ -1,6 +1,6 @@ /* Common operations. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -30,7 +30,7 @@ if (!__INTEGER(attr)) return attr.value; else - return &__common_integer_obj; + return (__ref) &__common_integer_obj; } /* Basic structure tests. */ diff -r 81587921b9b4 -r 6024d7e1d83a templates/progops.c --- a/templates/progops.c Wed Jul 11 23:53:09 2018 +0200 +++ b/templates/progops.c Thu Jul 12 00:15:16 2018 +0200 @@ -156,6 +156,11 @@ __Raise(__new___builtins___core_TypeError(__NULL)); } +void __raise_underflow_error() +{ + __Raise(__new___builtins___core_UnderflowError(__NULL)); +} + void __raise_zero_division_error() { __Raise(__new___builtins___core_ZeroDivisionError(__NULL)); @@ -303,7 +308,7 @@ __ref value = __VALUE(attr); - return value == &__predefined___builtins___boolean_True ? 1 : - value == &__predefined___builtins___boolean_False ? 0 : - __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == &__predefined___builtins___boolean_True; + return value == (__ref) &__predefined___builtins___boolean_True ? 1 : + value == (__ref) &__predefined___builtins___boolean_False ? 0 : + __VALUE(__fn___builtins___boolean_bool(__NULL, attr)) == (__ref) &__predefined___builtins___boolean_True; } diff -r 81587921b9b4 -r 6024d7e1d83a templates/progops.h --- a/templates/progops.h Wed Jul 11 23:53:09 2018 +0200 +++ b/templates/progops.h Thu Jul 12 00:15:16 2018 +0200 @@ -1,6 +1,6 @@ /* Operations depending on program specifics. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -38,25 +38,22 @@ #define __newliteral___builtins___list_list(NUM, ...) __newdata_list(NUM, __ARGS(__VA_ARGS__)) #define __newliteral___builtins___tuple_tuple(NUM, ...) __newdata_tuple(NUM, __ARGS(__VA_ARGS__)) +/* Potentially superfluous operations. */ + #ifdef __HAVE___builtins___dict_dict __attr __newdata_dict(unsigned int number, __attr args[]); #define __newliteral___builtins___dict_dict(NUM, ...) __newdata_dict(NUM, __ARGS(__VA_ARGS__)) -#endif /* __HAVE___builtins___dict_dict */ +#endif /* Helpers for raising errors within common operations. */ void __raise_eof_error(); - void __raise_io_error(__attr value); - void __raise_memory_error(); - void __raise_os_error(__attr value, __attr arg); - void __raise_overflow_error(); - +void __raise_underflow_error(); void __raise_zero_division_error(); - void __raise_type_error(); /* Helper for raising exception instances. */ @@ -76,17 +73,21 @@ /* Generic operations depending on specific program details. */ void __SETDEFAULT(__ref obj, int pos, __attr value); - __attr __GETDEFAULT(__ref obj, int pos); - int __BOOL(__attr attr); /* Convenience definitions. */ -#define __INSTANCESIZE(CLS) sizeof(__obj_##CLS) +#define __OBJTYPE(CLS) __obj_##CLS +#define __INSTANCESIZE(CLS) sizeof(__OBJTYPE(CLS)) #define __INSTANCETABLE(CLS) (__InstanceTable_##CLS) #define __NEWINSTANCE(CLS) __new(&__INSTANCETABLE(CLS), &CLS, __INSTANCESIZE(CLS), 0) #define __NEWINSTANCEIM(CLS) __new(&__INSTANCETABLE(CLS), &CLS, __INSTANCESIZE(CLS), 1) #define __ISINSTANCE(ATTR, TYPE) __BOOL(__fn_native_introspection_isinstance(__NULL, ATTR, TYPE)) +/* Operations for accessing trailing data. */ + +#define __get_trailing_data(ATTR, TYPE) (((__OBJTYPE(TYPE) *) ((ATTR).value))->trailing) +#define __set_trailing_data(ATTR, TYPE, VALUE) ((__OBJTYPE(TYPE) *) ((ATTR).value))->trailing = VALUE; + #endif /* __PROGOPS_H__ */ diff -r 81587921b9b4 -r 6024d7e1d83a templates/types.h --- a/templates/types.h Wed Jul 11 23:53:09 2018 +0200 +++ b/templates/types.h Thu Jul 12 00:15:16 2018 +0200 @@ -1,6 +1,6 @@ /* Runtime types. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -85,7 +85,6 @@ __ppos pos; /* parameter table position for key */ }; __attr (*fn)(); /* callable details */ - float floatvalue; /* floating point value */ char * strvalue; /* string value */ __fragment * seqvalue; /* sequence data */ void * datavalue; /* object-specific data */ @@ -96,6 +95,11 @@ const __table * table; /* attribute table */ __ppos pos; /* position of attribute indicating class */ __attr attrs[]; /* attributes */ + + /* Specialisations of this type may add other members. + See generator.py for type generation, progops.h for definitions, and + the generated progtypes.h for the final details. */ + } __obj; #define __INSTANCE_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + sizeof(__table *) + sizeof(__ppos)) @@ -117,7 +121,7 @@ /* Attribute value setting. */ -#define __ATTRVALUE(VALUE) ((__attr) {.value=VALUE}) +#define __ATTRVALUE(VALUE) ((__attr) {.value=(__ref) VALUE}) #define __NULL __ATTRVALUE(0) #define __SETNULL(ATTR) ((ATTR).value = 0) diff -r 81587921b9b4 -r 6024d7e1d83a tests/numbers.py --- a/tests/numbers.py Wed Jul 11 23:53:09 2018 +0200 +++ b/tests/numbers.py Thu Jul 12 00:15:16 2018 +0200 @@ -55,6 +55,21 @@ print "# hash((sys.maxint - 1, 0)):", print hash((sys.maxint - 1, 0)) +# Floating point numbers. + +i = 2.0 ** 29 +print i # 536870912.0 +j = -2.0 ** 29 +print j # -536870912.0 +print i + j # 0 +print i - j # -1073741824.0 +print i * i # 2.8823037615171174e+17 + +try: + print i ** i +except OverflowError: + print "i ** i: overflow occurred" + # Test combining numbers with strings. s = "Number is " + str(123)