git.delta.rocks / jrsonnet / refs/commits / d34410c49dcf

difftreelog

source

crates/jrsonnet-ir/src/expr.rs9.2 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: 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	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 named: Vec<(IStr, Rc<Expr>)>,199}200impl ArgsDesc {201	pub fn new(unnamed: Vec<Rc<Expr>>, named: Vec<(IStr, Rc<Expr>)>) -> Self {202		Self { unnamed, named }203	}204}205206#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]207pub enum DestructRest {208	/// ...rest209	Keep(IStr),210	/// ...211	Drop,212}213214#[derive(Debug, Clone, PartialEq, Acyclic)]215pub enum Destruct {216	Full(IStr),217	#[cfg(feature = "exp-destruct")]218	Skip,219	#[cfg(feature = "exp-destruct")]220	Array {221		start: Vec<Destruct>,222		rest: Option<DestructRest>,223		end: Vec<Destruct>,224	},225	#[cfg(feature = "exp-destruct")]226	Object {227		#[allow(clippy::type_complexity)]228		fields: Vec<(IStr, Option<Destruct>, Option<Rc<Spanned<Expr>>>)>,229		rest: Option<DestructRest>,230	},231}232impl Destruct {233	/// Name of destructure, used for function parameter names234	pub fn name(&self) -> ParamName {235		match self {236			Self::Full(name) => ParamName::Named(name.clone()),237			#[cfg(feature = "exp-destruct")]238			_ => ParamName::Unnamed,239		}240	}241	pub fn binds_len(&self) -> usize {242		#[cfg(feature = "exp-destruct")]243		fn cap_rest(rest: &Option<DestructRest>) -> usize {244			match rest {245				Some(DestructRest::Keep(_)) => 1,246				Some(DestructRest::Drop) => 0,247				None => 0,248			}249		}250		match self {251			Self::Full(_) => 1,252			#[cfg(feature = "exp-destruct")]253			Self::Skip => 0,254			#[cfg(feature = "exp-destruct")]255			Self::Array { start, rest, end } => {256				start.iter().map(Destruct::binds_len).sum::<usize>()257					+ end.iter().map(Destruct::binds_len).sum::<usize>()258					+ cap_rest(rest)259			}260			#[cfg(feature = "exp-destruct")]261			Self::Object { fields, rest } => {262				let mut out = 0;263				for (_, into, _) in fields {264					match into {265						Some(v) => out += v.binds_len(),266						// Field is destructured to default name267						None => out += 1,268					}269				}270				out + cap_rest(rest)271			}272		}273	}274}275276#[derive(Debug, PartialEq, Acyclic)]277pub enum BindSpec {278	Field {279		into: Destruct,280		value: Rc<Expr>,281	},282	Function {283		name: IStr,284		params: ExprParams,285		value: Rc<Expr>,286	},287}288impl BindSpec {289	pub fn binds_len(&self) -> usize {290		match self {291			BindSpec::Field { into, .. } => into.binds_len(),292			BindSpec::Function { .. } => 1,293		}294	}295}296297#[derive(Debug, PartialEq, Acyclic)]298pub struct IfSpecData(pub Expr);299300#[derive(Debug, PartialEq, Acyclic)]301pub struct ForSpecData(pub Destruct, pub Expr);302303#[derive(Debug, PartialEq, Acyclic)]304pub enum CompSpec {305	IfSpec(Spanned<IfSpecData>),306	ForSpec(Spanned<ForSpecData>),307}308309#[derive(Debug, PartialEq, Acyclic)]310pub struct ObjComp {311	pub locals: Rc<Vec<BindSpec>>,312	pub field: Rc<FieldMember>,313	pub compspecs: Vec<CompSpec>,314}315316#[derive(Debug, PartialEq, Acyclic)]317pub struct ObjMembers {318	pub locals: Rc<Vec<BindSpec>>,319	pub asserts: Rc<Vec<AssertStmt>>,320	pub fields: Vec<FieldMember>,321}322323#[derive(Debug, PartialEq, Acyclic)]324pub enum ObjBody {325	MemberList(ObjMembers),326	ObjComp(ObjComp),327}328329#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]330pub enum LiteralType {331	This,332	Super,333	Dollar,334	Null,335	True,336	False,337}338339#[derive(Debug, PartialEq, Acyclic)]340pub struct SliceDesc {341	pub start: Option<Spanned<Expr>>,342	pub end: Option<Spanned<Expr>>,343	pub step: Option<Spanned<Expr>>,344}345346#[derive(Debug, PartialEq, Acyclic)]347pub struct AssertExpr {348	pub assert: AssertStmt,349	pub rest: Expr,350}351352#[derive(Debug, PartialEq, Acyclic)]353pub struct BinaryOp {354	pub lhs: Expr,355	pub op: BinaryOpType,356	pub rhs: Expr,357}358359#[derive(Debug, PartialEq, Acyclic)]360pub enum ImportKind {361	Normal,362	Str,363	Bin,364}365366#[derive(Debug, PartialEq, Acyclic)]367pub struct IfElse {368	pub cond: IfSpecData,369	pub cond_then: Expr,370	pub cond_else: Option<Expr>,371}372373#[derive(Debug, PartialEq, Acyclic)]374pub struct Slice {375	pub value: Expr,376	pub slice: SliceDesc,377}378379/// Syntax base380#[derive(Debug, PartialEq, Acyclic)]381pub enum Expr {382	Literal(LiteralType),383384	/// String value: "hello"385	Str(IStr),386	/// Number: 1, 2.0, 2e+20387	Num(f64),388	/// Variable name: test389	Var(Spanned<IStr>),390391	/// Array of expressions: [1, 2, "Hello"]392	Arr(Rc<Vec<Expr>>),393	/// Array comprehension:394	/// ```jsonnet395	///  ingredients: [396	///    { kind: kind, qty: 4 / 3 }397	///    for kind in [398	///      'Honey Syrup',399	///      'Lemon Juice',400	///      'Farmers Gin',401	///    ]402	///  ],403	/// ```404	ArrComp(Rc<Expr>, Vec<CompSpec>),405406	/// Object: {a: 2}407	Obj(ObjBody),408	/// Object extension: var1 {b: 2}409	ObjExtend(Rc<Expr>, ObjBody),410411	/// -2412	UnaryOp(UnaryOpType, Box<Expr>),413	/// 2 - 2414	BinaryOp(Box<BinaryOp>),415	/// assert 2 == 2 : "Math is broken"416	AssertExpr(Rc<AssertExpr>),417	/// local a = 2; { b: a }418	LocalExpr(Vec<BindSpec>, Box<Expr>),419420	/// import* "hello"421	Import(Spanned<ImportKind>, Box<Expr>),422	/// error "I'm broken"423	ErrorStmt(Span, Box<Expr>),424	/// a(b, c)425	Apply(Box<Expr>, Spanned<ArgsDesc>, bool),426	/// a[b], a.b, a?.b427	Index {428		indexable: Box<Expr>,429		parts: Vec<IndexPart>,430	},431	/// function(x) x432	Function(ExprParams, Rc<Expr>),433	/// if true == false then 1 else 2434	IfElse(Box<IfElse>),435	Slice(Box<Slice>),436}437438#[derive(Debug, PartialEq, Acyclic)]439pub struct IndexPart {440	pub span: Span,441	pub value: Expr,442	#[cfg(feature = "exp-null-coaelse")]443	pub null_coaelse: bool,444}445446/// file, begin offset, end offset447#[derive(Clone, PartialEq, Eq, Acyclic)]448#[repr(C)]449pub struct Span(pub Source, pub u32, pub u32);450impl Span {451	pub fn belongs_to(&self, other: &Span) -> bool {452		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2453	}454}455456static_assertions::assert_eq_size!(Span, (usize, usize));457458impl Debug for Span {459	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {460		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)461	}462}463464#[derive(Clone, PartialEq, Acyclic)]465pub struct Spanned<T: Acyclic>(pub T, pub Span);466impl<T: Acyclic> Deref for Spanned<T> {467	type Target = T;468	fn deref(&self) -> &Self::Target {469		&self.0470	}471}472impl<T: Acyclic> Spanned<T> {473	#[inline]474	pub fn new(v: T, s: Span) -> Self {475		Self(v, s)476	}477	#[inline]478	pub fn span(&self) -> Span {479		self.1.clone()480	}481}482483impl<T: Debug + Acyclic> Debug for Spanned<T> {484	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {485		let expr = &**self;486		if f.alternate() {487			write!(f, "{:#?}", expr)?;488		} else {489			write!(f, "{:?}", expr)?;490		}491		write!(f, " from {:?}", self.span())?;492		Ok(())493	}494}