1.1 --- a/encoders.py Sun Oct 30 22:33:22 2016 +0100
1.2 +++ b/encoders.py Mon Oct 31 18:26:36 2016 +0100
1.3 @@ -340,6 +340,14 @@
1.4 else:
1.5 return '"%s"' % str(value).replace('"', '\\"')
1.6
1.7 +def encode_literal_instantiator(path):
1.8 +
1.9 + """
1.10 + Encode a reference to an instantiator for a literal having the given 'path'.
1.11 + """
1.12 +
1.13 + return "__newliteral_%s" % encode_path(path)
1.14 +
1.15 def encode_literal_reference(n):
1.16
1.17 "Encode a reference to a literal constant with the number 'n'."
2.1 --- a/generator.py Sun Oct 30 22:33:22 2016 +0100
2.2 +++ b/generator.py Mon Oct 31 18:26:36 2016 +0100
2.3 @@ -23,7 +23,8 @@
2.4 from encoders import encode_bound_reference, encode_function_pointer, \
2.5 encode_instantiator_pointer, \
2.6 encode_literal_constant, encode_literal_constant_member, \
2.7 - encode_literal_constant_value, encode_literal_reference, \
2.8 + encode_literal_constant_value, \
2.9 + encode_literal_instantiator, encode_literal_reference, \
2.10 encode_path, \
2.11 encode_predefined_reference, encode_size, \
2.12 encode_symbol, encode_tablename, \
2.13 @@ -61,6 +62,12 @@
2.14 ("__builtins__.notimplemented", "NotImplemented"),
2.15 )
2.16
2.17 + literal_instantiator_types = (
2.18 + "__builtins__.dict.dict",
2.19 + "__builtins__.list.list",
2.20 + "__builtins__.tuple.tuple",
2.21 + )
2.22 +
2.23 def __init__(self, importer, optimiser, output):
2.24 self.importer = importer
2.25 self.optimiser = optimiser
2.26 @@ -120,7 +127,9 @@
2.27 """
2.28 print >>f_code, """\
2.29 #include <string.h>
2.30 +#include <stdio.h>
2.31 #include "types.h"
2.32 +#include "exceptions.h"
2.33 #include "ops.h"
2.34 #include "progconsts.h"
2.35 #include "progtypes.h"
2.36 @@ -201,13 +210,9 @@
2.37
2.38 init_ref = attrs["__init__"]
2.39
2.40 - # Signature: __attr __new_<name>(__attr[]);
2.41 -
2.42 - print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path)
2.43 -
2.44 # Write instantiator definitions.
2.45
2.46 - self.write_instantiator(f_code, path, init_ref)
2.47 + self.write_instantiator(f_code, f_signatures, path, init_ref)
2.48
2.49 # Write parameter table.
2.50
2.51 @@ -797,11 +802,12 @@
2.52 for name, default in self.importer.function_defaults.get(path):
2.53 structure.append(self.encode_member(path, name, default, "<instance>"))
2.54
2.55 - def write_instantiator(self, f_code, path, init_ref):
2.56 + def write_instantiator(self, f_code, f_signatures, path, init_ref):
2.57
2.58 """
2.59 - Write an instantiator to 'f_code' for instances of the class with the
2.60 - given 'path', with 'init_ref' as the initialiser function reference.
2.61 + Write an instantiator to 'f_code', with a signature to 'f_signatures',
2.62 + for instances of the class with the given 'path', with 'init_ref' as the
2.63 + initialiser function reference.
2.64
2.65 NOTE: This also needs to initialise any __fn__ and __args__ members
2.66 NOTE: where __call__ is provided by the class.
2.67 @@ -812,8 +818,13 @@
2.68 print >>f_code, """\
2.69 __attr %s(__attr __args[])
2.70 {
2.71 + /* Allocate the structure. */
2.72 __args[0] = __new(&%s, &%s, sizeof(%s));
2.73 +
2.74 + /* Call the initialiser. */
2.75 %s(__args);
2.76 +
2.77 + /* Return the allocated object details. */
2.78 return __args[0];
2.79 }
2.80 """ % (
2.81 @@ -824,6 +835,39 @@
2.82 encode_function_pointer(init_ref.get_origin())
2.83 )
2.84
2.85 + print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path)
2.86 +
2.87 + # Write additional literal instantiators. These do not call the
2.88 + # initialisers but instead populate the structures directly.
2.89 +
2.90 + if path in self.literal_instantiator_types:
2.91 + print >>f_code, """\
2.92 +__attr %s(__attr __args[], unsigned int number)
2.93 +{
2.94 + __attr data;
2.95 +
2.96 + /* Allocate the structure. */
2.97 + __args[0] = __new(&%s, &%s, sizeof(%s));
2.98 +
2.99 + /* Allocate a structure for the data. */
2.100 + data = __newdata(__args, number);
2.101 +
2.102 + /* Store a reference to the data in the object's __data__ attribute. */
2.103 + __store_via_object(__args[0].value, %s, data);
2.104 +
2.105 + /* Return the allocated object details. */
2.106 + return __args[0];
2.107 +}
2.108 +""" % (
2.109 + encode_literal_instantiator(path),
2.110 + encode_tablename("<instance>", path),
2.111 + encode_path(path),
2.112 + encode_symbol("obj", path),
2.113 + encode_symbol("pos", "__data__")
2.114 + )
2.115 +
2.116 + print >>f_signatures, "__attr %s(__attr[], unsigned int);" % encode_literal_instantiator(path)
2.117 +
2.118 def write_main_program(self, f_code, f_signatures):
2.119
2.120 """
2.121 @@ -833,7 +877,9 @@
2.122
2.123 print >>f_code, """\
2.124 int main(int argc, char *argv[])
2.125 -{"""
2.126 +{
2.127 + __Try
2.128 + {"""
2.129
2.130 for name in self.importer.modules.keys():
2.131 function_name = "__main_%s" % encode_path(name)
2.132 @@ -846,8 +892,14 @@
2.133 %s();""" % function_name
2.134
2.135 print >>f_code, """\
2.136 - __main___main__();
2.137 - return 0;
2.138 + __main___main__();
2.139 + return 0;
2.140 + }
2.141 + __Catch_anonymous
2.142 + {
2.143 + fprintf(stderr, "Program terminated due to exception.\\n");
2.144 + return 1;
2.145 + }
2.146 }
2.147 """
2.148
3.1 --- a/lib/__builtins__/list.py Sun Oct 30 22:33:22 2016 +0100
3.2 +++ b/lib/__builtins__/list.py Mon Oct 31 18:26:36 2016 +0100
3.3 @@ -31,13 +31,13 @@
3.4
3.5 "Initialise the list."
3.6
3.7 + # Reserve space for a fragment reference.
3.8 +
3.9 + self.__data__ = native._list_init(args) # reserve space for elements
3.10 +
3.11 if args is not None:
3.12 self.extend(args)
3.13
3.14 - # Reserve space for a fragment reference.
3.15 -
3.16 - self.__data__ = None
3.17 -
3.18 def __getitem__(self, index):
3.19
3.20 "Return the item or slice specified by 'index'."
4.1 --- a/lib/__builtins__/tuple.py Sun Oct 30 22:33:22 2016 +0100
4.2 +++ b/lib/__builtins__/tuple.py Mon Oct 31 18:26:36 2016 +0100
4.3 @@ -20,13 +20,18 @@
4.4 """
4.5
4.6 from __builtins__.iterator import listiterator
4.7 -from __builtins__.sequence import _getitem, _getslice, _tuple
4.8 +from __builtins__.sequence import _getitem, _getslice
4.9 +import native
4.10
4.11 class tuple(object):
4.12
4.13 "Implementation of tuple."
4.14
4.15 - def __init__(self, args): pass
4.16 + def __init__(self, args=None):
4.17 +
4.18 + "Initialise the tuple."
4.19 +
4.20 + self.__data__ = native._tuple_init(args) # allocate and copy elements
4.21
4.22 def __getitem__(self, index):
4.23
4.24 @@ -38,10 +43,16 @@
4.25
4.26 "Return a slice starting from 'start', with the optional 'end'."
4.27
4.28 - return _tuple(_getslice(self, start, end))
4.29 + return native._list_to_tuple(_getslice(self, start, end))
4.30 +
4.31 + def __len__(self):
4.32
4.33 - def __len__(self): pass
4.34 + "Return the length of the tuple."
4.35 +
4.36 + return native._tuple_len(self)
4.37 +
4.38 def __add__(self, other): pass
4.39 +
4.40 def __str__(self): pass
4.41
4.42 def __bool__(self):
4.43 @@ -58,6 +69,7 @@
4.44
4.45 # Special implementation methods.
4.46
4.47 - def __get_single_item__(self, index): pass
4.48 + def __get_single_item__(self, index):
4.49 + return native._tuple_element(self, index)
4.50
4.51 # vim: tabstop=4 expandtab shiftwidth=4
5.1 --- a/lib/native.py Sun Oct 30 22:33:22 2016 +0100
5.2 +++ b/lib/native.py Mon Oct 31 18:26:36 2016 +0100
5.3 @@ -48,10 +48,17 @@
5.4 def _str_len(self): pass
5.5 def _str_nonempty(self): pass
5.6
5.7 +def _list_init(args): pass
5.8 def _list_len(self): pass
5.9 def _list_nonempty(self): pass
5.10 def _list_element(self, index): pass
5.11
5.12 +def _list_to_tuple(l): pass
5.13 +
5.14 +def _tuple_init(args): pass
5.15 +def _tuple_len(self): pass
5.16 +def _tuple_element(self, index): pass
5.17 +
5.18 def _isinstance(obj, cls): pass
5.19
5.20 # vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/templates/progops.c Sun Oct 30 22:33:22 2016 +0100
6.2 +++ b/templates/progops.c Mon Oct 31 18:26:36 2016 +0100
6.3 @@ -21,6 +21,23 @@
6.4 return self;
6.5 }
6.6
6.7 +/* Generic internal data allocation. */
6.8 +
6.9 +__attr __newdata(__attr args[], unsigned int number)
6.10 +{
6.11 + __fragment *data = calloc(sizeof(__attr), number);
6.12 + __attr attr = {0, .data=data};
6.13 + unsigned int i, j;
6.14 +
6.15 + /* Copy the given number of values, starting from the second element. */
6.16 +
6.17 + for (i = 1, j = 0; i <= number; i++, j++)
6.18 + data->attrs[j] = args[i];
6.19 +
6.20 + data->size = number;
6.21 + return attr;
6.22 +}
6.23 +
6.24 /* Generic invocation operations. */
6.25
6.26 /* Invoke the given callable, supplying keyword argument details in the given
7.1 --- a/templates/progops.h Sun Oct 30 22:33:22 2016 +0100
7.2 +++ b/templates/progops.h Mon Oct 31 18:26:36 2016 +0100
7.3 @@ -5,6 +5,9 @@
7.4 /* Common operations. */
7.5
7.6 __attr __new(const __table *table, __ref cls, int size);
7.7 +
7.8 +__attr __newdata(__attr args[], unsigned int number);
7.9 +
7.10 __attr __invoke(__attr callable, int always_callable,
7.11 unsigned int nkwargs, __param kwcodes[], __attr kwargs[],
7.12 unsigned int nargs, __attr args[]);
7.13 @@ -16,5 +19,7 @@
7.14 /* Generic operations depending on specific program details. */
7.15
7.16 void __SETDEFAULT(__ref obj, int pos, __attr value);
7.17 +
7.18 __attr __GETDEFAULT(__ref obj, int pos);
7.19 +
7.20 int __BOOL(__attr attr);
8.1 --- a/templates/types.h Sun Oct 30 22:33:22 2016 +0100
8.2 +++ b/templates/types.h Mon Oct 31 18:26:36 2016 +0100
8.3 @@ -31,6 +31,7 @@
8.4 Attribute references are references to single attributes. */
8.5
8.6 typedef struct __obj __obj;
8.7 +typedef struct __fragment __fragment;
8.8
8.9 typedef struct __attr
8.10 {
8.11 @@ -49,9 +50,10 @@
8.12 const __ptable * ptable;/* parameter table */
8.13 struct __attr (*fn)(); /* callable details */
8.14
8.15 - int intvalue; /* integer value */
8.16 - double floatvalue; /* floating point value */
8.17 - char * strvalue; /* string value */
8.18 + int intvalue; /* integer value */
8.19 + double floatvalue; /* floating point value */
8.20 + char * strvalue; /* string value */
8.21 + __fragment * data; /* sequence data */
8.22 };
8.23 } __attr;
8.24
8.25 @@ -64,6 +66,14 @@
8.26
8.27 typedef __obj * __ref;
8.28
8.29 +/* Fragments are simple collections of attributes employed by sequence types. */
8.30 +
8.31 +typedef struct __fragment
8.32 +{
8.33 + unsigned int size;
8.34 + __attr attrs[];
8.35 +} __fragment;
8.36 +
8.37 /* Special instance position value. The pos member of __obj refers to the
8.38 special type attribute for classes, indicating which position holds the
8.39 attribute describing the class type. For instances, it is set to zero. */
9.1 --- a/translator.py Sun Oct 30 22:33:22 2016 +0100
9.2 +++ b/translator.py Mon Oct 31 18:26:36 2016 +0100
9.3 @@ -836,10 +836,20 @@
9.4 expr = self.process_structure_node(n.node)
9.5 objpath = expr.get_origin()
9.6 target = None
9.7 + literal_instantiation = False
9.8
9.9 # Obtain details of the callable.
9.10
9.11 - if objpath:
9.12 + # Literals may be instantiated specially.
9.13 +
9.14 + if expr.is_name() and expr.name.startswith("$L") and objpath:
9.15 + literal_instantiation = True
9.16 + parameters = None
9.17 + target = encode_literal_instantiator(objpath)
9.18 +
9.19 + # Identified targets employ function pointers directly.
9.20 +
9.21 + elif objpath:
9.22 parameters = self.importer.function_parameters.get(objpath)
9.23 if expr.has_kind("<class>"):
9.24 target = encode_instantiator_pointer(objpath)
9.25 @@ -847,6 +857,9 @@
9.26 elif expr.has_kind("<function>"):
9.27 target = encode_function_pointer(objpath)
9.28 target_structure = encode_path(objpath)
9.29 +
9.30 + # Other targets are retrieved at run-time.
9.31 +
9.32 else:
9.33 parameters = None
9.34
9.35 @@ -906,6 +919,12 @@
9.36 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0"
9.37 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0"
9.38
9.39 + # Where literal instantiation is occurring, add an argument indicating
9.40 + # the number of values.
9.41 +
9.42 + if literal_instantiation:
9.43 + argstr += ", %d" % (len(args) - 1)
9.44 +
9.45 # First, the invocation expression is presented.
9.46
9.47 stages = []
9.48 @@ -1260,6 +1279,9 @@
9.49 # Output generation.
9.50
9.51 def start_output(self):
9.52 +
9.53 + "Write the declarations at the top of each source file."
9.54 +
9.55 print >>self.out, """\
9.56 #include "types.h"
9.57 #include "exceptions.h"
9.58 @@ -1271,16 +1293,25 @@
9.59 """
9.60
9.61 def start_module(self):
9.62 +
9.63 + "Write the start of each module's main function."
9.64 +
9.65 print >>self.out, "void __main_%s()" % encode_path(self.name)
9.66 print >>self.out, "{"
9.67 self.indent += 1
9.68 self.write_temporaries()
9.69
9.70 def end_module(self):
9.71 +
9.72 + "End each module by closing its main function."
9.73 +
9.74 self.indent -= 1
9.75 print >>self.out, "}"
9.76
9.77 def start_function(self, name):
9.78 +
9.79 + "Start the function having the given 'name'."
9.80 +
9.81 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name)
9.82 print >>self.out, "{"
9.83 self.indent += 1
9.84 @@ -1311,17 +1342,30 @@
9.85 self.write_parameters(name, True)
9.86
9.87 def end_function(self, name):
9.88 +
9.89 + "End the function having the given 'name'."
9.90 +
9.91 self.write_parameters(name, False)
9.92 self.indent -= 1
9.93 print >>self.out, "}"
9.94 print >>self.out
9.95
9.96 def write_temporaries(self):
9.97 +
9.98 + "Write temporary storage employed by functions."
9.99 +
9.100 self.writeline("__ref __tmp_context, __tmp_value;")
9.101 self.writeline("__attr __tmp_target, __tmp_result;")
9.102 self.writeline("__exc __tmp_exc;")
9.103
9.104 def write_parameters(self, name, define=True):
9.105 +
9.106 + """
9.107 + For the function having the given 'name', write definitions of
9.108 + parameters found in the arguments array if 'define' is set to a true
9.109 + value, or write "undefinitions" if 'define' is set to a false value.
9.110 + """
9.111 +
9.112 parameters = self.importer.function_parameters[name]
9.113
9.114 # Generate any self reference.
9.115 @@ -1370,6 +1414,16 @@
9.116 for result in results:
9.117 self.statement(result)
9.118
9.119 + def writeline(self, s):
9.120 + print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1))
9.121 +
9.122 + def writestmt(self, s):
9.123 + print >>self.out
9.124 + self.writeline(s)
9.125 +
9.126 + def write_comment(self, s):
9.127 + self.writestmt("/* %s */" % s)
9.128 +
9.129 def pad(self, extra=0):
9.130 return (self.indent + extra) * self.tabstop
9.131
9.132 @@ -1384,14 +1438,4 @@
9.133 levels -= 1
9.134 return "\n".join(out)
9.135
9.136 - def writeline(self, s):
9.137 - print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1))
9.138 -
9.139 - def writestmt(self, s):
9.140 - print >>self.out
9.141 - self.writeline(s)
9.142 -
9.143 - def write_comment(self, s):
9.144 - self.writestmt("/* %s */" % s)
9.145 -
9.146 # vim: tabstop=4 expandtab shiftwidth=4