Skip to content

Commit d643603

Browse files
authored
Use quoted identifiers in wasmprinter by default (#1615)
* Use quoted identifiers in `wasmprinter` by default This commit updates `wasmprinter` to use quoted identifiers of the form `$"foo"` when necessary instead of synthesizing identifiers such as `$#func4<foo>`. This helps produce more readable modules by default when names are synthesized since if a name is unique but otherwise has non-identifier characters then the quoted string form can be used. While here I've additionally changed the way that non-printable characters in strings are printed to using `\u{XXX}` syntax instead of `\NN` syntax. This makes it a bit more obvious in unicode contexts that a single character is present and not multiple. * Fix some test expectations * Migrate a number of `wasmprinter` unit tests to `tests/cli/*.wat` This makes them easier to update as the output changes over time and additionally easier to add new files here too.
1 parent 38a0b16 commit d643603

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+734
-789
lines changed

crates/wasmprinter/src/lib.rs

+63-51
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,14 @@ impl State {
147147
}
148148

149149
struct Naming {
150-
identifier: Option<String>,
151150
name: String,
151+
kind: NamingKind,
152+
}
153+
154+
enum NamingKind {
155+
DollarName,
156+
DollarQuotedName,
157+
SyntheticPrefix(String),
152158
}
153159

154160
impl Config {
@@ -410,7 +416,7 @@ impl Printer<'_, '_> {
410416
if len == 1 {
411417
if let Some(name) = state.name.as_ref() {
412418
self.result.write_str(" ")?;
413-
name.write(self.result)?;
419+
name.write(self)?;
414420
}
415421
}
416422
}
@@ -925,7 +931,10 @@ impl Printer<'_, '_> {
925931
self.result.write_str(" ")?;
926932
if let Some(idxs @ (_, field_idx)) = ty_field_idx {
927933
match state.core.field_names.index_to_name.get(&idxs) {
928-
Some(name) => write!(self.result, "${} ", name.identifier())?,
934+
Some(name) => {
935+
name.write_identifier(self)?;
936+
self.result.write_str(" ")?;
937+
}
929938
None if self.config.name_unnamed => write!(self.result, "$#field{field_idx} ")?,
930939
None => {}
931940
}
@@ -1453,7 +1462,7 @@ impl Printer<'_, '_> {
14531462
fn _print_idx(&mut self, names: &HashMap<u32, Naming>, idx: u32, desc: &str) -> Result<()> {
14541463
self.result.start_name()?;
14551464
match names.get(&idx) {
1456-
Some(name) => write!(self.result, "${}", name.identifier())?,
1465+
Some(name) => name.write_identifier(self)?,
14571466
None if self.config.name_unnamed => write!(self.result, "$#{desc}{idx}")?,
14581467
None => write!(self.result, "{idx}")?,
14591468
}
@@ -1464,7 +1473,7 @@ impl Printer<'_, '_> {
14641473
fn print_local_idx(&mut self, state: &State, func: u32, idx: u32) -> Result<()> {
14651474
self.result.start_name()?;
14661475
match state.core.local_names.index_to_name.get(&(func, idx)) {
1467-
Some(name) => write!(self.result, "${}", name.identifier())?,
1476+
Some(name) => name.write_identifier(self)?,
14681477
None if self.config.name_unnamed => write!(self.result, "$#local{idx}")?,
14691478
None => write!(self.result, "{}", idx)?,
14701479
}
@@ -1475,7 +1484,7 @@ impl Printer<'_, '_> {
14751484
fn print_field_idx(&mut self, state: &State, ty: u32, idx: u32) -> Result<()> {
14761485
self.result.start_name()?;
14771486
match state.core.field_names.index_to_name.get(&(ty, idx)) {
1478-
Some(name) => write!(self.result, "${}", name.identifier())?,
1487+
Some(name) => name.write_identifier(self)?,
14791488
None if self.config.name_unnamed => write!(self.result, "$#field{idx}")?,
14801489
None => write!(self.result, "{}", idx)?,
14811490
}
@@ -1499,7 +1508,7 @@ impl Printer<'_, '_> {
14991508
self.result.start_name()?;
15001509
match names.get(&cur_idx) {
15011510
Some(name) => {
1502-
name.write(self.result)?;
1511+
name.write(self)?;
15031512
self.result.write_str(" ")?;
15041513
}
15051514
None if self.config.name_unnamed => {
@@ -1911,7 +1920,7 @@ impl Printer<'_, '_> {
19111920
let outer = Self::outer_state(states, count)?;
19121921
self.start_group("alias outer ")?;
19131922
if let Some(name) = outer.name.as_ref() {
1914-
name.write(self.result)?;
1923+
name.write(self)?;
19151924
} else {
19161925
write!(self.result, "{count}")?;
19171926
}
@@ -2592,7 +2601,7 @@ impl Printer<'_, '_> {
25922601
let outer = Self::outer_state(states, count)?;
25932602
self.start_group("alias outer ")?;
25942603
if let Some(name) = outer.name.as_ref() {
2595-
name.write(self.result)?;
2604+
name.write(self)?;
25962605
} else {
25972606
write!(self.result, "{count}")?;
25982607
}
@@ -2643,20 +2652,22 @@ impl Printer<'_, '_> {
26432652

26442653
fn print_str(&mut self, name: &str) -> Result<()> {
26452654
self.result.start_literal()?;
2646-
let mut bytes = [0; 4];
26472655
self.result.write_str("\"")?;
2656+
self.print_str_contents(name)?;
2657+
self.result.write_str("\"")?;
2658+
self.result.reset_color()?;
2659+
Ok(())
2660+
}
2661+
2662+
fn print_str_contents(&mut self, name: &str) -> Result<()> {
26482663
for c in name.chars() {
26492664
let v = c as u32;
26502665
if (0x20..0x7f).contains(&v) && c != '"' && c != '\\' && v < 0xff {
26512666
write!(self.result, "{c}")?;
26522667
} else {
2653-
for byte in c.encode_utf8(&mut bytes).as_bytes() {
2654-
self.hex_byte(*byte)?;
2655-
}
2668+
write!(self.result, "\\u{{{v:x}}}",)?;
26562669
}
26572670
}
2658-
self.result.write_str("\"")?;
2659-
self.result.reset_color()?;
26602671
Ok(())
26612672
}
26622673

@@ -2917,7 +2928,7 @@ impl NamedLocalPrinter {
29172928
// Print the optional name if given...
29182929
match name {
29192930
Some(name) => {
2920-
name.write(dst.result)?;
2931+
name.write(dst)?;
29212932
dst.result.write_str(" ")?;
29222933
self.end_group_after_local = true;
29232934
}
@@ -3057,7 +3068,10 @@ impl Naming {
30573068
group: &str,
30583069
used: Option<&mut HashSet<&'a str>>,
30593070
) -> Naming {
3060-
let mut identifier = None;
3071+
let mut kind = NamingKind::DollarName;
3072+
if name.chars().any(|c| !is_idchar(c)) {
3073+
kind = NamingKind::DollarQuotedName;
3074+
}
30613075

30623076
// If the `name` provided can't be used as the raw identifier for the
30633077
// item that it's describing then a synthetic name must be made. The
@@ -3078,17 +3092,13 @@ impl Naming {
30783092
// valid identifier characters of `name` still appear in the returned
30793093
// name).
30803094
if name.is_empty()
3081-
|| name.chars().any(|c| !is_idchar(c))
30823095
|| name.starts_with('#')
30833096
|| used.map(|set| !set.insert(name)).unwrap_or(false)
30843097
{
3085-
let mut id = format!("#{group}{index}<");
3086-
id.extend(name.chars().map(|c| if is_idchar(c) { c } else { '_' }));
3087-
id.push('>');
3088-
identifier = Some(id);
3098+
kind = NamingKind::SyntheticPrefix(format!("#{group}{index}"));
30893099
}
30903100
return Naming {
3091-
identifier,
3101+
kind,
30923102
name: name.to_string(),
30933103
};
30943104

@@ -3126,37 +3136,39 @@ impl Naming {
31263136
}
31273137
}
31283138

3129-
fn identifier(&self) -> &str {
3130-
match &self.identifier {
3131-
Some(s) => s,
3132-
None => &self.name,
3139+
fn write_identifier(&self, printer: &mut Printer<'_, '_>) -> Result<()> {
3140+
match &self.kind {
3141+
NamingKind::DollarName => {
3142+
printer.result.write_str("$")?;
3143+
printer.result.write_str(&self.name)?;
3144+
}
3145+
NamingKind::DollarQuotedName => {
3146+
printer.result.write_str("$\"")?;
3147+
printer.print_str_contents(&self.name)?;
3148+
printer.result.write_str("\"")?;
3149+
}
3150+
NamingKind::SyntheticPrefix(prefix) => {
3151+
printer.result.write_str("$\"")?;
3152+
printer.result.write_str(&prefix)?;
3153+
printer.result.write_str(" ")?;
3154+
printer.print_str_contents(&self.name)?;
3155+
printer.result.write_str("\"")?;
3156+
}
31333157
}
3158+
Ok(())
31343159
}
31353160

3136-
fn write(&self, dst: &mut dyn Print) -> Result<()> {
3137-
match &self.identifier {
3138-
Some(alternate) => {
3139-
assert!(*alternate != self.name);
3140-
write!(dst, "${alternate} (@name \"")?;
3141-
// https://webassembly.github.io/spec/core/text/values.html#text-string
3142-
for c in self.name.chars() {
3143-
match c {
3144-
'\t' => write!(dst, "\\t")?,
3145-
'\n' => write!(dst, "\\n")?,
3146-
'\r' => write!(dst, "\\r")?,
3147-
'"' => write!(dst, "\\\"")?,
3148-
'\'' => write!(dst, "\\'")?,
3149-
'\\' => write!(dst, "\\\\")?,
3150-
c if (c as u32) < 0x20 || c as u32 == 0x7f => {
3151-
write!(dst, "\\u{{{:x}}}", c as u32)?;
3152-
}
3153-
other => write!(dst, "{other}")?,
3154-
}
3155-
}
3156-
write!(dst, "\")")?;
3157-
}
3158-
None => {
3159-
write!(dst, "${}", self.name)?;
3161+
fn write(&self, dst: &mut Printer<'_, '_>) -> Result<()> {
3162+
self.write_identifier(dst)?;
3163+
match &self.kind {
3164+
NamingKind::DollarName | NamingKind::DollarQuotedName => {}
3165+
3166+
NamingKind::SyntheticPrefix(_) => {
3167+
dst.result.write_str(" ")?;
3168+
dst.start_group("@name \"")?;
3169+
dst.print_str_contents(&self.name)?;
3170+
dst.result.write_str("\"")?;
3171+
dst.end_group()?;
31603172
}
31613173
}
31623174
Ok(())

crates/wasmprinter/src/operator.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl<'printer, 'state, 'a, 'b> PrintOperator<'printer, 'state, 'a, 'b> {
8686
let has_name = match self.state.core.label_names.index_to_name.get(&key) {
8787
Some(name) => {
8888
write!(self.printer.result, " ")?;
89-
name.write(self.printer.result)?;
89+
name.write(self.printer)?;
9090
true
9191
}
9292
None if self.printer.config.name_unnamed => {
@@ -176,7 +176,7 @@ impl<'printer, 'state, 'a, 'b> PrintOperator<'printer, 'state, 'a, 'b> {
176176
match name {
177177
// Only print the name if one is found and there's also no
178178
// name conflict.
179-
Some(name) if !name_conflict => name.write(self.printer.result)?,
179+
Some(name) if !name_conflict => name.write(self.printer)?,
180180

181181
// If there's no name conflict, and we're synthesizing
182182
// names, and this isn't targetting the function itself then

0 commit comments

Comments
 (0)