1use super::{
2 Definition, InterfaceDcl, ModuleDcl, ParserProperties, Specification, TypeDcl,
3 expand_annotations, interface_codegen, parse_xidlc_pragma,
4};
5use crate::jsonrpc_hir;
6use crate::rest_hir::{self, HirProjectionKind, ProjectedHir};
7use crate::semantic;
8use serde_json::Value;
9use std::path::Path;
10
11impl From<crate::typed_ast::Specification> for Specification {
12 fn from(value: crate::typed_ast::Specification) -> Self {
13 spec_from_typed_ast(value, true)
14 }
15}
16
17impl Specification {
18 pub fn from_typed_ast_with_properties(
19 value: crate::typed_ast::Specification,
20 properties: ParserProperties,
21 ) -> Self {
22 spec_from_typed_ast(value, expand_interface(&properties))
23 }
24
25 pub fn from_typed_ast_with_properties_and_path(
26 value: crate::typed_ast::Specification,
27 properties: ParserProperties,
28 _path: impl AsRef<Path>,
29 ) -> crate::error::ParserResult<Self> {
30 Self::lower(value, expand_interface(&properties))
31 }
32
33 pub fn from_typed_ast_with_path(
34 value: crate::typed_ast::Specification,
35 _path: impl AsRef<Path>,
36 ) -> crate::error::ParserResult<Self> {
37 Self::lower(value, true)
38 }
39
40 pub fn project_typed_ast_with_properties_and_path(
41 value: crate::typed_ast::Specification,
42 properties: ParserProperties,
43 _path: impl AsRef<Path>,
44 ) -> crate::error::ParserResult<ProjectedHir> {
45 let spec = Self::lower(value, expand_interface(&properties))?;
46 match hir_projection_kind(&properties) {
47 HirProjectionKind::Rpc => Ok(ProjectedHir::Rpc(spec)),
48 HirProjectionKind::Http => rest_hir::project(&spec).map(ProjectedHir::Http),
49 HirProjectionKind::JsonRpc => jsonrpc_hir::project(&spec).map(ProjectedHir::JsonRpc),
50 }
51 }
52
53 fn lower(
54 value: crate::typed_ast::Specification,
55 expand_interfaces: bool,
56 ) -> crate::error::ParserResult<Self> {
57 let mut definitions = Vec::new();
58 collect_defs(value.0, &mut definitions);
59 let mut spec = Self(definitions);
60 rest_hir::HttpUnion::validate_source(&spec.0)?;
63 if expand_interfaces {
66 Self::expand_interfaces(&mut spec.0, &mut Vec::new())?;
67 }
68 semantic::analyze(&mut spec);
69 Ok(spec)
70 }
71
72 fn expand_interfaces(
73 definitions: &mut Vec<Definition>,
74 modules: &mut Vec<String>,
75 ) -> crate::error::ParserResult<()> {
76 for mut definition in std::mem::take(definitions) {
77 match &mut definition {
78 Definition::ModuleDcl(module) => {
79 modules.push(module.ident.clone());
80 Self::expand_interfaces(&mut module.definition, modules)?;
81 modules.pop();
82 }
83 Definition::InterfaceDcl(interface) => {
84 definitions.extend(interface_codegen::expand_interface(interface, modules)?);
85 }
86 _ => {}
87 }
88 definitions.push(definition);
89 }
90 Ok(())
91 }
92}
93
94pub(crate) fn spec_from_typed_ast(
95 value: crate::typed_ast::Specification,
96 expand_interfaces: bool,
97) -> Specification {
98 Specification::lower(value, expand_interfaces).expect("HIR conversion should not fail")
99}
100
101pub(super) fn collect_defs(defs: Vec<crate::typed_ast::Definition>, out: &mut Vec<Definition>) {
102 for def in defs {
103 match def {
104 crate::typed_ast::Definition::ModuleDcl(module) => {
105 let ident = module.ident.0;
106 let annotations = expand_annotations(module.annotations);
107 let mut inner = Vec::new();
108 collect_defs(module.definition, &mut inner);
109 out.push(Definition::ModuleDcl(ModuleDcl {
110 annotations,
111 ident,
112 definition: inner,
113 }));
114 }
115 crate::typed_ast::Definition::PreprocCall(call) => {
116 if let Some(pragma) = parse_xidlc_pragma(&call) {
117 out.push(Definition::Pragma(pragma));
118 }
119 }
120 crate::typed_ast::Definition::TypeDcl(value) => {
121 out.push(Definition::TypeDcl(TypeDcl::from(value)))
122 }
123 crate::typed_ast::Definition::ConstDcl(value) => {
124 out.push(Definition::ConstDcl(value.into()))
125 }
126 crate::typed_ast::Definition::ExceptDcl(value) => {
127 out.push(Definition::ExceptDcl(value.into()))
128 }
129 crate::typed_ast::Definition::InterfaceDcl(value) => {
130 out.push(Definition::InterfaceDcl(InterfaceDcl::from(value)));
131 }
132 crate::typed_ast::Definition::PreprocInclude(_) => {
133 }
136 crate::typed_ast::Definition::TemplateModuleDcl(_)
137 | crate::typed_ast::Definition::TemplateModuleInst(_)
138 | crate::typed_ast::Definition::PreprocDefine(_) => {}
139 }
140 }
141}
142
143fn expand_interface(properties: &ParserProperties) -> bool {
144 if let Some(expand) = properties.get("expand_interface").and_then(Value::as_bool) {
145 return expand;
146 }
147
148 matches!(hir_projection_kind(properties), HirProjectionKind::Rpc)
149}
150
151fn hir_projection_kind(properties: &ParserProperties) -> HirProjectionKind {
152 match properties.get("hir_kind").and_then(Value::as_str) {
153 Some(value) if value.eq_ignore_ascii_case("http") => HirProjectionKind::Http,
154 Some(value)
155 if value.eq_ignore_ascii_case("jsonrpc") || value.eq_ignore_ascii_case("json-rpc") =>
156 {
157 HirProjectionKind::JsonRpc
158 }
159 _ => HirProjectionKind::Rpc,
160 }
161}