From faf0e56570d336b5353e52b32efa6199c904c3d8 Mon Sep 17 00:00:00 2001 From: Devin Jean Date: Tue, 14 Nov 2023 19:08:49 -0600 Subject: [PATCH] stop this script --- Cargo.toml | 4 +- src/bytecode.rs | 176 ++++++++++++++++-------------- src/process.rs | 54 +++++---- src/test/project.rs | 33 ++++++ src/test/projects/stop-script.xml | 1 + 5 files changed, 162 insertions(+), 106 deletions(-) create mode 100644 src/test/projects/stop-script.xml diff --git a/Cargo.toml b/Cargo.toml index c87c008..82094ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,8 +70,8 @@ rustls-tls-webpki-roots = [ # core deps serde_json = { version = "1.0", default-features = false, features = ["alloc"] } gc-arena = { version = "=0.4.0", default-features = false } -netsblox-ast = { version = "=0.4.2", default-features = false } -# netsblox-ast = { path = "../netsblox-ast", default-features = false } +# netsblox-ast = { version = "=0.4.2", default-features = false } +netsblox-ast = { path = "../netsblox-ast", default-features = false } num-traits = { version = "0.2.17", default-features = false } num-derive = { version = "0.4.1", default-features = false } bin-pool = { version = "0.1.1", default-features = false } diff --git a/src/bytecode.rs b/src/bytecode.rs index e4ef8a8..c54782d 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -58,6 +58,11 @@ pub(crate) enum Relation { } #[derive(Clone, Copy, Debug, FromPrimitive)] #[repr(u8)] +pub(crate) enum StopMode { + All, Process, Function, Others, MyOthers, +} +#[derive(Clone, Copy, Debug, FromPrimitive)] +#[repr(u8)] pub(crate) enum TimeQuery { Year, Month, Date, DayOfWeek, Hour, Minute, Second, UnixTimestampMs, } @@ -100,6 +105,7 @@ pub(crate) enum UnaryOp { UnicodeToChar, CharToUnicode, } +impl From for Instruction<'_> { fn from(mode: StopMode) -> Self { Self::Stop { mode } } } impl From for Instruction<'_> { fn from(relation: Relation) -> Self { Self::Cmp { relation } } } impl From for Instruction<'_> { fn from(op: BinaryOp) -> Self { Self::BinaryOp { op } } } impl From for Instruction<'_> { fn from(op: UnaryOp) -> Self { Self::UnaryOp { op } } } @@ -337,6 +343,9 @@ pub(crate) enum Instruction<'a> { /// with the reported value being the (only) value remaining in the value stack. Return, + /// Stops one of more processes/functions/etc. immediately without running any following code. + Stop { mode: StopMode }, + /// Pushes a new error handler onto the handler stack. PushHandler { pos: usize, var: &'a str }, /// Pops an error handler from the handler stack. @@ -490,7 +499,7 @@ macro_rules! read_write_u8_type { } )*} } -read_write_u8_type! { PrintStyle, Property, Relation, TimeQuery, BinaryOp, UnaryOp, VariadicOp, BasicType } +read_write_u8_type! { PrintStyle, Property, Relation, TimeQuery, BinaryOp, UnaryOp, VariadicOp, BasicType, StopMode } /// encodes values as a sequence of bytes of form [1: next][7: bits] in little-endian order. /// `bytes` can be used to force a specific size (too small will panic), otherwise calculates and uses the smallest possible size. @@ -791,61 +800,63 @@ impl<'a> BinaryRead<'a> for Instruction<'a> { 82 => read_prefixed!(Instruction::ForkClosure {} : args), 83 => read_prefixed!(Instruction::Return), - 84 => read_prefixed!(Instruction::PushHandler {} : pos, var), - 85 => read_prefixed!(Instruction::PopHandler), - 86 => read_prefixed!(Instruction::Throw), + 84 => read_prefixed!(Instruction::Stop {} : mode), + + 85 => read_prefixed!(Instruction::PushHandler {} : pos, var), + 86 => read_prefixed!(Instruction::PopHandler), + 87 => read_prefixed!(Instruction::Throw), - 87 => read_prefixed!(Instruction::CallRpc {} : tokens), - 88 => read_prefixed!(Instruction::PushRpcError), + 88 => read_prefixed!(Instruction::CallRpc {} : tokens), + 89 => read_prefixed!(Instruction::PushRpcError), - 89 => read_prefixed!(Instruction::Syscall {} : len), - 90 => read_prefixed!(Instruction::PushSyscallError), + 90 => read_prefixed!(Instruction::Syscall {} : len), + 91 => read_prefixed!(Instruction::PushSyscallError), - 91 => read_prefixed!(Instruction::SendLocalMessage { wait: false, target: false }), - 92 => read_prefixed!(Instruction::SendLocalMessage { wait: false, target: true }), - 93 => read_prefixed!(Instruction::SendLocalMessage { wait: true, target: false }), - 94 => read_prefixed!(Instruction::SendLocalMessage { wait: true, target: true }), + 92 => read_prefixed!(Instruction::SendLocalMessage { wait: false, target: false }), + 93 => read_prefixed!(Instruction::SendLocalMessage { wait: false, target: true }), + 94 => read_prefixed!(Instruction::SendLocalMessage { wait: true, target: false }), + 95 => read_prefixed!(Instruction::SendLocalMessage { wait: true, target: true }), - 95 => read_prefixed!(Instruction::PushLocalMessage), + 96 => read_prefixed!(Instruction::PushLocalMessage), - 96 => read_prefixed!(Instruction::Print { style: PrintStyle::Say }), - 97 => read_prefixed!(Instruction::Print { style: PrintStyle::Think }), - 98 => read_prefixed!(Instruction::Ask), - 99 => read_prefixed!(Instruction::PushAnswer), + 97 => read_prefixed!(Instruction::Print { style: PrintStyle::Say }), + 98 => read_prefixed!(Instruction::Print { style: PrintStyle::Think }), + 99 => read_prefixed!(Instruction::Ask), + 100 => read_prefixed!(Instruction::PushAnswer), - 100 => read_prefixed!(Instruction::ResetTimer), - 101 => read_prefixed!(Instruction::PushTimer), - 102 => read_prefixed!(Instruction::Sleep), - 103 => read_prefixed!(Instruction::PushRealTime {} : query), + 101 => read_prefixed!(Instruction::ResetTimer), + 102 => read_prefixed!(Instruction::PushTimer), + 103 => read_prefixed!(Instruction::Sleep), + 104 => read_prefixed!(Instruction::PushRealTime {} : query), - 104 => read_prefixed!(Instruction::SendNetworkMessage { expect_reply: false, } : tokens), - 105 => read_prefixed!(Instruction::SendNetworkMessage { expect_reply: true, } : tokens), - 106 => read_prefixed!(Instruction::SendNetworkReply), + 105 => read_prefixed!(Instruction::SendNetworkMessage { expect_reply: false, } : tokens), + 106 => read_prefixed!(Instruction::SendNetworkMessage { expect_reply: true, } : tokens), + 107 => read_prefixed!(Instruction::SendNetworkReply), - 107 => read_prefixed!(Instruction::PushProperty {} : prop), - 108 => read_prefixed!(Instruction::SetProperty {} : prop), - 109 => read_prefixed!(Instruction::ChangeProperty {} : prop), + 108 => read_prefixed!(Instruction::PushProperty {} : prop), + 109 => read_prefixed!(Instruction::SetProperty {} : prop), + 110 => read_prefixed!(Instruction::ChangeProperty {} : prop), - 110 => read_prefixed!(Instruction::PushCostume), - 111 => read_prefixed!(Instruction::PushCostumeNumber), - 112 => read_prefixed!(Instruction::PushCostumeList), - 113 => read_prefixed!(Instruction::SetCostume), - 114 => read_prefixed!(Instruction::NextCostume), + 111 => read_prefixed!(Instruction::PushCostume), + 112 => read_prefixed!(Instruction::PushCostumeNumber), + 113 => read_prefixed!(Instruction::PushCostumeList), + 114 => read_prefixed!(Instruction::SetCostume), + 115 => read_prefixed!(Instruction::NextCostume), - 115 => read_prefixed!(Instruction::Clone), + 116 => read_prefixed!(Instruction::Clone), - 116 => read_prefixed!(Instruction::ClearEffects), - 117 => read_prefixed!(Instruction::ClearDrawings), + 117 => read_prefixed!(Instruction::ClearEffects), + 118 => read_prefixed!(Instruction::ClearDrawings), - 118 => read_prefixed!(Instruction::GotoXY), - 119 => read_prefixed!(Instruction::Goto), + 119 => read_prefixed!(Instruction::GotoXY), + 120 => read_prefixed!(Instruction::Goto), - 120 => read_prefixed!(Instruction::PointTowardsXY), - 121 => read_prefixed!(Instruction::PointTowards), + 121 => read_prefixed!(Instruction::PointTowardsXY), + 122 => read_prefixed!(Instruction::PointTowards), - 122 => read_prefixed!(Instruction::Forward), + 123 => read_prefixed!(Instruction::Forward), - 123 => read_prefixed!(Instruction::UnknownBlock {} : name, args), + 124 => read_prefixed!(Instruction::UnknownBlock {} : name, args), _ => unreachable!(), } @@ -982,61 +993,63 @@ impl BinaryWrite for Instruction<'_> { Instruction::ForkClosure { args } => append_prefixed!(82: args), Instruction::Return => append_prefixed!(83), - Instruction::PushHandler { pos, var } => append_prefixed!(84: move pos, move str var), - Instruction::PopHandler => append_prefixed!(85), - Instruction::Throw => append_prefixed!(86), + Instruction::Stop { mode } => append_prefixed!(84: mode), + + Instruction::PushHandler { pos, var } => append_prefixed!(85: move pos, move str var), + Instruction::PopHandler => append_prefixed!(86), + Instruction::Throw => append_prefixed!(87), - Instruction::CallRpc { tokens } => append_prefixed!(87: move str tokens), - Instruction::PushRpcError => append_prefixed!(88), + Instruction::CallRpc { tokens } => append_prefixed!(88: move str tokens), + Instruction::PushRpcError => append_prefixed!(89), - Instruction::Syscall { len } => append_prefixed!(89: len), - Instruction::PushSyscallError => append_prefixed!(90), + Instruction::Syscall { len } => append_prefixed!(90: len), + Instruction::PushSyscallError => append_prefixed!(91), - Instruction::SendLocalMessage { wait: false, target: false } => append_prefixed!(91), - Instruction::SendLocalMessage { wait: false, target: true } => append_prefixed!(92), - Instruction::SendLocalMessage { wait: true, target: false } => append_prefixed!(93), - Instruction::SendLocalMessage { wait: true, target: true } => append_prefixed!(94), + Instruction::SendLocalMessage { wait: false, target: false } => append_prefixed!(92), + Instruction::SendLocalMessage { wait: false, target: true } => append_prefixed!(93), + Instruction::SendLocalMessage { wait: true, target: false } => append_prefixed!(94), + Instruction::SendLocalMessage { wait: true, target: true } => append_prefixed!(95), - Instruction::PushLocalMessage => append_prefixed!(95), + Instruction::PushLocalMessage => append_prefixed!(96), - Instruction::Print { style: PrintStyle::Say } => append_prefixed!(96), - Instruction::Print { style: PrintStyle::Think } => append_prefixed!(97), - Instruction::Ask => append_prefixed!(98), - Instruction::PushAnswer => append_prefixed!(99), + Instruction::Print { style: PrintStyle::Say } => append_prefixed!(97), + Instruction::Print { style: PrintStyle::Think } => append_prefixed!(98), + Instruction::Ask => append_prefixed!(99), + Instruction::PushAnswer => append_prefixed!(100), - Instruction::ResetTimer => append_prefixed!(100), - Instruction::PushTimer => append_prefixed!(101), - Instruction::Sleep => append_prefixed!(102), - Instruction::PushRealTime { query } => append_prefixed!(103: query), + Instruction::ResetTimer => append_prefixed!(101), + Instruction::PushTimer => append_prefixed!(102), + Instruction::Sleep => append_prefixed!(103), + Instruction::PushRealTime { query } => append_prefixed!(104: query), - Instruction::SendNetworkMessage { tokens, expect_reply: false } => append_prefixed!(104: move str tokens), - Instruction::SendNetworkMessage { tokens, expect_reply: true } => append_prefixed!(105: move str tokens), - Instruction::SendNetworkReply => append_prefixed!(106), + Instruction::SendNetworkMessage { tokens, expect_reply: false } => append_prefixed!(105: move str tokens), + Instruction::SendNetworkMessage { tokens, expect_reply: true } => append_prefixed!(106: move str tokens), + Instruction::SendNetworkReply => append_prefixed!(107), - Instruction::PushProperty { prop } => append_prefixed!(107: prop), - Instruction::SetProperty { prop } => append_prefixed!(108: prop), - Instruction::ChangeProperty { prop } => append_prefixed!(109: prop), + Instruction::PushProperty { prop } => append_prefixed!(108: prop), + Instruction::SetProperty { prop } => append_prefixed!(109: prop), + Instruction::ChangeProperty { prop } => append_prefixed!(110: prop), - Instruction::PushCostume => append_prefixed!(110), - Instruction::PushCostumeNumber => append_prefixed!(111), - Instruction::PushCostumeList => append_prefixed!(112), - Instruction::SetCostume => append_prefixed!(113), - Instruction::NextCostume => append_prefixed!(114), + Instruction::PushCostume => append_prefixed!(111), + Instruction::PushCostumeNumber => append_prefixed!(112), + Instruction::PushCostumeList => append_prefixed!(113), + Instruction::SetCostume => append_prefixed!(114), + Instruction::NextCostume => append_prefixed!(115), - Instruction::Clone => append_prefixed!(115), + Instruction::Clone => append_prefixed!(116), - Instruction::ClearEffects => append_prefixed!(116), - Instruction::ClearDrawings => append_prefixed!(117), + Instruction::ClearEffects => append_prefixed!(117), + Instruction::ClearDrawings => append_prefixed!(118), - Instruction::GotoXY => append_prefixed!(118), - Instruction::Goto => append_prefixed!(119), + Instruction::GotoXY => append_prefixed!(119), + Instruction::Goto => append_prefixed!(120), - Instruction::PointTowardsXY => append_prefixed!(120), - Instruction::PointTowards => append_prefixed!(121), + Instruction::PointTowardsXY => append_prefixed!(121), + Instruction::PointTowards => append_prefixed!(122), - Instruction::Forward => append_prefixed!(122), + Instruction::Forward => append_prefixed!(123), - Instruction::UnknownBlock { name, args } => append_prefixed!(123: move str name, args), + Instruction::UnknownBlock { name, args } => append_prefixed!(124: move str name, args), } } } @@ -1702,6 +1715,7 @@ impl<'a: 'b, 'b> ByteCodeBuilder<'a, 'b> { ast::StmtKind::ChangePenSize { delta } => self.append_simple_ins(entity, &[delta], Instruction::ChangeProperty { prop: Property::PenSize })?, ast::StmtKind::NextCostume => self.ins.push(Instruction::NextCostume.into()), ast::StmtKind::PenClear => self.ins.push(Instruction::ClearDrawings.into()), + ast::StmtKind::Stop { mode: ast::StopMode::ThisScript } => self.ins.push(Instruction::Stop { mode: StopMode::Process }.into()), ast::StmtKind::SetCostume { costume } => match costume { Some(x) => self.append_simple_ins(entity, &[x], Instruction::SetCostume)?, None => { diff --git a/src/process.rs b/src/process.rs index 4b588af..095c66f 100644 --- a/src/process.rs +++ b/src/process.rs @@ -347,6 +347,30 @@ impl<'gc, C: CustomTypes, S: System> Process<'gc, C, S> { Ok((closure.pos, locals)) } + fn do_return<'gc, C: CustomTypes, S: System>(return_value: Value<'gc, C, S>, proc: &mut Process<'gc, C, S>) -> Result, ErrorCause> { + let CallStackEntry { called_from, return_to, warp_counter, value_stack_size, handler_stack_size, .. } = proc.call_stack.last().unwrap(); + + proc.pos = *return_to; + proc.warp_counter = *warp_counter; + proc.value_stack.drain(value_stack_size..); + proc.handler_stack.drain(handler_stack_size..); + debug_assert_eq!(proc.value_stack.len(), *value_stack_size); + debug_assert_eq!(proc.handler_stack.len(), *handler_stack_size); + + if proc.call_stack.len() > 1 { + proc.call_stack.pop(); + proc.value_stack.push(return_value); + Ok(ProcessStep::Normal) + } else { + debug_assert_eq!(proc.value_stack.len(), 0); + debug_assert_eq!(*called_from, usize::MAX); + debug_assert_eq!(*return_to, usize::MAX); + debug_assert_eq!(*warp_counter, 0); + debug_assert_eq!(*value_stack_size, 0); + debug_assert_eq!(*handler_stack_size, 0); + Ok(ProcessStep::Terminate { result: Some(return_value) }) + } + } let system = self.global_context.borrow().system.clone(); match self.defer.take() { @@ -952,29 +976,13 @@ impl<'gc, C: CustomTypes, S: System> Process<'gc, C, S> { self.pos = aft_pos; return Ok(ProcessStep::Fork { pos: closure_pos, locals, entity: self.call_stack.last().unwrap().entity }); } - Instruction::Return => { - let CallStackEntry { called_from, return_to, warp_counter, value_stack_size, handler_stack_size, .. } = self.call_stack.last().unwrap(); - let return_value = self.value_stack.pop().unwrap(); - - self.pos = *return_to; - self.warp_counter = *warp_counter; - self.value_stack.drain(value_stack_size..); - self.handler_stack.drain(handler_stack_size..); - debug_assert_eq!(self.value_stack.len(), *value_stack_size); - debug_assert_eq!(self.handler_stack.len(), *handler_stack_size); - - self.value_stack.push(return_value); - - if self.call_stack.len() > 1 { - self.call_stack.pop(); - } else { - debug_assert_eq!(self.value_stack.len(), 1); - debug_assert_eq!(*called_from, usize::MAX); - debug_assert_eq!(*return_to, usize::MAX); - debug_assert_eq!(*warp_counter, 0); - debug_assert_eq!(*value_stack_size, 0); - debug_assert_eq!(*handler_stack_size, 0); - return Ok(ProcessStep::Terminate { result: Some(self.value_stack.pop().unwrap()) }); + Instruction::Return => return do_return(self.value_stack.pop().unwrap(), self), + Instruction::Stop { mode } => { + self.pos = aft_pos; + match mode { + StopMode::Process => return Ok(ProcessStep::Terminate { result: None }), + StopMode::Function => return do_return(empty_string().into(), self), + x => unimplemented!("{x:?}"), } } Instruction::PushHandler { pos, var } => { diff --git a/src/test/project.rs b/src/test/project.rs index 36cf5f9..a6f5bf2 100644 --- a/src/test/project.rs +++ b/src/test/project.rs @@ -247,6 +247,39 @@ fn test_proj_watchers() { }); } +#[test] +fn test_proj_stop_script() { + let system = Rc::new(StdSystem::new_sync(BASE_URL.to_owned(), None, default_properties_config(), Arc::new(Clock::new(UtcOffset::UTC, None)))); + let proj = get_running_project(include_str!("projects/stop-script.xml"), system); + proj.mutate(|mc, proj| { + run_till_term(mc, &mut *proj.proj.borrow_mut(mc)).unwrap(); + let global_context = proj.proj.borrow().get_global_context(); + let global_context = global_context.borrow(); + + let expected = Value::from_simple(mc, SimpleValue::from_json(json!([ + ["1", 1], + ["2", 1], + ["3", 1], + ["4", 1], + ["1", 2], + ["2", 2], + ["3", 2], + ["4", 2], + ["1", 3], + ["2", 3], + ["3", 3], + ["1", 4], + ["3", 4], + ["1", 5], + ["3", 5], + ["1", 6], + ["3", 6], + ["1", 7], + ])).unwrap()); + assert_values_eq(&global_context.globals.lookup("res").unwrap().get(), &expected, 1e-10, "res"); + }); +} + #[test] fn test_proj_costumes() { let config = Config::> { diff --git a/src/test/projects/stop-script.xml b/src/test/projects/stop-script.xml new file mode 100644 index 0000000..3a20b5a --- /dev/null +++ b/src/test/projects/stop-script.xml @@ -0,0 +1 @@ +messagemsg
\ No newline at end of file