1use crate::error::DecodeError;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum Opcode {
14 Motion(MotionOpcode),
16
17 Looks(LooksOpcode),
19
20 Sound(SoundOpcode),
22
23 Events(EventsOpcode),
25
26 Control(ControlOpcode),
28
29 Sensing(SensingOpcode),
31
32 Operators(OperatorsOpcode),
34
35 Data(DataOpcode),
37
38 Procedures(ProceduresOpcode),
40}
41
42impl std::str::FromStr for Opcode {
43 type Err = DecodeError;
44
45 fn from_str(input: &str) -> Result<Self, Self::Err> {
46 let parts: Vec<&str> = input.splitn(2, '_').collect();
47 if parts.len() != 2 {
48 return Err(DecodeError::InvalidData(format!("Invalid opcode format: {}", input)));
49 }
50 let category = parts[0];
51 match category {
52 "motion" => Ok(Opcode::Motion(input.parse()?)),
53 "looks" => Ok(Opcode::Looks(input.parse()?)),
54 "sound" => Ok(Opcode::Sound(input.parse()?)),
55 "event" => Ok(Opcode::Events(input.parse()?)),
56 "control" => Ok(Opcode::Control(input.parse()?)),
57 "sensing" => Ok(Opcode::Sensing(input.parse()?)),
58 "operator" => Ok(Opcode::Operators(input.parse()?)),
59 "data" => Ok(Opcode::Data(input.parse()?)),
60 "procedures" => Ok(Opcode::Procedures(input.parse()?)),
61 _ => Err(DecodeError::Unknown("opcode category".to_string(), category.to_string())),
62 }
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
68pub enum MotionOpcode {
69 MoveSteps,
70 TurnRight,
71 TurnLeft,
72 GoTo,
73 GoToXY,
74 GlideTo,
75 GlideToXY,
76 PointInDirection,
77 PointTowards,
78 ChangeXBy,
79 SetXTo,
80 ChangeYBy,
81 SetYTo,
82 IfOnEdgeBounce,
83 SetRotationStyle,
84 XPosition,
85 YPosition,
86 Direction,
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub enum LooksOpcode {
92 SayForSeconds,
93 Say,
94 ThinkForSeconds,
95 Think,
96 SwitchCostumeTo,
97 NextCostume,
98 SwitchBackdropTo,
99 SwitchBackdropToAndWait,
100 NextBackdrop,
101 ChangeSizeBy,
102 SetSizeTo,
103 ChangeEffectBy,
104 SetEffectTo,
105 ClearGraphicEffects,
106 Show,
107 Hide,
108 GoToLayer,
109 GoLayers,
110 Costume,
111 Backdrop,
112 Size,
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
117pub enum SoundOpcode {
118 PlaySoundUntilDone,
119 StartSound,
120 StopAllSounds,
121 ChangeEffectBy,
122 SetEffectTo,
123 ClearSoundEffects,
124 ChangeVolumeBy,
125 SetVolumeTo,
126 Volume,
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
131pub enum EventsOpcode {
132 WhenFlagClicked,
133 WhenKeyPressed,
134 WhenThisSpriteClicked,
135 WhenStageClicked,
136 WhenBackdropSwitchesTo,
137 WhenGreaterThan,
138 WhenIReceive,
139 Broadcast,
140 BroadcastAndWait,
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
145pub enum ControlOpcode {
146 Wait,
147 Repeat,
148 Forever,
149 If,
150 IfElse,
151 WaitUntil,
152 RepeatUntil,
153 Stop,
154 WhenIStartAsAClone,
155 CreateCloneOf,
156 DeleteThisClone,
157}
158
159#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
161pub enum SensingOpcode {
162 Touching,
163 TouchingColor,
164 ColorTouchingColor,
165 DistanceTo,
166 AskAndWait,
167 Answer,
168 KeyPressed,
169 MouseDown,
170 MouseX,
171 MouseY,
172 SetDragMode,
173 Loudness,
174 Timer,
175 ResetTimer,
176 Of,
177 Current,
178 DaysSince2000,
179 Username,
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
184pub enum OperatorsOpcode {
185 Add,
186 Subtract,
187 Multiply,
188 Divide,
189 Random,
190 GreaterThan,
191 LessThan,
192 Equals,
193 And,
194 Or,
195 Not,
196 Join,
197 LetterOf,
198 Length,
199 Contains,
200 Mod,
201 Round,
202 MathOp,
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
207pub enum DataOpcode {
208 Variable,
209 SetVariableTo,
210 ChangeVariableBy,
211 ShowVariable,
212 HideVariable,
213 List,
214 AddToList,
215 DeleteOfList,
216 DeleteAllOfList,
217 InsertInList,
218 ReplaceItemInList,
219 ItemOfList,
220 ItemNumOfList,
221 LengthOfList,
222 ListContainsItem,
223 ShowList,
224 HideList,
225}
226
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
229pub enum ProceduresOpcode {
230 Define,
231 Call,
232 ArgumentStringNumber,
233 ArgumentBoolean,
234}
235
236macro_rules! impl_from_str {
237 ($enum:ty, $prefix:literal { $($opcode:literal => $variant:ident),* $(,)? }) => {
238 impl std::str::FromStr for $enum {
239 type Err = DecodeError;
240
241 fn from_str(input: &str) -> Result<Self, Self::Err> {
242 match input {
243 $(
244 concat!($prefix, "_", $opcode) => Ok(<$enum>::$variant),
245 )*
246 _ => Err(DecodeError::Unknown("opcode".to_string(), input.to_string()))
247 }
248 }
249 }
250 };
251}
252
253impl_from_str!(MotionOpcode, "motion" {
254 "movesteps" => MoveSteps,
255 "turnright" => TurnRight,
256 "turnleft" => TurnLeft,
257 "goto" => GoTo,
258 "gotoxy" => GoToXY,
259 "glideto" => GlideTo,
260 "glidesecstoxy" => GlideToXY,
261 "pointindirection" => PointInDirection,
262 "pointtowards" => PointTowards,
263 "changexby" => ChangeXBy,
264 "setx" => SetXTo,
265 "changeyby" => ChangeYBy,
266 "sety" => SetYTo,
267 "ifonedgebounce" => IfOnEdgeBounce,
268 "setrotationstyle" => SetRotationStyle,
269 "xposition" => XPosition,
270 "yposition" => YPosition,
271 "direction" => Direction,
272});
273
274impl_from_str!(LooksOpcode, "looks" {
275 "sayforsecs" => SayForSeconds,
276 "say" => Say,
277 "thinkforsecs" => ThinkForSeconds,
278 "think" => Think,
279 "switchcostumeto" => SwitchCostumeTo,
280 "nextcostume" => NextCostume,
281 "switchbackdropto" => SwitchBackdropTo,
282 "switchbackdroptoandwait" => SwitchBackdropToAndWait,
283 "nextbackdrop" => NextBackdrop,
284 "changesizeby" => ChangeSizeBy,
285 "setsizeto" => SetSizeTo,
286 "changeeffectby" => ChangeEffectBy,
287 "seteffectto" => SetEffectTo,
288 "cleargraphiceffects" => ClearGraphicEffects,
289 "show" => Show,
290 "hide" => Hide,
291 "gotofrontback" => GoToLayer,
292 "goforwardbackwardlayers" => GoLayers,
293 "costumenumbername" => Costume,
294 "backdropnumbername" => Backdrop,
295 "size" => Size,
296});
297
298impl_from_str!(SoundOpcode, "sound" {
299 "playuntildone" => PlaySoundUntilDone,
300 "play" => StartSound,
301 "stopallsounds" => StopAllSounds,
302 "changeeffectby" => ChangeEffectBy,
303 "seteffectto" => SetEffectTo,
304 "cleareffects" => ClearSoundEffects,
305 "changevolumeby" => ChangeVolumeBy,
306 "setvolumeto" => SetVolumeTo,
307 "volume" => Volume,
308});
309
310impl_from_str!(EventsOpcode, "event" {
311 "whenflagclicked" => WhenFlagClicked,
312 "whenkeypressed" => WhenKeyPressed,
313 "whenthisspriteclicked" => WhenThisSpriteClicked,
314 "whenstageclicked" => WhenStageClicked,
315 "whenbackdropswitchesto" => WhenBackdropSwitchesTo,
316 "whengreaterthan" => WhenGreaterThan,
317 "whenbroadcastreceived" => WhenIReceive,
318 "broadcast" => Broadcast,
319 "broadcastandwait" => BroadcastAndWait,
320});
321
322impl_from_str!(ControlOpcode, "control" {
323 "wait" => Wait,
324 "repeat" => Repeat,
325 "forever" => Forever,
326 "if" => If,
327 "if_else" => IfElse,
328 "wait_until" => WaitUntil,
329 "repeat_until" => RepeatUntil,
330 "stop" => Stop,
331 "start_as_clone" => WhenIStartAsAClone,
332 "create_clone_of" => CreateCloneOf,
333 "delete_this_clone" => DeleteThisClone,
334});
335
336impl_from_str!(SensingOpcode, "sensing" {
337 "touchingobject" => Touching,
338 "touchingcolor" => TouchingColor,
339 "coloristouchingcolor" => ColorTouchingColor,
340 "distanceto" => DistanceTo,
341 "askandwait" => AskAndWait,
342 "answer" => Answer,
343 "keypressed" => KeyPressed,
344 "mousedown" => MouseDown,
345 "mousex" => MouseX,
346 "mousey" => MouseY,
347 "setdragmode" => SetDragMode,
348 "loudness" => Loudness,
349 "timer" => Timer,
350 "resettimer" => ResetTimer,
351 "of" => Of,
352 "current" => Current,
353 "dayssince2000" => DaysSince2000,
354 "username" => Username,
355});
356
357impl_from_str!(OperatorsOpcode, "operator" {
358 "add" => Add,
359 "subtract" => Subtract,
360 "multiply" => Multiply,
361 "divide" => Divide,
362 "random" => Random,
363 "gt" => GreaterThan,
364 "lt" => LessThan,
365 "equals" => Equals,
366 "and" => And,
367 "or" => Or,
368 "not" => Not,
369 "join" => Join,
370 "letter_of" => LetterOf,
371 "length" => Length,
372 "contains" => Contains,
373 "mod" => Mod,
374 "round" => Round,
375 "mathop" => MathOp,
376});
377
378impl_from_str!(DataOpcode, "data" {
379 "variable" => Variable,
380 "setvariableto" => SetVariableTo,
381 "changevariableby" => ChangeVariableBy,
382 "showvariable" => ShowVariable,
383 "hidevariable" => HideVariable,
384 "listcontent" => List,
385 "addtolist" => AddToList,
386 "deleteoflist" => DeleteOfList,
387 "deletealloflist" => DeleteAllOfList,
388 "insertatlist" => InsertInList,
389 "replaceitemoflist" => ReplaceItemInList,
390 "itemoflist" => ItemOfList,
391 "itemnumoflist" => ItemNumOfList,
392 "lengthoflist" => LengthOfList,
393 "listcontainsitem" => ListContainsItem,
394 "showlist" => ShowList,
395 "hidelist" => HideList,
396});
397
398impl_from_str!(ProceduresOpcode, "procedures" {
399 "definition" => Define,
400 "call" => Call,
401 "argument_reporter_string_number" => ArgumentStringNumber,
402 "argument_reporter_boolean" => ArgumentBoolean,
403});