1use jrsonnet_interner::IStr;23#[cfg(feature = "exp-object-iteration")]4use crate::ForObjSpecData;5use crate::{6 ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, Expr, ExprParam,7 ExprParams, FieldMember, FieldName, ForSpecData, IfElse, IfSpecData, ImportKind, IndexPart,8 ObjBody, ObjComp, ObjMembers, Slice, SliceDesc,9};1011pub trait Visitor: Sized {12 fn visit_expr(&mut self, e: &Expr) {13 visit_expr(self, e)14 }15 fn visit_import(&mut self, _as_expression: bool, _value: IStr) {}16}1718#[cfg(feature = "exp-destruct")]19pub fn visit_destruct_rest<V: Visitor>(_v: &mut V, destruct: &crate::DestructRest) {20 match destruct {21 crate::DestructRest::Keep(_name) => {}22 crate::DestructRest::Drop => {}23 }24}2526#[allow(unused_variables, reason = "used with exp-destruct")]27pub fn visit_destruct<V: Visitor>(v: &mut V, destruct: &Destruct) {28 match destruct {29 Destruct::Full(_istr) => {}30 #[cfg(feature = "exp-destruct")]31 Destruct::Skip => {}32 #[cfg(feature = "exp-destruct")]33 Destruct::Array { start, rest, end } => {34 for s in start {35 visit_destruct(v, s);36 }37 if let Some(rest) = rest {38 visit_destruct_rest(v, rest);39 }40 for s in end {41 visit_destruct(v, s);42 }43 }44 #[cfg(feature = "exp-destruct")]45 Destruct::Object { fields, rest } => {46 for (_name, into, default) in fields {47 if let Some(into) = into {48 visit_destruct(v, into);49 }50 if let Some(default) = default {51 v.visit_expr(default);52 }53 if let Some(rest) = rest {54 visit_destruct_rest(v, rest);55 }56 }57 }58 }59}6061pub fn visit_if_spec<V: Visitor>(v: &mut V, cond: &IfSpecData) {62 let IfSpecData { span: _, cond } = cond;63 v.visit_expr(cond);64}6566pub fn visit_comp_spec<V: Visitor>(v: &mut V, c: &CompSpec) {67 match c {68 CompSpec::IfSpec(cond) => visit_if_spec(v, cond),69 CompSpec::ForSpec(for_spec_data) => {70 let ForSpecData { destruct, over } = for_spec_data;71 visit_destruct(v, destruct);72 v.visit_expr(over);73 }74 #[cfg(feature = "exp-object-iteration")]75 CompSpec::ForObjSpec(for_obj_spec_data) => {76 let ForObjSpecData {77 key: _,78 visibility: _,79 value,80 over,81 } = for_obj_spec_data;82 visit_destruct(v, value);83 v.visit_expr(over);84 }85 }86}87pub fn visit_params<V: Visitor>(v: &mut V, par: &ExprParams) {88 let ExprParams {89 exprs,90 signature: _,91 binds_len: _,92 } = par;93 for par in &**exprs {94 let ExprParam { destruct, default } = ∥95 visit_destruct(v, destruct);96 if let Some(default) = default {97 v.visit_expr(default);98 }99 }100}101102pub fn visit_bind_spec<V: Visitor>(v: &mut V, bind: &BindSpec) {103 match bind {104 BindSpec::Field { into, value } => {105 visit_destruct(v, into);106 v.visit_expr(value);107 }108 BindSpec::Function {109 name: _,110 params,111 value,112 } => {113 visit_params(v, params);114 v.visit_expr(value);115 }116 }117}118119pub fn visit_field_member<V: Visitor>(v: &mut V, mem: &FieldMember) {120 let FieldMember {121 name,122 plus: _,123 params,124 visibility: _,125 value,126 } = mem;127 match &**name {128 FieldName::Fixed(_istr) => {}129 FieldName::Dyn(expr) => v.visit_expr(expr),130 }131 if let Some(params) = params {132 visit_params(v, params);133 }134 v.visit_expr(value);135}136137pub fn visit_obj_body<V: Visitor>(v: &mut V, obj_body: &ObjBody) {138 match obj_body {139 ObjBody::MemberList(obj_members) => {140 let ObjMembers {141 locals,142 asserts,143 fields,144 } = obj_members;145 for local in &**locals {146 visit_bind_spec(v, local);147 }148 for assert in &**asserts {149 visit_assert_stmt(v, assert);150 }151 for field in fields {152 visit_field_member(v, field);153 }154 }155 ObjBody::ObjComp(obj_comp) => {156 let ObjComp {157 locals,158 field,159 compspecs,160 } = obj_comp;161 for local in &**locals {162 visit_bind_spec(v, local);163 }164 visit_field_member(v, field);165 for compspec in compspecs {166 visit_comp_spec(v, compspec);167 }168 }169 }170}171172pub fn visit_assert_stmt<V: Visitor>(v: &mut V, ass: &AssertStmt) {173 let AssertStmt { assertion, message } = ass;174 v.visit_expr(assertion);175 if let Some(message) = message {176 v.visit_expr(message);177 }178}179pub fn visit_expr<V: Visitor>(v: &mut V, e: &Expr) {180 match e {181 Expr::Literal(_span, _literal_type) => {}182 Expr::Str(_istr) => {}183 Expr::Num(_num) => {}184 Expr::Var(_spanned) => {}185 Expr::Arr(exprs) => {186 for e in &**exprs {187 v.visit_expr(e);188 }189 }190 Expr::ArrComp(expr, comp_specs) => {191 v.visit_expr(expr);192 for ele in comp_specs {193 visit_comp_spec(v, ele);194 }195 }196 Expr::Obj(obj_body) => visit_obj_body(v, obj_body),197 Expr::ObjExtend(expr, obj_body) => {198 v.visit_expr(expr);199 visit_obj_body(v, obj_body);200 }201 Expr::UnaryOp(_unary_op_type, expr) => {202 v.visit_expr(expr);203 }204 Expr::BinaryOp(binary_op) => {205 let BinaryOp { lhs, op: _, rhs } = &**binary_op;206 v.visit_expr(lhs);207 v.visit_expr(rhs);208 }209 Expr::AssertExpr(assert_expr) => {210 let AssertExpr { assert, rest } = &**assert_expr;211 visit_assert_stmt(v, assert);212 v.visit_expr(rest);213 }214 Expr::LocalExpr(bind_specs, expr) => {215 for local in bind_specs {216 visit_bind_spec(v, local);217 }218 v.visit_expr(expr);219 }220 Expr::Import(kind, expr) => {221 v.visit_expr(expr);222223 if let Expr::Str(expr) = &**expr {224 v.visit_import(matches!(**kind, ImportKind::Normal), expr.clone());225 }226 }227 Expr::ErrorStmt(_span, expr) => {228 v.visit_expr(expr);229 }230 Expr::Apply(expr, spanned, _) => {231 v.visit_expr(expr);232 let ArgsDesc {233 unnamed,234 names: _,235 values,236 } = &**spanned;237 for unnamed in unnamed {238 v.visit_expr(unnamed);239 }240 for named in values {241 v.visit_expr(named);242 }243 }244 Expr::Index { indexable, parts } => {245 v.visit_expr(indexable);246247 for part in parts {248 let IndexPart {249 span: _,250 value,251 #[cfg(feature = "exp-null-coaelse")]252 null_coaelse: _,253 } = part;254 v.visit_expr(value);255 }256 }257 Expr::Function(_span, expr_params, expr) => {258 visit_params(v, expr_params);259 v.visit_expr(expr);260 }261 Expr::IfElse(if_else) => {262 let IfElse {263 cond,264 cond_then,265 cond_else,266 } = &**if_else;267 visit_if_spec(v, cond);268 v.visit_expr(cond_then);269 if let Some(cond_else) = cond_else {270 v.visit_expr(cond_else);271 }272 }273 Expr::Slice(slice) => {274 let Slice { value, slice } = &**slice;275 v.visit_expr(value);276 let SliceDesc { start, end, step } = slice;277278 if let Some(start) = start {279 v.visit_expr(start);280 }281 if let Some(end) = end {282 v.visit_expr(end);283 }284 if let Some(step) = step {285 v.visit_expr(step);286 }287 }288 }289}