Property attributes
[hiphop-php.git] / hphp / hack / src / hackc / ir / conversions / textual / writer.rs
blob5d819b63a0feaf0001dce43466f9572f4126d729
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 use std::path::Path;
7 use std::sync::Arc;
9 use anyhow::bail;
10 use anyhow::Result;
11 use hash::HashMap;
12 use strum::IntoEnumIterator;
14 use crate::decls;
15 use crate::hack;
16 use crate::state::UnitState;
17 use crate::textual;
18 use crate::textual::TextualFile;
20 const UNIT_START_MARKER: &str = "TEXTUAL UNIT START";
21 const UNIT_END_MARKER: &str = "TEXTUAL UNIT END";
23 pub fn textual_writer(
24     w: &mut dyn std::io::Write,
25     path: &Path,
26     unit: ir::Unit<'_>,
27     no_builtins: bool,
28 ) -> Result<()> {
29     let mut txf = TextualFile::new(w, Arc::clone(&unit.strings));
31     let escaped_path = escaper::escape(path.display().to_string());
32     txf.write_comment(&format!("{UNIT_START_MARKER} {escaped_path}"))?;
34     txf.set_attribute(textual::FileAttribute::SourceLanguage("hack".to_string()))?;
35     txf.debug_separator()?;
37     let mut state = UnitState::new(Arc::clone(&unit.strings));
38     check_fatal(path, unit.fatal.as_ref())?;
40     for cls in unit.classes {
41         crate::class::write_class(&mut txf, &mut state, cls)?;
42     }
44     for func in unit.functions {
45         crate::func::write_function(&mut txf, &mut state, func)?;
46     }
48     let all_builtins: HashMap<&str, hack::Builtin> = hack::Builtin::iter()
49         .map(|b| (b.as_str(), b))
50         .chain(hack::Hhbc::iter().map(|b| (b.as_str(), hack::Builtin::Hhbc(b))))
51         .collect();
53     let builtins = txf.write_epilogue(&all_builtins)?;
55     if !no_builtins {
56         decls::write_decls(&mut txf, &builtins)?;
57     }
59     txf.write_comment(&format!("{UNIT_END_MARKER} {escaped_path}"))?;
60     txf.debug_separator()?;
62     Ok(())
65 fn check_fatal(path: &Path, fatal: Option<&ir::Fatal>) -> Result<()> {
66     if let Some(fatal) = fatal {
67         let err = match fatal.op {
68             ir::FatalOp::Parse => "Parse",
69             ir::FatalOp::Runtime => "Runtime",
70             ir::FatalOp::RuntimeOmitFrame => "Runtime Omit",
71             _ => unreachable!(),
72         };
74         bail!(
75             "{err} error in {}[{}]: {}",
76             path.display(),
77             fatal.loc.line_begin,
78             fatal.message
79         );
80     }
82     Ok(())