1use std::{2 fmt::{self, Debug, Display},3 ops::{Deref, RangeInclusive},4};56use jrsonnet_gcmodule::Acyclic;7use jrsonnet_interner::IStr;89use crate::{10 NumValue,11 function::{FunctionSignature, ParamDefault, ParamName, ParamParse},12 source::Source,13};1415#[derive(Debug, PartialEq, Acyclic)]16pub enum FieldName {17 18 Fixed(IStr),19 20 Dyn(Expr),21}2223#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]24#[repr(u8)]25pub enum Visibility {26 27 Normal,28 29 Hidden,30 31 Unhide,32}3334#[derive(Debug, Clone, PartialEq, Acyclic)]35pub enum TrivialVal {36 Null,37 Bool(bool),38 Num(NumValue),39 Str(IStr),40}4142impl Visibility {43 pub fn is_visible(&self) -> bool {44 matches!(self, Self::Normal | Self::Unhide)45 }46}4748#[derive(Debug, PartialEq, Acyclic)]49pub struct AssertStmt {50 pub assertion: Spanned<Expr>,51 pub message: Option<Expr>,52}5354#[derive(Debug, PartialEq, Acyclic)]55pub struct FieldMember {56 pub name: Spanned<FieldName>,57 pub plus: bool,58 pub params: Option<ExprParams>,59 pub visibility: Visibility,60 pub value: Expr,61}6263#[derive(Debug, PartialEq, Acyclic)]64pub enum Member {65 Field(FieldMember),66 BindStmt(BindSpec),67 AssertStmt(AssertStmt),68}6970#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]71pub enum UnaryOpType {72 Plus,73 Minus,74 BitNot,75 Not,76}7778impl Display for UnaryOpType {79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {80 use UnaryOpType::*;81 write!(82 f,83 "{}",84 match self {85 Plus => "+",86 Minus => "-",87 BitNot => "~",88 Not => "!",89 }90 )91 }92}9394#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]95pub enum BinaryOpType {96 Mul,97 Div,9899 100 Mod,101102 Add,103 Sub,104105 Lhs,106 Rhs,107108 Lt,109 Gt,110 Lte,111 Gte,112113 BitAnd,114 BitOr,115 BitXor,116117 Eq,118 Neq,119120 And,121 Or,122 #[cfg(feature = "exp-null-coaelse")]123 NullCoaelse,124125 126 In,127}128129impl Display for BinaryOpType {130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {131 use BinaryOpType::*;132 write!(133 f,134 "{}",135 match self {136 Mul => "*",137 Div => "/",138 Mod => "%",139 Add => "+",140 Sub => "-",141 Lhs => "<<",142 Rhs => ">>",143 Lt => "<",144 Gt => ">",145 Lte => "<=",146 Gte => ">=",147 BitAnd => "&",148 BitOr => "|",149 BitXor => "^",150 Eq => "==",151 Neq => "!=",152 And => "&&",153 Or => "||",154 In => "in",155 #[cfg(feature = "exp-null-coaelse")]156 NullCoaelse => "??",157 }158 )159 }160}161162163#[derive(Debug, PartialEq, Acyclic)]164pub struct ExprParam {165 pub destruct: Destruct,166 pub default: Option<Expr>,167}168169170#[derive(Debug, PartialEq, Acyclic)]171pub struct ExprParams {172 pub exprs: Vec<ExprParam>,173 pub signature: FunctionSignature,174 pub(crate) binds_len: usize,175}176impl ExprParams {177 pub fn len(&self) -> usize {178 self.exprs.len()179 }180 pub fn is_empty(&self) -> bool {181 self.exprs.is_empty()182 }183184 pub fn binds_len(&self) -> usize {185 self.binds_len186 }187 pub fn new(exprs: Vec<ExprParam>) -> Self {188 Self {189 signature: FunctionSignature::new(190 exprs191 .iter()192 .map(|p| {193 ParamParse::new(194 p.destruct.name(),195 ParamDefault::exists(p.default.is_some()),196 )197 })198 .collect(),199 ),200 binds_len: exprs.iter().map(|v| v.destruct.binds_len()).sum(),201 exprs,202 }203 }204}205206#[derive(Debug, PartialEq, Acyclic)]207pub struct ArgsDesc {208 pub unnamed: Vec<Expr>,209 pub names: Vec<IStr>,210 pub values: Vec<Expr>,211}212impl ArgsDesc {213 pub fn new(unnamed: Vec<Expr>, names: Vec<IStr>, values: Vec<Expr>) -> Self {214 Self {215 unnamed,216 names,217 values,218 }219 }220}221222#[derive(Debug, PartialEq, Eq, Acyclic)]223pub enum DestructRest {224 225 Keep(IStr),226 227 Drop,228}229230#[derive(Debug, PartialEq, Acyclic)]231pub enum Destruct {232 Full(Spanned<IStr>),233 #[cfg(feature = "exp-destruct")]234 Skip,235 #[cfg(feature = "exp-destruct")]236 Array {237 start: Vec<Destruct>,238 rest: Option<DestructRest>,239 end: Vec<Destruct>,240 },241 #[cfg(feature = "exp-destruct")]242 Object {243 #[allow(clippy::type_complexity)]244 fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,245 rest: Option<DestructRest>,246 },247}248impl Destruct {249 250 pub fn name(&self) -> ParamName {251 match self {252 Self::Full(name) => ParamName::Named(name.value.clone()),253 #[cfg(feature = "exp-destruct")]254 _ => ParamName::Unnamed,255 }256 }257 pub fn binds_len(&self) -> usize {258 #[cfg(feature = "exp-destruct")]259 fn cap_rest(rest: &Option<DestructRest>) -> usize {260 match rest {261 Some(DestructRest::Keep(_)) => 1,262 Some(DestructRest::Drop) => 0,263 None => 0,264 }265 }266 match self {267 Self::Full(_) => 1,268 #[cfg(feature = "exp-destruct")]269 Self::Skip => 0,270 #[cfg(feature = "exp-destruct")]271 Self::Array { start, rest, end } => {272 start.iter().map(Destruct::binds_len).sum::<usize>()273 + end.iter().map(Destruct::binds_len).sum::<usize>()274 + cap_rest(rest)275 }276 #[cfg(feature = "exp-destruct")]277 Self::Object { fields, rest } => {278 let mut out = 0;279 for (_, into, _) in fields {280 match into {281 Some(v) => out += v.binds_len(),282 283 None => out += 1,284 }285 }286 out + cap_rest(rest)287 }288 }289 }290}291292#[derive(Debug, PartialEq, Acyclic)]293pub enum BindSpec {294 Field {295 into: Destruct,296 value: Expr,297 },298 Function {299 name: Spanned<IStr>,300 params: ExprParams,301 value: Expr,302 },303}304impl BindSpec {305 pub fn binds_len(&self) -> usize {306 match self {307 BindSpec::Field { into, .. } => into.binds_len(),308 BindSpec::Function { .. } => 1,309 }310 }311}312313#[derive(Debug, PartialEq, Acyclic)]314pub struct IfSpecData {315 pub span: Span,316 pub cond: Expr,317}318319#[derive(Debug, PartialEq, Acyclic)]320pub struct ForSpecData {321 pub destruct: Destruct,322 pub over: Expr,323}324325#[cfg(feature = "exp-object-iteration")]326#[derive(Debug, PartialEq, Acyclic)]327pub struct ForObjSpecData {328 pub key: IStr,329 pub visibility: Visibility,330 pub value: Destruct,331 pub over: Expr,332}333334#[derive(Debug, PartialEq, Acyclic)]335pub enum CompSpec {336 IfSpec(IfSpecData),337 ForSpec(ForSpecData),338 #[cfg(feature = "exp-object-iteration")]339 ForObjSpec(ForObjSpecData),340}341342#[derive(Debug, PartialEq, Acyclic)]343pub struct ObjComp {344 pub locals: Vec<BindSpec>,345 pub field: Box<FieldMember>,346 pub compspecs: Vec<CompSpec>,347}348349#[derive(Debug, PartialEq, Acyclic)]350pub struct ObjMembers {351 pub locals: Vec<BindSpec>,352 pub asserts: Vec<AssertStmt>,353 pub fields: Vec<FieldMember>,354}355356#[derive(Debug, PartialEq, Acyclic)]357pub enum ObjBody {358 MemberList(ObjMembers),359 ObjComp(ObjComp),360}361362363#[derive(Debug, PartialEq, Acyclic)]364pub enum IdentityKind {365 This,366 Super,367 Dollar,368}369370#[derive(Debug, PartialEq, Acyclic)]371pub struct SliceDesc {372 pub start: Option<Spanned<Expr>>,373 pub end: Option<Spanned<Expr>>,374 pub step: Option<Spanned<Expr>>,375}376377#[derive(Debug, PartialEq, Acyclic)]378pub struct AssertExpr {379 pub assert: AssertStmt,380 pub rest: Expr,381}382383#[derive(Debug, PartialEq, Acyclic)]384pub struct BinaryOp {385 pub lhs: Expr,386 pub op: BinaryOpType,387 pub rhs: Expr,388}389390#[derive(Debug, PartialEq, Acyclic, Clone, Copy)]391pub enum ImportKind {392 Normal,393 Str,394 Bin,395}396397#[derive(Debug, PartialEq, Acyclic)]398pub struct IfElse {399 pub cond: IfSpecData,400 pub cond_then: Expr,401 pub cond_else: Option<Expr>,402}403404#[derive(Debug, PartialEq, Acyclic)]405pub struct Slice {406 pub value: Expr,407 pub slice: SliceDesc,408}409410411#[derive(Debug, PartialEq, Acyclic)]412pub enum Expr {413 414 Identity(Span, IdentityKind),415416 417 Trivial(TrivialVal),418419 420 Var(Spanned<IStr>),421422 423 Arr(Vec<Expr>),424 425 426 427 428 429 430 431 432 433 434 435 ArrComp(Box<Expr>, Vec<CompSpec>),436437 438 Obj(ObjBody),439 440 ObjExtend(Box<Expr>, ObjBody),441442 443 UnaryOp(UnaryOpType, Box<Expr>),444 445 BinaryOp(Box<BinaryOp>),446 447 AssertExpr(Box<AssertExpr>),448 449 LocalExpr(Vec<BindSpec>, Box<Expr>),450451 452 Import(Spanned<ImportKind>, Box<Expr>),453 454 ErrorStmt(Span, Box<Expr>),455 456 Apply(Box<Expr>, Spanned<ArgsDesc>, bool),457 458 Index {459 indexable: Box<Expr>,460 parts: Vec<IndexPart>,461 },462 463 Function(Span, ExprParams, Box<Expr>),464 465 IfElse(Box<IfElse>),466 Slice(Box<Slice>),467}468469#[derive(Debug, PartialEq, Acyclic)]470pub struct IndexPart {471 pub span: Span,472 pub value: Expr,473 #[cfg(feature = "exp-null-coaelse")]474 pub null_coaelse: bool,475}476477478#[derive(Clone, PartialEq, Eq, Acyclic)]479#[repr(C)]480pub struct Span(pub Source, pub u32, pub u32);481impl Span {482 pub fn belongs_to(&self, other: &Span) -> bool {483 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2484 }485 pub fn range(&self) -> RangeInclusive<usize> {486 let start = self.1;487 let mut end = self.2;488 if end > start {489 490 end -= 1;491 }492 start as usize..=end as usize493 }494}495496#[cfg(target_pointer_width = "64")]497static_assertions::assert_eq_size!(Span, (usize, usize));498499impl Debug for Span {500 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {501 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)502 }503}504505#[derive(Clone, PartialEq, Acyclic)]506pub struct Spanned<T: Acyclic> {507 pub value: T,508 pub span: Span,509}510impl<T: Acyclic> Deref for Spanned<T> {511 type Target = T;512 fn deref(&self) -> &Self::Target {513 &self.value514 }515}516impl<T: Acyclic> Spanned<T> {517 #[inline]518 pub fn new(value: T, span: Span) -> Self {519 Self { value, span }520 }521 pub fn map<U: Acyclic>(self, v: impl FnOnce(T) -> U) -> Spanned<U> {522 Spanned {523 span: self.span,524 value: v(self.value),525 }526 }527 pub fn as_ref<'a>(&'a self) -> Spanned<&'a T>528 where529 &'a T: Acyclic,530 {531 Spanned {532 span: self.span.clone(),533 value: &self.value,534 }535 }536}537538impl<T: Debug + Acyclic> Debug for Spanned<T> {539 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {540 let expr = &**self;541 if f.alternate() {542 write!(f, "{:#?}", expr)?;543 } else {544 write!(f, "{:?}", expr)?;545 }546 write!(f, " from {:?}", self.span)?;547 Ok(())548 }549}