sonolus.py 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sonolus.py might be problematic. Click here for more details.

Files changed (72) hide show
  1. sonolus/backend/allocate.py +125 -51
  2. sonolus/backend/blocks.py +756 -756
  3. sonolus/backend/coalesce.py +85 -0
  4. sonolus/backend/constant_evaluation.py +374 -0
  5. sonolus/backend/dead_code.py +80 -0
  6. sonolus/backend/dominance.py +111 -0
  7. sonolus/backend/excepthook.py +37 -37
  8. sonolus/backend/finalize.py +69 -69
  9. sonolus/backend/flow.py +121 -92
  10. sonolus/backend/inlining.py +150 -0
  11. sonolus/backend/ir.py +5 -3
  12. sonolus/backend/liveness.py +173 -0
  13. sonolus/backend/mode.py +24 -24
  14. sonolus/backend/node.py +40 -40
  15. sonolus/backend/ops.py +197 -197
  16. sonolus/backend/optimize.py +37 -9
  17. sonolus/backend/passes.py +52 -6
  18. sonolus/backend/simplify.py +47 -30
  19. sonolus/backend/ssa.py +187 -0
  20. sonolus/backend/utils.py +48 -48
  21. sonolus/backend/visitor.py +892 -880
  22. sonolus/build/cli.py +7 -1
  23. sonolus/build/compile.py +88 -90
  24. sonolus/build/engine.py +55 -5
  25. sonolus/build/level.py +24 -23
  26. sonolus/build/node.py +43 -43
  27. sonolus/script/archetype.py +23 -6
  28. sonolus/script/array.py +2 -2
  29. sonolus/script/bucket.py +191 -191
  30. sonolus/script/callbacks.py +127 -115
  31. sonolus/script/comptime.py +1 -1
  32. sonolus/script/containers.py +23 -0
  33. sonolus/script/debug.py +19 -3
  34. sonolus/script/easing.py +323 -0
  35. sonolus/script/effect.py +131 -131
  36. sonolus/script/engine.py +37 -1
  37. sonolus/script/globals.py +269 -269
  38. sonolus/script/graphics.py +200 -150
  39. sonolus/script/instruction.py +151 -0
  40. sonolus/script/internal/__init__.py +5 -5
  41. sonolus/script/internal/builtin_impls.py +144 -144
  42. sonolus/script/internal/context.py +12 -4
  43. sonolus/script/internal/descriptor.py +17 -17
  44. sonolus/script/internal/introspection.py +14 -14
  45. sonolus/script/internal/native.py +40 -38
  46. sonolus/script/internal/value.py +3 -3
  47. sonolus/script/interval.py +120 -112
  48. sonolus/script/iterator.py +214 -211
  49. sonolus/script/math.py +30 -1
  50. sonolus/script/num.py +1 -1
  51. sonolus/script/options.py +191 -191
  52. sonolus/script/particle.py +157 -157
  53. sonolus/script/pointer.py +30 -30
  54. sonolus/script/{preview.py → print.py} +81 -81
  55. sonolus/script/random.py +14 -0
  56. sonolus/script/range.py +58 -58
  57. sonolus/script/record.py +3 -3
  58. sonolus/script/runtime.py +45 -6
  59. sonolus/script/sprite.py +333 -333
  60. sonolus/script/text.py +407 -407
  61. sonolus/script/timing.py +42 -42
  62. sonolus/script/transform.py +77 -23
  63. sonolus/script/ui.py +160 -160
  64. sonolus/script/vec.py +81 -72
  65. {sonolus_py-0.1.2.dist-info → sonolus_py-0.1.4.dist-info}/METADATA +1 -2
  66. sonolus_py-0.1.4.dist-info/RECORD +84 -0
  67. {sonolus_py-0.1.2.dist-info → sonolus_py-0.1.4.dist-info}/WHEEL +1 -1
  68. {sonolus_py-0.1.2.dist-info → sonolus_py-0.1.4.dist-info}/licenses/LICENSE +21 -21
  69. sonolus/build/defaults.py +0 -32
  70. sonolus/script/icon.py +0 -73
  71. sonolus_py-0.1.2.dist-info/RECORD +0 -76
  72. {sonolus_py-0.1.2.dist-info → sonolus_py-0.1.4.dist-info}/entry_points.txt +0 -0
@@ -1,112 +1,120 @@
1
- from typing import Self
2
-
3
- from sonolus.backend.ops import Op
4
- from sonolus.script.debug import error
5
- from sonolus.script.internal.native import native_function
6
- from sonolus.script.record import Record
7
-
8
-
9
- class Interval(Record):
10
- """A closed interval."""
11
-
12
- start: float
13
- end: float
14
-
15
- @property
16
- def length(self) -> float:
17
- return self.end - self.start
18
-
19
- @property
20
- def is_empty(self) -> bool:
21
- return self.start > self.end
22
-
23
- @property
24
- def mid(self) -> float:
25
- return (self.start + self.end) / 2
26
-
27
- @property
28
- def tuple(self):
29
- return self.start, self.end
30
-
31
- def __contains__(self, item: Self | float | int) -> bool:
32
- match item:
33
- case Interval(start, end):
34
- return self.start <= start and end <= self.end
35
- case float() | int() as value:
36
- return self.start <= value <= self.end
37
- case _:
38
- error("Invalid type for interval check")
39
-
40
- def __add__(self, other: float | int) -> Self:
41
- return Interval(self.start + other, self.end + other)
42
-
43
- def __sub__(self, other: float | int) -> Self:
44
- return Interval(self.start - other, self.end - other)
45
-
46
- def __mul__(self, other: float | int) -> Self:
47
- return Interval(self.start * other, self.end * other)
48
-
49
- def __truediv__(self, other: float | int) -> Self:
50
- return Interval(self.start / other, self.end / other)
51
-
52
- def __floordiv__(self, other: float | int) -> Self:
53
- return Interval(self.start // other, self.end // other)
54
-
55
- def __and__(self, other: Self) -> Self:
56
- return Interval(max(self.start, other.start), min(self.end, other.end))
57
-
58
- def shrink(self, value: float | int) -> Self:
59
- return Interval(self.start + value, self.end - value)
60
-
61
- def expand(self, value: float | int) -> Self:
62
- return Interval(self.start - value, self.end + value)
63
-
64
- def lerp(self, x: float, /) -> float:
65
- return lerp(self.start, self.end, x)
66
-
67
- def lerp_clamped(self, x: float, /) -> float:
68
- return lerp_clamped(self.start, self.end, x)
69
-
70
- def unlerp(self, x: float, /) -> float:
71
- return unlerp(self.start, self.end, x)
72
-
73
- def unlerp_clamped(self, x: float, /) -> float:
74
- return unlerp_clamped(self.start, self.end, x)
75
-
76
- def clamp(self, x: float, /) -> float:
77
- return clamp(x, self.start, self.end)
78
-
79
-
80
- @native_function(Op.Lerp)
81
- def lerp(a, b, x, /):
82
- return a + (b - a) * x
83
-
84
-
85
- @native_function(Op.LerpClamped)
86
- def lerp_clamped(a, b, x, /):
87
- return a + (b - a) * max(0, min(1, x))
88
-
89
-
90
- @native_function(Op.Unlerp)
91
- def unlerp(a, b, x, /):
92
- return (x - a) / (b - a)
93
-
94
-
95
- @native_function(Op.UnlerpClamped)
96
- def unlerp_clamped(a, b, x, /):
97
- return max(0, min(1, (x - a) / (b - a)))
98
-
99
-
100
- @native_function(Op.Remap)
101
- def remap(a, b, c, d, x, /):
102
- return c + (d - c) * (x - a) / (b - a)
103
-
104
-
105
- @native_function(Op.RemapClamped)
106
- def remap_clamped(a, b, c, d, x, /):
107
- return c + (d - c) * max(0, min(1, (x - a) / (b - a)))
108
-
109
-
110
- @native_function(Op.Clamp)
111
- def clamp(x, a, b, /):
112
- return max(a, min(b, x))
1
+ from typing import Self
2
+
3
+ from sonolus.backend.ops import Op
4
+ from sonolus.script.debug import error
5
+ from sonolus.script.internal.native import native_function
6
+ from sonolus.script.record import Record
7
+
8
+
9
+ class Interval(Record):
10
+ """A closed interval."""
11
+
12
+ start: float
13
+ end: float
14
+
15
+ @property
16
+ def length(self) -> float:
17
+ return self.end - self.start
18
+
19
+ @property
20
+ def is_empty(self) -> bool:
21
+ return self.start > self.end
22
+
23
+ @property
24
+ def mid(self) -> float:
25
+ return (self.start + self.end) / 2
26
+
27
+ @property
28
+ def tuple(self):
29
+ return self.start, self.end
30
+
31
+ def __contains__(self, item: Self | float | int) -> bool:
32
+ match item:
33
+ case Interval(start, end):
34
+ return self.start <= start and end <= self.end
35
+ case float() | int() as value:
36
+ return self.start <= value <= self.end
37
+ case _:
38
+ error("Invalid type for interval check")
39
+
40
+ def __add__(self, other: float | int) -> Self:
41
+ return Interval(self.start + other, self.end + other)
42
+
43
+ def __sub__(self, other: float | int) -> Self:
44
+ return Interval(self.start - other, self.end - other)
45
+
46
+ def __mul__(self, other: float | int) -> Self:
47
+ return Interval(self.start * other, self.end * other)
48
+
49
+ def __truediv__(self, other: float | int) -> Self:
50
+ return Interval(self.start / other, self.end / other)
51
+
52
+ def __floordiv__(self, other: float | int) -> Self:
53
+ return Interval(self.start // other, self.end // other)
54
+
55
+ def __and__(self, other: Self) -> Self:
56
+ return Interval(max(self.start, other.start), min(self.end, other.end))
57
+
58
+ def shrink(self, value: float | int) -> Self:
59
+ return Interval(self.start + value, self.end - value)
60
+
61
+ def expand(self, value: float | int) -> Self:
62
+ return Interval(self.start - value, self.end + value)
63
+
64
+ def lerp(self, x: float, /) -> float:
65
+ return lerp(self.start, self.end, x)
66
+
67
+ def lerp_clamped(self, x: float, /) -> float:
68
+ return lerp_clamped(self.start, self.end, x)
69
+
70
+ def unlerp(self, x: float, /) -> float:
71
+ return unlerp(self.start, self.end, x)
72
+
73
+ def unlerp_clamped(self, x: float, /) -> float:
74
+ return unlerp_clamped(self.start, self.end, x)
75
+
76
+ def clamp(self, x: float, /) -> float:
77
+ return clamp(x, self.start, self.end)
78
+
79
+
80
+ @native_function(Op.Lerp)
81
+ def lerp(a, b, x, /):
82
+ return a + (b - a) * x
83
+
84
+
85
+ @native_function(Op.LerpClamped)
86
+ def lerp_clamped(a, b, x, /):
87
+ return a + (b - a) * max(0, min(1, x))
88
+
89
+
90
+ @native_function(Op.Unlerp)
91
+ def unlerp(a, b, x, /):
92
+ return (x - a) / (b - a)
93
+
94
+
95
+ @native_function(Op.UnlerpClamped)
96
+ def unlerp_clamped(a, b, x, /):
97
+ return max(0, min(1, (x - a) / (b - a)))
98
+
99
+
100
+ @native_function(Op.Remap)
101
+ def remap(a, b, c, d, x, /):
102
+ return c + (d - c) * (x - a) / (b - a)
103
+
104
+
105
+ @native_function(Op.RemapClamped)
106
+ def remap_clamped(a, b, c, d, x, /):
107
+ return c + (d - c) * max(0, min(1, (x - a) / (b - a)))
108
+
109
+
110
+ @native_function(Op.Clamp)
111
+ def clamp(x, a, b, /):
112
+ return max(a, min(b, x))
113
+
114
+
115
+ def generic_lerp[T](a: T, b: T, x: float, /) -> T:
116
+ return a + (b - a) * x
117
+
118
+
119
+ def generic_lerp_clamped[T](a: T, b: T, x: float, /) -> T:
120
+ return a + (b - a) * max(0, min(1, x))
@@ -1,211 +1,214 @@
1
- from __future__ import annotations
2
-
3
- from abc import abstractmethod
4
- from collections.abc import Collection, Iterator
5
-
6
- from sonolus.script.num import Num
7
- from sonolus.script.record import Record
8
- from sonolus.script.values import copy
9
-
10
-
11
- class SonolusIterator[T](Iterator[T]):
12
- @abstractmethod
13
- def has_next(self) -> bool:
14
- raise NotImplementedError
15
-
16
- @abstractmethod
17
- def next(self) -> T:
18
- raise NotImplementedError
19
-
20
- def __next__(self) -> T:
21
- if not self.has_next():
22
- raise StopIteration
23
- return self.next()
24
-
25
-
26
- class ArrayLike[T](Collection):
27
- @abstractmethod
28
- def size(self) -> int:
29
- pass
30
-
31
- @abstractmethod
32
- def __getitem__(self, index: Num) -> T:
33
- pass
34
-
35
- @abstractmethod
36
- def __setitem__(self, index: Num, value: T):
37
- pass
38
-
39
- def __len__(self) -> int:
40
- return self.size()
41
-
42
- def __iter__(self) -> SonolusIterator[T]:
43
- return ArrayIterator(0, self)
44
-
45
- def __contains__(self, value: T) -> bool:
46
- i = 0
47
- while i < self.size():
48
- if self[i] == value:
49
- return True
50
- i += 1
51
- return False
52
-
53
- def reversed(self) -> ArrayLike[T]:
54
- return ArrayReverser(self)
55
-
56
- def iter(self) -> SonolusIterator[T]:
57
- return self.__iter__() # noqa: PLC2801
58
-
59
- def enumerate(self, start: Num = 0) -> SonolusIterator[T]:
60
- return ArrayEnumerator(0, start, self)
61
-
62
- def index_of(self, value: T, start: Num = 0) -> Num:
63
- i = start
64
- while i < self.size():
65
- if self[i] == value:
66
- return i
67
- i += 1
68
- return -1
69
-
70
- def last_index_of(self, value: T) -> Num:
71
- i = self.size() - 1
72
- while i >= 0:
73
- if self[i] == value:
74
- return i
75
- i -= 1
76
- return -1
77
-
78
- def index_of_max(self) -> Num:
79
- if self.size() == 0:
80
- return -1
81
- max_index = 0
82
- i = 1
83
- while i < self.size():
84
- if self[i] > self[max_index]:
85
- max_index = i
86
- i += 1
87
- return max_index
88
-
89
- def index_of_min(self) -> Num:
90
- if self.size() == 0:
91
- return -1
92
- min_index = 0
93
- i = 1
94
- while i < self.size():
95
- if self[i] < self[min_index]:
96
- min_index = i
97
- i += 1
98
- return min_index
99
-
100
- def max(self) -> T:
101
- return self[self.index_of_max()]
102
-
103
- def min(self) -> T:
104
- return self[self.index_of_min()]
105
-
106
- def swap(self, i: Num, j: Num):
107
- temp = copy(self[i])
108
- self[i] = self[j]
109
- self[j] = temp
110
-
111
- def sort(self, *, reverse: bool = False):
112
- if self.size() < 15:
113
- _insertion_sort(self, 0, self.size(), reverse)
114
- else:
115
- _heap_sort(self, 0, self.size(), reverse)
116
-
117
-
118
- def _insertion_sort[T](array: ArrayLike[T], start: Num, end: Num, reverse: bool):
119
- i = start + 1
120
- while i < end:
121
- value = copy(array[i])
122
- j = i - 1
123
- while j >= start and (array[j] > value) != reverse:
124
- array[j + 1] = array[j]
125
- j -= 1
126
- array[j + 1] = value
127
- i += 1
128
-
129
-
130
- def _heapify[T](array: ArrayLike[T], end: Num, index: Num, reverse: bool):
131
- while True:
132
- left = index * 2 + 1
133
- right = left + 1
134
- largest = index
135
- if left < end and (array[left] > array[largest]) != reverse:
136
- largest = left
137
- if right < end and (array[right] > array[largest]) != reverse:
138
- largest = right
139
- if largest == index:
140
- break
141
- array.swap(index, largest)
142
- index = largest
143
-
144
-
145
- # Heap sort is simple to implement iteratively without dynamic memory allocation
146
- def _heap_sort[T](array: ArrayLike[T], start: Num, end: Num, reverse: bool):
147
- i = end // 2 - 1
148
- while i >= start:
149
- _heapify(array, end, i, reverse)
150
- i -= 1
151
- i = end - 1
152
- while i > start:
153
- array.swap(start, i)
154
- _heapify(array, i, start, reverse)
155
- i -= 1
156
-
157
-
158
- class ArrayIterator[V: ArrayLike](Record, SonolusIterator):
159
- i: int
160
- array: V
161
-
162
- def has_next(self) -> bool:
163
- return self.i < self.array.size()
164
-
165
- def next(self) -> V:
166
- value = self.array[self.i]
167
- self.i += 1
168
- return value
169
-
170
-
171
- class ArrayReverser[V: ArrayLike](Record, ArrayLike):
172
- array: V
173
-
174
- def size(self) -> int:
175
- return self.array.size()
176
-
177
- def __getitem__(self, index: Num) -> V:
178
- return self.array[self.size() - 1 - index]
179
-
180
- def __setitem__(self, index: Num, value: V):
181
- self.array[self.size() - 1 - index] = value
182
-
183
-
184
- class Enumerator[V: SonolusIterator](Record, SonolusIterator):
185
- i: int
186
- offset: int
187
- iterator: V
188
-
189
- def has_next(self) -> bool:
190
- return self.iterator.has_next()
191
-
192
- def next(self):
193
- value = self.iterator.next()
194
- index = self.i + self.offset
195
- self.i += 1
196
- return index, value
197
-
198
-
199
- class ArrayEnumerator[V: ArrayLike](Record, SonolusIterator):
200
- i: int
201
- offset: int
202
- array: V
203
-
204
- def has_next(self) -> bool:
205
- return self.i < self.array.size()
206
-
207
- def next(self):
208
- value = self.array[self.i]
209
- index = self.i + self.offset
210
- self.i += 1
211
- return index, value
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+ from collections.abc import Collection, Iterator
5
+
6
+ from sonolus.script.num import Num
7
+ from sonolus.script.record import Record
8
+ from sonolus.script.values import copy
9
+
10
+
11
+ class SonolusIterator[T](Iterator[T]):
12
+ @abstractmethod
13
+ def has_next(self) -> bool:
14
+ raise NotImplementedError
15
+
16
+ @abstractmethod
17
+ def next(self) -> T:
18
+ raise NotImplementedError
19
+
20
+ def __next__(self) -> T:
21
+ if not self.has_next():
22
+ raise StopIteration
23
+ return self.next()
24
+
25
+
26
+ class ArrayLike[T](Collection):
27
+ @abstractmethod
28
+ def size(self) -> int:
29
+ pass
30
+
31
+ @abstractmethod
32
+ def __getitem__(self, index: Num) -> T:
33
+ pass
34
+
35
+ @abstractmethod
36
+ def __setitem__(self, index: Num, value: T):
37
+ pass
38
+
39
+ def __len__(self) -> int:
40
+ return self.size()
41
+
42
+ def __iter__(self) -> SonolusIterator[T]:
43
+ return ArrayIterator(0, self)
44
+
45
+ def __contains__(self, value: T) -> bool:
46
+ i = 0
47
+ while i < self.size():
48
+ if self[i] == value:
49
+ return True
50
+ i += 1
51
+ return False
52
+
53
+ def reversed(self) -> ArrayLike[T]:
54
+ return ArrayReverser(self)
55
+
56
+ def iter(self) -> SonolusIterator[T]:
57
+ return self.__iter__() # noqa: PLC2801
58
+
59
+ def enumerate(self, start: Num = 0) -> SonolusIterator[T]:
60
+ return ArrayEnumerator(0, start, self)
61
+
62
+ def index_of(self, value: T, start: Num = 0) -> Num:
63
+ i = start
64
+ while i < self.size():
65
+ if self[i] == value:
66
+ return i
67
+ i += 1
68
+ return -1
69
+
70
+ def last_index_of(self, value: T) -> Num:
71
+ i = self.size() - 1
72
+ while i >= 0:
73
+ if self[i] == value:
74
+ return i
75
+ i -= 1
76
+ return -1
77
+
78
+ def index_of_max(self) -> Num:
79
+ if self.size() == 0:
80
+ return -1
81
+ max_index = 0
82
+ i = 1
83
+ while i < self.size():
84
+ if self[i] > self[max_index]:
85
+ max_index = i
86
+ i += 1
87
+ return max_index
88
+
89
+ def index_of_min(self) -> Num:
90
+ if self.size() == 0:
91
+ return -1
92
+ min_index = 0
93
+ i = 1
94
+ while i < self.size():
95
+ if self[i] < self[min_index]:
96
+ min_index = i
97
+ i += 1
98
+ return min_index
99
+
100
+ def max(self) -> T:
101
+ return self[self.index_of_max()]
102
+
103
+ def min(self) -> T:
104
+ return self[self.index_of_min()]
105
+
106
+ def swap(self, i: Num, j: Num):
107
+ temp = copy(self[i])
108
+ self[i] = self[j]
109
+ self[j] = temp
110
+
111
+ def sort(self, *, reverse: bool = False):
112
+ if self.size() < 15:
113
+ _insertion_sort(self, 0, self.size(), reverse)
114
+ else:
115
+ _heap_sort(self, 0, self.size(), reverse)
116
+
117
+
118
+ def _insertion_sort[T](array: ArrayLike[T], start: Num, end: Num, reverse: bool):
119
+ i = start + 1
120
+ while i < end:
121
+ value = copy(array[i])
122
+ j = i - 1
123
+ while j >= start and (array[j] > value) != reverse:
124
+ array[j + 1] = array[j]
125
+ j -= 1
126
+ array[j + 1] = value
127
+ i += 1
128
+
129
+
130
+ def _heapify[T](array: ArrayLike[T], end: Num, index: Num, reverse: bool):
131
+ while True:
132
+ left = index * 2 + 1
133
+ right = left + 1
134
+ largest = index
135
+ if left < end and (array[left] > array[largest]) != reverse:
136
+ largest = left
137
+ if right < end and (array[right] > array[largest]) != reverse:
138
+ largest = right
139
+ if largest == index:
140
+ break
141
+ array.swap(index, largest)
142
+ index = largest
143
+
144
+
145
+ # Heap sort is simple to implement iteratively without dynamic memory allocation
146
+ def _heap_sort[T](array: ArrayLike[T], start: Num, end: Num, reverse: bool):
147
+ i = end // 2 - 1
148
+ while i >= start:
149
+ _heapify(array, end, i, reverse)
150
+ i -= 1
151
+ i = end - 1
152
+ while i > start:
153
+ array.swap(start, i)
154
+ _heapify(array, i, start, reverse)
155
+ i -= 1
156
+
157
+
158
+ class ArrayIterator[V: ArrayLike](Record, SonolusIterator):
159
+ i: int
160
+ array: V
161
+
162
+ def has_next(self) -> bool:
163
+ return self.i < self.array.size()
164
+
165
+ def next(self) -> V:
166
+ value = self.array[self.i]
167
+ self.i += 1
168
+ return value
169
+
170
+
171
+ class ArrayReverser[V: ArrayLike](Record, ArrayLike):
172
+ array: V
173
+
174
+ def size(self) -> int:
175
+ return self.array.size()
176
+
177
+ def __getitem__(self, index: Num) -> V:
178
+ return self.array[self.size() - 1 - index]
179
+
180
+ def __setitem__(self, index: Num, value: V):
181
+ self.array[self.size() - 1 - index] = value
182
+
183
+ def reversed(self) -> ArrayLike[V]:
184
+ return self.array
185
+
186
+
187
+ class Enumerator[V: SonolusIterator](Record, SonolusIterator):
188
+ i: int
189
+ offset: int
190
+ iterator: V
191
+
192
+ def has_next(self) -> bool:
193
+ return self.iterator.has_next()
194
+
195
+ def next(self):
196
+ value = self.iterator.next()
197
+ index = self.i + self.offset
198
+ self.i += 1
199
+ return index, value
200
+
201
+
202
+ class ArrayEnumerator[V: ArrayLike](Record, SonolusIterator):
203
+ i: int
204
+ offset: int
205
+ array: V
206
+
207
+ def has_next(self) -> bool:
208
+ return self.i < self.array.size()
209
+
210
+ def next(self):
211
+ value = self.array[self.i]
212
+ index = self.i + self.offset
213
+ self.i += 1
214
+ return index, value