1.1 --- a/branching.py Mon Feb 13 21:40:34 2017 +0100
1.2 +++ b/branching.py Fri Feb 24 13:27:07 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 13 21:40:34 2017 +0100
2.2 +++ b/common.py Fri Feb 24 13:27:07 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."
2.49 @@ -741,14 +771,16 @@
2.50
2.51 return isinstance(node.expr, compiler.ast.Getattr)
2.52
2.53 - def get_name_for_tracking(self, name, path=None):
2.54 + def get_name_for_tracking(self, name, name_ref=None):
2.55
2.56 """
2.57 Return the name to be used for attribute usage observations involving
2.58 - the given 'name' in the current namespace. If 'path' is indicated and
2.59 - the name is being used outside a function, return the path value;
2.60 - otherwise, return a path computed using the current namespace and the
2.61 - given name.
2.62 + the given 'name' in the current namespace.
2.63 +
2.64 + If the name is being used outside a function, and if 'name_ref' is
2.65 + given, a path featuring the name in the global namespace is returned
2.66 + where 'name_ref' indicates a global. Otherwise, a path computed using
2.67 + the current namespace and the given name is returned.
2.68
2.69 The intention of this method is to provide a suitably-qualified name
2.70 that can be tracked across namespaces. Where globals are being
2.71 @@ -766,10 +798,10 @@
2.72 if self.in_function:
2.73 return name
2.74
2.75 - # For static namespaces, use the given qualified name.
2.76 + # For global names outside functions, use a global name.
2.77
2.78 - elif path:
2.79 - return path
2.80 + elif name_ref and name_ref.is_global_name():
2.81 + return self.get_global_path(name)
2.82
2.83 # Otherwise, establish a name in the current namespace.
2.84
3.1 --- a/deducer.py Mon Feb 13 21:40:34 2017 +0100
3.2 +++ b/deducer.py Fri Feb 24 13:27:07 2017 +0100
3.3 @@ -917,9 +917,9 @@
3.4
3.5 # For each version of the name, obtain the access location.
3.6
3.7 - for version, (original_name, attrnames, access_number) in all_aliases.items():
3.8 + for version, (original_path, original_name, attrnames, access_number) in all_aliases.items():
3.9 accessor_location = (path, name, None, version)
3.10 - access_location = (path, original_name, attrnames, access_number)
3.11 + access_location = (original_path, original_name, attrnames, access_number)
3.12 init_item(self.alias_index, accessor_location, list)
3.13 self.alias_index[accessor_location].append(access_location)
3.14
3.15 @@ -2088,7 +2088,9 @@
3.16 # All other methods of access involve traversal.
3.17
3.18 else:
3.19 - final_method = is_assignment and "assign" or "access"
3.20 + final_method = is_assignment and "assign" or \
3.21 + is_invocation and "access-invoke" or \
3.22 + "access"
3.23 origin = None
3.24
3.25 # First attribute accessed at a known position via the accessor.
4.1 --- a/docs/lplc.1 Mon Feb 13 21:40:34 2017 +0100
4.2 +++ b/docs/lplc.1 Fri Feb 24 13:27:07 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 13 21:40:34 2017 +0100
5.2 +++ b/encoders.py Fri Feb 24 13:27:07 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 13 21:40:34 2017 +0100
6.2 +++ b/generator.py Fri Feb 24 13:27:07 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 @@ -517,7 +536,7 @@
6.209 # Employ a special alias that will be tested specifically in
6.210 # encode_member.
6.211
6.212 - encoding_ref = Reference("<instance>", self.string_type, "$c%d" % n)
6.213 + encoding_ref = Reference("<instance>", self.string_type, "$c%s" % n)
6.214
6.215 # Use None where no encoding was indicated.
6.216
6.217 @@ -538,31 +557,34 @@
6.218 # Define a macro for the constant.
6.219
6.220 attr_name = encode_path(const_path)
6.221 - print >>f_decls, "#define %s ((__attr) {{.context=&%s, .value=&%s}})" % (attr_name, structure_name, structure_name)
6.222 + print >>f_decls, "#define %s ((__attr) {.value=&%s})" % (attr_name, structure_name)
6.223
6.224 - def make_parameter_table(self, f_decls, f_defs, parameters):
6.225 + def make_parameter_table(self, f_decls, f_defs, argmin, parameters):
6.226
6.227 """
6.228 Write parameter table details to 'f_decls' (to declare a table) and to
6.229 - 'f_defs' (to define the contents) for the given 'parameters'.
6.230 + 'f_defs' (to define the contents) for the given 'argmin' and
6.231 + 'parameters'.
6.232 """
6.233
6.234 # Use a signature for the table name instead of a separate name for each
6.235 # function.
6.236
6.237 - signature = self.get_parameter_signature(parameters)
6.238 + signature = self.get_parameter_signature(argmin, parameters)
6.239 table_name = encode_tablename("<function>", signature)
6.240 - structure_size = encode_size("pmax", signature)
6.241 + min_parameters = encode_size("pmin", signature)
6.242 + max_parameters = encode_size("pmax", signature)
6.243 + structure_size = encode_size("psize", signature)
6.244
6.245 table = []
6.246 self.populate_parameter_table(parameters, table)
6.247 - self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table)
6.248 + self.write_parameter_table(f_decls, f_defs, table_name, min_parameters, max_parameters, structure_size, table)
6.249
6.250 - def get_parameter_signature(self, parameters):
6.251 + def get_parameter_signature(self, argmin, parameters):
6.252
6.253 - "Return a signature for the given 'parameters'."
6.254 + "Return a signature for the given 'argmin' and 'parameters'."
6.255
6.256 - l = []
6.257 + l = [str(argmin)]
6.258 for parameter in parameters:
6.259 if parameter is None:
6.260 l.append("")
6.261 @@ -576,8 +598,9 @@
6.262 "Return the signature for the callable with the given 'path'."
6.263
6.264 function_path = self.callables[path]
6.265 + argmin, argmax = self.get_argument_limits(function_path)
6.266 parameters = self.optimiser.parameters[function_path]
6.267 - return self.get_parameter_signature(parameters)
6.268 + return self.get_parameter_signature(argmin, parameters)
6.269
6.270 def write_size_constants(self, f_consts, size_prefix, sizes, padding):
6.271
6.272 @@ -644,19 +667,22 @@
6.273 %s
6.274 }
6.275 };
6.276 -""" % (table_name, structure_size, ",\n ".join(table))
6.277 +""" % (table_name, structure_size,
6.278 + ",\n ".join(table))
6.279
6.280 - def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table):
6.281 + def write_parameter_table(self, f_decls, f_defs, table_name, min_parameters,
6.282 + max_parameters, structure_size, table):
6.283
6.284 """
6.285 Write the declarations to 'f_decls' and definitions to 'f_defs' for
6.286 - the object having the given 'table_name' and the given 'structure_size',
6.287 - with 'table' details used to populate the definition.
6.288 + the object having the given 'table_name' and the given 'min_parameters',
6.289 + 'max_parameters' and 'structure_size', with 'table' details used to
6.290 + populate the definition.
6.291 """
6.292
6.293 members = []
6.294 for t in table:
6.295 - members.append("{%s, %s}" % t)
6.296 + members.append("{.code=%s, .pos=%s}" % t)
6.297
6.298 print >>f_decls, "extern const __ptable %s;\n" % table_name
6.299
6.300 @@ -664,12 +690,15 @@
6.301
6.302 print >>f_defs, """\
6.303 const __ptable %s = {
6.304 - %s,
6.305 + .min=%s,
6.306 + .max=%s,
6.307 + .size=%s,
6.308 {
6.309 %s
6.310 }
6.311 };
6.312 -""" % (table_name, structure_size, ",\n ".join(members))
6.313 +""" % (table_name, min_parameters, max_parameters, structure_size,
6.314 + ",\n ".join(members))
6.315
6.316 def write_instance_structure(self, f_decls, path, structure_size):
6.317
6.318 @@ -879,16 +908,10 @@
6.319
6.320 if kind == "<class>":
6.321 attr = encode_instantiator_pointer(attr)
6.322 - unbound_attr = attr
6.323 -
6.324 - # Provide bound method and unbound function pointers if
6.325 - # populating methods in a class.
6.326 -
6.327 else:
6.328 attr = encode_function_pointer(attr)
6.329 - unbound_attr = "__unbound_method"
6.330
6.331 - structure.append("{{.inv=%s, .fn=%s}}" % (unbound_attr, attr))
6.332 + structure.append("{.fn=%s}" % attr)
6.333 continue
6.334
6.335 # Special argument specification member.
6.336 @@ -897,7 +920,7 @@
6.337 signature = self.get_signature_for_callable(ref.get_origin())
6.338 ptable = encode_tablename("<function>", signature)
6.339
6.340 - structure.append("{{.min=%s, .ptable=&%s}}" % (attr, ptable))
6.341 + structure.append("{.ptable=&%s}" % ptable)
6.342 continue
6.343
6.344 # Special internal data member.
6.345 @@ -917,8 +940,8 @@
6.346 # Special internal key member.
6.347
6.348 elif attrname == "__key__":
6.349 - structure.append("{{.code=%s, .pos=%s}}" % (attr and encode_symbol("code", attr) or "0",
6.350 - attr and encode_symbol("pos", attr) or "0"))
6.351 + structure.append("{.code=%s, .pos=%s}" % (attr and encode_symbol("code", attr) or "0",
6.352 + attr and encode_symbol("pos", attr) or "0"))
6.353 continue
6.354
6.355 # Special cases.
6.356 @@ -950,7 +973,7 @@
6.357 constant_name = "$c%d" % local_number
6.358 attr_path = "%s.%s" % (path, constant_name)
6.359 constant_number = self.optimiser.constant_numbers[attr_path]
6.360 - constant_value = "__const%d" % constant_number
6.361 + constant_value = "__const%s" % constant_number
6.362 structure.append("%s /* %s */" % (constant_value, attrname))
6.363 continue
6.364
6.365 @@ -961,13 +984,33 @@
6.366 # object paths.
6.367
6.368 value = path.rsplit(".", 1)[0]
6.369 - structure.append("{{.context=0, .value=&%s}}" % encode_path(value))
6.370 + structure.append("{.value=&%s}" % encode_path(value))
6.371 + continue
6.372 +
6.373 + # Special context member.
6.374 + # Set the context depending on the kind of attribute.
6.375 + # For methods: <parent>
6.376 + # For other attributes: __NULL
6.377 +
6.378 + elif attrname == "__context__":
6.379 + path = ref.get_origin()
6.380 +
6.381 + # Contexts of methods are derived from their object paths.
6.382 +
6.383 + context = "0"
6.384 +
6.385 + if ref.get_kind() == "<function>":
6.386 + parent = path.rsplit(".", 1)[0]
6.387 + if self.importer.classes.has_key(parent):
6.388 + context = "&%s" % encode_path(parent)
6.389 +
6.390 + structure.append("{.value=%s}" % context)
6.391 continue
6.392
6.393 # Special class relationship attributes.
6.394
6.395 elif is_type_attribute(attrname):
6.396 - structure.append("{{.context=0, .value=&%s}}" % encode_path(decode_type_attribute(attrname)))
6.397 + structure.append("{.value=&%s}" % encode_path(decode_type_attribute(attrname)))
6.398 continue
6.399
6.400 # All other kinds of members.
6.401 @@ -992,7 +1035,7 @@
6.402 # Use the alias directly if appropriate.
6.403
6.404 if alias.startswith("$c"):
6.405 - constant_value = encode_literal_constant(int(alias[2:]))
6.406 + constant_value = encode_literal_constant(alias[2:])
6.407 return "%s /* %s */" % (constant_value, name)
6.408
6.409 # Obtain a constant value directly assigned to the attribute.
6.410 @@ -1006,33 +1049,22 @@
6.411
6.412 if kind == "<instance>" and origin == self.none_type:
6.413 attr_path = encode_predefined_reference(self.none_value)
6.414 - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name)
6.415 + return "{.value=&%s} /* %s */" % (attr_path, name)
6.416
6.417 # Predefined constant members.
6.418
6.419 if (path, name) in self.predefined_constant_members:
6.420 attr_path = encode_predefined_reference("%s.%s" % (path, name))
6.421 - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name)
6.422 + return "{.value=&%s} /* %s */" % (attr_path, name)
6.423
6.424 # General undetermined members.
6.425
6.426 if kind in ("<var>", "<instance>"):
6.427 attr_path = encode_predefined_reference(self.none_value)
6.428 - return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name)
6.429 -
6.430 - # Set the context depending on the kind of attribute.
6.431 - # For methods: {&<parent>, &<attr>}
6.432 - # For other attributes: {&<attr>, &<attr>}
6.433 + return "{.value=&%s} /* %s */" % (attr_path, name)
6.434
6.435 else:
6.436 - if kind == "<function>" and structure_type == "<class>":
6.437 - parent = origin.rsplit(".", 1)[0]
6.438 - context = "&%s" % encode_path(parent)
6.439 - elif kind == "<instance>":
6.440 - context = "&%s" % encode_path(origin)
6.441 - else:
6.442 - context = "0"
6.443 - return "{{.context=%s, .value=&%s}}" % (context, encode_path(origin))
6.444 + return "{.value=&%s}" % encode_path(origin)
6.445
6.446 def append_defaults(self, path, structure):
6.447
6.448 @@ -1140,7 +1172,7 @@
6.449 }
6.450 __Catch(__tmp_exc)
6.451 {
6.452 - if (__ISINSTANCE(__tmp_exc.arg, ((__attr) {{.context=0, .value=&__builtins___exception_system_SystemExit}})))
6.453 + if (__ISINSTANCE(__tmp_exc.arg, ((__attr) {.value=&__builtins___exception_system_SystemExit})))
6.454 return __load_via_object(
6.455 __load_via_object(__tmp_exc.arg.value, %s).value,
6.456 %s).intvalue;
7.1 --- a/inspector.py Mon Feb 13 21:40:34 2017 +0100
7.2 +++ b/inspector.py Fri Feb 24 13:27:07 2017 +0100
7.3 @@ -412,7 +412,7 @@
7.4 # if assigned in the namespace, or using an external name
7.5 # (presently just globals within classes).
7.6
7.7 - name = self.get_name_for_tracking(name_ref.name, name_ref.final())
7.8 + name = self.get_name_for_tracking(name_ref.name, name_ref)
7.9 tracker = self.trackers[-1]
7.10
7.11 immediate_access = len(self.attrs) == 1
7.12 @@ -420,10 +420,7 @@
7.13
7.14 # Record global-based chains for subsequent resolution.
7.15
7.16 - is_global = self.in_function and not self.function_locals[path].has_key(name) or \
7.17 - not self.in_function
7.18 -
7.19 - if is_global:
7.20 + if name_ref.is_global_name():
7.21 self.record_global_access_details(name, attrnames)
7.22
7.23 # Make sure the name is being tracked: global names will not
7.24 @@ -521,14 +518,17 @@
7.25 # class. Function instances provide these attributes.
7.26
7.27 if class_name != "__builtins__.core.function":
7.28 +
7.29 self.set_name("__fn__") # special instantiator attribute
7.30 self.set_name("__args__") # special instantiator attribute
7.31
7.32 - # Provide leafname and parent attributes.
7.33 + # Provide leafname, parent and context attributes.
7.34
7.35 parent, leafname = class_name.rsplit(".", 1)
7.36 self.set_name("__name__", self.get_constant("string", leafname).reference())
7.37 - self.set_name("__parent__")
7.38 +
7.39 + if class_name != "__builtins__.core.function":
7.40 + self.set_name("__parent__")
7.41
7.42 self.process_structure_node(n.code)
7.43 self.exit_namespace()
7.44 @@ -873,12 +873,12 @@
7.45
7.46 ref = self.find_name(n.name)
7.47 if ref:
7.48 - return ResolvedNameRef(n.name, ref)
7.49 + return ResolvedNameRef(n.name, ref, is_global=True)
7.50
7.51 # Explicitly-declared global names.
7.52
7.53 elif self.in_function and n.name in self.scope_globals[path]:
7.54 - return NameRef(n.name)
7.55 + return NameRef(n.name, is_global=True)
7.56
7.57 # Examine other names.
7.58
7.59 @@ -899,7 +899,7 @@
7.60 # Possible global or built-in name.
7.61
7.62 else:
7.63 - return NameRef(n.name)
7.64 + return NameRef(n.name, is_global=True)
7.65
7.66 def process_operator_chain(self, nodes, fn):
7.67
8.1 --- a/internal_tests/branches.py Mon Feb 13 21:40:34 2017 +0100
8.2 +++ b/internal_tests/branches.py Fri Feb 24 13:27:07 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__/character.py Mon Feb 13 21:40:34 2017 +0100
9.2 +++ b/lib/__builtins__/character.py Fri Feb 24 13:27:07 2017 +0100
9.3 @@ -20,7 +20,7 @@
9.4 """
9.5
9.6 from __builtins__.types import check_int, check_string
9.7 -from native import str_chr
9.8 +from native import str_chr, unicode_unichr
9.9
9.10 def chr(i):
9.11
9.12 @@ -87,6 +87,15 @@
9.13
9.14 return c.__ord__()
9.15
9.16 -def unichr(i): pass
9.17 +def unichr(i):
9.18 +
9.19 + "Return the given character value 'i' encoded as a character."
9.20 +
9.21 + check_int(i)
9.22 +
9.23 + if 0 <= i <= 2097151:
9.24 + return utf8string(unicode_unichr(i.__data__))
9.25 + else:
9.26 + raise ValueError, i
9.27
9.28 # vim: tabstop=4 expandtab shiftwidth=4
10.1 --- a/lib/__builtins__/core.py Mon Feb 13 21:40:34 2017 +0100
10.2 +++ b/lib/__builtins__/core.py Fri Feb 24 13:27:07 2017 +0100
10.3 @@ -86,6 +86,7 @@
10.4 self.__args__ = None
10.5 self.__name__ = None
10.6 self.__parent__ = None
10.7 + self.__context__ = None
10.8
10.9 def __bool__(self):
10.10
10.11 @@ -122,6 +123,25 @@
10.12
10.13 __repr__ = __str__
10.14
10.15 +class wrapper:
10.16 +
10.17 + "A special method wrapper."
10.18 +
10.19 + def __init__(self, context, value):
10.20 +
10.21 + "Initialise a wrapper with the given 'context' and wrapped 'value'."
10.22 +
10.23 + self.__context__ = context
10.24 + self.__value__ = value
10.25 +
10.26 + def __str__(self):
10.27 +
10.28 + "Return a string representation, referring to the wrapped object."
10.29 +
10.30 + return self.__value__.__str__()
10.31 +
10.32 + __repr__ = __str__
10.33 +
10.34 class Exception:
10.35
10.36 "The root of all exception types."
11.1 --- a/lib/native/__init__.py Mon Feb 13 21:40:34 2017 +0100
11.2 +++ b/lib/native/__init__.py Fri Feb 24 13:27:07 2017 +0100
11.3 @@ -48,6 +48,6 @@
11.4
11.5 from native.system import exit, get_argv, get_path
11.6
11.7 -from native.unicode import unicode_len, unicode_ord, unicode_substr
11.8 +from native.unicode import unicode_len, unicode_ord, unicode_substr, unicode_unichr
11.9
11.10 # vim: tabstop=4 expandtab shiftwidth=4
12.1 --- a/lib/native/unicode.py Mon Feb 13 21:40:34 2017 +0100
12.2 +++ b/lib/native/unicode.py Fri Feb 24 13:27:07 2017 +0100
12.3 @@ -29,5 +29,6 @@
12.4 def unicode_len(data, size): pass
12.5 def unicode_ord(data, size): pass
12.6 def unicode_substr(data, size, start, end, step): pass
12.7 +def unicode_unichr(value): pass
12.8
12.9 # vim: tabstop=4 expandtab shiftwidth=4
13.1 --- a/lplc Mon Feb 13 21:40:34 2017 +0100
13.2 +++ b/lplc Fri Feb 24 13:27:07 2017 +0100
13.3 @@ -22,8 +22,8 @@
13.4 VERSION = "0.1"
13.5
13.6 from errors import *
13.7 -from os import environ, rename
13.8 -from os.path import abspath, exists, isfile, join, split
13.9 +from os import environ, listdir, remove, rename
13.10 +from os.path import abspath, exists, extsep, isdir, isfile, join, split
13.11 from pyparser import error
13.12 from subprocess import Popen, PIPE
13.13 from time import time
13.14 @@ -82,6 +82,17 @@
13.15 else:
13.16 return l, needed
13.17
13.18 +def remove_all(dirname):
13.19 +
13.20 + "Remove 'dirname' and its contents."
13.21 +
13.22 + for filename in listdir(dirname):
13.23 + pathname = join(dirname, filename)
13.24 + if isdir(pathname):
13.25 + remove_all(pathname)
13.26 + else:
13.27 + remove(pathname)
13.28 +
13.29 # Main program.
13.30
13.31 if __name__ == "__main__":
13.32 @@ -98,21 +109,34 @@
13.33 Compile the program whose principal file is given in place of <filename>.
13.34 The following options may be specified:
13.35
13.36 --c Only partially compile the program; do not attempt to build or link it
13.37 --E Ignore environment variables affecting the module search path
13.38 --g Generate debugging information for the built executable
13.39 --P Show the module search path
13.40 --q Silence messages produced when building an executable
13.41 --r Reset (discard) cached program information; inspect the whole program again
13.42 --t Silence timing messages
13.43 --tb Provide a traceback for any internal errors (development only)
13.44 --v Report compiler activities in a verbose fashion (development only)
13.45 +-c Only partially compile the program; do not build or link it
13.46 +--compile Equivalent to -c
13.47 +-E Ignore environment variables affecting the module search path
13.48 +--no-env Equivalent to -E
13.49 +-g Generate debugging information for the built executable
13.50 +--debug Equivalent to -g
13.51 +-G Remove superfluous sections of the built executable
13.52 +--gc-sections Equivalent to -G
13.53 +-P Show the module search path
13.54 +--show-path Equivalent to -P
13.55 +-q Silence messages produced when building an executable
13.56 +--quiet Equivalent to -q
13.57 +-r Reset (discard) cached information; inspect the whole program again
13.58 +--reset Equivalent to -r
13.59 +-R Reset (discard) all program details including translated code
13.60 +--reset-all Equivalent to -R
13.61 +-t Silence timing messages
13.62 +--no-timing Equivalent to -t
13.63 +-tb Provide a traceback for any internal errors (development only)
13.64 +--traceback Equivalent to -tb
13.65 +-v Report compiler activities in a verbose fashion (development only)
13.66 +--verbose Equivalent to -v
13.67
13.68 Some options may be followed by values, either immediately after the option
13.69 (without any space between) or in the arguments that follow them:
13.70
13.71 --o Indicate the output executable name
13.72 --W Show warnings on the topics indicated
13.73 +-o Indicate the output executable name
13.74 +-W Show warnings on the topics indicated
13.75
13.76 Currently, the following warnings are supported:
13.77
13.78 @@ -148,10 +172,12 @@
13.79 # Determine the options and arguments.
13.80
13.81 debug = False
13.82 + gc_sections = False
13.83 ignore_env = False
13.84 make = True
13.85 make_verbose = True
13.86 reset = False
13.87 + reset_all = False
13.88 timings = True
13.89 traceback = False
13.90 verbose = False
13.91 @@ -166,15 +192,17 @@
13.92 needed = None
13.93
13.94 for arg in args:
13.95 - if arg == "-c": make = False
13.96 - elif arg == "-E": ignore_env = True
13.97 - elif arg == "-g": debug = True
13.98 - elif arg == "-q": make_verbose = False
13.99 - elif arg == "-r": reset = True
13.100 - elif arg == "-t": timings = False
13.101 - elif arg == "-tb": traceback = True
13.102 + if arg in ("-c", "--compile"): make = False
13.103 + elif arg in ("-E", "--no-env"): ignore_env = True
13.104 + elif arg in ("-g", "--debug"): debug = True
13.105 + elif arg in ("-G", "--gc-sections"): gc_sections = True
13.106 + elif arg in ("-q", "--quiet"): make_verbose = False
13.107 + elif arg in ("-r", "--reset"): reset = True
13.108 + elif arg in ("-R", "--reset-all"): reset_all = True
13.109 + elif arg in ("-t", "--no-timing"): timings = False
13.110 + elif arg in ("-tb", "--traceback"): traceback = True
13.111 elif arg.startswith("-o"): l, needed = start_arg_list(outputs, arg, "-o", 1)
13.112 - elif arg == "-v": verbose = True
13.113 + elif arg == ("-v", "--verbose"): verbose = True
13.114 elif arg.startswith("-W"): l, needed = start_arg_list(warnings, arg, "-W", 1)
13.115 else:
13.116 l.append(arg)
13.117 @@ -193,7 +221,7 @@
13.118
13.119 # Show the module search path if requested.
13.120
13.121 - if "-P" in args:
13.122 + if "-P" in args or "--show-path" in args:
13.123 for libdir in libdirs:
13.124 print libdir
13.125 sys.exit(0)
13.126 @@ -221,12 +249,17 @@
13.127
13.128 # Define the output data directories.
13.129
13.130 - datadir = "_lplc"
13.131 + datadir = "%s%s%s" % (output, extsep, "lplc") # _main.lplc by default
13.132 cache_dir = join(datadir, "_cache")
13.133 deduced_dir = join(datadir, "_deduced")
13.134 output_dir = join(datadir, "_output")
13.135 generated_dir = join(datadir, "_generated")
13.136
13.137 + # Perform any full reset of the working data.
13.138 +
13.139 + if reset_all:
13.140 + remove_all(datadir)
13.141 +
13.142 # Load the program.
13.143
13.144 try:
13.145 @@ -255,7 +288,7 @@
13.146 if timings: now = stopwatch("Optimisation", now)
13.147
13.148 g = generator.Generator(i, o, generated_dir)
13.149 - g.to_output(debug)
13.150 + g.to_output(debug, gc_sections)
13.151
13.152 if timings: now = stopwatch("Generation", now)
13.153
13.154 @@ -270,9 +303,7 @@
13.155 make_clean_cmd = ["make", "-C", generated_dir, "clean"]
13.156 make_cmd = make_clean_cmd[:-1]
13.157
13.158 - retval = call(make_clean_cmd, make_verbose)
13.159 - if not retval:
13.160 - retval = call(make_cmd, make_verbose)
13.161 + retval = call(make_cmd, make_verbose)
13.162
13.163 if not retval:
13.164 if timings: stopwatch("Compilation", now)
14.1 --- a/modules.py Mon Feb 13 21:40:34 2017 +0100
14.2 +++ b/modules.py Fri Feb 24 13:27:07 2017 +0100
14.3 @@ -495,11 +495,11 @@
14.4 f.readline() # "aliased names:"
14.5 line = f.readline().rstrip()
14.6 while line:
14.7 - name, version, original_name, attrnames, number = self._get_fields(line, 5)
14.8 + name, version, path, original_name, attrnames, number = self._get_fields(line, 6)
14.9 init_item(self.aliased_names, name, dict)
14.10 if number == "{}": number = None
14.11 else: number = int(number)
14.12 - self.aliased_names[name][int(version)] = (original_name, attrnames != "{}" and attrnames or None, number)
14.13 + self.aliased_names[name][int(version)] = (path, original_name, attrnames != "{}" and attrnames or None, number)
14.14 line = f.readline().rstrip()
14.15
14.16 def _get_function_parameters(self, f):
14.17 @@ -785,8 +785,8 @@
14.18 versions = aliases.items()
14.19 versions.sort()
14.20 for version, alias in versions:
14.21 - original_name, attrnames, number = alias
14.22 - print >>f, name, version, original_name, attrnames or "{}", number is None and "{}" or number
14.23 + path, original_name, attrnames, number = alias
14.24 + print >>f, name, version, path, original_name, attrnames or "{}", number is None and "{}" or number
14.25
14.26 print >>f
14.27 print >>f, "function parameters:"
15.1 --- a/optimiser.py Mon Feb 13 21:40:34 2017 +0100
15.2 +++ b/optimiser.py Fri Feb 24 13:27:07 2017 +0100
15.3 @@ -21,7 +21,7 @@
15.4
15.5 from common import add_counter_item, get_attrname_from_location, init_item, \
15.6 sorted_output
15.7 -from encoders import encode_access_location, encode_instruction, get_kinds
15.8 +from encoders import digest, encode_access_location, encode_instruction, get_kinds
15.9 from os.path import exists, join
15.10 from os import makedirs
15.11 from referencing import Reference
15.12 @@ -351,9 +351,13 @@
15.13 first_method, final_method, \
15.14 origin, accessor_kinds = access_plan
15.15
15.16 + # Emit instructions by appending them to a list.
15.17 +
15.18 instructions = []
15.19 emit = instructions.append
15.20
15.21 + # Identify any static original accessor.
15.22 +
15.23 if base:
15.24 original_accessor = base
15.25 else:
15.26 @@ -371,7 +375,7 @@
15.27 # Perform the first access explicitly if at least one operation
15.28 # requires it.
15.29
15.30 - access_first_attribute = final_method in ("access", "assign") or traversed or attrnames
15.31 + access_first_attribute = final_method in ("access", "access-invoke", "assign") or traversed or attrnames
15.32
15.33 # Determine whether the first access involves assignment.
15.34
15.35 @@ -388,8 +392,12 @@
15.36 # Prevent re-evaluation of any dynamic expression by storing it.
15.37
15.38 if original_accessor == "<expr>":
15.39 - emit((set_accessor, original_accessor))
15.40 - accessor = context_var = (stored_accessor,)
15.41 + if final_method in ("access-invoke", "static-invoke"):
15.42 + emit(("<set_context>", original_accessor))
15.43 + accessor = context_var = ("<context>",)
15.44 + else:
15.45 + emit((set_accessor, original_accessor))
15.46 + accessor = context_var = (stored_accessor,)
15.47 else:
15.48 accessor = context_var = (original_accessor,)
15.49
15.50 @@ -462,12 +470,24 @@
15.51 # Set the context, if appropriate.
15.52
15.53 if remaining == 1 and final_method != "assign" and context == "final-accessor":
15.54 - emit(("__set_context", accessor))
15.55 - accessor = context_var = "<context>"
15.56 +
15.57 + # Invoked attributes employ a separate context accessed
15.58 + # during invocation.
15.59 +
15.60 + if final_method in ("access-invoke", "static-invoke"):
15.61 + emit(("<set_context>", accessor))
15.62 + accessor = context_var = "<context>"
15.63 +
15.64 + # A private context within the access is otherwise
15.65 + # retained.
15.66 +
15.67 + else:
15.68 + emit(("<set_private_context>", accessor))
15.69 + accessor = context_var = "<private_context>"
15.70
15.71 # Perform the access only if not achieved directly.
15.72
15.73 - if remaining > 1 or final_method in ("access", "assign"):
15.74 + if remaining > 1 or final_method in ("access", "access-invoke", "assign"):
15.75
15.76 if traversal_mode == "class":
15.77 if assigning:
15.78 @@ -489,12 +509,24 @@
15.79 # Set the context, if appropriate.
15.80
15.81 if remaining == 1 and final_method != "assign" and context == "final-accessor":
15.82 - emit(("__set_context", accessor))
15.83 - accessor = context_var = "<context>"
15.84 +
15.85 + # Invoked attributes employ a separate context accessed
15.86 + # during invocation.
15.87 +
15.88 + if final_method in ("access-invoke", "static-invoke"):
15.89 + emit(("<set_context>", accessor))
15.90 + accessor = context_var = "<context>"
15.91 +
15.92 + # A private context within the access is otherwise
15.93 + # retained.
15.94 +
15.95 + else:
15.96 + emit(("<set_private_context>", accessor))
15.97 + accessor = context_var = "<private_context>"
15.98
15.99 # Perform the access only if not achieved directly.
15.100
15.101 - if remaining > 1 or final_method in ("access", "assign"):
15.102 + if remaining > 1 or final_method in ("access", "access-invoke", "assign"):
15.103
15.104 if assigning:
15.105 emit(("__check_and_store_via_any", accessor, attrname, "<assexpr>"))
15.106 @@ -505,23 +537,72 @@
15.107
15.108 # Define or emit the means of accessing the actual target.
15.109
15.110 + # Assignments to known attributes.
15.111 +
15.112 if final_method == "static-assign":
15.113 parent, attrname = origin.rsplit(".", 1)
15.114 emit(("__store_via_object", parent, attrname, "<assexpr>"))
15.115
15.116 + # Invoked attributes employ a separate context.
15.117 +
15.118 elif final_method in ("static", "static-invoke"):
15.119 - parent, attrname = origin.rsplit(".", 1)
15.120 - accessor = ("__load_static", parent, origin)
15.121 + accessor = ("__load_static_ignore", origin)
15.122
15.123 # Wrap accesses in context operations.
15.124
15.125 if context_test == "test":
15.126 - emit(("__test_context", context_var, accessor))
15.127 +
15.128 + # Test and combine the context with static attribute details.
15.129 +
15.130 + if final_method == "static":
15.131 + emit(("__load_static_test", context_var, origin))
15.132 +
15.133 + # Test the context, storing it separately if required for the
15.134 + # immediately invoked static attribute.
15.135 +
15.136 + elif final_method == "static-invoke":
15.137 + emit(("<test_context_static>", context_var, origin))
15.138 +
15.139 + # Test the context, storing it separately if required for an
15.140 + # immediately invoked attribute.
15.141 +
15.142 + elif final_method == "access-invoke":
15.143 + emit(("<test_context_revert>", context_var, accessor))
15.144 +
15.145 + # Test the context and update the attribute details if
15.146 + # appropriate.
15.147 +
15.148 + else:
15.149 + emit(("__test_context", context_var, accessor))
15.150
15.151 elif context_test == "replace":
15.152 - emit(("__update_context", context_var, accessor))
15.153 +
15.154 + # Produce an object with updated context.
15.155 +
15.156 + if final_method == "static":
15.157 + emit(("__load_static_replace", context_var, origin))
15.158 +
15.159 + # Omit the context update operation where the target is static
15.160 + # and the context is recorded separately.
15.161 +
15.162 + elif final_method == "static-invoke":
15.163 + pass
15.164
15.165 - elif final_method not in ("assign", "static-assign"):
15.166 + # If a separate context is used for an immediate invocation,
15.167 + # produce the attribute details unchanged.
15.168 +
15.169 + elif final_method == "access-invoke":
15.170 + emit(accessor)
15.171 +
15.172 + # Update the context in the attribute details.
15.173 +
15.174 + else:
15.175 + emit(("__update_context", context_var, accessor))
15.176 +
15.177 + # Omit the accessor for assignments and for invocations of static
15.178 + # targets.
15.179 +
15.180 + elif final_method not in ("assign", "static-assign", "static-invoke"):
15.181 emit(accessor)
15.182
15.183 self.access_instructions[access_location] = instructions
15.184 @@ -642,7 +723,7 @@
15.185 # Each constant is actually (value, value_type, encoding).
15.186
15.187 for constant, n in constants.items():
15.188 - add_counter_item(self.constants, constant)
15.189 + self.constants[constant] = digest(constant)
15.190
15.191 self.constant_numbers = {}
15.192
16.1 --- a/resolving.py Mon Feb 13 21:40:34 2017 +0100
16.2 +++ b/resolving.py Fri Feb 24 13:27:07 2017 +0100
16.3 @@ -3,7 +3,7 @@
16.4 """
16.5 Name resolution.
16.6
16.7 -Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
16.8 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
16.9
16.10 This program is free software; you can redistribute it and/or modify it under
16.11 the terms of the GNU General Public License as published by the Free Software
16.12 @@ -289,7 +289,13 @@
16.13
16.14 if not ref:
16.15 if not invocation:
16.16 - aliased_names[i] = name_ref.original_name, name_ref.attrnames, name_ref.number
16.17 +
16.18 + # Record the path used for tracking purposes
16.19 + # alongside original name, attribute and access
16.20 + # number details.
16.21 +
16.22 + aliased_names[i] = path, name_ref.original_name, name_ref.attrnames, name_ref.number
16.23 +
16.24 continue
16.25
16.26 # Attempt to resolve a plain name reference.
16.27 @@ -303,7 +309,13 @@
16.28
16.29 if not origin:
16.30 if not invocation:
16.31 - aliased_names[i] = name_ref.name, None, name_ref.number
16.32 +
16.33 + # Record the path used for tracking purposes
16.34 + # alongside original name, attribute and access
16.35 + # number details.
16.36 +
16.37 + aliased_names[i] = path, name_ref.name, None, name_ref.number
16.38 +
16.39 continue
16.40
16.41 ref = self.get_resolved_object(origin)
17.1 --- a/results.py Mon Feb 13 21:40:34 2017 +0100
17.2 +++ b/results.py Fri Feb 24 13:27:07 2017 +0100
17.3 @@ -30,6 +30,9 @@
17.4 def is_name(self):
17.5 return False
17.6
17.7 + def is_global_name(self):
17.8 + return False
17.9 +
17.10 def reference(self):
17.11 return None
17.12
17.13 @@ -90,25 +93,29 @@
17.14
17.15 "A reference to a name."
17.16
17.17 - def __init__(self, name, expr=None):
17.18 + def __init__(self, name, expr=None, is_global=False):
17.19 self.name = name
17.20 self.expr = expr
17.21 + self.is_global = is_global
17.22
17.23 def is_name(self):
17.24 return True
17.25
17.26 + def is_global_name(self):
17.27 + return self.is_global
17.28 +
17.29 def final(self):
17.30 return None
17.31
17.32 def __repr__(self):
17.33 - return "NameRef(%r, %r)" % (self.name, self.expr)
17.34 + return "NameRef(%r, %r, %r)" % (self.name, self.expr, self.is_global)
17.35
17.36 class LocalNameRef(NameRef):
17.37
17.38 "A reference to a local name."
17.39
17.40 def __init__(self, name, number):
17.41 - NameRef.__init__(self, name)
17.42 + NameRef.__init__(self, name, is_global=False)
17.43 self.number = number
17.44
17.45 def __repr__(self):
17.46 @@ -149,12 +156,12 @@
17.47
17.48 "A resolved name-based reference."
17.49
17.50 - def __init__(self, name, ref, expr=None):
17.51 - NameRef.__init__(self, name, expr)
17.52 + def __init__(self, name, ref, expr=None, is_global=False):
17.53 + NameRef.__init__(self, name, expr, is_global)
17.54 ResolvedRef.__init__(self, ref)
17.55
17.56 def __repr__(self):
17.57 - return "ResolvedNameRef(%r, %r, %r)" % (self.name, self.ref, self.expr)
17.58 + return "ResolvedNameRef(%r, %r, %r, %r)" % (self.name, self.ref, self.expr, self.is_global)
17.59
17.60 class ConstantValueRef(ResolvedNameRef):
17.61
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/templates/gc_sections.mk Fri Feb 24 13:27:07 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/iconv.c Mon Feb 13 21:40:34 2017 +0100
19.2 +++ b/templates/native/iconv.c Fri Feb 24 13:27:07 2017 +0100
19.3 @@ -156,7 +156,6 @@
19.4
19.5 /* Return the descriptor as an opaque value. */
19.6
19.7 - attr.context = 0;
19.8 attr.datavalue = (void *) result;
19.9 return attr;
19.10 }
21.1 --- a/templates/native/unicode.c Mon Feb 13 21:40:34 2017 +0100
21.2 +++ b/templates/native/unicode.c Fri Feb 24 13:27:07 2017 +0100
21.3 @@ -1,6 +1,6 @@
21.4 /* Native functions for Unicode operations.
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 @@ -202,6 +202,48 @@
21.12 return __new_str(sub, resultsize);
21.13 }
21.14
21.15 +__attr __fn_native_unicode_unicode_unichr(__attr __args[])
21.16 +{
21.17 + __attr * const value = &__args[1];
21.18 + /* value interpreted as int */
21.19 + int i = value->intvalue;
21.20 + unsigned int resultsize;
21.21 + char *s;
21.22 +
21.23 + if (i < 128) resultsize = 1;
21.24 + else if (i < 2048) resultsize = 2;
21.25 + else if (i < 65536) resultsize = 3;
21.26 + else resultsize = 4;
21.27 +
21.28 + /* Reserve space for a new string. */
21.29 +
21.30 + s = (char *) __ALLOCATE(resultsize + 1, sizeof(char));
21.31 +
21.32 + /* Populate the string. */
21.33 +
21.34 + if (i < 128) s[0] = (char) i;
21.35 + else if (i < 2048)
21.36 + {
21.37 + s[0] = 0b11000000 | (i >> 6);
21.38 + s[1] = 0b10000000 | (i & 0b00111111);
21.39 + }
21.40 + else if (i < 65536)
21.41 + {
21.42 + s[0] = 0b11100000 | (i >> 12);
21.43 + s[1] = 0b10000000 | ((i >> 6) & 0b00111111);
21.44 + s[2] = 0b10000000 | (i & 0b00111111);
21.45 + }
21.46 + else
21.47 + {
21.48 + s[0] = 0b11110000 | (i >> 18);
21.49 + s[1] = 0b10000000 | ((i >> 12) & 0b00111111);
21.50 + s[2] = 0b10000000 | ((i >> 6) & 0b00111111);
21.51 + s[3] = 0b10000000 | (i & 0b00111111);
21.52 + }
21.53 +
21.54 + return __new_str(s, resultsize);
21.55 +}
21.56 +
21.57 /* Module initialisation. */
21.58
21.59 void __main_native_unicode()
22.1 --- a/templates/native/unicode.h Mon Feb 13 21:40:34 2017 +0100
22.2 +++ b/templates/native/unicode.h Fri Feb 24 13:27:07 2017 +0100
22.3 @@ -24,6 +24,7 @@
22.4 __attr __fn_native_unicode_unicode_len(__attr __args[]);
22.5 __attr __fn_native_unicode_unicode_ord(__attr __args[]);
22.6 __attr __fn_native_unicode_unicode_substr(__attr __args[]);
22.7 +__attr __fn_native_unicode_unicode_unichr(__attr __args[]);
22.8
22.9 /* Module initialisation. */
22.10
23.1 --- a/templates/ops.c Mon Feb 13 21:40:34 2017 +0100
23.2 +++ b/templates/ops.c Fri Feb 24 13:27:07 2017 +0100
23.3 @@ -21,14 +21,22 @@
23.4 #include "progops.h" /* for raising errors */
23.5 #include "progconsts.h"
23.6 #include "progtypes.h"
23.7 -#include <stdio.h>
23.8
23.9 /* Direct access and manipulation of static objects. */
23.10
23.11 -__attr __load_static(__ref parent, __ref obj)
23.12 +__attr __load_static_ignore(__ref obj)
23.13 +{
23.14 + return (__attr) {.value=obj};
23.15 +}
23.16 +
23.17 +__attr __load_static_replace(__ref context, __ref obj)
23.18 {
23.19 - __attr out = {.context=parent, .value=obj};
23.20 - return out;
23.21 + return __update_context(context, (__attr) {.value=obj});
23.22 +}
23.23 +
23.24 +__attr __load_static_test(__ref context, __ref obj)
23.25 +{
23.26 + return __test_context(context, (__attr) {.value=obj});
23.27 }
23.28
23.29 /* Direct retrieval operations, returning and setting attributes. */
23.30 @@ -190,77 +198,122 @@
23.31
23.32 /* Context-related operations. */
23.33
23.34 -__attr __test_context(__ref context, __attr attr)
23.35 +int __test_context_update(__ref context, __attr attr)
23.36 {
23.37 + /* Return whether the context should be updated for the attribute. */
23.38 +
23.39 + __ref attrcontext = __CONTEXT_AS_VALUE(attr).value;
23.40 +
23.41 /* Preserve any existing null or instance context. */
23.42
23.43 - if ((attr.context == 0) || __is_instance(attr.context))
23.44 - return attr;
23.45 + if ((attrcontext == 0) || __is_instance(attrcontext))
23.46 + return 0;
23.47
23.48 /* Test any instance context against the context employed by the
23.49 attribute. */
23.50
23.51 if (__is_instance(context))
23.52 {
23.53 - if (__test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context)))
23.54 - return __update_context(context, attr);
23.55 + /* Obtain the special class attribute position and code identifying the
23.56 + attribute context's class, inspecting the context instance for
23.57 + compatibility. */
23.58 +
23.59 + if (__test_common_instance(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext)))
23.60 + return 1;
23.61 else
23.62 __raise_type_error();
23.63 }
23.64
23.65 /* Test for access to a type class attribute using a type instance. */
23.66
23.67 - if (__test_specific_type(attr.context, &__TYPE_CLASS_TYPE) && __is_type_instance(context))
23.68 - return __update_context(context, attr);
23.69 + if (__test_specific_type(attrcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context))
23.70 + return 1;
23.71
23.72 /* Otherwise, preserve the attribute as retrieved. */
23.73
23.74 - return attr;
23.75 + return 0;
23.76 +}
23.77 +
23.78 +__attr __test_context(__ref context, __attr attr)
23.79 +{
23.80 + /* Update the context or return the unchanged attribute. */
23.81 +
23.82 + if (__test_context_update(context, attr))
23.83 + return __update_context(context, attr);
23.84 + else
23.85 + return attr;
23.86 }
23.87
23.88 __attr __update_context(__ref context, __attr attr)
23.89 {
23.90 - __attr out = {.context=context, .value=attr.value};
23.91 - return out;
23.92 + return __new_wrapper(context, attr);
23.93 +}
23.94 +
23.95 +__attr __test_context_revert(int target, __ref context, __attr attr, __ref contexts[])
23.96 +{
23.97 + /* Revert the local context to that employed by the attribute if the
23.98 + supplied context is not appropriate. */
23.99 +
23.100 + if (!__test_context_update(context, attr))
23.101 + contexts[target] = __CONTEXT_AS_VALUE(attr).value;
23.102 + return attr;
23.103 +}
23.104 +
23.105 +__attr __test_context_static(int target, __ref context, __ref value, __ref contexts[])
23.106 +{
23.107 + /* Set the local context to the specified context if appropriate. */
23.108 +
23.109 + if (__test_context_update(context, (__attr) {.value=value}))
23.110 + contexts[target] = context;
23.111 + return (__attr) {.value=value};
23.112 }
23.113
23.114 /* Context testing for invocations. */
23.115
23.116 -int __type_method_invocation(__attr attr)
23.117 +int __type_method_invocation(__ref context, __attr target)
23.118 {
23.119 - __attr parent;
23.120 + __ref targetcontext = __CONTEXT_AS_VALUE(target).value;
23.121
23.122 /* Require instances, not classes, where methods are function instances. */
23.123
23.124 - if (!__is_instance(attr.value))
23.125 + if (!__is_instance(target.value))
23.126 return 0;
23.127
23.128 - /* Access the parent of the callable and test if it is the type object. */
23.129 + /* Access the context of the callable and test if it is the type object. */
23.130
23.131 - parent = __check_and_load_via_object_null(attr.value, __ATTRPOS(__parent__), __ATTRCODE(__parent__));
23.132 - return ((parent.value != 0) && __test_specific_type(parent.value, &__TYPE_CLASS_TYPE) && __is_type_instance(attr.context));
23.133 + return ((targetcontext != 0) && __test_specific_type(targetcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context));
23.134 }
23.135
23.136 -__attr (*__get_function(__attr attr))(__attr[])
23.137 +__attr __unwrap_callable(__attr callable)
23.138 {
23.139 + __attr value = __check_and_load_via_object_null(callable.value, __ATTRPOS(__value__), __ATTRCODE(__value__));
23.140 + return value.value ? value : callable;
23.141 +}
23.142 +
23.143 +__attr (*__get_function(__ref context, __attr target))(__attr[])
23.144 +{
23.145 + target = __unwrap_callable(target);
23.146 +
23.147 /* Require null or instance contexts for functions and methods respectively,
23.148 or type instance contexts for type methods. */
23.149
23.150 - if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr))
23.151 - return __load_via_object(attr.value, __ATTRPOS(__fn__)).fn;
23.152 + if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))
23.153 + return __load_via_object(target.value, __ATTRPOS(__fn__)).fn;
23.154 else
23.155 - return __load_via_object(attr.value, __ATTRPOS(__fn__)).inv;
23.156 + return __unbound_method;
23.157 }
23.158
23.159 -__attr (*__check_and_get_function(__attr attr))(__attr[])
23.160 +__attr (*__check_and_get_function(__ref context, __attr target))(__attr[])
23.161 {
23.162 + target = __unwrap_callable(target);
23.163 +
23.164 /* Require null or instance contexts for functions and methods respectively,
23.165 or type instance contexts for type methods. */
23.166
23.167 - if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr))
23.168 - return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;
23.169 + if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))
23.170 + return __check_and_load_via_object(target.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;
23.171 else
23.172 - return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).inv;
23.173 + return __unbound_method;
23.174 }
23.175
23.176 /* Basic structure tests. */
23.177 @@ -295,10 +348,7 @@
23.178
23.179 __attr __CONTEXT_AS_VALUE(__attr attr)
23.180 {
23.181 - __attr out;
23.182 - out.context = attr.context;
23.183 - out.value = attr.context;
23.184 - return out;
23.185 + return __check_and_load_via_object_null(attr.value, __ATTRPOS(__context__), __ATTRCODE(__context__));
23.186 }
23.187
23.188 /* Type testing. */
23.189 @@ -310,7 +360,6 @@
23.190
23.191 int __ISNULL(__attr value)
23.192 {
23.193 - /* (value.context == __NULL.context) is superfluous */
23.194 return (value.value == 0); /* __NULL.value */
23.195 }
23.196
24.1 --- a/templates/ops.h Mon Feb 13 21:40:34 2017 +0100
24.2 +++ b/templates/ops.h Fri Feb 24 13:27:07 2017 +0100
24.3 @@ -24,7 +24,9 @@
24.4
24.5 /* Direct access and manipulation of static objects. */
24.6
24.7 -__attr __load_static(__ref parent, __ref obj);
24.8 +__attr __load_static_ignore(__ref obj);
24.9 +__attr __load_static_replace(__ref context, __ref obj);
24.10 +__attr __load_static_test(__ref context, __ref obj);
24.11
24.12 /* Direct retrieval operations, returning attributes. */
24.13
24.14 @@ -68,17 +70,23 @@
24.15
24.16 /* Context-related operations. */
24.17
24.18 +int __test_context_update(__ref context, __attr attr);
24.19 __attr __test_context(__ref context, __attr attr);
24.20 __attr __update_context(__ref context, __attr attr);
24.21 +__attr __test_context_revert(int target, __ref context, __attr attr, __ref contexts[]);
24.22 +__attr __test_context_static(int target, __ref context, __ref value, __ref contexts[]);
24.23
24.24 -#define __set_context(__ATTR) (__tmp_context = (__ATTR).value)
24.25 +#define __get_context(__TARGET) (__tmp_contexts[__TARGET])
24.26 +#define __set_context(__TARGET, __ATTR) (__tmp_contexts[__TARGET] = (__ATTR).value)
24.27 +#define __set_private_context(__ATTR) (__tmp_private_context = (__ATTR).value)
24.28 #define __set_accessor(__ATTR) (__tmp_value = (__ATTR).value)
24.29 #define __set_target_accessor(__ATTR) (__tmp_target_value = (__ATTR).value)
24.30
24.31 /* Context testing for invocations. */
24.32
24.33 -__attr (*__get_function(__attr attr))(__attr[]);
24.34 -__attr (*__check_and_get_function(__attr attr))(__attr[]);
24.35 +__attr __unwrap_callable(__attr callable);
24.36 +__attr (*__get_function(__ref context, __attr target))(__attr[]);
24.37 +__attr (*__check_and_get_function(__ref context, __attr target))(__attr[]);
24.38
24.39 /* Basic structure tests. */
24.40
25.1 --- a/templates/progops.c Mon Feb 13 21:40:34 2017 +0100
25.2 +++ b/templates/progops.c Fri Feb 24 13:27:07 2017 +0100
25.3 @@ -30,11 +30,14 @@
25.4 __attr __new(const __table * table, __ref cls, size_t size)
25.5 {
25.6 __ref obj = (__ref) __ALLOCATE(1, size);
25.7 - __attr self = {.context=obj, .value=obj};
25.8 - __attr tmp = {.context=0, .value=cls};
25.9 obj->table = table;
25.10 - __store_via_object(obj, __ATTRPOS(__class__), tmp);
25.11 - return self;
25.12 + __store_via_object(obj, __ATTRPOS(__class__), (__attr) {.value=cls});
25.13 + return (__attr) {.value=obj};
25.14 +}
25.15 +
25.16 +__attr __new_wrapper(__ref context, __attr attr)
25.17 +{
25.18 + return __new___builtins___core_wrapper((__attr[]) {__NULL, {.value=context}, attr});
25.19 }
25.20
25.21 /* Generic internal data allocation. */
25.22 @@ -155,7 +158,7 @@
25.23 {
25.24 /* Reserve space for the instance. */
25.25
25.26 - __attr args[1];
25.27 + __attr args[1] = {__NULL};
25.28
25.29 /* Return instances as provided. */
25.30
25.31 @@ -181,14 +184,15 @@
25.32 unsigned int nkwargs, __param kwcodes[], __attr kwargs[],
25.33 unsigned int nargs, __attr args[])
25.34 {
25.35 - /* Obtain the __args__ special member, referencing the parameter table. */
25.36 + /* Unwrap any wrapped function. */
25.37
25.38 - __attr minparams = __check_and_load_via_object(callable.value, __ATTRPOS(__args__), __ATTRCODE(__args__));
25.39 + __attr target = __unwrap_callable(callable);
25.40
25.41 + /* Obtain the __args__ special member, referencing the parameter table. */
25.42 /* Refer to the table and minimum/maximum. */
25.43
25.44 - const __ptable *ptable = minparams.ptable;
25.45 - const unsigned int min = minparams.min, max = ptable->size;
25.46 + const __ptable *ptable = __check_and_load_via_object(target.value, __ATTRPOS(__args__), __ATTRCODE(__args__)).ptable;
25.47 + const unsigned int min = ptable->min, max = ptable->max;
25.48
25.49 /* Reserve enough space for the arguments. */
25.50
25.51 @@ -240,12 +244,12 @@
25.52 for (pos = nargs; pos < max; pos++)
25.53 {
25.54 if (allargs[pos].value == 0)
25.55 - allargs[pos] = __GETDEFAULT(callable.value, pos - min);
25.56 + allargs[pos] = __GETDEFAULT(target.value, pos - min);
25.57 }
25.58
25.59 /* Call with the prepared arguments. */
25.60
25.61 - return (always_callable ? __get_function(callable) : __check_and_get_function(callable))(allargs);
25.62 + return (always_callable ? __get_function(allargs[0].value, target) : __check_and_get_function(allargs[0].value, target))(allargs);
25.63 }
25.64
25.65 /* Error routines. */
26.1 --- a/templates/progops.h Mon Feb 13 21:40:34 2017 +0100
26.2 +++ b/templates/progops.h Fri Feb 24 13:27:07 2017 +0100
26.3 @@ -25,6 +25,7 @@
26.4 /* Generic instantiation operations, defining common members. */
26.5
26.6 __attr __new(const __table *table, __ref cls, size_t size);
26.7 +__attr __new_wrapper(__ref context, __attr attr);
26.8
26.9 /* Generic internal data allocation. */
26.10
27.1 --- a/templates/types.h Mon Feb 13 21:40:34 2017 +0100
27.2 +++ b/templates/types.h Fri Feb 24 13:27:07 2017 +0100
27.3 @@ -22,10 +22,12 @@
27.4 /* Define code and position types, populated by enum values defined for each
27.5 program specifically. */
27.6
27.7 -typedef unsigned short __code;
27.8 -typedef unsigned short __pos;
27.9 -typedef unsigned short __pcode;
27.10 -typedef unsigned short __ppos;
27.11 +#include <stdint.h>
27.12 +
27.13 +typedef uint16_t __code;
27.14 +typedef uint16_t __pos;
27.15 +typedef uint16_t __pcode;
27.16 +typedef uint16_t __ppos;
27.17
27.18 /* Attribute tables are lists of codes confirming the presence of attributes. */
27.19
27.20 @@ -47,48 +49,34 @@
27.21
27.22 typedef struct __ptable
27.23 {
27.24 - const __ppos size;
27.25 + const __ppos min, max, size;
27.26 const __param params[];
27.27 } __ptable;
27.28
27.29 -/* Attributes are context and value pairs.
27.30 +/* Attributes are values referring to objects or encoding other information.
27.31 Objects are collections of attributes.
27.32 Object references are references to tables and collections of attributes.
27.33 Attribute references are references to single attributes. */
27.34
27.35 typedef struct __obj __obj;
27.36 typedef struct __fragment __fragment;
27.37 +typedef union __attr __attr;
27.38 +typedef __obj * __ref;
27.39
27.40 -typedef struct __attr
27.41 +typedef union __attr
27.42 {
27.43 - /* One of... */
27.44 - union
27.45 - {
27.46 - struct {
27.47 - __obj * context; /* attribute context */
27.48 - __obj * value; /* attribute value */
27.49 - };
27.50 - struct {
27.51 - __ppos min; /* minimum number of parameters */
27.52 - const __ptable * ptable; /* parameter table */
27.53 - };
27.54 - struct {
27.55 - __pcode code; /* parameter table code for key */
27.56 - __ppos pos; /* parameter table position for key */
27.57 - };
27.58 - struct {
27.59 - struct __attr (*inv)(); /* unbound callable details */
27.60 - struct __attr (*fn)(); /* callable details */
27.61 - };
27.62 - union
27.63 - {
27.64 - int intvalue; /* integer value */
27.65 - double floatvalue; /* floating point value */
27.66 - char * strvalue; /* string value */
27.67 - __fragment * seqvalue; /* sequence data */
27.68 - void * datavalue; /* object-specific data */
27.69 - };
27.70 + __ref value; /* attribute value */
27.71 + const __ptable * ptable; /* parameter table */
27.72 + struct {
27.73 + __pcode code; /* parameter table code for key */
27.74 + __ppos pos; /* parameter table position for key */
27.75 };
27.76 + __attr (*fn)(); /* callable details */
27.77 + int intvalue; /* integer value */
27.78 + float floatvalue; /* floating point value */
27.79 + char * strvalue; /* string value */
27.80 + __fragment * seqvalue; /* sequence data */
27.81 + void * datavalue; /* object-specific data */
27.82 } __attr;
27.83
27.84 typedef struct __obj
27.85 @@ -98,7 +86,7 @@
27.86 __attr attrs[]; /* attributes */
27.87 } __obj;
27.88
27.89 -typedef __obj * __ref;
27.90 +#define __INSTANCE_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + sizeof(__table *) + sizeof(__ppos))
27.91
27.92 /* Fragments are simple collections of attributes employed by sequence types.
27.93 They provide the basis of lists and tuples. */
27.94 @@ -109,7 +97,7 @@
27.95 __attr attrs[];
27.96 } __fragment;
27.97
27.98 -#define __FRAGMENT_SIZE(NUMBER) (NUMBER * sizeof(__attr) + 2 * sizeof(unsigned int))
27.99 +#define __FRAGMENT_SIZE(NUMBER) ((NUMBER) * sizeof(__attr) + 2 * sizeof(unsigned int))
27.100
27.101 /* Special instance position value. The pos member of __obj refers to the
27.102 special type attribute for classes, indicating which position holds the
27.103 @@ -119,7 +107,7 @@
27.104
27.105 /* Special null values. */
27.106
27.107 -#define __NULL ((__attr) {{.context=0, .value=0}})
27.108 +#define __NULL ((__attr) {.value=0})
27.109
27.110 /* Function pointer type. */
27.111
28.1 --- a/test_all.sh Mon Feb 13 21:40:34 2017 +0100
28.2 +++ b/test_all.sh Fri Feb 24 13:27:07 2017 +0100
28.3 @@ -3,7 +3,7 @@
28.4 # This tool runs the toolchain for each of the tests, optionally building and
28.5 # running the test programs.
28.6 #
28.7 -# Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>
28.8 +# Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
28.9 #
28.10 # This program is free software; you can redistribute it and/or modify it under
28.11 # the terms of the GNU General Public License as published by the Free Software
28.12 @@ -22,7 +22,7 @@
28.13 OPTION=$1
28.14
28.15 LPLC="./lplc"
28.16 -DATADIR="_lplc"
28.17 +DATADIR="_main.lplc"
28.18 TESTINPUT="_results/testinput.txt"
28.19
28.20 # Expect failure from the "bad" tests.
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/tests/nested_calls.py Fri Feb 24 13:27:07 2017 +0100
30.3 @@ -0,0 +1,15 @@
30.4 +class C:
30.5 + def __init__(self, x):
30.6 + self.x = x
30.7 +
30.8 + def value(self):
30.9 + return self.x
30.10 +
30.11 + def length(self):
30.12 + return self.double(self.value())
30.13 +
30.14 + def double(self, x):
30.15 + return x * 2
30.16 +
30.17 +c = C(3)
30.18 +print c.length() # 6
31.1 --- a/tests/unicode.py Mon Feb 13 21:40:34 2017 +0100
31.2 +++ b/tests/unicode.py Fri Feb 24 13:27:07 2017 +0100
31.3 @@ -212,3 +212,5 @@
31.4 print repr(euro) # "\u20ac"
31.5 print ord(euro) # 8364
31.6 print "\u20ac" # ¤
31.7 +print unichr(ord(euro)) # ¤
31.8 +print unichr(ord(euro)) == euro # True
32.1 --- a/translator.py Mon Feb 13 21:40:34 2017 +0100
32.2 +++ b/translator.py Fri Feb 24 13:27:07 2017 +0100
32.3 @@ -20,7 +20,8 @@
32.4 """
32.5
32.6 from common import CommonModule, CommonOutput, InstructionSequence, \
32.7 - first, get_builtin_class, init_item, predefined_constants
32.8 + first, get_builtin_class, init_item, is_newer, \
32.9 + predefined_constants
32.10 from encoders import encode_access_instruction, \
32.11 encode_function_pointer, encode_literal_constant, \
32.12 encode_literal_instantiator, encode_instantiator_pointer, \
32.13 @@ -45,22 +46,33 @@
32.14 self.deducer = deducer
32.15 self.optimiser = optimiser
32.16 self.output = output
32.17 - self.modules = {}
32.18
32.19 def to_output(self):
32.20 +
32.21 + "Write a program to the configured output directory."
32.22 +
32.23 + # Make a directory for the final sources.
32.24 +
32.25 output = join(self.output, "src")
32.26
32.27 if not exists(output):
32.28 makedirs(output)
32.29
32.30 + # Clean the output directory of irrelevant data.
32.31 +
32.32 self.check_output()
32.33
32.34 for module in self.importer.modules.values():
32.35 + output_filename = join(output, "%s.c" % module.name)
32.36 +
32.37 + # Do not generate modules in the native package. They are provided
32.38 + # by native functionality source files.
32.39 +
32.40 parts = module.name.split(".")
32.41 - if parts[0] != "native":
32.42 +
32.43 + if parts[0] != "native" and is_newer(module.filename, output_filename):
32.44 tm = TranslatedModule(module.name, self.importer, self.deducer, self.optimiser)
32.45 - tm.translate(module.filename, join(output, "%s.c" % module.name))
32.46 - self.modules[module.name] = tm
32.47 + tm.translate(module.filename, output_filename)
32.48
32.49 # Classes representing intermediate translation results.
32.50
32.51 @@ -91,8 +103,8 @@
32.52
32.53 "A reference to a name in the translation."
32.54
32.55 - def __init__(self, name, ref, expr=None, parameter=None, location=None):
32.56 - results.ResolvedNameRef.__init__(self, name, ref, expr)
32.57 + def __init__(self, name, ref, expr=None, is_global=False, parameter=None, location=None):
32.58 + results.ResolvedNameRef.__init__(self, name, ref, expr, is_global)
32.59 self.parameter = parameter
32.60 self.location = location
32.61
32.62 @@ -142,7 +154,7 @@
32.63 elif static_name:
32.64 parent = ref.parent()
32.65 context = ref.has_kind("<function>") and encode_path(parent) or None
32.66 - return "((__attr) {{.context=%s, .value=&%s}})" % (context and "&%s" % context or "0", static_name)
32.67 + return "((__attr) {.value=&%s})" % static_name
32.68
32.69 # Qualified names must be converted into parent-relative accesses.
32.70
32.71 @@ -331,6 +343,10 @@
32.72
32.73 self.temp_usage = {}
32.74
32.75 + # Initialise some data used for attribute access generation.
32.76 +
32.77 + self.init_substitutions()
32.78 +
32.79 def __repr__(self):
32.80 return "TranslatedModule(%r, %r)" % (self.name, self.importer)
32.81
32.82 @@ -726,7 +742,7 @@
32.83 # the complete access.
32.84
32.85 name_ref = attr_expr and attr_expr.is_name() and attr_expr
32.86 - name = name_ref and self.get_name_for_tracking(name_ref.name, name_ref and name_ref.final()) or None
32.87 + name = name_ref and self.get_name_for_tracking(name_ref.name, name_ref) or None
32.88
32.89 location = self.get_access_location(name, self.attrs)
32.90 refs = self.get_referenced_attributes(location)
32.91 @@ -738,42 +754,71 @@
32.92 "<assexpr>" : self.in_assignment,
32.93 }
32.94
32.95 - temp_subs = {
32.96 - "<context>" : "__tmp_context",
32.97 - "<accessor>" : "__tmp_value",
32.98 - "<target_accessor>" : "__tmp_target_value",
32.99 - "<set_accessor>" : "__tmp_value",
32.100 - "<set_target_accessor>" : "__tmp_target_value",
32.101 - }
32.102 -
32.103 - op_subs = {
32.104 - "<set_accessor>" : "__set_accessor",
32.105 - "<set_target_accessor>" : "__set_target_accessor",
32.106 - }
32.107 -
32.108 - subs.update(temp_subs)
32.109 - subs.update(op_subs)
32.110 + subs.update(self.temp_subs)
32.111 + subs.update(self.op_subs)
32.112
32.113 output = []
32.114 substituted = set()
32.115
32.116 + # The context set or retrieved will be that used by any enclosing
32.117 + # invocation.
32.118 +
32.119 + context_index = self.function_target - 1
32.120 +
32.121 # Obtain encoded versions of each instruction, accumulating temporary
32.122 # variables.
32.123
32.124 for instruction in self.optimiser.access_instructions[location]:
32.125 - encoded, _substituted = encode_access_instruction(instruction, subs)
32.126 + encoded, _substituted = encode_access_instruction(instruction, subs, context_index)
32.127 output.append(encoded)
32.128 substituted.update(_substituted)
32.129
32.130 # Record temporary name usage.
32.131
32.132 for sub in substituted:
32.133 - if temp_subs.has_key(sub):
32.134 - self.record_temp(temp_subs[sub])
32.135 + if self.temp_subs.has_key(sub):
32.136 + self.record_temp(self.temp_subs[sub])
32.137
32.138 del self.attrs[0]
32.139 return AttrResult(output, refs, location)
32.140
32.141 + def init_substitutions(self):
32.142 +
32.143 + """
32.144 + Initialise substitutions, defining temporary variable mappings, some of
32.145 + which are also used as substitutions, together with operation mappings
32.146 + used as substitutions in instructions defined by the optimiser.
32.147 + """
32.148 +
32.149 + self.temp_subs = {
32.150 +
32.151 + # Substitutions used by instructions.
32.152 +
32.153 + "<private_context>" : "__tmp_private_context",
32.154 + "<accessor>" : "__tmp_value",
32.155 + "<target_accessor>" : "__tmp_target_value",
32.156 +
32.157 + # Mappings to be replaced by those given below.
32.158 +
32.159 + "<context>" : "__tmp_contexts",
32.160 + "<test_context_revert>" : "__tmp_contexts",
32.161 + "<test_context_static>" : "__tmp_contexts",
32.162 + "<set_context>" : "__tmp_contexts",
32.163 + "<set_private_context>" : "__tmp_private_context",
32.164 + "<set_accessor>" : "__tmp_value",
32.165 + "<set_target_accessor>" : "__tmp_target_value",
32.166 + }
32.167 +
32.168 + self.op_subs = {
32.169 + "<context>" : "__get_context",
32.170 + "<test_context_revert>" : "__test_context_revert",
32.171 + "<test_context_static>" : "__test_context_static",
32.172 + "<set_context>" : "__set_context",
32.173 + "<set_private_context>" : "__set_private_context",
32.174 + "<set_accessor>" : "__set_accessor",
32.175 + "<set_target_accessor>" : "__set_target_accessor",
32.176 + }
32.177 +
32.178 def get_referenced_attributes(self, location):
32.179
32.180 """
32.181 @@ -875,7 +920,7 @@
32.182
32.183 if not ref.static():
32.184 self.process_assignment_for_object(
32.185 - n.name, make_expression("((__attr) {{.context=0, .value=&%s}})" %
32.186 + n.name, make_expression("((__attr) {.value=&%s})" %
32.187 encode_path(class_name)))
32.188
32.189 self.enter_namespace(n.name)
32.190 @@ -1054,9 +1099,7 @@
32.191 context = self.is_method(objpath)
32.192
32.193 self.process_assignment_for_object(original_name,
32.194 - make_expression("((__attr) {{.context=%s, .value=&%s}})" % (
32.195 - context and "&%s" % encode_path(context) or "0",
32.196 - encode_path(objpath))))
32.197 + make_expression("((__attr) {.value=&%s})" % encode_path(objpath)))
32.198
32.199 def process_function_defaults(self, n, name, objpath, instance_name=None):
32.200
32.201 @@ -1146,7 +1189,21 @@
32.202
32.203 "Process the given invocation node 'n'."
32.204
32.205 + # Any invocations in the expression will store target details in a
32.206 + # different location.
32.207 +
32.208 + self.function_target += 1
32.209 +
32.210 + # Process the expression.
32.211 +
32.212 expr = self.process_structure_node(n.node)
32.213 +
32.214 + # Reference the current target again.
32.215 +
32.216 + self.function_target -= 1
32.217 +
32.218 + # Obtain details of the invocation expression.
32.219 +
32.220 objpath = expr.get_origin()
32.221 location = expr.access_location()
32.222
32.223 @@ -1167,6 +1224,7 @@
32.224 # Invocation requirements.
32.225
32.226 context_required = True
32.227 + have_access_context = isinstance(expr, AttrResult)
32.228 parameters = None
32.229
32.230 # Obtain details of the callable and of its parameters.
32.231 @@ -1237,8 +1295,12 @@
32.232 # set to null.
32.233
32.234 if context_required:
32.235 - self.record_temp("__tmp_targets")
32.236 - args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target]
32.237 + if have_access_context:
32.238 + self.record_temp("__tmp_contexts")
32.239 + args = ["(__attr) {.value=__tmp_contexts[%d]}" % self.function_target]
32.240 + else:
32.241 + self.record_temp("__tmp_targets")
32.242 + args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target]
32.243 else:
32.244 args = ["__NULL"]
32.245
32.246 @@ -1335,8 +1397,11 @@
32.247 # Without a known specific callable, the expression provides the target.
32.248
32.249 if not target or context_required:
32.250 - self.record_temp("__tmp_targets")
32.251 - stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr))
32.252 + if target:
32.253 + stages.append(str(expr))
32.254 + else:
32.255 + self.record_temp("__tmp_targets")
32.256 + stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr))
32.257
32.258 # Any specific callable is then obtained.
32.259
32.260 @@ -1349,7 +1414,13 @@
32.261 self.record_temp("__tmp_targets")
32.262
32.263 if context_required:
32.264 - stages.append("__get_function(__tmp_targets[%d])" % self.function_target)
32.265 + if have_access_context:
32.266 + self.record_temp("__tmp_contexts")
32.267 + stages.append("__get_function(__tmp_contexts[%d], __tmp_targets[%d])" % (
32.268 + self.function_target, self.function_target))
32.269 + else:
32.270 + stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % (
32.271 + self.function_target, self.function_target))
32.272 else:
32.273 stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % (
32.274 self.function_target, encode_symbol("pos", "__fn__")))
32.275 @@ -1414,14 +1485,14 @@
32.276 # Without defaults, produce an attribute referring to the function.
32.277
32.278 if not defaults:
32.279 - return make_expression("((__attr) {{.context=0, .value=&%s}})" % encode_path(function_name))
32.280 + return make_expression("((__attr) {.value=&%s})" % encode_path(function_name))
32.281
32.282 # With defaults, copy the function structure and set the defaults on the
32.283 # copy.
32.284
32.285 else:
32.286 self.record_temp("__tmp_value")
32.287 - return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {{.context=0, .value=__tmp_value}})" % (
32.288 + return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {.value=__tmp_value})" % (
32.289 encode_path(function_name),
32.290 encode_symbol("obj", function_name),
32.291 ", ".join(defaults)))
32.292 @@ -1490,8 +1561,23 @@
32.293 # Determine any assigned globals.
32.294
32.295 globals = self.importer.get_module(self.name).scope_globals.get(path)
32.296 +
32.297 + # Explicitly declared globals.
32.298 +
32.299 if globals and n.name in globals:
32.300 objpath = self.get_global_path(n.name)
32.301 + is_global = True
32.302 +
32.303 + # Implicitly referenced globals in functions.
32.304 +
32.305 + elif self.in_function:
32.306 + is_global = n.name not in self.importer.function_locals[path]
32.307 +
32.308 + # Implicitly referenced globals elsewhere.
32.309 +
32.310 + else:
32.311 + namespace = self.importer.identify(path)
32.312 + is_global = not self.importer.get_attributes(namespace, n.name)
32.313
32.314 # Get the static identity of the name.
32.315
32.316 @@ -1520,7 +1606,7 @@
32.317 # static namespace members. The reference should be configured to return
32.318 # such names.
32.319
32.320 - return TrResolvedNameRef(n.name, ref, expr=expr, parameter=parameter, location=location)
32.321 + return TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global, parameter=parameter, location=location)
32.322
32.323 def process_not_node(self, n):
32.324
32.325 @@ -1899,14 +1985,17 @@
32.326
32.327 # Provide space for the given number of targets.
32.328
32.329 + targets = self.importer.function_targets.get(name)
32.330 +
32.331 if self.uses_temp(name, "__tmp_targets"):
32.332 - targets = self.importer.function_targets.get(name)
32.333 self.writeline("__attr __tmp_targets[%d];" % targets)
32.334 + if self.uses_temp(name, "__tmp_contexts"):
32.335 + self.writeline("__ref __tmp_contexts[%d];" % targets)
32.336
32.337 # Add temporary variable usage details.
32.338
32.339 - if self.uses_temp(name, "__tmp_context"):
32.340 - self.writeline("__ref __tmp_context;")
32.341 + if self.uses_temp(name, "__tmp_private_context"):
32.342 + self.writeline("__ref __tmp_private_context;")
32.343 if self.uses_temp(name, "__tmp_value"):
32.344 self.writeline("__ref __tmp_value;")
32.345 if self.uses_temp(name, "__tmp_target_value"):