1use std::{2 fmt::{self, Debug, Display},3 ops::Deref,4 rc::Rc,5};67use jrsonnet_gcmodule::Acyclic;8use jrsonnet_interner::IStr;910use crate::{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}3334impl Visibility {35 pub fn is_visible(&self) -> bool {36 matches!(self, Self::Normal | Self::Unhide)37 }38}3940#[derive(Debug, PartialEq, Acyclic)]41pub struct AssertStmt(pub Spanned<Expr>, pub Option<Spanned<Expr>>);4243#[derive(Debug, PartialEq, Acyclic)]44pub struct FieldMember {45 pub name: Spanned<FieldName>,46 pub plus: bool,47 pub params: Option<ExprParams>,48 pub visibility: Visibility,49 pub value: Rc<Expr>,50}5152#[derive(Debug, PartialEq, Acyclic)]53pub enum Member {54 Field(FieldMember),55 BindStmt(BindSpec),56 AssertStmt(AssertStmt),57}5859#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]60pub enum UnaryOpType {61 Plus,62 Minus,63 BitNot,64 Not,65}6667impl Display for UnaryOpType {68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {69 use UnaryOpType::*;70 write!(71 f,72 "{}",73 match self {74 Plus => "+",75 Minus => "-",76 BitNot => "~",77 Not => "!",78 }79 )80 }81}8283#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]84pub enum BinaryOpType {85 Mul,86 Div,8788 89 Mod,9091 Add,92 Sub,9394 Lhs,95 Rhs,9697 Lt,98 Gt,99 Lte,100 Gte,101102 BitAnd,103 BitOr,104 BitXor,105106 Eq,107 Neq,108109 And,110 Or,111 #[cfg(feature = "exp-null-coaelse")]112 NullCoaelse,113114 115 In,116}117118impl Display for BinaryOpType {119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {120 use BinaryOpType::*;121 write!(122 f,123 "{}",124 match self {125 Mul => "*",126 Div => "/",127 Mod => "%",128 Add => "+",129 Sub => "-",130 Lhs => "<<",131 Rhs => ">>",132 Lt => "<",133 Gt => ">",134 Lte => "<=",135 Gte => ">=",136 BitAnd => "&",137 BitOr => "|",138 BitXor => "^",139 Eq => "==",140 Neq => "!=",141 And => "&&",142 Or => "||",143 In => "in",144 #[cfg(feature = "exp-null-coaelse")]145 NullCoaelse => "??",146 }147 )148 }149}150151152#[derive(Debug, PartialEq, Acyclic)]153pub struct ExprParam {154 pub destruct: Destruct,155 pub default: Option<Rc<Expr>>,156}157158159#[derive(Debug, Clone, PartialEq, Acyclic)]160pub struct ExprParams {161 pub exprs: Rc<Vec<ExprParam>>,162 pub signature: FunctionSignature,163 pub(crate) binds_len: usize,164}165impl ExprParams {166 pub fn len(&self) -> usize {167 self.exprs.len()168 }169 pub fn is_empty(&self) -> bool {170 self.exprs.is_empty()171 }172173 pub fn binds_len(&self) -> usize {174 self.binds_len175 }176 pub fn new(exprs: Vec<ExprParam>) -> Self {177 Self {178 signature: FunctionSignature::new(179 exprs180 .iter()181 .map(|p| {182 ParamParse::new(183 p.destruct.name(),184 ParamDefault::exists(p.default.is_some()),185 )186 })187 .collect(),188 ),189 binds_len: exprs.iter().map(|v| v.destruct.binds_len()).sum(),190 exprs: Rc::new(exprs),191 }192 }193}194195#[derive(Debug, PartialEq, Acyclic)]196pub struct ArgsDesc {197 pub unnamed: Vec<Rc<Expr>>,198 pub names: Vec<IStr>,199 pub values: Vec<Rc<Expr>>,200}201impl ArgsDesc {202 pub fn new(unnamed: Vec<Rc<Expr>>, names: Vec<IStr>, values: Vec<Rc<Expr>>) -> Self {203 Self {204 unnamed,205 names,206 values,207 }208 }209}210211#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]212pub enum DestructRest {213 214 Keep(IStr),215 216 Drop,217}218219#[derive(Debug, Clone, PartialEq, Acyclic)]220pub enum Destruct {221 Full(IStr),222 #[cfg(feature = "exp-destruct")]223 Skip,224 #[cfg(feature = "exp-destruct")]225 Array {226 start: Vec<Destruct>,227 rest: Option<DestructRest>,228 end: Vec<Destruct>,229 },230 #[cfg(feature = "exp-destruct")]231 Object {232 #[allow(clippy::type_complexity)]233 fields: Vec<(IStr, Option<Destruct>, Option<Rc<Spanned<Expr>>>)>,234 rest: Option<DestructRest>,235 },236}237impl Destruct {238 239 pub fn name(&self) -> ParamName {240 match self {241 Self::Full(name) => ParamName::Named(name.clone()),242 #[cfg(feature = "exp-destruct")]243 _ => ParamName::Unnamed,244 }245 }246 pub fn binds_len(&self) -> usize {247 #[cfg(feature = "exp-destruct")]248 fn cap_rest(rest: &Option<DestructRest>) -> usize {249 match rest {250 Some(DestructRest::Keep(_)) => 1,251 Some(DestructRest::Drop) => 0,252 None => 0,253 }254 }255 match self {256 Self::Full(_) => 1,257 #[cfg(feature = "exp-destruct")]258 Self::Skip => 0,259 #[cfg(feature = "exp-destruct")]260 Self::Array { start, rest, end } => {261 start.iter().map(Destruct::binds_len).sum::<usize>()262 + end.iter().map(Destruct::binds_len).sum::<usize>()263 + cap_rest(rest)264 }265 #[cfg(feature = "exp-destruct")]266 Self::Object { fields, rest } => {267 let mut out = 0;268 for (_, into, _) in fields {269 match into {270 Some(v) => out += v.binds_len(),271 272 None => out += 1,273 }274 }275 out + cap_rest(rest)276 }277 }278 }279}280281#[derive(Debug, PartialEq, Acyclic)]282pub enum BindSpec {283 Field {284 into: Destruct,285 value: Rc<Expr>,286 },287 Function {288 name: IStr,289 params: ExprParams,290 value: Rc<Expr>,291 },292}293impl BindSpec {294 pub fn binds_len(&self) -> usize {295 match self {296 BindSpec::Field { into, .. } => into.binds_len(),297 BindSpec::Function { .. } => 1,298 }299 }300}301302#[derive(Debug, PartialEq, Acyclic)]303pub struct IfSpecData {304 pub span: Span,305 pub cond: Expr,306}307308#[derive(Debug, PartialEq, Acyclic)]309pub struct ForSpecData {310 pub destruct: Destruct,311 pub over: Expr,312}313314#[derive(Debug, PartialEq, Acyclic)]315pub enum CompSpec {316 IfSpec(IfSpecData),317 ForSpec(ForSpecData),318}319320#[derive(Debug, PartialEq, Acyclic)]321pub struct ObjComp {322 pub locals: Rc<Vec<BindSpec>>,323 pub field: Rc<FieldMember>,324 pub compspecs: Vec<CompSpec>,325}326327#[derive(Debug, PartialEq, Acyclic)]328pub struct ObjMembers {329 pub locals: Rc<Vec<BindSpec>>,330 pub asserts: Rc<Vec<AssertStmt>>,331 pub fields: Vec<FieldMember>,332}333334#[derive(Debug, PartialEq, Acyclic)]335pub enum ObjBody {336 MemberList(ObjMembers),337 ObjComp(ObjComp),338}339340#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]341pub enum LiteralType {342 This,343 Super,344 Dollar,345 Null,346 True,347 False,348}349350#[derive(Debug, PartialEq, Acyclic)]351pub struct SliceDesc {352 pub start: Option<Spanned<Expr>>,353 pub end: Option<Spanned<Expr>>,354 pub step: Option<Spanned<Expr>>,355}356357#[derive(Debug, PartialEq, Acyclic)]358pub struct AssertExpr {359 pub assert: AssertStmt,360 pub rest: Expr,361}362363#[derive(Debug, PartialEq, Acyclic)]364pub struct BinaryOp {365 pub lhs: Expr,366 pub op: BinaryOpType,367 pub rhs: Expr,368}369370#[derive(Debug, PartialEq, Acyclic)]371pub enum ImportKind {372 Normal,373 Str,374 Bin,375}376377#[derive(Debug, PartialEq, Acyclic)]378pub struct IfElse {379 pub cond: IfSpecData,380 pub cond_then: Expr,381 pub cond_else: Option<Expr>,382}383384#[derive(Debug, PartialEq, Acyclic)]385pub struct Slice {386 pub value: Expr,387 pub slice: SliceDesc,388}389390391#[derive(Debug, PartialEq, Acyclic)]392pub enum Expr {393 Literal(LiteralType),394395 396 Str(IStr),397 398 Num(f64),399 400 Var(Spanned<IStr>),401402 403 Arr(Rc<Vec<Expr>>),404 405 406 407 408 409 410 411 412 413 414 415 ArrComp(Rc<Expr>, Vec<CompSpec>),416417 418 Obj(ObjBody),419 420 ObjExtend(Rc<Expr>, ObjBody),421422 423 UnaryOp(UnaryOpType, Box<Expr>),424 425 BinaryOp(Box<BinaryOp>),426 427 AssertExpr(Rc<AssertExpr>),428 429 LocalExpr(Vec<BindSpec>, Box<Expr>),430431 432 Import(Spanned<ImportKind>, Box<Expr>),433 434 ErrorStmt(Span, Box<Expr>),435 436 Apply(Box<Expr>, Spanned<ArgsDesc>, bool),437 438 Index {439 indexable: Box<Expr>,440 parts: Vec<IndexPart>,441 },442 443 Function(ExprParams, Rc<Expr>),444 445 IfElse(Box<IfElse>),446 Slice(Box<Slice>),447}448449#[derive(Debug, PartialEq, Acyclic)]450pub struct IndexPart {451 pub span: Span,452 pub value: Expr,453 #[cfg(feature = "exp-null-coaelse")]454 pub null_coaelse: bool,455}456457458#[derive(Clone, PartialEq, Eq, Acyclic)]459#[repr(C)]460pub struct Span(pub Source, pub u32, pub u32);461impl Span {462 pub fn belongs_to(&self, other: &Span) -> bool {463 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2464 }465}466467#[cfg(target_pointer_width = "64")]468static_assertions::assert_eq_size!(Span, (usize, usize));469470impl Debug for Span {471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {472 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)473 }474}475476#[derive(Clone, PartialEq, Acyclic)]477pub struct Spanned<T: Acyclic> {478 pub value: T,479 pub span: Span,480}481impl<T: Acyclic> Deref for Spanned<T> {482 type Target = T;483 fn deref(&self) -> &Self::Target {484 &self.value485 }486}487impl<T: Acyclic> Spanned<T> {488 #[inline]489 pub fn new(value: T, span: Span) -> Self {490 Self { value, span }491 }492}493494impl<T: Debug + Acyclic> Debug for Spanned<T> {495 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {496 let expr = &**self;497 if f.alternate() {498 write!(f, "{:#?}", expr)?;499 } else {500 write!(f, "{:?}", expr)?;501 }502 write!(f, " from {:?}", self.span)?;503 Ok(())504 }505}