1use crate::{ast::*, interpreter::Instruction, types::*};
59use std::string::ToString;
60
61impl ToString for &InterfaceType {
63 fn to_string(&self) -> String {
64 match self {
65 InterfaceType::S8 => "s8".to_string(),
66 InterfaceType::S16 => "s16".to_string(),
67 InterfaceType::S32 => "s32".to_string(),
68 InterfaceType::S64 => "s64".to_string(),
69 InterfaceType::U8 => "u8".to_string(),
70 InterfaceType::U16 => "u16".to_string(),
71 InterfaceType::U32 => "u32".to_string(),
72 InterfaceType::U64 => "u64".to_string(),
73 InterfaceType::F32 => "f32".to_string(),
74 InterfaceType::F64 => "f64".to_string(),
75 InterfaceType::String => "string".to_string(),
76 InterfaceType::Anyref => "anyref".to_string(),
77 InterfaceType::I32 => "i32".to_string(),
78 InterfaceType::I64 => "i64".to_string(),
79 InterfaceType::Record(record_type) => record_type.to_string(),
80 }
81 }
82}
83
84impl ToString for &RecordType {
85 fn to_string(&self) -> String {
86 format!(
87 "record{fields}",
88 fields = self
89 .fields
90 .iter()
91 .fold(String::new(), |mut accumulator, interface_type| {
92 accumulator.push(' ');
93 accumulator.push_str(&format!("(field {})", &interface_type.to_string()));
94 accumulator
95 }),
96 )
97 }
98}
99
100impl ToString for &Instruction {
102 fn to_string(&self) -> String {
103 match self {
104 Instruction::ArgumentGet { index } => format!("arg.get {}", index),
105 Instruction::CallCore { function_index } => format!("call-core {}", function_index),
106 Instruction::S8FromI32 => "s8.from_i32".into(),
107 Instruction::S8FromI64 => "s8.from_i64".into(),
108 Instruction::S16FromI32 => "s16.from_i32".into(),
109 Instruction::S16FromI64 => "s16.from_i64".into(),
110 Instruction::S32FromI32 => "s32.from_i32".into(),
111 Instruction::S32FromI64 => "s32.from_i64".into(),
112 Instruction::S64FromI32 => "s64.from_i32".into(),
113 Instruction::S64FromI64 => "s64.from_i64".into(),
114 Instruction::I32FromS8 => "i32.from_s8".into(),
115 Instruction::I32FromS16 => "i32.from_s16".into(),
116 Instruction::I32FromS32 => "i32.from_s32".into(),
117 Instruction::I32FromS64 => "i32.from_s64".into(),
118 Instruction::I64FromS8 => "i64.from_s8".into(),
119 Instruction::I64FromS16 => "i64.from_s16".into(),
120 Instruction::I64FromS32 => "i64.from_s32".into(),
121 Instruction::I64FromS64 => "i64.from_s64".into(),
122 Instruction::U8FromI32 => "u8.from_i32".into(),
123 Instruction::U8FromI64 => "u8.from_i64".into(),
124 Instruction::U16FromI32 => "u16.from_i32".into(),
125 Instruction::U16FromI64 => "u16.from_i64".into(),
126 Instruction::U32FromI32 => "u32.from_i32".into(),
127 Instruction::U32FromI64 => "u32.from_i64".into(),
128 Instruction::U64FromI32 => "u64.from_i32".into(),
129 Instruction::U64FromI64 => "u64.from_i64".into(),
130 Instruction::I32FromU8 => "i32.from_u8".into(),
131 Instruction::I32FromU16 => "i32.from_u16".into(),
132 Instruction::I32FromU32 => "i32.from_u32".into(),
133 Instruction::I32FromU64 => "i32.from_u64".into(),
134 Instruction::I64FromU8 => "i64.from_u8".into(),
135 Instruction::I64FromU16 => "i64.from_u16".into(),
136 Instruction::I64FromU32 => "i64.from_u32".into(),
137 Instruction::I64FromU64 => "i64.from_u64".into(),
138 Instruction::StringLiftMemory => "string.lift_memory".into(),
139 Instruction::StringLowerMemory => "string.lower_memory".into(),
140 Instruction::StringSize => "string.size".into(),
141 Instruction::RecordLift { type_index } => format!("record.lift {}", type_index),
142 Instruction::RecordLower { type_index } => format!("record.lower {}", type_index),
143 }
144 }
145}
146
147fn input_types_to_param(input_types: &[InterfaceType]) -> String {
150 if input_types.is_empty() {
151 "".into()
152 } else {
153 format!(
154 "\n (param{})",
155 input_types
156 .iter()
157 .fold(String::new(), |mut accumulator, interface_type| {
158 accumulator.push(' ');
159 accumulator.push_str(&interface_type.to_string());
160 accumulator
161 })
162 )
163 }
164}
165
166fn output_types_to_result(output_types: &[InterfaceType]) -> String {
169 if output_types.is_empty() {
170 "".into()
171 } else {
172 format!(
173 "\n (result{})",
174 output_types
175 .iter()
176 .fold(String::new(), |mut accumulator, interface_type| {
177 accumulator.push(' ');
178 accumulator.push_str(&interface_type.to_string());
179 accumulator
180 })
181 )
182 }
183}
184
185impl<'input> ToString for &Type {
187 fn to_string(&self) -> String {
188 match self {
189 Type::Function { inputs, outputs } => format!(
190 r#"(@interface type (func{inputs}{outputs}))"#,
191 inputs = input_types_to_param(&inputs),
192 outputs = output_types_to_result(&outputs),
193 ),
194
195 Type::Record(record_type) => format!(
196 r#"(@interface type ({record_type}))"#,
197 record_type = record_type.to_string(),
198 ),
199 }
200 }
201}
202
203impl<'input> ToString for &Import<'input> {
205 fn to_string(&self) -> String {
206 format!(
207 r#"(@interface import "{namespace}" "{name}" (func (type {type})))"#,
208 namespace = self.namespace,
209 name = self.name,
210 type = self.signature_type,
211 )
212 }
213}
214
215impl ToString for &Adapter {
217 fn to_string(&self) -> String {
218 format!(
219 r#"(@interface func (type {function_type}){instructions})"#,
220 function_type = self.function_type,
221 instructions =
222 self.instructions
223 .iter()
224 .fold(String::new(), |mut accumulator, instruction| {
225 accumulator.push_str("\n ");
226 accumulator.push_str(&instruction.to_string());
227 accumulator
228 }),
229 )
230 }
231}
232
233impl<'input> ToString for &Export<'input> {
235 fn to_string(&self) -> String {
236 format!(
237 r#"(@interface export "{name}" (func {type}))"#,
238 name = self.name,
239 type = self.function_type,
240 )
241 }
242}
243
244impl<'input> ToString for &Implementation {
246 fn to_string(&self) -> String {
247 format!(
248 r#"(@interface implement (func {core_function_type}) (func {adapter_function_type}))"#,
249 core_function_type = self.core_function_type,
250 adapter_function_type = self.adapter_function_type,
251 )
252 }
253}
254
255impl<'input> ToString for &Interfaces<'input> {
257 fn to_string(&self) -> String {
258 let mut output = String::new();
259
260 let types = self
261 .types
262 .iter()
263 .fold(String::new(), |mut accumulator, ty| {
264 accumulator.push('\n');
265 accumulator.push_str(&ty.to_string());
266 accumulator
267 });
268
269 let imports = self
270 .imports
271 .iter()
272 .fold(String::new(), |mut accumulator, import| {
273 accumulator.push('\n');
274 accumulator.push_str(&import.to_string());
275 accumulator
276 });
277
278 let adapters = self
279 .adapters
280 .iter()
281 .fold(String::new(), |mut accumulator, adapter| {
282 accumulator.push('\n');
283 accumulator.push_str(&adapter.to_string());
284 accumulator
285 });
286
287 let exports = self
288 .exports
289 .iter()
290 .fold(String::new(), |mut accumulator, export| {
291 accumulator.push('\n');
292 accumulator.push_str(&export.to_string());
293 accumulator
294 });
295
296 let implementations =
297 self.implementations
298 .iter()
299 .fold(String::new(), |mut accumulator, implementation| {
300 accumulator.push('\n');
301 accumulator.push_str(&implementation.to_string());
302 accumulator
303 });
304
305 let separator = |output: &mut String| {
306 if !output.is_empty() {
307 output.push_str("\n\n");
308 }
309 };
310
311 if !types.is_empty() {
312 output.push_str(";; Types");
313 output.push_str(&types);
314 }
315
316 separator(&mut output);
317
318 if !imports.is_empty() {
319 output.push_str(";; Imports");
320 output.push_str(&imports);
321 }
322
323 separator(&mut output);
324
325 if !adapters.is_empty() {
326 output.push_str(";; Adapters");
327 output.push_str(&adapters);
328 }
329
330 separator(&mut output);
331
332 if !exports.is_empty() {
333 output.push_str(";; Exports");
334 output.push_str(&exports);
335 }
336
337 separator(&mut output);
338
339 if !implementations.is_empty() {
340 output.push_str(";; Implementations");
341 output.push_str(&implementations);
342 }
343
344 output
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use super::*;
351
352 #[test]
353 fn test_interface_types() {
354 let inputs: Vec<String> = vec![
355 (&InterfaceType::S8).to_string(),
356 (&InterfaceType::S16).to_string(),
357 (&InterfaceType::S32).to_string(),
358 (&InterfaceType::S64).to_string(),
359 (&InterfaceType::U8).to_string(),
360 (&InterfaceType::U16).to_string(),
361 (&InterfaceType::U32).to_string(),
362 (&InterfaceType::U64).to_string(),
363 (&InterfaceType::F32).to_string(),
364 (&InterfaceType::F64).to_string(),
365 (&InterfaceType::String).to_string(),
366 (&InterfaceType::Anyref).to_string(),
367 (&InterfaceType::I32).to_string(),
368 (&InterfaceType::I64).to_string(),
369 (&InterfaceType::Record(RecordType {
370 fields: vec1![InterfaceType::String],
371 }))
372 .to_string(),
373 ];
374 let outputs = vec![
375 "s8",
376 "s16",
377 "s32",
378 "s64",
379 "u8",
380 "u16",
381 "u32",
382 "u64",
383 "f32",
384 "f64",
385 "string",
386 "anyref",
387 "i32",
388 "i64",
389 "record (field string)",
390 ];
391
392 assert_eq!(inputs, outputs);
393 }
394
395 #[test]
396 fn test_record_type() {
397 let inputs = vec![
398 (&RecordType {
399 fields: vec1![InterfaceType::String],
400 })
401 .to_string(),
402 (&RecordType {
403 fields: vec1![InterfaceType::String, InterfaceType::I32],
404 })
405 .to_string(),
406 (&RecordType {
407 fields: vec1![
408 InterfaceType::String,
409 InterfaceType::Record(RecordType {
410 fields: vec1![InterfaceType::I32, InterfaceType::I32],
411 }),
412 InterfaceType::F64,
413 ],
414 })
415 .to_string(),
416 ];
417 let outputs = vec![
418 "record (field string)",
419 "record (field string) (field i32)",
420 "record (field string) (field record (field i32) (field i32)) (field f64)",
421 ];
422
423 assert_eq!(inputs, outputs);
424 }
425
426 #[test]
427 fn test_instructions() {
428 let inputs: Vec<String> = vec![
429 (&Instruction::ArgumentGet { index: 7 }).to_string(),
430 (&Instruction::CallCore { function_index: 7 }).to_string(),
431 (&Instruction::S8FromI32).to_string(),
432 (&Instruction::S8FromI64).to_string(),
433 (&Instruction::S16FromI32).to_string(),
434 (&Instruction::S16FromI64).to_string(),
435 (&Instruction::S32FromI32).to_string(),
436 (&Instruction::S32FromI64).to_string(),
437 (&Instruction::S64FromI32).to_string(),
438 (&Instruction::S64FromI64).to_string(),
439 (&Instruction::I32FromS8).to_string(),
440 (&Instruction::I32FromS16).to_string(),
441 (&Instruction::I32FromS32).to_string(),
442 (&Instruction::I32FromS64).to_string(),
443 (&Instruction::I64FromS8).to_string(),
444 (&Instruction::I64FromS16).to_string(),
445 (&Instruction::I64FromS32).to_string(),
446 (&Instruction::I64FromS64).to_string(),
447 (&Instruction::U8FromI32).to_string(),
448 (&Instruction::U8FromI64).to_string(),
449 (&Instruction::U16FromI32).to_string(),
450 (&Instruction::U16FromI64).to_string(),
451 (&Instruction::U32FromI32).to_string(),
452 (&Instruction::U32FromI64).to_string(),
453 (&Instruction::U64FromI32).to_string(),
454 (&Instruction::U64FromI64).to_string(),
455 (&Instruction::I32FromU8).to_string(),
456 (&Instruction::I32FromU16).to_string(),
457 (&Instruction::I32FromU32).to_string(),
458 (&Instruction::I32FromU64).to_string(),
459 (&Instruction::I64FromU8).to_string(),
460 (&Instruction::I64FromU16).to_string(),
461 (&Instruction::I64FromU32).to_string(),
462 (&Instruction::I64FromU64).to_string(),
463 (&Instruction::StringLiftMemory).to_string(),
464 (&Instruction::StringLowerMemory).to_string(),
465 (&Instruction::StringSize).to_string(),
466 (&Instruction::RecordLift { type_index: 42 }).to_string(),
467 (&Instruction::RecordLower { type_index: 42 }).to_string(),
468 ];
469 let outputs = vec![
470 "arg.get 7",
471 "call-core 7",
472 "s8.from_i32",
473 "s8.from_i64",
474 "s16.from_i32",
475 "s16.from_i64",
476 "s32.from_i32",
477 "s32.from_i64",
478 "s64.from_i32",
479 "s64.from_i64",
480 "i32.from_s8",
481 "i32.from_s16",
482 "i32.from_s32",
483 "i32.from_s64",
484 "i64.from_s8",
485 "i64.from_s16",
486 "i64.from_s32",
487 "i64.from_s64",
488 "u8.from_i32",
489 "u8.from_i64",
490 "u16.from_i32",
491 "u16.from_i64",
492 "u32.from_i32",
493 "u32.from_i64",
494 "u64.from_i32",
495 "u64.from_i64",
496 "i32.from_u8",
497 "i32.from_u16",
498 "i32.from_u32",
499 "i32.from_u64",
500 "i64.from_u8",
501 "i64.from_u16",
502 "i64.from_u32",
503 "i64.from_u64",
504 "string.lift_memory",
505 "string.lower_memory",
506 "string.size",
507 "record.lift 42",
508 "record.lower 42",
509 ];
510
511 assert_eq!(inputs, outputs);
512 }
513
514 #[test]
515 fn test_types() {
516 let inputs: Vec<String> = vec![
517 (&Type::Function {
518 inputs: vec![InterfaceType::I32, InterfaceType::F32],
519 outputs: vec![InterfaceType::I32],
520 })
521 .to_string(),
522 (&Type::Function {
523 inputs: vec![InterfaceType::I32],
524 outputs: vec![],
525 })
526 .to_string(),
527 (&Type::Function {
528 inputs: vec![],
529 outputs: vec![InterfaceType::I32],
530 })
531 .to_string(),
532 (&Type::Function {
533 inputs: vec![],
534 outputs: vec![],
535 })
536 .to_string(),
537 (&Type::Record(RecordType {
538 fields: vec1![InterfaceType::String, InterfaceType::I32],
539 }))
540 .to_string(),
541 ];
542 let outputs = vec![
543 r#"(@interface type (func
544 (param i32 f32)
545 (result i32)))"#,
546 r#"(@interface type (func
547 (param i32)))"#,
548 r#"(@interface type (func
549 (result i32)))"#,
550 r#"(@interface type (func))"#,
551 r#"(@interface type (record (field string) (field i32)))"#,
552 ];
553
554 assert_eq!(inputs, outputs);
555 }
556
557 #[test]
558 fn test_exports() {
559 let input = (&Export {
560 name: "foo",
561 function_type: 0,
562 })
563 .to_string();
564 let output = r#"(@interface export "foo" (func 0))"#;
565
566 assert_eq!(input, output);
567 }
568
569 #[test]
570 fn test_imports() {
571 let input = (&Import {
572 namespace: "ns",
573 name: "foo",
574 signature_type: 0,
575 })
576 .to_string();
577 let output = r#"(@interface import "ns" "foo" (func (type 0)))"#;
578
579 assert_eq!(input, output);
580 }
581
582 #[test]
583 fn test_adapter() {
584 let input = (&Adapter {
585 function_type: 0,
586 instructions: vec![Instruction::ArgumentGet { index: 42 }],
587 })
588 .to_string();
589 let output = r#"(@interface func (type 0)
590 arg.get 42)"#;
591
592 assert_eq!(input, output);
593 }
594
595 #[test]
596 fn test_interfaces() {
597 let input: String = (&Interfaces {
598 types: vec![Type::Function {
599 inputs: vec![InterfaceType::I32],
600 outputs: vec![InterfaceType::S8],
601 }],
602 imports: vec![Import {
603 namespace: "ns",
604 name: "foo",
605 signature_type: 0,
606 }],
607 adapters: vec![Adapter {
608 function_type: 0,
609 instructions: vec![Instruction::ArgumentGet { index: 42 }],
610 }],
611 exports: vec![Export {
612 name: "bar",
613 function_type: 0,
614 }],
615 implementations: vec![Implementation {
616 core_function_type: 0,
617 adapter_function_type: 1,
618 }],
619 })
620 .to_string();
621 let output = r#";; Types
622(@interface type (func
623 (param i32)
624 (result s8)))
625
626;; Imports
627(@interface import "ns" "foo" (func (type 0)))
628
629;; Adapters
630(@interface func (type 0)
631 arg.get 42)
632
633;; Exports
634(@interface export "bar" (func 0))
635
636;; Implementations
637(@interface implement (func 0) (func 1))"#;
638
639 assert_eq!(input, output);
640 }
641}