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

difftreelog

source

crates/jrsonnet-parser/src/expr.rs8.8 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::source::Source;1112#[derive(Debug, PartialEq, Acyclic)]13pub enum FieldName {14	/// {fixed: 2}15	Fixed(IStr),16	/// {["dyn"+"amic"]: 3}17	Dyn(Spanned<Expr>),18}1920#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]21#[repr(u8)]22pub enum Visibility {23	/// :24	Normal,25	/// ::26	Hidden,27	/// :::28	Unhide,29}3031impl Visibility {32	pub fn is_visible(&self) -> bool {33		matches!(self, Self::Normal | Self::Unhide)34	}35}3637#[derive(Debug, PartialEq, Acyclic)]38pub struct AssertStmt(pub Spanned<Expr>, pub Option<Spanned<Expr>>);3940#[derive(Debug, PartialEq, Acyclic)]41pub struct FieldMember {42	pub name: FieldName,43	pub plus: bool,44	pub params: Option<ParamsDesc>,45	pub visibility: Visibility,46	pub value: Rc<Spanned<Expr>>,47}4849#[derive(Debug, PartialEq, Acyclic)]50pub(crate) enum Member {51	Field(FieldMember),52	BindStmt(BindSpec),53	AssertStmt(AssertStmt),54}5556#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]57pub enum UnaryOpType {58	Plus,59	Minus,60	BitNot,61	Not,62}6364impl Display for UnaryOpType {65	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {66		use UnaryOpType::*;67		write!(68			f,69			"{}",70			match self {71				Plus => "+",72				Minus => "-",73				BitNot => "~",74				Not => "!",75			}76		)77	}78}7980#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]81pub enum BinaryOpType {82	Mul,83	Div,8485	/// Implemented as intrinsic, put here for completeness86	Mod,8788	Add,89	Sub,9091	Lhs,92	Rhs,9394	Lt,95	Gt,96	Lte,97	Gte,9899	BitAnd,100	BitOr,101	BitXor,102103	Eq,104	Neq,105106	And,107	Or,108	#[cfg(feature = "exp-null-coaelse")]109	NullCoaelse,110111	// Equialent to std.objectHasEx(a, b, true)112	In,113}114115impl Display for BinaryOpType {116	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {117		use BinaryOpType::*;118		write!(119			f,120			"{}",121			match self {122				Mul => "*",123				Div => "/",124				Mod => "%",125				Add => "+",126				Sub => "-",127				Lhs => "<<",128				Rhs => ">>",129				Lt => "<",130				Gt => ">",131				Lte => "<=",132				Gte => ">=",133				BitAnd => "&",134				BitOr => "|",135				BitXor => "^",136				Eq => "==",137				Neq => "!=",138				And => "&&",139				Or => "||",140				In => "in",141				#[cfg(feature = "exp-null-coaelse")]142				NullCoaelse => "??",143			}144		)145	}146}147148/// name, default value149#[derive(Debug, PartialEq, Acyclic)]150pub struct Param(pub Destruct, pub Option<Rc<Spanned<Expr>>>);151152/// Defined function parameters153#[derive(Debug, Clone, PartialEq, Acyclic)]154pub struct ParamsDesc(pub Rc<Vec<Param>>);155156impl Deref for ParamsDesc {157	type Target = Vec<Param>;158	fn deref(&self) -> &Self::Target {159		&self.0160	}161}162163#[derive(Debug, PartialEq, Acyclic)]164pub struct ArgsDesc {165	pub unnamed: Vec<Rc<Spanned<Expr>>>,166	pub named: Vec<(IStr, Rc<Spanned<Expr>>)>,167}168impl ArgsDesc {169	pub fn new(unnamed: Vec<Rc<Spanned<Expr>>>, named: Vec<(IStr, Rc<Spanned<Expr>>)>) -> Self {170		Self { unnamed, named }171	}172}173174#[derive(Debug, Clone, PartialEq, Eq, Acyclic)]175pub enum DestructRest {176	/// ...rest177	Keep(IStr),178	/// ...179	Drop,180}181182#[derive(Debug, Clone, PartialEq, Acyclic)]183pub enum Destruct {184	Full(IStr),185	#[cfg(feature = "exp-destruct")]186	Skip,187	#[cfg(feature = "exp-destruct")]188	Array {189		start: Vec<Destruct>,190		rest: Option<DestructRest>,191		end: Vec<Destruct>,192	},193	#[cfg(feature = "exp-destruct")]194	Object {195		fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,196		rest: Option<DestructRest>,197	},198}199impl Destruct {200	/// Name of destructure, used for function parameter names201	pub fn name(&self) -> Option<IStr> {202		match self {203			Self::Full(name) => Some(name.clone()),204			#[cfg(feature = "exp-destruct")]205			_ => None,206		}207	}208	pub fn capacity_hint(&self) -> usize {209		#[cfg(feature = "exp-destruct")]210		fn cap_rest(rest: &Option<DestructRest>) -> usize {211			match rest {212				Some(DestructRest::Keep(_)) => 1,213				Some(DestructRest::Drop) => 0,214				None => 0,215			}216		}217		match self {218			Self::Full(_) => 1,219			#[cfg(feature = "exp-destruct")]220			Self::Skip => 0,221			#[cfg(feature = "exp-destruct")]222			Self::Array { start, rest, end } => {223				start.iter().map(Destruct::capacity_hint).sum::<usize>()224					+ end.iter().map(Destruct::capacity_hint).sum::<usize>()225					+ cap_rest(rest)226			}227			#[cfg(feature = "exp-destruct")]228			Self::Object { fields, rest } => {229				let mut out = 0;230				for (_, into, _) in fields {231					match into {232						Some(v) => out += v.capacity_hint(),233						// Field is destructured to default name234						None => out += 1,235					}236				}237				out + cap_rest(rest)238			}239		}240	}241}242243#[derive(Debug, PartialEq, Acyclic)]244pub enum BindSpec {245	Field {246		into: Destruct,247		value: Rc<Spanned<Expr>>,248	},249	Function {250		name: IStr,251		params: ParamsDesc,252		value: Rc<Spanned<Expr>>,253	},254}255impl BindSpec {256	pub fn capacity_hint(&self) -> usize {257		match self {258			BindSpec::Field { into, .. } => into.capacity_hint(),259			BindSpec::Function { .. } => 1,260		}261	}262}263264#[derive(Debug, PartialEq, Acyclic)]265pub struct IfSpecData(pub Spanned<Expr>);266267#[derive(Debug, PartialEq, Acyclic)]268pub struct ForSpecData(pub Destruct, pub Spanned<Expr>);269270#[derive(Debug, PartialEq, Acyclic)]271pub enum CompSpec {272	IfSpec(IfSpecData),273	ForSpec(ForSpecData),274}275276#[derive(Debug, PartialEq, Acyclic)]277pub struct ObjComp {278	pub locals: Rc<Vec<BindSpec>>,279	pub field: Rc<FieldMember>,280	pub compspecs: Vec<CompSpec>,281}282283#[derive(Debug, PartialEq, Acyclic)]284pub struct ObjMembers {285	pub locals: Rc<Vec<BindSpec>>,286	pub asserts: Rc<Vec<AssertStmt>>,287	pub fields: Vec<FieldMember>,288}289290#[derive(Debug, PartialEq, Acyclic)]291pub enum ObjBody {292	MemberList(ObjMembers),293	ObjComp(ObjComp),294}295296#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]297pub enum LiteralType {298	This,299	Super,300	Dollar,301	Null,302	True,303	False,304}305306#[derive(Debug, PartialEq, Acyclic)]307pub struct SliceDesc {308	pub start: Option<Spanned<Expr>>,309	pub end: Option<Spanned<Expr>>,310	pub step: Option<Spanned<Expr>>,311}312313#[derive(Debug, PartialEq, Acyclic)]314pub struct AssertExpr {315	pub assert: AssertStmt,316	pub rest: Spanned<Expr>,317}318319#[derive(Debug, PartialEq, Acyclic)]320pub struct BinaryOp {321	pub lhs: Spanned<Expr>,322	pub op: BinaryOpType,323	pub rhs: Spanned<Expr>,324}325326#[derive(Debug, PartialEq, Acyclic)]327pub enum ImportKind {328	Normal,329	Str,330	Bin,331}332333#[derive(Debug, PartialEq, Acyclic)]334pub struct IfElse {335	pub cond: IfSpecData,336	pub cond_then: Spanned<Expr>,337	pub cond_else: Option<Spanned<Expr>>,338}339340#[derive(Debug, PartialEq, Acyclic)]341pub struct Slice {342	pub value: Spanned<Expr>,343	pub slice: SliceDesc,344}345346/// Syntax base347#[derive(Debug, PartialEq, Acyclic)]348pub enum Expr {349	Literal(LiteralType),350351	/// String value: "hello"352	Str(IStr),353	/// Number: 1, 2.0, 2e+20354	Num(f64),355	/// Variable name: test356	Var(IStr),357358	/// Array of expressions: [1, 2, "Hello"]359	Arr(Rc<Vec<Spanned<Expr>>>),360	/// Array comprehension:361	/// ```jsonnet362	///  ingredients: [363	///    { kind: kind, qty: 4 / 3 }364	///    for kind in [365	///      'Honey Syrup',366	///      'Lemon Juice',367	///      'Farmers Gin',368	///    ]369	///  ],370	/// ```371	ArrComp(Rc<Spanned<Expr>>, Vec<CompSpec>),372373	/// Object: {a: 2}374	Obj(ObjBody),375	/// Object extension: var1 {b: 2}376	ObjExtend(Rc<Spanned<Expr>>, ObjBody),377378	/// -2379	UnaryOp(UnaryOpType, Box<Spanned<Expr>>),380	/// 2 - 2381	BinaryOp(Box<BinaryOp>),382	/// assert 2 == 2 : "Math is broken"383	AssertExpr(Rc<AssertExpr>),384	/// local a = 2; { b: a }385	LocalExpr(Vec<BindSpec>, Box<Spanned<Expr>>),386387	/// import* "hello"388	Import(ImportKind, Box<Spanned<Expr>>),389	/// error "I'm broken"390	ErrorStmt(Box<Spanned<Expr>>),391	/// a(b, c)392	Apply(Box<Spanned<Expr>>, ArgsDesc, bool),393	/// a[b], a.b, a?.b394	Index {395		indexable: Box<Spanned<Expr>>,396		parts: Vec<IndexPart>,397	},398	/// function(x) x399	Function(ParamsDesc, Rc<Spanned<Expr>>),400	/// if true == false then 1 else 2401	IfElse(Box<IfElse>),402	Slice(Box<Slice>),403}404405#[derive(Debug, PartialEq, Acyclic)]406pub struct IndexPart {407	pub value: Spanned<Expr>,408	#[cfg(feature = "exp-null-coaelse")]409	pub null_coaelse: bool,410}411412/// file, begin offset, end offset413#[derive(Clone, PartialEq, Eq, Acyclic)]414#[repr(C)]415pub struct Span(pub Source, pub u32, pub u32);416impl Span {417	pub fn belongs_to(&self, other: &Span) -> bool {418		other.0 == self.0 && other.1 <= self.1 && other.2 >= self.2419	}420}421422static_assertions::assert_eq_size!(Span, (usize, usize));423424impl Debug for Span {425	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {426		write!(f, "{:?}:{:?}-{:?}", self.0, self.1, self.2)427	}428}429430#[derive(Clone, PartialEq, Acyclic)]431pub struct Spanned<T: Acyclic>(T, Span);432impl<T: Acyclic> Deref for Spanned<T> {433	type Target = T;434	fn deref(&self) -> &Self::Target {435		&self.0436	}437}438impl<T: Acyclic> Spanned<T> {439	#[inline]440	pub fn new(v: T, s: Span) -> Self {441		Self(v, s)442	}443	#[inline]444	pub fn span(&self) -> Span {445		self.1.clone()446	}447}448449impl<T: Debug + Acyclic> Debug for Spanned<T> {450	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {451		let expr = &**self;452		if f.alternate() {453			write!(f, "{:#?}", expr)?;454		} else {455			write!(f, "{:?}", expr)?;456		}457		write!(f, " from {:?}", self.span())?;458		Ok(())459	}460}