Remove positive is_typechecker guards
[hiphop-php.git] / hphp / hack / src / hhbc / emitter / emit_native_opcode.rs
blob8ca59ab010eec1f5b9d68a1819592302312b629e
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.
5 use ast_scope::Scope;
6 use emit_fatal::raise_fatal_runtime;
7 use env::emitter::Emitter;
8 use ffi::{Maybe::Just, Slice, Str};
9 use hhas_body::HhasBody;
10 use instruction_sequence::{instr, Error::Unrecoverable, InstrSeq, Result};
11 use local::Local;
12 use oxidized::{aast, ast, pos::Pos};
14 pub fn emit_body<'a, 'arena, 'decl>(
15     emitter: &mut Emitter<'arena, 'decl>,
16     scope: &Scope<'a, 'arena>,
17     class_attrs: &[ast::UserAttribute],
18     name: &ast::Sid,
19     params: &[ast::FunParam],
20     ret: Option<&aast::Hint>,
21 ) -> Result<HhasBody<'arena>> {
22     let body_instrs = emit_native_opcode_impl(emitter.alloc, &name.1, params, class_attrs);
23     let mut tparams = scope
24         .get_tparams()
25         .iter()
26         .map(|tp| tp.name.1.as_str())
27         .collect::<Vec<_>>();
28     let params = emit_param::from_asts(emitter, &mut tparams, false, scope, params);
29     let return_type_info =
30         emit_body::emit_return_type_info(emitter.alloc, tparams.as_slice(), false, ret);
32     body_instrs.and_then(|body_instrs| {
33         params.and_then(|params| {
34             return_type_info.map(|rti| {
35                 let mut body = hhas_body::default_with_body_instrs(body_instrs);
36                 body.params = Slice::fill_iter(emitter.alloc, params.into_iter().map(|p| p.0));
37                 body.return_type_info = Just(rti);
38                 body
39             })
40         })
41     })
44 fn emit_native_opcode_impl<'arena>(
45     alloc: &'arena bumpalo::Bump,
46     name: &str,
47     params: &[ast::FunParam],
48     user_attrs: &[ast::UserAttribute],
49 ) -> Result<InstrSeq<'arena>> {
50     if let [ua] = user_attrs {
51         if ua.name.1 == "__NativeData" {
52             if let [p] = ua.params.as_slice() {
53                 match p.2.as_string() {
54                     Some(s) if s == "HH\\AsyncGenerator" || s == "Generator" => {
55                         return emit_generator_method(alloc, name, params);
56                     }
57                     _ => {}
58                 }
59             };
60         }
61     };
62     Err(emit_fatal::raise_fatal_runtime(
63         &Pos::make_none(),
64         format!("OpCodeImpl attribute is not applicable to {}", name),
65     ))
68 fn emit_generator_method<'arena>(
69     alloc: &'arena bumpalo::Bump,
70     name: &str,
71     params: &[ast::FunParam],
72 ) -> Result<InstrSeq<'arena>> {
73     let instrs = match name {
74         "send" => {
75             let local = Local::Named(Str::new_str(alloc, get_first_param_name(params)?));
76             InstrSeq::gather(
77                 alloc,
78                 vec![
79                     instr::contcheck_check(alloc),
80                     instr::pushl(alloc, local),
81                     instr::contenter(alloc),
82                 ],
83             )
84         }
85         "raise" | "throw" => {
86             let local = Local::Named(Str::new_str(alloc, get_first_param_name(params)?));
87             InstrSeq::gather(
88                 alloc,
89                 vec![
90                     instr::contcheck_check(alloc),
91                     instr::pushl(alloc, local),
92                     instr::contraise(alloc),
93                 ],
94             )
95         }
96         "next" | "rewind" => InstrSeq::gather(
97             alloc,
98             vec![
99                 instr::contcheck_ignore(alloc),
100                 instr::null(alloc),
101                 instr::contenter(alloc),
102             ],
103         ),
104         "valid" => instr::contvalid(alloc),
105         "current" => instr::contcurrent(alloc),
106         "key" => instr::contkey(alloc),
107         "getReturn" => instr::contgetreturn(alloc),
108         _ => {
109             return Err(raise_fatal_runtime(
110                 &Pos::make_none(),
111                 "incorrect native generator function",
112             ));
113         }
114     };
115     Ok(InstrSeq::gather(alloc, vec![instrs, instr::retc(alloc)]))
118 fn get_first_param_name(params: &[ast::FunParam]) -> Result<&str> {
119     match params {
120         [p, ..] => Ok(&p.name),
121         _ => Err(Unrecoverable(String::from(
122             "native generator requires params",
123         ))),
124     }