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

difftreelog

source

cmds/jrsonnet-fmt/src/main.rs10.8 KiBsourcehistory
1use std::any::type_name;23use dprint_core::formatting::{PrintItems, PrintOptions, Signal};4use jrsonnet_rowan_parser::{5	nodes::{6		ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart,7		DestructRest, Expr, Field, FieldName, ForSpec, IfSpec, ImportKind, LhsExpr, Literal,8		Member, Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, String,9		UnaryOperator,10	},11	AstToken, SyntaxToken,12};1314pub trait Printable {15	fn print(&self) -> PrintItems;16}1718macro_rules! pi {19	(@i; $($t:tt)*) => {{20		#[allow(unused_mut)]21		let mut o = PrintItems::new();22		pi!(@s; o: $($t)*);23		o24	}};25	(@s; $o:ident: str($e:expr $(,)?) $($t:tt)*) => {{26		$o.push_str($e);27		pi!(@s; $o: $($t)*);28	}};29	(@s; $o:ident: nl $($t:tt)*) => {{30		$o.push_signal(Signal::NewLine);31		pi!(@s; $o: $($t)*);32	}};33	(@s; $o:ident: >i $($t:tt)*) => {{34		$o.push_signal(Signal::StartIndent);35		pi!(@s; $o: $($t)*);36	}};37	(@s; $o:ident: <i $($t:tt)*) => {{38		$o.push_signal(Signal::FinishIndent);39		pi!(@s; $o: $($t)*);40	}};41	(@s; $o:ident: {$expr:expr} $($t:tt)*) => {{42		$o.extend($expr.print());43		pi!(@s; $o: $($t)*);44	}};45	(@s; $o:ident: if ($e:expr)($($then:tt)*) $($t:tt)*) => {{46		if $e {47			pi!(@s; $o: $($then)*);48		}49		pi!(@s; $o: $($t)*);50	}};51	(@s; $o:ident: ifelse ($e:expr)($($then:tt)*)($($else:tt)*) $($t:tt)*) => {{52		if $e {53			pi!(@s; $o: $($then)*);54		} else {55			pi!(@s; $o: $($else)*);56		}57		pi!(@s; $o: $($t)*);58	}};59	(@s; $i:ident:) => {}60}61macro_rules! p {62	(new: $($t:tt)*) => {63		pi!(@i; $($t)*)64	};65	($o:ident: $($t:tt)*) => {66		pi!(@s; $o: $($t)*)67	};68}6970impl<P> Printable for Option<P>71where72	P: Printable,73{74	fn print(&self) -> PrintItems {75		if let Some(v) = self {76			v.print()77		} else {78			p!(new: str(79				&format!(80					"/*missing {}*/",81					type_name::<P>().replace("jrsonnet_rowan_parser::generated::nodes::", "")82				),83			))84		}85	}86}8788impl Printable for SyntaxToken {89	fn print(&self) -> PrintItems {90		p!(new: str(&self.to_string()))91	}92}9394impl Printable for String {95	fn print(&self) -> PrintItems {96		p!(new: str(&format!("{}", self)))97	}98}99impl Printable for Number {100	fn print(&self) -> PrintItems {101		p!(new: str(&format!("{}", self)))102	}103}104105impl Printable for Name {106	fn print(&self) -> PrintItems {107		p!(new: {self.ident_lit()})108	}109}110111impl Printable for DestructRest {112	fn print(&self) -> PrintItems {113		let mut pi = p!(new: str("..."));114		if let Some(name) = self.into() {115			p!(pi: {name});116		}117		pi118	}119}120121impl Printable for Destruct {122	fn print(&self) -> PrintItems {123		let mut pi = p!(new:);124		match self {125			Destruct::DestructFull(f) => {126				p!(pi: {f.name()})127			}128			Destruct::DestructSkip(_) => p!(pi: str("?")),129			Destruct::DestructArray(a) => {130				p!(pi: str("[") >i nl);131				for el in a.destruct_array_parts() {132					match el {133						DestructArrayPart::DestructArrayElement(e) => {134							p!(pi: {e.destruct()} str(",") nl)135						}136						DestructArrayPart::DestructRest(d) => {137							p!(pi: {d} str(",") nl)138						}139					}140				}141				p!(pi: <i str("]"));142			}143			Destruct::DestructObject(o) => {144				p!(pi: str("{") >i nl);145				for item in o.destruct_object_fields() {146					p!(pi: {item.field()});147					if let Some(des) = item.destruct() {148						p!(pi: str(": ") {des})149					}150					if let Some(def) = item.expr() {151						p!(pi: str(" = ") {def});152					}153					p!(pi: str(",") nl);154				}155				if let Some(rest) = o.destruct_rest() {156					p!(pi: {rest} nl)157				}158				p!(pi: <i str("}"));159			}160		}161		pi162	}163}164165impl Printable for FieldName {166	fn print(&self) -> PrintItems {167		match self {168			FieldName::FieldNameFixed(f) => {169				if let Some(id) = f.id() {170					p!(new: {id})171				} else if let Some(str) = f.string() {172					p!(new: {str})173				} else {174					p!(new: str("/*missing FieldName*/"))175				}176			}177			FieldName::FieldNameDynamic(d) => {178				p!(new: str("[") {d.expr()} str("]"))179			}180		}181	}182}183impl Printable for Field {184	fn print(&self) -> PrintItems {185		let mut pi = p!(new:);186		match self {187			Field::FieldNormal(n) => {188				p!(pi: {n.field_name()});189				if n.plus_token().is_some() {190					p!(pi: str("+"));191				}192				p!(pi: str(": ") {n.expr()});193			}194			Field::FieldMethod(m) => {195				p!(pi: {m.field_name()} {m.params_desc()} str(": ") {m.expr()});196			}197		}198		pi199	}200}201202impl Printable for ObjLocal {203	fn print(&self) -> PrintItems {204		p!(new: str("local ") {self.bind()})205	}206}207208impl Printable for Assertion {209	fn print(&self) -> PrintItems {210		let mut pi = p!(new: str("assert ") {self.condition()});211		if self.colon_token().is_some() || self.message().is_some() {212			p!(pi: str(": ") {self.message()})213		}214		pi215	}216}217218impl Printable for ParamsDesc {219	fn print(&self) -> PrintItems {220		let mut pi = p!(new: str("(") >i nl);221		for param in self.params() {222			p!(pi: {param.destruct()});223			if param.assign_token().is_some() || param.expr().is_some() {224				p!(pi: str(" = ") {param.expr()})225			}226			p!(pi: str(",") nl)227		}228		p!(pi: <i str(")"));229		pi230	}231}232impl Printable for ArgsDesc {233	fn print(&self) -> PrintItems {234		let mut pi = p!(new: str("(") >i nl);235		for arg in self.args() {236			if arg.name().is_some() || arg.assign_token().is_some() {237				p!(pi: {arg.name()} str(" = "));238			}239			p!(pi: {arg.expr()} str(",") nl)240		}241		p!(pi: <i str(")"));242		pi243	}244}245impl Printable for SliceDesc {246	fn print(&self) -> PrintItems {247		let mut pi = p!(new: str("["));248		if self.from().is_some() {249			p!(pi: {self.from()});250		}251		p!(pi: str(":"));252		if self.end().is_some() {253			p!(pi: {self.end().map(|e|e.expr())})254		}255		// Keep only one : in case if we don't need step256		if self.step().is_some() {257			p!(pi: str(":") {self.step().map(|e|e.expr())});258		}259		p!(pi: str("]"));260		pi261	}262}263264impl Printable for ObjBody {265	fn print(&self) -> PrintItems {266		match self {267			ObjBody::ObjBodyComp(_) => todo!(),268			ObjBody::ObjBodyMemberList(l) => {269				let mut pi = p!(new:);270				for mem in l.members() {271					match mem {272						Member::MemberBindStmt(b) => {273							p!(pi: {b.obj_local()})274						}275						Member::MemberAssertStmt(ass) => {276							p!(pi: {ass.assertion()})277						}278						Member::MemberField(f) => {279							p!(pi: {f.field()})280						}281					}282					p!(pi: str(",") nl)283				}284				pi285			}286		}287	}288}289impl Printable for UnaryOperator {290	fn print(&self) -> PrintItems {291		p!(new: str(self.text()))292	}293}294impl Printable for BinaryOperator {295	fn print(&self) -> PrintItems {296		p!(new: str(self.text()))297	}298}299impl Printable for Bind {300	fn print(&self) -> PrintItems {301		match self {302			Bind::BindDestruct(d) => {303				p!(new: {d.into()} str(" = ") {d.value()})304			}305			Bind::BindFunction(f) => {306				p!(new: str("function") {f.params()} str(" = ") {f.value()})307			}308		}309	}310}311impl Printable for Literal {312	fn print(&self) -> PrintItems {313		p!(new: str(&self.syntax().to_string()))314	}315}316impl Printable for ImportKind {317	fn print(&self) -> PrintItems {318		p!(new: str(&self.syntax().to_string()))319	}320}321impl Printable for LhsExpr {322	fn print(&self) -> PrintItems {323		p!(new: {self.expr()})324	}325}326impl Printable for ForSpec {327	fn print(&self) -> PrintItems {328		p!(new: str("for ") {self.bind()} str(" in ") {self.expr()})329	}330}331impl Printable for IfSpec {332	fn print(&self) -> PrintItems {333		p!(new: str("if ") {self.expr()})334	}335}336impl Printable for CompSpec {337	fn print(&self) -> PrintItems {338		match self {339			CompSpec::ForSpec(f) => f.print(),340			CompSpec::IfSpec(i) => i.print(),341		}342	}343}344impl Printable for Expr {345	fn print(&self) -> PrintItems {346		match self {347			Expr::ExprBinary(b) => {348				p!(new: {b.lhs()} str(" ") {b.binary_operator()} str(" ") {b.rhs()})349			}350			Expr::ExprUnary(u) => p!(new: {u.unary_operator()} {u.rhs()}),351			Expr::ExprSlice(s) => {352				p!(new: {s.expr()} {s.slice_desc()})353			}354			Expr::ExprIndex(i) => {355				p!(new: {i.expr()} str(".") {i.index()})356			}357			Expr::ExprIndexExpr(i) => p!(new: {i.base()} str("[") {i.index()} str("]")),358			Expr::ExprApply(a) => {359				let mut pi = p!(new: {a.expr()} {a.args_desc()});360				if a.tailstrict_kw_token().is_some() {361					p!(pi: str(" tailstrict"));362				}363				pi364			}365			Expr::ExprObjExtend(ex) => {366				p!(new: {ex.lhs_expr()} str(" ") {ex.expr()})367			}368			Expr::ExprParened(p) => {369				p!(new: str("(") {p.expr()} str(")"))370			}371			Expr::ExprIntrinsicThisFile(_) => p!(new: str("$intrinsicThisFile")),372			Expr::ExprIntrinsicId(_) => p!(new: str("$intrinsicId")),373			Expr::ExprIntrinsic(i) => p!(new: str("$intrinsic(") {i.name()} str(")")),374			Expr::ExprString(s) => p!(new: {s.string()}),375			Expr::ExprNumber(n) => p!(new: {n.number()}),376			Expr::ExprArray(a) => {377				let mut pi = p!(new: str("[") >i nl);378				for el in a.exprs() {379					p!(pi: {el} str(",") nl);380				}381				p!(pi: <i str("]"));382				pi383			}384			Expr::ExprObject(o) => {385				p!(new: str("{") >i nl {o.obj_body()} <i str("}"))386			}387			Expr::ExprArrayComp(arr) => {388				let mut pi = p!(new: str("[") {arr.expr()});389				for spec in arr.comp_specs() {390					p!(pi: str(" ") {spec});391				}392				p!(pi: str("]"));393				pi394			}395			Expr::ExprImport(v) => {396				p!(new: {v.import_kind()} str(" ") {v.string()})397			}398			Expr::ExprVar(n) => p!(new: {n.name()}),399			Expr::ExprLocal(l) => {400				let mut pi = p!(new: str("local") >i nl);401				for bind in l.binds() {402					p!(pi: {bind} str(",") nl);403				}404				p!(pi: <i str(";") nl {l.expr()});405				pi406			}407			Expr::ExprIfThenElse(ite) => {408				let mut pi =409					p!(new: str("if ") {ite.cond()} str(" then ") {ite.then().map(|t| t.expr())});410				if ite.else_kw_token().is_some() || ite.else_().is_some() {411					p!(pi: str(" else ") {ite.else_().map(|t| t.expr())})412				}413				pi414			}415			Expr::ExprFunction(f) => p!(new: str("function") {f.params_desc()} str(" ") {f.expr()}),416			Expr::ExprAssert(a) => p!(new: {a.assertion()} str("; ") {a.expr()}),417			Expr::ExprError(e) => p!(new: str("error ") {e.expr()}),418			Expr::ExprLiteral(l) => {419				p!(new: {l.literal()})420			}421		}422	}423}424425impl Printable for SourceFile {426	fn print(&self) -> PrintItems {427		assert!(self.expr().is_some());428		self.expr().print()429	}430}431432fn main() {433	let (parsed, _errors) = jrsonnet_rowan_parser::parse(434		r#"435436437		# Edit me!438		local b = import "b.libsonnet";  # comment439		local a = import "a.libsonnet";440441			 local f(x,y)=x+y;442443		local {a: [b, ..., c], d, ...e} = null;444445		local ass = assert false : false; false;446447		local fn = function(a, b, c = 3) 4;448449		local comp = [a for b in c if d == e];450		local ocomp = {[k]: 1 for k in v};451452		local ? = skip;453454		local intr = $intrinsic(test);455		local intrId = $intrinsicId;456		local intrThisFile = $intrinsicThisFile;457458		local ie = a[expr];459460		local unary = !a;461462		local Template = {z: "foo"};463464		{465						local466467					h = 3,468					assert self.a == 1469470					: "error",471		"f": ((((((3)))))) ,472		"g g":473		f(4,2),474		arr: [[475		  1, 2,476		  ],477		  3,478		  {479			  b: {480				  c: {481					  k: [16]482				  }483			  }484		  }485		  ],486		  m: a[1::],487		  m: b[::],488		  k: if a         == b    then489490491		  2492493		  else Template {}494		} + Template495496497"#,498	);499500	// dbg!(errors);501	dbg!(&parsed);502503	let o = dprint_core::formatting::format(504		|| parsed.print(),505		PrintOptions {506			indent_width: 2,507			max_width: 100,508			use_tabs: false,509			new_line_text: "\n",510		},511	);512	println!("{}", o);513}