# HG changeset patch # User Paul Boddie # Date 1490283657 -3600 # Node ID b496ef9d5ee1446ff1f20ee2c094e812c3ca8704 # Parent 195b15f90472d5128ac8bc34a3a35dc9a1d87303 Switched to using __attr values in many operations instead of using __ref values. This should allow __attr values to be passed around while being interpreted in other ways by certain native functions. diff -r 195b15f90472 -r b496ef9d5ee1 encoders.py --- a/encoders.py Tue Mar 21 18:45:42 2017 +0100 +++ b/encoders.py Thu Mar 23 16:40:57 2017 +0100 @@ -237,9 +237,13 @@ "", "", ) -reference_acting_ops = attribute_ops + checked_ops + typename_ops +reference_acting_ops = attribute_ops + checked_ops + type_ops + typename_ops attribute_producing_ops = attribute_loading_ops + checked_loading_ops +attribute_producing_variables = ( + "", "", "", "", "" + ) + def encode_access_instruction(instruction, subs, context_index): """ @@ -340,13 +344,7 @@ if isinstance(arg, tuple): encoded, substituted = encode_access_instruction(arg, subs, context_index) - - # Convert attribute results to references where required. - - if op and op in reference_acting_ops and arg[0] in attribute_producing_ops: - return "%s.value" % encoded, substituted - else: - return encoded, substituted + return attribute_to_reference(op, arg[0], encoded, substituted) # Special values only need replacing, not encoding. @@ -355,13 +353,18 @@ # Handle values modified by storage details. if arg in context_values: - return "%s(%s)" % (subs.get(arg), context_index), set([arg]) + encoded = "%s(%s)" % (subs.get(arg), context_index) else: - return subs.get(arg), set([arg]) + encoded = subs.get(arg) + + substituted = set([arg]) + return attribute_to_reference(op, arg, encoded, substituted) # Convert static references to the appropriate type. - elif op and op in reference_acting_ops and arg != "": + elif op and op in reference_acting_ops and \ + arg not in attribute_producing_variables: + return "&%s" % encode_path(arg), set() # Other values may need encoding. @@ -369,6 +372,18 @@ else: return encode_path(arg), set() +def attribute_to_reference(op, arg, encoded, substituted): + + # Convert attribute results to references where required. + + if op and op in reference_acting_ops and ( + arg in attribute_producing_ops or + arg in attribute_producing_variables): + + return "__VALUE(%s)" % encoded, substituted + else: + return encoded, substituted + def encode_function_pointer(path): "Encode 'path' as a reference to an output program function." diff -r 195b15f90472 -r b496ef9d5ee1 templates/native/introspection.c --- a/templates/native/introspection.c Tue Mar 21 18:45:42 2017 +0100 +++ b/templates/native/introspection.c Thu Mar 23 16:40:57 2017 +0100 @@ -51,7 +51,7 @@ /* Update the context to the object if it is a method. */ - return __update_context(obj->value, out); + return __update_context(*obj, out); } return out; diff -r 195b15f90472 -r b496ef9d5ee1 templates/native/program.c --- a/templates/native/program.c Tue Mar 21 18:45:42 2017 +0100 +++ b/templates/native/program.c Thu Mar 23 16:40:57 2017 +0100 @@ -31,7 +31,7 @@ __attr * const callable = &__args[1]; __attr * const instance = &__args[2]; - return __test_context(instance->value, *callable); + return __test_context(*instance, *callable); } /* Module initialisation. */ diff -r 195b15f90472 -r b496ef9d5ee1 templates/ops.c --- a/templates/ops.c Tue Mar 21 18:45:42 2017 +0100 +++ b/templates/ops.c Thu Mar 23 16:40:57 2017 +0100 @@ -23,6 +23,13 @@ #include "progconsts.h" #include "progtypes.h" +/* Get object reference from attribute. */ + +__ref __VALUE(__attr attr) +{ + return attr.value; +} + /* Basic structure tests. */ static inline int __HASATTR(__ref obj, int pos, int code) @@ -37,12 +44,12 @@ return __ATTRVALUE(obj); } -__attr __load_static_replace(__ref context, __ref obj) +__attr __load_static_replace(__attr context, __ref obj) { return __update_context(context, __ATTRVALUE(obj)); } -__attr __load_static_test(__ref context, __ref obj) +__attr __load_static_test(__attr context, __ref obj) { return __test_context(context, __ATTRVALUE(obj)); } @@ -92,12 +99,12 @@ int __is_subclass(__ref obj, __attr cls) { - return __HASATTR(obj, __TYPEPOS(cls.value), __TYPECODE(cls.value)); + return __HASATTR(obj, __TYPEPOS(__VALUE(cls)), __TYPECODE(__VALUE(cls))); } int __is_instance_subclass(__ref obj, __attr cls) { - return __is_instance(obj) && __HASATTR(__get_class(obj), __TYPEPOS(cls.value), __TYPECODE(cls.value)); + return __is_instance(obj) && __HASATTR(__get_class(obj), __TYPEPOS(__VALUE(cls)), __TYPECODE(__VALUE(cls))); } int __is_type_instance(__ref obj) @@ -107,7 +114,7 @@ __ref __get_class(__ref obj) { - return __load_via_object(obj, __class__).value; + return __VALUE(__load_via_object(obj, __class__)); } __attr __get_class_attr(__ref obj) @@ -174,7 +181,7 @@ __attr __check_and_load_via_any__(__ref obj, int pos, int code) { __attr out = __check_and_load_via_object_null(obj, pos, code); - if (out.value == 0) + if (__ISNULL(out)) out = __check_and_load_via_class__(obj, pos, code); return out; } @@ -216,27 +223,28 @@ /* Context-related operations. */ -int __test_context_update(__ref context, __attr attr) +int __test_context_update(__attr context, __attr attr) { /* Return whether the context should be updated for the attribute. */ - __ref attrcontext = __CONTEXT_AS_VALUE(attr).value; + __attr attrcontext = __CONTEXT_AS_VALUE(attr); + __ref attrcontextvalue = __VALUE(attrcontext); /* Preserve any existing null or instance context. */ - if ((attrcontext == 0) || __is_instance(attrcontext)) + if (__ISNULL(attrcontext) || __is_instance(attrcontextvalue)) return 0; /* Test any instance context against the context employed by the attribute. */ - if (__is_instance(context)) + if (__is_instance(__VALUE(context))) { /* Obtain the special class attribute position and code identifying the attribute context's class, inspecting the context instance for compatibility. */ - if (__test_common_instance__(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext))) + if (__test_common_instance__(__VALUE(context), __TYPEPOS(attrcontextvalue), __TYPECODE(attrcontextvalue))) return 1; else __raise_type_error(); @@ -244,7 +252,7 @@ /* Test for access to a type class attribute using a type instance. */ - if (__test_specific_type(attrcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context)) + if (__test_specific_type(attrcontextvalue, &__TYPE_CLASS_TYPE) && __is_type_instance(__VALUE(context))) return 1; /* Otherwise, preserve the attribute as retrieved. */ @@ -252,7 +260,7 @@ return 0; } -__attr __test_context(__ref context, __attr attr) +__attr __test_context(__attr context, __attr attr) { /* Update the context or return the unchanged attribute. */ @@ -262,22 +270,22 @@ return attr; } -__attr __update_context(__ref context, __attr attr) +__attr __update_context(__attr context, __attr attr) { return __new_wrapper(context, attr); } -__attr __test_context_revert(int target, __ref context, __attr attr, __ref contexts[]) +__attr __test_context_revert(int target, __attr context, __attr attr, __attr contexts[]) { /* Revert the local context to that employed by the attribute if the supplied context is not appropriate. */ if (!__test_context_update(context, attr)) - contexts[target] = __CONTEXT_AS_VALUE(attr).value; + contexts[target] = __CONTEXT_AS_VALUE(attr); return attr; } -__attr __test_context_static(int target, __ref context, __ref value, __ref contexts[]) +__attr __test_context_static(int target, __attr context, __ref value, __attr contexts[]) { /* Set the local context to the specified context if appropriate. */ @@ -288,53 +296,53 @@ /* Context testing for invocations. */ -int __type_method_invocation(__ref context, __attr target) +int __type_method_invocation(__attr context, __attr target) { - __ref targetcontext = __CONTEXT_AS_VALUE(target).value; + __attr targetcontext = __CONTEXT_AS_VALUE(target); /* Require instances, not classes, where methods are function instances. */ - if (!__is_instance(target.value)) + if (!__is_instance(__VALUE(target))) return 0; /* Access the context of the callable and test if it is the type object. */ - return ((targetcontext != 0) && __test_specific_type(targetcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context)); + return (!__ISNULL(targetcontext) && __test_specific_type(__VALUE(targetcontext), &__TYPE_CLASS_TYPE) && __is_type_instance(__VALUE(context))); } __attr __unwrap_callable(__attr callable) { - __attr value = __check_and_load_via_object_null(callable.value, __ATTRPOS(__value__), __ATTRCODE(__value__)); - return value.value ? value : callable; + __attr value = __check_and_load_via_object_null(__VALUE(callable), __ATTRPOS(__value__), __ATTRCODE(__value__)); + return __VALUE(value) ? value : callable; } __attr (*__get_function_unchecked(__attr target))(__attr[]) { - return __load_via_object(__unwrap_callable(target).value, __fn__).fn; + return __load_via_object(__VALUE(__unwrap_callable(target)), __fn__).fn; } -__attr (*__get_function(__ref context, __attr target))(__attr[]) +__attr (*__get_function(__attr context, __attr target))(__attr[]) { target = __unwrap_callable(target); /* Require null or instance contexts for functions and methods respectively, or type instance contexts for type methods. */ - if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target)) - return __load_via_object(target.value, __fn__).fn; + if (__ISNULL(context) || __is_instance(__VALUE(context)) || __type_method_invocation(context, target)) + return __load_via_object(__VALUE(target), __fn__).fn; else return __unbound_method; } -__attr (*__check_and_get_function(__ref context, __attr target))(__attr[]) +__attr (*__check_and_get_function(__attr context, __attr target))(__attr[]) { target = __unwrap_callable(target); /* Require null or instance contexts for functions and methods respectively, or type instance contexts for type methods. */ - if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target)) - return __check_and_load_via_object__(target.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn; + if (__ISNULL(context) || __is_instance(__VALUE(context)) || __type_method_invocation(context, target)) + return __check_and_load_via_object__(__VALUE(target), __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn; else return __unbound_method; } @@ -359,7 +367,7 @@ __attr __CONTEXT_AS_VALUE(__attr attr) { - return __check_and_load_via_object_null(attr.value, __ATTRPOS(__context__), __ATTRCODE(__context__)); + return __check_and_load_via_object_null(__VALUE(attr), __ATTRPOS(__context__), __ATTRCODE(__context__)); } /* Type testing. */ diff -r 195b15f90472 -r b496ef9d5ee1 templates/ops.h --- a/templates/ops.h Tue Mar 21 18:45:42 2017 +0100 +++ b/templates/ops.h Thu Mar 23 16:40:57 2017 +0100 @@ -22,11 +22,15 @@ #include "types.h" #include /* for __COPY */ +/* Get object reference from attribute. */ + +__ref __VALUE(__attr attr); + /* Direct access and manipulation of static objects. */ __attr __load_static_ignore(__ref obj); -__attr __load_static_replace(__ref context, __ref obj); -__attr __load_static_test(__ref context, __ref obj); +__attr __load_static_replace(__attr context, __ref obj); +__attr __load_static_test(__attr context, __ref obj); /* Direct retrieval operations, returning attributes. */ @@ -93,24 +97,24 @@ /* Context-related operations. */ -int __test_context_update(__ref context, __attr attr); -__attr __test_context(__ref context, __attr attr); -__attr __update_context(__ref context, __attr attr); -__attr __test_context_revert(int target, __ref context, __attr attr, __ref contexts[]); -__attr __test_context_static(int target, __ref context, __ref value, __ref contexts[]); +int __test_context_update(__attr context, __attr attr); +__attr __test_context(__attr context, __attr attr); +__attr __update_context(__attr context, __attr attr); +__attr __test_context_revert(int target, __attr context, __attr attr, __attr contexts[]); +__attr __test_context_static(int target, __attr context, __ref value, __attr contexts[]); #define __get_context(__TARGET) (__tmp_contexts[__TARGET]) -#define __set_context(__TARGET, __ATTR) (__tmp_contexts[__TARGET] = (__ATTR).value) -#define __set_private_context(__ATTR) (__tmp_private_context = (__ATTR).value) -#define __set_accessor(__ATTR) (__tmp_value = (__ATTR).value) -#define __set_target_accessor(__ATTR) (__tmp_target_value = (__ATTR).value) +#define __set_context(__TARGET, __ATTR) (__tmp_contexts[__TARGET] = (__ATTR)) +#define __set_private_context(__ATTR) (__tmp_private_context = (__ATTR)) +#define __set_accessor(__ATTR) (__tmp_value = (__ATTR)) +#define __set_target_accessor(__ATTR) (__tmp_target_value = (__ATTR)) /* Context testing for invocations. */ __attr __unwrap_callable(__attr callable); __attr (*__get_function_unchecked(__attr target))(__attr[]); -__attr (*__get_function(__ref context, __attr target))(__attr[]); -__attr (*__check_and_get_function(__ref context, __attr target))(__attr[]); +__attr (*__get_function(__attr context, __attr target))(__attr[]); +__attr (*__check_and_get_function(__attr context, __attr target))(__attr[]); /* Parameter position operations. */ diff -r 195b15f90472 -r b496ef9d5ee1 templates/progops.c --- a/templates/progops.c Tue Mar 21 18:45:42 2017 +0100 +++ b/templates/progops.c Thu Mar 23 16:40:57 2017 +0100 @@ -32,13 +32,13 @@ __ref obj = (__ref) (immutable ? __ALLOCATEIM : __ALLOCATE)(1, size); obj->table = table; obj->pos = __INSTANCEPOS; - __store_via_object(obj, __class__, (__attr) {.value=cls}); - return (__attr) {.value=obj}; + __store_via_object(obj, __class__, __ATTRVALUE(cls)); + return __ATTRVALUE(obj); } -__attr __new_wrapper(__ref context, __attr attr) +__attr __new_wrapper(__attr context, __attr attr) { - return __new___builtins___core_wrapper((__attr[]) {__NULL, {.value=context}, attr}); + return __new___builtins___core_wrapper((__attr[]) {__NULL, context, attr}); } /* Generic internal data allocation. */ @@ -163,7 +163,7 @@ /* Return instances as provided. */ - if (__is_instance(arg.value)) + if (__is_instance(__VALUE(arg))) return arg; /* Invoke non-instances to produce instances. */ @@ -192,7 +192,7 @@ /* Obtain the __args__ special member, referencing the parameter table. */ /* Refer to the table and minimum/maximum. */ - const __ptable *ptable = __check_and_load_via_object(target.value, __args__).ptable; + const __ptable *ptable = __check_and_load_via_object(__VALUE(target), __args__).ptable; const unsigned int min = ptable->min, max = ptable->max; /* Reserve enough space for the arguments. */ @@ -247,13 +247,13 @@ for (pos = nargs; pos < max; pos++) { if (allargs[pos].value == 0) - allargs[pos] = __GETDEFAULT(target.value, pos - min); + allargs[pos] = __GETDEFAULT(__VALUE(target), pos - min); } } /* Call with the prepared arguments. */ - return (always_callable ? __get_function(allargs[0].value, target) : __check_and_get_function(allargs[0].value, target))(allargs); + return (always_callable ? __get_function(allargs[0], target) : __check_and_get_function(allargs[0], target))(allargs); } /* Error routines. */ @@ -281,9 +281,10 @@ int __BOOL(__attr attr) { __attr args[2] = {__NULL, attr}; + __ref truevalue = __VALUE(__builtins___boolean_True); /* Invoke the bool function with the object and test against True. */ - return (attr.value == __builtins___boolean_True.value) || - (__fn___builtins___boolean_bool(args).value == __builtins___boolean_True.value); + return (__VALUE(attr) == truevalue) || + (__VALUE(__fn___builtins___boolean_bool(args)) == truevalue); } diff -r 195b15f90472 -r b496ef9d5ee1 templates/progops.h --- a/templates/progops.h Tue Mar 21 18:45:42 2017 +0100 +++ b/templates/progops.h Thu Mar 23 16:40:57 2017 +0100 @@ -25,7 +25,7 @@ /* Generic instantiation operations, defining common members. */ __attr __new(const __table *table, __ref cls, size_t size, int immutable); -__attr __new_wrapper(__ref context, __attr attr); +__attr __new_wrapper(__attr context, __attr attr); /* Generic internal data allocation. */ diff -r 195b15f90472 -r b496ef9d5ee1 translator.py --- a/translator.py Tue Mar 21 18:45:42 2017 +0100 +++ b/translator.py Thu Mar 23 16:40:57 2017 +0100 @@ -542,7 +542,7 @@ subs = { "" : attr_expr, - "" : "%s.value" % attr_expr, + "" : attr_expr, "" : self.in_assignment, } @@ -884,16 +884,25 @@ # Produce an appropriate access to an attribute's value. - parameters = self.importer.function_parameters.get(self.get_namespace_path()) - if parameters and name in parameters: - name_to_value = "%s->value" % encode_path(name) - else: - name_to_value = "%s.value" % encode_path(name) + name_as_attr = self.get_name_as_attribute(name) # Write a test that raises a TypeError upon failure. - self.writestmt("if (!__test_%s_%s(%s, %s)) __raise_type_error();" % ( - guard, guard_type, name_to_value, argstr)) + self.writestmt("if (!__test_%s_%s(__VALUE(%s), %s)) __raise_type_error();" % ( + guard, guard_type, name_as_attr, argstr)) + + def get_name_as_attribute(self, name): + + "Return a generated expression for 'name' yielding an attribute." + + parameters = self.importer.function_parameters.get(self.get_namespace_path()) + parameter = name == "self" and self.in_method() or \ + parameters and name in parameters + + if parameter: + return "*%s" % encode_path(name) + else: + return "%s" % encode_path(name) def process_function_node(self, n): @@ -963,6 +972,8 @@ if not instance_name: instance_name = "&%s" % encode_path(objpath) + else: + instance_name = "__VALUE(%s)" % instance_name # Where defaults are involved but cannot be identified, obtain a new # instance of the lambda and populate the defaults. @@ -1199,8 +1210,9 @@ if not target_identity: self.record_temp("__tmp_targets") - if context_identity and context_identity.startswith("__tmp_contexts"): - self.record_temp("__tmp_contexts") + if context_identity: + if context_identity.startswith("__tmp_contexts"): + self.record_temp("__tmp_contexts") # Arguments are presented in a temporary frame array with any context # always being the first argument. Where it would be unused, it may be @@ -1210,7 +1222,7 @@ if context_required: if have_access_context: - args = ["__ATTRVALUE(%s)" % context_identity] + args = [context_identity] else: args = ["__CONTEXT_AS_VALUE(%s)" % context_var] else: @@ -1355,19 +1367,19 @@ stages.append("__get_function(%s, %s)" % ( context_identity, target_var)) else: - stages.append("__get_function(__CONTEXT_AS_VALUE(%s).value, %s)" % ( + stages.append("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % ( context_var, target_var)) else: - stages.append("__load_via_object(%s.value, __fn__).fn" % target_var) + stages.append("__load_via_object(__VALUE(%s), __fn__).fn" % target_var) # With known parameters, the target can be tested. elif known_parameters: context_arg = context_required and args[0] or "__NULL" if self.always_callable(refs): - stages.append("__get_function(%s.value, %s)" % (context_arg, target_var)) + stages.append("__get_function(%s, %s)" % (context_arg, target_var)) else: - stages.append("__check_and_get_function(%s.value, %s)" % (context_arg, target_var)) + stages.append("__check_and_get_function(%s, %s)" % (context_arg, target_var)) # With a known target, the function is obtained directly and called. # By putting the invocation at the end of the final element in the @@ -1467,7 +1479,7 @@ else: self.record_temp("__tmp_value") - return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, __ATTRVALUE(__tmp_value))" % ( + return make_expression("(__tmp_value = __ATTRVALUE(__COPY(&%s, sizeof(%s))), %s, __tmp_value)" % ( encode_path(function_name), encode_symbol("obj", function_name), ", ".join(defaults))) @@ -2018,16 +2030,16 @@ if self.uses_temp(name, "__tmp_targets"): self.writeline("__attr __tmp_targets[%d];" % targets) if self.uses_temp(name, "__tmp_contexts"): - self.writeline("__ref __tmp_contexts[%d];" % targets) + self.writeline("__attr __tmp_contexts[%d];" % targets) # Add temporary variable usage details. if self.uses_temp(name, "__tmp_private_context"): - self.writeline("__ref __tmp_private_context;") + self.writeline("__attr __tmp_private_context;") if self.uses_temp(name, "__tmp_value"): - self.writeline("__ref __tmp_value;") + self.writeline("__attr __tmp_value;") if self.uses_temp(name, "__tmp_target_value"): - self.writeline("__ref __tmp_target_value;") + self.writeline("__attr __tmp_target_value;") if self.uses_temp(name, "__tmp_result"): self.writeline("__attr __tmp_result;")