1use std::{2 fmt::{self, Debug, Display},3 ops::Deref,4 rc::Rc,5};67use jrsonnet_gcmodule::Trace;8use jrsonnet_interner::IStr;910use crate::source::Source;1112#[derive(Debug, PartialEq, Trace)]13pub enum FieldName {14 15 Fixed(IStr),16 17 Dyn(LocExpr),18}1920#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]21#[repr(u8)]22pub enum Visibility {23 24 Normal,25 26 Hidden,27 28 Unhide,29}3031impl Visibility {32 pub fn is_visible(&self) -> bool {33 matches!(self, Self::Normal | Self::Unhide)34 }35}3637#[derive(Clone, Debug, PartialEq, Trace)]38pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);3940#[derive(Debug, PartialEq, Trace)]41pub struct FieldMember {42 pub name: FieldName,43 pub plus: bool,44 pub params: Option<ParamsDesc>,45 pub visibility: Visibility,46 pub value: LocExpr,47}4849#[derive(Debug, PartialEq, Trace)]50pub enum Member {51 Field(FieldMember),52 BindStmt(BindSpec),53 AssertStmt(AssertStmt),54}5556#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]57pub enum UnaryOpType {58 Plus,59 Minus,60 BitNot,61 Not,62}6364impl Display for UnaryOpType {65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {66 use UnaryOpType::*;67 write!(68 f,69 "{}",70 match self {71 Plus => "+",72 Minus => "-",73 BitNot => "~",74 Not => "!",75 }76 )77 }78}7980#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]81pub enum BinaryOpType {82 Mul,83 Div,8485 86 Mod,8788 Add,89 Sub,9091 Lhs,92 Rhs,9394 Lt,95 Gt,96 Lte,97 Gte,9899 BitAnd,100 BitOr,101 BitXor,102103 Eq,104 Neq,105106 And,107 Or,108 #[cfg(feature = "exp-null-coaelse")]109 NullCoaelse,110111 112 In,113}114115impl Display for BinaryOpType {116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {117 use BinaryOpType::*;118 write!(119 f,120 "{}",121 match self {122 Mul => "*",123 Div => "/",124 Mod => "%",125 Add => "+",126 Sub => "-",127 Lhs => "<<",128 Rhs => ">>",129 Lt => "<",130 Gt => ">",131 Lte => "<=",132 Gte => ">=",133 BitAnd => "&",134 BitOr => "|",135 BitXor => "^",136 Eq => "==",137 Neq => "!=",138 And => "&&",139 Or => "||",140 In => "in",141 #[cfg(feature = "exp-null-coaelse")]142 NullCoaelse => "??",143 }144 )145 }146}147148149#[derive(Debug, PartialEq, Trace)]150pub struct Param(pub Destruct, pub Option<LocExpr>);151152153#[derive(Debug, Clone, PartialEq, Trace)]154pub struct ParamsDesc(pub Rc<Vec<Param>>);155156impl Deref for ParamsDesc {157 type Target = Vec<Param>;158 fn deref(&self) -> &Self::Target {159 &self.0160 }161}162163#[derive(Debug, PartialEq, Trace)]164pub struct ArgsDesc {165 pub unnamed: Vec<LocExpr>,166 pub named: Vec<(IStr, LocExpr)>,167}168impl ArgsDesc {169 pub fn new(unnamed: Vec<LocExpr>, named: Vec<(IStr, LocExpr)>) -> Self {170 Self { unnamed, named }171 }172}173174#[derive(Debug, Clone, PartialEq, Eq, Trace)]175pub enum DestructRest {176 177 Keep(IStr),178 179 Drop,180}181182#[derive(Debug, Clone, PartialEq, Trace)]183pub enum Destruct {184 Full(IStr),185 #[cfg(feature = "exp-destruct")]186 Skip,187 #[cfg(feature = "exp-destruct")]188 Array {189 start: Vec<Destruct>,190 rest: Option<DestructRest>,191 end: Vec<Destruct>,192 },193 #[cfg(feature = "exp-destruct")]194 Object {195 fields: Vec<(IStr, Option<Destruct>, Option<LocExpr>)>,196 rest: Option<DestructRest>,197 },198}199impl Destruct {200 201 pub fn name(&self) -> Option<IStr> {202 match self {203 Self::Full(name) => Some(name.clone()),204 #[cfg(feature = "exp-destruct")]205 _ => None,206 }207 }208 pub fn capacity_hint(&self) -> usize {209 #[cfg(feature = "exp-destruct")]210 fn cap_rest(rest: &Option<DestructRest>) -> usize {211 match rest {212 Some(DestructRest::Keep(_)) => 1,213 Some(DestructRest::Drop) => 0,214 None => 0,215 }216 }217 match self {218 Self::Full(_) => 1,219 #[cfg(feature = "exp-destruct")]220 Self::Skip => 0,221 #[cfg(feature = "exp-destruct")]222 Self::Array { start, rest, end } => {223 start.iter().map(Destruct::capacity_hint).sum::<usize>()224 + end.iter().map(Destruct::capacity_hint).sum::<usize>()225 + cap_rest(rest)226 }227 #[cfg(feature = "exp-destruct")]228 Self::Object { fields, rest } => {229 let mut out = 0;230 for (_, into, _) in fields {231 match into {232 Some(v) => out += v.capacity_hint(),233 234 None => out += 1,235 }236 }237 out + cap_rest(rest)238 }239 }240 }241}242243#[derive(Debug, Clone, PartialEq, Trace)]244pub enum BindSpec {245 Field {246 into: Destruct,247 value: LocExpr,248 },249 Function {250 name: IStr,251 params: ParamsDesc,252 value: LocExpr,253 },254}255impl BindSpec {256 pub fn capacity_hint(&self) -> usize {257 match self {258 BindSpec::Field { into, .. } => into.capacity_hint(),259 BindSpec::Function { .. } => 1,260 }261 }262}263264#[derive(Debug, PartialEq, Trace)]265pub struct IfSpecData(pub LocExpr);266267#[derive(Debug, PartialEq, Trace)]268pub struct ForSpecData(pub Destruct, pub LocExpr);269270#[derive(Debug, PartialEq, Trace)]271pub enum CompSpec {272 IfSpec(IfSpecData),273 ForSpec(ForSpecData),274}275276#[derive(Debug, PartialEq, Trace)]277pub struct ObjComp {278 pub pre_locals: Vec<BindSpec>,279 pub field: FieldMember,280 pub post_locals: Vec<BindSpec>,281 pub compspecs: Vec<CompSpec>,282}283284#[derive(Debug, PartialEq, Trace)]285pub enum ObjBody {286 MemberList(Vec<Member>),287 ObjComp(ObjComp),288}289290#[derive(Debug, PartialEq, Eq, Clone, Copy, Trace)]291pub enum LiteralType {292 This,293 Super,294 Dollar,295 Null,296 True,297 False,298}299300#[derive(Debug, PartialEq, Trace)]301pub struct SliceDesc {302 pub start: Option<LocExpr>,303 pub end: Option<LocExpr>,304 pub step: Option<LocExpr>,305}306307308#[derive(Debug, PartialEq, Trace)]309pub enum Expr {310 Literal(LiteralType),311312 313 Str(IStr),314 315 Num(f64),316 317 Var(IStr),318319 320 Arr(Vec<LocExpr>),321 322 323 324 325 326 327 328 329 330 331 332 ArrComp(LocExpr, Vec<CompSpec>),333334 335 Obj(ObjBody),336 337 ObjExtend(LocExpr, ObjBody),338339 340 Parened(LocExpr),341342 343 UnaryOp(UnaryOpType, LocExpr),344 345 BinaryOp(LocExpr, BinaryOpType, LocExpr),346 347 AssertExpr(AssertStmt, LocExpr),348 349 LocalExpr(Vec<BindSpec>, LocExpr),350351 352 Import(LocExpr),353 354 ImportStr(LocExpr),355 356 ImportBin(LocExpr),357 358 ErrorStmt(LocExpr),359 360 Apply(LocExpr, ArgsDesc, bool),361 362 Index {363 indexable: LocExpr,364 parts: Vec<IndexPart>,365 },366 367 Function(ParamsDesc, LocExpr),368 369 IfElse {370 cond: IfSpecData,371 cond_then: LocExpr,372 cond_else: Option<LocExpr>,373 },374 Slice(LocExpr, SliceDesc),375}376377#[derive(Debug, PartialEq, Trace)]378pub struct IndexPart {379 pub value: LocExpr,380 #[cfg(feature = "exp-null-coaelse")]381 pub null_coaelse: bool,382}383384385#[derive(Clone, PartialEq, Eq, Trace)]386#[trace(skip)]387#[repr(C)]388pub struct Span(pub Source, pub u32, pub u32);389impl Span {390 pub fn belongs_to(&self, other: &Span) -> bool {391 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2392 }393}394395static_assertions::assert_eq_size!(Span, (usize, usize));396397impl Debug for Span {398 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {399 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)400 }401}402403404#[derive(Clone, PartialEq, Trace)]405pub struct LocExpr(Rc<(Expr, Span)>);406impl LocExpr {407 pub fn new(expr: Expr, span: Span) -> Self {408 Self(Rc::new((expr, span)))409 }410 #[inline]411 pub fn span(&self) -> Span {412 self.0 .1.clone()413 }414 #[inline]415 pub fn expr(&self) -> &Expr {416 &self.0 .0417 }418}419420static_assertions::assert_eq_size!(LocExpr, usize);421422impl Debug for LocExpr {423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {424 let expr = self.expr();425 if f.alternate() {426 write!(f, "{:#?}", expr)?;427 } else {428 write!(f, "{:?}", expr)?;429 }430 write!(f, " from {:?}", self.span())?;431 Ok(())432 }433}