git.delta.rocks / jrsonnet / refs/commits / 5df60b8b674f

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		fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,228		rest: Option<DestructRest>,229	},230}231impl Destruct {232	/// Name of destructure, used for function parameter names233	pub fn name(&self) -> ParamName {234		match self {235			Self::Full(name) => ParamName::Named(name.clone()),236			#[cfg(feature = "exp-destruct")]237			_ => ParamName::Unnamed,238		}239	}240	pub fn binds_len(&self) -> usize {241		#[cfg(feature = "exp-destruct")]242		fn cap_rest(rest: &Option<DestructRest>) -> usize {243			match rest {244				Some(DestructRest::Keep(_)) => 1,245				Some(DestructRest::Drop) => 0,246				None => 0,247			}248		}249		match self {250			Self::Full(_) => 1,251			#[cfg(feature = "exp-destruct")]252			Self::Skip => 0,253			#[cfg(feature = "exp-destruct")]254			Self::Array { start, rest, end } => {255				start.iter().map(Destruct::binds_len).sum::<usize>()256					+ end.iter().map(Destruct::binds_len).sum::<usize>()257					+ cap_rest(rest)258			}259			#[cfg(feature = "exp-destruct")]260			Self::Object { fields, rest } => {261				let mut out = 0;262				for (_, into, _) in fields {263					match into {264						Some(v) => out += v.capacity_hint(),265						// Field is destructured to default name266						None => out += 1,267					}268				}269				out + cap_rest(rest)270			}271		}272	}273}274275#[derive(Debug, PartialEq, Acyclic)]276pub enum BindSpec {277	Field {278		into: Destruct,279		value: Rc<Spanned<Expr>>,280	},281	Function {282		name: IStr,283		params: ExprParams,284		value: Rc<Spanned<Expr>>,285	},286}287impl BindSpec {288	pub fn binds_len(&self) -> usize {289		match self {290			BindSpec::Field { into, .. } => into.binds_len(),291			BindSpec::Function { .. } => 1,292		}293	}294}295296#[derive(Debug, PartialEq, Acyclic)]297pub struct IfSpecData(pub Spanned<Expr>);298299#[derive(Debug, PartialEq, Acyclic)]300pub struct ForSpecData(pub Destruct, pub Spanned<Expr>);301302#[derive(Debug, PartialEq, Acyclic)]303pub enum CompSpec {304	IfSpec(IfSpecData),305	ForSpec(ForSpecData),306}307308#[derive(Debug, PartialEq, Acyclic)]309pub struct ObjComp {310	pub locals: Rc<Vec<BindSpec>>,311	pub field: Rc<FieldMember>,312	pub compspecs: Vec<CompSpec>,313}314315#[derive(Debug, PartialEq, Acyclic)]316pub struct ObjMembers {317	pub locals: Rc<Vec<BindSpec>>,318	pub asserts: Rc<Vec<AssertStmt>>,319	pub fields: Vec<FieldMember>,320}321322#[derive(Debug, PartialEq, Acyclic)]323pub enum ObjBody {324	MemberList(ObjMembers),325	ObjComp(ObjComp),326}327328#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]329pub enum LiteralType {330	This,331	Super,332	Dollar,333	Null,334	True,335	False,336}337338#[derive(Debug, PartialEq, Acyclic)]339pub struct SliceDesc {340	pub start: Option<Spanned<Expr>>,341	pub end: Option<Spanned<Expr>>,342	pub step: Option<Spanned<Expr>>,343}344345#[derive(Debug, PartialEq, Acyclic)]346pub struct AssertExpr {347	pub assert: AssertStmt,348	pub rest: Spanned<Expr>,349}350351#[derive(Debug, PartialEq, Acyclic)]352pub struct BinaryOp {353	pub lhs: Spanned<Expr>,354	pub op: BinaryOpType,355	pub rhs: Spanned<Expr>,356}357358#[derive(Debug, PartialEq, Acyclic)]359pub enum ImportKind {360	Normal,361	Str,362	Bin,363}364365#[derive(Debug, PartialEq, Acyclic)]366pub struct IfElse {367	pub cond: IfSpecData,368	pub cond_then: Spanned<Expr>,369	pub cond_else: Option<Spanned<Expr>>,370}371372#[derive(Debug, PartialEq, Acyclic)]373pub struct Slice {374	pub value: Spanned<Expr>,375	pub slice: SliceDesc,376}377378/// Syntax base379#[derive(Debug, PartialEq, Acyclic)]380pub enum Expr {381	Literal(LiteralType),382383	/// String value: "hello"384	Str(IStr),385	/// Number: 1, 2.0, 2e+20386	Num(f64),387	/// Variable name: test388	Var(IStr),389390	/// Array of expressions: [1, 2, "Hello"]391	Arr(Rc<Vec<Spanned<Expr>>>),392	/// Array comprehension:393	/// ```jsonnet394	///  ingredients: [395	///    { kind: kind, qty: 4 / 3 }396	///    for kind in [397	///      'Honey Syrup',398	///      'Lemon Juice',399	///      'Farmers Gin',400	///    ]401	///  ],402	/// ```403	ArrComp(Rc<Spanned<Expr>>, Vec<CompSpec>),404405	/// Object: {a: 2}406	Obj(ObjBody),407	/// Object extension: var1 {b: 2}408	ObjExtend(Rc<Spanned<Expr>>, ObjBody),409410	/// -2411	UnaryOp(UnaryOpType, Box<Spanned<Expr>>),412	/// 2 - 2413	BinaryOp(Box<BinaryOp>),414	/// assert 2 == 2 : "Math is broken"415	AssertExpr(Rc<AssertExpr>),416	/// local a = 2; { b: a }417	LocalExpr(Vec<BindSpec>, Box<Spanned<Expr>>),418419	/// import* "hello"420	Import(ImportKind, Box<Spanned<Expr>>),421	/// error "I'm broken"422	ErrorStmt(Box<Spanned<Expr>>),423	/// a(b, c)424	Apply(Box<Spanned<Expr>>, ArgsDesc, bool),425	/// a[b], a.b, a?.b426	Index {427		indexable: Box<Spanned<Expr>>,428		parts: Vec<IndexPart>,429	},430	/// function(x) x431	Function(ExprParams, Rc<Spanned<Expr>>),432	/// if true == false then 1 else 2433	IfElse(Box<IfElse>),434	Slice(Box<Slice>),435}436437#[derive(Debug, PartialEq, Acyclic)]438pub struct IndexPart {439	pub value: Spanned<Expr>,440	#[cfg(feature = "exp-null-coaelse")]441	pub null_coaelse: bool,442}443444/// file, begin offset, end offset445#[derive(Clone, PartialEq, Eq, Acyclic)]446#[repr(C)]447pub struct Span(pub Source, pub u32, pub u32);448impl Span {449	pub fn belongs_to(&self, other: &Span) -> bool {450		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2451	}452}453454static_assertions::assert_eq_size!(Span, (usize, usize));455456impl Debug for Span {457	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {458		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)459	}460}461462#[derive(Clone, PartialEq, Acyclic)]463pub struct Spanned<T: Acyclic>(T, Span);464impl<T: Acyclic> Deref for Spanned<T> {465	type Target = T;466	fn deref(&self) -> &Self::Target {467		&self.0468	}469}470impl<T: Acyclic> Spanned<T> {471	#[inline]472	pub fn new(v: T, s: Span) -> Self {473		Self(v, s)474	}475	#[inline]476	pub fn span(&self) -> Span {477		self.1.clone()478	}479}480481impl<T: Debug + Acyclic> Debug for Spanned<T> {482	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {483		let expr = &**self;484		if f.alternate() {485			write!(f, "{:#?}", expr)?;486		} else {487			write!(f, "{:?}", expr)?;488		}489		write!(f, " from {:?}", self.span())?;490		Ok(())491	}492}