Lichen

Annotated docs/wiki/Representations

850:6024d7e1d83a
2018-07-12 Paul Boddie Support trailing data after attributes in objects, employed by float instances to store their double-precision numeric data which needs more space than single attributes on some systems. In order to initialise such instances statically, specific object types must be indicated instead of the generic __obj type. This then requires casting to __ref of direct references to objects. Added an underflow error. Added initial testing of floating point numbers. trailing-data
paul@810 1
= Representing Program Objects =
paul@810 2
paul@810 3
Certain representations have been chosen for program objects that attempt to support efficient access to those objects during the execution of a program.
paul@810 4
paul@810 5
<<TableOfContents(2,2)>>
paul@810 6
paul@810 7
== Attributes ==
paul@810 8
paul@810 9
The principal means of referring to an object in a program is by using an '''attribute''', having this name because it is the representation of an attribute in classes, instances and modules. Each attribute can hold a reference to an object, known as the '''value''', or other kinds of data:
paul@810 10
paul@810 11
{{{#!graphviz
paul@810 12
//format=svg
paul@810 13
//transform=notugly
paul@810 14
digraph attributes {
paul@810 15
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Attributes"];
paul@810 16
  edge [fontsize="13.0",fontname="Helvetica",tooltip="Attributes"];
paul@810 17
  rankdir=TB;
paul@810 18
paul@810 19
  attrA [label="attribute | { value |<value> reference to object }",shape=record];
paul@810 20
  obj1 [label="<main> object | { attr1 | value } | { attr2 | value } | ...",shape=record];
paul@810 21
paul@810 22
  attrB [label="attribute | { intvalue |<intvalue> 12345 }",shape=record];
paul@810 23
paul@810 24
  attrA:value -> obj1:main;
paul@810 25
}
paul@810 26
}}}
paul@810 27
paul@810 28
Although a value indicates a specific object of interest for an attribute, if the object is callable then additional '''context''' information may be required to call the object. Such context information is not stored in an attribute record but is instead obtained from the object itself, if appropriate.
paul@810 29
paul@810 30
=== Integer Representation ===
paul@810 31
paul@810 32
The `intvalue` member of the attribute structure is employed instead of the `value` member to store integer values. Since `value` normally holds a pointer, and since pointers are often aligned to certain address boundaries on many modern platforms (usually four-byte boundaries on 32-bit platforms, eight-byte boundaries on 64-bit platforms, two-byte boundaries on platforms with 16-bit addressing), the lowest significant bit (bit 0) will typically be zero for a valid pointer. Consequently, by setting bit 0 to 1, other data can be stored in the remaining bits and be distinguished from pointer information. Obviously, operations on attributes first need to test whether the `value` member or the `intvalue` member is in use by testing bit 0.
paul@810 33
paul@810 34
Thus, integers are transformed and stored directly within attributes, and they are therefore passed around by value. When an attribute of an integer needs to be accessed, the operation usually providing the `value` member, thus obtaining an instance under normal circumstances, instead provides the address of a common integer instance. This instance may then provide instance attributes, whose values will be the same for all integers, or class attributes through a reference to the integer (`int`) class.
paul@810 35
paul@810 36
Each method provided by `int`, when called, will be given the original attribute for which the method was obtained as its context. In such methods, operations on the context via `self` will either involve the propagation of the attribute to other functions or methods or attribute accesses on `self`, yielding common instance attributes or class attributes as already described. Only native functions will attempt to interpret the attribute in a different way, decoding the representation, performing arithmetic or logical operations, and encoding the result in a new attribute.
paul@810 37
paul@810 38
== Contexts and Wrappers ==
paul@810 39
paul@810 40
The context of an object is of significance if that object is callable. For example, an instance may permit access to a method via an attribute. Since the method will be callable, and since the method is accessed via the instance, the context of that method will be the instance. In order to retain both context and value information, a '''wrapper''' may be created.
paul@810 41
paul@810 42
{{{#!graphviz
paul@810 43
//format=svg
paul@810 44
//transform=notugly
paul@810 45
digraph wrappers {
paul@810 46
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Wrappers"];
paul@810 47
  edge [fontsize="13.0",fontname="Helvetica",tooltip="Wrappers"];
paul@810 48
  rankdir=TB;
paul@810 49
paul@810 50
  inst [label="<main> instance | { attr1 |<attr1> reference to method } | { attr2 | value } | ...",shape=record];
paul@810 51
  method [label="<main> method | ...",shape=record];
paul@810 52
  wrapper [label="<main> wrapper | { __context__ |<context> reference to instance } | { __value__ |<value> reference to method } | ...",shape=record];
paul@810 53
paul@810 54
  inst:attr1 -> method:main;
paul@810 55
  wrapper:context -> inst:main;
paul@810 56
  wrapper:value -> method:main;
paul@810 57
}
paul@810 58
}}}
paul@810 59
paul@810 60
The context is not always the accessor of the object - in this case, the instance - because the object may already be a wrapper with its own context.
paul@810 61
paul@810 62
== Objects ==
paul@810 63
paul@810 64
Classes, instances and modules are objects, and all of these kinds of objects provide metadata describing the type of each object, together with a collection of attributes forming the contents of such objects.
paul@810 65
paul@810 66
{{{#!graphviz
paul@810 67
//format=svg
paul@810 68
//transform=notugly
paul@810 69
digraph objects {
paul@810 70
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Objects"];
paul@810 71
  edge [fontsize="13.0",fontname="Helvetica",tooltip="Objects"];
paul@810 72
  rankdir=TB;
paul@810 73
paul@810 74
  instC [label="<main> instance of C | { 0 | reference to\ninstance table } | { __class__ |<cls> reference\nto C } | { a | value } | { b | value } | ...",shape=record];
paul@810 75
  clsC [label="<main> class C | { class identifier | reference to\nclass table } | { __class__ |<cls> reference\nto type } | { __fn__ | instantiator\nreference } | { __args__ | reference to\nparameter table } | { f | <f> reference\nto f } | { g | value } | ...",shape=record];
paul@810 76
  methodF [label="<main> function f | { 0 | reference to\ninstance table } | { __class__ |<cls> reference\nto function } | { __fn__ | method\nreference } | { __args__ | reference to\nparameter table } | ...",shape=record];
paul@810 77
  function [label="<main> class function | { class identifier | reference to\nclass table } | { __class__ |<cls> reference\nto type } | ...",shape=record];
paul@810 78
  type [label="<main> class type | { class identifier | reference to\nclass table } | { __class__ |<cls> reference\nto type } | ...",shape=record];
paul@810 79
paul@810 80
  instC:cls -> clsC:main;
paul@810 81
  clsC:cls -> type:main;
paul@810 82
  clsC:f -> methodF:main;
paul@810 83
  methodF:cls -> function:main;
paul@810 84
}
paul@810 85
}}}
paul@810 86
paul@810 87
Classes are represented by structures whose members reference class attributes and class metadata (the class table), as well as incorporating invocation metadata (the `__args__` and `__fn__` special attributes).
paul@810 88
paul@810 89
Instances are represented by structures whose members reference instance attributes (including `__class__` which indicates the class instantiated by a given instance) and instance metadata (the instance table), as well as incorporating invocation metadata (the `__args__` and `__fn__` special attributes).
paul@810 90
paul@810 91
Functions are instances of a general function type that does not permit additional, general instance attributes. However, function instance structures may have extra members corresponding to default parameter values. Access to such extra members is performed using the minimum and maximum values provided via `__args__` and with knowledge of the number of declared instance attributes indicated by the instance table for the function type.
paul@810 92
paul@810 93
Modules are represented by structures whose members reference module attributes and module metadata (the module table).
paul@810 94
paul@810 95
== Special Members ==
paul@810 96
paul@810 97
All object representations support the following special members describing the invocation properties of each object:
paul@810 98
paul@810 99
{{{#!table
paul@810 100
`__args__` || the minimum number of arguments supported in an invocation and a reference to the parameter table for the object
paul@810 101
==
paul@810 102
`__fn__` || a reference to a native function containing the actual code run when calling the object
paul@810 103
}}}
paul@810 104
paul@810 105
Classes are invoked in order to create instances of each class ('''instantiation'''). Instances may support invocation by providing a `__call__` method. Functions are supported by instances of a general function class. Modules are generally not callable and will not actually provide these special members in practice.
paul@810 106
paul@810 107
All object representations support information about their type:
paul@810 108
paul@810 109
{{{#!table
paul@810 110
`__class__`
paul@810 111
|| the class of the object: instances refer to their classes, classes refer to the `type` class, functions are instances that refer to the `function` class, modules refer to the `module` class
paul@810 112
}}}
paul@810 113
paul@810 114
Certain kinds of object support other descriptive attributes:
paul@810 115
paul@810 116
{{{#!table
paul@810 117
`__name__` || the name of a class or a function
paul@810 118
==
paul@810 119
`__parent__` || the parent scope of a class or a function
paul@810 120
}}}
paul@810 121
paul@810 122
Objects supported by native, system-level functionality require a means of retaining information in special attributes:
paul@810 123
paul@810 124
{{{#!table
paul@810 125
`__data__` || private data manipulated at the native level
paul@810 126
}}}
paul@810 127
paul@810 128
Strings support special annotation attributes that permit their use in dynamically resolving attributes:
paul@810 129
paul@810 130
{{{#!table
paul@810 131
`__key__` || the code and position of the attribute whose name is represented by the string
paul@810 132
}}}
paul@810 133
paul@810 134
Such "key" attributes provide information that can be used to inspect an object table and to test for the presence of an attribute. With such information, the `getattr` and `hasattr` functions can be supported.
paul@810 135
paul@810 136
== Attribute Tables ==
paul@810 137
paul@810 138
In order to provide information about the attributes supported by each object, the structure of each object will reference a table containing entries describing these supported attributes. The size of this table is declared within the table structure, and for each position in the table an entry corresponding to the same position within an actual object structure describes the nature of the attribute at that position.
paul@810 139
paul@810 140
== Parameter Tables ==
paul@810 141
paul@810 142
In order to support argument validation and keyword arguments in invocations, a structure is referenced by `__args__` that indicates...
paul@810 143
paul@810 144
 * The minimum number of parameters supported by a callable
paul@810 145
 * The maximum number of parameters supported by a callable
paul@810 146
 * The size of the table describing the parameters
paul@810 147
 * A table of entries with each entry indicating the nature of a parameter (in effect, which name it uses, albeit as a generated code instead of a string) and the position of the parameter in any argument list prepared for an invocation
paul@810 148
paul@810 149
Parameter tables only need to be consulted at run-time if the nature of a callable is undetermined. By supporting a uniform interface, the arguments used in an invocation can be tested against the description provided by `__args__` and the table.