1 // Copyright (c) Facebook, Inc. and its affiliates.
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
10 use ast_scope::{self as ast_scope, Scope, ScopeItem};
11 use bitflags::bitflags;
15 use ocamlrep::rc::RcOc;
16 use oxidized::{ast, namespace_env::Env as NamespaceEnv};
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;
27 /// `'a` is an AST lifetime, `'arena` the lifetime of the `InstrSeq`
29 #[derive(Clone, Debug)]
30 pub struct Env<'a, 'arena> {
31 pub arena: &'arena bumpalo::Bump,
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 {
45 flags: Flags::default(),
46 jump_targets_gen: jump_targets::Gen::default(),
47 scope: Scope::default(),
53 pub fn with_allows_array_append<F, R>(&mut self, alloc: &'arena bumpalo::Bump, f: F) -> R
55 F: FnOnce(&'arena bumpalo::Bump, &mut Self) -> R,
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);
64 pub fn with_need_local_this(&mut self, need_local_this: bool) {
66 self.flags |= Flags::NEEDS_LOCAL_THIS;
70 pub fn with_pipe_var(&mut self, local: Local<'arena>) {
71 self.pipe_var = Some(local);
74 pub fn with_scope(mut self, scope: Scope<'a, 'arena>) -> Env<'a, 'arena> {
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))],
85 pub fn do_in_loop_body<'decl, R, F>(
87 e: &mut Emitter<'arena, 'decl>,
89 label_continue: Label,
90 iterator: Option<iterator::Id>,
95 F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt]) -> R,
98 .with_loop(label_break, label_continue, iterator);
99 self.run_and_release_ids(e, |env, e| f(env, e, b))
102 pub fn do_in_switch_body<'decl, R, F>(
104 e: &mut Emitter<'arena, 'decl>,
110 F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Case]) -> R,
112 self.jump_targets_gen.with_switch(end_label);
113 self.run_and_release_ids(e, |env, e| f(env, e, cases))
116 pub fn do_in_try_catch_body<'decl, R, F>(
118 e: &mut Emitter<'arena, 'decl>,
119 finally_label: Label,
120 try_block: &[ast::Stmt],
121 catch_block: &[ast::Catch],
125 F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt], &[ast::Catch]) -> R,
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))
131 pub fn do_in_try_body<'decl, R, F>(
133 e: &mut Emitter<'arena, 'decl>,
134 finally_label: Label,
139 F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt]) -> R,
141 self.jump_targets_gen.with_try(finally_label);
142 self.run_and_release_ids(e, |env, e| f(env, e, block))
145 pub fn do_in_finally_body<'decl, R, F>(
147 e: &mut Emitter<'arena, 'decl>,
152 F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt]) -> R,
154 self.jump_targets_gen.with_finally();
155 self.run_and_release_ids(e, |env, e| f(env, e, block))
158 pub fn do_in_using_body<'decl, R, F>(
160 e: &mut Emitter<'arena, 'decl>,
161 finally_label: Label,
166 F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &[ast::Stmt]) -> R,
168 self.jump_targets_gen.with_using(finally_label);
169 self.run_and_release_ids(e, |env, e| f(env, e, block))
172 pub fn do_function<'decl, R, F>(
174 e: &mut Emitter<'arena, 'decl>,
179 F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>, &AstBody<'_>) -> R,
181 self.jump_targets_gen.with_function();
182 self.run_and_release_ids(e, |env, e| f(env, e, defs))
185 fn run_and_release_ids<'decl, R, F>(&mut self, e: &mut Emitter<'arena, 'decl>, f: F) -> R
187 F: FnOnce(&mut Self, &mut Emitter<'arena, 'decl>) -> R,
189 let res = f(self, e);
190 self.jump_targets_gen.release_ids();
191 self.jump_targets_gen.revert();
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);