1.1 --- a/branching.py Mon Feb 20 18:48:39 2017 +0100
1.2 +++ b/branching.py Fri Feb 24 13:27:44 2017 +0100
1.3 @@ -4,7 +4,7 @@
1.4 Track attribute usage for names.
1.5
1.6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013,
1.7 - 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk>
1.8 + 2014, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -75,7 +75,11 @@
1.13 if name in self.assignments:
1.14 return [self]
1.15 else:
1.16 - return [b for b in self.get_all_suppliers(name) if name in b.assignments]
1.17 + sources = []
1.18 + for b in self.get_all_suppliers(name):
1.19 + if name in b.assignments:
1.20 + sources.append(b)
1.21 + return sources
1.22
1.23 def set_usage(self, name, attrname, invocation=False, assignment=False):
1.24
1.25 @@ -597,7 +601,10 @@
1.26
1.27 d = {}
1.28 for name, branches in self.assignments.items():
1.29 - d[name] = [branch.values.get(name) for branch in branches]
1.30 + l = []
1.31 + for branch in branches:
1.32 + l.append(branch.values.get(name))
1.33 + d[name] = l
1.34 return d
1.35
1.36 # Special objects.
2.1 --- a/common.py Mon Feb 20 18:48:39 2017 +0100
2.2 +++ b/common.py Fri Feb 24 13:27:44 2017 +0100
2.3 @@ -23,7 +23,7 @@
2.4 from compiler.transformer import Transformer
2.5 from errors import InspectError
2.6 from os import listdir, makedirs, remove
2.7 -from os.path import exists, isdir, join, split
2.8 +from os.path import exists, getmtime, isdir, join, split
2.9 from results import ConstantValueRef, LiteralSequenceRef, NameRef
2.10 import compiler.ast
2.11
2.12 @@ -76,6 +76,36 @@
2.13 else:
2.14 remove(path)
2.15
2.16 +def copy(source, target, only_if_newer=True):
2.17 +
2.18 + "Copy a text file from 'source' to 'target'."
2.19 +
2.20 + if isdir(target):
2.21 + target = join(target, split(source)[-1])
2.22 +
2.23 + if only_if_newer and not is_newer(source, target):
2.24 + return
2.25 +
2.26 + infile = open(source)
2.27 + outfile = open(target, "w")
2.28 +
2.29 + try:
2.30 + outfile.write(infile.read())
2.31 + finally:
2.32 + outfile.close()
2.33 + infile.close()
2.34 +
2.35 +def is_newer(source, target):
2.36 +
2.37 + "Return whether 'source' is newer than 'target'."
2.38 +
2.39 + if exists(target):
2.40 + target_mtime = getmtime(target)
2.41 + source_mtime = getmtime(source)
2.42 + return source_mtime > target_mtime
2.43 +
2.44 + return True
2.45 +
2.46 class CommonModule:
2.47
2.48 "A common module representation."
3.1 --- a/deducer.py Mon Feb 20 18:48:39 2017 +0100
3.2 +++ b/deducer.py Fri Feb 24 13:27:44 2017 +0100
3.3 @@ -2088,7 +2088,9 @@
3.4 # All other methods of access involve traversal.
3.5
3.6 else:
3.7 - final_method = is_assignment and "assign" or "access"
3.8 + final_method = is_assignment and "assign" or \
3.9 + is_invocation and "access-invoke" or \
3.10 + "access"
3.11 origin = None
3.12
3.13 # First attribute accessed at a known position via the accessor.
4.1 --- a/docs/lplc.1 Mon Feb 20 18:48:39 2017 +0100
4.2 +++ b/docs/lplc.1 Fri Feb 24 13:27:44 2017 +0100
4.3 @@ -24,31 +24,39 @@
4.4 The following options may be specified:
4.5 .PP
4.6 .TP
4.7 -.B \-c
4.8 -Only partially compile the program; do not attempt to build or link it
4.9 +.BR \-c ", " \-\-compile
4.10 +Only partially compile the program; do not build or link it
4.11 .TP
4.12 -.B \-E
4.13 +.BR \-E ", " \-\-no\-env
4.14 Ignore environment variables affecting the module search path
4.15 .TP
4.16 -.B \-g
4.17 +.BR \-g ", " \-\-debug
4.18 Generate debugging information for the built executable
4.19 .TP
4.20 -.B \-P
4.21 +.BR \-G ", " \-\-gc\-sections
4.22 +Remove superfluous sections of the built executable by applying the
4.23 +.B \-\-gc\-sections
4.24 +linker option and associated compiler options
4.25 +.TP
4.26 +.BR \-P ", " \-\-show\-path
4.27 Show the module search path
4.28 .TP
4.29 -.B \-q
4.30 +.BR \-q ", " \-\-quiet
4.31 Silence messages produced when building an executable
4.32 .TP
4.33 -.B \-r
4.34 -Reset (discard) cached program information; inspect the whole program again
4.35 +.BR \-r ", " \-\-reset
4.36 +Reset (discard) cached information; inspect the whole program again
4.37 .TP
4.38 -.B \-t
4.39 +.BR \-R ", " \-\-reset\-all
4.40 +Reset (discard) all program details including translated code
4.41 +.TP
4.42 +.BR \-t ", " \-\-no\-timing
4.43 Silence timing messages
4.44 .TP
4.45 -.B \-tb
4.46 +.BR \-tb ", " \-\-traceback
4.47 Provide a traceback for any internal errors (development only)
4.48 .TP
4.49 -.B \-v
4.50 +.BR \-v ", " \-\-verbose
4.51 Report compiler activities in a verbose fashion (development only)
4.52 .PP
4.53 Some options may be followed by values, either immediately after the option
4.54 @@ -79,7 +87,35 @@
4.55 .TP
4.56 .BR \-V ", " \-\-version
4.57 Show version information for this tool
4.58 -.SH ENVIRONMENT VARIABLES
4.59 +.SH EXAMPLES
4.60 +Compile the main program in
4.61 +.BR hello.py ,
4.62 +including all source files that the program requires:
4.63 +.IP
4.64 +lplc -o hello hello.py
4.65 +.PP
4.66 +This produces an output executable called
4.67 +.B hello
4.68 +in the current directory, assuming that
4.69 +.B hello.py
4.70 +can be compiled without errors.
4.71 +.SH FILES
4.72 +.B lplc
4.73 +produces an output executable file called
4.74 +.B _main
4.75 +unless the
4.76 +.B \-o
4.77 +option is given with a different name. Working data is stored in a directory
4.78 +whose name is derived from the output executable name. Therefore, the working
4.79 +data directory will be called
4.80 +.B _main.lplc
4.81 +unless otherwise specified. For example, an output executable called
4.82 +.B hello
4.83 +will have a working data directory called
4.84 +.BR hello.lplc .
4.85 +This is intended to allow work to proceed efficiently on multiple programs in
4.86 +the same directory, although it can also create lots of unwanted directories.
4.87 +.SH ENVIRONMENT
4.88 .TP
4.89 ARCH
4.90 Indicates a prefix to be used with tool names when building an executable. This
4.91 @@ -93,7 +129,7 @@
4.92 A collection of directories that are searched before those in the collection
4.93 comprising the default "module search path". This collection, if already defined
4.94 in the environment, may be excluded by specifying the
4.95 -.B \-E
4.96 +.BR \-E " (or " \-\-no\-env )
4.97 option.
4.98 .SH AUTHOR
4.99 Paul Boddie <paul@boddie.org.uk>
5.1 --- a/encoders.py Mon Feb 20 18:48:39 2017 +0100
5.2 +++ b/encoders.py Fri Feb 24 13:27:44 2017 +0100
5.3 @@ -21,6 +21,21 @@
5.4
5.5 from common import first, InstructionSequence
5.6
5.7 +
5.8 +
5.9 +# Value digest computation.
5.10 +
5.11 +from base64 import b64encode
5.12 +from hashlib import sha1
5.13 +
5.14 +def digest(values):
5.15 + m = sha1()
5.16 + for value in values:
5.17 + m.update(str(value))
5.18 + return b64encode(m.digest()).replace("+", "__").replace("/", "_").rstrip("=")
5.19 +
5.20 +
5.21 +
5.22 # Output encoding and decoding for the summary files.
5.23
5.24 def encode_attrnames(attrnames):
5.25 @@ -207,13 +222,25 @@
5.26 )
5.27
5.28 static_ops = (
5.29 - "__load_static",
5.30 + "__load_static_ignore", "__load_static_replace", "__load_static_test", "<test_context_static>",
5.31 + )
5.32 +
5.33 +context_values = (
5.34 + "<context>",
5.35 + )
5.36 +
5.37 +context_ops = (
5.38 + "<context>", "<set_context>", "<test_context_revert>", "<test_context_static>",
5.39 + )
5.40 +
5.41 +context_op_functions = (
5.42 + "<test_context_revert>", "<test_context_static>",
5.43 )
5.44
5.45 reference_acting_ops = attribute_ops + checked_ops + typename_ops
5.46 attribute_producing_ops = attribute_loading_ops + checked_loading_ops
5.47
5.48 -def encode_access_instruction(instruction, subs):
5.49 +def encode_access_instruction(instruction, subs, context_index):
5.50
5.51 """
5.52 Encode the 'instruction' - a sequence starting with an operation and
5.53 @@ -223,6 +250,9 @@
5.54 The 'subs' parameter defines a mapping of substitutions for special values
5.55 used in instructions.
5.56
5.57 + The 'context_index' parameter defines the position in local context storage
5.58 + for the referenced context or affected by a context operation.
5.59 +
5.60 Return both the encoded instruction and a collection of substituted names.
5.61 """
5.62
5.63 @@ -230,54 +260,65 @@
5.64 args = instruction[1:]
5.65 substituted = set()
5.66
5.67 - if not args:
5.68 - argstr = ""
5.69 + # Encode the arguments.
5.70
5.71 - else:
5.72 - # Encode the arguments.
5.73 -
5.74 - a = []
5.75 + a = []
5.76 + if args:
5.77 converting_op = op
5.78 for arg in args:
5.79 - s, _substituted = encode_access_instruction_arg(arg, subs, converting_op)
5.80 + s, _substituted = encode_access_instruction_arg(arg, subs, converting_op, context_index)
5.81 substituted.update(_substituted)
5.82 a.append(s)
5.83 converting_op = None
5.84
5.85 - # Modify certain arguments.
5.86 + # Modify certain arguments.
5.87
5.88 - # Convert attribute name arguments to position symbols.
5.89 + # Convert attribute name arguments to position symbols.
5.90
5.91 - if op in attribute_ops:
5.92 - arg = a[1]
5.93 - a[1] = encode_symbol("pos", arg)
5.94 + if op in attribute_ops:
5.95 + arg = a[1]
5.96 + a[1] = encode_symbol("pos", arg)
5.97 +
5.98 + # Convert attribute name arguments to position and code symbols.
5.99
5.100 - # Convert attribute name arguments to position and code symbols.
5.101 + elif op in checked_ops:
5.102 + arg = a[1]
5.103 + a[1] = encode_symbol("pos", arg)
5.104 + a.insert(2, encode_symbol("code", arg))
5.105 +
5.106 + # Convert type name arguments to position and code symbols.
5.107
5.108 - elif op in checked_ops:
5.109 - arg = a[1]
5.110 - a[1] = encode_symbol("pos", arg)
5.111 - a.insert(2, encode_symbol("code", arg))
5.112 + elif op in typename_ops:
5.113 + arg = encode_type_attribute(args[1])
5.114 + a[1] = encode_symbol("pos", arg)
5.115 + a.insert(2, encode_symbol("code", arg))
5.116
5.117 - # Convert type name arguments to position and code symbols.
5.118 + # Obtain addresses of type arguments.
5.119
5.120 - elif op in typename_ops:
5.121 - arg = encode_type_attribute(args[1])
5.122 - a[1] = encode_symbol("pos", arg)
5.123 - a.insert(2, encode_symbol("code", arg))
5.124 + elif op in type_ops:
5.125 + a[1] = "&%s" % a[1]
5.126 +
5.127 + # Obtain addresses of static objects.
5.128
5.129 - # Obtain addresses of type arguments.
5.130 + elif op in static_ops:
5.131 + a[-1] = "&%s" % a[-1]
5.132 +
5.133 + # Add context storage information to certain operations.
5.134
5.135 - elif op in type_ops:
5.136 - a[1] = "&%s" % a[1]
5.137 + if op in context_ops:
5.138 + a.insert(0, context_index)
5.139
5.140 - # Obtain addresses of static objects.
5.141 + # Add the local context array to certain operations.
5.142
5.143 - elif op in static_ops:
5.144 - a[0] = "&%s" % a[0]
5.145 - a[1] = "&%s" % a[1]
5.146 + if op in context_op_functions:
5.147 + a.append("__tmp_contexts")
5.148 +
5.149 + # Define any argument string.
5.150
5.151 + if a:
5.152 argstr = "(%s)" % ", ".join(map(str, a))
5.153 + else:
5.154 + argstr = ""
5.155
5.156 # Substitute the first element of the instruction, which may not be an
5.157 # operation at all.
5.158 @@ -301,16 +342,19 @@
5.159
5.160 return "%s%s" % (op, argstr), substituted
5.161
5.162 -def encode_access_instruction_arg(arg, subs, op):
5.163 +def encode_access_instruction_arg(arg, subs, op, context_index):
5.164
5.165 """
5.166 - Encode 'arg' using 'subs' to define substitutions, returning a tuple
5.167 - containing the encoded form of 'arg' along with a collection of any
5.168 - substituted values.
5.169 + Encode 'arg' using 'subs' to define substitutions, 'op' to indicate the
5.170 + operation to which the argument belongs, and 'context_index' to indicate any
5.171 + affected context storage.
5.172 +
5.173 + Return a tuple containing the encoded form of 'arg' along with a collection
5.174 + of any substituted values.
5.175 """
5.176
5.177 if isinstance(arg, tuple):
5.178 - encoded, substituted = encode_access_instruction(arg, subs)
5.179 + encoded, substituted = encode_access_instruction(arg, subs, context_index)
5.180
5.181 # Convert attribute results to references where required.
5.182
5.183 @@ -322,7 +366,13 @@
5.184 # Special values only need replacing, not encoding.
5.185
5.186 elif subs.has_key(arg):
5.187 - return subs.get(arg), set([arg])
5.188 +
5.189 + # Handle values modified by storage details.
5.190 +
5.191 + if arg in context_values:
5.192 + return "%s(%s)" % (subs.get(arg), context_index), set([arg])
5.193 + else:
5.194 + return subs.get(arg), set([arg])
5.195
5.196 # Convert static references to the appropriate type.
5.197
5.198 @@ -359,7 +409,7 @@
5.199
5.200 "Encode a name for the literal constant with the number 'n'."
5.201
5.202 - return "__const%d" % n
5.203 + return "__const%s" % n
5.204
5.205 def encode_literal_constant_size(value):
5.206
5.207 @@ -419,7 +469,7 @@
5.208
5.209 "Encode a reference to a literal constant with the number 'n'."
5.210
5.211 - return "__constvalue%d" % n
5.212 + return "__constvalue%s" % n
5.213
5.214
5.215
6.1 --- a/generator.py Mon Feb 20 18:48:39 2017 +0100
6.2 +++ b/generator.py Fri Feb 24 13:27:44 2017 +0100
6.3 @@ -19,7 +19,7 @@
6.4 this program. If not, see <http://www.gnu.org/licenses/>.
6.5 """
6.6
6.7 -from common import CommonOutput
6.8 +from common import CommonOutput, copy
6.9 from encoders import encode_function_pointer, \
6.10 encode_instantiator_pointer, \
6.11 encode_literal_constant, encode_literal_constant_member, \
6.12 @@ -31,24 +31,10 @@
6.13 encode_symbol, encode_tablename, \
6.14 encode_type_attribute, decode_type_attribute, \
6.15 is_type_attribute
6.16 -from os import listdir, mkdir
6.17 -from os.path import exists, isdir, join, split
6.18 +from os import listdir, mkdir, remove
6.19 +from os.path import exists, isdir, join, split, splitext
6.20 from referencing import Reference
6.21
6.22 -def copy(source, target):
6.23 -
6.24 - "Copy a text file from 'source' to 'target'."
6.25 -
6.26 - if isdir(target):
6.27 - target = join(target, split(source)[-1])
6.28 - infile = open(source)
6.29 - outfile = open(target, "w")
6.30 - try:
6.31 - outfile.write(infile.read())
6.32 - finally:
6.33 - outfile.close()
6.34 - infile.close()
6.35 -
6.36 class Generator(CommonOutput):
6.37
6.38 "A code generator."
6.39 @@ -92,13 +78,13 @@
6.40 self.optimiser = optimiser
6.41 self.output = output
6.42
6.43 - def to_output(self, debug=False):
6.44 + def to_output(self, debug=False, gc_sections=False):
6.45
6.46 "Write the generated code."
6.47
6.48 self.check_output()
6.49 self.write_structures()
6.50 - self.write_scripts(debug)
6.51 + self.write_scripts(debug, gc_sections)
6.52 self.copy_templates()
6.53
6.54 def copy_templates(self):
6.55 @@ -124,9 +110,34 @@
6.56 if not exists(target):
6.57 mkdir(target)
6.58
6.59 - for filename in listdir(pathname):
6.60 + existing = listdir(target)
6.61 + needed = listdir(pathname)
6.62 +
6.63 + # Determine which files are superfluous by comparing their
6.64 + # basenames (without extensions) to those of the needed
6.65 + # filenames. This should preserve object files for needed source
6.66 + # files, only discarding completely superfluous files from the
6.67 + # target directory.
6.68 +
6.69 + needed_basenames = set()
6.70 + for filename in needed:
6.71 + needed_basenames.add(splitext(filename)[0])
6.72 +
6.73 + superfluous = []
6.74 + for filename in existing:
6.75 + if splitext(filename)[0] not in needed_basenames:
6.76 + superfluous.append(filename)
6.77 +
6.78 + # Copy needed files.
6.79 +
6.80 + for filename in needed:
6.81 copy(join(pathname, filename), target)
6.82
6.83 + # Remove superfluous files.
6.84 +
6.85 + for filename in superfluous:
6.86 + remove(join(target, filename))
6.87 +
6.88 def write_structures(self):
6.89
6.90 "Write structures used by the program."
6.91 @@ -217,7 +228,7 @@
6.92 # Define special attributes.
6.93
6.94 attrs["__fn__"] = path
6.95 - attrs["__args__"] = encode_size("pmin", path)
6.96 + attrs["__args__"] = path
6.97
6.98 self.populate_structure(Reference(kind, path), attrs, kind, structure)
6.99
6.100 @@ -270,7 +281,7 @@
6.101 # Set a special callable attribute on the instance.
6.102
6.103 function_instance_attrs["__fn__"] = path
6.104 - function_instance_attrs["__args__"] = encode_size("pmin", path)
6.105 + function_instance_attrs["__args__"] = path
6.106
6.107 structure = self.populate_function(path, function_instance_attrs)
6.108 self.write_structure(f_decls, f_defs, path, table_name, structure)
6.109 @@ -286,22 +297,48 @@
6.110
6.111 print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path)
6.112
6.113 + # Generate parameter table size data.
6.114 +
6.115 + min_parameters = {}
6.116 + max_parameters = {}
6.117 + size_parameters = {}
6.118 +
6.119 # Consolidate parameter tables for instantiators and functions.
6.120
6.121 parameter_tables = set()
6.122
6.123 for path, function_path in self.callables.items():
6.124 + argmin, argmax = self.get_argument_limits(function_path)
6.125 +
6.126 + # Obtain the parameter table members.
6.127 +
6.128 parameters = self.optimiser.parameters[function_path]
6.129 if not parameters:
6.130 parameters = ()
6.131 else:
6.132 parameters = tuple(parameters)
6.133 - parameter_tables.add(parameters)
6.134 +
6.135 + # Define each table in terms of the members and the minimum
6.136 + # number of arguments.
6.137 +
6.138 + parameter_tables.add((argmin, parameters))
6.139 + signature = self.get_parameter_signature(argmin, parameters)
6.140 +
6.141 + # Record the minimum number of arguments, the maximum number,
6.142 + # and the size of the table.
6.143 +
6.144 + min_parameters[signature] = argmin
6.145 + max_parameters[signature] = argmax
6.146 + size_parameters[signature] = len(parameters)
6.147 +
6.148 + self.write_size_constants(f_consts, "pmin", min_parameters, 0)
6.149 + self.write_size_constants(f_consts, "pmax", max_parameters, 0)
6.150 + self.write_size_constants(f_consts, "psize", size_parameters, 0)
6.151
6.152 # Generate parameter tables for distinct function signatures.
6.153
6.154 - for parameters in parameter_tables:
6.155 - self.make_parameter_table(f_decls, f_defs, parameters)
6.156 + for argmin, parameters in parameter_tables:
6.157 + self.make_parameter_table(f_decls, f_defs, argmin, parameters)
6.158
6.159 # Generate predefined constants.
6.160
6.161 @@ -340,27 +377,6 @@
6.162 for kind, sizes in size_tables:
6.163 self.write_size_constants(f_consts, kind, sizes, 0)
6.164
6.165 - # Generate parameter table size data.
6.166 -
6.167 - min_sizes = {}
6.168 - max_sizes = {}
6.169 -
6.170 - # Determine the minimum number of parameters for each
6.171 -
6.172 - for path in self.optimiser.parameters.keys():
6.173 - argmin, argmax = self.get_argument_limits(path)
6.174 - min_sizes[path] = argmin
6.175 -
6.176 - # Use the parameter table details to define the maximum number.
6.177 - # The context is already present in the collection.
6.178 -
6.179 - for parameters in parameter_tables:
6.180 - signature = self.get_parameter_signature(parameters)
6.181 - max_sizes[signature] = len(parameters)
6.182 -
6.183 - self.write_size_constants(f_consts, "pmin", min_sizes, 0)
6.184 - self.write_size_constants(f_consts, "pmax", max_sizes, 0)
6.185 -
6.186 # Generate parameter codes.
6.187
6.188 self.write_code_constants(f_consts, self.optimiser.all_paramnames, self.optimiser.arg_locations, "pcode", "ppos")
6.189 @@ -402,7 +418,7 @@
6.190 f_signatures.close()
6.191 f_code.close()
6.192
6.193 - def write_scripts(self, debug):
6.194 + def write_scripts(self, debug, gc_sections):
6.195
6.196 "Write scripts used to build the program."
6.197
6.198 @@ -413,6 +429,9 @@
6.199 if debug:
6.200 print >>f_options, "CFLAGS = -g"
6.201
6.202 + if gc_sections:
6.203 + print >>f_options, "include gc_sections.mk"
6.204 +
6.205 # Identify modules used by the program.
6.206
6.207 native_modules = [join("native", "common.c")]
6.208 @@ -500,6 +519,11 @@
6.209 else:
6.210 attrs["__key__"] = None
6.211
6.212 + # Initialise the size, if a string.
6.213 +
6.214 + if attrs.has_key("__size__"):
6.215 + attrs["__size__"] = len(data)
6.216 +
6.217 # Define Unicode constant encoding details.
6.218
6.219 if cls == self.unicode_type:
6.220 @@ -512,7 +536,7 @@
6.221 # Employ a special alias that will be tested specifically in
6.222 # encode_member.
6.223
6.224 - encoding_ref = Reference("<instance>", self.string_type, "$c%d" % n)
6.225 + encoding_ref = Reference("<instance>", self.string_type, "$c%s" % n)
6.226
6.227 # Use None where no encoding was indicated.
6.228
6.229 @@ -533,31 +557,34 @@
6.230 # Define a macro for the constant.
6.231
6.232 attr_name = encode_path(const_path)
6.233 - print >>f_decls, "#define %s ((__attr) {{.context=&%s, .value=&%s}})" % (attr_name, structure_name, structure_name)
6.234 + print >>f_decls, "#define %s ((__attr) {.value=&%s})" % (attr_name, structure_name)
6.235
6.236 - def make_parameter_table(self, f_decls, f_defs, parameters):
6.237 + def make_parameter_table(self, f_decls, f_defs, argmin, parameters):
6.238
6.239 """
6.240 Write parameter table details to 'f_decls' (to declare a table) and to
6.241 - 'f_defs' (to define the contents) for the given 'parameters'.
6.242 + 'f_defs' (to define the contents) for the given 'argmin' and
6.243 + 'parameters'.
6.244 """
6.245
6.246 # Use a signature for the table name instead of a separate name for each
6.247 # function.
6.248
6.249 - signature = self.get_parameter_signature(parameters)
6.250 + signature = self.get_parameter_signature(argmin, parameters)
6.251 table_name = encode_tablename("<function>", signature)
6.252 - structure_size = encode_size("pmax", signature)
6.253 + min_parameters = encode_size("pmin", signature)
6.254 + max_parameters = encode_size("pmax", signature)
6.255 + structure_size = encode_size("psize", signature)
6.256
6.257 table = []
6.258 self.populate_parameter_table(parameters, table)
6.259 - self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table)
6.260 + self.write_parameter_table(f_decls, f_defs, table_name, min_parameters, max_parameters, structure_size, table)
6.261
6.262 - def get_parameter_signature(self, parameters):
6.263 + def get_parameter_signature(self, argmin, parameters):
6.264
6.265 - "Return a signature for the given 'parameters'."
6.266 + "Return a signature for the given 'argmin' and 'parameters'."
6.267
6.268 - l = []
6.269 + l = [str(argmin)]
6.270 for parameter in parameters:
6.271 if parameter is None:
6.272 l.append("")
6.273 @@ -571,8 +598,9 @@
6.274 "Return the signature for the callable with the given 'path'."
6.275
6.276 function_path = self.callables[path]
6.277 + argmin, argmax = self.get_argument_limits(function_path)
6.278 parameters = self.optimiser.parameters[function_path]
6.279 - return self.get_parameter_signature(parameters)
6.280 + return self.get_parameter_signature(argmin, parameters)
6.281
6.282 def write_size_constants(self, f_consts, size_prefix, sizes, padding):
6.283
6.284 @@ -632,25 +660,45 @@
6.285
6.286 # Write the corresponding definition.
6.287
6.288 - print >>f_defs, "const __table %s = {\n %s,\n {\n %s\n }\n };\n" % (
6.289 - table_name, structure_size,
6.290 - ",\n ".join(table))
6.291 + print >>f_defs, """\
6.292 +const __table %s = {
6.293 + %s,
6.294 + {
6.295 + %s
6.296 + }
6.297 +};
6.298 +""" % (table_name, structure_size,
6.299 + ",\n ".join(table))
6.300
6.301 - def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table):
6.302 + def write_parameter_table(self, f_decls, f_defs, table_name, min_parameters,
6.303 + max_parameters, structure_size, table):
6.304
6.305 """
6.306 Write the declarations to 'f_decls' and definitions to 'f_defs' for
6.307 - the object having the given 'table_name' and the given 'structure_size',
6.308 - with 'table' details used to populate the definition.
6.309 + the object having the given 'table_name' and the given 'min_parameters',
6.310 + 'max_parameters' and 'structure_size', with 'table' details used to
6.311 + populate the definition.
6.312 """
6.313
6.314 + members = []
6.315 + for t in table:
6.316 + members.append("{.code=%s, .pos=%s}" % t)
6.317 +
6.318 print >>f_decls, "extern const __ptable %s;\n" % table_name
6.319
6.320 # Write the corresponding definition.
6.321
6.322 - print >>f_defs, "const __ptable %s = {\n %s,\n {\n %s\n }\n };\n" % (
6.323 - table_name, structure_size,
6.324 - ",\n ".join([("{%s, %s}" % t) for t in table]))
6.325 + print >>f_defs, """\
6.326 +const __ptable %s = {
6.327 + .min=%s,
6.328 + .max=%s,
6.329 + .size=%s,
6.330 + {
6.331 + %s
6.332 + }
6.333 +};
6.334 +""" % (table_name, min_parameters, max_parameters, structure_size,
6.335 + ",\n ".join(members))
6.336
6.337 def write_instance_structure(self, f_decls, path, structure_size):
6.338
6.339 @@ -860,16 +908,10 @@
6.340
6.341 if kind == "<class>":
6.342 attr = encode_instantiator_pointer(attr)
6.343 - unbound_attr = attr
6.344 -
6.345 - # Provide bound method and unbound function pointers if
6.346 - # populating methods in a class.
6.347 -
6.348 else:
6.349 attr = encode_function_pointer(attr)
6.350 - unbound_attr = "__unbound_method"
6.351
6.352 - structure.append("{{.inv=%s, .fn=%s}}" % (unbound_attr, attr))
6.353 + structure.append("{.fn=%s}" % attr)
6.354 continue
6.355
6.356 # Special argument specification member.
6.357 @@ -878,23 +920,28 @@
6.358 signature = self.get_signature_for_callable(ref.get_origin())
6.359 ptable = encode_tablename("<function>", signature)
6.360
6.361 - structure.append("{{.min=%s, .ptable=&%s}}" % (attr, ptable))
6.362 + structure.append("{.ptable=&%s}" % ptable)
6.363 continue
6.364
6.365 # Special internal data member.
6.366
6.367 elif attrname == "__data__":
6.368 - structure.append("{{.size=%d, .%s=%s}}" % (
6.369 - encode_literal_constant_size(attr),
6.370 + structure.append("{.%s=%s}" % (
6.371 encode_literal_constant_member(attr),
6.372 encode_literal_constant_value(attr)))
6.373 continue
6.374
6.375 + # Special internal size member.
6.376 +
6.377 + elif attrname == "__size__":
6.378 + structure.append("{.intvalue=%d}" % attr)
6.379 + continue
6.380 +
6.381 # Special internal key member.
6.382
6.383 elif attrname == "__key__":
6.384 - structure.append("{{.code=%s, .pos=%s}}" % (attr and encode_symbol("code", attr) or "0",
6.385 - attr and encode_symbol("pos", attr) or "0"))
6.386 + structure.append("{.code=%s, .pos=%s}" % (attr and encode_symbol("code", attr) or "0",
6.387 + attr and encode_symbol("pos", attr) or "0"))
6.388 continue
6.389
6.390 # Special cases.
6.391 @@ -926,7 +973,7 @@
6.392 constant_name = "$c%d" % local_number
6.393 attr_path = "%s.%s" % (path, constant_name)
6.394 constant_number = self.optimiser.constant_numbers[attr_path]
6.395 - constant_value = "__const%d" % constant_number
6.396 + constant_value = "__const%s" % constant_number
6.397 structure.append("%s /* %s */" % (constant_value, attrname))
6.398 continue
6.399
6.400 @@ -937,13 +984,33 @@
6.401 # object paths.
6.402
6.403 value = path.rsplit(".", 1)[0]
6.404 - structure.append("{{.context=0, .value=&%s}}" % encode_path(value))
6.405 + structure.append("{.value=&%s}" % encode_path(value))
6.406 + continue
6.407 +
6.408 + # Special context member.
6.409 + # Set the context depending on the kind of attribute.
6.410 + # For methods: <parent>
6.411 + # For other attributes: __NULL
6.412 +
6.413 + elif attrname == "__context__":
6.414 + path = ref.get_origin()
6.415 +
6.416 + # Contexts of methods are derived from their object paths.
6.417 +
6.418 + context = "0"
6.419 +
6.420 + if ref.get_kind() == "<function>":
6.421 + parent = path.rsplit(".", 1)[0]
6.422 + if self.importer.classes.has_key(parent):
6.423 + context = "&%s" % encode_path(parent)
6.424 +
6.425 + structure.append("{.value=%s}" % context)
6.426 continue
6.427
6.428 # Special class relationship attributes.
6.429
6.430 elif is_type_attribute(attrname):
6.431 - structure.append("{{.context=0, .value=&%s}}" % encode_path(decode_type_attribute(attrname)))
6.432 + structure.append("{.value=&%s}" % encode_path(decode_type_attribute(attrname)))
6.433 continue
6.434
6.435 # All other kinds of members.
6.436 @@ -968,7 +1035,7 @@
6.437 # Use the alias directly if appropriate.
6.438
6.439 if alias.startswith("$c"):
6.440 - constant_value = encode_literal_constant(int(alias[2:]))
6.441 + constant_value = encode_literal_constant(alias[2:])
6.442 return "%s /* %s */" % (constant_value, name)
6.443
6.444 # Obtain a constant value directly assigned to the attribute.
6.445 @@ -982,33 +1049,22 @@
6.446
6.447 if kind == "<instance>" and origin == self.none_type:
6.448 attr_path = encode_predefined_reference(self.none_value)
6.449 - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name)
6.450 + return "{.value=&%s} /* %s */" % (attr_path, name)
6.451
6.452 # Predefined constant members.
6.453
6.454 if (path, name) in self.predefined_constant_members:
6.455 attr_path = encode_predefined_reference("%s.%s" % (path, name))
6.456 - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name)
6.457 + return "{.value=&%s} /* %s */" % (attr_path, name)
6.458
6.459 # General undetermined members.
6.460
6.461 if kind in ("<var>", "<instance>"):
6.462 attr_path = encode_predefined_reference(self.none_value)
6.463 - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name)
6.464 -
6.465 - # Set the context depending on the kind of attribute.
6.466 - # For methods: {&<parent>, &<attr>}
6.467 - # For other attributes: {&<attr>, &<attr>}
6.468 + return "{.value=&%s} /* %s */" % (attr_path, name)
6.469
6.470 else:
6.471 - if kind == "<function>" and structure_type == "<class>":
6.472 - parent = origin.rsplit(".", 1)[0]
6.473 - context = "&%s" % encode_path(parent)
6.474 - elif kind == "<instance>":
6.475 - context = "&%s" % encode_path(origin)
6.476 - else:
6.477 - context = "0"
6.478 - return "{{.context=%s, .value=&%s}}" % (context, encode_path(origin))
6.479 + return "{.value=&%s}" % encode_path(origin)
6.480
6.481 def append_defaults(self, path, structure):
6.482
6.483 @@ -1116,7 +1172,7 @@
6.484 }
6.485 __Catch(__tmp_exc)
6.486 {
6.487 - if (__ISINSTANCE(__tmp_exc.arg, ((__attr) {{.context=0, .value=&__builtins___exception_system_SystemExit}})))
6.488 + if (__ISINSTANCE(__tmp_exc.arg, ((__attr) {.value=&__builtins___exception_system_SystemExit})))
6.489 return __load_via_object(
6.490 __load_via_object(__tmp_exc.arg.value, %s).value,
6.491 %s).intvalue;
7.1 --- a/inspector.py Mon Feb 20 18:48:39 2017 +0100
7.2 +++ b/inspector.py Fri Feb 24 13:27:44 2017 +0100
7.3 @@ -518,14 +518,17 @@
7.4 # class. Function instances provide these attributes.
7.5
7.6 if class_name != "__builtins__.core.function":
7.7 +
7.8 self.set_name("__fn__") # special instantiator attribute
7.9 self.set_name("__args__") # special instantiator attribute
7.10
7.11 - # Provide leafname and parent attributes.
7.12 + # Provide leafname, parent and context attributes.
7.13
7.14 parent, leafname = class_name.rsplit(".", 1)
7.15 self.set_name("__name__", self.get_constant("string", leafname).reference())
7.16 - self.set_name("__parent__")
7.17 +
7.18 + if class_name != "__builtins__.core.function":
7.19 + self.set_name("__parent__")
7.20
7.21 self.process_structure_node(n.code)
7.22 self.exit_namespace()
8.1 --- a/internal_tests/branches.py Mon Feb 20 18:48:39 2017 +0100
8.2 +++ b/internal_tests/branches.py Fri Feb 24 13:27:44 2017 +0100
8.3 @@ -2,10 +2,73 @@
8.4
8.5 import branching
8.6
8.7 +def simple_usage(assignment):
8.8 + d = {}
8.9 + for name, usages in assignment.get_usage().items():
8.10 + l = []
8.11 + for usage in usages:
8.12 + if not usage:
8.13 + l.append(usage)
8.14 + else:
8.15 + l2 = []
8.16 + for t in usage:
8.17 + attrname, invocation, assignment = t
8.18 + l2.append(attrname)
8.19 + l.append(tuple(l2))
8.20 + d[name] = set(l)
8.21 + return d
8.22 +
8.23 names = []
8.24
8.25 # Equivalent to...
8.26 #
8.27 +# y = ...
8.28 +# while cond0:
8.29 +# if cond1:
8.30 +# y.a1
8.31 +# elif cond2:
8.32 +# y = ...
8.33 +# y.a2
8.34 +# else:
8.35 +# y.a3
8.36 +
8.37 +bt = branching.BranchTracker()
8.38 +y1 = bt.assign_names(["y"])
8.39 +bt.new_branchpoint(True) # begin
8.40 +bt.new_branch(True) # while ...
8.41 +bt.new_branchpoint() # begin
8.42 +bt.new_branch() # if ...
8.43 +ya1 = bt.use_attribute("y", "a1")
8.44 +bt.shelve_branch()
8.45 +bt.new_branch() # elif ...
8.46 +y2 = bt.assign_names(["y"])
8.47 +ya2 = bt.use_attribute("y", "a2")
8.48 +bt.shelve_branch()
8.49 +bt.new_branch() # else
8.50 +ya1 = bt.use_attribute("y", "a3")
8.51 +bt.shelve_branch()
8.52 +bt.merge_branches() # end
8.53 +bt.resume_continuing_branches()
8.54 +bt.shelve_branch(True)
8.55 +bt.new_branch() # (null)
8.56 +bt.shelve_branch()
8.57 +bt.merge_branches() # end
8.58 +bt.resume_broken_branches()
8.59 +
8.60 +print simple_usage(y1) == \
8.61 + {'y' : set([(), ('a1',), ('a3',)])}, \
8.62 + simple_usage(y1)
8.63 +print simple_usage(y2) == \
8.64 + {'y' : set([('a2',)])}, \
8.65 + simple_usage(y2)
8.66 +print bt.get_assignment_positions_for_branches("y", ya1) == [0, 1], \
8.67 + bt.get_assignment_positions_for_branches("y", ya1)
8.68 +print bt.get_assignment_positions_for_branches("y", ya2) == [1], \
8.69 + bt.get_assignment_positions_for_branches("y", ya2)
8.70 +names.append(bt.assignments["y"])
8.71 +
8.72 +# Equivalent to...
8.73 +#
8.74 # a = ...
8.75 # a.p
8.76 # if ...:
8.77 @@ -28,12 +91,12 @@
8.78 bt.merge_branches() # end
8.79 aq = bt.use_attribute("a", "q")
8.80
8.81 -print a1.get_usage() == \
8.82 +print simple_usage(a1) == \
8.83 {'a' : set([('p',), ('p', 'q')])}, \
8.84 - a1.get_usage()
8.85 -print a2.get_usage() == \
8.86 + simple_usage(a1)
8.87 +print simple_usage(a2) == \
8.88 {'a' : set([('q', 'x')])}, \
8.89 - a2.get_usage()
8.90 + simple_usage(a2)
8.91 print bt.get_assignment_positions_for_branches("a", ax) == [1], \
8.92 bt.get_assignment_positions_for_branches("a", ax)
8.93 print bt.get_assignment_positions_for_branches("a", aq) == [0, 1], \
8.94 @@ -68,9 +131,9 @@
8.95 bt.merge_branches() # end
8.96 bt.use_attribute("a", "q")
8.97
8.98 -print a.get_usage() == \
8.99 +print simple_usage(a) == \
8.100 {'a' : set([('p', 'q'), ('p', 'q', 'x'), ('p', 'q', 'y', 'z')])}, \
8.101 - a.get_usage()
8.102 + simple_usage(a)
8.103 print bt.get_assignment_positions_for_branches("a", ax) == [0], \
8.104 bt.get_assignment_positions_for_branches("a", ax)
8.105 print bt.get_assignment_positions_for_branches("a", ay) == [0], \
8.106 @@ -101,8 +164,8 @@
8.107 bt.resume_broken_branches()
8.108 bt.use_attribute("a", "q")
8.109
8.110 -print a.get_usage() == \
8.111 - {'a' : set([('p', 'q'), ('p', 'q', 'x')])}, a.get_usage()
8.112 +print simple_usage(a) == \
8.113 + {'a' : set([('p', 'q'), ('p', 'q', 'x')])}, simple_usage(a)
8.114 print bt.get_assignment_positions_for_branches("a", ax) == [0], \
8.115 bt.get_assignment_positions_for_branches("a", ax)
8.116 names.append(bt.assignments["a"])
8.117 @@ -139,9 +202,9 @@
8.118 bt.resume_broken_branches()
8.119 bt.use_attribute("a", "q")
8.120
8.121 -print a.get_usage() == \
8.122 +print simple_usage(a) == \
8.123 {'a' : set([('p', 'q'), ('p', 'q', 'x'), ('p', 'q', 'y')])}, \
8.124 - a.get_usage()
8.125 + simple_usage(a)
8.126 print bt.get_assignment_positions_for_branches("a", ax) == [0], \
8.127 bt.get_assignment_positions_for_branches("a", ax)
8.128 print bt.get_assignment_positions_for_branches("a", ay) == [0], \
8.129 @@ -182,10 +245,10 @@
8.130 bt.resume_broken_branches()
8.131 bt.use_attribute("a", "q")
8.132
8.133 -print a1.get_usage() == \
8.134 - {'a' : set([('p', 'q'), ('p', 'q', 'y'), ('p',)])}, a1.get_usage()
8.135 -print a2.get_usage() == \
8.136 - {'a' : set([('q', 'x')])}, a2.get_usage()
8.137 +print simple_usage(a1) == \
8.138 + {'a' : set([('p', 'q'), ('p', 'q', 'y'), ('p',)])}, simple_usage(a1)
8.139 +print simple_usage(a2) == \
8.140 + {'a' : set([('q', 'x')])}, simple_usage(a2)
8.141 print bt.get_assignment_positions_for_branches("a", ax) == [1], \
8.142 bt.get_assignment_positions_for_branches("a", ax)
8.143 print bt.get_assignment_positions_for_branches("a", ay) == [0, 1], \
8.144 @@ -226,10 +289,10 @@
8.145 bt.resume_broken_branches()
8.146 bt.use_attribute("a", "q")
8.147
8.148 -print a1.get_usage() == \
8.149 - {'a' : set([('p', 'q'), ('p', 'q', 'y'), ('p',)])}, a1.get_usage()
8.150 -print a2.get_usage() == \
8.151 - {'a' : set([('q', 'x')])}, a2.get_usage()
8.152 +print simple_usage(a1) == \
8.153 + {'a' : set([('p', 'q'), ('p', 'q', 'y'), ('p',)])}, simple_usage(a1)
8.154 +print simple_usage(a2) == \
8.155 + {'a' : set([('q', 'x')])}, simple_usage(a2)
8.156 print bt.get_assignment_positions_for_branches("a", ax) == [1], \
8.157 bt.get_assignment_positions_for_branches("a", ax)
8.158 print bt.get_assignment_positions_for_branches("a", ay) == [0, 1], \
8.159 @@ -260,10 +323,10 @@
8.160 bt.resume_broken_branches()
8.161 aq = bt.use_attribute("a", "q")
8.162
8.163 -print a1.get_usage() == \
8.164 - {'a' : set([('p', 'q'), ('p',)])}, a1.get_usage()
8.165 -print a2.get_usage() == \
8.166 - {'a' : set([('q', 'x')])}, a2.get_usage()
8.167 +print simple_usage(a1) == \
8.168 + {'a' : set([('p', 'q'), ('p',)])}, simple_usage(a1)
8.169 +print simple_usage(a2) == \
8.170 + {'a' : set([('q', 'x')])}, simple_usage(a2)
8.171 print bt.get_assignment_positions_for_branches("a", ax) == [1], \
8.172 bt.get_assignment_positions_for_branches("a", ax)
8.173 print bt.get_assignment_positions_for_branches("a", ap) == [0], \
8.174 @@ -301,8 +364,8 @@
8.175 bt.resume_broken_branches()
8.176 bt.use_attribute("a", "r")
8.177
8.178 -print a1.get_usage() == \
8.179 - {'a' : set([('p', 'q', 'r'), ('p', 'r')])}, a1.get_usage()
8.180 +print simple_usage(a1) == \
8.181 + {'a' : set([('p', 'q', 'r'), ('p', 'r')])}, simple_usage(a1)
8.182 names.append(bt.assignments["a"])
8.183
8.184 # Equivalent to...
8.185 @@ -332,8 +395,8 @@
8.186 bt.shelve_branch()
8.187 bt.merge_branches() # end
8.188
8.189 -print a1.get_usage() == \
8.190 - {'a' : set([('p', 'q', 'r'), ('p', 'q'), ('p',)])}, a1.get_usage()
8.191 +print simple_usage(a1) == \
8.192 + {'a' : set([('p', 'q', 'r'), ('p', 'q'), ('p',)])}, simple_usage(a1)
8.193 names.append(bt.assignments["a"])
8.194
8.195 # Equivalent to...
8.196 @@ -356,8 +419,8 @@
8.197 bt.merge_branches() # end
8.198 bt.use_attribute("a", "q")
8.199
8.200 -print a1.get_usage() == \
8.201 - {'a' : set([('p',), ('q',)])}, a1.get_usage()
8.202 +print simple_usage(a1) == \
8.203 + {'a' : set([('p',), ('q',)])}, simple_usage(a1)
8.204 names.append(bt.assignments["a"])
8.205
8.206 # Equivalent to...
8.207 @@ -388,8 +451,8 @@
8.208 bt.shelve_branch()
8.209 bt.merge_branches() # end
8.210
8.211 -print a1.get_usage() == \
8.212 - {'a' : set([('p',), ('q', 'r')])}, a1.get_usage()
8.213 +print simple_usage(a1) == \
8.214 + {'a' : set([('p',), ('q', 'r')])}, simple_usage(a1)
8.215 names.append(bt.assignments["a"])
8.216
8.217 # Equivalent to...
8.218 @@ -421,10 +484,10 @@
8.219 bt.shelve_branch()
8.220 bt.merge_branches() # end
8.221
8.222 -print a1.get_usage() == \
8.223 - {'a' : set([('p',), ()])}, a1.get_usage()
8.224 -print a2.get_usage() == \
8.225 - {'a' : set([('q',), ()])}, a2.get_usage()
8.226 +print simple_usage(a1) == \
8.227 + {'a' : set([('p',), ()])}, simple_usage(a1)
8.228 +print simple_usage(a2) == \
8.229 + {'a' : set([('q',), ()])}, simple_usage(a2)
8.230 print bt.get_assignment_positions_for_branches("a", ap) == [0], \
8.231 bt.get_assignment_positions_for_branches("a", ap)
8.232 print bt.get_assignment_positions_for_branches("a", aq) == [1], \
8.233 @@ -455,12 +518,12 @@
8.234 bt.merge_branches() # end
8.235 aq = bt.use_attribute("a", "q")
8.236
8.237 -print a1.get_usage() == \
8.238 +print simple_usage(a1) == \
8.239 {'a' : set([('p',), ('p', 'q')])}, \
8.240 - a1.get_usage()
8.241 -print a2.get_usage() == \
8.242 + simple_usage(a1)
8.243 +print simple_usage(a2) == \
8.244 {'a' : set([('q', 'x')])}, \
8.245 - a2.get_usage()
8.246 + simple_usage(a2)
8.247 print bt.get_assignment_positions_for_branches("a", ap) == [0], \
8.248 bt.get_assignment_positions_for_branches("a", ap)
8.249 print bt.get_assignment_positions_for_branches("a", ax) == [1], \
8.250 @@ -489,9 +552,9 @@
8.251 bt.merge_branches() # end
8.252 aq = bt.use_attribute("a", "q")
8.253
8.254 -print a1.get_usage() == \
8.255 +print simple_usage(a1) == \
8.256 {'a' : set([('q', 'x')])}, \
8.257 - a1.get_usage()
8.258 + simple_usage(a1)
8.259 print bt.get_assignment_positions_for_branches("a", aq) == [None, 0], \
8.260 bt.get_assignment_positions_for_branches("a", aq)
8.261 names.append(bt.assignments["a"])
8.262 @@ -514,8 +577,8 @@
8.263 bt.merge_branches() # end
8.264 aq = bt.use_attribute("a", "q")
8.265
8.266 -print a1.get_usage() == \
8.267 - {'a' : set([()])}, a1.get_usage()
8.268 +print simple_usage(a1) == \
8.269 + {'a' : set([()])}, simple_usage(a1)
8.270 print bt.get_assignment_positions_for_branches("a", aq) == [None], \
8.271 bt.get_assignment_positions_for_branches("a", aq)
8.272 names.append(bt.assignments["a"])
8.273 @@ -546,8 +609,8 @@
8.274 bt.use_attribute("a", "r")
8.275 bt.restore_active_branches(branches)
8.276
8.277 -print a1.get_usage() == \
8.278 - {'a' : set([('p', 'r'), ('q', 'r')])}, a1.get_usage()
8.279 +print simple_usage(a1) == \
8.280 + {'a' : set([('p', 'r'), ('q', 'r')])}, simple_usage(a1)
8.281 names.append(bt.assignments["a"])
8.282
8.283 # Equivalent to...
8.284 @@ -578,10 +641,10 @@
8.285 ar = bt.use_attribute("a", "r")
8.286 bt.restore_active_branches(branches)
8.287
8.288 -print a1.get_usage() == \
8.289 - {'a' : set([(), ('q', 'r')])}, a1.get_usage()
8.290 -print a2.get_usage() == \
8.291 - {'a' : set([('p', 'r')])}, a2.get_usage()
8.292 +print simple_usage(a1) == \
8.293 + {'a' : set([(), ('q', 'r')])}, simple_usage(a1)
8.294 +print simple_usage(a2) == \
8.295 + {'a' : set([('p', 'r')])}, simple_usage(a2)
8.296 print bt.get_assignment_positions_for_branches("a", ar) == [0, 1], \
8.297 bt.get_assignment_positions_for_branches("a", ar)
8.298 names.append(bt.assignments["a"])
8.299 @@ -616,10 +679,10 @@
8.300 bt.shelve_branch()
8.301 bt.merge_branches() # end
8.302
8.303 -print a1.get_usage() == \
8.304 - {'a' : set([(), ('q', 'r')])}, a1.get_usage()
8.305 -print a2.get_usage() == \
8.306 - {'a' : set([('p',)])}, a2.get_usage()
8.307 +print simple_usage(a1) == \
8.308 + {'a' : set([(), ('q', 'r')])}, simple_usage(a1)
8.309 +print simple_usage(a2) == \
8.310 + {'a' : set([('p',)])}, simple_usage(a2)
8.311 print bt.get_assignment_positions_for_branches("a", ar) == [0, 1], \
8.312 bt.get_assignment_positions_for_branches("a", ar)
8.313 names.append(bt.assignments["a"])
9.1 --- a/lib/__builtins__/core.py Mon Feb 20 18:48:39 2017 +0100
9.2 +++ b/lib/__builtins__/core.py Fri Feb 24 13:27:44 2017 +0100
9.3 @@ -86,6 +86,7 @@
9.4 self.__args__ = None
9.5 self.__name__ = None
9.6 self.__parent__ = None
9.7 + self.__context__ = None
9.8
9.9 def __bool__(self):
9.10
9.11 @@ -122,6 +123,25 @@
9.12
9.13 __repr__ = __str__
9.14
9.15 +class wrapper:
9.16 +
9.17 + "A special method wrapper."
9.18 +
9.19 + def __init__(self, context, value):
9.20 +
9.21 + "Initialise a wrapper with the given 'context' and wrapped 'value'."
9.22 +
9.23 + self.__context__ = context
9.24 + self.__value__ = value
9.25 +
9.26 + def __str__(self):
9.27 +
9.28 + "Return a string representation, referring to the wrapped object."
9.29 +
9.30 + return self.__value__.__str__()
9.31 +
9.32 + __repr__ = __str__
9.33 +
9.34 class Exception:
9.35
9.36 "The root of all exception types."
10.1 --- a/lib/__builtins__/str.py Mon Feb 20 18:48:39 2017 +0100
10.2 +++ b/lib/__builtins__/str.py Fri Feb 24 13:27:44 2017 +0100
10.3 @@ -22,8 +22,8 @@
10.4 from __builtins__.operator import _negate
10.5 from __builtins__.sequence import hashable, itemaccess
10.6 from __builtins__.types import check_int
10.7 -from native import str_add, str_lt, str_gt, str_eq, str_len, str_ord, \
10.8 - str_nonempty, str_substr
10.9 +from native import int_new, str_add, str_lt, str_gt, str_eq, str_ord, \
10.10 + str_substr
10.11
10.12 WHITESPACE = (" ", "\f", "\n", "\r", "\t")
10.13
10.14 @@ -39,26 +39,25 @@
10.15 # literals or converted using routines defined for other types, no form
10.16 # of actual initialisation is performed here.
10.17
10.18 + # Note the __key__ member. This is also initialised statically. Where
10.19 + # a string is the same as an attribute name, the __key__ member contains
10.20 + # attribute position and code details.
10.21 +
10.22 # NOTE: Cannot perform "other and other.__data__ or None" since the
10.23 # NOTE: __data__ attribute is not a normal attribute.
10.24
10.25 if other:
10.26 self.__data__ = other.__data__
10.27 + self.__key__ = other.__key__
10.28 + self.__size__ = other.__size__
10.29 else:
10.30 self.__data__ = None
10.31 -
10.32 - # Note the __key__ member. This is also initialised statically. Where
10.33 - # a string is the same as an attribute name, the __key__ member contains
10.34 - # attribute position and code details.
10.35 -
10.36 - if other:
10.37 - self.__key__ = other.__key__
10.38 - else:
10.39 self.__key__ = None
10.40 + self.__size__ = None
10.41
10.42 # Internal methods.
10.43
10.44 - def _binary_op(self, op, other):
10.45 + def _binary_op(self, op, other, sizes=False):
10.46
10.47 "Perform 'op' on this object and 'other' if appropriate."
10.48
10.49 @@ -69,10 +68,12 @@
10.50
10.51 # Otherwise, perform the operation on the operands' data.
10.52
10.53 + elif sizes:
10.54 + return op(self.__data__, other.__data__, self.__size__, other.__size__)
10.55 else:
10.56 return op(self.__data__, other.__data__)
10.57
10.58 - def _binary_op_rev(self, op, other):
10.59 + def _binary_op_rev(self, op, other, sizes=False):
10.60
10.61 "Perform 'op' on 'other' and this object if appropriate."
10.62
10.63 @@ -83,6 +84,8 @@
10.64
10.65 # Otherwise, perform the operation on the operands' data.
10.66
10.67 + elif sizes:
10.68 + return op(other.__data__, self.__data__, other.__size__, self.__size__)
10.69 else:
10.70 return op(other.__data__, self.__data__)
10.71
10.72 @@ -154,7 +157,7 @@
10.73
10.74 "Return the number of bytes in this string."
10.75
10.76 - return str_len(self.__data__)
10.77 + return int_new(self.__size__)
10.78
10.79 # General type methods.
10.80
10.81 @@ -162,7 +165,7 @@
10.82
10.83 "Return whether the string provides any data."
10.84
10.85 - return str_nonempty(self.__data__)
10.86 + return int_new(self.__size__).__bool__()
10.87
10.88 def __contains__(self, value):
10.89
10.90 @@ -196,7 +199,7 @@
10.91
10.92 "Return a string combining this string with 'other'."
10.93
10.94 - return self._binary_op(str_add, other)
10.95 + return self._binary_op(str_add, other, True)
10.96
10.97 __add__ = __iadd__
10.98
10.99 @@ -204,7 +207,7 @@
10.100
10.101 "Return a string combining this string with 'other'."
10.102
10.103 - return self._binary_op_rev(str_add, other)
10.104 + return self._binary_op_rev(str_add, other, True)
10.105
10.106 def __mod__(self, other): pass
10.107 def __rmod__(self, other): pass
11.1 --- a/lib/__builtins__/unicode.py Mon Feb 20 18:48:39 2017 +0100
11.2 +++ b/lib/__builtins__/unicode.py Fri Feb 24 13:27:44 2017 +0100
11.3 @@ -40,7 +40,7 @@
11.4 self.encoding = encoding
11.5 self.length = None
11.6
11.7 - def _binary_op(self, op, other):
11.8 + def _binary_op(self, op, other, sizes=False):
11.9
11.10 "Perform 'op' on this object and 'other' if appropriate."
11.11
11.12 @@ -51,16 +51,17 @@
11.13
11.14 # Combining text with bytes.
11.15
11.16 - elif not _isinstance(other, utf8string):
11.17 + if not _isinstance(other, utf8string):
11.18 s = self.encode()
11.19 + else:
11.20 + s = self
11.21 +
11.22 + if sizes:
11.23 + return op(s.__data__, other.__data__, s.__size__, other.__size__)
11.24 + else:
11.25 return op(s.__data__, other.__data__)
11.26
11.27 - # Otherwise, perform the operation on the operands' data.
11.28 -
11.29 - else:
11.30 - return op(self.__data__, other.__data__)
11.31 -
11.32 - def _binary_op_rev(self, op, other):
11.33 + def _binary_op_rev(self, op, other, sizes=False):
11.34
11.35 "Perform 'op' on 'other' and this object if appropriate."
11.36
11.37 @@ -71,14 +72,15 @@
11.38
11.39 # Combining text with bytes.
11.40
11.41 - elif not _isinstance(other, utf8string):
11.42 + if not _isinstance(other, utf8string):
11.43 s = self.encode()
11.44 - return op(other.__data__, s.__data__)
11.45 + else:
11.46 + s = self
11.47
11.48 - # Otherwise, perform the operation on the operands' data.
11.49 -
11.50 + if sizes:
11.51 + return op(other.__data__, s.__data__, other.__size__, s.__size__)
11.52 else:
11.53 - return op(other.__data__, self.__data__)
11.54 + return op(other.__data__, s.__data__)
11.55
11.56 def _convert(self, result, other):
11.57
11.58 @@ -118,7 +120,7 @@
11.59
11.60 "Return a string combining this string with 'other'."
11.61
11.62 - return self._convert(self._binary_op(str_add, other), other)
11.63 + return self._convert(self._binary_op(str_add, other, True), other)
11.64
11.65 __add__ = __iadd__
11.66
11.67 @@ -126,14 +128,14 @@
11.68
11.69 "Return a string combining this string with 'other'."
11.70
11.71 - return self._convert(self._binary_op_rev(str_add, other), other)
11.72 + return self._convert(self._binary_op_rev(str_add, other, True), other)
11.73
11.74 def __len__(self):
11.75
11.76 "Return the length of this string in characters."
11.77
11.78 if self.length is None:
11.79 - self.length = unicode_len(self.__data__)
11.80 + self.length = unicode_len(self.__data__, self.__size__)
11.81
11.82 return self.length
11.83
11.84 @@ -142,7 +144,7 @@
11.85 "Return the value of the string, if only a single character."
11.86
11.87 if self.__len__() == 1:
11.88 - return unicode_ord(self.__data__)
11.89 + return unicode_ord(self.__data__, self.__size__)
11.90 else:
11.91 raise ValueError, self
11.92
11.93 @@ -204,7 +206,7 @@
11.94 "Return the item at the normalised (positive) 'index'."
11.95
11.96 self._check_index(index)
11.97 - return utf8string(unicode_substr(self.__data__, index, index + 1, 1), self.encoding)
11.98 + return utf8string(unicode_substr(self.__data__, self.__size__, index, index + 1, 1), self.encoding)
11.99
11.100 def __get_multiple_items__(self, start, end, step):
11.101
12.1 --- a/lib/native/__init__.py Mon Feb 20 18:48:39 2017 +0100
12.2 +++ b/lib/native/__init__.py Fri Feb 24 13:27:44 2017 +0100
12.3 @@ -23,7 +23,8 @@
12.4
12.5 from native.identity import is_, is_not
12.6
12.7 -from native.int import int_add, int_div, int_mod, int_mul, int_neg, int_pow, \
12.8 +from native.int import int_new, \
12.9 + int_add, int_div, int_mod, int_mul, int_neg, int_pow, \
12.10 int_sub, int_and, int_not, int_or, int_xor, int_lt, \
12.11 int_gt, int_eq, int_ne, int_str
12.12
12.13 @@ -42,8 +43,8 @@
12.14
12.15 from native.program import get_using
12.16
12.17 -from native.str import str_add, str_chr, str_eq, str_gt, str_lt, str_len, \
12.18 - str_nonempty, str_ord, str_substr
12.19 +from native.str import str_add, str_chr, str_eq, str_gt, str_lt, \
12.20 + str_ord, str_substr
12.21
12.22 from native.system import exit, get_argv, get_path
12.23
13.1 --- a/lib/native/int.py Mon Feb 20 18:48:39 2017 +0100
13.2 +++ b/lib/native/int.py Fri Feb 24 13:27:44 2017 +0100
13.3 @@ -8,7 +8,7 @@
13.4 non-core exceptions used by the native functions because they need to be
13.5 identified as being needed by the program.
13.6
13.7 -Copyright (C) 2011, 2015, 2016 Paul Boddie <paul@boddie.org.uk>
13.8 +Copyright (C) 2011, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
13.9
13.10 This program is free software; you can redistribute it and/or modify it under
13.11 the terms of the GNU General Public License as published by the Free Software
13.12 @@ -24,6 +24,8 @@
13.13 this program. If not, see <http://www.gnu.org/licenses/>.
13.14 """
13.15
13.16 +def int_new(data): pass
13.17 +
13.18 def int_add(self, other): pass
13.19 def int_div(self, other): pass
13.20 def int_mod(self, other): pass
14.1 --- a/lib/native/str.py Mon Feb 20 18:48:39 2017 +0100
14.2 +++ b/lib/native/str.py Fri Feb 24 13:27:44 2017 +0100
14.3 @@ -26,13 +26,11 @@
14.4
14.5 # String operations.
14.6
14.7 -def str_add(data, other_data): pass
14.8 +def str_add(data, other_data, size, other_size): pass
14.9 def str_chr(data): pass
14.10 def str_eq(data, other_data): pass
14.11 def str_gt(data, other_data): pass
14.12 def str_lt(data, other_data): pass
14.13 -def str_len(data): pass
14.14 -def str_nonempty(data): pass
14.15 def str_ord(data): pass
14.16 def str_substr(data, start, end, step): pass
14.17
15.1 --- a/lib/native/unicode.py Mon Feb 20 18:48:39 2017 +0100
15.2 +++ b/lib/native/unicode.py Fri Feb 24 13:27:44 2017 +0100
15.3 @@ -26,9 +26,9 @@
15.4
15.5 # Unicode string operations.
15.6
15.7 -def unicode_len(data): pass
15.8 -def unicode_ord(data): pass
15.9 -def unicode_substr(data, start, end, step): pass
15.10 +def unicode_len(data, size): pass
15.11 +def unicode_ord(data, size): pass
15.12 +def unicode_substr(data, size, start, end, step): pass
15.13 def unicode_unichr(value): pass
15.14
15.15 # vim: tabstop=4 expandtab shiftwidth=4
16.1 --- a/lplc Mon Feb 20 18:48:39 2017 +0100
16.2 +++ b/lplc Fri Feb 24 13:27:44 2017 +0100
16.3 @@ -22,8 +22,8 @@
16.4 VERSION = "0.1"
16.5
16.6 from errors import *
16.7 -from os import environ, rename
16.8 -from os.path import abspath, exists, isfile, join, split
16.9 +from os import environ, listdir, remove, rename
16.10 +from os.path import abspath, exists, extsep, isdir, isfile, join, split
16.11 from pyparser import error
16.12 from subprocess import Popen, PIPE
16.13 from time import time
16.14 @@ -82,6 +82,17 @@
16.15 else:
16.16 return l, needed
16.17
16.18 +def remove_all(dirname):
16.19 +
16.20 + "Remove 'dirname' and its contents."
16.21 +
16.22 + for filename in listdir(dirname):
16.23 + pathname = join(dirname, filename)
16.24 + if isdir(pathname):
16.25 + remove_all(pathname)
16.26 + else:
16.27 + remove(pathname)
16.28 +
16.29 # Main program.
16.30
16.31 if __name__ == "__main__":
16.32 @@ -98,21 +109,34 @@
16.33 Compile the program whose principal file is given in place of <filename>.
16.34 The following options may be specified:
16.35
16.36 --c Only partially compile the program; do not attempt to build or link it
16.37 --E Ignore environment variables affecting the module search path
16.38 --g Generate debugging information for the built executable
16.39 --P Show the module search path
16.40 --q Silence messages produced when building an executable
16.41 --r Reset (discard) cached program information; inspect the whole program again
16.42 --t Silence timing messages
16.43 --tb Provide a traceback for any internal errors (development only)
16.44 --v Report compiler activities in a verbose fashion (development only)
16.45 +-c Only partially compile the program; do not build or link it
16.46 +--compile Equivalent to -c
16.47 +-E Ignore environment variables affecting the module search path
16.48 +--no-env Equivalent to -E
16.49 +-g Generate debugging information for the built executable
16.50 +--debug Equivalent to -g
16.51 +-G Remove superfluous sections of the built executable
16.52 +--gc-sections Equivalent to -G
16.53 +-P Show the module search path
16.54 +--show-path Equivalent to -P
16.55 +-q Silence messages produced when building an executable
16.56 +--quiet Equivalent to -q
16.57 +-r Reset (discard) cached information; inspect the whole program again
16.58 +--reset Equivalent to -r
16.59 +-R Reset (discard) all program details including translated code
16.60 +--reset-all Equivalent to -R
16.61 +-t Silence timing messages
16.62 +--no-timing Equivalent to -t
16.63 +-tb Provide a traceback for any internal errors (development only)
16.64 +--traceback Equivalent to -tb
16.65 +-v Report compiler activities in a verbose fashion (development only)
16.66 +--verbose Equivalent to -v
16.67
16.68 Some options may be followed by values, either immediately after the option
16.69 (without any space between) or in the arguments that follow them:
16.70
16.71 --o Indicate the output executable name
16.72 --W Show warnings on the topics indicated
16.73 +-o Indicate the output executable name
16.74 +-W Show warnings on the topics indicated
16.75
16.76 Currently, the following warnings are supported:
16.77
16.78 @@ -148,10 +172,12 @@
16.79 # Determine the options and arguments.
16.80
16.81 debug = False
16.82 + gc_sections = False
16.83 ignore_env = False
16.84 make = True
16.85 make_verbose = True
16.86 reset = False
16.87 + reset_all = False
16.88 timings = True
16.89 traceback = False
16.90 verbose = False
16.91 @@ -166,15 +192,17 @@
16.92 needed = None
16.93
16.94 for arg in args:
16.95 - if arg == "-c": make = False
16.96 - elif arg == "-E": ignore_env = True
16.97 - elif arg == "-g": debug = True
16.98 - elif arg == "-q": make_verbose = False
16.99 - elif arg == "-r": reset = True
16.100 - elif arg == "-t": timings = False
16.101 - elif arg == "-tb": traceback = True
16.102 + if arg in ("-c", "--compile"): make = False
16.103 + elif arg in ("-E", "--no-env"): ignore_env = True
16.104 + elif arg in ("-g", "--debug"): debug = True
16.105 + elif arg in ("-G", "--gc-sections"): gc_sections = True
16.106 + elif arg in ("-q", "--quiet"): make_verbose = False
16.107 + elif arg in ("-r", "--reset"): reset = True
16.108 + elif arg in ("-R", "--reset-all"): reset_all = True
16.109 + elif arg in ("-t", "--no-timing"): timings = False
16.110 + elif arg in ("-tb", "--traceback"): traceback = True
16.111 elif arg.startswith("-o"): l, needed = start_arg_list(outputs, arg, "-o", 1)
16.112 - elif arg == "-v": verbose = True
16.113 + elif arg == ("-v", "--verbose"): verbose = True
16.114 elif arg.startswith("-W"): l, needed = start_arg_list(warnings, arg, "-W", 1)
16.115 else:
16.116 l.append(arg)
16.117 @@ -193,7 +221,7 @@
16.118
16.119 # Show the module search path if requested.
16.120
16.121 - if "-P" in args:
16.122 + if "-P" in args or "--show-path" in args:
16.123 for libdir in libdirs:
16.124 print libdir
16.125 sys.exit(0)
16.126 @@ -221,12 +249,17 @@
16.127
16.128 # Define the output data directories.
16.129
16.130 - datadir = "_lplc"
16.131 + datadir = "%s%s%s" % (output, extsep, "lplc") # _main.lplc by default
16.132 cache_dir = join(datadir, "_cache")
16.133 deduced_dir = join(datadir, "_deduced")
16.134 output_dir = join(datadir, "_output")
16.135 generated_dir = join(datadir, "_generated")
16.136
16.137 + # Perform any full reset of the working data.
16.138 +
16.139 + if reset_all:
16.140 + remove_all(datadir)
16.141 +
16.142 # Load the program.
16.143
16.144 try:
16.145 @@ -255,7 +288,7 @@
16.146 if timings: now = stopwatch("Optimisation", now)
16.147
16.148 g = generator.Generator(i, o, generated_dir)
16.149 - g.to_output(debug)
16.150 + g.to_output(debug, gc_sections)
16.151
16.152 if timings: now = stopwatch("Generation", now)
16.153
16.154 @@ -270,9 +303,7 @@
16.155 make_clean_cmd = ["make", "-C", generated_dir, "clean"]
16.156 make_cmd = make_clean_cmd[:-1]
16.157
16.158 - retval = call(make_clean_cmd, make_verbose)
16.159 - if not retval:
16.160 - retval = call(make_cmd, make_verbose)
16.161 + retval = call(make_cmd, make_verbose)
16.162
16.163 if not retval:
16.164 if timings: stopwatch("Compilation", now)
17.1 --- a/optimiser.py Mon Feb 20 18:48:39 2017 +0100
17.2 +++ b/optimiser.py Fri Feb 24 13:27:44 2017 +0100
17.3 @@ -21,7 +21,7 @@
17.4
17.5 from common import add_counter_item, get_attrname_from_location, init_item, \
17.6 sorted_output
17.7 -from encoders import encode_access_location, encode_instruction, get_kinds
17.8 +from encoders import digest, encode_access_location, encode_instruction, get_kinds
17.9 from os.path import exists, join
17.10 from os import makedirs
17.11 from referencing import Reference
17.12 @@ -351,9 +351,13 @@
17.13 first_method, final_method, \
17.14 origin, accessor_kinds = access_plan
17.15
17.16 + # Emit instructions by appending them to a list.
17.17 +
17.18 instructions = []
17.19 emit = instructions.append
17.20
17.21 + # Identify any static original accessor.
17.22 +
17.23 if base:
17.24 original_accessor = base
17.25 else:
17.26 @@ -371,7 +375,7 @@
17.27 # Perform the first access explicitly if at least one operation
17.28 # requires it.
17.29
17.30 - access_first_attribute = final_method in ("access", "assign") or traversed or attrnames
17.31 + access_first_attribute = final_method in ("access", "access-invoke", "assign") or traversed or attrnames
17.32
17.33 # Determine whether the first access involves assignment.
17.34
17.35 @@ -388,8 +392,12 @@
17.36 # Prevent re-evaluation of any dynamic expression by storing it.
17.37
17.38 if original_accessor == "<expr>":
17.39 - emit((set_accessor, original_accessor))
17.40 - accessor = context_var = (stored_accessor,)
17.41 + if final_method in ("access-invoke", "static-invoke"):
17.42 + emit(("<set_context>", original_accessor))
17.43 + accessor = context_var = ("<context>",)
17.44 + else:
17.45 + emit((set_accessor, original_accessor))
17.46 + accessor = context_var = (stored_accessor,)
17.47 else:
17.48 accessor = context_var = (original_accessor,)
17.49
17.50 @@ -462,12 +470,24 @@
17.51 # Set the context, if appropriate.
17.52
17.53 if remaining == 1 and final_method != "assign" and context == "final-accessor":
17.54 - emit(("__set_context", accessor))
17.55 - accessor = context_var = "<context>"
17.56 +
17.57 + # Invoked attributes employ a separate context accessed
17.58 + # during invocation.
17.59 +
17.60 + if final_method in ("access-invoke", "static-invoke"):
17.61 + emit(("<set_context>", accessor))
17.62 + accessor = context_var = "<context>"
17.63 +
17.64 + # A private context within the access is otherwise
17.65 + # retained.
17.66 +
17.67 + else:
17.68 + emit(("<set_private_context>", accessor))
17.69 + accessor = context_var = "<private_context>"
17.70
17.71 # Perform the access only if not achieved directly.
17.72
17.73 - if remaining > 1 or final_method in ("access", "assign"):
17.74 + if remaining > 1 or final_method in ("access", "access-invoke", "assign"):
17.75
17.76 if traversal_mode == "class":
17.77 if assigning:
17.78 @@ -489,12 +509,24 @@
17.79 # Set the context, if appropriate.
17.80
17.81 if remaining == 1 and final_method != "assign" and context == "final-accessor":
17.82 - emit(("__set_context", accessor))
17.83 - accessor = context_var = "<context>"
17.84 +
17.85 + # Invoked attributes employ a separate context accessed
17.86 + # during invocation.
17.87 +
17.88 + if final_method in ("access-invoke", "static-invoke"):
17.89 + emit(("<set_context>", accessor))
17.90 + accessor = context_var = "<context>"
17.91 +
17.92 + # A private context within the access is otherwise
17.93 + # retained.
17.94 +
17.95 + else:
17.96 + emit(("<set_private_context>", accessor))
17.97 + accessor = context_var = "<private_context>"
17.98
17.99 # Perform the access only if not achieved directly.
17.100
17.101 - if remaining > 1 or final_method in ("access", "assign"):
17.102 + if remaining > 1 or final_method in ("access", "access-invoke", "assign"):
17.103
17.104 if assigning:
17.105 emit(("__check_and_store_via_any", accessor, attrname, "<assexpr>"))
17.106 @@ -505,23 +537,72 @@
17.107
17.108 # Define or emit the means of accessing the actual target.
17.109
17.110 + # Assignments to known attributes.
17.111 +
17.112 if final_method == "static-assign":
17.113 parent, attrname = origin.rsplit(".", 1)
17.114 emit(("__store_via_object", parent, attrname, "<assexpr>"))
17.115
17.116 + # Invoked attributes employ a separate context.
17.117 +
17.118 elif final_method in ("static", "static-invoke"):
17.119 - parent, attrname = origin.rsplit(".", 1)
17.120 - accessor = ("__load_static", parent, origin)
17.121 + accessor = ("__load_static_ignore", origin)
17.122
17.123 # Wrap accesses in context operations.
17.124
17.125 if context_test == "test":
17.126 - emit(("__test_context", context_var, accessor))
17.127 +
17.128 + # Test and combine the context with static attribute details.
17.129 +
17.130 + if final_method == "static":
17.131 + emit(("__load_static_test", context_var, origin))
17.132 +
17.133 + # Test the context, storing it separately if required for the
17.134 + # immediately invoked static attribute.
17.135 +
17.136 + elif final_method == "static-invoke":
17.137 + emit(("<test_context_static>", context_var, origin))
17.138 +
17.139 + # Test the context, storing it separately if required for an
17.140 + # immediately invoked attribute.
17.141 +
17.142 + elif final_method == "access-invoke":
17.143 + emit(("<test_context_revert>", context_var, accessor))
17.144 +
17.145 + # Test the context and update the attribute details if
17.146 + # appropriate.
17.147 +
17.148 + else:
17.149 + emit(("__test_context", context_var, accessor))
17.150
17.151 elif context_test == "replace":
17.152 - emit(("__update_context", context_var, accessor))
17.153 +
17.154 + # Produce an object with updated context.
17.155 +
17.156 + if final_method == "static":
17.157 + emit(("__load_static_replace", context_var, origin))
17.158 +
17.159 + # Omit the context update operation where the target is static
17.160 + # and the context is recorded separately.
17.161 +
17.162 + elif final_method == "static-invoke":
17.163 + pass
17.164
17.165 - elif final_method not in ("assign", "static-assign"):
17.166 + # If a separate context is used for an immediate invocation,
17.167 + # produce the attribute details unchanged.
17.168 +
17.169 + elif final_method == "access-invoke":
17.170 + emit(accessor)
17.171 +
17.172 + # Update the context in the attribute details.
17.173 +
17.174 + else:
17.175 + emit(("__update_context", context_var, accessor))
17.176 +
17.177 + # Omit the accessor for assignments and for invocations of static
17.178 + # targets.
17.179 +
17.180 + elif final_method not in ("assign", "static-assign", "static-invoke"):
17.181 emit(accessor)
17.182
17.183 self.access_instructions[access_location] = instructions
17.184 @@ -642,7 +723,7 @@
17.185 # Each constant is actually (value, value_type, encoding).
17.186
17.187 for constant, n in constants.items():
17.188 - add_counter_item(self.constants, constant)
17.189 + self.constants[constant] = digest(constant)
17.190
17.191 self.constant_numbers = {}
17.192
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/templates/gc_sections.mk Fri Feb 24 13:27:44 2017 +0100
18.3 @@ -0,0 +1,2 @@
18.4 +CFLAGS += -fdata-sections -ffunction-sections
18.5 +LDFLAGS += -Wl,--gc-sections
19.1 --- a/templates/native/buffer.c Mon Feb 20 18:48:39 2017 +0100
19.2 +++ b/templates/native/buffer.c Fri Feb 24 13:27:44 2017 +0100
19.3 @@ -1,6 +1,6 @@
19.4 /* Native functions for buffer operations.
19.5
19.6 -Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
19.7 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
19.8
19.9 This program is free software; you can redistribute it and/or modify it under
19.10 the terms of the GNU General Public License as published by the Free Software
19.11 @@ -37,7 +37,7 @@
19.12
19.13 /* Calculate the size of the string. */
19.14 for (i = 0; i < data->size; i++)
19.15 - size += __load_via_object(data->attrs[i].value, __pos___data__).size;
19.16 + size += __load_via_object(data->attrs[i].value, __pos___size__).intvalue;
19.17
19.18 /* Reserve space for a new string. */
19.19 s = (char *) __ALLOCATE(size + 1, sizeof(char));
19.20 @@ -46,7 +46,7 @@
19.21 for (i = 0, j = 0; i < data->size; i++)
19.22 {
19.23 o = __load_via_object(data->attrs[i].value, __pos___data__);
19.24 - n = o.size;
19.25 + n = __load_via_object(data->attrs[i].value, __pos___size__).intvalue;
19.26 memcpy(s + j, o.strvalue, n); /* does not null terminate but final byte should be zero */
19.27 j += n;
19.28 }
20.1 --- a/templates/native/common.c Mon Feb 20 18:48:39 2017 +0100
20.2 +++ b/templates/native/common.c Fri Feb 24 13:27:44 2017 +0100
20.3 @@ -34,12 +34,12 @@
20.4 return attr;
20.5 }
20.6
20.7 -__attr __new_str(char *s, size_t size)
20.8 +__attr __new_str(char *s, int size)
20.9 {
20.10 - /* Create a new string and mutate the __data__ and __key__ attributes. */
20.11 + /* Create a new string and mutate the __data__, __size__ and __key__ attributes. */
20.12 __attr attr = __NEWINSTANCE(__builtins___str_string);
20.13 - attr.value->attrs[__pos___data__].size = size;
20.14 attr.value->attrs[__pos___data__].strvalue = s;
20.15 + attr.value->attrs[__pos___size__].intvalue = size;
20.16 attr.value->attrs[__pos___key__] = __NULL;
20.17 return attr;
20.18 }
21.1 --- a/templates/native/common.h Mon Feb 20 18:48:39 2017 +0100
21.2 +++ b/templates/native/common.h Fri Feb 24 13:27:44 2017 +0100
21.3 @@ -1,6 +1,6 @@
21.4 /* Common operations for native functions.
21.5
21.6 -Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
21.7 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
21.8
21.9 This program is free software; you can redistribute it and/or modify it under
21.10 the terms of the GNU General Public License as published by the Free Software
21.11 @@ -24,7 +24,7 @@
21.12 /* Utility functions. */
21.13
21.14 __attr __new_int(int i);
21.15 -__attr __new_str(char *s, size_t size);
21.16 +__attr __new_str(char *s, int size);
21.17 __attr __new_list(__fragment *f);
21.18 __fragment *__fragment_append(__fragment *data, __attr * const value);
21.19
22.1 --- a/templates/native/iconv.c Mon Feb 20 18:48:39 2017 +0100
22.2 +++ b/templates/native/iconv.c Fri Feb 24 13:27:44 2017 +0100
22.3 @@ -1,6 +1,6 @@
22.4 /* Native functions for character set conversion.
22.5
22.6 -Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
22.7 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
22.8
22.9 This program is free software; you can redistribute it and/or modify it under
22.10 the terms of the GNU General Public License as published by the Free Software
22.11 @@ -156,7 +156,6 @@
22.12
22.13 /* Return the descriptor as an opaque value. */
22.14
22.15 - attr.context = 0;
22.16 attr.datavalue = (void *) result;
22.17 return attr;
22.18 }
23.1 --- a/templates/native/int.c Mon Feb 20 18:48:39 2017 +0100
23.2 +++ b/templates/native/int.c Fri Feb 24 13:27:44 2017 +0100
23.3 @@ -1,6 +1,6 @@
23.4 /* Native functions for integer operations.
23.5
23.6 -Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
23.7 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
23.8
23.9 This program is free software; you can redistribute it and/or modify it under
23.10 the terms of the GNU General Public License as published by the Free Software
23.11 @@ -18,8 +18,9 @@
23.12
23.13 #include <limits.h> /* INT_MAX, INT_MIN */
23.14 #include <math.h> /* ceil, log10, pow */
23.15 -#include <stdio.h> /* fdopen, snprintf, strlen */
23.16 +#include <stdio.h> /* fdopen, snprintf */
23.17 #include <errno.h> /* errno */
23.18 +#include <string.h> /* strlen */
23.19 #include "native/common.h"
23.20 #include "types.h"
23.21 #include "exceptions.h"
23.22 @@ -31,6 +32,13 @@
23.23
23.24 /* Integer operations. */
23.25
23.26 +__attr __fn_native_int_int_new(__attr __args[])
23.27 +{
23.28 + __attr * const _data = &__args[1];
23.29 +
23.30 + return __new_int(_data->intvalue);
23.31 +}
23.32 +
23.33 __attr __fn_native_int_int_add(__attr __args[])
23.34 {
23.35 __attr * const _data = &__args[1];
24.1 --- a/templates/native/int.h Mon Feb 20 18:48:39 2017 +0100
24.2 +++ b/templates/native/int.h Fri Feb 24 13:27:44 2017 +0100
24.3 @@ -1,6 +1,6 @@
24.4 /* Native functions for integer operations.
24.5
24.6 -Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
24.7 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
24.8
24.9 This program is free software; you can redistribute it and/or modify it under
24.10 the terms of the GNU General Public License as published by the Free Software
24.11 @@ -23,6 +23,8 @@
24.12
24.13 /* Integer operations. */
24.14
24.15 +__attr __fn_native_int_int_new(__attr __args[]);
24.16 +
24.17 __attr __fn_native_int_int_add(__attr __args[]);
24.18 __attr __fn_native_int_int_div(__attr __args[]);
24.19 __attr __fn_native_int_int_mod(__attr __args[]);
25.1 --- a/templates/native/io.c Mon Feb 20 18:48:39 2017 +0100
25.2 +++ b/templates/native/io.c Fri Feb 24 13:27:44 2017 +0100
25.3 @@ -1,6 +1,6 @@
25.4 /* Native functions for input/output.
25.5
25.6 -Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
25.7 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
25.8
25.9 This program is free software; you can redistribute it and/or modify it under
25.10 the terms of the GNU General Public License as published by the Free Software
25.11 @@ -80,7 +80,6 @@
25.12
25.13 else
25.14 {
25.15 - attr.context = 0;
25.16 attr.datavalue = (void *) f;
25.17 return attr;
25.18 }
25.19 @@ -113,7 +112,6 @@
25.20
25.21 else
25.22 {
25.23 - attr.context = 0;
25.24 attr.datavalue = (void *) f;
25.25 return attr;
25.26 }
25.27 @@ -160,9 +158,9 @@
25.28 /* fp interpreted as FILE reference */
25.29 FILE *f = (FILE *) fp->datavalue;
25.30 /* str.__data__ interpreted as string */
25.31 - __attr sa = __load_via_object(str->value, __pos___data__);
25.32 - char *s = sa.strvalue;
25.33 - size_t to_write = sa.size;
25.34 + char *s = __load_via_object(str->value, __pos___data__).strvalue;
25.35 + /* str.__size__ interpreted as int */
25.36 + int to_write = __load_via_object(str->value, __pos___size__).intvalue;
25.37 size_t have_written = fwrite(s, sizeof(char), to_write, f);
25.38 int error;
25.39
25.40 @@ -222,12 +220,13 @@
25.41 /* fd.__data__ interpreted as int */
25.42 int i = __load_via_object(fd->value, __pos___data__).intvalue;
25.43 /* str.__data__ interpreted as string */
25.44 - __attr sa = __load_via_object(str->value, __pos___data__);
25.45 - char *s = sa.strvalue;
25.46 + char *s = __load_via_object(str->value, __pos___data__).strvalue;
25.47 + /* str.__size__ interpreted as int */
25.48 + int size = __load_via_object(str->value, __pos___size__).intvalue;
25.49 ssize_t have_written;
25.50
25.51 errno = 0;
25.52 - have_written = write(i, s, sizeof(char) * sa.size);
25.53 + have_written = write(i, s, sizeof(char) * size);
25.54
25.55 if (have_written == -1)
25.56 __raise_io_error(__new_int(errno));
26.1 --- a/templates/native/list.c Mon Feb 20 18:48:39 2017 +0100
26.2 +++ b/templates/native/list.c Fri Feb 24 13:27:44 2017 +0100
26.3 @@ -32,7 +32,7 @@
26.4 __attr * const size = &__args[1];
26.5 /* size.__data__ interpreted as int */
26.6 unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;
26.7 - __attr attr = {{.size=0, .seqvalue=__new_fragment(n)}};
26.8 + __attr attr = {.seqvalue=__new_fragment(n)};
26.9
26.10 /* Return the __data__ attribute. */
26.11 return attr;
26.12 @@ -61,7 +61,7 @@
26.13
26.14 /* Replace the __data__ attribute if appropriate. */
26.15 if (newdata != data)
26.16 - __store_via_object(self->value, __pos___data__, ((__attr) {{.size=0, .seqvalue=newdata}}));
26.17 + __store_via_object(self->value, __pos___data__, ((__attr) {.seqvalue=newdata}));
26.18 return __builtins___none_None;
26.19 }
26.20
26.21 @@ -92,7 +92,7 @@
26.22
26.23 /* Replace the __data__ attribute if appropriate. */
26.24 if (newdata != data)
26.25 - __store_via_object(self->value, __pos___data__, ((__attr) {{.size=0, .seqvalue=newdata}}));
26.26 + __store_via_object(self->value, __pos___data__, ((__attr) {.seqvalue=newdata}));
26.27 return __builtins___none_None;
26.28 }
26.29
28.1 --- a/templates/native/str.c Mon Feb 20 18:48:39 2017 +0100
28.2 +++ b/templates/native/str.c Fri Feb 24 13:27:44 2017 +0100
28.3 @@ -32,14 +32,17 @@
28.4 {
28.5 __attr * const _data = &__args[1];
28.6 __attr * const other = &__args[2];
28.7 + __attr * const _size = &__args[3];
28.8 + __attr * const othersize = &__args[4];
28.9 /* _data, other interpreted as string */
28.10 char *s = _data->strvalue;
28.11 char *o = other->strvalue;
28.12 - int n = _data->size + other->size;
28.13 + int ss = _size->intvalue, os = othersize->intvalue;
28.14 + int n = ss + os;
28.15 char *r = (char *) __ALLOCATE(n + 1, sizeof(char));
28.16
28.17 - memcpy(r, s, _data->size);
28.18 - memcpy(r + _data->size, o, other->size);
28.19 + memcpy(r, s, ss);
28.20 + memcpy(r + ss, o, os);
28.21
28.22 /* Return a new string. */
28.23 return __new_str(r, n);
28.24 @@ -92,21 +95,6 @@
28.25 return strcmp(s, o) == 0 ? __builtins___boolean_True : __builtins___boolean_False;
28.26 }
28.27
28.28 -__attr __fn_native_str_str_len(__attr __args[])
28.29 -{
28.30 - __attr * const _data = &__args[1];
28.31 -
28.32 - /* Return the new integer. */
28.33 - return __new_int(_data->size);
28.34 -}
28.35 -
28.36 -__attr __fn_native_str_str_nonempty(__attr __args[])
28.37 -{
28.38 - __attr * const _data = &__args[1];
28.39 -
28.40 - return _data->size ? __builtins___boolean_True : __builtins___boolean_False;
28.41 -}
28.42 -
28.43 __attr __fn_native_str_str_ord(__attr __args[])
28.44 {
28.45 __attr * const _data = &__args[1];
29.1 --- a/templates/native/str.h Mon Feb 20 18:48:39 2017 +0100
29.2 +++ b/templates/native/str.h Fri Feb 24 13:27:44 2017 +0100
29.3 @@ -26,8 +26,6 @@
29.4 __attr __fn_native_str_str_lt(__attr __args[]);
29.5 __attr __fn_native_str_str_gt(__attr __args[]);
29.6 __attr __fn_native_str_str_eq(__attr __args[]);
29.7 -__attr __fn_native_str_str_len(__attr __args[]);
29.8 -__attr __fn_native_str_str_nonempty(__attr __args[]);
29.9 __attr __fn_native_str_str_ord(__attr __args[]);
29.10 __attr __fn_native_str_str_substr(__attr __args[]);
29.11
30.1 --- a/templates/native/unicode.c Mon Feb 20 18:48:39 2017 +0100
30.2 +++ b/templates/native/unicode.c Fri Feb 24 13:27:44 2017 +0100
30.3 @@ -72,11 +72,14 @@
30.4 __attr __fn_native_unicode_unicode_len(__attr __args[])
30.5 {
30.6 __attr * const _data = &__args[1];
30.7 + __attr * const _size = &__args[2];
30.8 /* _data interpreted as string */
30.9 char *s = _data->strvalue;
30.10 + /* _size interpreted as int */
30.11 + int size = _size->intvalue;
30.12 unsigned int i, c = 0;
30.13
30.14 - for (i = 0; i < _data->size; i++)
30.15 + for (i = 0; i < size; i++)
30.16 if (boundary(s[i]))
30.17 c++;
30.18
30.19 @@ -87,11 +90,14 @@
30.20 __attr __fn_native_unicode_unicode_ord(__attr __args[])
30.21 {
30.22 __attr * const _data = &__args[1];
30.23 + __attr * const _size = &__args[2];
30.24 /* _data interpreted as string */
30.25 char *s = _data->strvalue;
30.26 + /* _size interpreted as int */
30.27 + int size = _size->intvalue;
30.28 unsigned int i, c = 0, v;
30.29
30.30 - for (i = 0; i < _data->size; i++)
30.31 + for (i = 0; i < size; i++)
30.32 {
30.33 /* Evaluate the current character as a boundary. */
30.34
30.35 @@ -120,11 +126,14 @@
30.36 __attr __fn_native_unicode_unicode_substr(__attr __args[])
30.37 {
30.38 __attr * const _data = &__args[1];
30.39 - __attr * const start = &__args[2];
30.40 - __attr * const end = &__args[3];
30.41 - __attr * const step = &__args[4];
30.42 + __attr * const _size = &__args[2];
30.43 + __attr * const start = &__args[3];
30.44 + __attr * const end = &__args[4];
30.45 + __attr * const step = &__args[5];
30.46 /* _data interpreted as string */
30.47 char *s = _data->strvalue, *sub;
30.48 + /* _size interpreted as int */
30.49 + int ss = _size->intvalue;
30.50 /* start.__data__ interpreted as int */
30.51 int istart = __load_via_object(start->value, __pos___data__).intvalue;
30.52 /* end.__data__ interpreted as int */
30.53 @@ -137,14 +146,14 @@
30.54 unsigned int indexes[nchar];
30.55
30.56 unsigned int c, d, i, to, from, lastbyte = 0;
30.57 - size_t resultsize = 0;
30.58 + int resultsize = 0;
30.59
30.60 /* Find the indexes of the characters. */
30.61 if (istep > 0)
30.62 {
30.63 /* Get the first byte position. */
30.64 for (c = 0; c < istart; c++)
30.65 - lastbyte = nextpos(s, _data->size, lastbyte);
30.66 + lastbyte = nextpos(s, ss, lastbyte);
30.67
30.68 /* Get each subsequent byte position. */
30.69 for (c = istart, i = 0; i < nchar; c += istep, i++)
30.70 @@ -152,17 +161,17 @@
30.71 indexes[i] = lastbyte;
30.72
30.73 /* Add the character size to the result size. */
30.74 - resultsize += nextpos(s, _data->size, lastbyte) - lastbyte;
30.75 + resultsize += nextpos(s, ss, lastbyte) - lastbyte;
30.76
30.77 for (d = c; d < c + istep; d++)
30.78 - lastbyte = nextpos(s, _data->size, lastbyte);
30.79 + lastbyte = nextpos(s, ss, lastbyte);
30.80 }
30.81 }
30.82 else
30.83 {
30.84 /* Get the first byte position. */
30.85 for (c = 0; c < istart; c++)
30.86 - lastbyte = nextpos(s, _data->size, lastbyte);
30.87 + lastbyte = nextpos(s, ss, lastbyte);
30.88
30.89 /* Get each subsequent byte position. */
30.90 for (c = istart, i = 0; i < nchar; c += istep, i++)
30.91 @@ -170,7 +179,7 @@
30.92 indexes[i] = lastbyte;
30.93
30.94 /* Add the character size to the result size. */
30.95 - resultsize += nextpos(s, _data->size, lastbyte) - lastbyte;
30.96 + resultsize += nextpos(s, ss, lastbyte) - lastbyte;
30.97
30.98 for (d = c; d > c + istep; d--)
30.99 lastbyte = prevpos(s, lastbyte);
31.1 --- a/templates/ops.c Mon Feb 20 18:48:39 2017 +0100
31.2 +++ b/templates/ops.c Fri Feb 24 13:27:44 2017 +0100
31.3 @@ -21,14 +21,22 @@
31.4 #include "progops.h" /* for raising errors */
31.5 #include "progconsts.h"
31.6 #include "progtypes.h"
31.7 -#include <stdio.h>
31.8
31.9 /* Direct access and manipulation of static objects. */
31.10
31.11 -__attr __load_static(__ref parent, __ref obj)
31.12 +__attr __load_static_ignore(__ref obj)
31.13 +{
31.14 + return (__attr) {.value=obj};
31.15 +}
31.16 +
31.17 +__attr __load_static_replace(__ref context, __ref obj)
31.18 {
31.19 - __attr out = {.context=parent, .value=obj};
31.20 - return out;
31.21 + return __update_context(context, (__attr) {.value=obj});
31.22 +}
31.23 +
31.24 +__attr __load_static_test(__ref context, __ref obj)
31.25 +{
31.26 + return __test_context(context, (__attr) {.value=obj});
31.27 }
31.28
31.29 /* Direct retrieval operations, returning and setting attributes. */
31.30 @@ -190,77 +198,122 @@
31.31
31.32 /* Context-related operations. */
31.33
31.34 -__attr __test_context(__ref context, __attr attr)
31.35 +int __test_context_update(__ref context, __attr attr)
31.36 {
31.37 + /* Return whether the context should be updated for the attribute. */
31.38 +
31.39 + __ref attrcontext = __CONTEXT_AS_VALUE(attr).value;
31.40 +
31.41 /* Preserve any existing null or instance context. */
31.42
31.43 - if ((attr.context == 0) || __is_instance(attr.context))
31.44 - return attr;
31.45 + if ((attrcontext == 0) || __is_instance(attrcontext))
31.46 + return 0;
31.47
31.48 /* Test any instance context against the context employed by the
31.49 attribute. */
31.50
31.51 if (__is_instance(context))
31.52 {
31.53 - if (__test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context)))
31.54 - return __update_context(context, attr);
31.55 + /* Obtain the special class attribute position and code identifying the
31.56 + attribute context's class, inspecting the context instance for
31.57 + compatibility. */
31.58 +
31.59 + if (__test_common_instance(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext)))
31.60 + return 1;
31.61 else
31.62 __raise_type_error();
31.63 }
31.64
31.65 /* Test for access to a type class attribute using a type instance. */
31.66
31.67 - if (__test_specific_type(attr.context, &__TYPE_CLASS_TYPE) && __is_type_instance(context))
31.68 - return __update_context(context, attr);
31.69 + if (__test_specific_type(attrcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context))
31.70 + return 1;
31.71
31.72 /* Otherwise, preserve the attribute as retrieved. */
31.73
31.74 - return attr;
31.75 + return 0;
31.76 +}
31.77 +
31.78 +__attr __test_context(__ref context, __attr attr)
31.79 +{
31.80 + /* Update the context or return the unchanged attribute. */
31.81 +
31.82 + if (__test_context_update(context, attr))
31.83 + return __update_context(context, attr);
31.84 + else
31.85 + return attr;
31.86 }
31.87
31.88 __attr __update_context(__ref context, __attr attr)
31.89 {
31.90 - __attr out = {.context=context, .value=attr.value};
31.91 - return out;
31.92 + return __new_wrapper(context, attr);
31.93 +}
31.94 +
31.95 +__attr __test_context_revert(int target, __ref context, __attr attr, __ref contexts[])
31.96 +{
31.97 + /* Revert the local context to that employed by the attribute if the
31.98 + supplied context is not appropriate. */
31.99 +
31.100 + if (!__test_context_update(context, attr))
31.101 + contexts[target] = __CONTEXT_AS_VALUE(attr).value;
31.102 + return attr;
31.103 +}
31.104 +
31.105 +__attr __test_context_static(int target, __ref context, __ref value, __ref contexts[])
31.106 +{
31.107 + /* Set the local context to the specified context if appropriate. */
31.108 +
31.109 + if (__test_context_update(context, (__attr) {.value=value}))
31.110 + contexts[target] = context;
31.111 + return (__attr) {.value=value};
31.112 }
31.113
31.114 /* Context testing for invocations. */
31.115
31.116 -int __type_method_invocation(__attr attr)
31.117 +int __type_method_invocation(__ref context, __attr target)
31.118 {
31.119 - __attr parent;
31.120 + __ref targetcontext = __CONTEXT_AS_VALUE(target).value;
31.121
31.122 /* Require instances, not classes, where methods are function instances. */
31.123
31.124 - if (!__is_instance(attr.value))
31.125 + if (!__is_instance(target.value))
31.126 return 0;
31.127
31.128 - /* Access the parent of the callable and test if it is the type object. */
31.129 + /* Access the context of the callable and test if it is the type object. */
31.130
31.131 - parent = __check_and_load_via_object_null(attr.value, __ATTRPOS(__parent__), __ATTRCODE(__parent__));
31.132 - return ((parent.value != 0) && __test_specific_type(parent.value, &__TYPE_CLASS_TYPE) && __is_type_instance(attr.context));
31.133 + return ((targetcontext != 0) && __test_specific_type(targetcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context));
31.134 }
31.135
31.136 -__attr (*__get_function(__attr attr))(__attr[])
31.137 +__attr __unwrap_callable(__attr callable)
31.138 {
31.139 + __attr value = __check_and_load_via_object_null(callable.value, __ATTRPOS(__value__), __ATTRCODE(__value__));
31.140 + return value.value ? value : callable;
31.141 +}
31.142 +
31.143 +__attr (*__get_function(__ref context, __attr target))(__attr[])
31.144 +{
31.145 + target = __unwrap_callable(target);
31.146 +
31.147 /* Require null or instance contexts for functions and methods respectively,
31.148 or type instance contexts for type methods. */
31.149
31.150 - if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr))
31.151 - return __load_via_object(attr.value, __ATTRPOS(__fn__)).fn;
31.152 + if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))
31.153 + return __load_via_object(target.value, __ATTRPOS(__fn__)).fn;
31.154 else
31.155 - return __load_via_object(attr.value, __ATTRPOS(__fn__)).inv;
31.156 + return __unbound_method;
31.157 }
31.158
31.159 -__attr (*__check_and_get_function(__attr attr))(__attr[])
31.160 +__attr (*__check_and_get_function(__ref context, __attr target))(__attr[])
31.161 {
31.162 + target = __unwrap_callable(target);
31.163 +
31.164 /* Require null or instance contexts for functions and methods respectively,
31.165 or type instance contexts for type methods. */
31.166
31.167 - if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr))
31.168 - return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;
31.169 + if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))
31.170 + return __check_and_load_via_object(target.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;
31.171 else
31.172 - return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).inv;
31.173 + return __unbound_method;
31.174 }
31.175
31.176 /* Basic structure tests. */
31.177 @@ -295,10 +348,7 @@
31.178
31.179 __attr __CONTEXT_AS_VALUE(__attr attr)
31.180 {
31.181 - __attr out;
31.182 - out.context = attr.context;
31.183 - out.value = attr.context;
31.184 - return out;
31.185 + return __check_and_load_via_object_null(attr.value, __ATTRPOS(__context__), __ATTRCODE(__context__));
31.186 }
31.187
31.188 /* Type testing. */
31.189 @@ -310,7 +360,6 @@
31.190
31.191 int __ISNULL(__attr value)
31.192 {
31.193 - /* (value.context == __NULL.context) is superfluous */
31.194 return (value.value == 0); /* __NULL.value */
31.195 }
31.196
32.1 --- a/templates/ops.h Mon Feb 20 18:48:39 2017 +0100
32.2 +++ b/templates/ops.h Fri Feb 24 13:27:44 2017 +0100
32.3 @@ -24,7 +24,9 @@
32.4
32.5 /* Direct access and manipulation of static objects. */
32.6
32.7 -__attr __load_static(__ref parent, __ref obj);
32.8 +__attr __load_static_ignore(__ref obj);
32.9 +__attr __load_static_replace(__ref context, __ref obj);
32.10 +__attr __load_static_test(__ref context, __ref obj);
32.11
32.12 /* Direct retrieval operations, returning attributes. */
32.13
32.14 @@ -68,17 +70,23 @@
32.15
32.16 /* Context-related operations. */
32.17
32.18 +int __test_context_update(__ref context, __attr attr);
32.19 __attr __test_context(__ref context, __attr attr);
32.20 __attr __update_context(__ref context, __attr attr);
32.21 +__attr __test_context_revert(int target, __ref context, __attr attr, __ref contexts[]);
32.22 +__attr __test_context_static(int target, __ref context, __ref value, __ref contexts[]);
32.23
32.24 -#define __set_context(__ATTR) (__tmp_context = (__ATTR).value)
32.25 +#define __get_context(__TARGET) (__tmp_contexts[__TARGET])
32.26 +#define __set_context(__TARGET, __ATTR) (__tmp_contexts[__TARGET] = (__ATTR).value)
32.27 +#define __set_private_context(__ATTR) (__tmp_private_context = (__ATTR).value)
32.28 #define __set_accessor(__ATTR) (__tmp_value = (__ATTR).value)
32.29 #define __set_target_accessor(__ATTR) (__tmp_target_value = (__ATTR).value)
32.30
32.31 /* Context testing for invocations. */
32.32
32.33 -__attr (*__get_function(__attr attr))(__attr[]);
32.34 -__attr (*__check_and_get_function(__attr attr))(__attr[]);
32.35 +__attr __unwrap_callable(__attr callable);
32.36 +__attr (*__get_function(__ref context, __attr target))(__attr[]);
32.37 +__attr (*__check_and_get_function(__ref context, __attr target))(__attr[]);
32.38
32.39 /* Basic structure tests. */
32.40
33.1 --- a/templates/progops.c Mon Feb 20 18:48:39 2017 +0100
33.2 +++ b/templates/progops.c Fri Feb 24 13:27:44 2017 +0100
33.3 @@ -30,11 +30,14 @@
33.4 __attr __new(const __table * table, __ref cls, size_t size)
33.5 {
33.6 __ref obj = (__ref) __ALLOCATE(1, size);
33.7 - __attr self = {.context=obj, .value=obj};
33.8 - __attr tmp = {.context=0, .value=cls};
33.9 obj->table = table;
33.10 - __store_via_object(obj, __pos___class__, tmp);
33.11 - return self;
33.12 + __store_via_object(obj, __ATTRPOS(__class__), (__attr) {.value=cls});
33.13 + return (__attr) {.value=obj};
33.14 +}
33.15 +
33.16 +__attr __new_wrapper(__ref context, __attr attr)
33.17 +{
33.18 + return __new___builtins___core_wrapper((__attr[]) {__NULL, {.value=context}, attr});
33.19 }
33.20
33.21 /* Generic internal data allocation. */
33.22 @@ -57,7 +60,7 @@
33.23 /* Calculate the size of the fragment. */
33.24
33.25 __fragment *data = __new_fragment(number);
33.26 - __attr attr = {{.size=0, .seqvalue=data}};
33.27 + __attr attr = {.seqvalue=data};
33.28 unsigned int i, j;
33.29
33.30 /* Copy the given number of values, starting from the second element. */
33.31 @@ -69,7 +72,7 @@
33.32
33.33 /* Store a reference to the data in the object's __data__ attribute. */
33.34
33.35 - __store_via_object(args[0].value, __pos___data__, attr);
33.36 + __store_via_object(args[0].value, __ATTRPOS(__data__), attr);
33.37 }
33.38
33.39 #ifdef __HAVE___builtins___dict_dict
33.40 @@ -155,7 +158,7 @@
33.41 {
33.42 /* Reserve space for the instance. */
33.43
33.44 - __attr args[1];
33.45 + __attr args[1] = {__NULL};
33.46
33.47 /* Return instances as provided. */
33.48
33.49 @@ -181,14 +184,15 @@
33.50 unsigned int nkwargs, __param kwcodes[], __attr kwargs[],
33.51 unsigned int nargs, __attr args[])
33.52 {
33.53 - /* Obtain the __args__ special member, referencing the parameter table. */
33.54 + /* Unwrap any wrapped function. */
33.55
33.56 - __attr minparams = __check_and_load_via_object(callable.value, __pos___args__, __code___args__);
33.57 + __attr target = __unwrap_callable(callable);
33.58
33.59 + /* Obtain the __args__ special member, referencing the parameter table. */
33.60 /* Refer to the table and minimum/maximum. */
33.61
33.62 - const __ptable *ptable = minparams.ptable;
33.63 - const unsigned int min = minparams.min, max = ptable->size;
33.64 + const __ptable *ptable = __check_and_load_via_object(target.value, __ATTRPOS(__args__), __ATTRCODE(__args__)).ptable;
33.65 + const unsigned int min = ptable->min, max = ptable->max;
33.66
33.67 /* Reserve enough space for the arguments. */
33.68
33.69 @@ -240,12 +244,12 @@
33.70 for (pos = nargs; pos < max; pos++)
33.71 {
33.72 if (allargs[pos].value == 0)
33.73 - allargs[pos] = __GETDEFAULT(callable.value, pos - min);
33.74 + allargs[pos] = __GETDEFAULT(target.value, pos - min);
33.75 }
33.76
33.77 /* Call with the prepared arguments. */
33.78
33.79 - return (always_callable ? __get_function(callable) : __check_and_get_function(callable))(allargs);
33.80 + return (always_callable ? __get_function(allargs[0].value, target) : __check_and_get_function(allargs[0].value, target))(allargs);
33.81 }
33.82
33.83 /* Error routines. */
34.1 --- a/templates/progops.h Mon Feb 20 18:48:39 2017 +0100
34.2 +++ b/templates/progops.h Fri Feb 24 13:27:44 2017 +0100
34.3 @@ -1,6 +1,6 @@
34.4 /* Operations depending on program specifics.
34.5
34.6 -Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
34.7 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
34.8
34.9 This program is free software; you can redistribute it and/or modify it under
34.10 the terms of the GNU General Public License as published by the Free Software
34.11 @@ -19,11 +19,13 @@
34.12 #ifndef __PROGOPS_H__
34.13 #define __PROGOPS_H__
34.14
34.15 +#include <stdlib.h> /* size_t */
34.16 #include "types.h"
34.17
34.18 /* Generic instantiation operations, defining common members. */
34.19
34.20 __attr __new(const __table *table, __ref cls, size_t size);
34.21 +__attr __new_wrapper(__ref context, __attr attr);
34.22
34.23 /* Generic internal data allocation. */
34.24
35.1 --- a/templates/types.h Mon Feb 20 18:48:39 2017 +0100
35.2 +++ b/templates/types.h Fri Feb 24 13:27:44 2017 +0100
35.3 @@ -19,15 +19,15 @@
35.4 #ifndef __TYPES_H__
35.5 #define __TYPES_H__
35.6
35.7 -#include <stddef.h> /* size_t */
35.8 -
35.9 /* Define code and position types, populated by enum values defined for each
35.10 program specifically. */
35.11
35.12 -typedef unsigned short __code;
35.13 -typedef unsigned short __pos;
35.14 -typedef unsigned short __pcode;
35.15 -typedef unsigned short __ppos;
35.16 +#include <stdint.h>
35.17 +
35.18 +typedef uint16_t __code;
35.19 +typedef uint16_t __pos;
35.20 +typedef uint16_t __pcode;
35.21 +typedef uint16_t __ppos;
35.22
35.23 /* Attribute tables are lists of codes confirming the presence of attributes. */
35.24
35.25 @@ -49,51 +49,34 @@
35.26
35.27 typedef struct __ptable
35.28 {
35.29 - const __ppos size;
35.30 + const __ppos min, max, size;
35.31 const __param params[];
35.32 } __ptable;
35.33
35.34 -/* Attributes are context and value pairs.
35.35 +/* Attributes are values referring to objects or encoding other information.
35.36 Objects are collections of attributes.
35.37 Object references are references to tables and collections of attributes.
35.38 Attribute references are references to single attributes. */
35.39
35.40 typedef struct __obj __obj;
35.41 typedef struct __fragment __fragment;
35.42 +typedef union __attr __attr;
35.43 +typedef __obj * __ref;
35.44
35.45 -typedef struct __attr
35.46 +typedef union __attr
35.47 {
35.48 - /* One of... */
35.49 - union
35.50 - {
35.51 - struct {
35.52 - __obj * context; /* attribute context */
35.53 - __obj * value; /* attribute value */
35.54 - };
35.55 - struct {
35.56 - __ppos min; /* minimum number of parameters */
35.57 - const __ptable * ptable; /* parameter table */
35.58 - };
35.59 - struct {
35.60 - __pcode code; /* parameter table code for key */
35.61 - __ppos pos; /* parameter table position for key */
35.62 - };
35.63 - struct {
35.64 - struct __attr (*inv)(); /* unbound callable details */
35.65 - struct __attr (*fn)(); /* callable details */
35.66 - };
35.67 - struct {
35.68 - size_t size; /* size of value */
35.69 - union
35.70 - {
35.71 - int intvalue; /* integer value */
35.72 - double floatvalue; /* floating point value */
35.73 - char * strvalue; /* string value */
35.74 - __fragment * seqvalue; /* sequence data */
35.75 - void * datavalue; /* object-specific data */
35.76 - };
35.77 - };
35.78 + __ref value; /* attribute value */
35.79 + const __ptable * ptable; /* parameter table */
35.80 + struct {
35.81 + __pcode code; /* parameter table code for key */
35.82 + __ppos pos; /* parameter table position for key */
35.83 };
35.84 + __attr (*fn)(); /* callable details */
35.85 + int intvalue; /* integer value */
35.86 + float floatvalue; /* floating point value */
35.87 + char * strvalue; /* string value */
35.88 + __fragment * seqvalue; /* sequence data */
35.89 + void * datavalue; /* object-specific data */
35.90 } __attr;
35.91
35.92 typedef struct __obj
35.93 @@ -103,7 +86,7 @@
35.94 __attr attrs[]; /* attributes */
35.95 } __obj;
35.96
35.97 -typedef __obj * __ref;
35.98 +#define __INSTANCE_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + sizeof(__table *) + sizeof(__ppos))
35.99
35.100 /* Fragments are simple collections of attributes employed by sequence types.
35.101 They provide the basis of lists and tuples. */
35.102 @@ -114,7 +97,7 @@
35.103 __attr attrs[];
35.104 } __fragment;
35.105
35.106 -#define __FRAGMENT_SIZE(NUMBER) (NUMBER * sizeof(__attr) + 2 * sizeof(unsigned int))
35.107 +#define __FRAGMENT_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + 2 * sizeof(unsigned int))
35.108
35.109 /* Special instance position value. The pos member of __obj refers to the
35.110 special type attribute for classes, indicating which position holds the
35.111 @@ -124,7 +107,7 @@
35.112
35.113 /* Special null values. */
35.114
35.115 -#define __NULL ((__attr) {{.context=0, .value=0}})
35.116 +#define __NULL ((__attr) {.value=0})
35.117
35.118 /* Function pointer type. */
35.119
36.1 --- a/test_all.sh Mon Feb 20 18:48:39 2017 +0100
36.2 +++ b/test_all.sh Fri Feb 24 13:27:44 2017 +0100
36.3 @@ -3,7 +3,7 @@
36.4 # This tool runs the toolchain for each of the tests, optionally building and
36.5 # running the test programs.
36.6 #
36.7 -# Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
36.8 +# Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
36.9 #
36.10 # This program is free software; you can redistribute it and/or modify it under
36.11 # the terms of the GNU General Public License as published by the Free Software
36.12 @@ -22,7 +22,7 @@
36.13 OPTION=$1
36.14
36.15 LPLC="./lplc"
36.16 -DATADIR="_lplc"
36.17 +DATADIR="_main.lplc"
36.18 TESTINPUT="_results/testinput.txt"
36.19
36.20 # Expect failure from the "bad" tests.
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/tests/nested_calls.py Fri Feb 24 13:27:44 2017 +0100
38.3 @@ -0,0 +1,15 @@
38.4 +class C:
38.5 + def __init__(self, x):
38.6 + self.x = x
38.7 +
38.8 + def value(self):
38.9 + return self.x
38.10 +
38.11 + def length(self):
38.12 + return self.double(self.value())
38.13 +
38.14 + def double(self, x):
38.15 + return x * 2
38.16 +
38.17 +c = C(3)
38.18 +print c.length() # 6
39.1 --- a/translator.py Mon Feb 20 18:48:39 2017 +0100
39.2 +++ b/translator.py Fri Feb 24 13:27:44 2017 +0100
39.3 @@ -20,7 +20,8 @@
39.4 """
39.5
39.6 from common import CommonModule, CommonOutput, InstructionSequence, \
39.7 - first, get_builtin_class, init_item, predefined_constants
39.8 + first, get_builtin_class, init_item, is_newer, \
39.9 + predefined_constants
39.10 from encoders import encode_access_instruction, \
39.11 encode_function_pointer, encode_literal_constant, \
39.12 encode_literal_instantiator, encode_instantiator_pointer, \
39.13 @@ -45,22 +46,33 @@
39.14 self.deducer = deducer
39.15 self.optimiser = optimiser
39.16 self.output = output
39.17 - self.modules = {}
39.18
39.19 def to_output(self):
39.20 +
39.21 + "Write a program to the configured output directory."
39.22 +
39.23 + # Make a directory for the final sources.
39.24 +
39.25 output = join(self.output, "src")
39.26
39.27 if not exists(output):
39.28 makedirs(output)
39.29
39.30 + # Clean the output directory of irrelevant data.
39.31 +
39.32 self.check_output()
39.33
39.34 for module in self.importer.modules.values():
39.35 + output_filename = join(output, "%s.c" % module.name)
39.36 +
39.37 + # Do not generate modules in the native package. They are provided
39.38 + # by native functionality source files.
39.39 +
39.40 parts = module.name.split(".")
39.41 - if parts[0] != "native":
39.42 +
39.43 + if parts[0] != "native" and is_newer(module.filename, output_filename):
39.44 tm = TranslatedModule(module.name, self.importer, self.deducer, self.optimiser)
39.45 - tm.translate(module.filename, join(output, "%s.c" % module.name))
39.46 - self.modules[module.name] = tm
39.47 + tm.translate(module.filename, output_filename)
39.48
39.49 # Classes representing intermediate translation results.
39.50
39.51 @@ -142,7 +154,7 @@
39.52 elif static_name:
39.53 parent = ref.parent()
39.54 context = ref.has_kind("<function>") and encode_path(parent) or None
39.55 - return "((__attr) {{.context=%s, .value=&%s}})" % (context and "&%s" % context or "0", static_name)
39.56 + return "((__attr) {.value=&%s})" % static_name
39.57
39.58 # Qualified names must be converted into parent-relative accesses.
39.59
39.60 @@ -331,6 +343,10 @@
39.61
39.62 self.temp_usage = {}
39.63
39.64 + # Initialise some data used for attribute access generation.
39.65 +
39.66 + self.init_substitutions()
39.67 +
39.68 def __repr__(self):
39.69 return "TranslatedModule(%r, %r)" % (self.name, self.importer)
39.70
39.71 @@ -738,42 +754,71 @@
39.72 "<assexpr>" : self.in_assignment,
39.73 }
39.74
39.75 - temp_subs = {
39.76 - "<context>" : "__tmp_context",
39.77 - "<accessor>" : "__tmp_value",
39.78 - "<target_accessor>" : "__tmp_target_value",
39.79 - "<set_accessor>" : "__tmp_value",
39.80 - "<set_target_accessor>" : "__tmp_target_value",
39.81 - }
39.82 -
39.83 - op_subs = {
39.84 - "<set_accessor>" : "__set_accessor",
39.85 - "<set_target_accessor>" : "__set_target_accessor",
39.86 - }
39.87 -
39.88 - subs.update(temp_subs)
39.89 - subs.update(op_subs)
39.90 + subs.update(self.temp_subs)
39.91 + subs.update(self.op_subs)
39.92
39.93 output = []
39.94 substituted = set()
39.95
39.96 + # The context set or retrieved will be that used by any enclosing
39.97 + # invocation.
39.98 +
39.99 + context_index = self.function_target - 1
39.100 +
39.101 # Obtain encoded versions of each instruction, accumulating temporary
39.102 # variables.
39.103
39.104 for instruction in self.optimiser.access_instructions[location]:
39.105 - encoded, _substituted = encode_access_instruction(instruction, subs)
39.106 + encoded, _substituted = encode_access_instruction(instruction, subs, context_index)
39.107 output.append(encoded)
39.108 substituted.update(_substituted)
39.109
39.110 # Record temporary name usage.
39.111
39.112 for sub in substituted:
39.113 - if temp_subs.has_key(sub):
39.114 - self.record_temp(temp_subs[sub])
39.115 + if self.temp_subs.has_key(sub):
39.116 + self.record_temp(self.temp_subs[sub])
39.117
39.118 del self.attrs[0]
39.119 return AttrResult(output, refs, location)
39.120
39.121 + def init_substitutions(self):
39.122 +
39.123 + """
39.124 + Initialise substitutions, defining temporary variable mappings, some of
39.125 + which are also used as substitutions, together with operation mappings
39.126 + used as substitutions in instructions defined by the optimiser.
39.127 + """
39.128 +
39.129 + self.temp_subs = {
39.130 +
39.131 + # Substitutions used by instructions.
39.132 +
39.133 + "<private_context>" : "__tmp_private_context",
39.134 + "<accessor>" : "__tmp_value",
39.135 + "<target_accessor>" : "__tmp_target_value",
39.136 +
39.137 + # Mappings to be replaced by those given below.
39.138 +
39.139 + "<context>" : "__tmp_contexts",
39.140 + "<test_context_revert>" : "__tmp_contexts",
39.141 + "<test_context_static>" : "__tmp_contexts",
39.142 + "<set_context>" : "__tmp_contexts",
39.143 + "<set_private_context>" : "__tmp_private_context",
39.144 + "<set_accessor>" : "__tmp_value",
39.145 + "<set_target_accessor>" : "__tmp_target_value",
39.146 + }
39.147 +
39.148 + self.op_subs = {
39.149 + "<context>" : "__get_context",
39.150 + "<test_context_revert>" : "__test_context_revert",
39.151 + "<test_context_static>" : "__test_context_static",
39.152 + "<set_context>" : "__set_context",
39.153 + "<set_private_context>" : "__set_private_context",
39.154 + "<set_accessor>" : "__set_accessor",
39.155 + "<set_target_accessor>" : "__set_target_accessor",
39.156 + }
39.157 +
39.158 def get_referenced_attributes(self, location):
39.159
39.160 """
39.161 @@ -875,7 +920,7 @@
39.162
39.163 if not ref.static():
39.164 self.process_assignment_for_object(
39.165 - n.name, make_expression("((__attr) {{.context=0, .value=&%s}})" %
39.166 + n.name, make_expression("((__attr) {.value=&%s})" %
39.167 encode_path(class_name)))
39.168
39.169 self.enter_namespace(n.name)
39.170 @@ -1054,9 +1099,7 @@
39.171 context = self.is_method(objpath)
39.172
39.173 self.process_assignment_for_object(original_name,
39.174 - make_expression("((__attr) {{.context=%s, .value=&%s}})" % (
39.175 - context and "&%s" % encode_path(context) or "0",
39.176 - encode_path(objpath))))
39.177 + make_expression("((__attr) {.value=&%s})" % encode_path(objpath)))
39.178
39.179 def process_function_defaults(self, n, name, objpath, instance_name=None):
39.180
39.181 @@ -1146,7 +1189,21 @@
39.182
39.183 "Process the given invocation node 'n'."
39.184
39.185 + # Any invocations in the expression will store target details in a
39.186 + # different location.
39.187 +
39.188 + self.function_target += 1
39.189 +
39.190 + # Process the expression.
39.191 +
39.192 expr = self.process_structure_node(n.node)
39.193 +
39.194 + # Reference the current target again.
39.195 +
39.196 + self.function_target -= 1
39.197 +
39.198 + # Obtain details of the invocation expression.
39.199 +
39.200 objpath = expr.get_origin()
39.201 location = expr.access_location()
39.202
39.203 @@ -1167,6 +1224,7 @@
39.204 # Invocation requirements.
39.205
39.206 context_required = True
39.207 + have_access_context = isinstance(expr, AttrResult)
39.208 parameters = None
39.209
39.210 # Obtain details of the callable and of its parameters.
39.211 @@ -1237,8 +1295,12 @@
39.212 # set to null.
39.213
39.214 if context_required:
39.215 - self.record_temp("__tmp_targets")
39.216 - args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target]
39.217 + if have_access_context:
39.218 + self.record_temp("__tmp_contexts")
39.219 + args = ["(__attr) {.value=__tmp_contexts[%d]}" % self.function_target]
39.220 + else:
39.221 + self.record_temp("__tmp_targets")
39.222 + args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target]
39.223 else:
39.224 args = ["__NULL"]
39.225
39.226 @@ -1335,8 +1397,11 @@
39.227 # Without a known specific callable, the expression provides the target.
39.228
39.229 if not target or context_required:
39.230 - self.record_temp("__tmp_targets")
39.231 - stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr))
39.232 + if target:
39.233 + stages.append(str(expr))
39.234 + else:
39.235 + self.record_temp("__tmp_targets")
39.236 + stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr))
39.237
39.238 # Any specific callable is then obtained.
39.239
39.240 @@ -1349,7 +1414,13 @@
39.241 self.record_temp("__tmp_targets")
39.242
39.243 if context_required:
39.244 - stages.append("__get_function(__tmp_targets[%d])" % self.function_target)
39.245 + if have_access_context:
39.246 + self.record_temp("__tmp_contexts")
39.247 + stages.append("__get_function(__tmp_contexts[%d], __tmp_targets[%d])" % (
39.248 + self.function_target, self.function_target))
39.249 + else:
39.250 + stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % (
39.251 + self.function_target, self.function_target))
39.252 else:
39.253 stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % (
39.254 self.function_target, encode_symbol("pos", "__fn__")))
39.255 @@ -1414,14 +1485,14 @@
39.256 # Without defaults, produce an attribute referring to the function.
39.257
39.258 if not defaults:
39.259 - return make_expression("((__attr) {{.context=0, .value=&%s}})" % encode_path(function_name))
39.260 + return make_expression("((__attr) {.value=&%s})" % encode_path(function_name))
39.261
39.262 # With defaults, copy the function structure and set the defaults on the
39.263 # copy.
39.264
39.265 else:
39.266 self.record_temp("__tmp_value")
39.267 - return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {{.context=0, .value=__tmp_value}})" % (
39.268 + return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {.value=__tmp_value})" % (
39.269 encode_path(function_name),
39.270 encode_symbol("obj", function_name),
39.271 ", ".join(defaults)))
39.272 @@ -1914,14 +1985,17 @@
39.273
39.274 # Provide space for the given number of targets.
39.275
39.276 + targets = self.importer.function_targets.get(name)
39.277 +
39.278 if self.uses_temp(name, "__tmp_targets"):
39.279 - targets = self.importer.function_targets.get(name)
39.280 self.writeline("__attr __tmp_targets[%d];" % targets)
39.281 + if self.uses_temp(name, "__tmp_contexts"):
39.282 + self.writeline("__ref __tmp_contexts[%d];" % targets)
39.283
39.284 # Add temporary variable usage details.
39.285
39.286 - if self.uses_temp(name, "__tmp_context"):
39.287 - self.writeline("__ref __tmp_context;")
39.288 + if self.uses_temp(name, "__tmp_private_context"):
39.289 + self.writeline("__ref __tmp_private_context;")
39.290 if self.uses_temp(name, "__tmp_value"):
39.291 self.writeline("__ref __tmp_value;")
39.292 if self.uses_temp(name, "__tmp_target_value"):