1use std::{2 fmt::{self, Debug, Display},3 ops::Deref,4 rc::Rc,5};67use jrsonnet_gcmodule::Acyclic;8use jrsonnet_interner::IStr;910use crate::source::Source;1112#[derive(Debug, PartialEq, Acyclic)]13pub enum FieldName {14 15 Fixed(IStr),16 17 Dyn(LocExpr),18}1920#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]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, Acyclic)]38pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);3940#[derive(Debug, PartialEq, Acyclic)]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, Acyclic)]50pub enum Member {51 Field(FieldMember),52 BindStmt(BindSpec),53 AssertStmt(AssertStmt),54}5556#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]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, Acyclic)]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, Acyclic)]150pub struct Param(pub Destruct, pub Option<LocExpr>);151152153#[derive(Debug, Clone, PartialEq, Acyclic)]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, Acyclic)]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, Acyclic)]175pub enum DestructRest {176 177 Keep(IStr),178 179 Drop,180}181182#[derive(Debug, Clone, PartialEq, Acyclic)]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, Acyclic)]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, Acyclic)]265pub struct IfSpecData(pub LocExpr);266267#[derive(Debug, PartialEq, Acyclic)]268pub struct ForSpecData(pub Destruct, pub LocExpr);269270#[derive(Debug, PartialEq, Acyclic)]271pub enum CompSpec {272 IfSpec(IfSpecData),273 ForSpec(ForSpecData),274}275276#[derive(Debug, PartialEq, Acyclic)]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, Acyclic)]285pub enum ObjBody {286 MemberList(Vec<Member>),287 ObjComp(ObjComp),288}289290#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]291pub enum LiteralType {292 This,293 Super,294 Dollar,295 Null,296 True,297 False,298}299300#[derive(Debug, PartialEq, Acyclic)]301pub struct SliceDesc {302 pub start: Option<LocExpr>,303 pub end: Option<LocExpr>,304 pub step: Option<LocExpr>,305}306307308#[derive(Debug, PartialEq, Acyclic)]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 UnaryOp(UnaryOpType, LocExpr),341 342 BinaryOp(LocExpr, BinaryOpType, LocExpr),343 344 AssertExpr(AssertStmt, LocExpr),345 346 LocalExpr(Vec<BindSpec>, LocExpr),347348 349 Import(LocExpr),350 351 ImportStr(LocExpr),352 353 ImportBin(LocExpr),354 355 ErrorStmt(LocExpr),356 357 Apply(LocExpr, ArgsDesc, bool),358 359 Index {360 indexable: LocExpr,361 parts: Vec<IndexPart>,362 },363 364 Function(ParamsDesc, LocExpr),365 366 IfElse {367 cond: IfSpecData,368 cond_then: LocExpr,369 cond_else: Option<LocExpr>,370 },371 Slice(LocExpr, SliceDesc),372}373374#[derive(Debug, PartialEq, Acyclic)]375pub struct IndexPart {376 pub value: LocExpr,377 #[cfg(feature = "exp-null-coaelse")]378 pub null_coaelse: bool,379}380381382#[derive(Clone, PartialEq, Eq, Acyclic)]383#[repr(C)]384pub struct Span(pub Source, pub u32, pub u32);385impl Span {386 pub fn belongs_to(&self, other: &Span) -> bool {387 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2388 }389}390391static_assertions::assert_eq_size!(Span, (usize, usize));392393impl Debug for Span {394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {395 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)396 }397}398399400#[derive(Clone, PartialEq, Acyclic)]401pub struct LocExpr(Rc<(Expr, Span)>);402impl LocExpr {403 pub fn new(expr: Expr, span: Span) -> Self {404 Self(Rc::new((expr, span)))405 }406 #[inline]407 pub fn span(&self) -> Span {408 self.0 .1.clone()409 }410 #[inline]411 pub fn expr(&self) -> &Expr {412 &self.0 .0413 }414}415416static_assertions::assert_eq_size!(LocExpr, usize);417418impl Debug for LocExpr {419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {420 let expr = self.expr();421 if f.alternate() {422 write!(f, "{:#?}", expr)?;423 } else {424 write!(f, "{:?}", expr)?;425 }426 write!(f, " from {:?}", self.span())?;427 Ok(())428 }429}