Skip to main content

nargo_ir/
validator.rs

1#![warn(missing_docs)]
2
3//! 验证器模块
4//! 
5//! 提供 IR 结构的验证功能,包括类型检查、作用域分析、语义验证等。
6
7use nargo_types::{NargoValue, Result};
8use std::collections::HashMap;
9
10use crate::expr::JsExpr;
11use crate::program::{IRModule, JsProgram};
12use crate::stmt::JsStmt;
13use crate::types::IRError;
14
15/// 类型信息
16///
17/// 表示 JavaScript 表达式的类型。
18#[derive(Debug, Clone, PartialEq)]
19pub enum TypeInfo {
20    /// 数字类型
21    Number,
22    /// 字符串类型
23    String,
24    /// 布尔类型
25    Boolean,
26    /// 对象类型
27    Object,
28    /// 数组类型
29    Array,
30    /// 函数类型
31    Function,
32    /// 未定义类型
33    Undefined,
34    /// 空类型
35    Null,
36    /// 任意类型
37    Any,
38}
39
40/// 类型环境
41pub struct TypeEnvironment {
42    /// 变量类型映射
43    variables: HashMap<String, TypeInfo>,
44}
45
46impl TypeEnvironment {
47    /// 创建新的类型环境
48    pub fn new() -> Self {
49        Self { variables: HashMap::new() }
50    }
51
52    /// 添加变量类型
53    pub fn add_variable(&mut self, name: String, type_info: TypeInfo) {
54        self.variables.insert(name, type_info);
55    }
56
57    /// 获取变量类型
58    pub fn get_variable(&self, name: &String) -> Option<&TypeInfo> {
59        self.variables.get(name)
60    }
61}
62
63/// 表达式验证器
64pub struct ExprValidator {
65    /// 类型环境
66    env: TypeEnvironment,
67}
68
69impl ExprValidator {
70    /// 创建新的表达式验证器
71    pub fn new() -> Self {
72        Self { env: TypeEnvironment::new() }
73    }
74
75    /// 验证表达式
76    pub fn validate(&mut self, expr: &JsExpr) -> Result<TypeInfo> {
77        match expr {
78            JsExpr::Identifier(id, _span, _) => {
79                if let Some(type_info) = self.env.get_variable(id) {
80                    Ok(type_info.clone())
81                }
82                else {
83                    Err(IRError::InvalidExpression(format!("Undefined variable: {}", id)).into())
84                }
85            }
86            JsExpr::Literal(value, _, _) => Ok(match value {
87                NargoValue::Number(_) => TypeInfo::Number,
88                NargoValue::String(_) => TypeInfo::String,
89                NargoValue::Bool(_) => TypeInfo::Boolean,
90                NargoValue::Object(_) => TypeInfo::Object,
91                NargoValue::Array(_) => TypeInfo::Array,
92                NargoValue::Null => TypeInfo::Null,
93                _ => TypeInfo::Any,
94            }),
95            JsExpr::Unary { op, argument, span: _, .. } => {
96                let arg_type = self.validate(argument)?;
97                match op.as_str() {
98                    "!" => Ok(TypeInfo::Boolean),
99                    "-" | "+" | "~" => {
100                        if matches!(arg_type, TypeInfo::Number) {
101                            Ok(TypeInfo::Number)
102                        }
103                        else {
104                            Err(IRError::InvalidExpression(format!("Unary operator {} requires number type", op)).into())
105                        }
106                    }
107                    _ => Ok(TypeInfo::Any),
108                }
109            }
110            JsExpr::Binary { left, op, right, span: _, .. } => {
111                let left_type = self.validate(left)?;
112                let right_type = self.validate(right)?;
113                match op.as_str() {
114                    "+" => {
115                        if matches!(left_type, TypeInfo::Number) && matches!(right_type, TypeInfo::Number) {
116                            Ok(TypeInfo::Number)
117                        }
118                        else if matches!(left_type, TypeInfo::String) || matches!(right_type, TypeInfo::String) {
119                            Ok(TypeInfo::String)
120                        }
121                        else {
122                            Err(IRError::InvalidExpression(format!("Addition operator requires number or string types").to_string()).into())
123                        }
124                    }
125                    "-" | "*" | "/" | "%" => {
126                        if matches!(left_type, TypeInfo::Number) && matches!(right_type, TypeInfo::Number) {
127                            Ok(TypeInfo::Number)
128                        }
129                        else {
130                            Err(IRError::InvalidExpression(format!("Arithmetic operator {} requires number types", op)).into())
131                        }
132                    }
133                    "==" | "!=" | "===" | "!==" => Ok(TypeInfo::Boolean),
134                    "<" | "<=" | ">" | ">=" => {
135                        if matches!(left_type, TypeInfo::Number) && matches!(right_type, TypeInfo::Number) {
136                            Ok(TypeInfo::Boolean)
137                        }
138                        else if matches!(left_type, TypeInfo::String) && matches!(right_type, TypeInfo::String) {
139                            Ok(TypeInfo::Boolean)
140                        }
141                        else {
142                            Err(IRError::InvalidExpression(format!("Comparison operator {} requires number or string types", op)).into())
143                        }
144                    }
145                    "&&" | "||" => Ok(TypeInfo::Boolean),
146                    "&" | "|" | "^" | "<<" | ">>" | ">>>" => {
147                        if matches!(left_type, TypeInfo::Number) && matches!(right_type, TypeInfo::Number) {
148                            Ok(TypeInfo::Number)
149                        }
150                        else {
151                            Err(IRError::InvalidExpression(format!("Bitwise operator {} requires number types", op)).into())
152                        }
153                    }
154                    "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | ">>>=" => Ok(left_type),
155                    _ => Ok(TypeInfo::Any),
156                }
157            }
158            JsExpr::Call { callee, args, span: _, .. } => {
159                let callee_type = self.validate(callee)?;
160                if matches!(callee_type, TypeInfo::Function) {
161                    // 验证参数
162                    for arg in args {
163                        self.validate(arg)?;
164                    }
165                    Ok(TypeInfo::Any)
166                }
167                else {
168                    Err(IRError::InvalidExpression("Callee must be a function".to_string()).into())
169                }
170            }
171            JsExpr::Member { object, property, .. } => {
172                self.validate(object)?;
173                self.validate(property)?;
174                Ok(TypeInfo::Any)
175            }
176            JsExpr::OptionalMember { object, property, .. } => {
177                self.validate(object)?;
178                self.validate(property)?;
179                Ok(TypeInfo::Any)
180            }
181            JsExpr::OptionalCall { callee, args, .. } => {
182                self.validate(callee)?;
183                for arg in args {
184                    self.validate(arg)?;
185                }
186                Ok(TypeInfo::Any)
187            }
188            JsExpr::NullishCoalescing { left, right, .. } => {
189                self.validate(left)?;
190                self.validate(right)?;
191                Ok(TypeInfo::Any)
192            }
193            JsExpr::LogicalAssignment { left, right, .. } => {
194                self.validate(left)?;
195                self.validate(right)?;
196                Ok(TypeInfo::Any)
197            }
198            JsExpr::Array(items, ..) => {
199                for item in items {
200                    self.validate(item)?;
201                }
202                Ok(TypeInfo::Array)
203            }
204            JsExpr::Object(props, ..) => {
205                for (_, value) in props {
206                    self.validate(value)?;
207                }
208                Ok(TypeInfo::Object)
209            }
210            JsExpr::ArrowFunction { params, body, .. } => {
211                // 添加参数到环境
212                for param in params {
213                    self.env.add_variable(param.clone(), TypeInfo::Any);
214                }
215                self.validate(body)?;
216                Ok(TypeInfo::Function)
217            }
218            JsExpr::TseElement { children, .. } => {
219                for child in children {
220                    self.validate(child)?;
221                }
222                Ok(TypeInfo::Any)
223            }
224            JsExpr::Conditional { test, consequent, alternate, .. } => {
225                let test_type = self.validate(test)?;
226                if !matches!(test_type, TypeInfo::Boolean) {
227                    return Err(IRError::InvalidExpression("Condition must be a boolean".to_string()).into());
228                }
229                let _consequent_type = self.validate(consequent)?;
230                let _alternate_type = self.validate(alternate)?;
231                // 简化处理,返回任意类型
232                Ok(TypeInfo::Any)
233            }
234            JsExpr::TemplateLiteral { expressions, .. } => {
235                for expr in expressions {
236                    self.validate(expr)?;
237                }
238                Ok(TypeInfo::String)
239            }
240            JsExpr::Spread(expr, ..) => {
241                self.validate(expr)?;
242                Ok(TypeInfo::Any)
243            }
244            JsExpr::TypeOf(expr, ..) => {
245                self.validate(expr)?;
246                Ok(TypeInfo::String)
247            }
248            JsExpr::InstanceOf { left, right, .. } => {
249                self.validate(left)?;
250                self.validate(right)?;
251                Ok(TypeInfo::Boolean)
252            }
253            JsExpr::Other(_, _, _) => Ok(TypeInfo::Any),
254        }
255    }
256}
257
258/// 语句验证器
259pub struct StmtValidator {
260    /// 表达式验证器
261    expr_validator: ExprValidator,
262}
263
264impl StmtValidator {
265    /// 创建新的语句验证器
266    pub fn new() -> Self {
267        Self { expr_validator: ExprValidator::new() }
268    }
269
270    /// 验证语句
271    pub fn validate(&mut self, stmt: &JsStmt) -> Result<()> {
272        match stmt {
273            JsStmt::Expr(expr, ..) => {
274                self.expr_validator.validate(expr)?;
275                Ok(())
276            }
277            JsStmt::VariableDecl { kind: _, id, init, .. } => {
278                if let Some(expr) = init {
279                    let type_info = self.expr_validator.validate(expr)?;
280                    self.expr_validator.env.add_variable(id.clone(), type_info);
281                }
282                else {
283                    // 未初始化的变量,默认为任意类型
284                    self.expr_validator.env.add_variable(id.clone(), TypeInfo::Any);
285                }
286                Ok(())
287            }
288            JsStmt::Import { .. } => Ok(()),
289            JsStmt::Export { declaration, .. } => self.validate(declaration),
290            JsStmt::ExportAll { .. } => Ok(()),
291            JsStmt::ExportNamed { .. } => Ok(()),
292            JsStmt::FunctionDecl { id, params, body, .. } => {
293                // 添加函数到环境
294                self.expr_validator.env.add_variable(id.clone(), TypeInfo::Function);
295                // 添加参数到环境
296                for param in params {
297                    self.expr_validator.env.add_variable(param.clone(), TypeInfo::Any);
298                }
299                // 验证函数体
300                for stmt in body {
301                    self.validate(stmt)?;
302                }
303                Ok(())
304            }
305            JsStmt::Return(expr, ..) => {
306                if let Some(expr) = expr {
307                    self.expr_validator.validate(expr)?;
308                }
309                Ok(())
310            }
311            JsStmt::If { test, consequent, alternate, .. } => {
312                let test_type = self.expr_validator.validate(test)?;
313                if !matches!(test_type, TypeInfo::Boolean) {
314                    return Err(IRError::InvalidExpression("Condition must be a boolean".to_string()).into());
315                }
316                self.validate(consequent)?;
317                if let Some(alt) = alternate {
318                    self.validate(alt)?;
319                }
320                Ok(())
321            }
322            JsStmt::While { test, body, .. } => {
323                let test_type = self.expr_validator.validate(test)?;
324                if !matches!(test_type, TypeInfo::Boolean) {
325                    return Err(IRError::InvalidExpression("Condition must be a boolean".to_string()).into());
326                }
327                self.validate(body)?;
328                Ok(())
329            }
330            JsStmt::For { init, test, update, body, .. } => {
331                if let Some(init_stmt) = init {
332                    self.validate(init_stmt)?;
333                }
334                if let Some(test_expr) = test {
335                    let test_type = self.expr_validator.validate(test_expr)?;
336                    if !matches!(test_type, TypeInfo::Boolean) {
337                        return Err(IRError::InvalidExpression("Condition must be a boolean".to_string()).into());
338                    }
339                }
340                if let Some(update_expr) = update {
341                    self.expr_validator.validate(update_expr)?;
342                }
343                self.validate(body)?;
344                Ok(())
345            }
346            JsStmt::ForIn { left, right, body, .. } => {
347                self.validate(left)?;
348                self.expr_validator.validate(right)?;
349                self.validate(body)?;
350                Ok(())
351            }
352            JsStmt::ForOf { left, right, body, .. } => {
353                self.validate(left)?;
354                self.expr_validator.validate(right)?;
355                self.validate(body)?;
356                Ok(())
357            }
358            JsStmt::Try { block, handler, finalizer, .. } => {
359                self.validate(block)?;
360                if let Some((id, body)) = handler {
361                    // 添加错误变量到环境
362                    self.expr_validator.env.add_variable(id.clone(), TypeInfo::Any);
363                    self.validate(body)?;
364                }
365                if let Some(body) = finalizer {
366                    self.validate(body)?;
367                }
368                Ok(())
369            }
370            JsStmt::Switch { discriminant, cases, .. } => {
371                self.expr_validator.validate(discriminant)?;
372                for (test, stmts) in cases {
373                    if let Some(test_expr) = test {
374                        self.expr_validator.validate(test_expr)?;
375                    }
376                    for stmt in stmts {
377                        self.validate(stmt)?;
378                    }
379                }
380                Ok(())
381            }
382            JsStmt::Throw(expr, ..) => {
383                self.expr_validator.validate(expr)?;
384                Ok(())
385            }
386            JsStmt::Block(stmts, ..) => {
387                for stmt in stmts {
388                    self.validate(stmt)?;
389                }
390                Ok(())
391            }
392            JsStmt::Break(_, _) => Ok(()),
393            JsStmt::Continue(_, _) => Ok(()),
394            JsStmt::Other(_, _, _) => Ok(()),
395        }
396    }
397}
398
399/// 程序验证器
400pub struct ProgramValidator {
401    /// 语句验证器
402    stmt_validator: StmtValidator,
403}
404
405impl ProgramValidator {
406    /// 创建新的程序验证器
407    pub fn new() -> Self {
408        Self { stmt_validator: StmtValidator::new() }
409    }
410
411    /// 验证程序
412    pub fn validate(&mut self, program: &JsProgram) -> Result<()> {
413        for stmt in &program.body {
414            self.stmt_validator.validate(stmt)?;
415        }
416        Ok(())
417    }
418}
419
420/// IR 模块验证器
421pub struct IRValidator {
422    /// 程序验证器
423    program_validator: ProgramValidator,
424}
425
426impl IRValidator {
427    /// 创建新的 IR 模块验证器
428    pub fn new() -> Self {
429        Self { program_validator: ProgramValidator::new() }
430    }
431
432    /// 验证 IR 模块
433    pub fn validate(&mut self, module: &IRModule) -> Result<()> {
434        // 首先执行基本验证
435        module.validate()?;
436
437        // 然后执行类型检查和语义验证
438        if let Some(script) = &module.script {
439            self.program_validator.validate(script)?;
440        }
441        if let Some(script_server) = &module.script_server {
442            self.program_validator.validate(script_server)?;
443        }
444        if let Some(script_client) = &module.script_client {
445            self.program_validator.validate(script_client)?;
446        }
447
448        Ok(())
449    }
450}