Skip to content

Commit

Permalink
stop this script
Browse files Browse the repository at this point in the history
  • Loading branch information
dragazo committed Nov 15, 2023
1 parent 629e395 commit faf0e56
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 106 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
176 changes: 95 additions & 81 deletions src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -100,6 +105,7 @@ pub(crate) enum UnaryOp {
UnicodeToChar, CharToUnicode,
}

impl From<StopMode> for Instruction<'_> { fn from(mode: StopMode) -> Self { Self::Stop { mode } } }
impl From<Relation> for Instruction<'_> { fn from(relation: Relation) -> Self { Self::Cmp { relation } } }
impl From<BinaryOp> for Instruction<'_> { fn from(op: BinaryOp) -> Self { Self::BinaryOp { op } } }
impl From<UnaryOp> for Instruction<'_> { fn from(op: UnaryOp) -> Self { Self::UnaryOp { op } } }
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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!(),
}
Expand Down Expand Up @@ -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),
}
}
}
Expand Down Expand Up @@ -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 => {
Expand Down
54 changes: 31 additions & 23 deletions src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,30 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> Process<'gc, C, S> {

Ok((closure.pos, locals))
}
fn do_return<'gc, C: CustomTypes<S>, S: System<C>>(return_value: Value<'gc, C, S>, proc: &mut Process<'gc, C, S>) -> Result<ProcessStep<'gc, C, S>, ErrorCause<C, S>> {
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() {
Expand Down Expand Up @@ -952,29 +976,13 @@ impl<'gc, C: CustomTypes<S>, S: System<C>> 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 } => {
Expand Down
33 changes: 33 additions & 0 deletions src/test/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<C, StdSystem<C>> {
Expand Down
Loading

0 comments on commit faf0e56

Please sign in to comment.