git.delta.rocks / jrsonnet / refs/commits / 6fbff53f4c1d

difftreelog

source

crates/jrsonnet-ir/src/expr.rs9.3 KiBsourcehistory
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	/// {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(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	/// Implemented as intrinsic, put here for completeness89	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	// Equialent to std.objectHasEx(a, b, true)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}150151/// name, default value152#[derive(Debug, PartialEq, Acyclic)]153pub struct ExprParam {154	pub destruct: Destruct,155	pub default: Option<Rc<Expr>>,156}157158/// Defined function parameters159#[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	/// ...rest214	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	/// Name of destructure, used for function parameter names239	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						// Field is destructured to default name272						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}389390/// Syntax base391#[derive(Debug, PartialEq, Acyclic)]392pub enum Expr {393	Literal(LiteralType),394395	/// String value: "hello"396	Str(IStr),397	/// Number: 1, 2.0, 2e+20398	Num(f64),399	/// Variable name: test400	Var(Spanned<IStr>),401402	/// Array of expressions: [1, 2, "Hello"]403	Arr(Rc<Vec<Expr>>),404	/// Array comprehension:405	/// ```jsonnet406	///  ingredients: [407	///    { kind: kind, qty: 4 / 3 }408	///    for kind in [409	///      'Honey Syrup',410	///      'Lemon Juice',411	///      'Farmers Gin',412	///    ]413	///  ],414	/// ```415	ArrComp(Rc<Expr>, Vec<CompSpec>),416417	/// Object: {a: 2}418	Obj(ObjBody),419	/// Object extension: var1 {b: 2}420	ObjExtend(Rc<Expr>, ObjBody),421422	/// -2423	UnaryOp(UnaryOpType, Box<Expr>),424	/// 2 - 2425	BinaryOp(Box<BinaryOp>),426	/// assert 2 == 2 : "Math is broken"427	AssertExpr(Rc<AssertExpr>),428	/// local a = 2; { b: a }429	LocalExpr(Vec<BindSpec>, Box<Expr>),430431	/// import* "hello"432	Import(Spanned<ImportKind>, Box<Expr>),433	/// error "I'm broken"434	ErrorStmt(Span, Box<Expr>),435	/// a(b, c)436	Apply(Box<Expr>, Spanned<ArgsDesc>, bool),437	/// a[b], a.b, a?.b438	Index {439		indexable: Box<Expr>,440		parts: Vec<IndexPart>,441	},442	/// function(x) x443	Function(ExprParams, Rc<Expr>),444	/// if true == false then 1 else 2445	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}456457/// file, begin offset, end offset458#[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}