Remove positive is_typechecker guards
[hiphop-php.git] / hphp / hack / src / hhbc / emitter / env.rs
blobff55aaaade997e0e56093542985b26a56c1a55e6
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 pub mod emitter; // emitter is public API for mutating state
7 pub mod jump_targets;
9 use ast_body::AstBody;
10 use ast_scope::{self as ast_scope, Scope, ScopeItem};
11 use bitflags::bitflags;
12 use emitter::Emitter;
13 use label::Label;
14 use local::Local;
15 use ocamlrep::rc::RcOc;
16 use oxidized::{ast, namespace_env::Env as NamespaceEnv};
18 bitflags! {
19     #[derive(Default)]
20     pub struct Flags: u8 {
21         const NEEDS_LOCAL_THIS =    0b0000_0001;
22         const IN_TRY =              0b0000_0010;
23         const ALLOWS_ARRAY_APPEND = 0b0000_0100;
24     }
27 /// `'a` is an AST lifetime, `'arena` the lifetime of the `InstrSeq`
28 /// arena.
29 #[derive(Clone, Debug)]
30 pub struct Env<'a, 'arena> {
31     pub arena: &'arena bumpalo::Bump,
32     pub flags: Flags,
33     pub jump_targets_gen: jump_targets::Gen,
34     pub scope: Scope<'a, 'arena>,
35     pub namespace: RcOc<NamespaceEnv>,
36     pub call_context: Option<String>,
37     pub pipe_var: Option<Local<'arena>>,
40 impl<'a, 'arena> Env<'a, 'arena> {
41     pub fn default(arena: &'arena bumpalo::Bump, namespace: RcOc<NamespaceEnv>) -> Self {
42         Env {
43             arena,
44             namespace,
45             flags: Flags::default(),
46             jump_targets_gen: jump_targets::Gen::default(),
47             scope: Scope::default(),
48             call_context: None,
49             pipe_var: None,
50         }
51     }
53     pub fn with_allows_array_append<F, R>(&mut self, alloc: &'arena bumpalo::Bump, f: F) -> R
54     where
55         F: FnOnce(&'arena bumpalo::Bump, &mut Self) -> R,
56     {
57         let old = self.flags.contains(Flags::ALLOWS_ARRAY_APPEND);
58         self.flags.set(Flags::ALLOWS_ARRAY_APPEND, true);
59         let r = f(alloc, self);
60         self.flags.set(Flags::ALLOWS_ARRAY_APPEND, old);
61         r
62     }
64     pub fn with_need_local_this(&mut self, need_local_this: bool) {
65         if need_local_this {
66             self.flags |= Flags::NEEDS_LOCAL_THIS;
67         }
68     }
70     pub fn with_pipe_var(&mut self, local: Local<'arena>) {
71         self.pipe_var = Some(local);
72     }
74     pub fn with_scope(mut self, scope: Scope<'a, 'arena>) -> Env<'a, 'arena> {
75         self.scope = scope;
76         self
77     }
79     pub fn make_class_env(arena: &'arena bumpalo::Bump, class: &'a ast::Class_) -> Env<'a, 'arena> {
80         Env::default(arena, RcOc::clone(&class.namespace)).with_scope(Scope {
81             items: vec![ScopeItem::Class(ast_scope::Class::new_ref(class))],
82         })
83     }
85     pub fn do_in_loop_body<'decl, R, F>(
86         &mut self,
87         e: &mut Emitter<'arena, 'decl>,
88         label_break: Label,
89         label_continue: Label,
90         iterator: Option<iterator::Id>,
91         b: &[ast::Stmt],
92         f: F,
93     ) -> R
94     where
95         F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt]) -> R,
96     {
97         self.jump_targets_gen
98             .with_loop(label_break, label_continue, iterator);
99         self.run_and_release_ids(e, |env, e| f(env, e, b))
100     }
102     pub fn do_in_switch_body<'decl, R, F>(
103         &mut self,
104         e: &mut Emitter<'arena, 'decl>,
105         end_label: Label,
106         cases: &[ast::Case],
107         f: F,
108     ) -> R
109     where
110         F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Case]) -> R,
111     {
112         self.jump_targets_gen.with_switch(end_label);
113         self.run_and_release_ids(e, |env, e| f(env, e, cases))
114     }
116     pub fn do_in_try_catch_body<'decl, R, F>(
117         &mut self,
118         e: &mut Emitter<'arena, 'decl>,
119         finally_label: Label,
120         try_block: &[ast::Stmt],
121         catch_block: &[ast::Catch],
122         f: F,
123     ) -> R
124     where
125         F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt], &[ast::Catch]) -> R,
126     {
127         self.jump_targets_gen.with_try_catch(finally_label);
128         self.run_and_release_ids(e, |env, e| f(env, e, try_block, catch_block))
129     }
131     pub fn do_in_try_body<'decl, R, F>(
132         &mut self,
133         e: &mut Emitter<'arena, 'decl>,
134         finally_label: Label,
135         block: &[ast::Stmt],
136         f: F,
137     ) -> R
138     where
139         F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt]) -> R,
140     {
141         self.jump_targets_gen.with_try(finally_label);
142         self.run_and_release_ids(e, |env, e| f(env, e, block))
143     }
145     pub fn do_in_finally_body<'decl, R, F>(
146         &mut self,
147         e: &mut Emitter<'arena, 'decl>,
148         block: &[ast::Stmt],
149         f: F,
150     ) -> R
151     where
152         F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt]) -> R,
153     {
154         self.jump_targets_gen.with_finally();
155         self.run_and_release_ids(e, |env, e| f(env, e, block))
156     }
158     pub fn do_in_using_body<'decl, R, F>(
159         &mut self,
160         e: &mut Emitter<'arena, 'decl>,
161         finally_label: Label,
162         block: &[ast::Stmt],
163         f: F,
164     ) -> R
165     where
166         F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt]) -> R,
167     {
168         self.jump_targets_gen.with_using(finally_label);
169         self.run_and_release_ids(e, |env, e| f(env, e, block))
170     }
172     pub fn do_function<'decl, R, F>(
173         &mut self,
174         e: &mut Emitter<'arena, 'decl>,
175         defs: &AstBody<'_>,
176         f: F,
177     ) -> R
178     where
179         F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &AstBody<'_>) -> R,
180     {
181         self.jump_targets_gen.with_function();
182         self.run_and_release_ids(e, |env, e| f(env, e, defs))
183     }
185     fn run_and_release_ids<'decl, R, F>(&mut self, e: &mut Emitter<'arena, 'decl>, f: F) -> R
186     where
187         F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>) -> R,
188     {
189         let res = f(self, e);
190         self.jump_targets_gen.release_ids();
191         self.jump_targets_gen.revert();
192         res
193     }
196 #[cfg(test)]
197 mod tests {
198     use super::*;
200     #[test]
201     fn make_env() {
202         let a = bumpalo::Bump::new();
203         let alloc: &bumpalo::Bump = &a;
204         let namespace = RcOc::new(NamespaceEnv::empty(vec![], false, false));
205         let _: Env<'_, '_> = Env::default(&alloc, namespace);
206     }