1use std::path::PathBuf;23use dprint_core::formatting::{PrintItems, PrintOptions, Signal};4use jrsonnet_parser::{5 ArgsDesc, BinaryOpType, BindSpec, Expr, FieldName, LocExpr, Member, ObjBody, Param, ParamsDesc,6 ParserSettings, Visibility,7};89pub trait Printable {10 fn print(&self) -> PrintItems;11}1213macro_rules! pi {14 (@i; $($t:tt)*) => {{15 let mut o = PrintItems::new();16 pi!(@s; o: $($t)*);17 o18 }};19 (@s; $o:ident: str($e:expr) $($t:tt)*) => {{20 $o.push_str($e);21 pi!(@s; $o: $($t)*);22 }};23 (@s; $o:ident: nl $($t:tt)*) => {{24 $o.push_signal(Signal::NewLine);25 pi!(@s; $o: $($t)*);26 }};27 (@s; $o:ident: >i $($t:tt)*) => {{28 $o.push_signal(Signal::StartIndent);29 pi!(@s; $o: $($t)*);30 }};31 (@s; $o:ident: <i $($t:tt)*) => {{32 $o.push_signal(Signal::FinishIndent);33 pi!(@s; $o: $($t)*);34 }};35 (@s; $o:ident: {$expr:expr} $($t:tt)*) => {{36 $o.extend($expr.print());37 pi!(@s; $o: $($t)*);38 }};39 (@s; $o:ident: if ($e:expr)($($then:tt)*) $($t:tt)*) => {{40 if $e {41 pi!(@s; $o: $($then)*);42 }43 pi!(@s; $o: $($t)*);44 }};45 (@s; $o:ident: ifelse ($e:expr)($($then:tt)*)($($else:tt)*) $($t:tt)*) => {{46 if $e {47 pi!(@s; $o: $($then)*);48 } else {49 pi!(@s; $o: $($else)*);50 }51 pi!(@s; $o: $($t)*);52 }};53 (@s; $i:ident:) => {}54}55macro_rules! p {56 (new: $($t:tt)*) => {57 pi!(@i; $($t)*)58 };59 ($o:ident: $($t:tt)*) => {60 pi!(@s; $o: $($t)*)61 };62}6364impl Printable for FieldName {65 fn print(&self) -> PrintItems {66 match self {67 FieldName::Fixed(f) => {68 p!(new: str(&f))69 }70 FieldName::Dyn(_) => todo!(),71 }72 }73}7475impl Printable for Visibility {76 fn print(&self) -> PrintItems {77 match self {78 Visibility::Normal => p!(new: str(":")),79 Visibility::Hidden => p!(new: str("::")),80 Visibility::Unhide => p!(new: str(":::")),81 }82 }83}8485impl Printable for BinaryOpType {86 fn print(&self) -> PrintItems {87 let o = self.to_string();88 p!(new: str(&o))89 }90}9192impl<T: Printable> Printable for Option<T> {93 fn print(&self) -> PrintItems {94 if let Some(v) = self {95 v.print()96 } else {97 PrintItems::new()98 }99 }100}101102impl Printable for Param {103 fn print(&self) -> PrintItems {104 p!(new:105 str(&self.0)106 if(self.1.is_some())(str(" = ") {self.1})107 )108 }109}110111impl Printable for ParamsDesc {112 fn print(&self) -> PrintItems {113 let mut out = PrintItems::new();114 for (i, item) in self.0.iter().enumerate() {115 if i != 0 {116 p!(out: str(", "));117 }118 out.extend(item.print());119 }120 out121 }122}123124impl Printable for ArgsDesc {125 fn print(&self) -> PrintItems {126 let mut out = PrintItems::new();127 let mut first = Some(());128 for u in self.unnamed.iter() {129 if first.take().is_none() {130 p!(out: str(", "));131 }132 p!(out: {u})133 }134 for (n, u) in self.named.iter() {135 if first.take().is_none() {136 p!(out: str(", "));137 }138 p!(out: str(&n) str(" = ") {u})139 }140141 out142 }143}144145impl Printable for BindSpec {146 fn print(&self) -> PrintItems {147 p!(new: str(&self.name) if(self.params.is_some())(str("(") {self.params} str(")")) str(" = ") {self.value})148 }149}150151struct StrExpr<'s>(&'s str);152153impl<'s> Printable for StrExpr<'s> {154 fn print(&self) -> PrintItems {155 todo!()156 }157}158159impl Printable for ObjBody {160 fn print(&self) -> PrintItems {161 let mut pi = PrintItems::new();162 p!(pi: str("{"));163 match self {164 ObjBody::MemberList(m) => {165 if !m.is_empty() {166 p!(pi: nl > i);167 for m in m {168 match m {169 Member::Field(f) => {170 p!(pi:171 {f.name} {f.params}172 if(f.plus)(str("+"))173 {f.visibility} str(" ")174 {f.value}175 str(",") nl176 );177 }178 Member::BindStmt(s) => {179 p!(pi: str("local ") {s} str(",") nl)180 }181 Member::AssertStmt(a) => p!(pi: str("assert ") {a.0} if(a.1.is_some())(182 str(" : ") {a.1}183 ) str(",") nl),184 }185 }186 p!(pi: <i);187 } else {188 p!(pi: str(" "))189 }190 }191 ObjBody::ObjComp(_) => todo!(),192 }193 p!(pi: str("}"));194 pi195 }196}197198impl Printable for Expr {199 fn print(&self) -> PrintItems {200 let mut pi = PrintItems::new();201 match self {202 Expr::Literal(l) => match l {203 jrsonnet_parser::LiteralType::This => p!(pi: str("self")),204 jrsonnet_parser::LiteralType::Super => p!(pi: str("super")),205 jrsonnet_parser::LiteralType::Dollar => p!(pi: str("$")),206 jrsonnet_parser::LiteralType::Null => p!(pi: str("null")),207 jrsonnet_parser::LiteralType::True => p!(pi: str("true")),208 jrsonnet_parser::LiteralType::False => p!(pi: str("false")),209 },210 Expr::Str(s) => {211 p!(pi: str("\"") str(s) str("\""))212 }213 Expr::Num(n) => {214 let n = n.to_string();215 p!(pi: str(&n));216 }217 Expr::Var(v) => p!(pi: str(&v)),218 Expr::Arr(a) => {219 p!(pi: str("["));220 for (i, v) in a.iter().enumerate() {221 if i != 0 {222 p!(pi: str(", "));223 }224 p!(pi: {v})225 }226 p!(pi: str("]"));227 }228 Expr::ArrComp(_, _) => todo!(),229 Expr::Obj(o) => {230 p!(pi: {o});231 }232 Expr::ObjExtend(a, b) => p!(pi: {a} str(" ") {b}),233 Expr::Parened(v) => {234 if let Expr::Parened(_) = &v.0 as &Expr {235 p!(pi: {v})236 } else {237 p!(pi: str("(") {v} str(")"))238 }239 }240 Expr::UnaryOp(_, _) => todo!(),241 Expr::BinaryOp(a, o, b) => {242 p!(pi:243 {a} str(" ") if(!matches!(&b.0 as &Expr, Expr::Obj(_)))({o} str(" ")) {b}244 )245 }246 Expr::AssertExpr(_, _) => todo!(),247 Expr::LocalExpr(s, v) => {248 p!(pi:249 str("local") nl >i250 );251 for spec in s.iter() {252 p!(pi: {spec} str(";") nl)253 }254 p!(pi:255 <i256 {v}257 );258 }259 Expr::Import(i) => {260 let v = i.to_str().unwrap();261 p!(pi: str("import \"") str(&v) str("\""));262 }263 Expr::ImportStr(_) => todo!(),264 Expr::ErrorStmt(_) => todo!(),265 Expr::Apply(f, a, t) => p!(pi:266 {f} str("(") {a} str(")") if(*t)(str("tailstrict"))267 ),268 Expr::Index(a, b) => p!(pi: {a} str("[") {b} str("]")),269 Expr::Function(_, _) => todo!(),270 Expr::Intrinsic(_) => todo!(),271 Expr::IfElse {272 cond,273 cond_then,274 cond_else,275 } => p!(pi:276 str("if ") {cond.0} str(" then") ifelse(cond_else.is_some())(277 nl >i278 {cond_then} nl279 <i str("else") nl >i280 {cond_else}281 <i282 )(str(" ") {cond_then})283 ),284 Expr::Slice(v, d) => {285 p!(pi:286 {v}287 str("[") {d.start} str(":") {d.end}288 if(d.step.is_some())(289 str(":")290 {d.step}291 )292 str("]")293 )294 }295 }296 pi297 }298}299300impl Printable for LocExpr {301 fn print(&self) -> PrintItems {302 self.0.print()303 }304}305306fn main() {307 let parsed = jrsonnet_parser::parse(308 r#"309 310 311 # Edit me!312 local b = import "b.libsonnet"; # comment313 local a = import "a.libsonnet";314 315 local f(x,y)=x+y;316 317 318 local Template = {z: "foo"};319 320 Template + {321 local322323 h = 3,324 assert self.a == 1325 326 : "error",327 "f": ((((((3)))))) ,328 "g g":329 f(4,2),330 arr: [[331 1, 2,332 ],333 3,334 {335 b: {336 c: {337 k: [16]338 }339 }340 }341 ],342 m: a[1::],343 m: b[::],344 k: if a == b then 345346347 2348349 else Template {}350 }351 352 353"#,354 &ParserSettings {355 file_name: PathBuf::from("example").into(),356 },357 )358 .unwrap();359360 let o = dprint_core::formatting::format(361 || {362 let print_items = parsed.print();363 print_items364 },365 PrintOptions {366 indent_width: 2,367 max_width: 100,368 use_tabs: false,369 new_line_text: "\n",370 },371 );372 println!("{}", o);373}