/src/starlark-rust/starlark/src/eval/bc/compiler/assign.rs
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2019 The Starlark in Rust Authors. |
3 | | * Copyright (c) Facebook, Inc. and its affiliates. |
4 | | * |
5 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | | * you may not use this file except in compliance with the License. |
7 | | * You may obtain a copy of the License at |
8 | | * |
9 | | * https://www.apache.org/licenses/LICENSE-2.0 |
10 | | * |
11 | | * Unless required by applicable law or agreed to in writing, software |
12 | | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | * See the License for the specific language governing permissions and |
15 | | * limitations under the License. |
16 | | */ |
17 | | |
18 | | //! Compile assignment lhs. |
19 | | |
20 | | use starlark_syntax::slice_vec_ext::SliceExt; |
21 | | |
22 | | use crate::collections::symbol::symbol::Symbol; |
23 | | use crate::eval::bc::compiler::expr::write_n_exprs; |
24 | | use crate::eval::bc::instr_impl::InstrSetArrayIndex; |
25 | | use crate::eval::bc::instr_impl::InstrSetObjectField; |
26 | | use crate::eval::bc::instr_impl::InstrStoreModuleAndExport; |
27 | | use crate::eval::bc::instr_impl::InstrUnpack; |
28 | | use crate::eval::bc::stack_ptr::BcSlotIn; |
29 | | use crate::eval::bc::stack_ptr::BcSlotOut; |
30 | | use crate::eval::bc::writer::BcWriter; |
31 | | use crate::eval::compiler::span::IrSpanned; |
32 | | use crate::eval::compiler::stmt::AssignCompiledValue; |
33 | | |
34 | | impl AssignCompiledValue { |
35 | | /// After evaluation of `(x, y[z]) = ...`, variables `x`, `y` and `z` as definitely assigned. |
36 | 16 | pub(crate) fn mark_definitely_assigned_after(&self, bc: &mut BcWriter) { |
37 | 16 | match self { |
38 | 0 | AssignCompiledValue::Dot(object, field) => { |
39 | 0 | object.mark_definitely_assigned_after(bc); |
40 | 0 | let _ = field; |
41 | 0 | } |
42 | 8 | AssignCompiledValue::Module(..) => {} |
43 | 0 | AssignCompiledValue::Index(array, index) => { |
44 | 0 | array.mark_definitely_assigned_after(bc); |
45 | 0 | index.mark_definitely_assigned_after(bc); |
46 | 0 | } |
47 | 0 | AssignCompiledValue::LocalCaptured(_slot) => {} |
48 | 8 | AssignCompiledValue::Local(slot) => { |
49 | 8 | bc.mark_definitely_assigned(*slot); |
50 | 8 | } |
51 | 0 | AssignCompiledValue::Tuple(xs) => { |
52 | 0 | for x in xs { |
53 | 0 | x.mark_definitely_assigned_after(bc); |
54 | 0 | } |
55 | | } |
56 | | } |
57 | 16 | } |
58 | | } |
59 | | |
60 | | impl IrSpanned<AssignCompiledValue> { |
61 | 8 | pub(crate) fn write_bc(&self, value: BcSlotIn, bc: &mut BcWriter) { |
62 | 8 | let span = self.span; |
63 | 8 | match self.node { |
64 | 0 | AssignCompiledValue::Dot(ref object, ref field) => { |
65 | 0 | object.write_bc_cb(bc, |object, bc| { |
66 | 0 | let symbol = Symbol::new(field.as_str()); |
67 | 0 | bc.write_instr::<InstrSetObjectField>(span, (value, object, symbol)); |
68 | 0 | }); |
69 | 0 | } |
70 | 0 | AssignCompiledValue::Index(ref array, ref index) => { |
71 | 0 | write_n_exprs([array, index], bc, |[array, index], bc| { |
72 | 0 | bc.write_instr::<InstrSetArrayIndex>(span, (value, array, index)); |
73 | 0 | }); |
74 | 0 | } |
75 | 0 | AssignCompiledValue::Tuple(ref xs) => { |
76 | 0 | // All assignments are to local variables, e. g. |
77 | 0 | // ``` |
78 | 0 | // (x, y, z) = ... |
79 | 0 | // ``` |
80 | 0 | // so we can avoid using intermediate register. |
81 | 0 | let all_local = xs |
82 | 0 | .try_map(|x| { |
83 | 0 | x.as_local_non_captured() |
84 | 0 | .map(|l| l.to_bc_slot().to_out()) |
85 | 0 | .ok_or(()) |
86 | 0 | }) |
87 | 0 | .ok(); |
88 | 0 | if let Some(all_local) = all_local { |
89 | 0 | let args = bc.heap.alloc_any_slice(&all_local); |
90 | 0 | bc.write_instr::<InstrUnpack>(span, (value, args)); |
91 | 0 | } else { |
92 | 0 | bc.alloc_slots(xs.len() as u32, |slots, bc| { |
93 | 0 | let args: Vec<BcSlotOut> = slots.iter().map(|s| s.to_out()).collect(); |
94 | 0 | let args = bc.heap.alloc_any_slice(&args); |
95 | 0 | bc.write_instr::<InstrUnpack>(span, (value, args)); |
96 | | |
97 | 0 | for (x, slot) in xs.iter().zip(slots.iter()) { |
98 | 0 | x.write_bc(slot.to_in(), bc); |
99 | 0 | } |
100 | 0 | }); |
101 | 0 | } |
102 | | } |
103 | 0 | AssignCompiledValue::Local(slot) => { |
104 | 0 | bc.write_mov(span, value, slot.to_bc_slot().to_out()); |
105 | 0 | } |
106 | 0 | AssignCompiledValue::LocalCaptured(slot) => { |
107 | 0 | bc.write_store_local_captured(span, value, slot); |
108 | 0 | } |
109 | 8 | AssignCompiledValue::Module(slot, ref name) => { |
110 | 8 | bc.write_instr::<InstrStoreModuleAndExport>(span, (value, slot, name.clone())); |
111 | 8 | } |
112 | | } |
113 | 8 | } |
114 | | } |