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(Spanned<Expr>),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(Debug, PartialEq, Acyclic)]38pub struct AssertStmt(pub Spanned<Expr>, pub Option<Spanned<Expr>>);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: Rc<Spanned<Expr>>,47}4849#[derive(Debug, PartialEq, Acyclic)]50pub(crate) 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<Rc<Spanned<Expr>>>);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<Rc<Spanned<Expr>>>,166 pub named: Vec<(IStr, Rc<Spanned<Expr>>)>,167}168impl ArgsDesc {169 pub fn new(unnamed: Vec<Rc<Spanned<Expr>>>, named: Vec<(IStr, Rc<Spanned<Expr>>)>) -> 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<Spanned<Expr>>)>,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, PartialEq, Acyclic)]244pub enum BindSpec {245 Field {246 into: Destruct,247 value: Rc<Spanned<Expr>>,248 },249 Function {250 name: IStr,251 params: ParamsDesc,252 value: Rc<Spanned<Expr>>,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 Spanned<Expr>);266267#[derive(Debug, PartialEq, Acyclic)]268pub struct ForSpecData(pub Destruct, pub Spanned<Expr>);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 locals: Rc<Vec<BindSpec>>,279 pub field: Rc<FieldMember>,280 pub compspecs: Vec<CompSpec>,281}282283#[derive(Debug, PartialEq, Acyclic)]284pub struct ObjMembers {285 pub locals: Rc<Vec<BindSpec>>,286 pub asserts: Rc<Vec<AssertStmt>>,287 pub fields: Vec<FieldMember>,288}289290#[derive(Debug, PartialEq, Acyclic)]291pub enum ObjBody {292 MemberList(ObjMembers),293 ObjComp(ObjComp),294}295296#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]297pub enum LiteralType {298 This,299 Super,300 Dollar,301 Null,302 True,303 False,304}305306#[derive(Debug, PartialEq, Acyclic)]307pub struct SliceDesc {308 pub start: Option<Spanned<Expr>>,309 pub end: Option<Spanned<Expr>>,310 pub step: Option<Spanned<Expr>>,311}312313#[derive(Debug, PartialEq, Acyclic)]314pub struct AssertExpr {315 pub assert: AssertStmt,316 pub rest: Spanned<Expr>,317}318319#[derive(Debug, PartialEq, Acyclic)]320pub struct BinaryOp {321 pub lhs: Spanned<Expr>,322 pub op: BinaryOpType,323 pub rhs: Spanned<Expr>,324}325326#[derive(Debug, PartialEq, Acyclic)]327pub enum ImportKind {328 Normal,329 Str,330 Bin,331}332333#[derive(Debug, PartialEq, Acyclic)]334pub struct IfElse {335 pub cond: IfSpecData,336 pub cond_then: Spanned<Expr>,337 pub cond_else: Option<Spanned<Expr>>,338}339340#[derive(Debug, PartialEq, Acyclic)]341pub struct Slice {342 pub value: Spanned<Expr>,343 pub slice: SliceDesc,344}345346347#[derive(Debug, PartialEq, Acyclic)]348pub enum Expr {349 Literal(LiteralType),350351 352 Str(IStr),353 354 Num(f64),355 356 Var(IStr),357358 359 Arr(Rc<Vec<Spanned<Expr>>>),360 361 362 363 364 365 366 367 368 369 370 371 ArrComp(Rc<Spanned<Expr>>, Vec<CompSpec>),372373 374 Obj(ObjBody),375 376 ObjExtend(Rc<Spanned<Expr>>, ObjBody),377378 379 UnaryOp(UnaryOpType, Box<Spanned<Expr>>),380 381 BinaryOp(Box<BinaryOp>),382 383 AssertExpr(Rc<AssertExpr>),384 385 LocalExpr(Vec<BindSpec>, Box<Spanned<Expr>>),386387 388 Import(ImportKind, Box<Spanned<Expr>>),389 390 ErrorStmt(Box<Spanned<Expr>>),391 392 Apply(Box<Spanned<Expr>>, ArgsDesc, bool),393 394 Index {395 indexable: Box<Spanned<Expr>>,396 parts: Vec<IndexPart>,397 },398 399 Function(ParamsDesc, Rc<Spanned<Expr>>),400 401 IfElse(Box<IfElse>),402 Slice(Box<Slice>),403}404405#[derive(Debug, PartialEq, Acyclic)]406pub struct IndexPart {407 pub value: Spanned<Expr>,408 #[cfg(feature = "exp-null-coaelse")]409 pub null_coaelse: bool,410}411412413#[derive(Clone, PartialEq, Eq, Acyclic)]414#[repr(C)]415pub struct Span(pub Source, pub u32, pub u32);416impl Span {417 pub fn belongs_to(&self, other: &Span) -> bool {418 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2419 }420}421422static_assertions::assert_eq_size!(Span, (usize, usize));423424impl Debug for Span {425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {426 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)427 }428}429430#[derive(Clone, PartialEq, Acyclic)]431pub struct Spanned<T: Acyclic>(T, Span);432impl<T: Acyclic> Deref for Spanned<T> {433 type Target = T;434 fn deref(&self) -> &Self::Target {435 &self.0436 }437}438impl<T: Acyclic> Spanned<T> {439 #[inline]440 pub fn new(v: T, s: Span) -> Self {441 Self(v, s)442 }443 #[inline]444 pub fn span(&self) -> Span {445 self.1.clone()446 }447}448449impl<T: Debug + Acyclic> Debug for Spanned<T> {450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {451 let expr = &**self;452 if f.alternate() {453 write!(f, "{:#?}", expr)?;454 } else {455 write!(f, "{:?}", expr)?;456 }457 write!(f, " from {:?}", self.span())?;458 Ok(())459 }460}