git.delta.rocks / jrsonnet / refs/commits / 2223f9ab687d

difftreelog

source

crates/jrsonnet-ir/src/expr.rs10.1 KiBsourcehistory
1use std::{2	fmt::{self, Debug, Display},3	ops::{Deref, RangeInclusive},4};56use jrsonnet_gcmodule::Acyclic;7use jrsonnet_interner::IStr;89use crate::{10	NumValue,11	function::{FunctionSignature, ParamDefault, ParamName, ParamParse},12	source::Source,13};1415#[derive(Debug, PartialEq, Acyclic)]16pub enum FieldName {17	/// {fixed: 2}18	Fixed(IStr),19	/// {["dyn"+"amic"]: 3}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 {42	pub assertion: Spanned<Expr>,43	pub message: Option<Expr>,44}4546#[derive(Debug, PartialEq, Acyclic)]47pub struct FieldMember {48	pub name: Spanned<FieldName>,49	pub plus: bool,50	pub params: Option<ExprParams>,51	pub visibility: Visibility,52	pub value: Expr,53}5455#[derive(Debug, PartialEq, Acyclic)]56pub enum Member {57	Field(FieldMember),58	BindStmt(BindSpec),59	AssertStmt(AssertStmt),60}6162#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]63pub enum UnaryOpType {64	Plus,65	Minus,66	BitNot,67	Not,68}6970impl Display for UnaryOpType {71	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {72		use UnaryOpType::*;73		write!(74			f,75			"{}",76			match self {77				Plus => "+",78				Minus => "-",79				BitNot => "~",80				Not => "!",81			}82		)83	}84}8586#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]87pub enum BinaryOpType {88	Mul,89	Div,9091	/// Implemented as intrinsic, put here for completeness92	Mod,9394	Add,95	Sub,9697	Lhs,98	Rhs,99100	Lt,101	Gt,102	Lte,103	Gte,104105	BitAnd,106	BitOr,107	BitXor,108109	Eq,110	Neq,111112	And,113	Or,114	#[cfg(feature = "exp-null-coaelse")]115	NullCoaelse,116117	// Equialent to std.objectHasEx(a, b, true)118	In,119}120121impl Display for BinaryOpType {122	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {123		use BinaryOpType::*;124		write!(125			f,126			"{}",127			match self {128				Mul => "*",129				Div => "/",130				Mod => "%",131				Add => "+",132				Sub => "-",133				Lhs => "<<",134				Rhs => ">>",135				Lt => "<",136				Gt => ">",137				Lte => "<=",138				Gte => ">=",139				BitAnd => "&",140				BitOr => "|",141				BitXor => "^",142				Eq => "==",143				Neq => "!=",144				And => "&&",145				Or => "||",146				In => "in",147				#[cfg(feature = "exp-null-coaelse")]148				NullCoaelse => "??",149			}150		)151	}152}153154/// name, default value155#[derive(Debug, PartialEq, Acyclic)]156pub struct ExprParam {157	pub destruct: Destruct,158	pub default: Option<Expr>,159}160161/// Defined function parameters162#[derive(Debug, PartialEq, Acyclic)]163pub struct ExprParams {164	pub exprs: Vec<ExprParam>,165	pub signature: FunctionSignature,166	pub(crate) binds_len: usize,167}168impl ExprParams {169	pub fn len(&self) -> usize {170		self.exprs.len()171	}172	pub fn is_empty(&self) -> bool {173		self.exprs.is_empty()174	}175176	pub fn binds_len(&self) -> usize {177		self.binds_len178	}179	pub fn new(exprs: Vec<ExprParam>) -> Self {180		Self {181			signature: FunctionSignature::new(182				exprs183					.iter()184					.map(|p| {185						ParamParse::new(186							p.destruct.name(),187							ParamDefault::exists(p.default.is_some()),188						)189					})190					.collect(),191			),192			binds_len: exprs.iter().map(|v| v.destruct.binds_len()).sum(),193			exprs,194		}195	}196}197198#[derive(Debug, PartialEq, Acyclic)]199pub struct ArgsDesc {200	pub unnamed: Vec<Expr>,201	pub names: Vec<IStr>,202	pub values: Vec<Expr>,203}204impl ArgsDesc {205	pub fn new(unnamed: Vec<Expr>, names: Vec<IStr>, values: Vec<Expr>) -> Self {206		Self {207			unnamed,208			names,209			values,210		}211	}212}213214#[derive(Debug, PartialEq, Eq, Acyclic)]215pub enum DestructRest {216	/// ...rest217	Keep(IStr),218	/// ...219	Drop,220}221222#[derive(Debug, PartialEq, Acyclic)]223pub enum Destruct {224	Full(Spanned<IStr>),225	#[cfg(feature = "exp-destruct")]226	Skip,227	#[cfg(feature = "exp-destruct")]228	Array {229		start: Vec<Destruct>,230		rest: Option<DestructRest>,231		end: Vec<Destruct>,232	},233	#[cfg(feature = "exp-destruct")]234	Object {235		#[allow(clippy::type_complexity)]236		fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,237		rest: Option<DestructRest>,238	},239}240impl Destruct {241	/// Name of destructure, used for function parameter names242	pub fn name(&self) -> ParamName {243		match self {244			Self::Full(name) => ParamName::Named(name.value.clone()),245			#[cfg(feature = "exp-destruct")]246			_ => ParamName::Unnamed,247		}248	}249	pub fn binds_len(&self) -> usize {250		#[cfg(feature = "exp-destruct")]251		fn cap_rest(rest: &Option<DestructRest>) -> usize {252			match rest {253				Some(DestructRest::Keep(_)) => 1,254				Some(DestructRest::Drop) => 0,255				None => 0,256			}257		}258		match self {259			Self::Full(_) => 1,260			#[cfg(feature = "exp-destruct")]261			Self::Skip => 0,262			#[cfg(feature = "exp-destruct")]263			Self::Array { start, rest, end } => {264				start.iter().map(Destruct::binds_len).sum::<usize>()265					+ end.iter().map(Destruct::binds_len).sum::<usize>()266					+ cap_rest(rest)267			}268			#[cfg(feature = "exp-destruct")]269			Self::Object { fields, rest } => {270				let mut out = 0;271				for (_, into, _) in fields {272					match into {273						Some(v) => out += v.binds_len(),274						// Field is destructured to default name275						None => out += 1,276					}277				}278				out + cap_rest(rest)279			}280		}281	}282}283284#[derive(Debug, PartialEq, Acyclic)]285pub enum BindSpec {286	Field {287		into: Destruct,288		value: Expr,289	},290	Function {291		name: IStr,292		params: ExprParams,293		value: Expr,294	},295}296impl BindSpec {297	pub fn binds_len(&self) -> usize {298		match self {299			BindSpec::Field { into, .. } => into.binds_len(),300			BindSpec::Function { .. } => 1,301		}302	}303}304305#[derive(Debug, PartialEq, Acyclic)]306pub struct IfSpecData {307	pub span: Span,308	pub cond: Expr,309}310311#[derive(Debug, PartialEq, Acyclic)]312pub struct ForSpecData {313	pub destruct: Destruct,314	pub over: Expr,315}316317#[cfg(feature = "exp-object-iteration")]318#[derive(Debug, PartialEq, Acyclic)]319pub struct ForObjSpecData {320	pub key: IStr,321	pub visibility: Visibility,322	pub value: Destruct,323	pub over: Expr,324}325326#[derive(Debug, PartialEq, Acyclic)]327pub enum CompSpec {328	IfSpec(IfSpecData),329	ForSpec(ForSpecData),330	#[cfg(feature = "exp-object-iteration")]331	ForObjSpec(ForObjSpecData),332}333334#[derive(Debug, PartialEq, Acyclic)]335pub struct ObjComp {336	pub locals: Vec<BindSpec>,337	pub field: Box<FieldMember>,338	pub compspecs: Vec<CompSpec>,339}340341#[derive(Debug, PartialEq, Acyclic)]342pub struct ObjMembers {343	pub locals: Vec<BindSpec>,344	pub asserts: Vec<AssertStmt>,345	pub fields: Vec<FieldMember>,346}347348#[derive(Debug, PartialEq, Acyclic)]349pub enum ObjBody {350	MemberList(ObjMembers),351	ObjComp(ObjComp),352}353354#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]355pub enum LiteralType {356	This,357	Super,358	Dollar,359	Null,360	True,361	False,362}363364#[derive(Debug, PartialEq, Acyclic)]365pub struct SliceDesc {366	pub start: Option<Spanned<Expr>>,367	pub end: Option<Spanned<Expr>>,368	pub step: Option<Spanned<Expr>>,369}370371#[derive(Debug, PartialEq, Acyclic)]372pub struct AssertExpr {373	pub assert: AssertStmt,374	pub rest: Expr,375}376377#[derive(Debug, PartialEq, Acyclic)]378pub struct BinaryOp {379	pub lhs: Expr,380	pub op: BinaryOpType,381	pub rhs: Expr,382}383384#[derive(Debug, PartialEq, Acyclic, Clone, Copy)]385pub enum ImportKind {386	Normal,387	Str,388	Bin,389}390391#[derive(Debug, PartialEq, Acyclic)]392pub struct IfElse {393	pub cond: IfSpecData,394	pub cond_then: Expr,395	pub cond_else: Option<Expr>,396}397398#[derive(Debug, PartialEq, Acyclic)]399pub struct Slice {400	pub value: Expr,401	pub slice: SliceDesc,402}403404/// Syntax base405#[derive(Debug, PartialEq, Acyclic)]406pub enum Expr {407	Literal(LiteralType),408409	/// String value: "hello"410	Str(IStr),411	/// Number: 1, 2.0, 2e+20412	Num(NumValue),413	/// Variable name: test414	Var(Spanned<IStr>),415416	/// Array of expressions: [1, 2, "Hello"]417	Arr(Vec<Expr>),418	/// Array comprehension:419	/// ```jsonnet420	///  ingredients: [421	///    { kind: kind, qty: 4 / 3 }422	///    for kind in [423	///      'Honey Syrup',424	///      'Lemon Juice',425	///      'Farmers Gin',426	///    ]427	///  ],428	/// ```429	ArrComp(Box<Expr>, Vec<CompSpec>),430431	/// Object: {a: 2}432	Obj(ObjBody),433	/// Object extension: var1 {b: 2}434	ObjExtend(Box<Expr>, ObjBody),435436	/// -2437	UnaryOp(UnaryOpType, Box<Expr>),438	/// 2 - 2439	BinaryOp(Box<BinaryOp>),440	/// assert 2 == 2 : "Math is broken"441	AssertExpr(Box<AssertExpr>),442	/// local a = 2; { b: a }443	LocalExpr(Vec<BindSpec>, Box<Expr>),444445	/// import* "hello"446	Import(Spanned<ImportKind>, Box<Expr>),447	/// error "I'm broken"448	ErrorStmt(Span, Box<Expr>),449	/// a(b, c)450	Apply(Box<Expr>, Spanned<ArgsDesc>, bool),451	/// a[b], a.b, a?.b452	Index {453		indexable: Box<Expr>,454		parts: Vec<IndexPart>,455	},456	/// function(x) x457	Function(ExprParams, Box<Expr>),458	/// if true == false then 1 else 2459	IfElse(Box<IfElse>),460	Slice(Box<Slice>),461}462463#[derive(Debug, PartialEq, Acyclic)]464pub struct IndexPart {465	pub span: Span,466	pub value: Expr,467	#[cfg(feature = "exp-null-coaelse")]468	pub null_coaelse: bool,469}470471/// file, begin offset, end offset472#[derive(Clone, PartialEq, Eq, Acyclic)]473#[repr(C)]474pub struct Span(pub Source, pub u32, pub u32);475impl Span {476	pub fn belongs_to(&self, other: &Span) -> bool {477		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2478	}479	pub fn range(&self) -> RangeInclusive<usize> {480		let start = self.1;481		let mut end = self.2;482		if end > start {483			// Because it is originally exclusive484			end -= 1;485		}486		start as usize..=end as usize487	}488}489490#[cfg(target_pointer_width = "64")]491static_assertions::assert_eq_size!(Span, (usize, usize));492493impl Debug for Span {494	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {495		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)496	}497}498499#[derive(Clone, PartialEq, Acyclic)]500pub struct Spanned<T: Acyclic> {501	pub value: T,502	pub span: Span,503}504impl<T: Acyclic> Deref for Spanned<T> {505	type Target = T;506	fn deref(&self) -> &Self::Target {507		&self.value508	}509}510impl<T: Acyclic> Spanned<T> {511	#[inline]512	pub fn new(value: T, span: Span) -> Self {513		Self { value, span }514	}515	pub fn map<U: Acyclic>(self, v: impl FnOnce(T) -> U) -> Spanned<U> {516		Spanned {517			span: self.span,518			value: v(self.value),519		}520	}521	pub fn as_ref<'a>(&'a self) -> Spanned<&'a T>522	where523		&'a T: Acyclic,524	{525		Spanned {526			span: self.span.clone(),527			value: &self.value,528		}529	}530}531532impl<T: Debug + Acyclic> Debug for Spanned<T> {533	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {534		let expr = &**self;535		if f.alternate() {536			write!(f, "{:#?}", expr)?;537		} else {538			write!(f, "{:?}", expr)?;539		}540		write!(f, " from {:?}", self.span)?;541		Ok(())542	}543}