Skip to main content

nargo_ir/
program.rs

1#![warn(missing_docs)]
2
3//! 程序模块
4//! 
5//! 提供 JavaScript 程序和 IR 模块的表示和相关功能。
6
7use nargo_types::{NargoValue, Result, Span};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10
11use crate::stmt::JsStmt;
12use crate::template::{CustomBlockIR, StyleIR, TemplateIR, TestIR};
13use crate::types::{MAX_ARRAY_LENGTH, MAX_OBJECT_SIZE, MAX_STRING_LENGTH, IRError, Trivia};
14
15/// JavaScript 程序
16///
17/// 表示一个完整的 JavaScript 程序,包含多个语句
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
19pub struct JsProgram {
20    /// 程序体
21    ///
22    /// 包含程序的所有语句
23    pub body: Vec<JsStmt>,
24    /// 位置信息
25    ///
26    /// 程序在源文件中的位置
27    #[serde(default)]
28    pub span: Span,
29    /// Trivia 信息
30    ///
31    /// 包含程序的空白和注释信息
32    #[serde(default)]
33    pub trivia: Trivia,
34}
35
36impl JsProgram {
37    /// 验证程序的有效性
38    ///
39    /// 检查程序是否符合大小限制,并验证所有语句的有效性
40    ///
41    /// # Returns
42    /// - `Ok(())` 如果程序有效
43    /// - `Err(Error)` 如果程序无效
44    pub fn validate(&self) -> Result<()> {
45        if self.body.len() > MAX_ARRAY_LENGTH {
46            return Err(IRError::SizeLimitExceeded("Program body length exceeded".to_string()).into());
47        }
48        for stmt in &self.body {
49            stmt.validate(0)?;
50        }
51        Ok(())
52    }
53
54    /// 优化程序
55    pub fn optimize(&mut self) {
56        crate::optimizer::ProgramOptimizer::optimize(self);
57    }
58
59    /// 检查程序是否为空
60    pub fn is_empty(&self) -> bool {
61        self.body.is_empty()
62    }
63}
64
65/// IR 模块
66///
67/// 表示一个完整的 HXO IR 模块,包含脚本、模板、样式等信息
68#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
69pub struct IRModule {
70    /// 模块名称
71    ///
72    /// 模块的唯一标识符
73    pub name: String,
74    /// 元数据
75    ///
76    /// 模块的附加信息
77    pub metadata: HashMap<String, NargoValue>,
78    /// 脚本
79    ///
80    /// 通用脚本代码
81    pub script: Option<JsProgram>,
82    /// 服务端脚本
83    ///
84    /// 仅在服务端执行的脚本代码
85    pub script_server: Option<JsProgram>,
86    /// 客户端脚本
87    ///
88    /// 仅在客户端执行的脚本代码
89    pub script_client: Option<JsProgram>,
90    /// 脚本元数据
91    ///
92    /// 用于脚本分析结果的元数据
93    pub script_meta: Option<NargoValue>,
94    /// 模板
95    ///
96    /// 模块的模板结构
97    pub template: Option<TemplateIR>,
98    /// 提升节点
99    ///
100    /// 被提升的模板节点
101    pub hoisted_nodes: HashMap<String, crate::template::TemplateNodeIR>,
102    /// 样式
103    ///
104    /// 模块的样式定义
105    pub styles: Vec<StyleIR>,
106    /// 国际化
107    ///
108    /// 模块的国际化文本
109    pub i18n: Option<HashMap<String, HashMap<String, String>>>,
110    /// WASM
111    ///
112    /// WebAssembly 模块
113    pub wasm: Vec<Vec<u8>>,
114    /// 自定义块
115    ///
116    /// 模块的自定义块
117    pub custom_blocks: Vec<CustomBlockIR>,
118    /// 测试
119    ///
120    /// 模块的测试用例
121    pub tests: Vec<TestIR>,
122    /// 位置信息
123    ///
124    /// 模块在源文件中的位置
125    pub span: Span,
126}
127
128impl IRModule {
129    /// 验证 IR 模块的有效性
130    pub fn validate(&self) -> Result<()> {
131        if self.name.len() > MAX_STRING_LENGTH {
132            return Err(IRError::SizeLimitExceeded("Module name length exceeded".to_string()).into());
133        }
134
135        // 验证元数据
136        if self.metadata.len() > MAX_OBJECT_SIZE {
137            return Err(IRError::SizeLimitExceeded("Metadata size exceeded".to_string()).into());
138        }
139        for (key, value) in &self.metadata {
140            if key.len() > MAX_STRING_LENGTH {
141                return Err(IRError::SizeLimitExceeded("Metadata key length exceeded".to_string()).into());
142            }
143            value.validate(0)?;
144        }
145
146        // 验证脚本
147        if let Some(script) = &self.script {
148            script.validate()?;
149        }
150        if let Some(script_server) = &self.script_server {
151            script_server.validate()?;
152        }
153        if let Some(script_client) = &self.script_client {
154            script_client.validate()?;
155        }
156
157        // 验证脚本元数据
158        if let Some(meta) = &self.script_meta {
159            meta.validate(0)?;
160        }
161
162        // 验证模板
163        if let Some(template) = &self.template {
164            template.validate()?;
165        }
166
167        // 验证提升节点
168        if self.hoisted_nodes.len() > MAX_OBJECT_SIZE {
169            return Err(IRError::SizeLimitExceeded("Hoisted nodes size exceeded".to_string()).into());
170        }
171        for (key, node) in &self.hoisted_nodes {
172            if key.len() > MAX_STRING_LENGTH {
173                return Err(IRError::SizeLimitExceeded("Hoisted node key length exceeded".to_string()).into());
174            }
175            node.validate(0)?;
176        }
177
178        // 验证样式
179        if self.styles.len() > MAX_ARRAY_LENGTH {
180            return Err(IRError::SizeLimitExceeded("Styles length exceeded".to_string()).into());
181        }
182        for style in &self.styles {
183            style.validate()?;
184        }
185
186        // 验证国际化
187        if let Some(i18n) = &self.i18n {
188            if i18n.len() > MAX_OBJECT_SIZE {
189                return Err(IRError::SizeLimitExceeded("I18n size exceeded".to_string()).into());
190            }
191            for (lang, translations) in i18n {
192                if lang.len() > MAX_STRING_LENGTH {
193                    return Err(IRError::SizeLimitExceeded("I18n language length exceeded".to_string()).into());
194                }
195                if translations.len() > MAX_OBJECT_SIZE {
196                    return Err(IRError::SizeLimitExceeded("I18n translations size exceeded".to_string()).into());
197                }
198                for (key, value) in translations {
199                    if key.len() > MAX_STRING_LENGTH {
200                        return Err(IRError::SizeLimitExceeded("I18n key length exceeded".to_string()).into());
201                    }
202                    if value.len() > MAX_STRING_LENGTH {
203                        return Err(IRError::SizeLimitExceeded("I18n value length exceeded".to_string()).into());
204                    }
205                }
206            }
207        }
208
209        // 验证 WASM
210        if self.wasm.len() > MAX_ARRAY_LENGTH {
211            return Err(IRError::SizeLimitExceeded("WASM length exceeded".to_string()).into());
212        }
213        for wasm in &self.wasm {
214            if wasm.len() > MAX_STRING_LENGTH {
215                return Err(IRError::SizeLimitExceeded("WASM size exceeded".to_string()).into());
216            }
217        }
218
219        // 验证自定义块
220        if self.custom_blocks.len() > MAX_ARRAY_LENGTH {
221            return Err(IRError::SizeLimitExceeded("Custom blocks length exceeded".to_string()).into());
222        }
223        for block in &self.custom_blocks {
224            block.validate()?;
225        }
226
227        // 验证测试
228        if self.tests.len() > MAX_ARRAY_LENGTH {
229            return Err(IRError::SizeLimitExceeded("Tests length exceeded".to_string()).into());
230        }
231        for test in &self.tests {
232            test.validate()?;
233        }
234
235        Ok(())
236    }
237
238    /// 清理模块中的空元素
239    pub fn cleanup(&mut self) {
240        // 清理脚本
241        if let Some(script) = &mut self.script {
242            if script.body.is_empty() {
243                self.script = None;
244            }
245        }
246        if let Some(script_server) = &mut self.script_server {
247            if script_server.body.is_empty() {
248                self.script_server = None;
249            }
250        }
251        if let Some(script_client) = &mut self.script_client {
252            if script_client.body.is_empty() {
253                self.script_client = None;
254            }
255        }
256
257        // 清理脚本元数据
258        if let Some(meta) = &self.script_meta {
259            if *meta == NargoValue::Null {
260                self.script_meta = None;
261            }
262        }
263
264        // 清理模板
265        if let Some(template) = &mut self.template {
266            if template.nodes.is_empty() {
267                self.template = None;
268            }
269        }
270
271        // 清理国际化
272        if let Some(i18n) = &self.i18n {
273            if i18n.is_empty() {
274                self.i18n = None;
275            }
276        }
277    }
278
279    /// 优化模块
280    pub fn optimize(&mut self) {
281        crate::optimizer::IROptimizer::optimize(self);
282    }
283}