forked from svaarala/duktape
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtypealgorithms.html
More file actions
242 lines (211 loc) · 12.7 KB
/
Copy pathtypealgorithms.html
File metadata and controls
242 lines (211 loc) · 12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
<h1 id="typealgorithms">Type algorithms</h1>
<p>This section describes how type-related Ecmascript algorithms
like comparisons and coercions are extended to Duktape custom types.
Duktape specific type algorithms (<code>ToBuffer()</code> and <code>ToPointer()</code>)
are also discussed.</p>
<h2>Notation</h2>
<p>The following shorthand is used to indicate how values are compared:</p>
<table class="typeshorthand">
<thead>
<tr><th>Value</th><th>Description</th></tr>
</thead>
<tbody>
<tr><td>t</td><td>compares to true</td></tr>
<tr><td>f</td><td>compares to false</td></tr>
<tr><td>s</td><td>simple compare: boolean-to-boolean, string-to-string (string contents compared), buffer-to-buffer
(buffer contents compared), buffer-to-string (buffer and string contents compared)</td></tr>
<tr><td>n</td><td>number compare: NaN values compare false, zeroes compare true regardless of sign (e.g. +0 == -0)</td></tr>
<tr><td>N</td><td>number compare in SameValue: NaN values compare true, zeroes compare with sign (e.g. SameValue(+0,-0) is false)</td></tr>
<tr><td>p</td><td>heap pointer compare</td></tr>
<tr><td>1</td><td>string/buffer vs. number: coerce string with ToNumber() and retry comparison; a buffer is first
coerced to string and then to number (e.g. buffer with "2.5" coerces eventually to number 2.5)</td></tr>
<tr><td>2</td><td>boolean vs. any: coerce boolean with ToNumber() and retry comparison</td></tr>
<tr><td>3</td><td>object vs. string/number/buffer: coerce object with ToPrimitive() and retry comparison</td></tr>
</tbody>
</table>
<h2 id="non-strict-equality-algorithm">Equality (non-strict)</h2>
<p>Non-strict equality comparison is specified in
<a href="http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3">The Abstract Equality Comparison Algorithm</a>
for standard types. Custom type behavior is as follows:</p>
<ul>
<li>Buffer: buffer contents are compared byte-by-byte, buffer values containing
the same byte sequence compare equal. This comparison is potentially expensive.
(String comparison also compares contents, but because Duktape uses string
interning, string content comparison is a cheap pointer compare. This is
not the case for buffers.)</li>
<li>Pointer: comparison against any other type returns false. Comparison to a
pointer returns true if and only if the pointer values are the same. Note
in particular that comparing a number to a pointer returns false. This seems
a bit unintuitive, but numbers cannot represent 64-pointers accurately,
comparing numbers and pointers might be error prone.</li>
</ul>
<p>The standard behavior as well as behavior for Duktape custom types is summarized in the table below:</p>
<table class="typecomparison">
<thead>
<tr><th> </th><th>und</th><th>nul</th><th>boo</th><th>num</th><th>str</th><th>obj</th><th>buf</th><th>ptr</th></tr>
</thead>
<tbody>
<tr><th>und</th><td>t </td><td>t </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>nul</th><td> </td><td>t </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>boo</th><td> </td><td> </td><td>s </td><td>2 </td><td>2 </td><td>2 </td><td>2 </td><td>f </td></tr>
<tr><th>num</th><td> </td><td> </td><td> </td><td>n </td><td>1 </td><td>3 </td><td>1 </td><td>f </td></tr>
<tr><th>str</th><td> </td><td> </td><td> </td><td> </td><td>s </td><td>3 </td><td>s </td><td>f </td></tr>
<tr><th>obj</th><td> </td><td> </td><td> </td><td> </td><td> </td><td>p </td><td>3 </td><td>f </td></tr>
<tr><th>buf</th><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td>s </td><td>f </td></tr>
<tr><th>ptr</th><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td>s </td></tr>
</tbody>
</table>
<h2 id="strict-equality-algorithm">Strict equality</h2>
<p>Strict equality is much more straightforward and preferable whenever
possible for simplicity and performance. It is described in
<a href="http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.6">The Strict Equality Comparison Algorithm</a>
for standard types. Custom type behavior is as follows:</p>
<ul>
<li>Buffer: compared as heap pointers. Buffer contents are not compared,
so this comparison is always fast. Note that this behavior is
inconsistent with string comparison behavior: string contents are
compared even with strict equality (this is fast, however, due to
string interning). This is intentional, as it is important to be
able to compare buffer values quickly.</li>
<li>Pointer: like non-strict equality.</li>
</ul>
<p>The standard behavior as well as behavior for Duktape custom types is summarized in the table below:</p>
<table class="typecomparison">
<thead>
<tr><th> </th><th>und</th><th>nul</th><th>boo</th><th>num</th><th>str</th><th>obj</th><th>buf</th><th>ptr</th></tr>
</thead>
<tbody>
<tr><th>und</th><td>t </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>nul</th><td> </td><td>t </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>boo</th><td> </td><td> </td><td>s </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>num</th><td> </td><td> </td><td> </td><td>n </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>str</th><td> </td><td> </td><td> </td><td> </td><td>s </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>obj</th><td> </td><td> </td><td> </td><td> </td><td> </td><td>p </td><td>f </td><td>f </td></tr>
<tr><th>buf</th><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td>p </td><td>f </td></tr>
<tr><th>ptr</th><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td>s </td></tr>
</tbody>
</table>
<h2 id="samevalue-algorithm">SameValue</h2>
<p>The <code>SameValue</code> algorithm is not easy to invoke from user code.
It is used by e.g. <code>Object.defineProperty()</code> when checking whether
a property value is about to change. SameValue is even stricter than a
strict equality comparison, and most notably differs in how numbers are compared.
It is specified in
<a href="http://www.ecma-international.org/ecma-262/5.1/#sec-9.12">The SameValue algorithm</a>
for standard types. Custom type behavior is as follows:</p>
<ul>
<li>Buffer: like strict equality.</li>
<li>Pointer: like non-strict (and strict) equality.</li>
</ul>
<p>The standard behavior as well as behavior for Duktape custom types is summarized in the table below:</p>
<table class="typecomparison">
<thead>
<tr><th> </th><th>und</th><th>nul</th><th>boo</th><th>num</th><th>str</th><th>obj</th><th>buf</th><th>ptr</th></tr>
</thead>
<tbody>
<tr><th>und</th><td>t </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>nul</th><td> </td><td>t </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>boo</th><td> </td><td> </td><td>s </td><td>f </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>num</th><td> </td><td> </td><td> </td><td>N </td><td>f </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>str</th><td> </td><td> </td><td> </td><td> </td><td>s </td><td>f </td><td>f </td><td>f </td></tr>
<tr><th>obj</th><td> </td><td> </td><td> </td><td> </td><td> </td><td>p </td><td>f </td><td>f </td></tr>
<tr><th>buf</th><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td>p </td><td>f </td></tr>
<tr><th>ptr</th><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td>s </td></tr>
</tbody>
</table>
<h2>Type conversion and testing</h2>
<p>The custom types behave as follows for Ecmascript coercions described
<a href="http://www.ecma-international.org/ecma-262/5.1/#sec-9">Type Conversion and Testing</a>
(except SameValue which was already covered above):</p>
<table>
<thead>
<tr><th> </th><th>buffer</th><th>pointer</th></tr>
</thead>
<tbody>
<tr><th>ToPrimitive</th><td>identity</td><td>identity</td></tr>
<tr><th>ToBoolean</th><td>false for zero-size buffer, true otherwise</td><td>false for NULL pointer, true otherwise</td></tr>
<tr><th>ToNumber</th><td>like ToNumber() for a string</td><td>0 for NULL pointer, 1 otherwise</td></tr>
<tr><th>ToInteger</th><td>same as ToNumber</td><td>same as ToNumber</td></tr>
<tr><th>ToInt32</th><td>same as ToNumber</td><td>same as ToNumber</td></tr>
<tr><th>ToUint32</th><td>same as ToNumber</td><td>same as ToNumber</td></tr>
<tr><th>ToUint16</th><td>same as ToNumber</td><td>same as ToNumber</td></tr>
<tr><th>ToString</th><td>string with bytes from buffer data</td><td><code>sprintf()</code> with <code>%p</code> format (platform specific)</td></tr>
<tr><th>ToObject</th><td>Buffer object</td><td>Pointer object</td></tr>
<tr><th>CheckObjectCoercible</th><td>allow (no error)</td><td>allow (no error)</td></tr>
<tr><th>IsCallable</th><td>false</td><td>false</td></tr>
<tr><th>SameValue</th><td>(covered above)</td><td>(covered above)</td></tr>
</tbody>
</table>
<p>When a buffer is string coerced, the bytes from the buffer are used
directly as string data. The bytes will then be interpreted as CESU-8
(or extended UTF-8) from Ecmascript point of view.</p>
<h2>Custom coercions (ToBuffer, ToPointer)</h2>
<p>ToBuffer() coercion is used when a value is forced into a buffer
type e.g. with the <code>duk_to_buffer()</code> API call. The coercion
is as follows:</p>
<ul>
<li>A buffer coerces to itself (identity). The same buffer value is
returned.</li>
<li>Any other type (including pointer) is first string coerced with
<a href="http://www.ecma-international.org/ecma-262/5.1/#sec-9.8">ToString</a>,
and the resulting string is then copied, byte-by-byte, into a
fixed-size buffer.</li>
</ul>
<p>ToPointer() coercion is used e.g. by the <code>duk_to_pointer()</code>
call. The coercion is as follows:</p>
<ul>
<li>A pointer coerces to itself.</li>
<li>Heap-allocated types (string, object, buffer) coerce to a pointer value
pointing to their <b>internal heap header</b>. This pointer has only a
diagnostic value. Note, in particular, that the pointer returned for a
buffer or a string <b>does not</b> point to the buffer/string data area.
(This coercion is likely to change.)</li>
<li>Any other types (including number) coerce to a NULL pointer.</li>
</ul>
<p>The following table summarizes how different types are handled:</p>
<table>
<thead>
<tr><th> </th><th>ToBuffer</th><th>ToPointer</th></tr>
</thead>
<tbody>
<tr><th>undefined</th><td>buffer with "undefined"</td><td>NULL</td></tr>
<tr><th>null</th><td>buffer with "null"</td><td>NULL</td></tr>
<tr><th>boolean</th><td>buffer with "true" or "false"</td><td>NULL</td></tr>
<tr><th>number</th><td>buffer with string coerced number</td><td>NULL</td></tr>
<tr><th>string</th><td>buffer with copy of string data</td><td>ptr to heap hdr</td></tr>
<tr><th>object</th><td>buffer with ToString(value)</td><td>ptr to heap hdr</td></tr>
<tr><th>buffer</th><td>identity</td><td>ptr to heap hdr</td></tr>
<tr><th>pointer</th><td><code>sprintf()</code> with <code>%p</code> format (platform specific)</td><td>identity</td></tr>
</tbody>
</table>
<h2>Addition</h2>
<p>The Ecmascript addition operator is specified in
<a href="http://www.ecma-international.org/ecma-262/5.1/#sec-11.6.1">The Addition operator (+)</a>.
Addition behaves specially if either argument is a string: the other argument
is coerced to a string and the strings are then concatenated. This behavior
is extended to custom types as follows:</p>
<ul>
<li>As for standard types, object values are first coerced with <code>ToPrimitive()</code>,
e.g. a <code>Buffer</code> object is converted to a plain buffer value.</li>
<li>The string concatenation rule is triggered if either argument is a string
or a buffer. The arguments are coerced to strings and then concatenated into
the result string. This means that adding two buffers currently results in a
string, not a buffer.</li>
<li>Pointer types fall into the default number addition case. They are coerced
with <code>ToNumber()</code> and then added as numbers. NULL pointers coerce to
0, non-NULL pointers to 1, so addition results may not be very intuitive.</li>
</ul>
<h2>Property access</h2>
<p>If a plain buffer or pointer is used as a property access base value,
properties are looked up from the (initial) built-in prototype object
(<code>Duktape.Buffer.prototype</code> or <code>Duktape.Pointer.prototype</code>).
This mimics the behavior of standard types.</p>
<p>For example:</p>
<pre>
duk> buf = Duktape.dec('hex', '414243'); // plain buffer
= ABC
duk> buf.toString;
= function toString() {/* native code */}
duk> typeof buf.toString();
= string
</pre>