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 enum Member {51 Field(FieldMember),52 BindStmt(BindSpec),53 AssertStmt(Rc<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, Clone, 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 pre_locals: Vec<BindSpec>,279 pub field: Rc<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<Spanned<Expr>>,303 pub end: Option<Spanned<Expr>>,304 pub step: Option<Spanned<Expr>>,305}306307#[derive(Debug, PartialEq, Acyclic)]308pub struct AssertExpr {309 pub assert: AssertStmt,310 pub rest: Spanned<Expr>,311}312313#[derive(Debug, PartialEq, Acyclic)]314pub struct BinaryOp {315 pub lhs: Spanned<Expr>,316 pub op: BinaryOpType,317 pub rhs: Spanned<Expr>,318}319320#[derive(Debug, PartialEq, Acyclic)]321pub enum ImportKind {322 Normal,323 Str,324 Bin,325}326327#[derive(Debug, PartialEq, Acyclic)]328pub struct IfElse {329 pub cond: IfSpecData,330 pub cond_then: Spanned<Expr>,331 pub cond_else: Option<Spanned<Expr>>,332}333334#[derive(Debug, PartialEq, Acyclic)]335pub struct Slice {336 pub value: Spanned<Expr>,337 pub slice: SliceDesc,338}339340341#[derive(Debug, PartialEq, Acyclic)]342pub enum Expr {343 Literal(LiteralType),344345 346 Str(IStr),347 348 Num(f64),349 350 Var(IStr),351352 353 Arr(Rc<Vec<Spanned<Expr>>>),354 355 356 357 358 359 360 361 362 363 364 365 ArrComp(Rc<Spanned<Expr>>, Vec<CompSpec>),366367 368 Obj(ObjBody),369 370 ObjExtend(Rc<Spanned<Expr>>, ObjBody),371372 373 UnaryOp(UnaryOpType, Box<Spanned<Expr>>),374 375 BinaryOp(Box<BinaryOp>),376 377 AssertExpr(Rc<AssertExpr>),378 379 LocalExpr(Vec<BindSpec>, Box<Spanned<Expr>>),380381 382 Import(ImportKind, Box<Spanned<Expr>>),383 384 ErrorStmt(Box<Spanned<Expr>>),385 386 Apply(Box<Spanned<Expr>>, ArgsDesc, bool),387 388 Index {389 indexable: Box<Spanned<Expr>>,390 parts: Vec<IndexPart>,391 },392 393 Function(ParamsDesc, Rc<Spanned<Expr>>),394 395 IfElse(Box<IfElse>),396 Slice(Box<Slice>),397}398399#[derive(Debug, PartialEq, Acyclic)]400pub struct IndexPart {401 pub value: Spanned<Expr>,402 #[cfg(feature = "exp-null-coaelse")]403 pub null_coaelse: bool,404}405406407#[derive(Clone, PartialEq, Eq, Acyclic)]408#[repr(C)]409pub struct Span(pub Source, pub u32, pub u32);410impl Span {411 pub fn belongs_to(&self, other: &Span) -> bool {412 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2413 }414}415416static_assertions::assert_eq_size!(Span, (usize, usize));417418impl Debug for Span {419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {420 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)421 }422}423424#[derive(Clone, PartialEq, Acyclic)]425pub struct Spanned<T: Acyclic>(T, Span);426impl<T: Acyclic> Deref for Spanned<T> {427 type Target = T;428 fn deref(&self) -> &Self::Target {429 &self.0430 }431}432impl<T: Acyclic> Spanned<T> {433 #[inline]434 pub fn new(v: T, s: Span) -> Self {435 Self(v, s)436 }437 #[inline]438 pub fn span(&self) -> Span {439 self.1.clone()440 }441}442443impl<T: Debug + Acyclic> Debug for Spanned<T> {444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {445 let expr = &**self;446 if f.alternate() {447 write!(f, "{:#?}", expr)?;448 } else {449 write!(f, "{:?}", expr)?;450 }451 write!(f, " from {:?}", self.span())?;452 Ok(())453 }454}