bolt_compute 0.0.3__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.
- bolt_compute-0.0.3.dist-info/METADATA +100 -0
- bolt_compute-0.0.3.dist-info/RECORD +4 -0
- bolt_compute-0.0.3.dist-info/WHEEL +4 -0
- bolt_compute.py +502 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: bolt_compute
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: >=3.14
|
|
6
|
+
Requires-Dist: beet>=0.116.0
|
|
7
|
+
Requires-Dist: bolt>=0.50.1
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# Bolt Compute
|
|
11
|
+
|
|
12
|
+
A [beet](https://github.com/mcbeet/beet) plugin that allows to use expressions instead of inline [number providers](https://minecraft.wiki/w/Number_provider).
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
In a beet project, use `uv add bolt_compute` and add the module in the require phase in your beet config:
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
require:
|
|
21
|
+
- bolt
|
|
22
|
+
- bolt_compute # <-- Add this line
|
|
23
|
+
pipeline:
|
|
24
|
+
- mecha
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Any place where the `compute` command/subcommand is used, you can use the `bolt` subcommand to use an expression instead of a number provider. For example, instead of:
|
|
30
|
+
|
|
31
|
+
```mcfunction
|
|
32
|
+
compute default {type:"minecraft:sum",operands:[1,1]}
|
|
33
|
+
data modify storage namespace:path path set compute default {type:"minecraft:sum",operands:[1,1]}
|
|
34
|
+
```
|
|
35
|
+
You can use:
|
|
36
|
+
|
|
37
|
+
```mcfunction
|
|
38
|
+
compute bolt (1 + 1)
|
|
39
|
+
data modify storage namespace:path path set compute bolt (1 + 1)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Literals values
|
|
43
|
+
|
|
44
|
+
Bolt compute supports the following literal values:
|
|
45
|
+
```mcfunction
|
|
46
|
+
compute bolt (storage namespace:path path) # compute default {type:"minecraft:storage",storage:"namespace:path",path:"path"}
|
|
47
|
+
|
|
48
|
+
x = 1 # bolt variable assignment
|
|
49
|
+
compute bolt (x + 1) # compute default {type:"minecraft:sum",operands:[1,1]}
|
|
50
|
+
|
|
51
|
+
y = "namespace:path_to_number_provider"
|
|
52
|
+
compute bolt (y * y) # compute default {type:"minecraft:product",operands:["namespace:path_to_number_provider","namespace:path_to_number_provider"]}
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Operators
|
|
57
|
+
|
|
58
|
+
`+`, `-`, `*`, are supported, as well as parentheses for grouping.
|
|
59
|
+
|
|
60
|
+
### Functions
|
|
61
|
+
|
|
62
|
+
Built-in functions are supported, such as :
|
|
63
|
+
- `average` expect a list using square brackets, e.g. `average([1,2,3])`
|
|
64
|
+
- `binomial` expect N and P, can be expressions, e.g. `binomial(10, 0.5)`
|
|
65
|
+
- `conditional` currently not implemented
|
|
66
|
+
- `maximum` expect a list using square brackets, e.g. `maximum([1,2,3])`
|
|
67
|
+
- `minimum` expect a list using square brackets, e.g. `minimum([1,2,3])`
|
|
68
|
+
- `uniform` expect two number providers, can be expressions, e.g. `uniform(1, 10)`
|
|
69
|
+
- `sum` expect a list using square brackets, e.g. `sum([1,2,3])`
|
|
70
|
+
- `product` expect a list using square brackets, e.g. `product([1,2,3])`
|
|
71
|
+
|
|
72
|
+
### Multiline expressions
|
|
73
|
+
|
|
74
|
+
Expressions can be multiline, for example:
|
|
75
|
+
|
|
76
|
+
```mcfunction
|
|
77
|
+
x = 1
|
|
78
|
+
y = 2
|
|
79
|
+
compute bolt (
|
|
80
|
+
x + y
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Full example
|
|
85
|
+
|
|
86
|
+
```mcfunction
|
|
87
|
+
|
|
88
|
+
x = "namespace:path_to_number_provider"
|
|
89
|
+
y = 256*256
|
|
90
|
+
|
|
91
|
+
data modify storage example:main result_bolt set compute bolt (
|
|
92
|
+
(storage example:main prod1)*(storage example:main prod2)*(storage example:main prod3)*2
|
|
93
|
+
*
|
|
94
|
+
2485*52+
|
|
95
|
+
maximum([0,1,(storage example:main prod2),1])+(143)-
|
|
96
|
+
(y*x) + x
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
More examples can be found in the [examples](examples) folder.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
bolt_compute.py,sha256=U20K8rZsyDkTgUqnRCuXTcmoLqHs96MZthy8irmLzzQ,17718
|
|
2
|
+
bolt_compute-0.0.3.dist-info/METADATA,sha256=i0-hn6UyBplikmiHOd_5bTNy6Om9y7XXID2xSJgBQ_4,2821
|
|
3
|
+
bolt_compute-0.0.3.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
4
|
+
bolt_compute-0.0.3.dist-info/RECORD,,
|
bolt_compute.py
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any, Callable, Generator, Literal, Optional, Self, Type, TypedDict, overload
|
|
3
|
+
|
|
4
|
+
from beet import Context
|
|
5
|
+
from beet.core.utils import JsonDict, required_field
|
|
6
|
+
from bolt import AstCall, AstFormatString, AstIdentifier, AstValue
|
|
7
|
+
from mecha import AbstractNode, AstNbtPath, AstNbtPathKey, AstNbtPathSubscript, AstNode, AstNumber, AstResourceLocation, Mecha, CommandTree, MultilineParser, NbtPathParser, Rule, delegate, rule
|
|
8
|
+
from mecha.utils import QuoteHelper, number_to_string
|
|
9
|
+
from bolt.pattern import STRING_PATTERN, RESOURCE_LOCATION_PATTERN
|
|
10
|
+
from tokenstream import TokenStream, Token, set_location, InvalidSyntax
|
|
11
|
+
|
|
12
|
+
FUNCTION_OVERRIDES = [
|
|
13
|
+
"average",
|
|
14
|
+
"binomial",
|
|
15
|
+
"conditional",
|
|
16
|
+
"maximum",
|
|
17
|
+
"minimum",
|
|
18
|
+
"uniform",
|
|
19
|
+
"sum",
|
|
20
|
+
"product",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
def iter_compute_tree(tree: CommandTree):
|
|
24
|
+
if tree.children:
|
|
25
|
+
compute = tree.children["compute"]
|
|
26
|
+
if compute.children:
|
|
27
|
+
yield compute
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
data = tree.children["data"]
|
|
31
|
+
if data.children:
|
|
32
|
+
modify = data.children["modify"]
|
|
33
|
+
if modify.children:
|
|
34
|
+
childs = [
|
|
35
|
+
"block",
|
|
36
|
+
"entity",
|
|
37
|
+
"storage",
|
|
38
|
+
]
|
|
39
|
+
for c in childs:
|
|
40
|
+
child = modify.children[c]
|
|
41
|
+
if child.children:
|
|
42
|
+
target = child.children["target"]
|
|
43
|
+
if target.children:
|
|
44
|
+
targetPath = target.children["targetPath"]
|
|
45
|
+
if targetPath.children:
|
|
46
|
+
for o in [
|
|
47
|
+
"append",
|
|
48
|
+
"merge",
|
|
49
|
+
"prepend",
|
|
50
|
+
"set",
|
|
51
|
+
]:
|
|
52
|
+
operation = targetPath.children[o]
|
|
53
|
+
if operation.children:
|
|
54
|
+
compute = operation.children["compute"]
|
|
55
|
+
yield compute
|
|
56
|
+
insert = targetPath.children["insert"]
|
|
57
|
+
if insert.children:
|
|
58
|
+
index = insert.children["index"]
|
|
59
|
+
if index.children:
|
|
60
|
+
compute = index.children["compute"]
|
|
61
|
+
yield compute
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class MutableDepth:
|
|
65
|
+
value: int
|
|
66
|
+
|
|
67
|
+
@dataclass(frozen=True, slots=True)
|
|
68
|
+
class AstComputeStorage(AstNode):
|
|
69
|
+
"""Ast bolt compute storage node."""
|
|
70
|
+
storage: AstComputeResourceLocation = required_field()
|
|
71
|
+
path: AstNbtPath = required_field()
|
|
72
|
+
depth: MutableDepth = required_field()
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def from_value(
|
|
76
|
+
cls,
|
|
77
|
+
storage: AstComputeResourceLocation,
|
|
78
|
+
path: AstNbtPath,
|
|
79
|
+
depth: int,
|
|
80
|
+
) -> AstComputeStorage:
|
|
81
|
+
"""Return a bool node from the given value."""
|
|
82
|
+
return AstComputeStorage(storage=storage, path=path, depth=MutableDepth(depth))
|
|
83
|
+
|
|
84
|
+
@dataclass(frozen=True, slots=True)
|
|
85
|
+
class AstComputeBoltValue(AstNode):
|
|
86
|
+
value: AstNode = required_field()
|
|
87
|
+
depth: MutableDepth = required_field()
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def from_value(
|
|
91
|
+
cls,
|
|
92
|
+
value: AstNode,
|
|
93
|
+
depth: int,
|
|
94
|
+
) -> Self:
|
|
95
|
+
return cls(value=value, depth=MutableDepth(depth))
|
|
96
|
+
|
|
97
|
+
@dataclass(frozen=True, slots=True)
|
|
98
|
+
class AstComputeListCall(AstNode):
|
|
99
|
+
type: str = required_field()
|
|
100
|
+
operands: list[ValueType] = required_field()
|
|
101
|
+
depth: MutableDepth = required_field()
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def from_value(
|
|
105
|
+
cls,
|
|
106
|
+
type: str,
|
|
107
|
+
operands: list[ValueType],
|
|
108
|
+
depth: int,
|
|
109
|
+
) -> Self:
|
|
110
|
+
"""Return a bool node from the given value."""
|
|
111
|
+
return cls(type=type, operands=operands, depth=MutableDepth(depth))
|
|
112
|
+
|
|
113
|
+
@dataclass(frozen=True, slots=True)
|
|
114
|
+
class AstComputeBinomial(AstNode):
|
|
115
|
+
n: ValueType = required_field()
|
|
116
|
+
p: ValueType = required_field()
|
|
117
|
+
depth: MutableDepth = required_field()
|
|
118
|
+
|
|
119
|
+
@classmethod
|
|
120
|
+
def from_value(
|
|
121
|
+
cls,
|
|
122
|
+
n: ValueType,
|
|
123
|
+
p: ValueType,
|
|
124
|
+
depth: int,
|
|
125
|
+
) -> Self:
|
|
126
|
+
return cls(n=n, p=p, depth=MutableDepth(depth))
|
|
127
|
+
|
|
128
|
+
@dataclass(frozen=True, slots=True)
|
|
129
|
+
class AstComputeUniform(AstNode):
|
|
130
|
+
minimum: ValueType = required_field()
|
|
131
|
+
maximum: ValueType = required_field()
|
|
132
|
+
depth: MutableDepth = required_field()
|
|
133
|
+
|
|
134
|
+
@classmethod
|
|
135
|
+
def from_value(
|
|
136
|
+
cls,
|
|
137
|
+
minimum: ValueType,
|
|
138
|
+
maximum: ValueType,
|
|
139
|
+
depth: int,
|
|
140
|
+
) -> Self:
|
|
141
|
+
return cls(minimum=minimum, maximum=maximum, depth=MutableDepth(depth))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass(frozen=True, slots=True)
|
|
147
|
+
class AstComputeNumber(AstNode):
|
|
148
|
+
value: AstNumber = required_field()
|
|
149
|
+
depth: MutableDepth = required_field()
|
|
150
|
+
|
|
151
|
+
@classmethod
|
|
152
|
+
def from_value(
|
|
153
|
+
cls,
|
|
154
|
+
value: Any,
|
|
155
|
+
depth: int,
|
|
156
|
+
) -> Self:
|
|
157
|
+
"""Return a bool node from the given value."""
|
|
158
|
+
return cls(value=AstNumber.from_value(value), depth=MutableDepth(depth))
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
type AstComputeSource = AstComputeStorage # future AstScoreStorage
|
|
163
|
+
|
|
164
|
+
type ValueType = AstComputeOperation | AstComputeResourceLocation | AstComputeNumber | AstComputeSource | AstComputeBoltValue
|
|
165
|
+
type Operation = Literal["+", "-", "/", "*"]
|
|
166
|
+
|
|
167
|
+
@dataclass(frozen=True, slots=True)
|
|
168
|
+
class AstBoltComputeRoot(AstNode):
|
|
169
|
+
children: AstComputeOperation = required_field()
|
|
170
|
+
|
|
171
|
+
@dataclass(frozen=True, slots=True)
|
|
172
|
+
class AstComputeResourceLocation(AstNode):
|
|
173
|
+
resource_location: AstResourceLocation = required_field()
|
|
174
|
+
depth: MutableDepth = required_field()
|
|
175
|
+
|
|
176
|
+
@classmethod
|
|
177
|
+
def from_value(cls, value: Any, depth: int) -> "AstComputeResourceLocation":
|
|
178
|
+
return AstComputeResourceLocation(resource_location=AstResourceLocation.from_value(value), depth=MutableDepth(depth))
|
|
179
|
+
|
|
180
|
+
@dataclass(frozen=True, slots=True)
|
|
181
|
+
class AstComputeOperation(AstNode):
|
|
182
|
+
"""Ast bolt compute node."""
|
|
183
|
+
|
|
184
|
+
lvalue: ValueType = required_field()
|
|
185
|
+
operation: Optional[Operation] = required_field()
|
|
186
|
+
rvalue: Optional[ValueType] = required_field()
|
|
187
|
+
|
|
188
|
+
depth: MutableDepth = required_field()
|
|
189
|
+
|
|
190
|
+
parser = "bolt_compute:parse_operation"
|
|
191
|
+
|
|
192
|
+
@classmethod
|
|
193
|
+
def from_value(
|
|
194
|
+
cls,
|
|
195
|
+
lvalue: ValueType,
|
|
196
|
+
operation: Optional[Operation] = None,
|
|
197
|
+
rvalue: Optional[ValueType] = None,
|
|
198
|
+
depth: int = 0,
|
|
199
|
+
) -> AstComputeOperation:
|
|
200
|
+
"""Return a bool node from the given value."""
|
|
201
|
+
return AstComputeOperation(lvalue=lvalue, operation=operation, rvalue=rvalue, depth=MutableDepth(depth))
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def parse_operation(stream: TokenStream, depth: int) -> AstComputeOperation:
|
|
205
|
+
"""Parse operations with correct precedence: additive (lower) then multiplicative (higher)."""
|
|
206
|
+
return parse_additive(stream, depth)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def parse_additive(stream: TokenStream, depth: int) -> AstComputeOperation:
|
|
210
|
+
"""Parse additive operations (+, -) - lowest precedence."""
|
|
211
|
+
lvalue = parse_multiplicative(stream, depth)
|
|
212
|
+
|
|
213
|
+
while True:
|
|
214
|
+
with stream.alternative():
|
|
215
|
+
token = stream.expect("additive")
|
|
216
|
+
rvalue = parse_multiplicative(stream, depth+1)
|
|
217
|
+
op: Operation = token.value # pyright: ignore[reportAssignmentType]
|
|
218
|
+
lvalue = AstComputeOperation.from_value(lvalue, op, rvalue, depth=depth)
|
|
219
|
+
lvalue.lvalue.depth.value +=1
|
|
220
|
+
continue
|
|
221
|
+
break
|
|
222
|
+
|
|
223
|
+
return lvalue
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def parse_multiplicative(stream: TokenStream, depth: int) -> AstComputeOperation:
|
|
227
|
+
"""Parse multiplicative operations (*, /) - highest precedence."""
|
|
228
|
+
lvalue = parse_primary(stream, depth)
|
|
229
|
+
|
|
230
|
+
while True:
|
|
231
|
+
with stream.alternative():
|
|
232
|
+
token = stream.expect("multiplicative")
|
|
233
|
+
rvalue = parse_primary(stream, depth+1)
|
|
234
|
+
op: Operation = token.value # pyright: ignore[reportAssignmentType]
|
|
235
|
+
lvalue = AstComputeOperation.from_value(lvalue, op, rvalue, depth=depth)
|
|
236
|
+
lvalue.lvalue.depth.value +=1
|
|
237
|
+
continue
|
|
238
|
+
break
|
|
239
|
+
|
|
240
|
+
return lvalue
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def parse_primary(stream: TokenStream, depth: int) -> ValueType:
|
|
244
|
+
"""Parse primary expressions (literals, parenthesized expressions, function calls)."""
|
|
245
|
+
with stream.checkpoint() as commit:
|
|
246
|
+
stream.expect("oparent")
|
|
247
|
+
result = parse_additive(stream, depth=depth)
|
|
248
|
+
stream.expect("cparent")
|
|
249
|
+
commit()
|
|
250
|
+
return result
|
|
251
|
+
|
|
252
|
+
return parse_literal(stream, depth=depth)
|
|
253
|
+
|
|
254
|
+
def parse_list(stream: TokenStream, depth: int):
|
|
255
|
+
"""Parse a comma-separated list of expressions inside brackets."""
|
|
256
|
+
stream.expect("obracket")
|
|
257
|
+
values: list[ValueType] = []
|
|
258
|
+
while True:
|
|
259
|
+
with stream.checkpoint() as commit:
|
|
260
|
+
stream.expect("cbracket")
|
|
261
|
+
commit()
|
|
262
|
+
break
|
|
263
|
+
values.append(parse_operation(stream, depth=depth+1))
|
|
264
|
+
follow = stream.expect_any("comma", "cbracket")
|
|
265
|
+
match follow:
|
|
266
|
+
case Token("cbracket"):
|
|
267
|
+
break
|
|
268
|
+
case Token("comma"):
|
|
269
|
+
...
|
|
270
|
+
return values
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def parse_literal(stream: TokenStream, depth: int = 0) -> ValueType:
|
|
274
|
+
bolt_expression_parser = delegate("bolt:primary")
|
|
275
|
+
with stream.checkpoint() as commit:
|
|
276
|
+
bolt_node: AstNode = bolt_expression_parser(stream)
|
|
277
|
+
# parse and return value type
|
|
278
|
+
if isinstance(bolt_node, AstValue):
|
|
279
|
+
if isinstance(bolt_node.value, (float, int)):
|
|
280
|
+
commit()
|
|
281
|
+
return AstComputeNumber.from_value(bolt_node.value, depth=depth)
|
|
282
|
+
elif isinstance(bolt_node.value, str):
|
|
283
|
+
commit()
|
|
284
|
+
return AstComputeResourceLocation.from_value(bolt_node.value, depth=depth)
|
|
285
|
+
elif isinstance(bolt_node, AstIdentifier):
|
|
286
|
+
commit()
|
|
287
|
+
return AstComputeBoltValue.from_value(bolt_node, depth=depth)
|
|
288
|
+
elif isinstance(bolt_node, AstFormatString):
|
|
289
|
+
commit()
|
|
290
|
+
return AstComputeBoltValue.from_value(bolt_node, depth=depth)
|
|
291
|
+
elif isinstance(bolt_node, AstCall):
|
|
292
|
+
if isinstance(bolt_node.value, AstIdentifier) and bolt_node.value.value in FUNCTION_OVERRIDES:
|
|
293
|
+
raise InvalidSyntax(f"Python built-in sum collide with bolt_compute sum")
|
|
294
|
+
commit()
|
|
295
|
+
return AstComputeBoltValue.from_value(bolt_node, depth=depth)
|
|
296
|
+
|
|
297
|
+
raise NotImplementedError(bolt_node)
|
|
298
|
+
|
|
299
|
+
stream.crop()
|
|
300
|
+
token = stream.expect_any("oparent", "number", "quotes", "storage", "call")
|
|
301
|
+
match token:
|
|
302
|
+
case Token("oparent"):
|
|
303
|
+
return parse_operation(stream, depth=depth+1)
|
|
304
|
+
case Token("number"):
|
|
305
|
+
return AstComputeNumber.from_value(token.value, depth=depth)
|
|
306
|
+
case Token("quotes"):
|
|
307
|
+
res: AstResourceLocation = delegate("resource_location")(stream)
|
|
308
|
+
stream.expect("quotes")
|
|
309
|
+
return AstComputeResourceLocation.from_value(res, depth=depth)
|
|
310
|
+
case Token("storage"):
|
|
311
|
+
storage: AstComputeResourceLocation = delegate("resource_location")(stream)
|
|
312
|
+
parser = delegate("nbt_path")
|
|
313
|
+
path: AstNbtPath = parser(stream)
|
|
314
|
+
return AstComputeStorage.from_value(storage, path, depth=depth)
|
|
315
|
+
case Token("call"):
|
|
316
|
+
if token.value in ["maximum", "minimum", "average", "sum", "product"]:
|
|
317
|
+
stream.expect("oparent")
|
|
318
|
+
values = parse_list(stream, depth+1)
|
|
319
|
+
if len(values) == 0:
|
|
320
|
+
raise InvalidSyntax(f"Function {token.value} require at least one argument")
|
|
321
|
+
stream.expect("cparent")
|
|
322
|
+
return AstComputeListCall.from_value(token.value, values, depth)
|
|
323
|
+
elif token.value == "binomial":
|
|
324
|
+
stream.expect("oparent")
|
|
325
|
+
N = parse_literal(stream, depth=depth+1)
|
|
326
|
+
stream.expect("comma")
|
|
327
|
+
P = parse_literal(stream, depth=depth+1)
|
|
328
|
+
cparent, comma = stream.expect("cparent", "comma")
|
|
329
|
+
if comma: stream.expect("cparent")
|
|
330
|
+
return AstComputeBinomial.from_value(N, P, depth)
|
|
331
|
+
elif token.value == "uniform":
|
|
332
|
+
stream.expect("oparent")
|
|
333
|
+
minimum = parse_literal(stream, depth=depth+1)
|
|
334
|
+
stream.expect("comma")
|
|
335
|
+
maximum = parse_literal(stream, depth=depth+1)
|
|
336
|
+
cparent, comma = stream.expect("cparent", "comma")
|
|
337
|
+
if comma: stream.expect("cparent")
|
|
338
|
+
return AstComputeUniform.from_value(minimum, maximum, depth)
|
|
339
|
+
|
|
340
|
+
raise NotImplementedError(token.value)
|
|
341
|
+
|
|
342
|
+
raise NotImplementedError("UNREACHABLE")
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def operation_parser(stream: TokenStream):
|
|
347
|
+
"""Parse operation."""
|
|
348
|
+
with stream.syntax(
|
|
349
|
+
bolt="bolt"
|
|
350
|
+
):
|
|
351
|
+
stream.expect("bolt")
|
|
352
|
+
with stream.syntax(
|
|
353
|
+
oparent=r"\(",
|
|
354
|
+
cparent=r"\)",
|
|
355
|
+
obracket=r"\[",
|
|
356
|
+
cbracket=r"\]",
|
|
357
|
+
comma=r",",
|
|
358
|
+
equal=r"=",
|
|
359
|
+
additive=r"\+|\-",
|
|
360
|
+
multiplicative=r"\*|\/",
|
|
361
|
+
number=r"[+-]?([0-9]*[.])?[0-9]+",
|
|
362
|
+
storage=r"storage",
|
|
363
|
+
call="|".join(FUNCTION_OVERRIDES),
|
|
364
|
+
quotes=r'"',
|
|
365
|
+
resource=RESOURCE_LOCATION_PATTERN,
|
|
366
|
+
name=r'[a-z]([a-z0-9]+)?'
|
|
367
|
+
):
|
|
368
|
+
stream.expect("oparent")
|
|
369
|
+
operation = parse_operation(stream, depth=0)
|
|
370
|
+
stream.expect("cparent", "end")
|
|
371
|
+
return AstBoltComputeRoot(children=operation)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
@rule(AstComputeOperation)
|
|
376
|
+
def serialize_operation(node: AstComputeOperation, result: list[str]):
|
|
377
|
+
if node.lvalue and not node.rvalue:
|
|
378
|
+
assert node.operation is None
|
|
379
|
+
yield node.lvalue
|
|
380
|
+
elif node.lvalue and node.rvalue:
|
|
381
|
+
assert node.operation is not None
|
|
382
|
+
match node.operation:
|
|
383
|
+
case "+":
|
|
384
|
+
result.append('{type:"minecraft:sum",operands:[')
|
|
385
|
+
yield node.lvalue
|
|
386
|
+
result.append(',')
|
|
387
|
+
yield node.rvalue
|
|
388
|
+
result.append(']}')
|
|
389
|
+
case "-":
|
|
390
|
+
result.append('{type:"minecraft:sum",operands:[')
|
|
391
|
+
yield node.lvalue
|
|
392
|
+
result.append(',')
|
|
393
|
+
result.append('{type:"minecraft:product",operands:[-1')
|
|
394
|
+
result.append(',')
|
|
395
|
+
yield node.rvalue
|
|
396
|
+
result.append(']}')
|
|
397
|
+
result.append(']}')
|
|
398
|
+
case "*":
|
|
399
|
+
result.append('{type:"minecraft:product",operands:[')
|
|
400
|
+
yield node.lvalue
|
|
401
|
+
result.append(',')
|
|
402
|
+
yield node.rvalue
|
|
403
|
+
result.append(']}')
|
|
404
|
+
case _:
|
|
405
|
+
raise NotImplementedError()
|
|
406
|
+
|
|
407
|
+
@rule(AstBoltComputeRoot)
|
|
408
|
+
def serialize_root(node: AstBoltComputeRoot, result: list[str]):
|
|
409
|
+
result.append("default")
|
|
410
|
+
result.append(" ")
|
|
411
|
+
yield node.children
|
|
412
|
+
|
|
413
|
+
@rule(AstComputeResourceLocation)
|
|
414
|
+
def serialize_resource_location(node: AstComputeResourceLocation, result: list[str]):
|
|
415
|
+
if node.depth.value != 0: result.append('"')
|
|
416
|
+
result.append(node.resource_location.get_canonical_value())
|
|
417
|
+
if node.depth.value != 0: result.append('"')
|
|
418
|
+
|
|
419
|
+
@rule(AstComputeStorage)
|
|
420
|
+
def serialize_storage(node: AstComputeStorage, result: list[str]):
|
|
421
|
+
result.append('{type:"minecraft:storage",storage:"')
|
|
422
|
+
yield node.storage
|
|
423
|
+
result.append('",path:"')
|
|
424
|
+
yield node.path
|
|
425
|
+
result.append('"}')
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
@rule(AstComputeBoltValue)
|
|
429
|
+
def serialize_bolt_value(node: AstComputeBoltValue, result: list[str]):
|
|
430
|
+
if isinstance(node.value, (float, int)):
|
|
431
|
+
yield AstComputeNumber.from_value(node.value, node.depth.value)
|
|
432
|
+
elif isinstance(node.value, str):
|
|
433
|
+
a = AstComputeResourceLocation.from_value(node.value, node.depth.value)
|
|
434
|
+
yield a
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
@rule(AstComputeListCall)
|
|
438
|
+
def serialize_list_call(node: AstComputeListCall, result: list[str]):
|
|
439
|
+
result.append('{type:"minecraft:')
|
|
440
|
+
result.append(node.type)
|
|
441
|
+
result.append('",operands:[')
|
|
442
|
+
sep = ""
|
|
443
|
+
for children in node.operands:
|
|
444
|
+
result.append(sep)
|
|
445
|
+
sep = ","
|
|
446
|
+
yield children
|
|
447
|
+
result.append(']}')
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
@rule(AstComputeNumber)
|
|
453
|
+
def serialize_compute_number(node: AstComputeNumber, result: list[str]):
|
|
454
|
+
if node.depth.value == 0: result.append('{type:"minecraft:constant",value:')
|
|
455
|
+
yield node.value
|
|
456
|
+
if node.depth.value == 0: result.append('}')
|
|
457
|
+
|
|
458
|
+
@rule(AstComputeBinomial)
|
|
459
|
+
def serialize_compute_binomial(node: AstComputeBinomial, result: list[str]):
|
|
460
|
+
result.append('{type:"minecraft:binomial",n:')
|
|
461
|
+
yield node.n
|
|
462
|
+
result.append(',p:')
|
|
463
|
+
yield node.p
|
|
464
|
+
result.append('}')
|
|
465
|
+
|
|
466
|
+
@rule(AstComputeUniform)
|
|
467
|
+
def serialize_compute_uniform(node: AstComputeUniform, result: list[str]):
|
|
468
|
+
result.append('{type:"minecraft:uniform",min:')
|
|
469
|
+
yield node.minimum
|
|
470
|
+
result.append(',max:')
|
|
471
|
+
yield node.maximum
|
|
472
|
+
result.append('}')
|
|
473
|
+
|
|
474
|
+
def beet_default(ctx: Context):
|
|
475
|
+
mc = ctx.inject(Mecha)
|
|
476
|
+
mc.spec.parsers["command:argument:minecraft:number_provider"] = MultilineParser(delegate("resource_location_or_nbt"))
|
|
477
|
+
rules = [
|
|
478
|
+
serialize_operation,
|
|
479
|
+
serialize_resource_location,
|
|
480
|
+
serialize_root,
|
|
481
|
+
serialize_storage,
|
|
482
|
+
serialize_bolt_value,
|
|
483
|
+
serialize_compute_number,
|
|
484
|
+
serialize_list_call,
|
|
485
|
+
serialize_compute_binomial,
|
|
486
|
+
serialize_compute_uniform,
|
|
487
|
+
]
|
|
488
|
+
for r in rules:
|
|
489
|
+
mc.serialize.add_rule(r)
|
|
490
|
+
|
|
491
|
+
for compute in iter_compute_tree(mc.spec.tree):
|
|
492
|
+
if compute.children:
|
|
493
|
+
compute.children["bolt"] = CommandTree(**{
|
|
494
|
+
"type": "argument",
|
|
495
|
+
"executable": True,
|
|
496
|
+
"parser": "bolt_compute:operation_parser"
|
|
497
|
+
})
|
|
498
|
+
|
|
499
|
+
mc.spec.parsers["command:argument:bolt_compute:operation_parser"] = MultilineParser(operation_parser)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
mc.spec.update()
|