1use std::{2 fmt::{self, Debug, Display},3 ops::{Deref, RangeInclusive},4 rc::Rc,5};67use jrsonnet_gcmodule::Acyclic;8use jrsonnet_interner::IStr;910use crate::{11 NumValue,12 function::{FunctionSignature, ParamDefault, ParamName, ParamParse},13 source::Source,14};1516#[derive(Debug, PartialEq, Acyclic)]17pub enum FieldName {18 19 Fixed(IStr),20 21 Dyn(Expr),22}2324#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]25#[repr(u8)]26pub enum Visibility {27 28 Normal,29 30 Hidden,31 32 Unhide,33}3435impl Visibility {36 pub fn is_visible(&self) -> bool {37 matches!(self, Self::Normal | Self::Unhide)38 }39}4041#[derive(Debug, PartialEq, Acyclic)]42pub struct AssertStmt {43 pub assertion: Spanned<Expr>,44 pub message: Option<Expr>,45}4647#[derive(Debug, PartialEq, Acyclic)]48pub struct FieldMember {49 pub name: Spanned<FieldName>,50 pub plus: bool,51 pub params: Option<ExprParams>,52 pub visibility: Visibility,53 pub value: Rc<Expr>,54}5556#[derive(Debug, PartialEq, Acyclic)]57pub enum Member {58 Field(FieldMember),59 BindStmt(BindSpec),60 AssertStmt(AssertStmt),61}6263#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]64pub enum UnaryOpType {65 Plus,66 Minus,67 BitNot,68 Not,69}7071impl Display for UnaryOpType {72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {73 use UnaryOpType::*;74 write!(75 f,76 "{}",77 match self {78 Plus => "+",79 Minus => "-",80 BitNot => "~",81 Not => "!",82 }83 )84 }85}8687#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]88pub enum BinaryOpType {89 Mul,90 Div,9192 93 Mod,9495 Add,96 Sub,9798 Lhs,99 Rhs,100101 Lt,102 Gt,103 Lte,104 Gte,105106 BitAnd,107 BitOr,108 BitXor,109110 Eq,111 Neq,112113 And,114 Or,115 #[cfg(feature = "exp-null-coaelse")]116 NullCoaelse,117118 119 In,120}121122impl Display for BinaryOpType {123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {124 use BinaryOpType::*;125 write!(126 f,127 "{}",128 match self {129 Mul => "*",130 Div => "/",131 Mod => "%",132 Add => "+",133 Sub => "-",134 Lhs => "<<",135 Rhs => ">>",136 Lt => "<",137 Gt => ">",138 Lte => "<=",139 Gte => ">=",140 BitAnd => "&",141 BitOr => "|",142 BitXor => "^",143 Eq => "==",144 Neq => "!=",145 And => "&&",146 Or => "||",147 In => "in",148 #[cfg(feature = "exp-null-coaelse")]149 NullCoaelse => "??",150 }151 )152 }153}154155156#[derive(Debug, PartialEq, Acyclic)]157pub struct ExprParam {158 pub destruct: Destruct,159 pub default: Option<Rc<Expr>>,160}161162163#[derive(Debug, Clone, PartialEq, Acyclic)]164pub struct ExprParams {165 pub exprs: Rc<Vec<ExprParam>>,166 pub signature: FunctionSignature,167 pub(crate) binds_len: usize,168}169impl ExprParams {170 pub fn len(&self) -> usize {171 self.exprs.len()172 }173 pub fn is_empty(&self) -> bool {174 self.exprs.is_empty()175 }176177 pub fn binds_len(&self) -> usize {178 self.binds_len179 }180 pub fn new(exprs: Vec<ExprParam>) -> Self {181 Self {182 signature: FunctionSignature::new(183 exprs184 .iter()185 .map(|p| {186 ParamParse::new(187 p.destruct.name(),188 ParamDefault::exists(p.default.is_some()),189 )190 })191 .collect(),192 ),193 binds_len: exprs.iter().map(|v| v.destruct.binds_len()).sum(),194 exprs: Rc::new(exprs),195 }196 }197}198199#[derive(Debug, PartialEq, Acyclic)]200pub struct ArgsDesc {201 pub unnamed: Vec<Rc<Expr>>,202 pub names: Vec<IStr>,203 pub values: Vec<Rc<Expr>>,204}205impl ArgsDesc {206 pub fn new(unnamed: Vec<Rc<Expr>>, names: Vec<IStr>, values: Vec<Rc<Expr>>) -> Self {207 Self {208 unnamed,209 names,210 values,211 }212 }213}214215#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]216pub enum DestructRest {217 218 Keep(IStr),219 220 Drop,221}222223#[derive(Debug, Clone, PartialEq, Acyclic)]224pub enum Destruct {225 Full(IStr),226 #[cfg(feature = "exp-destruct")]227 Skip,228 #[cfg(feature = "exp-destruct")]229 Array {230 start: Vec<Destruct>,231 rest: Option<DestructRest>,232 end: Vec<Destruct>,233 },234 #[cfg(feature = "exp-destruct")]235 Object {236 #[allow(clippy::type_complexity)]237 fields: Vec<(IStr, Option<Destruct>, Option<Rc<Spanned<Expr>>>)>,238 rest: Option<DestructRest>,239 },240}241impl Destruct {242 243 pub fn name(&self) -> ParamName {244 match self {245 Self::Full(name) => ParamName::Named(name.clone()),246 #[cfg(feature = "exp-destruct")]247 _ => ParamName::Unnamed,248 }249 }250 pub fn binds_len(&self) -> usize {251 #[cfg(feature = "exp-destruct")]252 fn cap_rest(rest: &Option<DestructRest>) -> usize {253 match rest {254 Some(DestructRest::Keep(_)) => 1,255 Some(DestructRest::Drop) => 0,256 None => 0,257 }258 }259 match self {260 Self::Full(_) => 1,261 #[cfg(feature = "exp-destruct")]262 Self::Skip => 0,263 #[cfg(feature = "exp-destruct")]264 Self::Array { start, rest, end } => {265 start.iter().map(Destruct::binds_len).sum::<usize>()266 + end.iter().map(Destruct::binds_len).sum::<usize>()267 + cap_rest(rest)268 }269 #[cfg(feature = "exp-destruct")]270 Self::Object { fields, rest } => {271 let mut out = 0;272 for (_, into, _) in fields {273 match into {274 Some(v) => out += v.binds_len(),275 276 None => out += 1,277 }278 }279 out + cap_rest(rest)280 }281 }282 }283}284285#[derive(Debug, PartialEq, Acyclic)]286pub enum BindSpec {287 Field {288 into: Destruct,289 value: Rc<Expr>,290 },291 Function {292 name: IStr,293 params: ExprParams,294 value: Rc<Expr>,295 },296}297impl BindSpec {298 pub fn binds_len(&self) -> usize {299 match self {300 BindSpec::Field { into, .. } => into.binds_len(),301 BindSpec::Function { .. } => 1,302 }303 }304}305306#[derive(Debug, PartialEq, Acyclic)]307pub struct IfSpecData {308 pub span: Span,309 pub cond: Expr,310}311312#[derive(Debug, PartialEq, Acyclic)]313pub struct ForSpecData {314 pub destruct: Destruct,315 pub over: Expr,316}317318#[derive(Debug, PartialEq, Acyclic)]319pub enum CompSpec {320 IfSpec(IfSpecData),321 ForSpec(ForSpecData),322}323324#[derive(Debug, PartialEq, Acyclic)]325pub struct ObjComp {326 pub locals: Rc<Vec<BindSpec>>,327 pub field: Rc<FieldMember>,328 pub compspecs: Vec<CompSpec>,329}330331#[derive(Debug, PartialEq, Acyclic)]332pub struct ObjMembers {333 pub locals: Rc<Vec<BindSpec>>,334 pub asserts: Rc<Vec<AssertStmt>>,335 pub fields: Vec<FieldMember>,336}337338#[derive(Debug, PartialEq, Acyclic)]339pub enum ObjBody {340 MemberList(ObjMembers),341 ObjComp(ObjComp),342}343344#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]345pub enum LiteralType {346 This,347 Super,348 Dollar,349 Null,350 True,351 False,352}353354#[derive(Debug, PartialEq, Acyclic)]355pub struct SliceDesc {356 pub start: Option<Spanned<Expr>>,357 pub end: Option<Spanned<Expr>>,358 pub step: Option<Spanned<Expr>>,359}360361#[derive(Debug, PartialEq, Acyclic)]362pub struct AssertExpr {363 pub assert: AssertStmt,364 pub rest: Expr,365}366367#[derive(Debug, PartialEq, Acyclic)]368pub struct BinaryOp {369 pub lhs: Expr,370 pub op: BinaryOpType,371 pub rhs: Expr,372}373374#[derive(Debug, PartialEq, Acyclic)]375pub enum ImportKind {376 Normal,377 Str,378 Bin,379}380381#[derive(Debug, PartialEq, Acyclic)]382pub struct IfElse {383 pub cond: IfSpecData,384 pub cond_then: Expr,385 pub cond_else: Option<Expr>,386}387388#[derive(Debug, PartialEq, Acyclic)]389pub struct Slice {390 pub value: Expr,391 pub slice: SliceDesc,392}393394395#[derive(Debug, PartialEq, Acyclic)]396pub enum Expr {397 Literal(LiteralType),398399 400 Str(IStr),401 402 Num(NumValue),403 404 Var(Spanned<IStr>),405406 407 Arr(Rc<Vec<Expr>>),408 409 410 411 412 413 414 415 416 417 418 419 ArrComp(Rc<Expr>, Vec<CompSpec>),420421 422 Obj(ObjBody),423 424 ObjExtend(Rc<Expr>, ObjBody),425426 427 UnaryOp(UnaryOpType, Box<Expr>),428 429 BinaryOp(Box<BinaryOp>),430 431 AssertExpr(Rc<AssertExpr>),432 433 LocalExpr(Vec<BindSpec>, Box<Expr>),434435 436 Import(Spanned<ImportKind>, Box<Expr>),437 438 ErrorStmt(Span, Box<Expr>),439 440 Apply(Box<Expr>, Spanned<ArgsDesc>, bool),441 442 Index {443 indexable: Box<Expr>,444 parts: Vec<IndexPart>,445 },446 447 Function(ExprParams, Rc<Expr>),448 449 IfElse(Box<IfElse>),450 Slice(Box<Slice>),451}452453#[derive(Debug, PartialEq, Acyclic)]454pub struct IndexPart {455 pub span: Span,456 pub value: Expr,457 #[cfg(feature = "exp-null-coaelse")]458 pub null_coaelse: bool,459}460461462#[derive(Clone, PartialEq, Eq, Acyclic)]463#[repr(C)]464pub struct Span(pub Source, pub u32, pub u32);465impl Span {466 pub fn belongs_to(&self, other: &Span) -> bool {467 other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2468 }469 pub fn range(&self) -> RangeInclusive<usize> {470 let start = self.1;471 let mut end = self.2;472 if end > start {473 474 end -= 1;475 }476 start as usize..=end as usize477 }478}479480#[cfg(target_pointer_width = "64")]481static_assertions::assert_eq_size!(Span, (usize, usize));482483impl Debug for Span {484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {485 write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)486 }487}488489#[derive(Clone, PartialEq, Acyclic)]490pub struct Spanned<T: Acyclic> {491 pub value: T,492 pub span: Span,493}494impl<T: Acyclic> Deref for Spanned<T> {495 type Target = T;496 fn deref(&self) -> &Self::Target {497 &self.value498 }499}500impl<T: Acyclic> Spanned<T> {501 #[inline]502 pub fn new(value: T, span: Span) -> Self {503 Self { value, span }504 }505 pub fn map<U: Acyclic>(self, v: impl FnOnce(T) -> U) -> Spanned<U> {506 Spanned {507 span: self.span,508 value: v(self.value),509 }510 }511 pub fn as_ref<'a>(&'a self) -> Spanned<&'a T>512 where513 &'a T: Acyclic,514 {515 Spanned {516 span: self.span.clone(),517 value: &self.value,518 }519 }520}521522impl<T: Debug + Acyclic> Debug for Spanned<T> {523 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {524 let expr = &**self;525 if f.alternate() {526 write!(f, "{:#?}", expr)?;527 } else {528 write!(f, "{:?}", expr)?;529 }530 write!(f, " from {:?}", self.span)?;531 Ok(())532 }533}