1+ use std:: fmt:: Write ;
12use techscript_ast:: { DSLBlock , DSLChild , Program , Statement } ;
23
34pub trait Formatter {
@@ -20,136 +21,160 @@ impl DocumentFormatter {
2021 self . format ( & program)
2122 }
2223
23- fn format_indent ( & self , indent : usize ) -> String {
24- " " . repeat ( indent * self . indent_size )
24+ fn format_indent ( & self , indent : usize , buf : & mut String ) {
25+ for _ in 0 ..( indent * self . indent_size ) {
26+ buf. push ( ' ' ) ;
27+ }
2528 }
2629
27- fn format_dsl_block ( & self , block : & DSLBlock , indent : usize ) -> String {
28- let mut output = String :: new ( ) ;
29- let base = self . format_indent ( indent) ;
30-
31- output. push_str ( & base) ;
32- output. push_str ( & block. kind ) ;
30+ fn format_dsl_block ( & self , block : & DSLBlock , indent : usize , buf : & mut String ) {
31+ self . format_indent ( indent, buf) ;
32+ buf. push_str ( & block. kind ) ;
3333 for arg in & block. args {
34- output . push ( ' ' ) ;
35- output . push_str ( & self . format_expr ( arg) ) ;
34+ buf . push ( ' ' ) ;
35+ self . format_expr ( arg, buf ) ;
3636 }
37- output . push ( '\n' ) ;
37+ buf . push ( '\n' ) ;
3838
3939 for prop in & block. properties {
40- output . push_str ( & self . format_indent ( indent + 1 ) ) ;
41- output . push_str ( & prop. name ) ;
40+ self . format_indent ( indent + 1 , buf ) ;
41+ buf . push_str ( & prop. name ) ;
4242 if let Some ( ref val) = prop. value {
43- output . push ( ' ' ) ;
44- output . push_str ( & self . format_expr ( val) ) ;
43+ buf . push ( ' ' ) ;
44+ self . format_expr ( val, buf ) ;
4545 }
46- output . push ( '\n' ) ;
46+ buf . push ( '\n' ) ;
4747 }
4848
4949 for child in & block. children {
5050 match child {
5151 DSLChild :: Block ( sub_block) => {
52- output . push_str ( & self . format_dsl_block ( sub_block, indent + 1 ) ) ;
52+ self . format_dsl_block ( sub_block, indent + 1 , buf ) ;
5353 }
5454 DSLChild :: Code ( code_block) => {
55- output . push_str ( & self . format_indent ( indent + 1 ) ) ;
56- output . push_str ( "code\n " ) ;
55+ self . format_indent ( indent + 1 , buf ) ;
56+ buf . push_str ( "code\n " ) ;
5757 for stmt in & code_block. statements {
58- output . push_str ( & self . format_stmt ( stmt, indent + 2 ) ) ;
58+ self . format_stmt ( stmt, indent + 2 , buf ) ;
5959 }
6060 }
6161 DSLChild :: Property ( prop) => {
62- output . push_str ( & self . format_indent ( indent + 1 ) ) ;
63- output . push_str ( & prop. name ) ;
62+ self . format_indent ( indent + 1 , buf ) ;
63+ buf . push_str ( & prop. name ) ;
6464 if let Some ( ref val) = prop. value {
65- output . push ( ' ' ) ;
66- output . push_str ( & self . format_expr ( val) ) ;
65+ buf . push ( ' ' ) ;
66+ self . format_expr ( val, buf ) ;
6767 }
68- output . push ( '\n' ) ;
68+ buf . push ( '\n' ) ;
6969 }
7070 }
7171 }
7272
73- output. push_str ( & base) ;
74- output. push_str ( "end\n " ) ;
75- output
73+ self . format_indent ( indent, buf) ;
74+ buf. push_str ( "end\n " ) ;
7675 }
7776
78- fn format_expr ( & self , expr : & techscript_ast:: Expression ) -> String {
77+ fn format_expr ( & self , expr : & techscript_ast:: Expression , buf : & mut String ) {
7978 match expr {
80- techscript_ast:: Expression :: Literal ( lit) => self . format_lit ( & lit. value ) ,
81- techscript_ast:: Expression :: Identifier ( ident) => ident. name . clone ( ) ,
79+ techscript_ast:: Expression :: Literal ( lit) => self . format_lit ( & lit. value , buf ) ,
80+ techscript_ast:: Expression :: Identifier ( ident) => buf . push_str ( & ident. name ) ,
8281 techscript_ast:: Expression :: FString ( fs) => {
83- let mut s = "f\" " . to_string ( ) ;
82+ buf . push_str ( "f\" " ) ;
8483 for part in & fs. parts {
8584 match part {
86- techscript_ast:: FStringPart :: Literal ( l) => s . push_str ( l) ,
87- techscript_ast:: FStringPart :: Expr ( _) => s . push_str ( "{}" ) ,
85+ techscript_ast:: FStringPart :: Literal ( l) => buf . push_str ( l) ,
86+ techscript_ast:: FStringPart :: Expr ( _) => buf . push_str ( "{}" ) ,
8887 }
8988 }
90- s. push ( '"' ) ;
91- s
89+ buf. push ( '"' ) ;
90+ }
91+ _ => {
92+ let _ = write ! ( buf, "{:?}" , expr) ;
9293 }
93- _ => format ! ( "{:?}" , expr) ,
9494 }
9595 }
9696
97- fn format_lit ( & self , lit : & techscript_ast:: LiteralVal ) -> String {
97+ fn format_lit ( & self , lit : & techscript_ast:: LiteralVal , buf : & mut String ) {
9898 match lit {
99- techscript_ast:: LiteralVal :: Str ( s) => format ! ( "\" {}\" " , s) ,
100- techscript_ast:: LiteralVal :: Int ( i) => i. to_string ( ) ,
101- techscript_ast:: LiteralVal :: Float ( f) => f. to_string ( ) ,
102- techscript_ast:: LiteralVal :: Bool ( b) => b. to_string ( ) ,
103- techscript_ast:: LiteralVal :: None => "none" . to_string ( ) ,
99+ techscript_ast:: LiteralVal :: Str ( s) => {
100+ buf. push ( '"' ) ;
101+ buf. push_str ( s) ;
102+ buf. push ( '"' ) ;
103+ }
104+ techscript_ast:: LiteralVal :: Int ( i) => {
105+ let _ = write ! ( buf, "{}" , i) ;
106+ }
107+ techscript_ast:: LiteralVal :: Float ( f) => {
108+ let _ = write ! ( buf, "{}" , f) ;
109+ }
110+ techscript_ast:: LiteralVal :: Bool ( b) => {
111+ if * b {
112+ buf. push_str ( "true" ) ;
113+ } else {
114+ buf. push_str ( "false" ) ;
115+ }
116+ }
117+ techscript_ast:: LiteralVal :: None => buf. push_str ( "none" ) ,
104118 }
105119 }
106120
107- fn format_stmt ( & self , stmt : & Statement , indent : usize ) -> String {
108- let base = self . format_indent ( indent) ;
121+ fn format_stmt ( & self , stmt : & Statement , indent : usize , buf : & mut String ) {
109122 match stmt {
110- Statement :: DSL ( block) => self . format_dsl_block ( block, indent) ,
123+ Statement :: DSL ( block) => self . format_dsl_block ( block, indent, buf ) ,
111124 Statement :: VarDecl ( decl) => {
125+ self . format_indent ( indent, buf) ;
126+ buf. push_str ( "make " ) ;
112127 let name = match & decl. pattern {
113128 techscript_ast:: Pattern :: Single ( ident) => ident. name . clone ( ) ,
114129 _ => "<pat>" . to_string ( ) ,
115130 } ;
116- format ! (
117- "{}make {} = {}\n " ,
118- base,
119- name,
120- self . format_expr( & decl. initializer)
121- )
131+ buf. push_str ( & name) ;
132+ buf. push_str ( " = " ) ;
133+ self . format_expr ( & decl. initializer , buf) ;
134+ buf. push ( '\n' ) ;
122135 }
123136 Statement :: ConstDecl ( decl) => {
137+ self . format_indent ( indent, buf) ;
138+ buf. push_str ( "const " ) ;
124139 let name = match & decl. pattern {
125140 techscript_ast:: Pattern :: Single ( ident) => ident. name . clone ( ) ,
126141 _ => "<pat>" . to_string ( ) ,
127142 } ;
128- format ! (
129- "{}const {} = {}\n " ,
130- base,
131- name,
132- self . format_expr( & decl. initializer)
133- )
143+ buf. push_str ( & name) ;
144+ buf. push_str ( " = " ) ;
145+ self . format_expr ( & decl. initializer , buf) ;
146+ buf. push ( '\n' ) ;
147+ }
148+ Statement :: Say ( s) => {
149+ self . format_indent ( indent, buf) ;
150+ buf. push_str ( "say " ) ;
151+ self . format_expr ( & s. value , buf) ;
152+ buf. push ( '\n' ) ;
134153 }
135- Statement :: Say ( s) => format ! ( "{}say {}\n " , base, self . format_expr( & s. value) ) ,
136154 Statement :: Return ( ret) => {
155+ self . format_indent ( indent, buf) ;
137156 if let Some ( ref val) = ret. value {
138- format ! ( "{}return {}\n " , base, self . format_expr( val) )
157+ buf. push_str ( "return " ) ;
158+ self . format_expr ( val, buf) ;
159+ buf. push ( '\n' ) ;
139160 } else {
140- format ! ( "{} return\n ", base )
161+ buf . push_str ( " return\n ") ;
141162 }
142163 }
143- _ => format ! ( "{}<stmt>\n " , base) ,
164+ _ => {
165+ self . format_indent ( indent, buf) ;
166+ buf. push_str ( "<stmt>\n " ) ;
167+ }
144168 }
145169 }
146170}
147171
148172impl Formatter for DocumentFormatter {
149173 fn format ( & self , program : & Program ) -> String {
150- let mut output = String :: new ( ) ;
174+ // Estimate 64 bytes per statement as a reasonable baseline capacity
175+ let mut output = String :: with_capacity ( program. statements . len ( ) * 64 ) ;
151176 for stmt in & program. statements {
152- output . push_str ( & self . format_stmt ( stmt, 0 ) ) ;
177+ self . format_stmt ( stmt, 0 , & mut output ) ;
153178 }
154179 output
155180 }
0 commit comments