# HG changeset patch # User Paul Boddie # Date 1479774538 -3600 # Node ID 1a64c775111a787b29d9a8cffaa54a43c690975d # Parent 793757c2cd670573874a59fd77b1db857b306f25 Fixed fragment allocation in the native functions and added some list and buffer operations, extending the buffer class. Eventually, buffer and list may be combined in some way. diff -r 793757c2cd67 -r 1a64c775111a lib/__builtins__/buffer.py --- a/lib/__builtins__/buffer.py Mon Nov 21 22:56:52 2016 +0100 +++ b/lib/__builtins__/buffer.py Tue Nov 22 01:28:58 2016 +0100 @@ -3,7 +3,7 @@ """ Buffer object. -Copyright (C) 2015 Paul Boddie +Copyright (C) 2015, 2016 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,9 +19,39 @@ this program. If not, see . """ +from native import _list_init, _list_append, _list_concat, _buffer_str + class buffer(object): - def __init__(self, size): pass - def append(self, s): pass - def __str__(self): pass + + "A buffer, used to build strings." + + def __init__(self, args=None, size=None): + + "Initialise a buffer from the given 'args' or the given 'size'." + + self.__data__ = _list_init(len(args) or size or 0) + + # Append all arguments in string form to the buffer. + + if args: + for arg in args: + _list_append(self, str(arg)) + + def append(self, s): + + "Append 's' to the buffer." + + if isinstance(s, buffer): + _list_concat(self, s) + elif isinstance(s, string): + _list_append(self, s) + else: + raise TypeError(s) + + def __str__(self): + + "Return a string representation." + + return _buffer_str(self) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 793757c2cd67 -r 1a64c775111a lib/__builtins__/list.py --- a/lib/__builtins__/list.py Mon Nov 21 22:56:52 2016 +0100 +++ b/lib/__builtins__/list.py Tue Nov 22 01:28:58 2016 +0100 @@ -31,9 +31,10 @@ "Initialise the list." - # Reserve space for a fragment reference. + # Reserve an attribute for a fragment reference along with some space + # for elements. - self.__data__ = native._list_init(len(args)) # reserve space for elements + self.__data__ = native._list_init(len(args)) if args is not None: self.extend(args) @@ -56,7 +57,13 @@ def __setslice__(self, start, end, slice): pass def __delslice__(self, start, end): pass - def append(self, value): pass + + def append(self, value): + + "Append 'value' to the list." + + native._list_append(self, value) + def insert(self, i, value): pass def extend(self, iterable): @@ -77,15 +84,38 @@ return native._list_len(self) def __add__(self, other): pass - def __iadd__(self, other): pass + + def __iadd__(self, other): + + "Concatenate 'other' to the list." + + if isinstance(other, list): + native._list_concat(self, other) + else: + self.extend(other) + return self def __str__(self): "Return a string representation of the list." - # NOTE: To be implemented, maybe using a buffer. + b = buffer() + i = 0 + l = self.__len__() + first = True + + # NOTE: Should really show quoted forms of the items. - return "[...]" + b.append("[") + while i < l: + if first: + first = False + else: + b.append(", ") + b.append(self.__get_single_item__(i)) + b.append("]") + + return str(b) def __bool__(self): diff -r 793757c2cd67 -r 1a64c775111a lib/native.py --- a/lib/native.py Mon Nov 21 22:56:52 2016 +0100 +++ b/lib/native.py Tue Nov 22 01:28:58 2016 +0100 @@ -52,10 +52,14 @@ def _str_nonempty(self): pass def _list_init(size): pass +def _list_append(self, value): pass +def _list_concat(self, other): pass def _list_len(self): pass def _list_nonempty(self): pass def _list_element(self, index): pass +def _buffer_str(self): pass + def _list_to_tuple(l): pass def _tuple_init(args, size): pass diff -r 793757c2cd67 -r 1a64c775111a templates/native.c --- a/templates/native.c Mon Nov 21 22:56:52 2016 +0100 +++ b/templates/native.c Tue Nov 22 01:28:58 2016 +0100 @@ -1,4 +1,4 @@ -#include /* calloc, exit */ +#include /* calloc, exit, realloc */ #include /* read, write */ #include /* ceil, log10, pow */ #include /* strcmp, strlen */ @@ -370,13 +370,73 @@ __attr __fn_native__list_init(__attr __args[]) { - #define size (__args[1]) - /* size.__data__ interpreted as fragment */ - __fragment *data = calloc(__load_via_object(size.value, __pos___data__).intvalue, sizeof(__attr)); + #define __size (__args[1]) + /* __size.__data__ interpreted as int */ + unsigned int n = __load_via_object(__size.value, __pos___data__).intvalue; + + /* Allocate space for the list. */ + __fragment *data = calloc(1, __FRAGMENT_SIZE(n)); __attr attr = {0, .data=data}; + /* The initial capacity is the same as the given size. */ + data->size = 0; + data->capacity = n; return attr; - #undef size + #undef __size +} + +__attr __fn_native__list_append(__attr __args[]) +{ + #define self (__args[1]) + #define __value (__args[2]) + /* self.__data__ interpreted as list */ + __fragment *data = __load_via_object(self.value, __pos___data__).data; + unsigned int size = data->size, capacity = data->capacity; + unsigned int n; + + /* Re-allocate the fragment if the capacity has been reached. */ + if (size >= capacity) + { + /* NOTE: Consider various restrictions on capacity increases. */ + n = data->capacity * 2; + data = realloc(data, __FRAGMENT_SIZE(n)); + data->capacity = n; + } + + /* Insert the new element and increment the list size. */ + data->attrs[size] = __value; + data->size = size + 1; + return __builtins___none_None; + #undef self + #undef __value +} + +__attr __fn_native__list_concat(__attr __args[]) +{ + #define self (__args[1]) + #define __other (__args[2]) + /* self.__data__, __other.__data__ interpreted as list */ + __fragment *data = __load_via_object(self.value, __pos___data__).data; + __fragment *other_data = __load_via_object(__other.value, __pos___data__).data; + unsigned int size = data->size, capacity = data->capacity; + unsigned int other_size = other_data->size; + unsigned int i, j, n; + + /* Re-allocate the fragment if the capacity has been reached. */ + if (size + other_size >= capacity) + { + n = size + other_size; + data = realloc(data, __FRAGMENT_SIZE(n)); + data->capacity = n; + } + + /* Copy the elements from the other list and increment the list size. */ + for (i = size, j = 0; j < other_size; i++, j++) + data->attrs[i] = other_data->attrs[j]; + data->size = n; + return __builtins___none_None; + #undef self + #undef __other } __attr __fn_native__list_len(__attr __args[]) @@ -421,6 +481,30 @@ #undef l } +__attr __fn_native__buffer_str(__attr __args[]) +{ + #define self (__args[1]) + /* self.__data__ interpreted as buffer */ + __fragment *data = __load_via_object(self.value, __pos___data__).data; + unsigned int size = 0, i, j; + char *s; + + /* Calculate the size of the string. */ + for (i = 0; i < data->size; i++) + size += strlen(data->attrs[i].strvalue); + + /* Reserve space for a new string. */ + s = calloc(size + 1, sizeof(char)); + + /* Build a single string from the buffer contents. */ + for (i = 0, j = 0; i < data->size; j += strlen(data->attrs[i].strvalue), i++) + strcpy(s + j, data->attrs[i].strvalue); + + /* Return a new string. */ + return __new_str(s); + #undef self +} + __attr __fn_native__tuple_init(__attr __args[]) { #define size (__args[1]) diff -r 793757c2cd67 -r 1a64c775111a templates/native.h --- a/templates/native.h Mon Nov 21 22:56:52 2016 +0100 +++ b/templates/native.h Tue Nov 22 01:28:58 2016 +0100 @@ -41,11 +41,15 @@ __attr __fn_native__str_nonempty(__attr __args[]); __attr __fn_native__list_init(__attr __args[]); +__attr __fn_native__list_append(__attr __args[]); +__attr __fn_native__list_concat(__attr __args[]); __attr __fn_native__list_len(__attr __args[]); __attr __fn_native__list_nonempty(__attr __args[]); __attr __fn_native__list_element(__attr __args[]); __attr __fn_native__list_to_tuple(__attr __args[]); +__attr __fn_native__buffer_str(__attr __args[]); + __attr __fn_native__tuple_init(__attr __args[]); __attr __fn_native__tuple_len(__attr __args[]); __attr __fn_native__tuple_element(__attr __args[]); diff -r 793757c2cd67 -r 1a64c775111a templates/progops.c --- a/templates/progops.c Mon Nov 21 22:56:52 2016 +0100 +++ b/templates/progops.c Tue Nov 22 01:28:58 2016 +0100 @@ -26,8 +26,9 @@ __attr __newdata(__attr args[], unsigned int number) { - /* Manually calculate the size of the fragment. */ - __fragment *data = (__fragment *) calloc(1, number * sizeof(__attr) + sizeof(unsigned int)); + /* Calculate the size of the fragment. */ + + __fragment *data = (__fragment *) calloc(1, __FRAGMENT_SIZE(number)); __attr attr = {0, .data=data}; unsigned int i, j; @@ -37,6 +38,7 @@ data->attrs[j] = args[i]; data->size = number; + data->capacity = number; return attr; } diff -r 793757c2cd67 -r 1a64c775111a templates/types.h --- a/templates/types.h Mon Nov 21 22:56:52 2016 +0100 +++ b/templates/types.h Tue Nov 22 01:28:58 2016 +0100 @@ -70,10 +70,12 @@ typedef struct __fragment { - unsigned int size; + unsigned int size, capacity; __attr attrs[]; } __fragment; +#define __FRAGMENT_SIZE(NUMBER) (NUMBER * sizeof(__attr) + 2 * sizeof(unsigned int)) + /* Special instance position value. The pos member of __obj refers to the special type attribute for classes, indicating which position holds the attribute describing the class type. For instances, it is set to zero. */ diff -r 793757c2cd67 -r 1a64c775111a tests/list.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/list.py Tue Nov 22 01:28:58 2016 +0100 @@ -0,0 +1,7 @@ +l = [1, 2, 3] +l.append(4) +print len(l) +print l[0] +print l[1] +print l[2] +print l[3]