Add indentation to Luau output

This commit is contained in:
Rerumu 2022-08-21 02:06:56 -04:00
parent 7efeffeac6
commit 5b96c500df
5 changed files with 206 additions and 130 deletions

View File

@ -16,11 +16,11 @@ macro_rules! impl_write_number {
($name:tt, $numeric:ty) => { ($name:tt, $numeric:ty) => {
fn $name(number: $numeric, w: &mut dyn Write) -> Result<()> { fn $name(number: $numeric, w: &mut dyn Write) -> Result<()> {
match (number.classify(), number.is_sign_negative()) { match (number.classify(), number.is_sign_negative()) {
(FpCategory::Nan, true) => write!(w, "(0.0 / 0.0) "), (FpCategory::Nan, true) => write!(w, "(0.0 / 0.0)"),
(FpCategory::Nan, false) => write!(w, "-(0.0 / 0.0) "), (FpCategory::Nan, false) => write!(w, "-(0.0 / 0.0)"),
(FpCategory::Infinite, true) => write!(w, "-math.huge "), (FpCategory::Infinite, true) => write!(w, "-math.huge"),
(FpCategory::Infinite, false) => write!(w, "math.huge "), (FpCategory::Infinite, false) => write!(w, "math.huge"),
_ => write!(w, "{number:e} "), _ => write!(w, "{number:e}"),
} }
} }
}; };
@ -30,9 +30,9 @@ impl DriverNoContext for Select {
fn write(&self, w: &mut dyn Write) -> Result<()> { fn write(&self, w: &mut dyn Write) -> Result<()> {
write!(w, "(")?; write!(w, "(")?;
Condition(self.condition()).write(w)?; Condition(self.condition()).write(w)?;
write!(w, "and ")?; write!(w, " and ")?;
self.on_true().write(w)?; self.on_true().write(w)?;
write!(w, "or ")?; write!(w, " or ")?;
self.on_false().write(w)?; self.on_false().write(w)?;
write!(w, ")") write!(w, ")")
} }
@ -40,19 +40,19 @@ impl DriverNoContext for Select {
impl DriverNoContext for GetTemporary { impl DriverNoContext for GetTemporary {
fn write(&self, w: &mut dyn Write) -> Result<()> { fn write(&self, w: &mut dyn Write) -> Result<()> {
write!(w, "reg_{} ", self.var()) write!(w, "reg_{}", self.var())
} }
} }
impl DriverNoContext for GetLocal { impl DriverNoContext for GetLocal {
fn write(&self, w: &mut dyn Write) -> Result<()> { fn write(&self, w: &mut dyn Write) -> Result<()> {
write!(w, "loc_{} ", self.var()) write!(w, "loc_{}", self.var())
} }
} }
impl DriverNoContext for GetGlobal { impl DriverNoContext for GetGlobal {
fn write(&self, w: &mut dyn Write) -> Result<()> { fn write(&self, w: &mut dyn Write) -> Result<()> {
write!(w, "GLOBAL_LIST[{}].value ", self.var()) write!(w, "GLOBAL_LIST[{}].value", self.var())
} }
} }
@ -62,7 +62,7 @@ impl DriverNoContext for LoadAt {
self.pointer().write(w)?; self.pointer().write(w)?;
if self.offset() != 0 { if self.offset() != 0 {
write!(w, "+ {}", self.offset())?; write!(w, " + {}", self.offset())?;
} }
write!(w, ")") write!(w, ")")
@ -71,26 +71,26 @@ impl DriverNoContext for LoadAt {
impl DriverNoContext for MemorySize { impl DriverNoContext for MemorySize {
fn write(&self, w: &mut dyn Write) -> Result<()> { fn write(&self, w: &mut dyn Write) -> Result<()> {
write!(w, "memory_at_{}.min ", self.memory()) write!(w, "memory_at_{}.min", self.memory())
} }
} }
pub fn write_i32(number: i32, w: &mut dyn Write) -> Result<()> { pub fn write_i32(number: i32, w: &mut dyn Write) -> Result<()> {
let list = number.to_ne_bytes(); let list = number.to_ne_bytes();
write!(w, "{} ", u32::from_ne_bytes(list)) write!(w, "{}", u32::from_ne_bytes(list))
} }
fn write_i64(number: i64, w: &mut dyn Write) -> Result<()> { fn write_i64(number: i64, w: &mut dyn Write) -> Result<()> {
match number { match number {
0 => write!(w, "i64_ZERO "), 0 => write!(w, "i64_ZERO"),
1 => write!(w, "i64_ONE "), 1 => write!(w, "i64_ONE"),
_ => { _ => {
let list = number.to_ne_bytes(); let list = number.to_ne_bytes();
let a = u32::from_ne_bytes(list[0..4].try_into().unwrap()); let a = u32::from_ne_bytes(list[0..4].try_into().unwrap());
let b = u32::from_ne_bytes(list[4..8].try_into().unwrap()); let b = u32::from_ne_bytes(list[4..8].try_into().unwrap());
write!(w, "i64_from_u32({a}, {b}) ") write!(w, "i64_from_u32({a}, {b})")
} }
} }
} }
@ -124,7 +124,7 @@ impl DriverNoContext for BinOp {
if let Some(symbol) = self.op_type().as_symbol() { if let Some(symbol) = self.op_type().as_symbol() {
write!(w, "(")?; write!(w, "(")?;
self.lhs().write(w)?; self.lhs().write(w)?;
write!(w, "{symbol} ")?; write!(w, " {symbol} ")?;
self.rhs().write(w)?; self.rhs().write(w)?;
write!(w, ")") write!(w, ")")
} else { } else {
@ -147,7 +147,7 @@ impl DriverNoContext for CmpOpBoolean<'_> {
if let Some(symbol) = cmp.op_type().as_symbol() { if let Some(symbol) = cmp.op_type().as_symbol() {
cmp.lhs().write(w)?; cmp.lhs().write(w)?;
write!(w, "{symbol} ")?; write!(w, " {symbol} ")?;
cmp.rhs().write(w) cmp.rhs().write(w)
} else { } else {
let (head, tail) = cmp.op_type().as_name(); let (head, tail) = cmp.op_type().as_name();
@ -165,7 +165,7 @@ impl DriverNoContext for CmpOp {
fn write(&self, w: &mut dyn Write) -> Result<()> { fn write(&self, w: &mut dyn Write) -> Result<()> {
write!(w, "(")?; write!(w, "(")?;
CmpOpBoolean(self).write(w)?; CmpOpBoolean(self).write(w)?;
write!(w, "and 1 or 0)") write!(w, " and 1 or 0)")
} }
} }
@ -177,7 +177,7 @@ impl DriverNoContext for Condition<'_> {
CmpOpBoolean(node).write(w) CmpOpBoolean(node).write(w)
} else { } else {
self.0.write(w)?; self.0.write(w)?;
write!(w, "~= 0 ") write!(w, " ~= 0")
} }
} }
} }

View File

@ -6,10 +6,36 @@ use std::{
use wasm_ast::node::{BrTable, LabelType}; use wasm_ast::node::{BrTable, LabelType};
#[macro_export]
macro_rules! indentation {
($mng:tt, $w:tt) => {{
let mut iter = 0..$mng.indentation();
iter.try_for_each(|_| write!($w, "\t"))
}};
}
#[macro_export]
macro_rules! indented {
($mng:tt, $w:tt, $($args:tt)*) => {{
indentation!($mng, $w)?;
write!($w, $($args)*)
}};
}
#[macro_export]
macro_rules! line {
($mng:tt, $w:tt, $($args:tt)*) => {{
indentation!($mng, $w)?;
writeln!($w, $($args)*)
}};
}
#[derive(Default)] #[derive(Default)]
pub struct Manager { pub struct Manager {
table_map: HashMap<usize, usize>, table_map: HashMap<usize, usize>,
label_list: Vec<Option<LabelType>>, label_list: Vec<Option<LabelType>>,
indentation: usize,
} }
impl Manager { impl Manager {
@ -34,6 +60,18 @@ impl Manager {
pub fn pop_label(&mut self) { pub fn pop_label(&mut self) {
self.label_list.pop().unwrap(); self.label_list.pop().unwrap();
} }
pub fn indentation(&self) -> usize {
self.indentation
}
pub fn indent(&mut self) {
self.indentation += 1;
}
pub fn dedent(&mut self) {
self.indentation -= 1;
}
} }
pub trait Driver { pub trait Driver {

View File

@ -9,7 +9,7 @@ use wasm_ast::node::{
}; };
use wasmparser::ValType; use wasmparser::ValType;
use crate::analyzer::br_target; use crate::{analyzer::br_target, indentation, indented, line};
use super::{ use super::{
expression::Condition, expression::Condition,
@ -19,23 +19,24 @@ use super::{
impl Driver for Br { impl Driver for Br {
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
if !self.align().is_aligned() { if !self.align().is_aligned() {
indentation!(mng, w)?;
write_ascending("reg", self.align().new_range(), w)?; write_ascending("reg", self.align().new_range(), w)?;
write!(w, " = ")?; write!(w, " = ")?;
write_ascending("reg", self.align().old_range(), w)?; write_ascending("reg", self.align().old_range(), w)?;
write!(w, " ")?; writeln!(w)?;
} }
if self.target() == 0 { if self.target() == 0 {
if let Some(Some(LabelType::Backward)) = mng.label_list().last() { if let Some(Some(LabelType::Backward)) = mng.label_list().last() {
write!(w, "continue ") line!(mng, w, "continue")
} else { } else {
write!(w, "break ") line!(mng, w, "break")
} }
} else { } else {
let level = mng.label_list().len() - 1 - self.target(); let level = mng.label_list().len() - 1 - self.target();
write!(w, "desired = {level} ")?; line!(mng, w, "desired = {level}")?;
write!(w, "break ") line!(mng, w, "break")
} }
} }
} }
@ -62,39 +63,51 @@ fn write_search_layer(
let br = list[center]; let br = list[center];
if range.start != center { if range.start != center {
write!(w, "if temp < {} then ", br.target())?; line!(mng, w, "if temp < {} then", br.target())?;
mng.indent();
write_search_layer(range.start..center, list, mng, w)?; write_search_layer(range.start..center, list, mng, w)?;
write!(w, "else")?; mng.dedent();
indented!(mng, w, "else")?;
} }
if range.end != center + 1 { if range.end != center + 1 {
write!(w, "if temp > {} then ", br.target())?; writeln!(w, "if temp > {} then", br.target())?;
mng.indent();
write_search_layer(center + 1..range.end, list, mng, w)?; write_search_layer(center + 1..range.end, list, mng, w)?;
write!(w, "else")?; mng.dedent();
indented!(mng, w, "else")?;
} }
write!(w, " ")?; writeln!(w)?;
mng.indent();
br.write(mng, w)?; br.write(mng, w)?;
write!(w, "end ") mng.dedent();
line!(mng, w, "end")
} }
fn write_table_setup(table: &BrTable, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write_table_setup(table: &BrTable, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
let id = mng.get_table_index(table); let id = mng.get_table_index(table);
write!(w, "if not br_map[{id}] then ")?; line!(mng, w, "if not br_map[{id}] then")?;
write!(w, "br_map[{id}] = (function() return {{[0] =")?; mng.indent();
line!(mng, w, "br_map[{id}] = (function()")?;
mng.indent();
indented!(mng, w, "return {{ [0] = ")?;
table table
.data() .data()
.iter() .iter()
.try_for_each(|v| write!(w, "{},", v.target()))?; .try_for_each(|v| write!(w, "{}, ", v.target()))?;
write!(w, "}} end)()")?; writeln!(w, "}}")?;
write!(w, "end ")?; mng.dedent();
line!(mng, w, "end)()")?;
mng.dedent();
line!(mng, w, "end")?;
write!(w, "local temp = br_map[{id}][")?; indented!(mng, w, "temp = br_map[{id}][")?;
table.condition().write(w)?; table.condition().write(w)?;
write!(w, "] or {} ", table.default().target()) writeln!(w, "] or {}", table.default().target())
} }
impl Driver for BrTable { impl Driver for BrTable {
@ -119,82 +132,94 @@ impl Driver for BrTable {
impl Driver for Terminator { impl Driver for Terminator {
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
match self { match self {
Self::Unreachable => write!(w, "error(\"out of code bounds\")"), Self::Unreachable => line!(mng, w, r#"error("out of code bounds")"#),
Self::Br(s) => s.write(mng, w), Self::Br(s) => s.write(mng, w),
Self::BrTable(s) => s.write(mng, w), Self::BrTable(s) => s.write(mng, w),
} }
} }
} }
fn write_br_parent(label_list: &[Option<LabelType>], w: &mut dyn Write) -> Result<()> { fn write_br_parent(mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
if label_list.iter().all(Option::is_none) { if mng.label_list().iter().all(Option::is_none) {
return Ok(()); return Ok(());
} }
write!(w, "if desired then ")?; line!(mng, w, "if desired then")?;
mng.indent();
if let Some(last) = label_list.last().unwrap() { if let Some(last) = *mng.label_list().last().unwrap() {
let level = label_list.len() - 1; let level = mng.label_list().len() - 1;
write!(w, "if desired == {level} then ")?; line!(mng, w, "if desired == {level} then")?;
write!(w, "desired = nil ")?; mng.indent();
line!(mng, w, "desired = nil")?;
if *last == LabelType::Backward { if last == LabelType::Backward {
write!(w, "continue ")?; line!(mng, w, "continue")?;
} }
write!(w, "end ")?; mng.dedent();
line!(mng, w, "end")?;
} }
write!(w, "break ")?; line!(mng, w, "break")?;
write!(w, "end ")
mng.dedent();
line!(mng, w, "end")
} }
impl Driver for Block { impl Driver for Block {
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
mng.push_label(self.label_type()); mng.push_label(self.label_type());
write!(w, "while true do ")?; line!(mng, w, "while true do")?;
mng.indent();
self.code().iter().try_for_each(|s| s.write(mng, w))?; self.code().iter().try_for_each(|s| s.write(mng, w))?;
match self.last() { match self.last() {
Some(v) => v.write(mng, w)?, Some(v) => v.write(mng, w)?,
None => write!(w, "break ")?, None => line!(mng, w, "break")?,
} }
write!(w, "end ")?; mng.dedent();
line!(mng, w, "end")?;
mng.pop_label(); mng.pop_label();
write_br_parent(mng.label_list(), w) write_br_parent(mng, w)
} }
} }
impl Driver for BrIf { impl Driver for BrIf {
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
write!(w, "if ")?; indented!(mng, w, "if ")?;
Condition(self.condition()).write(w)?; Condition(self.condition()).write(w)?;
write!(w, "then ")?; writeln!(w, " then")?;
mng.indent();
self.target().write(mng, w)?; self.target().write(mng, w)?;
write!(w, "end ") mng.dedent();
line!(mng, w, "end")
} }
} }
impl Driver for If { impl Driver for If {
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
write!(w, "if ")?; indented!(mng, w, "if ")?;
Condition(self.condition()).write(w)?; Condition(self.condition()).write(w)?;
write!(w, "then ")?; writeln!(w, " then")?;
mng.indent();
self.on_true().write(mng, w)?; self.on_true().write(mng, w)?;
mng.dedent();
if let Some(v) = self.on_false() { if let Some(v) = self.on_false() {
write!(w, "else ")?; line!(mng, w, "else")?;
mng.indent();
v.write(mng, w)?; v.write(mng, w)?;
mng.dedent();
} }
write!(w, "end ") line!(mng, w, "end")
} }
} }
@ -276,19 +301,25 @@ impl DriverNoContext for MemoryGrow {
} }
} }
fn write_stat(stat: &dyn DriverNoContext, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
indentation!(mng, w)?;
stat.write(w)?;
writeln!(w)
}
impl Driver for Statement { impl Driver for Statement {
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
match self { match self {
Self::Block(s) => s.write(mng, w), Self::Block(s) => s.write(mng, w),
Self::BrIf(s) => s.write(mng, w), Self::BrIf(s) => s.write(mng, w),
Self::If(s) => s.write(mng, w), Self::If(s) => s.write(mng, w),
Self::Call(s) => s.write(w), Self::Call(s) => write_stat(s, mng, w),
Self::CallIndirect(s) => s.write(w), Self::CallIndirect(s) => write_stat(s, mng, w),
Self::SetTemporary(s) => s.write(w), Self::SetTemporary(s) => write_stat(s, mng, w),
Self::SetLocal(s) => s.write(w), Self::SetLocal(s) => write_stat(s, mng, w),
Self::SetGlobal(s) => s.write(w), Self::SetGlobal(s) => write_stat(s, mng, w),
Self::StoreAt(s) => s.write(w), Self::StoreAt(s) => write_stat(s, mng, w),
Self::MemoryGrow(s) => s.write(w), Self::MemoryGrow(s) => write_stat(s, mng, w),
} }
} }
} }
@ -296,33 +327,33 @@ impl Driver for Statement {
fn write_parameter_list(ast: &FuncData, w: &mut dyn Write) -> Result<()> { fn write_parameter_list(ast: &FuncData, w: &mut dyn Write) -> Result<()> {
write!(w, "function(")?; write!(w, "function(")?;
write_ascending("loc", 0..ast.num_param(), w)?; write_ascending("loc", 0..ast.num_param(), w)?;
write!(w, ")") writeln!(w, ")")
} }
fn write_variable_list(ast: &FuncData, w: &mut dyn Write) -> Result<()> { fn write_variable_list(ast: &FuncData, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
let mut total = ast.num_param(); let mut total = ast.num_param();
for data in ast.local_data().iter().filter(|v| v.0 != 0) { for data in ast.local_data().iter().filter(|v| v.0 != 0) {
let range = total..total + usize::try_from(data.0).unwrap(); let range = total..total + usize::try_from(data.0).unwrap();
let zero = if data.1 == ValType::I64 { let zero = if data.1 == ValType::I64 {
"i64_ZERO " "i64_ZERO"
} else { } else {
"0 " "0"
}; };
total = range.end; total = range.end;
write!(w, "local ")?; indented!(mng, w, "local ")?;
write_ascending("loc", range.clone(), w)?; write_ascending("loc", range.clone(), w)?;
write!(w, " = ")?; write!(w, " = ")?;
write_separated(range, |_, w| w.write_all(zero.as_bytes()), w)?; write_separated(range, |_, w| w.write_all(zero.as_bytes()), w)?;
write!(w, " ")?; writeln!(w)?;
} }
if ast.num_stack() != 0 { if ast.num_stack() != 0 {
write!(w, "local ")?; indented!(mng, w, "local ")?;
write_ascending("reg", 0..ast.num_stack(), w)?; write_ascending("reg", 0..ast.num_stack(), w)?;
write!(w, " ")?; writeln!(w)?;
} }
Ok(()) Ok(())
@ -332,26 +363,30 @@ impl Driver for FuncData {
fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
let br_data = br_target::visit(self); let br_data = br_target::visit(self);
mng.indent();
write_parameter_list(self, w)?; write_parameter_list(self, w)?;
write_variable_list(self, w)?; write_variable_list(self, mng, w)?;
if br_data.1 { if br_data.1 {
write!(w, "local desired ")?; line!(mng, w, "local desired")?;
} }
if !br_data.0.is_empty() { if !br_data.0.is_empty() {
write!(w, "local br_map = {{}} ")?; line!(mng, w, "local br_map = {{}}")?;
} }
mng.set_table_map(br_data.0); mng.set_table_map(br_data.0);
self.code().write(mng, w)?; self.code().write(mng, w)?;
if self.num_result() != 0 { if self.num_result() != 0 {
write!(w, "return ")?; indented!(mng, w, "return ")?;
write_ascending("reg", 0..self.num_result(), w)?; write_ascending("reg", 0..self.num_result(), w)?;
write!(w, " ")?; writeln!(w)?;
} }
write!(w, "end ") mng.dedent();
line!(mng, w, "end")
} }
} }

View File

@ -46,7 +46,7 @@ fn write_named_array(name: &str, len: usize, w: &mut dyn Write) -> Result<()> {
None => return Ok(()), None => return Ok(()),
}; };
write!(w, "local {name} = table.create({len})") writeln!(w, "local {name} = table.create({len})")
} }
fn write_constant(init: &InitExpr, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> { fn write_constant(init: &InitExpr, type_info: &TypeInfo, w: &mut dyn Write) -> Result<()> {
@ -56,7 +56,7 @@ fn write_constant(init: &InitExpr, type_info: &TypeInfo, w: &mut dyn Write) -> R
if let Some(Statement::SetTemporary(stat)) = func.code().code().last() { if let Some(Statement::SetTemporary(stat)) = func.code().code().last() {
stat.value().write(w) stat.value().write(w)
} else { } else {
write!(w, r#"error("Valueless constant")"#) writeln!(w, r#"error("Valueless constant")"#)
} }
} }
@ -69,7 +69,8 @@ fn write_import_of(list: &[Import], wanted: External, w: &mut dyn Write) -> Resu
.filter(|v| External::from(v.ty) == wanted) .filter(|v| External::from(v.ty) == wanted)
.enumerate() .enumerate()
{ {
write!(w, r#"{upper}[{i}] = wasm["{module}"].{lower}["{name}"]"#)?; write!(w, "\t")?;
writeln!(w, r#"{upper}[{i}] = wasm["{module}"].{lower}["{name}"]"#)?;
} }
Ok(()) Ok(())
@ -79,13 +80,14 @@ fn write_export_of(list: &[Export], wanted: External, w: &mut dyn Write) -> Resu
let lower = wanted.as_ie_name(); let lower = wanted.as_ie_name();
let upper = lower.to_uppercase(); let upper = lower.to_uppercase();
write!(w, "{lower} = {{")?; writeln!(w, "\t\t{lower} = {{")?;
for Export { name, index, .. } in list.iter().filter(|v| External::from(v.kind) == wanted) { for Export { name, index, .. } in list.iter().filter(|v| External::from(v.kind) == wanted) {
write!(w, r#"["{name}"] = {upper}[{index}],"#)?; write!(w, "\t\t\t")?;
writeln!(w, r#"["{name}"] = {upper}[{index}],"#)?;
} }
write!(w, "}},") writeln!(w, "\t\t}},")
} }
fn write_import_list(list: &[Import], w: &mut dyn Write) -> Result<()> { fn write_import_list(list: &[Import], w: &mut dyn Write) -> Result<()> {
@ -111,9 +113,9 @@ fn write_table_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
let min = table.initial; let min = table.initial;
let max = table.maximum.unwrap_or(0xFFFF); let max = table.maximum.unwrap_or(0xFFFF);
write!( writeln!(
w, w,
"TABLE_LIST[{index}] = {{ min = {min}, max = {max}, data = {{}} }}" "\tTABLE_LIST[{index}] = {{ min = {min}, max = {max}, data = {{}} }}"
)?; )?;
} }
@ -129,7 +131,7 @@ fn write_memory_list(wasm: &Module, w: &mut dyn Write) -> Result<()> {
let min = ty.initial; let min = ty.initial;
let max = ty.maximum.unwrap_or(0xFFFF); let max = ty.maximum.unwrap_or(0xFFFF);
write!(w, "MEMORY_LIST[{index}] = rt.allocator.new({min}, {max})")?; writeln!(w, "\tMEMORY_LIST[{index}] = rt.allocator.new({min}, {max})")?;
} }
Ok(()) Ok(())
@ -142,9 +144,9 @@ fn write_global_list(wasm: &Module, type_info: &TypeInfo, w: &mut dyn Write) ->
for (i, global) in global.iter().enumerate() { for (i, global) in global.iter().enumerate() {
let index = offset + i; let index = offset + i;
write!(w, "GLOBAL_LIST[{index}] = {{ value =")?; write!(w, "\tGLOBAL_LIST[{index}] = {{ value = ")?;
write_constant(&global.init_expr, type_info, w)?; write_constant(&global.init_expr, type_info, w)?;
write!(w, "}}")?; writeln!(w, " }}")?;
} }
Ok(()) Ok(())
@ -160,13 +162,14 @@ fn write_element_list(list: &[Element], type_info: &TypeInfo, w: &mut dyn Write)
_ => unimplemented!(), _ => unimplemented!(),
}; };
write!(w, "do ")?; writeln!(w, "\tdo")?;
write!(w, "local target = TABLE_LIST[{index}].data ")?; writeln!(w, "\t\tlocal target = TABLE_LIST[{index}].data")?;
write!(w, "local offset =")?; write!(w, "\t\tlocal offset = ")?;
write_constant(&init, type_info, w)?; write_constant(&init, type_info, w)?;
write!(w, "local data = {{")?; writeln!(w)?;
write!(w, "\t\tlocal data = {{ ")?;
for item in element.items.get_items_reader().unwrap() { for item in element.items.get_items_reader().unwrap() {
match item.unwrap() { match item.unwrap() {
@ -175,11 +178,9 @@ fn write_element_list(list: &[Element], type_info: &TypeInfo, w: &mut dyn Write)
}?; }?;
} }
write!(w, "}}")?; writeln!(w, " }}")?;
writeln!(w, "\t\ttable.move(data, 1, #data, offset, target)")?;
write!(w, "table.move(data, 1, #data, offset, target)")?; writeln!(w, "\tend")?;
write!(w, "end ")?;
} }
Ok(()) Ok(())
@ -195,10 +196,9 @@ fn write_data_list(list: &[Data], type_info: &TypeInfo, w: &mut dyn Write) -> Re
} => (memory_index, init_expr), } => (memory_index, init_expr),
}; };
write!(w, "rt.store.string(")?; write!(w, "\trt.store.string(MEMORY_LIST[{index}], ")?;
write!(w, "MEMORY_LIST[{index}],")?;
write_constant(&init, type_info, w)?; write_constant(&init, type_info, w)?;
write!(w, r#","{}")"#, data.data.escape_ascii())?; writeln!(w, r#","{}")"#, data.data.escape_ascii())?;
} }
Ok(()) Ok(())
@ -219,12 +219,14 @@ fn write_local_operation(head: &str, tail: &str, w: &mut dyn Write) -> Result<()
write!(w, "local {head}_{tail} = ")?; write!(w, "local {head}_{tail} = ")?;
match (head, tail) { match (head, tail) {
("abs" | "ceil" | "floor" | "sqrt", _) => write!(w, "math.{head} "), ("abs" | "ceil" | "floor" | "sqrt", _) => write!(w, "math.{head}"),
("band" | "bor" | "bxor" | "bnot", "i32") => write!(w, "bit32.{head} "), ("band" | "bor" | "bxor" | "bnot", "i32") => write!(w, "bit32.{head}"),
("clz", "i32") => write!(w, "bit32.countlz "), ("clz", "i32") => write!(w, "bit32.countlz"),
("ctz", "i32") => write!(w, "bit32.countrz "), ("ctz", "i32") => write!(w, "bit32.countrz"),
_ => write!(w, "rt.{head}.{tail} "), _ => write!(w, "rt.{head}.{tail}"),
} }?;
writeln!(w)
} }
fn write_localize_used( fn write_localize_used(
@ -258,17 +260,17 @@ fn write_localize_used(
} }
for mem in &mem_set { for mem in &mem_set {
write!(w, "local memory_at_{mem} ")?; writeln!(w, "local memory_at_{mem}")?;
} }
Ok(mem_set) Ok(mem_set)
} }
fn write_func_start(wasm: &Module, index: u32, w: &mut dyn Write) -> Result<()> { fn write_func_start(wasm: &Module, index: u32, w: &mut dyn Write) -> Result<()> {
write!(w, "FUNC_LIST[{index}] =")?; write!(w, "FUNC_LIST[{index}] = ")?;
match wasm.name_section().get(&index) { match wasm.name_section().get(&index) {
Some(name) => write!(w, "--[[ {name} ]]"), Some(name) => write!(w, "--[[ {name} ]] "),
None => Ok(()), None => Ok(()),
} }
} }
@ -291,29 +293,30 @@ fn write_module_start(
mem_set: &BTreeSet<usize>, mem_set: &BTreeSet<usize>,
w: &mut dyn Write, w: &mut dyn Write,
) -> Result<()> { ) -> Result<()> {
write!(w, "local function run_init_code()")?; writeln!(w, "local function run_init_code()")?;
write_table_list(wasm, w)?; write_table_list(wasm, w)?;
write_memory_list(wasm, w)?; write_memory_list(wasm, w)?;
write_global_list(wasm, type_info, w)?; write_global_list(wasm, type_info, w)?;
write_element_list(wasm.element_section(), type_info, w)?; write_element_list(wasm.element_section(), type_info, w)?;
write_data_list(wasm.data_section(), type_info, w)?; write_data_list(wasm.data_section(), type_info, w)?;
write!(w, "end ")?; writeln!(w, "end")?;
write!(w, "return function(wasm)")?; writeln!(w, "return function(wasm)")?;
write_import_list(wasm.import_section(), w)?; write_import_list(wasm.import_section(), w)?;
write!(w, "run_init_code()")?; writeln!(w, "\trun_init_code()")?;
for mem in mem_set { for mem in mem_set {
write!(w, "memory_at_{mem} = MEMORY_LIST[{mem}]")?; writeln!(w, "\tmemory_at_{mem} = MEMORY_LIST[{mem}]")?;
} }
if let Some(start) = wasm.start_section() { if let Some(start) = wasm.start_section() {
write!(w, "FUNC_LIST[{start}]()")?; writeln!(w, "\tFUNC_LIST[{start}]()")?;
} }
write!(w, "return {{")?; writeln!(w, "\treturn {{")?;
write_export_list(wasm.export_section(), w)?; write_export_list(wasm.export_section(), w)?;
write!(w, "}} end ") writeln!(w, "\t}}")?;
writeln!(w, "end")
} }
/// # Errors /// # Errors

View File

@ -105,9 +105,9 @@ impl Target for Luau {
}; };
let data = Module::from_data(&bytes); let data = Module::from_data(&bytes);
write!(w, "assert_trap((function() ")?; writeln!(w, "assert_trap((function()")?;
codegen_luau::from_module_untyped(&data, w)?; codegen_luau::from_module_untyped(&data, w)?;
writeln!(w, " end)(), linked)") writeln!(w, "end)(), linked)")
} }
} }
} }
@ -154,10 +154,10 @@ impl Target for Luau {
let numeric = codegen_luau::NUMERIC; let numeric = codegen_luau::NUMERIC;
writeln!(w, "local Integer = (function()")?; writeln!(w, "local Integer = (function()")?;
writeln!(w, "{numeric}")?; write!(w, "{numeric}")?;
writeln!(w, "end)()")?; writeln!(w, "end)()")?;
writeln!(w, "local rt = (function()")?; writeln!(w, "local rt = (function()")?;
writeln!(w, "{runtime}")?; write!(w, "{runtime}")?;
writeln!(w, "end)()")?; writeln!(w, "end)()")?;
writeln!(w, "{ASSERTION}") writeln!(w, "{ASSERTION}")
@ -166,7 +166,7 @@ impl Target for Luau {
fn write_module(data: &Module, name: Option<&str>, w: &mut dyn Write) -> Result<()> { fn write_module(data: &Module, name: Option<&str>, w: &mut dyn Write) -> Result<()> {
let type_info = TypeInfo::from_module(data); let type_info = TypeInfo::from_module(data);
write!(w, r#"loaded["temp"] = (function() "#)?; writeln!(w, r#"loaded["temp"] = (function()"#)?;
codegen_luau::from_module_typed(data, &type_info, w)?; codegen_luau::from_module_typed(data, &type_info, w)?;
writeln!(w, "end)()(linked)")?; writeln!(w, "end)()(linked)")?;