# HG changeset patch # User Paul Boddie # Date 1693612257 -7200 # Node ID a86d8a7da761bd25232ed7f8f634a46b0b3e7f5b # Parent 15feae4d469e03b9487878cdc411a37713b31e64# Parent 69c9a31a68eef250ad87933002f9b2789eac8fe5 Merged changes from the trailing-data branch. diff -r 15feae4d469e -r a86d8a7da761 README.txt --- a/README.txt Fri Sep 01 23:41:53 2023 +0200 +++ b/README.txt Sat Sep 02 01:50:57 2023 +0200 @@ -24,6 +24,25 @@ reconfigure such tools. However, an alternative suffix is likely to be introduced in future. +A Note about the Documentation +------------------------------ + +The original content in docs/wiki aims to be readable as plain text under most +circumstances, but the intention is that this content be translated to HTML +since it employs a formatting language based on the MoinMoin wiki format +syntax. + +The following command can be used to generate the HTML form of the +documentation from the main directory of this distribution: + +./docs/tools/make_docs.sh + +Specify the --web option for Web server deployment: + +./docs/tools/make_docs.sh --web + +To generate individual documents, specify their names after any options. + Getting Started =============== @@ -107,27 +126,3 @@ Copyright and licence information can be found in the docs directory - see docs/COPYING.txt and docs/gpl-3.0.txt for more information. - -Generating the Wiki Pages -========================= - -The docs/tools/make_pages.sh script generates a page package for MoinMoin. The -following command will generate a page package called pages.zip using the -pages directory for staging, with Lichen as the page prefix: - -docs/tools/make_pages.sh pages Lichen - -Make sure to include the page prefix where the pages are being deployed in a -wiki with other content at the top level. - -Currently, the wiki pages require the following extensions: - -ImprovedTableParser https://moinmo.in/ParserMarket/ImprovedTableParser - -MoinSupport http://hgweb.boddie.org.uk/MoinSupport - -GraphvizParser https://moinmo.in/ParserMarket/graphviz - -The GraphvizParser requires diagram-tools for the notugly.xsl stylesheet, -although a copy of the stylesheet is provided in the GraphvizParser -distribution for convenience. diff -r 15feae4d469e -r a86d8a7da761 common.py --- a/common.py Fri Sep 01 23:41:53 2023 +0200 +++ b/common.py Sat Sep 02 01:50:57 2023 +0200 @@ -362,9 +362,15 @@ l = [] for n in node.getChildNodes(): - l.append(self.process_structure_node(n)) + l.append(self.process_statement_node(n)) return l + def process_statement_node(self, node): + + "Process the given statement 'node'." + + return self.process_structure_node(node) + def process_augassign_node(self, n): "Process the given augmented assignment node 'n'." diff -r 15feae4d469e -r a86d8a7da761 docs/tools/make_docs.sh --- a/docs/tools/make_docs.sh Fri Sep 01 23:41:53 2023 +0200 +++ b/docs/tools/make_docs.sh Sat Sep 02 01:50:57 2023 +0200 @@ -2,7 +2,6 @@ THISDIR=`dirname "$0"` INDIR="$THISDIR/../wiki" -OUTDIR="$THISDIR/../html" ROOT="Lichen" @@ -16,6 +15,13 @@ DOCINDEX='--document-index index.html' fi +if [ "$1" = '-o' ] ; then + OUTDIR="$2" + shift 2 +else + OUTDIR="$THISDIR/../html" +fi + FILENAMES=${*:-'--all'} moinconvert --input-dir "$INDIR" \ diff -r 15feae4d469e -r a86d8a7da761 docs/wiki/Prerequisites --- a/docs/wiki/Prerequisites Fri Sep 01 23:41:53 2023 +0200 +++ b/docs/wiki/Prerequisites Sat Sep 02 01:50:57 2023 +0200 @@ -15,3 +15,6 @@ As Free Software, priority has been given to supporting Lichen on Free Software platforms, with Debian GNU/Linux being the development platform. Proprietary platforms are neither supported nor recommended. + +To generate HTML documentation, the [[https://projects.boddie.org.uk/MoinLight| +MoinLight]] distribution is required. diff -r 15feae4d469e -r a86d8a7da761 encoders.py --- a/encoders.py Fri Sep 01 23:41:53 2023 +0200 +++ b/encoders.py Sat Sep 02 01:50:57 2023 +0200 @@ -521,6 +521,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 15feae4d469e -r a86d8a7da761 generator.py --- a/generator.py Fri Sep 01 23:41:53 2023 +0200 +++ b/generator.py Sat Sep 02 01:50:57 2023 +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): """ @@ -184,6 +192,7 @@ #include #include #include "gc.h" +#include "signals.h" #include "types.h" #include "exceptions.h" #include "ops.h" @@ -219,6 +228,7 @@ if kind != "": structure = [] + trailing = [] attrs = self.get_static_attributes(kind, path, attrnames) # Set a special instantiator on the class. @@ -244,12 +254,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) - 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. @@ -296,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. @@ -410,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) @@ -616,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. @@ -657,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 +848,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 +952,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): @@ -1018,7 +1066,7 @@ # Special internal size member. elif attrname == "__size__": - structure.append("{.sizevalue=%d}" % attr) + structure.append("{.intvalue=__FROMINT(%d)}" % attr) continue # Special internal key member. @@ -1101,6 +1149,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 +1217,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): @@ -1269,6 +1332,8 @@ GC_INIT(); + __signals_install_handlers(); + __Try {""" diff -r 15feae4d469e -r a86d8a7da761 lib/__builtins__/core.py --- a/lib/__builtins__/core.py Fri Sep 01 23:41:53 2023 +0200 +++ b/lib/__builtins__/core.py Sat Sep 02 01:50:57 2023 +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 15feae4d469e -r a86d8a7da761 lib/__builtins__/float.py --- a/lib/__builtins__/float.py Fri Sep 01 23:41:53 2023 +0200 +++ b/lib/__builtins__/float.py Sat Sep 02 01:50:57 2023 +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, 2021 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 unicode +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 unicode(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 15feae4d469e -r a86d8a7da761 lib/native/__init__.py --- a/lib/native/__init__.py Fri Sep 01 23:41:53 2023 +0200 +++ b/lib/native/__init__.py Sat Sep 02 01:50:57 2023 +0200 @@ -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 15feae4d469e -r a86d8a7da761 lib/native/float.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/native/float.py Sat Sep 02 01:50:57 2023 +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 15feae4d469e -r a86d8a7da761 lib/native/int.py --- a/lib/native/int.py Fri Sep 01 23:41:53 2023 +0200 +++ b/lib/native/int.py Sat Sep 02 01:50:57 2023 +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 15feae4d469e -r a86d8a7da761 lib/operator/augmented.py --- a/lib/operator/augmented.py Fri Sep 01 23:41:53 2023 +0200 +++ b/lib/operator/augmented.py Sat Sep 02 01:50:57 2023 +0200 @@ -3,7 +3,7 @@ """ Operator support. -Copyright (C) 2010, 2013, 2015, 2017 Paul Boddie +Copyright (C) 2010, 2013, 2015, 2017, 2019 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 @@ -22,7 +22,8 @@ from operator.core import augassign from native import int_add, int_div, int_mod, int_mul, int_pow, int_sub, \ int_and, int_or, int_xor, \ - is_int + is_int, \ + float_add, float_div, float_mul, float_pow, float_sub # These functions defer method lookup by wrapping the attribute access in # lambda functions. Thus, the appropriate methods are defined locally, but no @@ -36,6 +37,8 @@ def iadd(a, b): if is_int(a) and is_int(b): return int_add(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_add(a, b) return augassign(a, b, lambda a: a.__iadd__, lambda a: a.__add__, lambda b: b.__radd__) def iand_(a, b): @@ -46,6 +49,8 @@ def idiv(a, b): if is_int(a) and is_int(b): return int_div(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_div(a, b) return augassign(a, b, lambda a: a.__idiv__, lambda a: a.__div__, lambda b: b.__rdiv__) def ifloordiv(a, b): @@ -62,6 +67,8 @@ def imul(a, b): if is_int(a) and is_int(b): return int_mul(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_mul(a, b) return augassign(a, b, lambda a: a.__imul__, lambda a: a.__mul__, lambda b: b.__rmul__) def ior_(a, b): @@ -72,6 +79,8 @@ def ipow(a, b): if is_int(a) and is_int(b): return int_pow(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_pow(a, b) return augassign(a, b, lambda a: a.__ipow__, lambda a: a.__pow__, lambda b: b.__rpow__) def irshift(a, b): @@ -80,6 +89,8 @@ def isub(a, b): if is_int(a) and is_int(b): return int_sub(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_sub(a, b) return augassign(a, b, lambda a: a.__isub__, lambda a: a.__sub__, lambda b: b.__rsub__) def ixor(a, b): diff -r 15feae4d469e -r a86d8a7da761 lib/operator/binary.py --- a/lib/operator/binary.py Fri Sep 01 23:41:53 2023 +0200 +++ b/lib/operator/binary.py Sat Sep 02 01:50:57 2023 +0200 @@ -3,7 +3,8 @@ """ Operator support. -Copyright (C) 2010, 2013, 2015, 2016, 2017 Paul Boddie +Copyright (C) 2010, 2013, 2015, 2016, 2017, + 2019 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 @@ -23,7 +24,9 @@ from native import int_add, int_div, int_mod, int_mul, int_pow, int_sub, \ int_lshift, int_rshift, \ int_and, int_not, int_or, int_xor, \ - is_int + is_int, \ + float_add, float_div, float_mul, float_pow, float_sub, \ + int_float # These functions defer method lookup by wrapping the attribute access in # lambda functions. Thus, the appropriate methods are defined locally, but no @@ -34,6 +37,8 @@ def add(a, b): if is_int(a) and is_int(b): return int_add(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_add(a, b) return binary_op(a, b, lambda a: a.__add__, lambda b: b.__radd__) def and_(a, b): @@ -47,6 +52,8 @@ def div(a, b): if is_int(a) and is_int(b): return int_div(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_div(a, b) return binary_op(a, b, lambda a: a.__div__, lambda b: b.__rdiv__) def floordiv(a, b): @@ -71,6 +78,8 @@ def mul(a, b): if is_int(a) and is_int(b): return int_mul(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_mul(a, b) return binary_op(a, b, lambda a: a.__mul__, lambda b: b.__rmul__) def or_(a, b): @@ -81,6 +90,11 @@ def pow(a, b): if is_int(a) and is_int(b): return int_pow(a, b) + elif a.__class__ is float: + if is_int(b): + return float_pow(a, int_float(b)) + if b.__class__ is float: + return float_pow(a, b) return binary_op(a, b, lambda a: a.__pow__, lambda b: b.__rpow__) def rshift(a, b): @@ -91,6 +105,8 @@ def sub(a, b): if is_int(a) and is_int(b): return int_sub(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_sub(a, b) return binary_op(a, b, lambda a: a.__sub__, lambda b: b.__rsub__) def xor(a, b): diff -r 15feae4d469e -r a86d8a7da761 lib/operator/comparison.py --- a/lib/operator/comparison.py Fri Sep 01 23:41:53 2023 +0200 +++ b/lib/operator/comparison.py Sat Sep 02 01:50:57 2023 +0200 @@ -3,7 +3,8 @@ """ Operator support. -Copyright (C) 2010, 2013, 2015, 2016, 2017 Paul Boddie +Copyright (C) 2010, 2013, 2015, 2016, 2017, + 2019 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 @@ -20,7 +21,8 @@ """ from operator.core import binary_op -from native import int_eq, int_ge, int_gt, int_le, int_lt, int_ne, is_int +from native import int_eq, int_ge, int_gt, int_le, int_lt, int_ne, is_int, \ + float_eq, float_ge, float_gt, float_le, float_lt, float_ne # These functions defer method lookup by wrapping the attribute access in # lambda functions. Thus, the appropriate methods are defined locally, but no @@ -31,31 +33,43 @@ def eq(a, b): if is_int(a) and is_int(b): return int_eq(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_eq(a, b) return binary_op(a, b, lambda a: a.__eq__, lambda b: b.__eq__, False) def ge(a, b): if is_int(a) and is_int(b): return int_ge(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_ge(a, b) return binary_op(a, b, lambda a: a.__ge__, lambda b: b.__le__) def gt(a, b): if is_int(a) and is_int(b): return int_gt(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_gt(a, b) return binary_op(a, b, lambda a: a.__gt__, lambda b: b.__lt__) def le(a, b): if is_int(a) and is_int(b): return int_le(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_le(a, b) return binary_op(a, b, lambda a: a.__le__, lambda b: b.__ge__) def lt(a, b): if is_int(a) and is_int(b): return int_lt(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_lt(a, b) return binary_op(a, b, lambda a: a.__lt__, lambda b: b.__gt__) def ne(a, b): if is_int(a) and is_int(b): return int_ne(a, b) + elif a.__class__ is float and b.__class__ is float: + return float_ne(a, b) return binary_op(a, b, lambda a: a.__ne__, lambda b: b.__ne__, True) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 15feae4d469e -r a86d8a7da761 lib/operator/unary.py --- a/lib/operator/unary.py Fri Sep 01 23:41:53 2023 +0200 +++ b/lib/operator/unary.py Sat Sep 02 01:50:57 2023 +0200 @@ -3,7 +3,8 @@ """ Operator support. -Copyright (C) 2010, 2013, 2015, 2016, 2017 Paul Boddie +Copyright (C) 2010, 2013, 2015, 2016, 2017, + 2019 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 @@ -20,7 +21,7 @@ """ from operator.core import unary_op -from native.int import int_neg, int_not, is_int +from native import int_neg, int_not, is_int, float_neg # These functions defer method lookup by wrapping the attribute access in # lambda functions. Thus, the appropriate methods are defined locally, but no @@ -34,6 +35,8 @@ def neg(a): if is_int(a): return int_neg(a) + elif a.__class__ is float: + return float_neg(a) return unary_op(a, lambda a: a.__neg__) def not_(a): @@ -42,7 +45,7 @@ return not a def pos(a): - if is_int(a): + if is_int(a) or a.__class__ is float: return a return unary_op(a, lambda a: a.__pos__) diff -r 15feae4d469e -r a86d8a7da761 templates/Makefile --- a/templates/Makefile Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/Makefile Sat Sep 02 01:50:57 2023 +0200 @@ -2,7 +2,7 @@ include modules.mk include options.mk -SRC += calls.c exceptions.c main.c ops.c progops.c progtypes.c +SRC += calls.c exceptions.c main.c ops.c progops.c progtypes.c signals.c OBJ = $(SRC:.c=.o) CFLAGS += -Wall -Wno-maybe-uninitialized -I. -finput-charset=UTF-8 LDFLAGS += -lm -lgc diff -r 15feae4d469e -r a86d8a7da761 templates/native/buffer.c --- a/templates/native/buffer.c Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/native/buffer.c Sat Sep 02 01:50:57 2023 +0200 @@ -36,7 +36,7 @@ /* Calculate the size of the string. */ for (i = 0; i < data->size; i++) - size += __load_via_object(__VALUE(data->attrs[i]), __size__).sizevalue; + size += __TOINT(__load_via_object(__VALUE(data->attrs[i]), __size__)); /* Reserve space for a new string. */ s = (char *) __ALLOCATE(size + 1, sizeof(char)); @@ -45,7 +45,7 @@ for (i = 0, j = 0; i < data->size; i++) { o = __load_via_object(__VALUE(data->attrs[i]), __data__); - n = __load_via_object(__VALUE(data->attrs[i]), __size__).sizevalue; + n = __TOINT(__load_via_object(__VALUE(data->attrs[i]), __size__)); memcpy(s + j, o.strvalue, n); /* does not null terminate but final byte should be zero */ j += n; } diff -r 15feae4d469e -r a86d8a7da761 templates/native/common.c --- a/templates/native/common.c Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/native/common.c Sat Sep 02 01:50:57 2023 +0200 @@ -31,7 +31,7 @@ /* Create a new string and mutate the __data__, __size__ and __key__ attributes. */ __attr attr = __NEWINSTANCE(__builtins___str_str); __store_via_object(__VALUE(attr), __data__, (__attr) {.strvalue=s}); - __store_via_object(__VALUE(attr), __size__, (__attr) {.sizevalue=size}); + __store_via_object(__VALUE(attr), __size__, __INTVALUE(size)); __store_via_object(__VALUE(attr), __key__, __NULL); return attr; } @@ -44,6 +44,14 @@ return attr; } +__attr __new_float(double n) +{ + /* Create a new float and set the trailing data. */ + __attr attr = __NEWINSTANCEIM(__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 15feae4d469e -r a86d8a7da761 templates/native/common.h --- a/templates/native/common.h Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/native/common.h Sat Sep 02 01:50:57 2023 +0200 @@ -1,6 +1,6 @@ /* Common operations for native functions. -Copyright (C) 2016, 2017 Paul Boddie +Copyright (C) 2016, 2017, 2018, 2021 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 15feae4d469e -r a86d8a7da761 templates/native/float.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/native/float.c Sat Sep 02 01:50:57 2023 +0200 @@ -0,0 +1,216 @@ +/* Native functions for floating point operations. + +Copyright (C) 2016, 2017, 2018, 2019 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 /* 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 of trailing data 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 operations. Exceptions are raised in the signal handler. */ + +__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); + return __new_float(i + j); +} + +__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); + return __new_float(i - j); +} + +__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); + return __new_float(i * j); +} + +__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); + return __new_float(i / j); +} + +__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); + return __new_float(fmod(i, j)); +} + +__attr __fn_native_float_float_neg(__attr __self, __attr self) +{ + /* self interpreted as float */ + double i = __TOFLOAT(self); + return __new_float(-i); +} + +__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 15feae4d469e -r a86d8a7da761 templates/native/float.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/native/float.h Sat Sep 02 01:50:57 2023 +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 15feae4d469e -r a86d8a7da761 templates/native/int.c --- a/templates/native/int.c Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/native/int.c Sat Sep 02 01:50:57 2023 +0200 @@ -1,6 +1,6 @@ /* Native functions for integer operations. -Copyright (C) 2016, 2017, 2021 Paul Boddie +Copyright (C) 2016, 2017, 2018, 2021 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 @@ -294,6 +294,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 15feae4d469e -r a86d8a7da761 templates/native/int.h --- a/templates/native/int.h Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/native/int.h Sat Sep 02 01:50:57 2023 +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 15feae4d469e -r a86d8a7da761 templates/native/io.c --- a/templates/native/io.c Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/native/io.c Sat Sep 02 01:50:57 2023 +0200 @@ -150,7 +150,7 @@ /* str.__data__ interpreted as string */ char *s = __load_via_object(__VALUE(str), __data__).strvalue; /* str.__size__ interpreted as int */ - size_t to_write = __load_via_object(__VALUE(str), __size__).sizevalue; + size_t to_write = __TOINT(__load_via_object(__VALUE(str), __size__)); size_t have_written = fwrite(s, sizeof(char), to_write, f); int error; @@ -207,7 +207,7 @@ /* str.__data__ interpreted as string */ char *s = __load_via_object(__VALUE(str), __data__).strvalue; /* str.__size__ interpreted as int */ - size_t size = __load_via_object(__VALUE(str), __size__).sizevalue; + size_t size = __TOINT(__load_via_object(__VALUE(str), __size__)); ssize_t have_written; errno = 0; diff -r 15feae4d469e -r a86d8a7da761 templates/native/str.c --- a/templates/native/str.c Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/native/str.c Sat Sep 02 01:50:57 2023 +0200 @@ -34,7 +34,7 @@ char *s = _data.strvalue; char *o = other.strvalue; /* _size, othersize interpreted as size */ - __int ss = _size.sizevalue, os = othersize.sizevalue; + __int ss = __TOINT(_size), os = __TOINT(othersize); __int n = ss + os; char *r = (char *) __ALLOCATE(n + 1, sizeof(char)); @@ -95,7 +95,7 @@ __attr __fn_native_str_str_size(__attr __self, __attr _size) { - return __new_int(_size.sizevalue); + return __new_int(__TOINT(_size)); } __attr __fn_native_str_str_substr(__attr __self, __attr _data, __attr start, __attr end, __attr step) diff -r 15feae4d469e -r a86d8a7da761 templates/native/unicode.c --- a/templates/native/unicode.c Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/native/unicode.c Sat Sep 02 01:50:57 2023 +0200 @@ -74,7 +74,7 @@ /* _data interpreted as string.__data__ */ char *s = _data.strvalue; /* _size interpreted as size */ - __int size = _size.sizevalue; + __int size = __TOINT(_size); __int i, c = 0; for (i = 0; i < size; i++) @@ -90,7 +90,7 @@ /* _data interpreted as string.__data__ */ char *s = _data.strvalue; /* _size interpreted as size */ - __int size = _size.sizevalue; + __int size = __TOINT(_size); __int i, c = 0, v; for (i = 0; i < size; i++) @@ -124,7 +124,7 @@ /* _data interpreted as string.__data__ */ char *s = _data.strvalue, *sub; /* _size interpreted as size */ - __int ss = _size.sizevalue; + __int ss = __TOINT(_size); /* start interpreted as int */ __int istart = __TOINT(start); /* end interpreted as int */ diff -r 15feae4d469e -r a86d8a7da761 templates/ops.c --- a/templates/ops.c Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/ops.c Sat Sep 02 01:50:57 2023 +0200 @@ -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 15feae4d469e -r a86d8a7da761 templates/progops.c --- a/templates/progops.c Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/progops.c Sat Sep 02 01:50:57 2023 +0200 @@ -1,6 +1,6 @@ /* Operations depending on program specifics. -Copyright (C) 2015, 2016, 2017, 2018, 2021 Paul Boddie +Copyright (C) 2015-2019, 2021 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 @@ -127,6 +127,11 @@ #endif /* __HAVE___builtins___exception_io_EOFError */ } +void __raise_floating_point_error() +{ + __Raise(__new___builtins___core_FloatingPointError(__NULL)); +} + void __raise_io_error(__attr value) { #ifdef __HAVE___builtins___exception_io_IOError @@ -161,6 +166,11 @@ __Raise(__new___builtins___core_TypeError(__NULL)); } +void __raise_underflow_error() +{ + __Raise(__new___builtins___core_UnderflowError(__NULL)); +} + void __raise_value_error(__attr value) { #ifdef __HAVE___builtins___exception_base_ValueError @@ -324,7 +334,7 @@ value = attr.value; - 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 15feae4d469e -r a86d8a7da761 templates/progops.h --- a/templates/progops.h Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/progops.h Sat Sep 02 01:50:57 2023 +0200 @@ -1,6 +1,6 @@ /* Operations depending on program specifics. -Copyright (C) 2015, 2016, 2017, 2018, 2021 Paul Boddie +Copyright (C) 2015-2019, 2021 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,29 +38,25 @@ #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(__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_floating_point_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_unbound_method_error(); - +void __raise_underflow_error(); void __raise_value_error(__attr value); - void __raise_zero_division_error(); - void __raise_type_error(); /* Helper for raising exception instances. */ @@ -80,17 +76,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 15feae4d469e -r a86d8a7da761 templates/signals.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/signals.c Sat Sep 02 01:50:57 2023 +0200 @@ -0,0 +1,60 @@ +/* Signal handling. + +Copyright (C) 2019 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 +#include + +#include "signals.h" +#include "progops.h" + +void __signals_install_handlers() +{ + struct sigaction context; + + context.sa_flags = SA_SIGINFO; + context.sa_sigaction = __signals_fpe_handler; + sigemptyset(&context.sa_mask); + + /* NOTE: Should test for -1 and errno. */ + + sigaction(SIGFPE, &context, NULL); +} + +void __signals_fpe_handler(int signum, siginfo_t *siginfo, void *context) +{ + /* Return from setjmp using the signal number. */ + + switch (siginfo->si_code) + { + case FPE_FLTOVF: + __raise_overflow_error(); + break; + + case FPE_FLTUND: + __raise_underflow_error(); + break; + + case FPE_FLTDIV: + __raise_zero_division_error(); + break; + + default: + __raise_floating_point_error(); + break; + } +} diff -r 15feae4d469e -r a86d8a7da761 templates/signals.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/signals.h Sat Sep 02 01:50:57 2023 +0200 @@ -0,0 +1,27 @@ +/* Signal handling. + +Copyright (C) 2019 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 __SIGNALS_H__ +#define __SIGNALS_H__ + +#include + +void __signals_install_handlers(); +void __signals_fpe_handler(int signum, siginfo_t *siginfo, void *context); + +#endif /* __SIGNALS_H__ */ diff -r 15feae4d469e -r a86d8a7da761 templates/types.h --- a/templates/types.h Fri Sep 01 23:41:53 2023 +0200 +++ b/templates/types.h Sat Sep 02 01:50:57 2023 +0200 @@ -82,7 +82,8 @@ /* General attribute members. */ __ref value; /* attribute value */ - __int intvalue; /* integer value data (shifted value, tagged) */ + __int intvalue; /* integer value data or object-specific size + (shifted value, tagged) */ /* Special case attribute members. */ @@ -92,11 +93,9 @@ __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 */ - __int sizevalue; /* object-specific size */ } __attr; typedef struct __obj @@ -104,6 +103,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)) @@ -132,9 +136,10 @@ #define __NULL __ATTRVALUE(0) #define __SETNULL(ATTR) ((ATTR).value = 0) -/* Attribute as instance setting. */ +/* Attribute as instance value. */ -#define __INTVALUE(VALUE) ((__attr) {.intvalue=(((__int) VALUE) << __NUM_TAG_BITS) | __TAG_INT}) +#define __FROMINT(VALUE) ((((__int) VALUE) << __NUM_TAG_BITS) | __TAG_INT) +#define __INTVALUE(VALUE) ((__attr) {.intvalue=__FROMINT(VALUE)}) #define __TOINT(ATTR) ((ATTR).intvalue >> __NUM_TAG_BITS) #define __MAXINT ((((__int) 1) << ((sizeof(__int) * 8) - 1 - __NUM_TAG_BITS)) - 1) #define __MININT (-(((__int) 1) << ((sizeof(__int) * 8) - 1 - __NUM_TAG_BITS))) diff -r 15feae4d469e -r a86d8a7da761 tests/numbers.py --- a/tests/numbers.py Fri Sep 01 23:41:53 2023 +0200 +++ b/tests/numbers.py Sat Sep 02 01:50:57 2023 +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) diff -r 15feae4d469e -r a86d8a7da761 translator.py --- a/translator.py Fri Sep 01 23:41:53 2023 +0200 +++ b/translator.py Sat Sep 02 01:50:57 2023 +0200 @@ -885,7 +885,7 @@ # Produce the body and any additional return statement. - expr = self.process_structure_node(n.code) or \ + expr = self.process_statement_node(n.code) or \ self.in_method() and \ function_name.rsplit(".", 1)[-1] == "__init__" and \ TrResolvedNameRef("self", self.importer.function_locals[function_name]["self"]) or \ @@ -1038,12 +1038,12 @@ first = True for test, body in n.tests: - test_ref = self.process_structure_node(test) + test_ref = self.process_statement_node(test) self.start_if(first, test_ref) in_conditional = self.in_conditional self.in_conditional = True - self.process_structure_node(body) + self.process_statement_node(body) self.in_conditional = in_conditional self.end_if() @@ -1051,7 +1051,7 @@ if n.else_: self.start_else() - self.process_structure_node(n.else_) + self.process_statement_node(n.else_) self.end_else() print >>self.out @@ -1769,7 +1769,7 @@ self.writestmt("__Try") self.writeline("{") self.indent += 1 - self.process_structure_node(n.body) + self.process_statement_node(n.body) # Put the else statement in another try block that handles any raised # exceptions and converts them to exceptions that will not be handled by @@ -1779,7 +1779,7 @@ self.writestmt("__Try") self.writeline("{") self.indent += 1 - self.process_structure_node(n.else_) + self.process_statement_node(n.else_) self.indent -= 1 self.writeline("}") self.writeline("__Catch (__tmp_exc)") @@ -1823,7 +1823,7 @@ # Test for specific exceptions. if name is not None: - name_ref = self.process_structure_node(name) + name_ref = self.process_statement_node(name) self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref) else: self.writeline("else if (1)") @@ -1837,7 +1837,7 @@ self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg"))) if handler is not None: - self.process_structure_node(handler) + self.process_statement_node(handler) self.indent -= 1 self.writeline("}") @@ -1866,7 +1866,7 @@ self.writestmt("__Try") self.writeline("{") self.indent += 1 - self.process_structure_node(n.body) + self.process_statement_node(n.body) self.indent -= 1 self.writeline("}") @@ -1877,7 +1877,7 @@ self.writeline("__Catch (__tmp_exc)") self.writeline("{") self.indent += 1 - self.process_structure_node(n.final) + self.process_statement_node(n.final) # Introduce an if statement to handle the completion of a try block. @@ -1918,7 +1918,7 @@ self.writeline("while (1)") self.writeline("{") self.indent += 1 - test = self.process_structure_node(n.test) + test = self.process_statement_node(n.test) # Emit the loop termination condition unless "while " is # indicated. @@ -1929,13 +1929,13 @@ self.start_if(True, self.make_negation(test)) if n.else_: - self.process_structure_node(n.else_) + self.process_statement_node(n.else_) self.writestmt("break;") self.end_if() in_conditional = self.in_conditional self.in_conditional = True - self.process_structure_node(n.body) + self.process_statement_node(n.body) self.in_conditional = in_conditional self.indent -= 1