git.delta.rocks / jrsonnet / refs/commits / 98b29c54b6bd

difftreelog

source

crates/jrsonnet-ir/src/expr.rs9.9 KiBsourcehistory
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	/// {fixed: 2}19	Fixed(IStr),20	/// {["dyn"+"amic"]: 3}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	/// Implemented as intrinsic, put here for completeness93	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	// Equialent to std.objectHasEx(a, b, true)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}154155/// name, default value156#[derive(Debug, PartialEq, Acyclic)]157pub struct ExprParam {158	pub destruct: Destruct,159	pub default: Option<Rc<Expr>>,160}161162/// Defined function parameters163#[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	/// ...rest218	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	/// Name of destructure, used for function parameter names243	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						// Field is destructured to default name276						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}393394/// Syntax base395#[derive(Debug, PartialEq, Acyclic)]396pub enum Expr {397	Literal(LiteralType),398399	/// String value: "hello"400	Str(IStr),401	/// Number: 1, 2.0, 2e+20402	Num(NumValue),403	/// Variable name: test404	Var(Spanned<IStr>),405406	/// Array of expressions: [1, 2, "Hello"]407	Arr(Rc<Vec<Expr>>),408	/// Array comprehension:409	/// ```jsonnet410	///  ingredients: [411	///    { kind: kind, qty: 4 / 3 }412	///    for kind in [413	///      'Honey Syrup',414	///      'Lemon Juice',415	///      'Farmers Gin',416	///    ]417	///  ],418	/// ```419	ArrComp(Rc<Expr>, Vec<CompSpec>),420421	/// Object: {a: 2}422	Obj(ObjBody),423	/// Object extension: var1 {b: 2}424	ObjExtend(Rc<Expr>, ObjBody),425426	/// -2427	UnaryOp(UnaryOpType, Box<Expr>),428	/// 2 - 2429	BinaryOp(Box<BinaryOp>),430	/// assert 2 == 2 : "Math is broken"431	AssertExpr(Rc<AssertExpr>),432	/// local a = 2; { b: a }433	LocalExpr(Vec<BindSpec>, Box<Expr>),434435	/// import* "hello"436	Import(Spanned<ImportKind>, Box<Expr>),437	/// error "I'm broken"438	ErrorStmt(Span, Box<Expr>),439	/// a(b, c)440	Apply(Box<Expr>, Spanned<ArgsDesc>, bool),441	/// a[b], a.b, a?.b442	Index {443		indexable: Box<Expr>,444		parts: Vec<IndexPart>,445	},446	/// function(x) x447	Function(ExprParams, Rc<Expr>),448	/// if true == false then 1 else 2449	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}460461/// file, begin offset, end offset462#[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			// Because it is originally exclusive474			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}