Skip to main content

nargo_ir/
expr.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::types::{MAX_ARRAY_LENGTH, MAX_OBJECT_SIZE, MAX_RECURSION_DEPTH, MAX_STRING_LENGTH, IRError, Trivia};
12
13/// TSE 属性
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15pub struct TseAttribute {
16    /// 属性名
17    pub name: String,
18    /// 属性值
19    pub value: Option<JsExpr>,
20    /// 是否为指令
21    pub is_directive: bool,
22    /// 位置信息
23    #[serde(default)]
24    pub span: Span,
25    /// Trivia 信息
26    #[serde(default)]
27    pub trivia: Trivia,
28}
29
30impl TseAttribute {
31    /// 验证 TSE 属性的有效性
32    pub fn validate(&self, depth: usize) -> Result<()> {
33        if self.name.len() > MAX_STRING_LENGTH {
34            return Err(IRError::SizeLimitExceeded("TSE attribute name length exceeded".to_string()).into());
35        }
36        if let Some(value) = &self.value {
37            value.validate(depth + 1)?;
38        }
39        Ok(())
40    }
41}
42
43/// JavaScript 表达式
44#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
45pub enum JsExpr {
46    /// 标识符
47    Identifier(String, #[serde(default)] Span, #[serde(default)] Trivia),
48    /// 字面量
49    Literal(NargoValue, #[serde(default)] Span, #[serde(default)] Trivia),
50    /// 一元表达式
51    Unary {
52        /// 操作符
53        op: String,
54        /// 参数
55        argument: Box<JsExpr>,
56        /// 位置信息
57        #[serde(default)]
58        span: Span,
59        /// Trivia 信息
60        #[serde(default)]
61        trivia: Trivia,
62    },
63    /// 二元表达式
64    Binary {
65        /// 左操作数
66        left: Box<JsExpr>,
67        /// 操作符
68        op: String,
69        /// 右操作数
70        right: Box<JsExpr>,
71        /// 位置信息
72        #[serde(default)]
73        span: Span,
74        /// Trivia 信息
75        #[serde(default)]
76        trivia: Trivia,
77    },
78    /// 函数调用
79    Call {
80        /// 调用目标
81        callee: Box<JsExpr>,
82        /// 参数列表
83        args: Vec<JsExpr>,
84        /// 位置信息
85        #[serde(default)]
86        span: Span,
87        /// Trivia 信息
88        #[serde(default)]
89        trivia: Trivia,
90    },
91    /// 成员访问
92    Member {
93        /// 对象
94        object: Box<JsExpr>,
95        /// 属性
96        property: Box<JsExpr>,
97        /// 是否为计算属性
98        computed: bool,
99        /// 位置信息
100        #[serde(default)]
101        span: Span,
102        /// Trivia 信息
103        #[serde(default)]
104        trivia: Trivia,
105    },
106    /// 可选链成员访问
107    OptionalMember {
108        /// 对象
109        object: Box<JsExpr>,
110        /// 属性
111        property: Box<JsExpr>,
112        /// 是否为计算属性
113        computed: bool,
114        /// 位置信息
115        #[serde(default)]
116        span: Span,
117        /// Trivia 信息
118        #[serde(default)]
119        trivia: Trivia,
120    },
121    /// 可选链函数调用
122    OptionalCall {
123        /// 调用目标
124        callee: Box<JsExpr>,
125        /// 参数列表
126        args: Vec<JsExpr>,
127        /// 位置信息
128        #[serde(default)]
129        span: Span,
130        /// Trivia 信息
131        #[serde(default)]
132        trivia: Trivia,
133    },
134    /// 空值合并表达式
135    NullishCoalescing {
136        /// 左操作数
137        left: Box<JsExpr>,
138        /// 右操作数
139        right: Box<JsExpr>,
140        /// 位置信息
141        #[serde(default)]
142        span: Span,
143        /// Trivia 信息
144        #[serde(default)]
145        trivia: Trivia,
146    },
147    /// 逻辑赋值表达式
148    LogicalAssignment {
149        /// 操作符
150        op: String,
151        /// 左操作数
152        left: Box<JsExpr>,
153        /// 右操作数
154        right: Box<JsExpr>,
155        /// 位置信息
156        #[serde(default)]
157        span: Span,
158        /// Trivia 信息
159        #[serde(default)]
160        trivia: Trivia,
161    },
162    /// 数组字面量
163    Array(Vec<JsExpr>, #[serde(default)] Span, #[serde(default)] Trivia),
164    /// 对象字面量
165    Object(HashMap<String, JsExpr>, #[serde(default)] Span, #[serde(default)] Trivia),
166    /// 箭头函数
167    ArrowFunction {
168        /// 参数列表
169        params: Vec<String>,
170        /// 函数体
171        body: Box<JsExpr>,
172        /// 位置信息
173        #[serde(default)]
174        span: Span,
175        /// Trivia 信息
176        #[serde(default)]
177        trivia: Trivia,
178    },
179    /// TSE 元素
180    TseElement {
181        /// 标签名
182        tag: String,
183        /// 属性列表
184        attributes: Vec<TseAttribute>,
185        /// 子元素
186        children: Vec<JsExpr>,
187        /// 位置信息
188        #[serde(default)]
189        span: Span,
190        /// Trivia 信息
191        #[serde(default)]
192        trivia: Trivia,
193    },
194    /// 条件表达式
195    Conditional {
196        /// 条件
197        test: Box<JsExpr>,
198        /// 真分支
199        consequent: Box<JsExpr>,
200        /// 假分支
201        alternate: Box<JsExpr>,
202        /// 位置信息
203        #[serde(default)]
204        span: Span,
205        /// Trivia 信息
206        #[serde(default)]
207        trivia: Trivia,
208    },
209    /// 模板字面量
210    TemplateLiteral {
211        /// 模板字符串片段
212        quasis: Vec<String>,
213        /// 表达式
214        expressions: Vec<JsExpr>,
215        /// 位置信息
216        #[serde(default)]
217        span: Span,
218        /// Trivia 信息
219        #[serde(default)]
220        trivia: Trivia,
221    },
222    /// 展开表达式
223    Spread(Box<JsExpr>, #[serde(default)] Span, #[serde(default)] Trivia),
224    /// 类型测试表达式
225    TypeOf(Box<JsExpr>, #[serde(default)] Span, #[serde(default)] Trivia),
226    /// 实例测试表达式
227    InstanceOf {
228        /// 左操作数
229        left: Box<JsExpr>,
230        /// 右操作数
231        right: Box<JsExpr>,
232        /// 位置信息
233        #[serde(default)]
234        span: Span,
235        /// Trivia 信息
236        #[serde(default)]
237        trivia: Trivia,
238    },
239    /// 其他表达式
240    Other(String, #[serde(default)] Span, #[serde(default)] Trivia),
241}
242
243impl JsExpr {
244    /// 获取表达式的位置信息
245    pub fn span(&self) -> Span {
246        match self {
247            JsExpr::Identifier(_, span, _) => *span,
248            JsExpr::Literal(_, span, _) => *span,
249            JsExpr::Unary { span, .. } => *span,
250            JsExpr::Binary { span, .. } => *span,
251            JsExpr::Call { span, .. } => *span,
252            JsExpr::Member { span, .. } => *span,
253            JsExpr::OptionalMember { span, .. } => *span,
254            JsExpr::OptionalCall { span, .. } => *span,
255            JsExpr::NullishCoalescing { span, .. } => *span,
256            JsExpr::LogicalAssignment { span, .. } => *span,
257            JsExpr::Array(_, span, _) => *span,
258            JsExpr::Object(_, span, _) => *span,
259            JsExpr::ArrowFunction { span, .. } => *span,
260            JsExpr::TseElement { span, .. } => *span,
261            JsExpr::Conditional { span, .. } => *span,
262            JsExpr::TemplateLiteral { span, .. } => *span,
263            JsExpr::Spread(_, span, _) => *span,
264            JsExpr::TypeOf(_, span, _) => *span,
265            JsExpr::InstanceOf { span, .. } => *span,
266            JsExpr::Other(_, span, _) => *span,
267        }
268    }
269
270    /// 获取表达式的 trivia 信息
271    pub fn trivia(&self) -> &Trivia {
272        match self {
273            JsExpr::Identifier(_, _, t) => t,
274            JsExpr::Literal(_, _, t) => t,
275            JsExpr::Unary { trivia, .. } => trivia,
276            JsExpr::Binary { trivia, .. } => trivia,
277            JsExpr::Call { trivia, .. } => trivia,
278            JsExpr::Member { trivia, .. } => trivia,
279            JsExpr::OptionalMember { trivia, .. } => trivia,
280            JsExpr::OptionalCall { trivia, .. } => trivia,
281            JsExpr::NullishCoalescing { trivia, .. } => trivia,
282            JsExpr::LogicalAssignment { trivia, .. } => trivia,
283            JsExpr::Array(_, _, t) => t,
284            JsExpr::Object(_, _, t) => t,
285            JsExpr::ArrowFunction { trivia, .. } => trivia,
286            JsExpr::TseElement { trivia, .. } => trivia,
287            JsExpr::Conditional { trivia, .. } => trivia,
288            JsExpr::TemplateLiteral { trivia, .. } => trivia,
289            JsExpr::Spread(_, _, t) => t,
290            JsExpr::TypeOf(_, _, t) => t,
291            JsExpr::InstanceOf { trivia, .. } => trivia,
292            JsExpr::Other(_, _, t) => t,
293        }
294    }
295
296    /// 验证表达式的有效性
297    pub fn validate(&self, depth: usize) -> Result<()> {
298        if depth > MAX_RECURSION_DEPTH {
299            return Err(IRError::CircularReference("Expression recursion depth exceeded".to_string()).into());
300        }
301
302        match self {
303            JsExpr::Identifier(id, _, _) => {
304                if id.len() > MAX_STRING_LENGTH {
305                    return Err(IRError::SizeLimitExceeded("Identifier length exceeded".to_string()).into());
306                }
307                Ok(())
308            }
309            JsExpr::Literal(value, _, _) => value.validate(depth + 1),
310            JsExpr::Unary { argument, .. } => argument.validate(depth + 1),
311            JsExpr::Binary { left, right, .. } => {
312                left.validate(depth + 1)?;
313                right.validate(depth + 1)
314            }
315            JsExpr::Call { callee, args, .. } => {
316                callee.validate(depth + 1)?;
317                if args.len() > MAX_ARRAY_LENGTH {
318                    return Err(IRError::SizeLimitExceeded("Call arguments length exceeded".to_string()).into());
319                }
320                for arg in args {
321                    arg.validate(depth + 1)?;
322                }
323                Ok(())
324            }
325            JsExpr::Member { object, property, .. } => {
326                object.validate(depth + 1)?;
327                property.validate(depth + 1)
328            }
329            JsExpr::OptionalMember { object, property, .. } => {
330                object.validate(depth + 1)?;
331                property.validate(depth + 1)
332            }
333            JsExpr::OptionalCall { callee, args, .. } => {
334                callee.validate(depth + 1)?;
335                if args.len() > MAX_ARRAY_LENGTH {
336                    return Err(IRError::SizeLimitExceeded("Optional call arguments length exceeded".to_string()).into());
337                }
338                for arg in args {
339                    arg.validate(depth + 1)?;
340                }
341                Ok(())
342            }
343            JsExpr::NullishCoalescing { left, right, .. } => {
344                left.validate(depth + 1)?;
345                right.validate(depth + 1)
346            }
347            JsExpr::LogicalAssignment { op, left, right, .. } => {
348                if op.len() > MAX_STRING_LENGTH {
349                    return Err(IRError::SizeLimitExceeded("Logical assignment operator length exceeded".to_string()).into());
350                }
351                left.validate(depth + 1)?;
352                right.validate(depth + 1)
353            }
354            JsExpr::Array(items, _, _) => {
355                if items.len() > MAX_ARRAY_LENGTH {
356                    return Err(IRError::SizeLimitExceeded("Array length exceeded".to_string()).into());
357                }
358                for item in items {
359                    item.validate(depth + 1)?;
360                }
361                Ok(())
362            }
363            JsExpr::Object(props, _, _) => {
364                if props.len() > MAX_OBJECT_SIZE {
365                    return Err(IRError::SizeLimitExceeded("Object size exceeded".to_string()).into());
366                }
367                for (key, value) in props {
368                    if key.len() > MAX_STRING_LENGTH {
369                        return Err(IRError::SizeLimitExceeded("Object key length exceeded".to_string()).into());
370                    }
371                    value.validate(depth + 1)?;
372                }
373                Ok(())
374            }
375            JsExpr::ArrowFunction { params, body, .. } => {
376                if params.len() > MAX_ARRAY_LENGTH {
377                    return Err(IRError::SizeLimitExceeded("Arrow function parameters length exceeded".to_string()).into());
378                }
379                for param in params {
380                    if param.len() > MAX_STRING_LENGTH {
381                        return Err(IRError::SizeLimitExceeded("Parameter name length exceeded".to_string()).into());
382                    }
383                }
384                body.validate(depth + 1)
385            }
386            JsExpr::TseElement { tag, attributes, children, .. } => {
387                if tag.len() > MAX_STRING_LENGTH {
388                    return Err(IRError::SizeLimitExceeded("TSE element tag length exceeded".to_string()).into());
389                }
390                if attributes.len() > MAX_ARRAY_LENGTH {
391                    return Err(IRError::SizeLimitExceeded("TSE element attributes length exceeded".to_string()).into());
392                }
393                for attr in attributes {
394                    attr.validate(depth + 1)?;
395                }
396                if children.len() > MAX_ARRAY_LENGTH {
397                    return Err(IRError::SizeLimitExceeded("TSE element children length exceeded".to_string()).into());
398                }
399                for child in children {
400                    child.validate(depth + 1)?;
401                }
402                Ok(())
403            }
404            JsExpr::Conditional { test, consequent, alternate, .. } => {
405                test.validate(depth + 1)?;
406                consequent.validate(depth + 1)?;
407                alternate.validate(depth + 1)
408            }
409            JsExpr::TemplateLiteral { quasis, expressions, .. } => {
410                if quasis.len() > MAX_ARRAY_LENGTH {
411                    return Err(IRError::SizeLimitExceeded("Template literal quasis length exceeded".to_string()).into());
412                }
413                for quasi in quasis {
414                    if quasi.len() > MAX_STRING_LENGTH {
415                        return Err(IRError::SizeLimitExceeded("Template literal quasi length exceeded".to_string()).into());
416                    }
417                }
418                if expressions.len() > MAX_ARRAY_LENGTH {
419                    return Err(IRError::SizeLimitExceeded("Template literal expressions length exceeded".to_string()).into());
420                }
421                for expr in expressions {
422                    expr.validate(depth + 1)?;
423                }
424                Ok(())
425            }
426            JsExpr::Spread(expr, _, _) => expr.validate(depth + 1),
427            JsExpr::TypeOf(expr, _, _) => expr.validate(depth + 1),
428            JsExpr::InstanceOf { left, right, .. } => {
429                left.validate(depth + 1)?;
430                right.validate(depth + 1)
431            }
432            JsExpr::Other(code, _, _) => {
433                if code.len() > MAX_STRING_LENGTH {
434                    return Err(IRError::SizeLimitExceeded("Other expression code length exceeded".to_string()).into());
435                }
436                Ok(())
437            }
438        }
439    }
440
441    /// 优化表达式
442    pub fn optimize(&mut self) {
443        crate::optimizer::ExprOptimizer::optimize(self);
444    }
445
446    /// 检查表达式是否为常量
447    pub fn is_constant(&self) -> bool {
448        match self {
449            JsExpr::Literal(_, _, _) => true,
450            JsExpr::Unary { argument, .. } => argument.is_constant(),
451            JsExpr::Binary { left, right, .. } => left.is_constant() && right.is_constant(),
452            _ => false,
453        }
454    }
455}
456
457/// 表达式访问者 trait
458pub trait JsExprVisitor<R> {
459    /// 访问标识符表达式
460    fn visit_identifier(&mut self, id: &String, span: &Span, trivia: &Trivia) -> R;
461    /// 访问字面量表达式
462    fn visit_literal(&mut self, value: &NargoValue, span: &Span, trivia: &Trivia) -> R;
463    /// 访问一元表达式
464    fn visit_unary(&mut self, op: &String, argument: &JsExpr, span: &Span, trivia: &Trivia) -> R;
465    /// 访问二元表达式
466    fn visit_binary(&mut self, left: &JsExpr, op: &String, right: &JsExpr, span: &Span, trivia: &Trivia) -> R;
467    /// 访问函数调用表达式
468    fn visit_call(&mut self, callee: &JsExpr, args: &Vec<JsExpr>, span: &Span, trivia: &Trivia) -> R;
469    /// 访问成员访问表达式
470    fn visit_member(&mut self, object: &JsExpr, property: &JsExpr, computed: bool, span: &Span, trivia: &Trivia) -> R;
471    /// 访问可选链成员访问表达式
472    fn visit_optional_member(&mut self, object: &JsExpr, property: &JsExpr, computed: bool, span: &Span, trivia: &Trivia) -> R;
473    /// 访问可选链函数调用表达式
474    fn visit_optional_call(&mut self, callee: &JsExpr, args: &Vec<JsExpr>, span: &Span, trivia: &Trivia) -> R;
475    /// 访问空值合并表达式
476    fn visit_nullish_coalescing(&mut self, left: &JsExpr, right: &JsExpr, span: &Span, trivia: &Trivia) -> R;
477    /// 访问逻辑赋值表达式
478    fn visit_logical_assignment(&mut self, op: &String, left: &JsExpr, right: &JsExpr, span: &Span, trivia: &Trivia) -> R;
479    /// 访问数组字面量表达式
480    fn visit_array(&mut self, items: &Vec<JsExpr>, span: &Span, trivia: &Trivia) -> R;
481    /// 访问对象字面量表达式
482    fn visit_object(&mut self, props: &HashMap<String, JsExpr>, span: &Span, trivia: &Trivia) -> R;
483    /// 访问箭头函数表达式
484    fn visit_arrow_function(&mut self, params: &Vec<String>, body: &JsExpr, span: &Span, trivia: &Trivia) -> R;
485    /// 访问 TSE 元素表达式
486    fn visit_tse_element(&mut self, tag: &String, attributes: &Vec<TseAttribute>, children: &Vec<JsExpr>, span: &Span, trivia: &Trivia) -> R;
487    /// 访问条件表达式
488    fn visit_conditional(&mut self, test: &JsExpr, consequent: &JsExpr, alternate: &JsExpr, span: &Span, trivia: &Trivia) -> R;
489    /// 访问模板字面量表达式
490    fn visit_template_literal(&mut self, quasis: &Vec<String>, expressions: &Vec<JsExpr>, span: &Span, trivia: &Trivia) -> R;
491    /// 访问展开表达式
492    fn visit_spread(&mut self, expr: &JsExpr, span: &Span, trivia: &Trivia) -> R;
493    /// 访问类型测试表达式
494    fn visit_type_of(&mut self, expr: &JsExpr, span: &Span, trivia: &Trivia) -> R;
495    /// 访问实例测试表达式
496    fn visit_instance_of(&mut self, left: &JsExpr, right: &JsExpr, span: &Span, trivia: &Trivia) -> R;
497    /// 访问其他表达式
498    fn visit_other(&mut self, code: &String, span: &Span, trivia: &Trivia) -> R;
499}
500
501impl JsExpr {
502    /// 接受访问者
503    pub fn accept<R>(&self, visitor: &mut dyn JsExprVisitor<R>) -> R {
504        match self {
505            JsExpr::Identifier(id, span, trivia) => visitor.visit_identifier(id, span, trivia),
506            JsExpr::Literal(value, span, trivia) => visitor.visit_literal(value, span, trivia),
507            JsExpr::Unary { op, argument, span, trivia } => visitor.visit_unary(op, argument, span, trivia),
508            JsExpr::Binary { left, op, right, span, trivia } => visitor.visit_binary(left, op, right, span, trivia),
509            JsExpr::Call { callee, args, span, trivia } => visitor.visit_call(callee, args, span, trivia),
510            JsExpr::Member { object, property, computed, span, trivia } => visitor.visit_member(object, property, *computed, span, trivia),
511            JsExpr::OptionalMember { object, property, computed, span, trivia } => visitor.visit_optional_member(object, property, *computed, span, trivia),
512            JsExpr::OptionalCall { callee, args, span, trivia } => visitor.visit_optional_call(callee, args, span, trivia),
513            JsExpr::NullishCoalescing { left, right, span, trivia } => visitor.visit_nullish_coalescing(left, right, span, trivia),
514            JsExpr::LogicalAssignment { op, left, right, span, trivia } => visitor.visit_logical_assignment(op, left, right, span, trivia),
515            JsExpr::Array(items, span, trivia) => visitor.visit_array(items, span, trivia),
516            JsExpr::Object(props, span, trivia) => visitor.visit_object(props, span, trivia),
517            JsExpr::ArrowFunction { params, body, span, trivia } => visitor.visit_arrow_function(params, body, span, trivia),
518            JsExpr::TseElement { tag, attributes, children, span, trivia } => visitor.visit_tse_element(tag, attributes, children, span, trivia),
519            JsExpr::Conditional { test, consequent, alternate, span, trivia } => visitor.visit_conditional(test, consequent, alternate, span, trivia),
520            JsExpr::TemplateLiteral { quasis, expressions, span, trivia } => visitor.visit_template_literal(quasis, expressions, span, trivia),
521            JsExpr::Spread(expr, span, trivia) => visitor.visit_spread(expr, span, trivia),
522            JsExpr::TypeOf(expr, span, trivia) => visitor.visit_type_of(expr, span, trivia),
523            JsExpr::InstanceOf { left, right, span, trivia } => visitor.visit_instance_of(left, right, span, trivia),
524            JsExpr::Other(code, span, trivia) => visitor.visit_other(code, span, trivia),
525        }
526    }
527}