1.1 --- a/encoders.py Mon Jan 30 22:32:38 2017 +0100
1.2 +++ b/encoders.py Mon Jan 30 22:34:46 2017 +0100
1.3 @@ -306,12 +306,6 @@
1.4 else:
1.5 return encode_path(arg), set()
1.6
1.7 -def encode_bound_reference(path):
1.8 -
1.9 - "Encode 'path' as a bound method name."
1.10 -
1.11 - return "__bound_%s" % encode_path(path)
1.12 -
1.13 def encode_function_pointer(path):
1.14
1.15 "Encode 'path' as a reference to an output program function."
2.1 --- a/generator.py Mon Jan 30 22:32:38 2017 +0100
2.2 +++ b/generator.py Mon Jan 30 22:34:46 2017 +0100
2.3 @@ -20,7 +20,7 @@
2.4 """
2.5
2.6 from common import CommonOutput, get_builtin_module, get_builtin_type
2.7 -from encoders import encode_bound_reference, encode_function_pointer, \
2.8 +from encoders import encode_function_pointer, \
2.9 encode_instantiator_pointer, \
2.10 encode_literal_constant, encode_literal_constant_member, \
2.11 encode_literal_constant_size, encode_literal_constant_value, \
2.12 @@ -282,20 +282,15 @@
2.13
2.14 if parent_kind == "<class>":
2.15
2.16 - # A bound version of a method.
2.17 + # A method.
2.18
2.19 - structure = self.populate_function(path, function_instance_attrs, False)
2.20 - self.write_structure(f_decls, f_defs, encode_bound_reference(path), table_name, structure)
2.21 -
2.22 - # An unbound version of a method.
2.23 -
2.24 - structure = self.populate_function(path, function_instance_attrs, True)
2.25 + structure = self.populate_function(path, function_instance_attrs)
2.26 self.write_structure(f_decls, f_defs, path, table_name, structure)
2.27
2.28 else:
2.29 # A normal function.
2.30
2.31 - structure = self.populate_function(path, function_instance_attrs, False)
2.32 + structure = self.populate_function(path, function_instance_attrs)
2.33 self.write_structure(f_decls, f_defs, path, table_name, structure)
2.34
2.35 # Functions with defaults need to declare instance structures.
2.36 @@ -821,32 +816,27 @@
2.37 name, pos = value
2.38 table.append((encode_symbol("pcode", name), pos))
2.39
2.40 - def populate_function(self, path, function_instance_attrs, unbound=False):
2.41 + def populate_function(self, path, function_instance_attrs):
2.42
2.43 """
2.44 Populate a structure for the function with the given 'path'. The given
2.45 - 'attrs' provide the instance attributes, and if 'unbound' is set to a
2.46 - true value, an unbound method structure is produced (as opposed to a
2.47 - callable bound method structure).
2.48 + 'attrs' provide the instance attributes.
2.49 """
2.50
2.51 structure = []
2.52 - self.populate_structure(Reference("<function>", path), function_instance_attrs, "<instance>", structure, unbound)
2.53 + self.populate_structure(Reference("<function>", path), function_instance_attrs, "<instance>", structure)
2.54
2.55 # Append default members.
2.56
2.57 self.append_defaults(path, structure)
2.58 return structure
2.59
2.60 - def populate_structure(self, ref, attrs, kind, structure, unbound=False):
2.61 + def populate_structure(self, ref, attrs, kind, structure):
2.62
2.63 """
2.64 Traverse the attributes in the determined order for the structure having
2.65 the given 'ref' whose members are provided by the 'attrs' mapping, in a
2.66 structure of the given 'kind', adding entries to the object 'structure'.
2.67 - If 'unbound' is set to a true value, an unbound method function pointer
2.68 - will be employed, with a reference to the bound method incorporated into
2.69 - the special __fn__ attribute.
2.70 """
2.71
2.72 # Populate function instance structures for functions.
2.73 @@ -877,29 +867,21 @@
2.74
2.75 if attrname == "__fn__":
2.76
2.77 - # Provide bound method references and the unbound function
2.78 - # pointer if populating methods in a class.
2.79 -
2.80 - bound_attr = None
2.81 -
2.82 - # Classes offer instantiators.
2.83 + # Classes offer instantiators which can be called without a
2.84 + # context.
2.85
2.86 if kind == "<class>":
2.87 attr = encode_instantiator_pointer(attr)
2.88 -
2.89 - # Methods offers references to bound versions and an unbound
2.90 - # method function.
2.91 + unbound_attr = attr
2.92
2.93 - elif unbound:
2.94 - bound_attr = encode_bound_reference(attr)
2.95 - attr = "__unbound_method"
2.96 -
2.97 - # Other functions just offer function pointers.
2.98 + # Provide bound method and unbound function pointers if
2.99 + # populating methods in a class.
2.100
2.101 else:
2.102 attr = encode_function_pointer(attr)
2.103 + unbound_attr = "__unbound_method"
2.104
2.105 - structure.append("{.b=%s, .fn=%s}" % (bound_attr and "&%s" % bound_attr or "0", attr))
2.106 + structure.append("{.inv=%s, .fn=%s}" % (unbound_attr, attr))
2.107 continue
2.108
2.109 # Special argument specification member.
3.1 --- a/optimiser.py Mon Jan 30 22:32:38 2017 +0100
3.2 +++ b/optimiser.py Mon Jan 30 22:34:46 2017 +0100
3.3 @@ -520,18 +520,7 @@
3.4 emit(("__test_context", context_var, accessor))
3.5
3.6 elif context_test == "replace":
3.7 -
3.8 - # Static invocation targets have a context added but no other
3.9 - # transformation performed.
3.10 -
3.11 - if final_method == "static-invoke":
3.12 - emit(("__update_context", context_var, accessor))
3.13 -
3.14 - # Other invocation targets gain a context and have the bound
3.15 - # version of the callable activated.
3.16 -
3.17 - else:
3.18 - emit(("__replace_context", context_var, accessor))
3.19 + emit(("__update_context", context_var, accessor))
3.20
3.21 elif final_method not in ("assign", "static-assign"):
3.22 emit(accessor)
4.1 --- a/templates/native/introspection.c Mon Jan 30 22:32:38 2017 +0100
4.2 +++ b/templates/native/introspection.c Mon Jan 30 22:34:46 2017 +0100
4.3 @@ -1,6 +1,6 @@
4.4 /* Native functions for introspection operations.
4.5
4.6 -Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
4.7 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
4.8
4.9 This program is free software; you can redistribute it and/or modify it under
4.10 the terms of the GNU General Public License as published by the Free Software
4.11 @@ -51,7 +51,7 @@
4.12
4.13 /* Update the context to the object if it is a method. */
4.14
4.15 - return __replace_context(obj->value, out);
4.16 + return __update_context(obj->value, out);
4.17 }
4.18
4.19 return out;
5.1 --- a/templates/ops.c Mon Jan 30 22:32:38 2017 +0100
5.2 +++ b/templates/ops.c Mon Jan 30 22:34:46 2017 +0100
5.3 @@ -1,6 +1,6 @@
5.4 /* Common operations.
5.5
5.6 -Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
5.7 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
5.8
5.9 This program is free software; you can redistribute it and/or modify it under
5.10 the terms of the GNU General Public License as published by the Free Software
5.11 @@ -21,6 +21,7 @@
5.12 #include "progops.h" /* for raising errors */
5.13 #include "progconsts.h"
5.14 #include "progtypes.h"
5.15 +#include <stdio.h>
5.16
5.17 /* Direct access and manipulation of static objects. */
5.18
5.19 @@ -202,7 +203,7 @@
5.20 if (__is_instance(context))
5.21 {
5.22 if (__test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context)))
5.23 - return __replace_context(context, attr);
5.24 + return __update_context(context, attr);
5.25 else
5.26 __raise_type_error();
5.27 }
5.28 @@ -210,34 +211,58 @@
5.29 /* Test for access to a type class attribute using a type instance. */
5.30
5.31 if (__test_specific_type(attr.context, &__TYPE_CLASS_TYPE) && __is_type_instance(context))
5.32 - return __replace_context(context, attr);
5.33 + return __update_context(context, attr);
5.34
5.35 /* Otherwise, preserve the attribute as retrieved. */
5.36
5.37 return attr;
5.38 }
5.39
5.40 -__attr __replace_context(__ref context, __attr attr)
5.41 -{
5.42 - __attr out;
5.43 -
5.44 - /* Set the context. */
5.45 -
5.46 - out.context = context;
5.47 -
5.48 - /* Reference a callable version of the attribute by obtaining the bound
5.49 - method reference from the __fn__ special attribute. */
5.50 -
5.51 - out.value = __load_via_object(attr.value, __ATTRPOS(__fn__)).b;
5.52 - return out;
5.53 -}
5.54 -
5.55 __attr __update_context(__ref context, __attr attr)
5.56 {
5.57 __attr out = {.context=context, .value=attr.value};
5.58 return out;
5.59 }
5.60
5.61 +/* Context testing for invocations. */
5.62 +
5.63 +int __type_method_invocation(__attr attr)
5.64 +{
5.65 + __attr parent;
5.66 +
5.67 + /* Require instances, not classes, where methods are function instances. */
5.68 +
5.69 + if (!__is_instance(attr.value))
5.70 + return 0;
5.71 +
5.72 + /* Access the parent of the callable and test if it is the type object. */
5.73 +
5.74 + parent = __check_and_load_via_object_null(attr.value, __ATTRPOS(__parent__), __ATTRCODE(__parent__));
5.75 + return ((parent.value != 0) && __test_specific_type(parent.value, &__TYPE_CLASS_TYPE) && __is_type_instance(attr.context));
5.76 +}
5.77 +
5.78 +__attr (*__get_function(__attr attr))(__attr[])
5.79 +{
5.80 + /* Require null or instance contexts for functions and methods respectively,
5.81 + or type instance contexts for type methods. */
5.82 +
5.83 + if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr))
5.84 + return __load_via_object(attr.value, __ATTRPOS(__fn__)).fn;
5.85 + else
5.86 + return __load_via_object(attr.value, __ATTRPOS(__fn__)).inv;
5.87 +}
5.88 +
5.89 +__attr (*__check_and_get_function(__attr attr))(__attr[])
5.90 +{
5.91 + /* Require null or instance contexts for functions and methods respectively,
5.92 + or type instance contexts for type methods. */
5.93 +
5.94 + if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr))
5.95 + return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;
5.96 + else
5.97 + return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).inv;
5.98 +}
5.99 +
5.100 /* Basic structure tests. */
5.101
5.102 int __WITHIN(__ref obj, int pos)
6.1 --- a/templates/ops.h Mon Jan 30 22:32:38 2017 +0100
6.2 +++ b/templates/ops.h Mon Jan 30 22:34:46 2017 +0100
6.3 @@ -1,6 +1,6 @@
6.4 /* Common operations.
6.5
6.6 -Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
6.7 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
6.8
6.9 This program is free software; you can redistribute it and/or modify it under
6.10 the terms of the GNU General Public License as published by the Free Software
6.11 @@ -69,13 +69,17 @@
6.12 /* Context-related operations. */
6.13
6.14 __attr __test_context(__ref context, __attr attr);
6.15 -__attr __replace_context(__ref context, __attr attr);
6.16 __attr __update_context(__ref context, __attr attr);
6.17
6.18 #define __set_context(__ATTR) (__tmp_context = (__ATTR).value)
6.19 #define __set_accessor(__ATTR) (__tmp_value = (__ATTR).value)
6.20 #define __set_target_accessor(__ATTR) (__tmp_target_value = (__ATTR).value)
6.21
6.22 +/* Context testing for invocations. */
6.23 +
6.24 +__attr (*__get_function(__attr attr))(__attr[]);
6.25 +__attr (*__check_and_get_function(__attr attr))(__attr[]);
6.26 +
6.27 /* Basic structure tests. */
6.28
6.29 int __WITHIN(__ref obj, int pos);
7.1 --- a/templates/progops.c Mon Jan 30 22:32:38 2017 +0100
7.2 +++ b/templates/progops.c Mon Jan 30 22:34:46 2017 +0100
7.3 @@ -1,6 +1,6 @@
7.4 /* Operations depending on program specifics.
7.5
7.6 -Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
7.7 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
7.8
7.9 This program is free software; you can redistribute it and/or modify it under
7.10 the terms of the GNU General Public License as published by the Free Software
7.11 @@ -243,9 +243,7 @@
7.12
7.13 /* Call with the prepared arguments. */
7.14
7.15 - return (always_callable ? __load_via_object(callable.value, __pos___fn__)
7.16 - : __check_and_load_via_object(callable.value, __pos___fn__, __code___fn__)
7.17 - ).fn(allargs);
7.18 + return (always_callable ? __get_function(callable) : __check_and_get_function(callable))(allargs);
7.19 }
7.20
7.21 /* Error routines. */
8.1 --- a/templates/types.h Mon Jan 30 22:32:38 2017 +0100
8.2 +++ b/templates/types.h Mon Jan 30 22:34:46 2017 +0100
8.3 @@ -1,6 +1,6 @@
8.4 /* Runtime types.
8.5
8.6 -Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
8.7 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
8.8
8.9 This program is free software; you can redistribute it and/or modify it under
8.10 the terms of the GNU General Public License as published by the Free Software
8.11 @@ -57,9 +57,9 @@
8.12 union
8.13 {
8.14 __obj * context; /* attribute context */
8.15 - __obj * b; /* bound callable object */
8.16 unsigned int min; /* minimum number of parameters */
8.17 unsigned int code; /* parameter table code for key */
8.18 + struct __attr (*inv)(); /* unbound callable details */
8.19
8.20 size_t size; /* size of value */
8.21 };
9.1 --- a/translator.py Mon Jan 30 22:32:38 2017 +0100
9.2 +++ b/translator.py Mon Jan 30 22:34:46 2017 +0100
9.3 @@ -22,7 +22,7 @@
9.4 from common import CommonModule, CommonOutput, InstructionSequence, \
9.5 first, get_builtin_module, get_builtin_type, init_item, \
9.6 predefined_constants
9.7 -from encoders import encode_access_instruction, encode_bound_reference, \
9.8 +from encoders import encode_access_instruction, \
9.9 encode_function_pointer, encode_literal_constant, \
9.10 encode_literal_instantiator, encode_instantiator_pointer, \
9.11 encode_instructions, \
9.12 @@ -1072,10 +1072,7 @@
9.13 # Handle bound methods.
9.14
9.15 if not instance_name:
9.16 - if self.is_method(objpath):
9.17 - instance_name = "&%s" % encode_bound_reference(objpath)
9.18 - else:
9.19 - instance_name = "&%s" % encode_path(objpath)
9.20 + instance_name = "&%s" % encode_path(objpath)
9.21
9.22 # Where defaults are involved but cannot be identified, obtain a new
9.23 # instance of the lambda and populate the defaults.
9.24 @@ -1164,7 +1161,7 @@
9.25 if expr.has_kind("<class>"):
9.26 instantiation = objpath
9.27 target = encode_instantiator_pointer(objpath)
9.28 - target_structure = "&%s" % encode_bound_reference("%s.__init__" % objpath)
9.29 + target_structure = "&%s" % encode_path("%s.__init__" % objpath)
9.30 context_required = False
9.31
9.32 # Only plain functions and bound methods employ function pointers.
9.33 @@ -1188,9 +1185,7 @@
9.34 # Access bound method defaults even if it is not clear whether
9.35 # the accessor is appropriate.
9.36
9.37 - target_structure = self.is_method(objpath) and \
9.38 - "&%s" % encode_bound_reference(objpath) or \
9.39 - "&%s" % encode_path(objpath)
9.40 + target_structure = "&%s" % encode_path(objpath)
9.41
9.42 # Other targets are retrieved at run-time.
9.43
9.44 @@ -1309,8 +1304,12 @@
9.45
9.46 elif function:
9.47 self.record_temp("__tmp_targets")
9.48 - stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % (
9.49 - self.function_target, encode_symbol("pos", "__fn__")))
9.50 +
9.51 + if context_required:
9.52 + stages.append("__get_function(__tmp_targets[%d])" % self.function_target)
9.53 + else:
9.54 + stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % (
9.55 + self.function_target, encode_symbol("pos", "__fn__")))
9.56
9.57 # With a known target, the function is obtained directly and called.
9.58 # By putting the invocation at the end of the final element in the