git.delta.rocks / jrsonnet / refs/commits / 1ddb92c00d0f

difftreelog

source

crates/jrsonnet-parser/src/expr.rs9.4 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(Spanned<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<Spanned<Expr>>,50}5152#[derive(Debug, PartialEq, Acyclic)]53pub(crate) 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<Spanned<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<Spanned<Expr>>>,198	pub named: Vec<(IStr, Rc<Spanned<Expr>>)>,199}200impl ArgsDesc {201	pub fn new(unnamed: Vec<Rc<Spanned<Expr>>>, named: Vec<(IStr, Rc<Spanned<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<Spanned<Expr>>,281	},282	Function {283		name: IStr,284		params: ExprParams,285		value: Rc<Spanned<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 Spanned<Expr>);299300#[derive(Debug, PartialEq, Acyclic)]301pub struct ForSpecData(pub Destruct, pub Spanned<Expr>);302303#[derive(Debug, PartialEq, Acyclic)]304pub enum CompSpec {305	IfSpec(IfSpecData),306	ForSpec(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: Spanned<Expr>,350}351352#[derive(Debug, PartialEq, Acyclic)]353pub struct BinaryOp {354	pub lhs: Spanned<Expr>,355	pub op: BinaryOpType,356	pub rhs: Spanned<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: Spanned<Expr>,370	pub cond_else: Option<Spanned<Expr>>,371}372373#[derive(Debug, PartialEq, Acyclic)]374pub struct Slice {375	pub value: Spanned<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(IStr),390391	/// Array of expressions: [1, 2, "Hello"]392	Arr(Rc<Vec<Spanned<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<Spanned<Expr>>, Vec<CompSpec>),405406	/// Object: {a: 2}407	Obj(ObjBody),408	/// Object extension: var1 {b: 2}409	ObjExtend(Rc<Spanned<Expr>>, ObjBody),410411	/// -2412	UnaryOp(UnaryOpType, Box<Spanned<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<Spanned<Expr>>),419420	/// import* "hello"421	Import(ImportKind, Box<Spanned<Expr>>),422	/// error "I'm broken"423	ErrorStmt(Box<Spanned<Expr>>),424	/// a(b, c)425	Apply(Box<Spanned<Expr>>, ArgsDesc, bool),426	/// a[b], a.b, a?.b427	Index {428		indexable: Box<Spanned<Expr>>,429		parts: Vec<IndexPart>,430	},431	/// function(x) x432	Function(ExprParams, Rc<Spanned<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 value: Spanned<Expr>,441	#[cfg(feature = "exp-null-coaelse")]442	pub null_coaelse: bool,443}444445/// file, begin offset, end offset446#[derive(Clone, PartialEq, Eq, Acyclic)]447#[repr(C)]448pub struct Span(pub Source, pub u32, pub u32);449impl Span {450	pub fn belongs_to(&self, other: &Span) -> bool {451		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2452	}453}454455static_assertions::assert_eq_size!(Span, (usize, usize));456457impl Debug for Span {458	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {459		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)460	}461}462463#[derive(Clone, PartialEq, Acyclic)]464pub struct Spanned<T: Acyclic>(T, Span);465impl<T: Acyclic> Deref for Spanned<T> {466	type Target = T;467	fn deref(&self) -> &Self::Target {468		&self.0469	}470}471impl<T: Acyclic> Spanned<T> {472	#[inline]473	pub fn new(v: T, s: Span) -> Self {474		Self(v, s)475	}476	#[inline]477	pub fn span(&self) -> Span {478		self.1.clone()479	}480}481482impl<T: Debug + Acyclic> Debug for Spanned<T> {483	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {484		let expr = &**self;485		if f.alternate() {486			write!(f, "{:#?}", expr)?;487		} else {488			write!(f, "{:?}", expr)?;489		}490		write!(f, " from {:?}", self.span())?;491		Ok(())492	}493}