Skip to content

Commit a1d8140

Browse files
committed
Implement basic printing strategy
1 parent 077cd66 commit a1d8140

File tree

6 files changed

+116
-17
lines changed

6 files changed

+116
-17
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ const tree = [
9292
const str = print(tree, {
9393
indent: ' ', // indentation characters
9494
newline: '\n', // new line charactes
95-
pad: 1, // pad start of each line
95+
pad: '', // pad start of each line with a string
9696
comments: true // keep comments
9797
})
9898
// (func (export "double")

src/print.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import parse from './parse.js';
2+
3+
let indent = '', newline = '\n', pad = '', comments = false, _i = 0
4+
5+
export default function print(tree, options = {}) {
6+
if (typeof tree === 'string') tree = parse(tree);
7+
8+
({ indent, newline, pad, comments } = options);
9+
newline ||= ''
10+
pad ||= ''
11+
indent ||= ''
12+
13+
let out = typeof tree[0] === 'string' ? printNode(tree) : tree.map(node => printNode(node)).join(newline)
14+
15+
return out
16+
}
17+
18+
const flats = ['param', 'local', 'global', 'result', 'export']
19+
20+
function printNode(node, level = 0) {
21+
if (!Array.isArray(node)) return node + ''
22+
23+
let content = node[0]
24+
25+
for (let i = 1; i < node.length; i++) {
26+
// new node doesn't need space separator, eg. [x,[y]] -> `x(y)`
27+
if (Array.isArray(node[i])) {
28+
// inline nodes like (param x)(param y)
29+
// (func (export "xxx")..., but not (func (export "a")(param "b")...
30+
if (
31+
flats.includes(node[i][0]) &&
32+
(!Array.isArray(node[i - 1]) || node[i][0] === node[i - 1][0])
33+
) {
34+
if (!Array.isArray(node[i - 1])) content += ` `
35+
} else {
36+
content += newline
37+
if (node[i]) content += indent.repeat(level + 1)
38+
}
39+
40+
content += printNode(node[i], level + 1)
41+
}
42+
else {
43+
content += ` `
44+
content += node[i]
45+
}
46+
}
47+
return `(${content})`
48+
}

test/compile.js

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,7 @@ t.skip('bench: brownian', async () => {
11701170
console.timeEnd('wabt')
11711171
})
11721172

1173-
async function file(path) {
1173+
export async function file(path) {
11741174
let res = await fetch(path)
11751175
let src = await res.text()
11761176
return src
@@ -1183,17 +1183,6 @@ async function runExample(path) {
11831183
// const mod = new WebAssembly.Module(buffer)
11841184
}
11851185

1186-
// stub fetch for local purpose
1187-
const isNode = typeof global !== 'undefined' && globalThis === global
1188-
if (isNode) {
1189-
let { readFileSync } = await import('fs')
1190-
globalThis.fetch = async path => {
1191-
path = `.${path}`
1192-
const data = readFileSync(path, 'utf8')
1193-
return { text() { return data } }
1194-
}
1195-
}
1196-
11971186
console.hex = (d) => console.log((Object(d).buffer instanceof ArrayBuffer ? new Uint8Array(d.buffer) :
11981187
typeof d === 'string' ? (new TextEncoder('utf-8')).encode(d) :
11991188
new Uint8ClampedArray(d)).reduce((p, c, i, a) => p + (i % 16 === 0 ? i.toString(16).padStart(6, 0) + ' ' : ' ') +
@@ -1215,7 +1204,7 @@ const hex = (str, ...fields) =>
12151204
)
12161205

12171206
// convert wast code to binary via Wabt
1218-
function wat2wasm(code, config) {
1207+
export function wat2wasm(code, config) {
12191208
let metrics = config ? config.metrics : true
12201209
const parsed = wabt.parseWat('inline', code, {})
12211210
metrics && console.time('wabt build')

test/index.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<doctype html>
22

3-
<script type="importmap">
3+
<script type="importmap">
44
{
55
"imports": {
66
"tst": "../node_modules/tst/tst.js",
@@ -10,5 +10,6 @@
1010
}
1111
</script>
1212

13-
<script src="./parse.js" type="module"></script>
14-
<script src="./compile.js" type="module"></script>
13+
<script src="./parse.js" type="module"></script>
14+
<script src="./compile.js" type="module"></script>
15+
<script src="./print.js" type="module"></script>

test/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
11
import './parse.js'
22
import './compile.js'
3+
import './print.js'
4+
5+
// stub fetch for local purpose
6+
const isNode = typeof global !== 'undefined' && globalThis === global
7+
if (isNode) {
8+
let { readFileSync } = await import('fs')
9+
globalThis.fetch = async path => {
10+
path = `.${path}`
11+
const data = readFileSync(path, 'utf8')
12+
return { text() { return data } }
13+
}
14+
}

test/print.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import t, { is, ok, same } from 'tst'
2+
import print from '../src/print.js'
3+
import { wat2wasm, file } from './compile.js'
4+
5+
t.only('print: basics', () => {
6+
const tree = [
7+
'func', ['export', '"double"'], ['param', 'f64', 'f32'], ['param', '$x', 'i32'], ['result', 'f64'],
8+
['f64.mul', ['local.get', 0], ['f64.const', 2]]
9+
]
10+
11+
// minify
12+
const min = print(tree, {
13+
indent: false,
14+
newline: false,
15+
pad: false,
16+
comments: false
17+
})
18+
wat2wasm(min)
19+
is(min, `(func (export "double")(param f64 f32)(param $x i32)(result f64)(f64.mul(local.get 0)(f64.const 2)))`)
20+
21+
// pretty-print
22+
const pretty = print(tree, {
23+
indent: ' ', // indentation characters
24+
newline: '\n', // new line charactes
25+
pad: '', // pad start of each line with a string
26+
comments: true // keep comments
27+
})
28+
wat2wasm(pretty)
29+
is(pretty,
30+
`(func (export "double")
31+
(param f64 f32)(param $x i32)
32+
(result f64)
33+
(f64.mul
34+
(local.get 0)
35+
(f64.const 2)))`)
36+
37+
is(
38+
print(`(import "Math" "random" (func $random (result f32)))`),
39+
`(import \"Math\" \"random\"(func $random (result f32)))`
40+
)
41+
})
42+
43+
t.only('print: dino', async t => {
44+
let src = await file('./example/dino.wat')
45+
const dino = print(src)
46+
console.log(dino)
47+
48+
wat2wasm(dino)
49+
})

0 commit comments

Comments
 (0)