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 256 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 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}