├── .gitignore
├── .npmignore
├── README.md
├── api.poem
├── boot.poem
├── cli.js
├── concept.poem
├── concept.wast
├── debug.wast
├── images
└── Poetree_256.png
├── index.js
├── package-lock.json
├── package.json
├── poetry.json
├── prettify_wast.js
├── runtime.wast
├── stdlib.wast
├── test.html
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # https://git-scm.com/docs/gitignore
2 | # https://help.github.com/articles/ignoring-files
3 | # Example .gitignore files: https://github.com/github/gitignore
4 | /node_modules/
5 | /build/
6 | /build-desktop/
7 | /deploy.json
8 | *.log
9 | Thumbs.db
10 | *~
11 | *.kra-autosave.kra
12 | boot.wa*
13 | boot.debug.*
14 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # https://git-scm.com/docs/gitignore
2 | # https://help.github.com/articles/ignoring-files
3 | # Example .gitignore files: https://github.com/github/gitignore
4 | /node_modules/
5 | /src/
6 | /images/
7 | /deploy.json
8 | *.log
9 | /Jakefile.*
10 | /.jshintrc
11 | Thumbs.db
12 | *~
13 | *.kra-autosave.kra
14 | boot.*
15 | api.*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Poetry
4 | ======
5 | A poetically dynamic and simple programming language that compiles to WebAssembly!
6 |
7 | Much features! Very hype!
8 | ------------------------
9 | - Easy to learn and use
10 | - Minimalistic syntax
11 | - Customizable
12 | - Full control of wasm imports and exports
13 | - Bundle multiple source files (including `.wa(s)t`-files!)
14 |
15 | Usage
16 | -----
17 | $ npm i -g poetry-compiler
18 | $ poetry my_program.poem -b my_program.wasm
19 |
20 | Example
21 | -------
22 | export_memory "memory"
23 | import "env" "log" _log 2 0
24 |
25 | func log message
26 | _log (address_of message) (size_of message)
27 |
28 | export "init" init
29 | log "Hello Poetry! 🌳"
30 |
31 | Check the [wiki for documentation](https://github.com/FantasyInternet/poetry/wiki)!
32 |
--------------------------------------------------------------------------------
/api.poem:
--------------------------------------------------------------------------------
1 | @import "env" "logNumber" log_number 1
2 | @import "env" "log" _log 2
3 |
4 | @export_memory "memory"
5 |
6 | @func log msg
7 | msg += ""
8 | _log (address_of msg) (size_of msg)
9 |
--------------------------------------------------------------------------------
/boot.poem:
--------------------------------------------------------------------------------
1 | include "./debug.wast"
2 | include "./api.poem"
3 |
4 | var meaning_of_life = 42.5
5 | var meaning_of_life2 = false
6 | var name = '"Hello \"world"! 🤖'
7 |
8 | var my_pet =
9 | :name = "Fido"
10 | :species = "dog"
11 | :age = 3
12 | :male = true
13 | :nutered = false
14 | :mother =
15 | :name = "Rita"
16 | :age = 10
17 | :male = false
18 | :father = null
19 |
20 |
21 | var friends =
22 | "Alice"
23 | 'Bob'
24 | 'Charlie'
25 | "Dennis"
26 |
27 | func sum a b
28 | var tableindex = #init
29 | return a + b + meaning_of_life
30 |
31 | export "init" init
32 | test_json
33 | ~ make_a_cup_of tea
34 |
35 | func test_json
36 | var val = "Små søde\njordbær!🍓"
37 | log val
38 | log json_encode val
39 | val = "\"\\\/\b\f\n\t\u0000"
40 | log val
41 | log json_encode val
42 | log json_encode friends
43 | log json_encode my_pet
44 | log "" + json_decode "42"
45 | log "" + json_decode "-42.50E-1"
46 | log json_decode '"Sm\\u00e5 s\\u00f8de\\njordb\\u00e6r!\\ud83c\\udf53"'
47 | log json_encode (json_decode (json_encode friends))
48 | log json_encode (json_decode "{\"form\":96,\"params\":[127,127],\"returns\":[127]}")
49 | log json_encode json_decode json_encode json_decode "{\n \"pi\": 3.141592653589793,\n \"name\": \"poetry-compiler\",\n \"version\": \"0.34.0\",\n \"description\": \"Poetic programming language that compiles to webassembly\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"build\": \"node cli.js boot.poem -t boot.wast -b boot.wasm --debug boot.debug.json\",\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n },\n \"bin\": {\n \"poetry\": \".\/cli.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https:\/\/github.com\/FantasyInternet\/poetry.git\"\n },\n \"keywords\": [\n \"wasm\",\n \"webassembly\",\n \"compiler\",\n \"programming\",\n \"language\",\n \"poetry\"\n ],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"bugs\": {\n \"url\": \"https:\/\/github.com\/FantasyInternet\/poetry\/issues\"\n },\n \"homepage\": \"https:\/\/github.com\/FantasyInternet\/poetry#readme\",\n \"dependencies\": {\n \"commander\": \"^2.17.1\",\n \"wabt\": \"^1.0.0\"\n }\n}"
50 |
51 | func test_unicode
52 | var danish = "æøå$¢€𐍈💩"
53 | for i in range 0 (string_length danish)
54 | log (char (char_code danish i))
55 |
56 | func test_if
57 | if false
58 | log "one"
59 | elsif false
60 | log "two"
61 | elsif false
62 | log "three"
63 | else
64 | log "four"
65 |
66 | func test_search
67 | log "Charlie is my " + (array_search friends "Charlie") + "th friend!"
68 | var friend = "Chøarlie"
69 | var sub = "lie"
70 | log friend + " has '"+sub+"' at " + (string_search friend sub 0 )
71 |
72 | func test_split
73 | var list = ",one,two,,three,four,"
74 | var arr = string_split list ","
75 | for item in arr
76 | log item
77 | log array_join arr ";"
78 | arr = array
79 | log array_join arr ";"
80 | array_push arr
81 | log array_join arr ";"
82 | array_push arr
83 | log array_join arr ";"
84 |
85 | func test_tableindex
86 | var tableindex = #sum
87 | log_number #tableindex tableindex meaning_of_life2
88 | log_number echo sum tableindex meaning_of_life2
89 |
90 | func test_whatever
91 | log name + " " + -32.00125
92 | var friend = friends[1 + 1]
93 | log friend
94 | var i = 10
95 | if i > 0
96 | log "yay!"
97 | else
98 | log "nay..."
99 | log "Greetings to all of my friends!"
100 | for frend in friends
101 | log "Hello " + frend + "! How are you!"
102 |
103 | func test_shifting
104 | log (array_unshift (friends) (array_pop (friends)))
105 | log (array_unshift friends (array_pop friends))
106 | log array_unshift friends string_upper array_pop friends
107 | log array_unshift friends `to` array_pop friends
108 | log array_unshift friends string_lower array_pop friends
109 | log array_unshift friends array_pop friends
110 | log array_unshift friends array_pop friends
111 | log array_unshift friends array_pop friends
112 |
113 | func introduce
114 | for friend1 in friends
115 | for friend2 in friends
116 | log friend1+", meet "+friend2+"!"
117 |
118 | export "echo" echo num
119 | ~ log_number num
120 | return num
121 |
--------------------------------------------------------------------------------
/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const compile = require("./index"),
3 | program = require('commander')
4 |
5 | program
6 | .arguments('')
7 | .option('-b, --wasm ', 'Compile to wasm binary')
8 | .option('-t, --wast ', 'Compile to wast text file')
9 | .option('--debug ', '(dump some debugging stuff to file)')
10 | .action(function (file) {
11 | compile(file, program)
12 | })
13 | .parse(process.argv)
14 |
--------------------------------------------------------------------------------
/concept.poem:
--------------------------------------------------------------------------------
1 | ~ This is a comment?
2 | print "some string"
3 | pset 100 100 red
4 | parse ( stringify obj )
5 |
6 | if age >= 18
7 | print "Get a job!"
8 |
9 | var meaning_of_life = 42
10 | var pi = 3.14
11 | var name = "John"
12 | var married = false
13 | var friends =
14 | "Alice"
15 | "Bob"
16 | "Carol"
17 | "Daniel"
18 |
19 | print "Hello! my name is $name"
20 | for friend in friends
21 | print "My friend is $friend!"
22 |
23 | if name == "John"
24 | print "You are my best friend!"
25 | else
26 | print "Go away!"
27 |
28 | func double n
29 | return n * 2
30 |
31 | include "./graphics.poem" gfx\
32 |
33 | gfx\create_image 320 200
34 |
35 |
36 | class Person
37 | var string first_name be "John"
38 | var string last_name be "Doe"
39 |
40 | init name
41 | let string[] names
42 | be (split name " ")
43 | let first_name be names[0]
44 | let last_name
45 | be names[1]
46 |
47 | func full_name
48 | return "$first_name $last_name"
--------------------------------------------------------------------------------
/concept.wast:
--------------------------------------------------------------------------------
1 | (module
2 | ;; imports
3 |
4 | ;; runtime
5 |
6 | ;; globals
7 | (global $meaning_of_life (mut i32) (i32.const 0))
8 | (global $pi (mut i32) (i32.const 0))
9 | (global $name (mut i32) (i32.const 0))
10 | (global $married (mut i32) (i32.const 0))
11 | (global $friends (mut i32) (i32.const 0))
12 |
13 | ;; functions
14 | (func $double (param $n i32) (result i32)
15 | (return (call $-mul (get_local $n) (call $-number (f32.const 2))))
16 |
17 | )
18 |
19 |
20 | ;; exports
21 |
22 | )
--------------------------------------------------------------------------------
/debug.wast:
--------------------------------------------------------------------------------
1 | (func $get_mindex (result i32)
2 | (get_global $-mindex)
3 | )
4 | (export "get_mindex" (func $get_mindex))
5 |
6 | (func $load_f64 (param $offset i32) (result f64)
7 | (f64.load (get_local $offset))
8 | )
9 | (export "load_f64" (func $load_f64))
10 | (export "garbagecollect" (func $-garbagecollect))
11 | ;; (export "traceGC" (func $-traceGC))
12 |
--------------------------------------------------------------------------------
/images/Poetree_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FantasyInternet/poetry/ac0bf73502f792d3c541d5c09f29b10f23150b9b/images/Poetree_256.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs"),
2 | path = require("path"),
3 | wabt = require("wabt")(),
4 | pretty_wast = require("./prettify_wast.js")
5 |
6 | function compile(filename, options = {}) {
7 | let compilation = {
8 | tokenTree: [],
9 | strings: [null, false, 0, "", null, true, true, true],
10 | bundle: []
11 | }
12 | compilation.bundle.push(require.resolve(filename, { paths: [path.dirname(filename)] }))
13 | compilation.ns = 0
14 | compilation.namespaces = { "": [] }
15 | while (compilation.bundle[compilation.ns]) {
16 | compilation.path = compilation.bundle[compilation.ns]
17 | compilation.src = ("\n" + fs.readFileSync(compilation.path)).replace(/\r/g, "") + "\n;;~end`\n;"
18 | compilation.config = findConfig(compilation.path)
19 | compilation.metaphors = compilation.config.metaphors
20 | if (compilation.config.includes) {
21 | for (let include of compilation.config.includes) {
22 | if (!compilation.bundle.includes(include)) {
23 | compilation.namespaces[""].push("ns" + compilation.bundle.length + "\\")
24 | compilation.bundle.push(include)
25 | }
26 | }
27 | }
28 |
29 | rewind(compilation)
30 | if (compilation.path.match(/.+\.was?t$/)) {
31 | compilation.tokenTree = compilation.tokenTree.concat(createWastTokenTree(compilation))
32 | } else {
33 | compilation.tokenTree = compilation.tokenTree.concat(createTokenTree(compilation))
34 | }
35 | compilation.ns++
36 | }
37 |
38 | compilation.globals = scanForGlobals(compilation.tokenTree)
39 | if (options.debug) {
40 | fs.writeFileSync(options.debug, JSON.stringify(compilation, null, 2))
41 | }
42 | compilation.globals["-namespaces"] = compilation.namespaces
43 | let wast = compileModule(compilation)
44 | if (options.wast) {
45 | wast = pretty_wast(wast)
46 | fs.writeFileSync(options.wast, wast)
47 | }
48 | if (options.debug) {
49 | fs.writeFileSync(options.debug, JSON.stringify(compilation, null, 2))
50 | }
51 | if (options.wasm) {
52 | let wasm = compileWast(wast, { write_debug_names: !!(options.wast || options.debug) })
53 | fs.writeFileSync(options.wasm, wasm)
54 | }
55 | }
56 |
57 | function findConfig(dir) {
58 | let config = {}
59 | let tries = dir.split(path.sep).length + 1
60 | while (tries--) {
61 | try {
62 | config = { ...require(path.join(dir, "poetry.json")), ...config }
63 | if (config.includes) {
64 | for (let i = 0; i < config.includes.length; i++) {
65 | config.includes[i] = require.resolve(config.includes[i], { paths: [dir] })
66 | }
67 | }
68 | } catch (error) { }
69 | if (dir !== path.dirname(dir)) {
70 | dir = path.dirname(dir)
71 | } else {
72 | dir = __dirname
73 | }
74 | }
75 | return config
76 | }
77 |
78 | function isKeyword(token) { return token && typeof token === "string" && (token[0] === "@") }
79 | function isProperty(token) { return token && typeof token === "string" && (token[0] === ":") }
80 | function isIdentifier(token) { return token && typeof token === "string" && (token[0].match(/[\$A-Z_a-z]/) || token.charCodeAt(0) > 127) }
81 | function isNumber(token) { return token && typeof token === "string" && (token[0].match(/[0-9]/)) }
82 | function isString(token) { return token && typeof token === "string" && (token[0].match(/["']/)) }
83 | function isSymbol(token) { return token && typeof token === "string" && (token[0].match(/[!#%&*+,\-/;<=>?^|]/)) }
84 | function isAssigner(token) { return token && typeof token === "string" && (token.substr(-1) === "=") }
85 | function isWast(token) { return token && typeof token === "object" && ["import", "global", "func", "export"].includes(token[0]) }
86 |
87 | function nextChar(c, peek) {
88 | let char = c.src[c.position]
89 | if (!peek) {
90 | c.position++
91 | c.col++
92 | if (char === "\n") {
93 | c.line++
94 | c.col = 1
95 | c.lastNl = c.position - 1
96 | }
97 | }
98 | return char
99 | }
100 | function rewind(c) {
101 | c.position = 0
102 | c.line = 1
103 | c.col = 1
104 | c.indents = [0]
105 | c.lastNl = 0
106 | }
107 | function rewindToNl(c) {
108 | c.position = c.lastNl
109 | c.line--
110 | }
111 | function croak(c, msg) {
112 | throw `${msg} at ${c.path}[${c.line}:${c.col}]!`
113 | }
114 |
115 | function escapeStr(str) {
116 | let buf = new Buffer(str)
117 | str = ""
118 | for (let i = 0; i < buf.length; i++) {
119 | if (buf[i] < 32 || buf[i] >= 127 || buf[i] === 34 || buf[i] === 92) {
120 | str += "\\" + ("0" + buf[i].toString(16)).substr(-2)
121 | } else {
122 | str += String.fromCharCode(buf[i])
123 | }
124 | }
125 | return str
126 | }
127 |
128 | function nextToken(c) {
129 | let token = " "
130 | let char
131 | while (" \t".includes(token)) {
132 | token = nextChar(c)
133 | if (!token) return
134 | if (token === "~") {
135 | while (token !== "\n") {
136 | token = nextChar(c)
137 | }
138 | }
139 | if (token === "`") {
140 | token = nextChar(c)
141 | while (token !== "`") {
142 | token = nextChar(c)
143 | }
144 | token = nextChar(c)
145 | }
146 | }
147 |
148 | if (token.match(/\n/)) {
149 | let i = 0
150 | char = nextChar(c, true)
151 | while (!char.trim()) {
152 | nextChar(c)
153 | i++
154 | if (char === "\n") i = 0
155 | char = nextChar(c, true)
156 | if (char === "~") {
157 | while (char !== "\n") {
158 | nextChar(c)
159 | char = nextChar(c, true)
160 | }
161 | }
162 | if (char === "`") {
163 | char = nextChar(c)
164 | char = nextChar(c)
165 | while (char !== "`") {
166 | char = nextChar(c)
167 | }
168 | char = nextChar(c, true)
169 | }
170 | }
171 | if (i > c.indents[c.indents.length - 1]) {
172 | c.indents.push(i)
173 | token = "{"
174 | } else if (i < c.indents[c.indents.length - 1]) {
175 | c.indents.pop()
176 | token = "}"
177 | rewindToNl(c)
178 | } else {
179 | token = ";"
180 | }
181 | } else if (token.match(/[\@]/)) {
182 | char = nextChar(c, true)
183 | while (char.match(/[A-Z_a-z]/)) {
184 | token += nextChar(c)
185 | char = nextChar(c, true)
186 | }
187 | token = token.toLowerCase()
188 | } else if (token.match(/[\:]/)) {
189 | char = nextChar(c, true)
190 | while (char.match(/[\$A-Z_a-z0-9.\\]/) || char.charCodeAt(0) > 127) {
191 | token += nextChar(c)
192 | char = nextChar(c, true)
193 | }
194 | } else if (token.match(/[\$A-Z_a-z]/) || token.charCodeAt(0) > 127) {
195 | char = nextChar(c, true)
196 | while (char.match(/[\$A-Z_a-z0-9.\\]/) || char.charCodeAt(0) > 127) {
197 | token += nextChar(c)
198 | char = nextChar(c, true)
199 | }
200 | token = token.toLowerCase()
201 | } else if (token.match(/[0-9.]/)) {
202 | let dot = token === "."
203 | char = nextChar(c, true).toLowerCase()
204 | if (token === "0" && char === "x") {
205 | token += nextChar(c).toLowerCase()
206 | char = nextChar(c, true).toLowerCase()
207 | while (char.match(/[0-9a-f]/)) {
208 | token += nextChar(c).toLowerCase()
209 | char = nextChar(c, true).toLowerCase()
210 | }
211 | } else {
212 | while (char.match(/[0-9]/) || (char === "." && !dot)) {
213 | if (char === ".") dot = true
214 | token += nextChar(c)
215 | char = nextChar(c, true)
216 | }
217 | }
218 | if (token.length > 1 && token[0] === ".") token = "0" + token
219 | } else if (token.match(/["']/)) {
220 | while (char !== token[0]) {
221 | if (char === "\\") token += nextChar(c)
222 | char = nextChar(c)
223 | token += char
224 | }
225 | token = '"' + token.substr(1, token.length - 2).replace(/(^|[^\\])"/g, '$1\\"') + '"'
226 | } else if (token.match(/[\{\(\[\;\]\)\}]/)) {
227 | } else while (token.substr(-1) === nextChar(c, true) || nextChar(c, true) === "=") {
228 | token += nextChar(c)
229 | }
230 |
231 | if (c.metaphors[token]) token = c.metaphors[token]
232 | if (isProperty(token)) {
233 | let str = token.substr(1)
234 | if (isNaN(str) && !c.strings.includes(str)) {
235 | c.strings.push(str)
236 | }
237 | }
238 | if (c.lastToken === "@import") {
239 | } else if (c.lastToken === "@import_memory") {
240 | } else if (c.lastToken === "@import_table") {
241 | } else if (c.lastToken === "@export") {
242 | } else if (c.lastToken === "@export_memory") {
243 | } else if (c.lastToken === "@export_table") {
244 | } else if (c.lastToken === "@include") {
245 | let filename = require.resolve(JSON.parse(token), { paths: [path.dirname(c.path)] })
246 | if (!c.bundle.includes(filename)) {
247 | c.bundle.push(filename)
248 | }
249 | token = JSON.stringify(filename)
250 | } else if (isString(token)) {
251 | let str = JSON.parse(token)
252 | if (str && !c.strings.includes(str)) {
253 | c.strings.push(str)
254 | }
255 | }
256 | if (isIdentifier(token)) {
257 | token = "ns" + c.ns + "\\" + token.toLowerCase()
258 | }
259 | if (c.lastToken === "@import") {
260 | c.lastToken = "@export"
261 | } else {
262 | c.lastToken = token
263 | }
264 | return token
265 | }
266 | function nextWastToken(c) {
267 | let token = " "
268 | let char
269 | while (token.charCodeAt(0) <= 32) {
270 | token = nextChar(c)
271 | if (!token) return
272 | if (token === ";" && nextChar(c, true) === ";") {
273 | token = nextChar(c)
274 | while (token !== "\n") {
275 | token = nextChar(c)
276 | }
277 | }
278 | }
279 |
280 | if (token.match(/[\w]/)) {
281 | char = nextChar(c, true)
282 | while (char.match(/[^\(\)\s]/)) {
283 | token += nextChar(c)
284 | char = nextChar(c, true)
285 | }
286 | } else if (token.match(/[\$]/)) {
287 | char = nextChar(c, true)
288 | while (char.match(/[^\(\)\s]/)) {
289 | token += nextChar(c)
290 | char = nextChar(c, true)
291 | }
292 | } else if (token.match(/[\-0-9.]/)) {
293 | let dot = token === "."
294 | char = nextChar(c, true)
295 | while (char.match(/[0-9x]/) || (char === "." && !dot)) {
296 | if (char === ".") dot = true
297 | token += nextChar(c)
298 | char = nextChar(c, true)
299 | }
300 | if (token.length > 1 && token[0] === ".") token = "0" + token
301 | } else if (token.match(/["']/)) {
302 | while (char !== token[0]) {
303 | if (char === "\\") token += nextChar(c)
304 | char = nextChar(c)
305 | token += char
306 | }
307 | token = '"' + token.substr(1, token.length - 2).replace(/(^|[^\\])"/g, '$1\\"') + '"'
308 | }
309 |
310 | if (token[0] === "$" && token[1] !== "-") {
311 | token = "$ns" + c.ns + "\\" + token.substr(1).toLowerCase()
312 | }
313 | return token
314 | }
315 |
316 | function createTokenTree(c) {
317 | let token
318 | let tree = []
319 | while ((token = nextToken(c)) && ("])}".includes(token) === false)) {
320 | if ("{([".includes(token)) {
321 | token = [token].concat(createTokenTree(c))
322 | } else if (isSymbol(tree[tree.length - 1]) && token === "-") {
323 | token = [token, nextToken(c)]
324 | }
325 | tree.push(token)
326 | }
327 | tree.push(token)
328 | return tree
329 | }
330 | function createWastTokenTree(c) {
331 | let token
332 | let tree = []
333 | while ((token = nextWastToken(c)) && (token !== ")")) {
334 | if (token === "(") {
335 | token = createWastTokenTree(c)
336 | }
337 | tree.push(token)
338 | }
339 | return tree
340 | }
341 |
342 | function scanForGlobals(tokenTree) {
343 | let globals = []
344 |
345 | let statement = []
346 | for (let token of tokenTree) {
347 | if (isWast(token)) {
348 | if (token[0] === "global") {
349 | if (isIdentifier(token[1].substr(1))) {
350 | if (globals[token[1].substr(1)]) throw `duplicate identifier "${token[1].substr(1)}"`
351 | globals[token[1].substr(1)] = true
352 | }
353 | }
354 | if (token[0] === "import") {
355 | token = token[3]
356 | }
357 | if (token[0] === "func") {
358 | if (isIdentifier(token[1].substr(1))) {
359 | if (globals[token[1].substr(1)]) throw `duplicate identifier "${token[1].substr(1)}"`
360 | let locals = []
361 | for (let i = 2; (typeof token === "object") && (token[i][0] === "param"); i++) {
362 | if (isIdentifier(token[i][1].substr(1))) {
363 | if (locals.includes(token[i][1].substr(1))) throw `duplicate parameter "${token[i][1].substr(1)}"`
364 | locals.push(token[i][1].substr(1))
365 | }
366 | }
367 | globals[token[1].substr(1)] = locals
368 | }
369 | }
370 | } else if (";}".includes(token)) {
371 | if (statement[0] === "@var") {
372 | if (isIdentifier(statement[1])) {
373 | if (globals[statement[1]]) throw `duplicate identifier "${statement[1]}"`
374 | globals[statement[1]] = true
375 | }
376 | }
377 | if (statement[0] === "@func" || statement[0] === "@import" || statement[0] === "@export") {
378 | if (statement[0] === "@import") {
379 | statement.splice(1, 2)
380 | }
381 | if (statement[0] === "@export") {
382 | statement.splice(1, 1)
383 | }
384 | if (isIdentifier(statement[1])) {
385 | if (globals[statement[1]]) throw `duplicate identifier "${statement[1]}"`
386 | let locals = []
387 | if (statement[0] === "@import") {
388 | let params = parseInt(statement[2])
389 | for (let i = 0; i < params; i++) {
390 | locals.push("p" + i)
391 | }
392 | } else {
393 | for (let i = 2; i < statement.length; i++) {
394 | if (isIdentifier(statement[i])) {
395 | if (locals.includes(statement[i])) throw `duplicate parameter "${statement[i]}"`
396 | locals.push(statement[i])
397 | }
398 | }
399 | }
400 | globals[statement[1]] = locals
401 | }
402 | }
403 | statement = []
404 | } else {
405 | statement.push(token)
406 | }
407 | }
408 |
409 | return globals
410 | }
411 |
412 |
413 | function compileModule(c) {
414 | let imports = ""
415 | let memory = `(memory $-memory 2) \n`
416 | let table = ""
417 | let globals = ""
418 | let functions = ""
419 | let start = "(call $-initruntime)\n"
420 | let startLocals = ["-ret"]
421 | let exports = ""
422 | let runtime = fs.readFileSync(path.join(__dirname, "runtime.wast"))
423 | let gc = ""
424 |
425 | let offset = 1024 * 64
426 | start += `(call $-resize (i32.const -1) (i32.const ${8 * c.strings.length}))`
427 | for (let i = 8; i < c.strings.length; i++) {
428 | let len = Buffer.byteLength(c.strings[i], 'utf8')
429 | memory += `(data (i32.const ${offset}) "${escapeStr(c.strings[i])}")\n`
430 | start += `(drop (call $-string (i32.const ${offset}) (i32.const ${len})))\n`
431 | offset += len
432 | offset = Math.floor(offset / 8) * 8 + 16
433 | }
434 | start += `(call $-funcstart)\n`
435 | c.globals["-string"] = c.strings
436 | c.globals["-table"] = []
437 |
438 | let statement = []
439 | for (let token of c.tokenTree) {
440 | if (isWast(token)) {
441 | if (token[0] === "import") imports += compileWastTokens(token)
442 | if (token[0] === "global") globals += compileWastTokens(token)
443 | if (token[0] === "func") functions += compileWastTokens(token)
444 | if (token[0] === "export") exports += compileWastTokens(token)
445 | } else if (";}".includes(token)) {
446 | if (statement[0] === "@var") {
447 | globals += `(global $${statement[1]} (mut i32) (i32.const 0))\n`
448 | statement.shift()
449 | }
450 | if (statement[0] === "@export") {
451 | exports += `(func $--${statement[2]}\n`
452 | for (let i = 3; i < statement.length - 1; i++) {
453 | exports += `(param $${statement[i]} f64)`
454 | }
455 | exports += `(result f64)(call $-funcstart)`
456 | exports += `(call $-funcend (call $${statement[2]}`
457 | for (let i = 3; i < statement.length - 1; i++) {
458 | exports += `(call $-number (get_local $${statement[i]}))`
459 | }
460 | exports += `))(call $-f64))(export ${statement[1]} (func $--${statement[2]}))\n`
461 | statement.shift()
462 | statement[0] = "@func"
463 | }
464 | if (statement[0] === "@import") {
465 | let name = statement[3]
466 | imports += `(import ${statement[1]} ${statement[2]} (func $--${name} `
467 | let params = parseInt(statement[4])
468 | let results = parseInt(statement[5]) || 1
469 | for (let i = 0; i < params; i++) {
470 | imports += `(param f64) `
471 | }
472 | for (let i = 0; i < results; i++) {
473 | imports += `(result f64) `
474 | }
475 | imports += `))\n`
476 |
477 | functions += `(func $${name}`
478 | for (let i = 0; i < params; i++) {
479 | functions += `(param $p${i} i32) `
480 | }
481 | functions += `(result i32)\n`
482 | functions += `(call $--${name} `
483 | for (let i = 0; i < params; i++) {
484 | functions += `(call $-f64 (call $-to_number (get_local $p${i}))) `
485 | }
486 | functions += `)`
487 | if (results) {
488 | functions += `(call $-number)`
489 | } else {
490 | functions += `(i32.const 0)`
491 | }
492 | functions += `)\n`
493 | } else if (statement[0] === "@import_memory") {
494 | imports += `(import ${statement[1]} ${statement[2]} (memory 2))\n`
495 | memory = memory.substr(memory.indexOf(")") + 1)
496 | } else if (statement[0] === "@export_memory") {
497 | exports += `(export ${statement[1]} (memory $-memory))\n`
498 | } else if (statement[0] === "@import_table") {
499 | table += `(import ${statement[1]} ${statement[2]} (table $-table 1 anyfunc))\n`
500 | } else if (statement[0] === "@export_table") {
501 | exports += `(export ${statement[1]} (table $-table))\n`
502 | } else if (statement[0] === "@func") {
503 | functions += compileFunction(statement, c.globals) + "\n"
504 | } else if (statement[0] === "@include") {
505 | let filename = JSON.parse(statement[1])
506 | let prefix = statement[2] || ""
507 | let ns = c.bundle.indexOf(filename)
508 | if (ns >= 0) {
509 | c.globals["-namespaces"][prefix] = c.globals["-namespaces"][prefix] || []
510 | c.globals["-namespaces"][prefix].push("ns" + ns + "\\")
511 | }
512 | } else {
513 | start += compileStatement(statement, c.globals, startLocals)
514 | }
515 | statement = []
516 | } else {
517 | statement.push(token)
518 | }
519 | }
520 | for (let i = 0; i < startLocals.length; i++) {
521 | start = `(local $${startLocals[i]} i32)` + start
522 | }
523 | if (!table) table = `(table $-table ${c.globals["-table"].length * 2} anyfunc)\n`
524 | for (let i = 0; i < c.globals["-table"].length; i++) {
525 | table += `(elem (i32.const ${i * 2}) $--${c.globals["-table"][i]})\n`
526 | table += `(elem (i32.const ${i * 2 + 1}) $${c.globals["-table"][i]})\n`
527 |
528 | exports += `(func $--${c.globals["-table"][i]}\n`
529 | for (let p = 0; p < c.globals[c.globals["-table"][i]].length; p++) {
530 | exports += `(param $${c.globals[c.globals["-table"][i]][p]} f64)`
531 | }
532 | exports += `(result f64)(call $-funcstart)`
533 | exports += `(call $-funcend (call $${c.globals["-table"][i]}`
534 | for (let p = 0; p < c.globals[c.globals["-table"][i]].length; p++) {
535 | exports += `(call $-number (get_local $${c.globals[c.globals["-table"][i]][p]}))`
536 | }
537 | exports += `))(call $-f64))\n`
538 | }
539 | gc += `(func $-passdown_globals\n`
540 | // gc += `(call $-zerorefs)\n`
541 | for (let g in c.globals) {
542 | if (c.globals[g] === true && !g.includes("~")) {
543 | gc += `(call $-passdown (get_global $${g}))\n`
544 | }
545 | }
546 | // gc += `(call $-garbagecollect)\n`
547 | gc += `)\n`
548 |
549 | return `
550 | (module
551 | ;; imports
552 | ${imports}
553 |
554 | ;; memory
555 | ${memory}
556 |
557 | ;; table
558 | ${table}
559 |
560 | ;; globals
561 | ${globals}
562 |
563 | ;; functions
564 | ${functions}
565 |
566 | ;; start
567 | (func $-start
568 | (local $-success i32)
569 | ${start})
570 | (start $-start)
571 |
572 | ;; exports
573 | ${exports}
574 |
575 | ;; runtime
576 | ${runtime}
577 |
578 | ;; gc
579 | ${gc}
580 | )
581 | `.trim()
582 | }
583 |
584 | function compileFunction(tokenTree, globals) {
585 | let wast = ""
586 | let locals = []
587 | tokenTree = deparens(tokenTree, true)
588 | globals["-blocks"] = -1
589 |
590 | wast += `\n;; function $${tokenTree[1]} \n`
591 | wast += `(func $${tokenTree[1]} `
592 | for (let i = 2; i < tokenTree.length; i++) {
593 | if (isIdentifier(tokenTree[i])) {
594 | wast += `(param $${tokenTree[i]} i32) `
595 | locals.push(tokenTree[i])
596 | }
597 | if (tokenTree[i][0] === "{") {
598 | wast += `(result i32)\n`
599 | let paramlength = locals.length
600 | let block = compileBlock(tokenTree[i], globals, locals)
601 | for (let i = paramlength; i < locals.length; i++) {
602 | wast += `(local $${locals[i]} i32)`
603 | }
604 | wast += `(local $-ret i32)(local $-success i32)`
605 | wast += `(call $-funcstart)`
606 | wast += block
607 | wast += `(call $-funcend (get_local $-ret))`
608 | // wast += `(call $-passdown)`
609 | // wast += `(get_local $-ret)`
610 | }
611 | }
612 | wast += `)\n`
613 |
614 | return wast
615 | }
616 |
617 | function compileBlock(tokenTree, globals, locals) {
618 | let wast = "(block\n"
619 | globals["-blocks"]++
620 | tokenTree = deparens(tokenTree, true)
621 |
622 | let statement = []
623 | for (let token of tokenTree) {
624 | if (";}".includes(token)) {
625 | wast += compileStatement(statement, globals, locals) + "\n"
626 | statement = []
627 | } else {
628 | statement.push(token)
629 | }
630 | }
631 | if (statement.length) {
632 | wast += compileStatement(statement, globals, locals) + "\n"
633 | }
634 | wast += "(set_local $-success (i32.const 1)))\n"
635 | globals["-blocks"]--
636 | return wast
637 | }
638 |
639 | function compileStatement(tokenTree, globals, locals) {
640 | let wast = ""
641 | tokenTree = deparens(tokenTree, true)
642 |
643 | if (tokenTree[0] === "@var" || tokenTree[0] === "@for") {
644 | if (!locals.includes(tokenTree[1])) {
645 | locals.push(tokenTree[1])
646 | }
647 | if (tokenTree[0] === "@var") tokenTree.shift()
648 | }
649 | if (tokenTree[0] === "@if") {
650 | wast += `(if (call $-truthy ${compileExpression(tokenTree.slice(1, tokenTree.length - 1), globals, locals)})\n`
651 | wast += `${compileBlock(tokenTree[tokenTree.length - 1], globals, locals)}`.replace("(block", "(then")
652 | wast += `(else (set_local $-success (i32.const 0))))`
653 | } else if (tokenTree[0] === "@elsif") {
654 | wast += `(if (i32.and (i32.eqz(get_local $-success)) (call $-truthy ${compileExpression(tokenTree.slice(1, tokenTree.length - 1), globals, locals)}))\n`
655 | wast += `${compileBlock(tokenTree[tokenTree.length - 1], globals, locals)})`.replace("(block", "(then")
656 | } else if (tokenTree[0] === "@else") {
657 | wast += `(if (i32.eqz (get_local $-success))\n`
658 | wast += `${compileBlock(tokenTree[tokenTree.length - 1], globals, locals)})`.replace("(block", "(then")
659 | } else if (tokenTree[0] === "@while") {
660 | wast += `(block(loop`
661 | globals["-blocks"] += 2
662 | wast += `(br_if 1 (call $-falsy ${compileExpression(tokenTree.slice(1, tokenTree.length - 1), globals, locals)}))`
663 | wast += ` ${compileBlock(tokenTree[tokenTree.length - 1], globals, locals)}`
664 | wast += `(br 0)))`
665 | globals["-blocks"] -= 2
666 | } else if (tokenTree[0] === "@for") {
667 | let fori = allocVar(locals, "-fori")
668 | let forl = allocVar(locals, "-forl")
669 | let fora = allocVar(locals, "-fora")
670 | let item = tokenTree[1]
671 | let array = tokenTree.slice(3, tokenTree.length - 1)
672 | wast += `(set_local $${fori} (i32.const 0) )`
673 | wast += `(set_local $${fora} ${compileExpression(array, globals, locals)} )`
674 | wast += `(set_local $${forl} (i32.div_u (call $-len (get_local $${fora}) ) (i32.const 4)) )`
675 | wast += `(block(loop`
676 | globals["-blocks"] += 2
677 | wast += `(br_if 1 (i32.ge_u (get_local $${fori}) (get_local $${forl}) ) )`
678 | wast += `(set_local $${item} (call $-get_from_obj (get_local $${fora}) (call $-integer_u (get_local $${fori}) )))`
679 | wast += ` ${compileBlock(tokenTree[tokenTree.length - 1], globals, locals)}`
680 | wast += `(set_local $${fori} (i32.add (get_local $${fori}) (i32.const 1)))(br 0)))`
681 | globals["-blocks"] -= 2
682 | } else if (tokenTree[0] === "@return") {
683 | wast += `(set_local $-ret ${compileExpression(tokenTree.slice(1), globals, locals)})(br ${globals["-blocks"]})\n`
684 | } else {
685 | let exprs = compileExpression(tokenTree, globals, locals, true)
686 | for (let expr of exprs) {
687 | if (expr) wast += `(drop ${expr})\n`
688 | }
689 | }
690 |
691 | return wast
692 | }
693 |
694 | function compileExpression(tokenTree, globals, locals, list) {
695 | let wast = ""
696 | let _values, values = deparens(tokenTree)
697 | if (values[0] === "{") return compileObjLit(tokenTree, globals, locals)
698 |
699 | for (let i = 0; i < values.length; i++) {
700 | let token = values[i]
701 | if (token === "#") {
702 | let operand = values[i + 1]
703 | if (isIdentifier(operand) && typeof globals[resolveIdentifier(operand, globals)] === "object" && !locals.includes(operand)) {
704 | let name = resolveIdentifier(operand, globals)
705 | if (!globals["-table"].includes(name)) globals["-table"].push(name)
706 | values.splice(i, 1)
707 | values[i] = `(call $-integer_u (i32.const ${globals["-table"].indexOf(name) * 2}))`
708 | } else {
709 | let index = compileExpression([operand], globals, locals)
710 | let a = values.slice(0, i)
711 | let b = values.slice(i + 2, values.length)
712 | values = a
713 | let args = compileExpression(b, globals, locals, true)
714 | let wast = `(call_indirect `
715 | for (let i = 0; i < args.length; i++) {
716 | wast += `(param i32) `
717 | }
718 | wast += `(result i32)\n`
719 | wast += args.join(" ")
720 | wast += `(i32.add (i32.const 1) (call $-i32_u ${index})))`
721 |
722 | values.push(wast)
723 | }
724 | }
725 | if (isIdentifier(token) && typeof globals[resolveIdentifier(token, globals)] === "object" && !locals.includes(token)) {
726 | let name = resolveIdentifier(token, globals)
727 | let a = values.slice(0, i)
728 | let b = values.slice(i + 1, values.length)
729 | values = a
730 | let args = compileExpression(b, globals, locals, true)
731 |
732 | while (args.length > globals[name].length) args.pop()
733 | while (args.length < globals[name].length) args.push("(i32.const 0)")
734 | values.push(`(call $${name} ${args.join(" ")})`)
735 | }
736 | }
737 |
738 | _values = values
739 | values = []
740 | for (let token of _values) {
741 | values.push(token)
742 | if (typeof token === "object" && token[0] !== "[") {
743 | values.pop()
744 | values.push(compileExpression(token, globals, locals))
745 | }
746 | if (isIdentifier(token)) {
747 | let id = resolveIdentifier(values.pop(), globals)
748 | if (locals.includes(token)) {
749 | values.push(`(get_local $${token})`)
750 | } else if (globals[id]) {
751 | if (typeof globals[id] === "object") {
752 | values.push(id)
753 | } else {
754 | values.push(`(get_global $${id})`)
755 | }
756 | } else {
757 | throw `undeclared identifier '${id}'`
758 | // values.push(`(i32.const 0)`)
759 | }
760 | }
761 | if (token === "@null") {
762 | values.pop()
763 | values.push(`(i32.const 0)`)
764 | }
765 | if (token === "@false") {
766 | values.pop()
767 | values.push(`(i32.const 1)`)
768 | }
769 | if (token === "@true") {
770 | values.pop()
771 | values.push(`(i32.const 5)`)
772 | }
773 | if (token === "@array") {
774 | values.pop()
775 | values.push(`(call $-new_value (i32.const 4) (i32.const 0))`)
776 | }
777 | if (token === "@object") {
778 | values.pop()
779 | values.push(`(call $-new_value (i32.const 5) (i32.const 0))`)
780 | }
781 | if (token === "@binary") {
782 | values.pop()
783 | values.push(`(call $-new_value (i32.const 6) (i32.const 0))`)
784 | }
785 | if (isNumber(token)) {
786 | let num = values.pop()
787 | values.push(`(call $-number (f64.const ${num}))`)
788 | }
789 | if (isString(token)) {
790 | let str = JSON.parse(values.pop())
791 | values.push(`(i32.const ${globals["-string"].indexOf(str)})`)
792 | }
793 | }
794 | _values = values
795 | values = []
796 | for (let token of _values) {
797 | values.push(token)
798 | if (isProperty(token)) {
799 | let prop = values.pop().substr(1)
800 | let obj = values.pop()
801 | if (isNaN(prop)) {
802 | prop = `(i32.const ${globals["-string"].indexOf(prop)})`
803 | } else {
804 | prop = `(call $-number (f64.const ${prop}))`
805 | }
806 | values.push(`(call $-get_from_obj ${obj} ${prop})`)
807 | }
808 | if (typeof token === "object" && token[0] === "[") {
809 | let prop = compileExpression(values.pop(), globals, locals)
810 | let obj = values.pop()
811 | values.push(`(call $-get_from_obj ${obj} ${prop})`)
812 | }
813 | }
814 | _values = values
815 | values = []
816 | for (let token of _values) {
817 | values.push(token)
818 | if (values[values.length - 1] === "++") {
819 | values.pop()
820 | let operand = values.pop()
821 | values.push(operand)
822 | values.push(`=`)
823 | values.push(`(call $-inc ${operand} (f64.const 1))`)
824 | }
825 | if (values[values.length - 1] === "--") {
826 | values.pop()
827 | let operand = values.pop()
828 | values.push(operand)
829 | values.push(`=`)
830 | values.push(`(call $-inc ${operand} (f64.const -1))`)
831 | }
832 | }
833 | _values = values
834 | values = []
835 | for (let token of _values) {
836 | values.push(token)
837 | if (values[values.length - 2] === "*") {
838 | let operand2 = values.pop()
839 | values.pop()
840 | let operand1 = values.pop()
841 | values.push(`(call $-mul ${operand1} ${operand2})`)
842 | }
843 | if (values[values.length - 2] === "/") {
844 | let operand2 = values.pop()
845 | values.pop()
846 | let operand1 = values.pop()
847 | values.push(`(call $-div ${operand1} ${operand2})`)
848 | }
849 | if (values[values.length - 2] === "%") {
850 | let operand2 = values.pop()
851 | values.pop()
852 | let operand1 = values.pop()
853 | values.push(`(call $-mod ${operand1} ${operand2})`)
854 | }
855 | }
856 | _values = values
857 | values = []
858 | for (let token of _values) {
859 | values.push(token)
860 | if (values[values.length - 2] === "+") {
861 | let operand2 = values.pop()
862 | values.pop()
863 | let operand1 = values.pop()
864 | values.push(`(call $-add ${operand1} ${operand2})`)
865 | }
866 | if (values[values.length - 2] === "-") {
867 | let operand2 = values.pop()
868 | values.pop()
869 | let operand1 = values.pop() || "(i32.const 2)"
870 | values.push(`(call $-sub ${operand1} ${operand2})`)
871 | }
872 | }
873 | _values = values
874 | values = []
875 | for (let token of _values) {
876 | values.push(token)
877 | if (values[values.length - 2] === "<") {
878 | let operand2 = values.pop()
879 | values.pop()
880 | let operand1 = values.pop()
881 | values.push(`(call $-lt ${operand1} ${operand2})`)
882 | }
883 | if (values[values.length - 2] === "<=") {
884 | let operand2 = values.pop()
885 | values.pop()
886 | let operand1 = values.pop()
887 | values.push(`(call $-le ${operand1} ${operand2})`)
888 | }
889 | if (values[values.length - 2] === ">") {
890 | let operand2 = values.pop()
891 | values.pop()
892 | let operand1 = values.pop()
893 | values.push(`(call $-gt ${operand1} ${operand2})`)
894 | }
895 | if (values[values.length - 2] === ">=") {
896 | let operand2 = values.pop()
897 | values.pop()
898 | let operand1 = values.pop()
899 | values.push(`(call $-ge ${operand1} ${operand2})`)
900 | }
901 | }
902 | _values = values
903 | values = []
904 | for (let token of _values) {
905 | values.push(token)
906 | if (values[values.length - 2] === "==") {
907 | let operand2 = values.pop()
908 | values.pop()
909 | let operand1 = values.pop()
910 | values.push(`(call $-equal ${operand1} ${operand2})`)
911 | }
912 | if (values[values.length - 2] === "!=") {
913 | let operand2 = values.pop()
914 | values.pop()
915 | let operand1 = values.pop()
916 | values.push(`(call $-unequal ${operand1} ${operand2})`)
917 | }
918 | }
919 | _values = values
920 | values = []
921 | for (let token of _values) {
922 | values.push(token)
923 | if (values[values.length - 2] === "&&") {
924 | let operand2 = values.pop()
925 | values.pop()
926 | let operand1 = values.pop()
927 | values.push(`(call $-and ${operand1} ${operand2})`)
928 | }
929 | if (values[values.length - 2] === "||") {
930 | let operand2 = values.pop()
931 | values.pop()
932 | let operand1 = values.pop()
933 | values.push(`(call $-or ${operand1} ${operand2})`)
934 | }
935 | }
936 | _values = values
937 | values = []
938 | for (let token of _values) {
939 | values.push(token)
940 | if (isAssigner(values[values.length - 2])) {
941 | let operand2 = values.pop()
942 | let op = values.pop()
943 | let operand1 = values.pop()
944 | let setter = operand1
945 | if (setter.indexOf(`(get_local `) === 0) {
946 | setter = setter.replace(`(get_local `, `(set_local `)
947 | } else if (setter.indexOf(`(get_global `) === 0) {
948 | setter = setter.replace(`(get_global `, `(set_global `)
949 | } else if (setter.indexOf(`(call $-get_from_obj `) === 0) {
950 | setter = setter.replace(`(call $-get_from_obj `, `(call $-set_to_obj `)
951 | } else {
952 | throw `cannot assign to ${setter}`
953 | }
954 | if (op[0] === "+") {
955 | operand2 = `(call $-add ${operand1} ${operand2})`
956 | }
957 | if (op[0] === "-") {
958 | operand2 = `(call $-sub ${operand1} ${operand2})`
959 | }
960 | if (op[0] === "*") {
961 | operand2 = `(call $-mul ${operand1} ${operand2})`
962 | }
963 | if (op[0] === "/") {
964 | operand2 = `(call $-div ${operand1} ${operand2})`
965 | }
966 | if (op[0] === "%") {
967 | operand2 = `(call $-mod ${operand1} ${operand2})`
968 | }
969 | setter = setter.substr(0, setter.lastIndexOf(")"))
970 | operand2 += ")"
971 | values.push(`${setter} ${operand2} ${operand1}\n`)
972 | }
973 | }
974 |
975 | if (list) return values
976 | return values.join(" ")
977 | }
978 |
979 | function compileObjLit(tokenTree, globals, locals) {
980 | let wast = ""
981 | let datatype = 5
982 | let index = 0
983 | tokenTree = deparens(tokenTree, true)
984 | tokenTree.push(";")
985 |
986 | let name = 0
987 | while (locals.includes("-obj" + name)) name++
988 | locals.push(name = "-obj" + name)
989 |
990 | let statement = []
991 | for (let token of tokenTree) {
992 | if (";}".includes(token)) {
993 | if (statement.length > 1 && isProperty(statement[0])) {
994 | statement.unshift(`(get_local $${name})`)
995 | wast += `(drop ${compileExpression(statement, globals, locals)})\n`
996 | index += 2
997 | } else {
998 | wast += `(call $-set_to_obj (get_local $${name}) (call $-number (f64.const ${index})) ${compileExpression(statement, globals, locals)})\n`
999 | index++
1000 | datatype = 4
1001 | }
1002 | statement = []
1003 | } else {
1004 | statement.push(token)
1005 | }
1006 | }
1007 | wast = `(tee_local $${name} (call $-new_value (i32.const ${datatype}) (i32.const 0)))\n` + wast
1008 |
1009 |
1010 | return wast
1011 | }
1012 |
1013 | function compileWastTokens(tokens, indent = "\n") {
1014 | wast = ""
1015 | for (let token of tokens) {
1016 | if (typeof token === "object") {
1017 | wast += compileWastTokens(token, indent + " ")
1018 | } else {
1019 | wast += token + " "
1020 | }
1021 | }
1022 | return `${indent}(${wast})`
1023 | }
1024 |
1025 | function deparens(tokens, all) {
1026 | let start = tokens[0]
1027 | let end = tokens[tokens.length - 1]
1028 | if (tokens.length === 1 && typeof start === "object") return deparens(start, all)
1029 | if (all && start === "{" && end === "}") return deparens(tokens.slice(1, tokens.length - 1), all)
1030 | if (start === "(" && end === ")") return deparens(tokens.slice(1, tokens.length - 1), all)
1031 | if (start === "[" && end === "]") return deparens(tokens.slice(1, tokens.length - 1), all)
1032 | return tokens.slice()
1033 | }
1034 |
1035 | function compileWast(wast, options) {
1036 | return wabt.parseWat("boot", wast).toBinary(options).buffer
1037 | }
1038 |
1039 | function resolveIdentifier(identifier, globals) {
1040 | let ns = identifier.substr(0, identifier.indexOf("\\") + 1)
1041 | let name = identifier.substr(identifier.indexOf("\\") + 1)
1042 | if (globals[identifier]) {
1043 | return identifier
1044 | } else {
1045 | for (let prefix in globals["-namespaces"]) {
1046 | let namespaces = globals["-namespaces"][prefix]
1047 | prefix = prefix || ns
1048 | for (let namespace of namespaces) {
1049 | if (identifier.substr(0, prefix.length) === prefix &&
1050 | globals[identifier.replace(prefix, namespace)]) {
1051 | return identifier.replace(prefix, namespace)
1052 | }
1053 | }
1054 | }
1055 | }
1056 | return identifier
1057 | }
1058 |
1059 | function allocVar(pool, prefix) {
1060 | let i = 0
1061 | while (pool.includes(prefix + i)) i++
1062 | pool.push(prefix + i)
1063 | return prefix + i
1064 | }
1065 |
1066 | module.exports = compile
1067 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "poetry-compiler",
3 | "version": "0.48.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "commander": {
8 | "version": "2.18.0",
9 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz",
10 | "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ=="
11 | },
12 | "wabt": {
13 | "version": "1.0.5",
14 | "resolved": "https://registry.npmjs.org/wabt/-/wabt-1.0.5.tgz",
15 | "integrity": "sha512-RVZyd7G3jTKVkXLgClKKxEkUqglKQ/NNnCln7wWP851+VhetU7Z2UdKm6ztMdLXWtSiFhIvqgGWJbkvwZYHoKg=="
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "poetry-compiler",
3 | "version": "0.48.0",
4 | "description": "Poetic programming language that compiles to webassembly",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "node cli.js boot.poem -t boot.wast -b boot.wasm --debug boot.debug.json",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "bin": {
11 | "poetry": "./cli.js"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/FantasyInternet/poetry.git"
16 | },
17 | "keywords": [
18 | "wasm",
19 | "webassembly",
20 | "compiler",
21 | "programming",
22 | "language",
23 | "poetry"
24 | ],
25 | "author": "",
26 | "license": "ISC",
27 | "bugs": {
28 | "url": "https://github.com/FantasyInternet/poetry/issues"
29 | },
30 | "homepage": "https://github.com/FantasyInternet/poetry#readme",
31 | "dependencies": {
32 | "commander": "^2.17.1",
33 | "wabt": "^1.0.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/poetry.json:
--------------------------------------------------------------------------------
1 | {
2 | "includes": [
3 | "./stdlib.wast"
4 | ],
5 | "metaphors": {
6 | "array": "@array",
7 | "binary": "@binary",
8 | "else": "@else",
9 | "elsif": "@elsif",
10 | "export": "@export",
11 | "export_memory": "@export_memory",
12 | "export_table": "@export_table",
13 | "false": "@false",
14 | "for": "@for",
15 | "func": "@func",
16 | "if": "@if",
17 | "in": "@in",
18 | "import": "@import",
19 | "import_memory": "@import_memory",
20 | "import_table": "@import_table",
21 | "include": "@include",
22 | "var": "@var",
23 | "null": "@null",
24 | "object": "@object",
25 | "return": "@return",
26 | "true": "@true",
27 | "while": "@while"
28 | }
29 | }
--------------------------------------------------------------------------------
/prettify_wast.js:
--------------------------------------------------------------------------------
1 |
2 | function prettify(wast) {
3 | let out = ""
4 | let indent = true
5 | let tokens = tokenize(wast.trim() + "\n")
6 | //return JSON.stringify(tokens,null,2)
7 | let stack = []
8 | tokens = tokens[0]
9 | while (tokens) {
10 | let token = tokens.shift()
11 | if (typeof token === "object") {
12 | if (indent) {
13 | out += "\n"
14 | for (let i = 0; i < stack.length; i++) out += " "
15 | }
16 | out += "("
17 | stack.push(tokens)
18 | tokens = token
19 | //out += countArrays(tokens)
20 | indent = countArrays(tokens) > 1
21 | } else if (token.substr(0, 2) === ";;") {
22 | if (indent) {
23 | out += "\n\n"
24 | for (let i = 0; i < stack.length; i++) out += " "
25 | }
26 | out += token + " "
27 | } else {
28 | out += token + " "
29 | }
30 | while (tokens && !tokens.length) {
31 | out += ") "
32 | tokens = stack.pop()
33 | indent = true
34 | //indent = countArrays(tokens) > 1
35 | }
36 | }
37 | return trimLineEnds(out.substr(0, out.lastIndexOf(")")))
38 | }
39 |
40 | function tokenize(wast) {
41 | let stack = []
42 | let tokens = []
43 | let pos = 0
44 | let char = ""
45 | while (pos < wast.length) {
46 | //console.log(pos)
47 | let token = ""
48 | while (char && !char.trim()) {
49 | char = wast[pos++]
50 | }
51 | if (char === ";" && wast[pos] === ";") {
52 | //token="\n\n"
53 | while (char && char !== "\n") {
54 | token += char
55 | char = wast[pos++]
56 | }
57 | token += char
58 | char = wast[pos++]
59 | } else if (char === "(" && wast[pos] === ";") {
60 | while (char && token.substr(-2) !== ";)") {
61 | token += char
62 | char = wast[pos++]
63 | }
64 | } else if ("(".includes(char)) {
65 | stack.push(tokens)
66 | tokens.push(tokens = [])
67 | char = wast[pos++]
68 | } else if (")".includes(char)) {
69 | tokens = stack.pop()
70 | char = wast[pos++]
71 | } else if ("\"\'".includes(char)) {
72 | while (char && char !== token[0]) {
73 | if (char === "\\") {
74 | token += char
75 | char = wast[pos++]
76 | }
77 | token += char
78 | char = wast[pos++]
79 | }
80 | token += char
81 | char = wast[pos++]
82 | } else {
83 | do {
84 | token += char
85 | char = wast[pos++]
86 | } while (char && char.trim() && !"(\";\')".includes(char))
87 | }
88 | token && tokens.push(token)
89 | //console.log(token)
90 | }
91 | while (stack.length) tokens = stack.pop()
92 | return tokens
93 | }
94 |
95 | function countArrays(arr) {
96 | if (!arr) return 0
97 | let count = 0
98 | for (let elem of arr) {
99 | if (typeof elem === "object") count++
100 | }
101 | return count
102 | }
103 |
104 | function trimLineEnds(txt) {
105 | while (txt.includes(" \n")) {
106 | txt = txt.replace(/ \n/g, "\n");
107 | }
108 | return txt.trim() + "\n"
109 | }
110 |
111 | module.exports = prettify
--------------------------------------------------------------------------------
/runtime.wast:
--------------------------------------------------------------------------------
1 | ;; memory management
2 | (global $-totmem (mut i32) (i32.const 0))
3 | (func $-initruntime
4 | (set_global $-totmem (i32.mul (i32.const 65536) (current_memory)))
5 | (i32.store (i32.const 0) (i32.sub (i32.mul (i32.const 65536) (current_memory)) (i32.const 8)))
6 | (set_global $-mindex (call $-alloc (i32.const 8)))
7 | )
8 |
9 | ;; function wrapper
10 | (global $-calls (mut i32) (i32.const 0))
11 | (func $-funcstart
12 | (if (i32.le_u (get_global $-calls) (i32.const 1))(then
13 | ;; (set_global $-passdown_mark (i32.and (i32.add (get_global $-passdown_mark) (i32.const 1)) (i32.const 127)))
14 | (call $-zerorefs)
15 | (call $-garbagecollect)
16 | ))
17 | (set_global $-calls (i32.add (get_global $-calls) (i32.const 1)))
18 | )
19 | (global $-gc_pending (mut i32) (i32.const 1))
20 | (func $-funcend (param $ret i32) (result i32)
21 | (if (get_global $-calls) (then
22 | (set_global $-calls (i32.sub (get_global $-calls) (i32.const 1)))
23 | (if (get_local $ret)(then
24 | (set_global $-passdown_mark (i32.and (i32.add (get_global $-passdown_mark) (i32.const 1)) (i32.const 127)))
25 | (call $-passdown (get_local $ret))
26 | ))
27 | (if (i32.gt_u (get_global $-gc_pending) (get_global $-calls))(then
28 | (call $-garbagecollect)
29 | ))
30 | ))
31 | (get_local $ret)
32 | )
33 |
34 | ;; allocate memory
35 | (global $-last_alloc (mut i32) (i32.const 0))
36 | (func $-alloc (param $len i32) (result i32)
37 | (local $offset i32)
38 | (local $offset2 i32)
39 | (local $space i32)
40 | (local $space2 i32)
41 | (local $totmem i32)
42 | (local $allowgrow i32)
43 |
44 | (if (get_global $-last_alloc)(then
45 | (set_local $offset (i32.sub (get_global $-last_alloc) (i32.const 8)))
46 | (set_local $offset (i32.sub (get_local $offset) (i32.load (get_local $offset))))
47 | )(else
48 | (set_local $allowgrow (i32.const 1))
49 | ))
50 | ;; how much space is here at the beginning?
51 | (set_local $space (i32.load (get_local $offset)))
52 | ;; round down to nearest multiple of 8
53 | (set_local $space (i32.and (get_local $space) (i32.const -8) ) )
54 | (block(loop
55 | ;; is there enough space here?
56 | (br_if 1 (i32.gt_u (get_local $space) (i32.add (get_local $len) (i32.const 32))))
57 | ;; skip the space
58 | (set_local $offset (i32.add (i32.add (get_local $offset) (get_local $space)) (i32.const 4)))
59 | ;; how much data is here?
60 | (set_local $space (i32.load (get_local $offset)))
61 |
62 | ;; is this the end of memory?
63 | (if (i32.le_u (i32.sub (get_global $-totmem) (get_local $offset)) (i32.const 8))(then
64 | ;; are we allowed to grow memory?
65 | (if (get_local $allowgrow)(then
66 | (set_local $offset2 (i32.add (get_global $-totmem) (i32.const 8)))
67 | (drop (grow_memory (current_memory)))
68 | (set_global $-totmem (i32.mul (i32.const 65536) (current_memory)))
69 | (i32.store (get_local $offset2) (i32.sub (get_global $-totmem) (i32.add (i32.const 8) (get_local $offset2))))
70 | (call $-dealloc (i32.sub (get_local $offset2) (i32.const 8)))
71 | (set_local $space (i32.load (i32.const 0)))
72 | (set_local $offset (i32.add (get_local $space) (i32.const 4)))
73 | (set_local $space (i32.load (get_local $offset)))
74 | )(else ;; first time? start from beginning
75 | (call $-garbagecollect)
76 | (set_local $allowgrow (i32.const 1))
77 | (set_local $offset (i32.const 0))
78 | (set_local $space (i32.load (get_local $offset)))
79 | (set_local $space (i32.and (get_local $space) (i32.const -8) ) )
80 | (set_local $offset (i32.add (i32.add (get_local $offset) (get_local $space)) (i32.const 4)))
81 | (set_local $space (i32.load (get_local $offset)))
82 | ))
83 | ))
84 |
85 | ;; skip the data
86 | (set_local $offset (i32.add (i32.add (get_local $offset) (get_local $space)) (i32.const 4)))
87 | ;; align to next multiple of 8
88 | (set_local $offset (i32.add (i32.and (get_local $offset) (i32.const -8)) (i32.const 8)))
89 | ;; how much space is here?
90 | (set_local $space (i32.load (get_local $offset)))
91 | ;; round down to nearest multiple of 8
92 | (set_local $space (i32.and (get_local $space) (i32.const -8) ) )
93 | (br 0)
94 | ))
95 | ;; claim the space
96 | (i32.store (get_local $offset) (i32.const 0))
97 | (set_local $offset2 (i32.add (get_local $offset) (i32.const 4)))
98 | (i32.store (get_local $offset2) (get_local $len))
99 |
100 | ;; skip allocation
101 | (set_local $offset2 (i32.add (i32.add (get_local $offset2) (get_local $len)) (i32.const 4)))
102 | ;; round down to nearest multiple of 8
103 | (set_local $offset2 (i32.and (get_local $offset2) (i32.const -8)))
104 | ;; set terminator
105 | (i64.store (get_local $offset2) (i64.const 0))
106 | (set_local $offset2 (i32.add (get_local $offset2) (i32.const 8)))
107 | ;; how much less space is there now?
108 | (set_local $space2 (i32.sub (get_local $space) (i32.sub (get_local $offset2) (get_local $offset))))
109 | ;; mark the space at both ends
110 | (i32.store (get_local $offset2) (get_local $space2))
111 | (set_local $offset2 (i32.add (get_local $offset2) (get_local $space2)))
112 | (i32.store (get_local $offset2) (get_local $space2))
113 |
114 | ;; zerofill allocation
115 | (set_local $offset (i32.add (i32.const 8) (get_local $offset)))
116 | (call $-memzero (get_local $offset) (get_local $len))
117 |
118 | ;; return offset where the data is supposed to begin
119 | (set_global $-last_alloc (get_local $offset))
120 | (return (get_local $offset))
121 | )
122 |
123 | ;; deallocate memory
124 | (func $-dealloc (param $offset i32)
125 | (local $offset i32)
126 | (local $offset2 i32)
127 | (local $space i32)
128 | (local $space2 i32)
129 |
130 | (if (i32.eq (get_local $offset) (get_global $-last_alloc))(then
131 | (set_global $-last_alloc (i32.const 0))
132 | ))
133 | (set_local $offset (i32.sub (i32.and (get_local $offset) (i32.const -8)) (i32.const 8)))
134 | (set_local $space (i32.load (get_local $offset)))
135 | (set_local $space (i32.and (get_local $space) (i32.const -8) ) )
136 | (set_local $offset (i32.sub (get_local $offset) (get_local $space)))
137 |
138 | (set_local $offset2 (i32.add (i32.add (get_local $offset) (get_local $space)) (i32.const 4)))
139 | (set_local $space2 (i32.load (get_local $offset2)))
140 | (set_local $offset2 (i32.add (i32.add (get_local $offset2) (get_local $space2)) (i32.const 4)))
141 | (set_local $offset2 (i32.add (i32.and (get_local $offset2) (i32.const -8)) (i32.const 8)))
142 | (set_local $space2 (i32.load (get_local $offset2)))
143 | (set_local $space2 (i32.and (get_local $space2) (i32.const -8) ) )
144 | (set_local $offset2 (i32.add (get_local $offset2) (get_local $space2)))
145 |
146 | (set_local $space (i32.sub (get_local $offset2) (get_local $offset)))
147 | (i32.store (get_local $offset) (get_local $space))
148 | (i32.store (get_local $offset2) (get_local $space))
149 | )
150 |
151 | ;; zerofill memory
152 | (func $-memzero (param $offset i32) (param $len i32)
153 | (block(loop (br_if 1 (i32.lt_u (get_local $len) (i32.const 8)))
154 | (i64.store (get_local $offset) (i64.const 0))
155 | (set_local $offset (i32.add (get_local $offset) (i32.const 8)))
156 | (set_local $len (i32.sub (get_local $len) (i32.const 8)))
157 | (br 0)))
158 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
159 | (i32.store8 (get_local $offset) (i32.const 0))
160 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
161 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
162 | (br 0)))
163 | )
164 |
165 | ;; copy memory
166 | (func $-memcopy (param $from i32) (param $to i32) (param $len i32)
167 | (local $delta i32)
168 | (if (i32.lt_u (get_local $from) (get_local $to))(then
169 | (set_local $delta (i32.const -8))
170 | (set_local $from (i32.add (get_local $from) (get_local $len)))
171 | (set_local $to (i32.add (get_local $to) (get_local $len)))
172 | (block(loop (br_if 1 (i32.lt_s (get_local $len) (i32.const 8)))
173 | (set_local $from (i32.add (get_local $from) (get_local $delta)))
174 | (set_local $to (i32.add (get_local $to) (get_local $delta)))
175 | (i64.store (get_local $to) (i64.load (get_local $from)))
176 | (set_local $len (i32.sub (get_local $len) (i32.const 8)))
177 | (br 0) ))
178 | (set_local $delta (i32.const -1))
179 | (block(loop (br_if 1 (i32.lt_s (get_local $len) (i32.const 1)))
180 | (set_local $from (i32.add (get_local $from) (get_local $delta)))
181 | (set_local $to (i32.add (get_local $to) (get_local $delta)))
182 | (i32.store8 (get_local $to) (i32.load8_u (get_local $from)))
183 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
184 | (br 0) ))
185 | )(else
186 | (set_local $delta (i32.const 8))
187 | (block(loop (br_if 1 (i32.lt_s (get_local $len) (i32.const 8)))
188 | (i64.store (get_local $to) (i64.load (get_local $from)))
189 | (set_local $from (i32.add (get_local $from) (get_local $delta)))
190 | (set_local $to (i32.add (get_local $to) (get_local $delta)))
191 | (set_local $len (i32.sub (get_local $len) (i32.const 8)))
192 | (br 0) ))
193 | (set_local $delta (i32.const 1))
194 | (block(loop (br_if 1 (i32.lt_s (get_local $len) (i32.const 1)))
195 | (i32.store8 (get_local $to) (i32.load8_u (get_local $from)))
196 | (set_local $from (i32.add (get_local $from) (get_local $delta)))
197 | (set_local $to (i32.add (get_local $to) (get_local $delta)))
198 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
199 | (br 0) ))
200 | ))
201 | )
202 |
203 | ;; memory index
204 | (global $-mindex (mut i32) (i32.const 0))
205 |
206 | ;; offset of memory allocation
207 | (func $-offset (param $id i32) (result i32)
208 | (local $offset i32)
209 | (if (i32.eq (get_local $id) (i32.const -1))(then
210 | (set_local $offset (get_global $-mindex))
211 | )(else
212 | (if (i32.lt_u (get_local $id) (i32.const 8))(then
213 | (set_local $offset (i32.const 0))
214 | )(else
215 | (set_local $id (i32.sub (get_local $id) (i32.const 8)))
216 | (if (i32.gt_u (call $-len (i32.const -1)) (i32.mul (i32.const 8) (get_local $id)))(then
217 | (set_local $offset (i32.add (get_global $-mindex) (i32.mul (i32.const 8) (get_local $id))))
218 | (set_local $offset (i32.load (get_local $offset)))
219 | ))
220 | ))
221 | ))
222 | (set_local $offset (i32.and (get_local $offset) (i32.const -8)))
223 | (get_local $offset)
224 | )
225 |
226 | ;; datatype of memory allocation
227 | (func $-datatype (param $id i32) (result i32)
228 | (local $datatype i32)
229 | (if (i32.eq (get_local $id) (i32.const -1))(then
230 | (set_local $datatype (i32.const 7))
231 | )(else
232 | (if (i32.lt_u (get_local $id) (i32.const 8))(then
233 | (set_local $datatype (i32.and (get_local $id) (i32.const 3)))
234 | )(else
235 | (set_local $datatype (i32.sub (get_global $-mindex) (i32.const 64)))
236 | (set_local $datatype (i32.add (get_local $datatype) (i32.add (i32.mul (i32.const 8) (get_local $id)) (i32.const 6))))
237 | (set_local $datatype (i32.load8_u (get_local $datatype)))
238 | ))
239 | ))
240 | (get_local $datatype)
241 | )
242 |
243 | ;; length of memory allocation
244 | (func $-len (param $id i32) (result i32)
245 | (local $offset i32)
246 | (local $len i32)
247 | (set_local $offset (call $-offset (get_local $id)))
248 | (if (get_local $offset)(then
249 | (set_local $len (i32.load (i32.sub (get_local $offset) (i32.const 4))))
250 | ))
251 | (get_local $len)
252 | )
253 |
254 | ;; callstack-depth of memory allocation
255 | (func $-callstack_depth (param $id i32) (result i32)
256 | (local $depth i32)
257 | (if (i32.ge_u (get_local $id) (i32.const 8))(then
258 | (set_local $depth (i32.sub (get_global $-mindex) (i32.const 64)))
259 | (set_local $depth (i32.add (get_local $depth) (i32.add (i32.mul (i32.const 8) (get_local $id)) (i32.const 4))))
260 | (set_local $depth (i32.load16_u (get_local $depth)))
261 | ))
262 | (get_local $depth)
263 | )
264 |
265 | ;; resize memory allocation
266 | (func $-resize (param $id i32) (param $newlen i32)
267 | (local $offset i32)
268 | (local $len i32)
269 | (local $spaceafter i32)
270 | (local $newoffset i32)
271 | (if (i32.eq (get_local $id) (i32.const -1))(then
272 | (set_local $len (i32.const 1))
273 | (block(loop (br_if 1 (i32.ge_u (get_local $len) (get_local $newlen)))
274 | (set_local $len (i32.mul (get_local $len) (i32.const 2)))
275 | (br 0)))
276 | (set_local $newlen (get_local $len))
277 | ))
278 | (set_local $offset (call $-offset (get_local $id)))
279 | (if (get_local $offset)(then ;; the value is in memory
280 | (set_local $len (i32.load (i32.sub (get_local $offset) (i32.const 4))))
281 | (if (i32.eq
282 | (i32.and (get_local $len) (i32.const -8))
283 | (i32.and (get_local $newlen) (i32.const -8))
284 | )(then ;; the old and new lengths are (almost) the same
285 | (i32.store (i32.sub (get_local $offset) (i32.const 4)) (get_local $newlen))
286 | (if (i32.gt_u (get_local $len) (get_local $newlen))(then ;; shrink
287 | (call $-memzero
288 | (i32.add (get_local $offset) (get_local $newlen))
289 | (i32.sub (get_local $len) (get_local $newlen))
290 | )
291 | )(else ;; grow
292 | (call $-memzero
293 | (i32.add (get_local $offset) (get_local $len))
294 | (i32.sub (get_local $newlen) (get_local $len))
295 | )
296 | ))
297 | )(else
298 | (set_local $spaceafter
299 | (i32.load
300 | (i32.add
301 | (get_local $offset)
302 | (i32.add (i32.and (get_local $len) (i32.const -8)) (i32.const 8))
303 | )
304 | )
305 | )
306 | (if (i32.or
307 | (i32.gt_u (get_local $len) (get_local $newlen))
308 | (i32.gt_u (get_local $spaceafter) (i32.sub (get_local $newlen) (get_local $len)))
309 | )(then ;; we can resize in-place
310 | (set_local $spaceafter (i32.add
311 | (get_local $spaceafter)
312 | (i32.sub
313 | (i32.and (get_local $len) (i32.const -8))
314 | (i32.and (get_local $newlen) (i32.const -8))
315 | )
316 | ))
317 | (i32.store (i32.sub (get_local $offset) (i32.const 4)) (get_local $newlen))
318 | (if (i32.gt_u (get_local $len) (get_local $newlen))(then ;; shrink
319 | (call $-memzero
320 | (i32.add (get_local $offset) (get_local $newlen))
321 | (i32.sub (get_local $len) (get_local $newlen))
322 | )
323 | )(else ;; grow
324 | (call $-memzero
325 | (i32.add (get_local $offset) (get_local $len))
326 | (i32.sub (get_local $newlen) (get_local $len))
327 | )
328 | ))
329 | (i32.store
330 | (i32.add
331 | (get_local $offset)
332 | (i32.add (i32.and (get_local $newlen) (i32.const -8)) (i32.const 8))
333 | )
334 | (get_local $spaceafter)
335 | )
336 | (i32.store
337 | (i32.add
338 | (i32.add
339 | (get_local $offset)
340 | (i32.add (i32.and (get_local $newlen) (i32.const -8)) (i32.const 8))
341 | )
342 | (get_local $spaceafter)
343 | )
344 | (get_local $spaceafter)
345 | )
346 | )(else ;; we need to re-allocate
347 | (set_local $newoffset (call $-alloc (i32.mul (get_local $newlen) (i32.const 2))))
348 | (call $-memcopy (get_local $offset) (get_local $newoffset) (get_local $len))
349 | (call $-dealloc (get_local $offset))
350 | (if (i32.eq (get_local $id) (i32.const -1))(then
351 | (set_global $-mindex (get_local $newoffset))
352 | )(else
353 | (call $-write32 (i32.const -1) (i32.mul (i32.sub (get_local $id) (i32.const 8)) (i32.const 8)) (get_local $newoffset))
354 | ))
355 | (drop (call $-new_value (i32.const 6) (i32.const 1)))
356 | (drop (call $-new_value (i32.const 6) (i32.const 1)))
357 | (call $-resize (get_local $id) (get_local $newlen))
358 | ))
359 | ))
360 | ))
361 | )
362 |
363 | ;; set datatype of memory allocation
364 | (func $-set_datatype (param $id i32) (param $datatype i32) (result i32)
365 | (local $offset i32)
366 | (if (i32.eq (get_local $id) (i32.const -1))(then
367 | (set_local $datatype (i32.const 7))
368 | )(else
369 | (if (i32.lt_u (get_local $id) (i32.const 8))(then
370 | (set_local $datatype (i32.and (get_local $id) (i32.const 3)))
371 | )(else
372 | (set_local $offset (i32.sub (get_global $-mindex) (i32.const 64)))
373 | (set_local $offset (i32.add (get_local $offset) (i32.add (i32.mul (i32.const 8) (get_local $id)) (i32.const 6))))
374 | (i32.store8 (get_local $offset) (get_local $datatype))
375 | ))
376 | ))
377 | (get_local $id)
378 | )
379 |
380 |
381 | ;; read from memory allocation
382 | (func $-read8 (param $id i32) (param $pos i32) (result i32)
383 | (local $offset i32)
384 | (local $data i32)
385 | (set_local $offset (call $-offset (get_local $id)))
386 | (if (i32.lt_u (get_local $pos) (call $-len (get_local $id)))(then
387 | (set_local $data (i32.load8_u (i32.add (get_local $offset) (get_local $pos))))
388 | ))
389 | (get_local $data)
390 | )
391 | (func $-read16 (param $id i32) (param $pos i32) (result i32)
392 | (local $offset i32)
393 | (local $data i32)
394 | (set_local $offset (call $-offset (get_local $id)))
395 | (if (i32.lt_u (i32.add (get_local $pos) (i32.const 1)) (call $-len (get_local $id)))(then
396 | (set_local $data (i32.load16_u (i32.add (get_local $offset) (get_local $pos))))
397 | ))
398 | (get_local $data)
399 | )
400 | (func $-read32 (param $id i32) (param $pos i32) (result i32)
401 | (local $offset i32)
402 | (local $data i32)
403 | (set_local $offset (call $-offset (get_local $id)))
404 | (if (i32.lt_u (i32.add (get_local $pos) (i32.const 3)) (call $-len (get_local $id)))(then
405 | (set_local $data (i32.load (i32.add (get_local $offset) (get_local $pos))))
406 | ))
407 | (get_local $data)
408 | )
409 | ;; write to memory allocation
410 | (func $-write8 (param $id i32) (param $pos i32) (param $data i32)
411 | (local $offset i32)
412 | (set_local $offset (call $-offset (get_local $id)))
413 | (if (get_local $offset)(then
414 | (if (i32.ge_u (get_local $pos) (call $-len (get_local $id)))(then
415 | (call $-resize (get_local $id) (i32.add (get_local $pos) (i32.const 1)))
416 | (set_local $offset (call $-offset (get_local $id)))
417 | ))
418 | (i32.store8 (i32.add (get_local $offset) (get_local $pos)) (get_local $data))
419 | ))
420 | )
421 | (func $-write16 (param $id i32) (param $pos i32) (param $data i32)
422 | (local $offset i32)
423 | (set_local $offset (call $-offset (get_local $id)))
424 | (if (get_local $offset)(then
425 | (if (i32.ge_u (i32.add (get_local $pos) (i32.const 1)) (call $-len (get_local $id)) )(then
426 | (call $-resize (get_local $id) (i32.add (get_local $pos) (i32.const 2)))
427 | (set_local $offset (call $-offset (get_local $id)))
428 | ))
429 | (i32.store16 (i32.add (get_local $offset) (get_local $pos)) (get_local $data))
430 | ))
431 | )
432 | (func $-write32 (param $id i32) (param $pos i32) (param $data i32)
433 | (local $offset i32)
434 | (set_local $offset (call $-offset (get_local $id)))
435 | (if (get_local $offset)(then
436 | (if (i32.ge_u (i32.add (get_local $pos) (i32.const 3)) (call $-len (get_local $id)) )(then
437 | (call $-resize (get_local $id) (i32.add (get_local $pos) (i32.const 4)))
438 | (set_local $offset (call $-offset (get_local $id)))
439 | ))
440 | (i32.store (i32.add (get_local $offset) (get_local $pos)) (get_local $data))
441 | ))
442 | )
443 | (func $-write_to (param $id i32) (param $pos i32) (param $data_id i32)
444 | (local $offset i32)
445 | (local $len i32)
446 | (set_local $offset (call $-offset (get_local $id)))
447 | (set_local $len (call $-len (get_local $data_id)))
448 | (if (get_local $offset)(then
449 | (if (i32.gt_u (i32.add (get_local $pos) (get_local $len)) (call $-len (get_local $id)) )(then
450 | (call $-resize (get_local $id) (i32.add (get_local $pos) (get_local $len)))
451 | (set_local $offset (call $-offset (get_local $id)))
452 | ))
453 | (call $-memcopy (call $-offset (get_local $data_id)) (i32.add (get_local $offset) (get_local $pos)) (get_local $len))
454 | ))
455 | )
456 |
457 | ;; make room for a new value
458 | (global $-next_id (mut i32) (i32.const 0))
459 | (func $-new_value (param $datatype i32) (param $len i32) (result i32)
460 | (local $offset i32)
461 | (local $id i32)
462 | (set_local $id (get_global $-next_id))
463 | (set_local $offset (call $-alloc (get_local $len)))
464 | (block(loop
465 | (br_if 1 (i32.eqz (call $-read32 (i32.const -1) (i32.mul (get_local $id) (i32.const 8)))))
466 | (set_local $id (i32.add (get_local $id) (i32.const 1)))
467 | (br 0)
468 | ))
469 | (call $-write32 (i32.const -1) (i32.mul (get_local $id) (i32.const 8)) (get_local $offset))
470 | (call $-write16 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 4)) (get_global $-calls))
471 | (call $-write8 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 6)) (get_local $datatype))
472 | (call $-write8 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 7)) (i32.const 130))
473 | (set_global $-next_id (i32.add (get_local $id) (i32.const 1)))
474 | (i32.add (get_local $id) (i32.const 8))
475 | )
476 |
477 | ;; mark id as referenced
478 | (func $-ref (param $id i32)
479 | (local $refs i32)
480 | (if (call $-offset (get_local $id))(then
481 | (set_local $id (i32.sub (get_local $id) (i32.const 8)))
482 | (call $-write8 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 7)) (i32.const 1))
483 | ))
484 | )
485 | (global $-hard_value (mut i32) (i32.const 0))
486 | ;; (global $-high_id (mut i32) (i32.const 0))
487 | ;; clear all references in index
488 | (func $-zerorefs
489 | (local $id i32)
490 | (if (i32.eqz (get_global $-hard_value))(then
491 | (set_global $-hard_value (get_global $-next_id))
492 | ))
493 | (set_local $id (i32.div_u (call $-len (i32.const -1)) (i32.const 8)))
494 | ;; (set_global $-high_id (get_global $-hard_value))
495 | (block(loop (br_if 1 (i32.eqz (get_local $id)))
496 | (set_local $id (i32.sub (get_local $id) (i32.const 1)))
497 | (if (i32.lt_u (get_local $id) (get_global $-hard_value))(then
498 | (call $-write16 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 4)) (i32.const 0))
499 | )(else
500 | (call $-write16 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 4)) (i32.const 4))
501 | ))
502 | (br 0)))
503 | )
504 | (global $-passdown_mark (mut i32) (i32.const 1))
505 | ;; pass down reference recursively
506 | (func $-passdown (param $id i32)
507 | (local $offset i32)
508 | (local $datatype i32)
509 | (local $csdepth i32)
510 | (local $mark i32)
511 | (set_local $offset (call $-offset (get_local $id)))
512 | ;; is it even in memory?
513 | (if (get_local $offset) (then
514 | (set_local $id (i32.sub (get_local $id) (i32.const 8)))
515 | (set_local $mark (call $-read8 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 7))))
516 | (set_local $csdepth (call $-read16 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 4))))
517 | ;; is it unreferenced?
518 | (if (i32.or
519 | (i32.ne (get_local $mark) (get_global $-passdown_mark))
520 | (i32.gt_u (get_local $csdepth) (get_global $-calls))
521 | )(then
522 | (call $-write8 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 7)) (get_global $-passdown_mark))
523 | (if (i32.gt_u (get_local $csdepth) (get_global $-calls))(then
524 | (call $-write16 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 4)) (get_global $-calls))
525 | ))
526 | (set_local $datatype (call $-read8 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 6))))
527 | (set_local $id (i32.add (get_local $id) (i32.const 8)))
528 | ;; is it array/object?
529 | (if (i32.eq (i32.and (get_local $datatype) (i32.const 6)) (i32.const 4))(then
530 | (set_local $offset (call $-len (get_local $id)))
531 | (block(loop (br_if 1 (i32.eqz (get_local $offset)))
532 | (set_local $offset (i32.sub (get_local $offset) (i32.const 4)))
533 | (call $-passdown (call $-read32 (get_local $id) (get_local $offset)))
534 | (br 0)))
535 | ))
536 | ))
537 | ))
538 | )
539 |
540 | ;; garbage collector
541 | (func $-garbagecollect
542 | (local $id i32)
543 | (local $csdepth i32)
544 | (local $offset i32)
545 | (local $last_id i32)
546 |
547 | (set_global $-passdown_mark (i32.and (i32.add (get_global $-passdown_mark) (i32.const 1)) (i32.const 127)))
548 | (call $-passdown_globals)
549 | (set_local $id (i32.div_u (call $-len (i32.const -1)) (i32.const 8)))
550 | (block(loop (br_if 1 (i32.eqz (get_local $id)))
551 | (set_local $id (i32.sub (get_local $id) (i32.const 1)))
552 | (set_local $offset (call $-read32 (i32.const -1) (i32.mul (get_local $id) (i32.const 8))))
553 | (set_local $csdepth (call $-read16 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 4))))
554 | (if (get_local $offset)(then
555 | (if (i32.gt_u (get_local $csdepth) (get_global $-calls))(then
556 | (call $-dealloc (get_local $offset))
557 | (set_global $-next_id (get_local $id))
558 | (call $-write32 (i32.const -1) (i32.mul (get_local $id) (i32.const 8)) (i32.const 0))
559 | (call $-write32 (i32.const -1) (i32.add (i32.mul (get_local $id) (i32.const 8)) (i32.const 4)) (i32.const 0))
560 | )(else
561 | (if (i32.eqz (get_local $last_id))(then
562 | (set_local $last_id (get_local $id))
563 | ))
564 | ))
565 | ))
566 | (br 0)))
567 | (set_global $-last_alloc (i32.const 0))
568 | (set_global $-gc_pending (get_global $-calls))
569 | (call $-resize (i32.const -1) (i32.mul (i32.add (get_local $last_id) (i32.const 1)) (i32.const 8)))
570 | )
571 |
572 | (func $-truthy (param $id i32) (result i32)
573 | (local $datatype i32)
574 | (local $truthy i32)
575 | (if (i32.gt_u (get_local $id) (i32.const 4))(then
576 | (set_local $truthy (i32.const 1))
577 | (set_local $datatype (call $-datatype (get_local $id)))
578 | (if (i32.and
579 | (i32.eq (get_local $datatype) (i32.const 2))
580 | (f64.eq (call $-f64 (get_local $id)) (f64.const 0))
581 | )(then
582 | (set_local $truthy (i32.const 0))
583 | ))
584 | (if (i32.and
585 | (i32.eq (get_local $datatype) (i32.const 3))
586 | (i32.eq (call $-len (get_local $id)) (i32.const 0))
587 | )(then
588 | (set_local $truthy (i32.const 0))
589 | ))
590 | ))
591 | (get_local $truthy)
592 | )
593 | (func $-falsy (param $id i32) (result i32)
594 | (i32.eqz (call $-truthy (get_local $id)))
595 | )
596 | (func $-compare (param $id1 i32) (param $id2 i32) (result i32)
597 | (local $res f64)
598 | (local $len i32)
599 | (local $pos i32)
600 | ;; equal reference
601 | (if (i32.eq (get_local $id1) (get_local $id2))(then
602 | (return (i32.const 0))
603 | ))
604 | ;; equal datatype
605 | (if (i32.eq (call $-datatype (get_local $id1)) (call $-datatype (get_local $id2)))(then
606 | ;; array/object
607 | (if (i32.eq
608 | (i32.and (call $-datatype (get_local $id1)) (i32.const 6))
609 | (i32.const 4)
610 | )(then
611 | (return (i32.sub
612 | (get_local $id1)
613 | (get_local $id2)
614 | ))
615 | ))
616 | ;; numerical values
617 | (if (i32.lt_u (call $-datatype (get_local $id1)) (i32.const 3))(then
618 | (set_local $res (f64.sub
619 | (call $-f64 (call $-to_number (get_local $id1)))
620 | (call $-f64 (call $-to_number (get_local $id2)))
621 | ))
622 | (if (f64.eq (get_local $res) (f64.const 0))(then
623 | (return (i32.const 0))
624 | ))
625 | (if (f64.gt (get_local $res) (f64.const 0))(then
626 | (return (i32.const 1))
627 | ))
628 | (if (f64.lt (get_local $res) (f64.const 0))(then
629 | (return (i32.const -1))
630 | ))
631 | )(else ;; strings/binaries
632 | (set_local $pos (i32.const 0))
633 | (if (i32.lt_u
634 | (call $-len (get_local $id1))
635 | (call $-len (get_local $id2))
636 | )(then
637 | (set_local $len (call $-len (get_local $id1)))
638 | )(else
639 | (set_local $len (call $-len (get_local $id2)))
640 | ))
641 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
642 | (if (i32.ne
643 | (call $-read8 (get_local $id1) (get_local $pos))
644 | (call $-read8 (get_local $id2) (get_local $pos))
645 | )(then
646 | (return (i32.sub
647 | (call $-read8 (get_local $id1) (get_local $pos))
648 | (call $-read8 (get_local $id2) (get_local $pos))
649 | ))
650 | ))
651 | (set_local $pos (i32.add (get_local $pos) (i32.const 1)))
652 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
653 | (br 0)))
654 | (return (i32.sub
655 | (call $-len (get_local $id1))
656 | (call $-len (get_local $id2))
657 | ))
658 | ))
659 | )(else ;; unequal datatypes
660 | (return (i32.sub
661 | (call $-datatype (get_local $id1))
662 | (call $-datatype (get_local $id2))
663 | ))
664 | ))
665 | (return (i32.const 0))
666 | )
667 |
668 | (func $-equal (param $id1 i32) (param $id2 i32) (result i32)
669 | (if (call $-compare (get_local $id1) (get_local $id2)) (then
670 | (return (i32.const 1))
671 | ))
672 | (i32.const 5)
673 | )
674 | (func $-unequal (param $id1 i32) (param $id2 i32) (result i32)
675 | (i32.sub (i32.const 6) (call $-equal (get_local $id1) (get_local $id2)))
676 | )
677 | (func $-lt (param $id1 i32) (param $id2 i32) (result i32)
678 | (if (i32.lt_s (call $-compare (get_local $id1) (get_local $id2)) (i32.const 0))(then
679 | (return (i32.const 5))
680 | ))
681 | (i32.const 1)
682 | )
683 | (func $-le (param $id1 i32) (param $id2 i32) (result i32)
684 | (if (i32.le_s (call $-compare (get_local $id1) (get_local $id2)) (i32.const 0))(then
685 | (return (i32.const 5))
686 | ))
687 | (i32.const 1)
688 | )
689 | (func $-gt (param $id1 i32) (param $id2 i32) (result i32)
690 | (if (i32.gt_s (call $-compare (get_local $id1) (get_local $id2)) (i32.const 0))(then
691 | (return (i32.const 5))
692 | ))
693 | (i32.const 1)
694 | )
695 | (func $-ge (param $id1 i32) (param $id2 i32) (result i32)
696 | (if (i32.ge_s (call $-compare (get_local $id1) (get_local $id2)) (i32.const 0))(then
697 | (return (i32.const 5))
698 | ))
699 | (i32.const 1)
700 | )
701 | (func $-and (param $id1 i32) (param $id2 i32) (result i32)
702 | (local $success i32)
703 | (set_local $success (i32.const 1))
704 | (if (call $-truthy (get_local $id1))(then
705 | (set_local $success (get_local $id2))
706 | )(else
707 | (set_local $success (get_local $id1))
708 | ))
709 | (get_local $success)
710 | )
711 | (func $-or (param $id1 i32) (param $id2 i32) (result i32)
712 | (local $success i32)
713 | (set_local $success (i32.const 1))
714 | (if (call $-truthy (get_local $id1))(then
715 | (set_local $success (get_local $id1))
716 | )(else
717 | (set_local $success (get_local $id2))
718 | ))
719 | (get_local $success)
720 | )
721 |
722 | (func $-concat (param $id1 i32) (param $id2 i32) (result i32)
723 | (local $len1 i32)
724 | (local $len2 i32)
725 | (local $datatype i32)
726 | (local $id3 i32)
727 | (local $offset i32)
728 | (set_local $len1 (call $-len (get_local $id1)))
729 | (set_local $len2 (call $-len (get_local $id2)))
730 | (set_local $datatype (call $-datatype (get_local $id1)))
731 | (set_local $id3 (call $-new_value (get_local $datatype) (i32.add (get_local $len1) (get_local $len2))))
732 | (call $-memcopy (call $-offset (get_local $id1)) (call $-offset (get_local $id3)) (get_local $len1))
733 | (call $-memcopy (call $-offset (get_local $id2)) (i32.add (call $-offset (get_local $id3)) (get_local $len1)) (get_local $len2))
734 | ;; (call $-resize (get_local $id3) (i32.add (get_local $len1) (get_local $len2)))
735 | (get_local $id3)
736 | )
737 |
738 | (func $-to_number (param $id i32) (result i32)
739 | (local $datatype i32)
740 | (local $id3 i32)
741 | (set_local $datatype (call $-datatype (get_local $id)))
742 | (set_local $id3 (i32.const 2))
743 | (if (i32.lt_u (get_local $id) (i32.const 2))(then
744 | (set_local $id3 (i32.const 2))
745 | ))
746 | (if (i32.eq (get_local $id) (i32.const 5))(then
747 | (set_local $id3 (call $-integer_u (i32.const 1)))
748 | ))
749 | (if (i32.eq (get_local $datatype) (i32.const 2))(then
750 | (set_local $id3 (get_local $id))
751 | ))
752 | (get_local $id3)
753 | )
754 |
755 | (func $-to_string (param $id i32) (result i32)
756 | (local $datatype i32)
757 | (local $id3 i32)
758 | (local $digit f64)
759 | (local $decimals i32)
760 | (local $pos i32)
761 | (set_local $datatype (call $-datatype (get_local $id)))
762 | (set_local $id3 (get_local $id))
763 | (if (i32.eq (get_local $id) (i32.const 0))(then
764 | (set_local $id3 (call $-new_value (i32.const 3) (i32.const 4)))
765 | (call $-write32 (get_local $id3) (i32.const 0) (i32.const 0x6c6c756e));;null
766 | ))
767 | (if (i32.eq (get_local $id) (i32.const 1))(then
768 | (set_local $id3 (call $-new_value (i32.const 3) (i32.const 5)))
769 | (call $-write32 (get_local $id3) (i32.const 0) (i32.const 0x736c6166));;fals
770 | (call $-write8 (get_local $id3) (i32.const 4) (i32.const 0x65));;e
771 | ))
772 | (if (i32.eq (get_local $id) (i32.const 5))(then
773 | (set_local $id3 (call $-new_value (i32.const 3) (i32.const 4)))
774 | (call $-write32 (get_local $id3) (i32.const 0) (i32.const 0x65757274));;true
775 | ))
776 | (if (i32.eq (get_local $datatype) (i32.const 2))(then ;; number
777 | (set_local $id3 (call $-new_value (i32.const 3) (i32.const 0)))
778 | (set_local $digit (call $-f64 (get_local $id)))
779 | (if (f64.lt (get_local $digit) (f64.const 0))(then
780 | (call $-write8 (get_local $id3) (get_local $pos) (i32.const 0x2d));; -
781 | (set_local $pos (i32.add (get_local $pos) (i32.const 1)))
782 | (set_local $digit (f64.mul (get_local $digit) (f64.const -1)))
783 | ))
784 | (call $-write8 (get_local $id3) (get_local $pos) (i32.const 0x30));; 0
785 | (block(loop (br_if 1 (f64.lt (get_local $digit) (f64.const 1)))
786 | (set_local $digit (f64.div (get_local $digit) (f64.const 10)))
787 | (call $-write8 (get_local $id3) (get_local $pos) (i32.const 0x30));; 0
788 | (set_local $pos (i32.add (get_local $pos) (i32.const 1)))
789 | (br 0)
790 | ))
791 | (set_local $decimals (i32.trunc_u/f64 (f64.trunc (f64.abs (call $-f64 (get_local $id))))))
792 | (block(loop (br_if 1 (i32.eqz (get_local $decimals)))
793 | (set_local $pos (i32.sub (get_local $pos) (i32.const 1)))
794 | (call $-write8 (get_local $id3) (get_local $pos) (i32.add (i32.const 0x30) (i32.rem_u (get_local $decimals) (i32.const 10))))
795 | (set_local $decimals (i32.div_u (get_local $decimals) (i32.const 10)))
796 | (br 0)))
797 | (set_local $pos (call $-len (get_local $id3)))
798 | (set_local $decimals (i32.const 0))
799 | (set_local $digit (f64.abs (call $-f64 (get_local $id))))
800 | (set_local $digit (f64.sub (get_local $digit) (f64.trunc (get_local $digit))))
801 | (if (f64.gt (get_local $digit) (f64.const 0.00001))(then
802 | (call $-write8 (get_local $id3) (get_local $pos) (i32.const 0x2e));; .
803 | (set_local $pos (i32.add (get_local $pos) (i32.const 1)))
804 | (set_local $digit (f64.mul (get_local $digit) (f64.const 10)))
805 | (block(loop
806 | (br_if 1 (i32.ge_s (get_local $decimals) (i32.const 16)))
807 | (call $-write8 (get_local $id3) (get_local $pos) (i32.add (i32.const 0x30) (i32.trunc_s/f64 (f64.trunc (get_local $digit)))))
808 | (set_local $pos (i32.add (get_local $pos) (i32.const 1)))
809 | (set_local $digit (f64.sub (get_local $digit) (f64.trunc (get_local $digit))))
810 | (set_local $digit (f64.mul (get_local $digit) (f64.const 10)))
811 | (if (f64.le (get_local $digit) (f64.const 0.00001))(then
812 | (set_local $decimals (i32.const 1024))
813 | ))
814 | (set_local $decimals (i32.add (get_local $decimals) (i32.const 1)))
815 | (br 0)
816 | ))
817 | ))
818 | ))
819 | (if (i32.eq (get_local $datatype) (i32.const 4))(then
820 | (set_local $id3 (call $-new_value (i32.const 3) (i32.const 5)))
821 | (call $-write32 (get_local $id3) (i32.const 0) (i32.const 0x61727261));;arra
822 | (call $-write8 (get_local $id3) (i32.const 4) (i32.const 0x79));;y
823 | ))
824 | (if (i32.eq (get_local $datatype) (i32.const 5))(then
825 | (set_local $id3 (call $-new_value (i32.const 3) (i32.const 6)))
826 | (call $-write32 (get_local $id3) (i32.const 0) (i32.const 0x656a626f));;obje
827 | (call $-write16 (get_local $id3) (i32.const 4) (i32.const 0x7463));;ct
828 | ))
829 | (if (i32.eq (get_local $datatype) (i32.const 6))(then
830 | (set_local $id3 (call $-concat (i32.const 3) (get_local $id)))
831 | ))
832 | (get_local $id3)
833 | )
834 |
835 | (func $-to_hex (param $int i32) (param $digits i32) (result i32)
836 | (local $str i32)
837 | (local $dig i32)
838 | (set_local $str (call $-new_value (i32.const 3) (get_local $digits)))
839 | (block(loop (br_if 1 (i32.eqz (get_local $digits)))
840 | (set_local $digits (i32.sub (get_local $digits) (i32.const 1)))
841 | (set_local $dig (i32.and (get_local $int) (i32.const 0xf)))
842 | (set_local $int (i32.div_u (get_local $int) (i32.const 0x10)))
843 | (if (i32.lt_u (get_local $dig) (i32.const 0xa))(then
844 | (call $-write8 (get_local $str) (get_local $digits) (i32.add (i32.const 0x30) (get_local $dig)))
845 | )(else
846 | (call $-write8 (get_local $str) (get_local $digits) (i32.add (i32.const 0x57) (get_local $dig)))
847 | ))
848 | (br 0)))
849 | (get_local $str)
850 | )
851 | (func $-from_hex (param $str i32) (result i32)
852 | (local $int i32)
853 | (local $dig i32)
854 | (local $pos i32)
855 | (local $len i32)
856 | (set_local $len (call $-len (get_local $str)))
857 | (block(loop (br_if 1 (i32.ge_u (get_local $pos) (get_local $len)))
858 | (set_local $int (i32.mul (get_local $int) (i32.const 0x10)))
859 | (set_local $dig (call $-read8 (get_local $str) (get_local $pos)))
860 | (if (i32.gt_u (get_local $dig) (i32.const 0x5f))(then
861 | (set_local $dig (i32.sub (get_local $dig) (i32.const 0x20)))
862 | ))
863 | (if (i32.lt_u (get_local $dig) (i32.const 0x40))(then
864 | (set_local $int (i32.add (get_local $int) (i32.sub (get_local $dig) (i32.const 0x30))))
865 | )(else
866 | (set_local $int (i32.add (get_local $int) (i32.sub (get_local $dig) (i32.const 0x37))))
867 | ))
868 | (set_local $pos (i32.add (get_local $pos) (i32.const 1)))
869 | (br 0)))
870 | (get_local $int)
871 | )
872 |
873 | (global $-parsing_offset (mut i32) (i32.const 0))
874 | (func $-parse_integer (param $offset i32) (param $base i32) (result i64)
875 | (local $result i64)
876 | (local $neg i32)
877 | (local $char i32)
878 | (local $digit i32)
879 | (if (i32.eqz (get_local $offset))(then
880 | (set_local $offset (get_global $-parsing_offset))
881 | ))
882 | (if (i32.eqz (get_local $base))(then
883 | (set_local $base (i32.const 10))
884 | ))
885 | (set_local $neg (i32.const 1))
886 | (set_local $char (i32.load8_u (get_local $offset)))
887 | (if (i32.eq (get_local $char) (i32.const 0x2d))(then ;; -
888 | (set_local $neg (i32.const -1))
889 | (set_local $char (i32.const 0x30))
890 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
891 | ))
892 | (if (i32.eq (get_local $char) (i32.const 0x2b))(then ;; +
893 | (set_local $neg (i32.const 1))
894 | (set_local $char (i32.const 0x30))
895 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
896 | ))
897 | (block(loop
898 | (set_local $char (i32.load8_u (get_local $offset)))
899 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
900 | (br_if 1 (i32.lt_u (get_local $char) (i32.const 0x30)))
901 | (set_local $digit (i32.sub (get_local $char) (i32.const 0x30)))
902 | (if (i32.gt_u (get_local $digit) (i32.const 0x9))(then
903 | (set_local $digit (i32.sub (get_local $digit) (i32.const 0x7)))
904 | ))
905 | (if (i32.gt_u (get_local $digit) (i32.const 0x29))(then
906 | (set_local $digit (i32.sub (get_local $digit) (i32.const 0x20)))
907 | ))
908 | (if (i32.eq (get_local $digit) (i32.const 0x21))(then ;; x
909 | (set_local $base (i32.const 0x10))
910 | (set_local $digit (i32.const 0x0))
911 | ))
912 | (br_if 1 (i32.ge_u (get_local $digit) (get_local $base)))
913 | (set_local $result (i64.mul (get_local $result) (i64.extend_u/i32 (get_local $base))))
914 | (set_local $result (i64.add (get_local $result) (i64.extend_u/i32 (get_local $digit))))
915 | (br 0)))
916 | (set_local $offset (i32.sub (get_local $offset) (i32.const 1)))
917 | (set_global $-parsing_offset (get_local $offset))
918 | (tee_local $result (i64.mul (get_local $result) (i64.extend_s/i32 (get_local $neg))))
919 | ;; (call $logNumber (f64.convert_s/i64 (get_local $result)))
920 | )
921 | (func $-parse_float (param $offset i32) (param $base i32) (result f64)
922 | (local $iresult f64)
923 | (local $dresult f64)
924 | (local $int i64)
925 | (local $dec i64)
926 | (local $declen i64)
927 | (local $exp i64)
928 | (local $pow i64)
929 | (local $neg f64)
930 | (local $k f64)
931 | (local $char i32)
932 | ;; (call $logNumber (f64.const 0xcafebabe) )
933 | ;; default params
934 | (if (i32.eqz (get_local $offset))(then
935 | (set_local $offset (get_global $-parsing_offset))
936 | ))
937 | (if (i32.eqz (get_local $base))(then
938 | (set_local $base (i32.const 10))
939 | ))
940 | ;; read sign
941 | (set_local $neg (f64.const 1))
942 | (set_local $char (i32.load8_u (get_local $offset)))
943 | (if (i32.eq (get_local $char) (i32.const 0x2d))(then ;; -
944 | (set_local $neg (f64.const -1))
945 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
946 | ))
947 | (if (i32.eq (get_local $char) (i32.const 0x2b))(then ;; +
948 | (set_local $neg (f64.const 1))
949 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
950 | ))
951 | ;; read base
952 | (set_local $char (i32.load16_u (get_local $offset)))
953 | (if (i32.eq (get_local $char) (i32.const 0x5830))(then ;; 0X
954 | (set_local $base (i32.const 0x10))
955 | (set_local $offset (i32.add (get_local $offset) (i32.const 2)))
956 | ))
957 | (if (i32.eq (get_local $char) (i32.const 0x7830))(then ;; 0x
958 | (set_local $base (i32.const 0x10))
959 | (set_local $offset (i32.add (get_local $offset) (i32.const 2)))
960 | ))
961 | ;; read integer
962 | (set_local $int (call $-parse_integer (get_local $offset) (get_local $base)))
963 | (set_local $offset (get_global $-parsing_offset))
964 | ;; read decimals
965 | (set_local $char (i32.load8_u (get_local $offset)))
966 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
967 | (if (i32.eq (get_local $char) (i32.const 0x2e))(then ;; .
968 | (set_local $dec (call $-parse_integer (get_local $offset) (get_local $base)))
969 | (set_local $declen (i64.extend_u/i32 (i32.sub (get_global $-parsing_offset) (get_local $offset))))
970 | (set_local $offset (get_global $-parsing_offset))
971 | (set_local $char (i32.load8_u (get_local $offset)))
972 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
973 | ))
974 | ;; read exponent
975 | (if (i32.ge_u (get_local $char) (i32.const 0x60))(then
976 | (set_local $char (i32.sub (get_local $char) (i32.const 0x20)))
977 | ))
978 | (if (i32.eq (get_local $char) (i32.const 0x45))(then ;; E
979 | (set_local $exp (call $-parse_integer (get_local $offset) (i32.const 0)))
980 | ))
981 | (if (i32.eq (get_local $char) (i32.const 0x50))(then ;; P
982 | (set_local $pow (call $-parse_integer (get_local $offset) (i32.const 0)))
983 | ))
984 |
985 | ;; calc decimals
986 | (set_local $dresult (f64.convert_u/i64 (get_local $dec)))
987 | (set_local $declen (i64.sub (get_local $exp) (get_local $declen)))
988 | (if (i64.lt_s (get_local $declen) (i64.const 0))(then
989 | (set_local $k (f64.const -1))
990 | )(else
991 | (set_local $k (f64.const 1))
992 | ))
993 | (block(loop (br_if 1 (i64.ge_s (get_local $declen) (i64.const 0)))
994 | (set_local $k (f64.mul (get_local $k) (f64.convert_u/i32 (get_local $base))))
995 | (set_local $declen (i64.add (get_local $declen) (i64.const 1)))
996 | (br 0)))
997 | (block(loop (br_if 1 (i64.le_s (get_local $declen) (i64.const 0)))
998 | (set_local $k (f64.mul (get_local $k) (f64.convert_u/i32 (get_local $base))))
999 | (set_local $declen (i64.sub (get_local $declen) (i64.const 1)))
1000 | (br 0)))
1001 | (if (f64.lt (get_local $k) (f64.const 0))(then
1002 | (set_local $k (f64.mul (get_local $k) (f64.const -1)))
1003 | (set_local $dresult (f64.div (get_local $dresult) (get_local $k)))
1004 | )(else
1005 | (set_local $dresult (f64.mul (get_local $dresult) (get_local $k)))
1006 | ))
1007 |
1008 | ;; calc integer
1009 | (set_local $iresult (f64.convert_u/i64 (get_local $int)))
1010 | (if (i64.lt_s (get_local $exp) (i64.const 0))(then
1011 | (set_local $k (f64.const -1))
1012 | )(else
1013 | (set_local $k (f64.const 1))
1014 | ))
1015 | (block(loop (br_if 1 (i64.ge_s (get_local $exp) (i64.const 0)))
1016 | (set_local $k (f64.mul (get_local $k) (f64.convert_u/i32 (get_local $base))))
1017 | (set_local $exp (i64.add (get_local $exp) (i64.const 1)))
1018 | (br 0)))
1019 | (block(loop (br_if 1 (i64.le_s (get_local $exp) (i64.const 0)))
1020 | (set_local $k (f64.mul (get_local $k) (f64.convert_u/i32 (get_local $base))))
1021 | (set_local $exp (i64.sub (get_local $exp) (i64.const 1)))
1022 | (br 0)))
1023 | (if (f64.lt (get_local $k) (f64.const 0))(then
1024 | (set_local $k (f64.mul (get_local $k) (f64.const -1)))
1025 | (set_local $iresult (f64.div (get_local $iresult) (get_local $k)))
1026 | )(else
1027 | (set_local $iresult (f64.mul (get_local $iresult) (get_local $k)))
1028 | ))
1029 |
1030 | ;; apply power
1031 | (block(loop (br_if 1 (i64.ge_s (get_local $pow) (i64.const 0)))
1032 | (set_local $iresult (f64.div (get_local $iresult) (f64.const 2)))
1033 | (set_local $dresult (f64.div (get_local $dresult) (f64.const 2)))
1034 | (set_local $pow (i64.add (get_local $pow) (i64.const 1)))
1035 | (br 0)))
1036 | (block(loop (br_if 1 (i64.le_s (get_local $pow) (i64.const 0)))
1037 | (set_local $iresult (f64.mul (get_local $iresult) (f64.const 2)))
1038 | (set_local $dresult (f64.mul (get_local $dresult) (f64.const 2)))
1039 | (set_local $pow (i64.sub (get_local $pow) (i64.const 1)))
1040 | (br 0)))
1041 |
1042 | ;; put it all together
1043 | (f64.mul (get_local $neg) (f64.add (get_local $iresult) (get_local $dresult)))
1044 | )
1045 |
1046 | (func $-inc (param $num i32) (param $delta f64) (result i32)
1047 | (local $offset i32)
1048 | (local $float f64)
1049 | (set_local $offset (call $-offset (get_local $num)))
1050 | (if (get_local $offset)(then
1051 | (set_local $float (f64.load (get_local $offset)))
1052 | (f64.store (get_local $offset) (f64.add (get_local $float) (get_local $delta)))
1053 | )(else
1054 | (set_local $num (call $-number (get_local $delta)))
1055 | ))
1056 | (get_local $num)
1057 | )
1058 |
1059 | (func $-add (param $id1 i32) (param $id2 i32) (result i32)
1060 | (local $datatype1 i32)
1061 | (local $datatype2 i32)
1062 | (local $id3 i32)
1063 | (set_local $datatype1 (call $-datatype (get_local $id1)))
1064 | (set_local $datatype2 (call $-datatype (get_local $id2)))
1065 | ;; numerical values
1066 | (if (i32.and (i32.lt_u (get_local $datatype1) (i32.const 3)) (i32.lt_u (get_local $datatype2) (i32.const 3)))(then
1067 | (set_local $id3
1068 | (call $-number
1069 | (f64.add
1070 | (call $-f64 (call $-to_number(get_local $id1)) )
1071 | (call $-f64 (call $-to_number(get_local $id2)) )
1072 | )
1073 | )
1074 | )
1075 | )(else
1076 | ;; is one of them a string?
1077 | (if (i32.or (i32.eq (get_local $datatype1) (i32.const 3)) (i32.eq (get_local $datatype2) (i32.const 3)))(then
1078 | (set_local $id3 (call $-concat
1079 | (call $-to_string (get_local $id1))
1080 | (call $-to_string (get_local $id2))
1081 | ))
1082 | )(else
1083 | ;; both the same datatype?
1084 | (if (i32.eq (get_local $datatype1) (get_local $datatype2) )(then
1085 | (set_local $id3 (call $-concat
1086 | (get_local $id1)
1087 | (get_local $id2)
1088 | ))
1089 | ))
1090 | ))
1091 | ))
1092 | (get_local $id3)
1093 | )
1094 | (func $-sub (param $id1 i32) (param $id2 i32) (result i32)
1095 | (local $datatype1 i32)
1096 | (local $datatype2 i32)
1097 | (local $id3 i32)
1098 | (set_local $datatype1 (call $-datatype (get_local $id1)))
1099 | (set_local $datatype2 (call $-datatype (get_local $id2)))
1100 | ;; numerical values
1101 | (if (i32.and (i32.lt_u (get_local $datatype1) (i32.const 3)) (i32.lt_u (get_local $datatype2) (i32.const 3)))(then
1102 | (set_local $id3
1103 | (call $-number
1104 | (f64.sub
1105 | (call $-f64 (call $-to_number(get_local $id1)) )
1106 | (call $-f64 (call $-to_number(get_local $id2)) )
1107 | )
1108 | )
1109 | )
1110 | ))
1111 | (get_local $id3)
1112 | )
1113 | (func $-mul (param $id1 i32) (param $id2 i32) (result i32)
1114 | (local $datatype1 i32)
1115 | (local $datatype2 i32)
1116 | (local $id3 i32)
1117 | (set_local $datatype1 (call $-datatype (get_local $id1)))
1118 | (set_local $datatype2 (call $-datatype (get_local $id2)))
1119 | ;; numerical values
1120 | (if (i32.and (i32.lt_u (get_local $datatype1) (i32.const 3)) (i32.lt_u (get_local $datatype2) (i32.const 3)))(then
1121 | (set_local $id3
1122 | (call $-number
1123 | (f64.mul
1124 | (call $-f64 (call $-to_number(get_local $id1)) )
1125 | (call $-f64 (call $-to_number(get_local $id2)) )
1126 | )
1127 | )
1128 | )
1129 | ))
1130 | (get_local $id3)
1131 | )
1132 | (func $-div (param $id1 i32) (param $id2 i32) (result i32)
1133 | (local $datatype1 i32)
1134 | (local $datatype2 i32)
1135 | (local $id3 i32)
1136 | (set_local $datatype1 (call $-datatype (get_local $id1)))
1137 | (set_local $datatype2 (call $-datatype (get_local $id2)))
1138 | ;; numerical values
1139 | (if (i32.and (i32.lt_u (get_local $datatype1) (i32.const 3)) (i32.lt_u (get_local $datatype2) (i32.const 3)))(then
1140 | (set_local $id3
1141 | (call $-number
1142 | (f64.div
1143 | (call $-f64 (call $-to_number(get_local $id1)) )
1144 | (call $-f64 (call $-to_number(get_local $id2)) )
1145 | )
1146 | )
1147 | )
1148 | ))
1149 | (get_local $id3)
1150 | )
1151 | (func $-mod (param $id1 i32) (param $id2 i32) (result i32)
1152 | (local $datatype1 i32)
1153 | (local $datatype2 i32)
1154 | (local $f1 f64)
1155 | (local $f2 f64)
1156 | (local $f3 f64)
1157 | (local $id3 i32)
1158 | (set_local $datatype1 (call $-datatype (get_local $id1)))
1159 | (set_local $datatype2 (call $-datatype (get_local $id2)))
1160 | ;; numerical values
1161 | (if (i32.and (i32.lt_u (get_local $datatype1) (i32.const 3)) (i32.lt_u (get_local $datatype2) (i32.const 3)))(then
1162 | (set_local $f1 (call $-f64 (call $-to_number(get_local $id1)) ))
1163 | (set_local $f2 (f64.abs (call $-f64 (call $-to_number(get_local $id2)) )))
1164 | (set_local $f3 (f64.trunc (f64.div (get_local $f1) (get_local $f2))))
1165 | (set_local $f1 (f64.sub (get_local $f1) (f64.mul (get_local $f2) (get_local $f3))))
1166 | (set_local $id3 (call $-number (get_local $f1) ) )
1167 | ))
1168 | (get_local $id3)
1169 | )
1170 |
1171 | (func $-f64 (param $id i32) (result f64)
1172 | (local $val f64)
1173 | (if (i32.gt_u (get_local $id) (i32.const 4))(then
1174 | (set_local $val (f64.load (call $-offset (get_local $id))))
1175 | ))
1176 | (get_local $val)
1177 | )
1178 | (func $-i32_s (param $id i32) (result i32)
1179 | (i32.trunc_s/f64 (call $-f64 (get_local $id)))
1180 | )
1181 | (func $-i32_u (param $id i32) (result i32)
1182 | (i32.trunc_u/f64 (call $-f64 (get_local $id)))
1183 | )
1184 |
1185 | (func $-number (param $val f64) (result i32)
1186 | (local $id i32)
1187 | (set_local $id (i32.const 2))
1188 | (if (f64.ne (get_local $val) (f64.const 0))(then
1189 | (set_local $id (call $-new_value (i32.const 2) (i32.const 0)))
1190 | (f64.store (call $-offset (get_local $id)) (get_local $val))
1191 | ))
1192 | (get_local $id)
1193 | )
1194 | (func $-integer_s (param $val i32) (result i32)
1195 | (call $-number (f64.convert_s/i32 (get_local $val)))
1196 | )
1197 | (func $-integer_u (param $val i32) (result i32)
1198 | (call $-number (f64.convert_u/i32 (get_local $val)))
1199 | )
1200 |
1201 | (func $-string (param $offset i32) (param $len i32) (result i32)
1202 | (local $id i32)
1203 | (set_local $id (call $-new_value (i32.const 3) (get_local $len)))
1204 | (call $-memcopy (get_local $offset) (call $-offset (get_local $id)) (get_local $len))
1205 | (call $-ref (get_local $id))
1206 | (get_local $id)
1207 | )
1208 | (func $-char_size (param $byte i32) (result i32)
1209 | (local $size i32)
1210 | (if (i32.ge_u (get_local $byte) (i32.const 0x01))(then
1211 | (set_local $size (i32.add (get_local $size) (i32.const 1)))
1212 | ))
1213 | (if (i32.ge_u (get_local $byte) (i32.const 0xc0))(then
1214 | (set_local $size (i32.add (get_local $size) (i32.const 1)))
1215 | ))
1216 | (if (i32.ge_u (get_local $byte) (i32.const 0xe0))(then
1217 | (set_local $size (i32.add (get_local $size) (i32.const 1)))
1218 | ))
1219 | (if (i32.ge_u (get_local $byte) (i32.const 0xf0))(then
1220 | (set_local $size (i32.add (get_local $size) (i32.const 1)))
1221 | ))
1222 | (if (i32.ge_u (get_local $byte) (i32.const 0xf8))(then
1223 | (set_local $size (i32.add (get_local $size) (i32.const 1)))
1224 | ))
1225 | (if (i32.ge_u (get_local $byte) (i32.const 0xfc))(then
1226 | (set_local $size (i32.add (get_local $size) (i32.const 1)))
1227 | ))
1228 | (if (i32.ge_u (get_local $byte) (i32.const 0xfe))(then
1229 | (set_local $size (i32.add (get_local $size) (i32.const 1)))
1230 | ))
1231 | (if (i32.ge_u (get_local $byte) (i32.const 0xff))(then
1232 | (set_local $size (i32.add (get_local $size) (i32.const 1)))
1233 | ))
1234 | (get_local $size)
1235 | )
1236 | (func $-bytes_to_chars (param $start i32) (param $bytes i32) (result i32)
1237 | (local $pos i32)
1238 | (local $len i32)
1239 | (local $charlen i32)
1240 | (local $chars i32)
1241 | (set_local $pos (get_local $start))
1242 | (set_local $len (get_local $bytes))
1243 | (block(loop (br_if 1 (i32.le_s (get_local $len) (i32.const 0)))
1244 | (set_local $charlen (call $-char_size (i32.load8_u (get_local $pos))))
1245 | (if (get_local $charlen)(then
1246 | (set_local $len (i32.sub (get_local $len) (get_local $charlen)))
1247 | (set_local $pos (i32.add (get_local $pos) (get_local $charlen)))
1248 | (set_local $chars (i32.add (get_local $chars) (i32.const 1)))
1249 | )(else
1250 | (set_local $len (i32.const 0))
1251 | ))
1252 | (br 0) ))
1253 | (get_local $chars)
1254 | )
1255 | (func $-chars_to_bytes (param $start i32) (param $chars i32) (result i32)
1256 | (local $pos i32)
1257 | (local $byte i32)
1258 | (set_local $pos (get_local $start))
1259 | (block(loop (br_if 1 (i32.le_s (get_local $chars) (i32.const 0)))
1260 | (set_local $byte (i32.load8_u (get_local $pos)))
1261 | (set_local $pos (i32.add (get_local $pos) (call $-char_size (get_local $byte))))
1262 | (set_local $chars (i32.sub (get_local $chars) (i32.const 1)))
1263 | (br 0) ))
1264 | (i32.sub (get_local $pos) (get_local $start))
1265 | )
1266 | (func $-char (param $code i32) (result i32)
1267 | (local $str i32)
1268 | (local $pos i32)
1269 | (local $max i32)
1270 | (local $charlen i32)
1271 | (if (i32.lt_u (get_local $code) (i32.const 0x80))(then
1272 | (set_local $str (call $-new_value (i32.const 3) (i32.const 1)))
1273 | (call $-write8 (get_local $str) (get_local $pos) (get_local $code))
1274 | )(else
1275 | (set_local $max (i32.const 1))
1276 | (block(loop (br_if 1 (i32.gt_u (get_local $max) (get_local $code)))
1277 | (set_local $charlen (i32.add (get_local $charlen) (i32.const 1)))
1278 | (set_local $max (i32.shl (get_local $max) (i32.const 5)))
1279 | (br 0)))
1280 | (set_local $str (call $-new_value (i32.const 3) (get_local $charlen)))
1281 | (block(loop (br_if 1 (i32.eqz (get_local $charlen)))
1282 | (set_local $charlen (i32.sub (get_local $charlen) (i32.const 1)))
1283 | (call $-write8 (get_local $str) (get_local $charlen) (i32.or
1284 | (i32.const 128)
1285 | (i32.and
1286 | (get_local $code)
1287 | (i32.const 0x3f)
1288 | )
1289 | ))
1290 | (set_local $code (i32.shr_u (get_local $code) (i32.const 6)))
1291 | (br 0)))
1292 | (set_local $max (i32.const 0xffff00))
1293 | (set_local $max (i32.shr_u (get_local $max) (call $-len (get_local $str))))
1294 | (call $-write8 (get_local $str) (get_local $charlen) (i32.or
1295 | (get_local $max)
1296 | (call $-read8 (get_local $str) (get_local $charlen))
1297 | ))
1298 | ))
1299 | (get_local $str)
1300 | )
1301 | (func $-char_code (param $offset i32) (result i32)
1302 | (local $code i32)
1303 | (local $charlen i32)
1304 | (local $mask i32)
1305 | (set_local $charlen (call $-char_size (i32.load8_u (get_local $offset))))
1306 | (set_local $mask (i32.const 0xff))
1307 | (set_local $mask (i32.shr_u (get_local $mask) (get_local $charlen)))
1308 | (block(loop (br_if 1 (i32.eqz (get_local $charlen)))
1309 | (set_local $code (i32.shl (get_local $code) (i32.const 6)))
1310 | (set_local $code (i32.add
1311 | (get_local $code)
1312 | (i32.and
1313 | (i32.load8_u (get_local $offset))
1314 | (get_local $mask)
1315 | )
1316 | ))
1317 | (set_local $mask (i32.const 0x3f))
1318 | (set_local $offset (i32.add (get_local $offset) (i32.const 1)))
1319 | (set_local $charlen (i32.sub (get_local $charlen) (i32.const 1)))
1320 | (br 0)))
1321 | (get_local $code)
1322 | )
1323 |
1324 |
1325 | (func $-get_from_obj (param $objId i32) (param $indexId i32) (result i32)
1326 | (local $elem i32)
1327 | (local $index i32)
1328 | (if (i32.eq (call $-datatype (get_local $indexId)) (i32.const 2))(then
1329 | (set_local $index (call $-i32_u (get_local $indexId)))
1330 | (set_local $elem (call $-read32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4))))
1331 | )(else
1332 | (set_local $elem (call $-read32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4))))
1333 | (block(loop
1334 | (if (i32.eqz (get_local $elem))(then
1335 | (set_local $elem (get_local $indexId))
1336 | ))
1337 | (br_if 1 (call $-truthy (call $-equal (get_local $elem) (get_local $indexId))))
1338 | (set_local $index (i32.add (get_local $index) (i32.const 2)))
1339 | (set_local $elem (call $-read32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4))))
1340 | (br 0)))
1341 | (set_local $index (i32.add (get_local $index) (i32.const 1)))
1342 | (set_local $elem (call $-read32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4))))
1343 | ))
1344 | (get_local $elem)
1345 | )
1346 | (func $-set_to_obj (param $objId i32) (param $indexId i32) (param $valId i32)
1347 | (local $elem i32)
1348 | (local $index i32)
1349 | (local $len i32)
1350 | (if (i32.eq (call $-datatype (get_local $indexId)) (i32.const 2))(then
1351 | (set_local $index (call $-i32_u (get_local $indexId)))
1352 | (call $-write32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4)) (get_local $valId))
1353 | )(else
1354 | (set_local $elem (call $-read32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4))))
1355 | (block(loop
1356 | (if (i32.eqz (get_local $elem))(then
1357 | (call $-write32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4)) (get_local $indexId))
1358 | (set_local $elem (get_local $indexId))
1359 | ))
1360 | (br_if 1 (call $-truthy (call $-equal (get_local $elem) (get_local $indexId))))
1361 | (set_local $index (i32.add (get_local $index) (i32.const 2)))
1362 | (set_local $elem (call $-read32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4))))
1363 | (br 0)))
1364 | (set_local $index (i32.add (get_local $index) (i32.const 1)))
1365 | (call $-write32 (get_local $objId) (i32.mul (get_local $index) (i32.const 4)) (get_local $valId))
1366 | (if (i32.eqz (get_local $valId))(then
1367 | (set_local $len (call $-len (get_local $objId)))
1368 | (set_local $len (i32.sub (get_local $len) (i32.mul (get_local $index) (i32.const 4))))
1369 | (call $-memcopy
1370 | (i32.add (call $-offset (get_local $objId)) (i32.mul (i32.add (get_local $index) (i32.const 1)) (i32.const 4)))
1371 | (i32.add (call $-offset (get_local $objId)) (i32.mul (i32.sub (get_local $index) (i32.const 1)) (i32.const 4)))
1372 | (get_local $len)
1373 | )
1374 | (call $-resize (get_local $objId) (i32.sub (call $-len (get_local $objId)) (i32.const 8)))
1375 | ))
1376 | ))
1377 | )
1378 |
--------------------------------------------------------------------------------
/stdlib.wast:
--------------------------------------------------------------------------------
1 | ;; general value functions
2 | (func $address_of (param $value i32) (result i32)
3 | (call $-integer_u (call $-offset (get_local $value)))
4 | )
5 | (func $size_of (param $value i32) (result i32)
6 | (call $-integer_u (call $-len (get_local $value)))
7 | )
8 | (func $datatype_of (param $value i32) (result i32)
9 | (call $-integer_u (call $-datatype (get_local $value)))
10 | )
11 |
12 | ;; binary functions
13 | (func $binary_string (param $len i32) (result i32)
14 | (call $-new_value (i32.const 6) (call $-i32_u (get_local $len)))
15 | )
16 | (func $binary_slice (param $binary i32) (param $start i32) (param $len i32) (result i32)
17 | (local $out i32)
18 | (set_local $start (call $-i32_u (get_local $start)))
19 | (set_local $len (call $-i32_u (get_local $len)) )
20 | (if (i32.lt_u (call $-len (get_local $binary)) (get_local $start))(then
21 | (set_local $start (call $-len (get_local $binary)))
22 | ))
23 | (if (i32.lt_u (i32.sub (call $-len (get_local $binary)) (get_local $start)) (get_local $len))(then
24 | (set_local $len (i32.sub (call $-len (get_local $binary)) (get_local $start)))
25 | ))
26 | (set_local $out (call $-new_value (i32.const 6) (get_local $len)))
27 | (call $-memcopy
28 | (i32.add (call $-offset (get_local $binary)) (get_local $start))
29 | (call $-offset (get_local $out))
30 | (get_local $len)
31 | )
32 | (get_local $out)
33 | )
34 | (func $binary_search (param $binary i32) (param $subbin i32) (param $start i32) (result i32)
35 | (local $sub i32)
36 | (if (i32.lt_u (call $-len (get_local $binary)) (call $-len (get_local $subbin))) (then
37 | (return (i32.const 0))
38 | ))
39 | (set_local $start (call $-i32_u (get_local $start)))
40 | (set_local $sub (call $-new_value (call $-datatype (get_local $subbin)) (call $-len (get_local $subbin))))
41 | (block(loop
42 | (br_if 1 (i32.gt_u (get_local $start) (i32.sub (call $-len (get_local $binary)) (call $-len (get_local $subbin)))))
43 | (call $-memcopy
44 | (i32.add (call $-offset (get_local $binary)) (get_local $start))
45 | (call $-offset (get_local $sub))
46 | (call $-len (get_local $sub))
47 | )
48 | (if (i32.eqz (call $-compare (get_local $sub) (get_local $subbin))) (then
49 | (return (call $-integer_u (get_local $start)))
50 | ))
51 | (set_local $start (i32.add (get_local $start) (i32.const 1)))
52 | (br 0)
53 | ))
54 | (i32.const 0)
55 | )
56 | (func $binary_read (param $binary i32) (param $pos i32) (result i32)
57 | (if (i32.ge_u (call $-i32_u (get_local $pos)) (call $-len (get_local $binary)))(then
58 | (return (i32.const 0))
59 | ))
60 | (call $-integer_u (call $-read8 (get_local $binary) (call $-i32_u (get_local $pos))))
61 | )
62 | (func $binary_write (param $binary i32) (param $pos i32) (param $data i32) (result i32)
63 | (local $subbin i32)
64 | (local $len i32)
65 | (set_local $pos (call $-i32_u (get_local $pos)))
66 | (if (i32.lt_u (call $-datatype (get_local $data)) (i32.const 3))(then
67 | (set_local $subbin (call $-new_value (i32.const 6) (i32.const 4)))
68 | (call $-write32 (get_local $subbin) (i32.const 0) (call $-i32_u (get_local $data)))
69 | (if (i32.eqz (call $-read8 (get_local $subbin) (i32.const 3)))(then
70 | (if (i32.eqz (call $-read8 (get_local $subbin) (i32.const 2)))(then
71 | (if (i32.eqz (call $-read8 (get_local $subbin) (i32.const 1)))(then
72 | (call $-resize (get_local $subbin) (i32.const 1))
73 | )(else
74 | (call $-resize (get_local $subbin) (i32.const 2))
75 | ))
76 | )(else
77 | (call $-resize (get_local $subbin) (i32.const 3))
78 | ))
79 | ))
80 | (set_local $data (get_local $subbin))
81 | ))
82 | (set_local $len (i32.add (get_local $pos) (call $-len (get_local $data))))
83 | (if (i32.lt_u (call $-len (get_local $binary)) (get_local $len) )(then
84 | (call $-resize (get_local $binary) (get_local $len))
85 | ))
86 | (call $-memcopy
87 | (call $-offset (get_local $data))
88 | (i32.add (call $-offset (get_local $binary)) (get_local $pos))
89 | (call $-len (get_local $data))
90 | )
91 | (i32.const 0)
92 | )
93 |
94 |
95 | ;; string functions
96 | (func $string_length (param $str i32) (result i32)
97 | (call $-integer_u (call $-bytes_to_chars (call $-offset (get_local $str)) (call $-len (get_local $str))))
98 | )
99 | (func $string_slice (param $string i32) (param $start i32) (param $len i32) (result i32)
100 | (set_local $start (call $-chars_to_bytes
101 | (call $-offset (get_local $string))
102 | (call $-i32_u (get_local $start))
103 | ))
104 | (set_local $len (call $-chars_to_bytes
105 | (i32.add (call $-offset (get_local $string)) (get_local $start))
106 | (call $-i32_u (get_local $len))
107 | ))
108 | (call $-set_datatype (call $binary_slice
109 | (get_local $string)
110 | (call $-integer_u (get_local $start))
111 | (call $-integer_u (get_local $len))
112 | ) (i32.const 3))
113 | )
114 | (func $string_search (param $string i32) (param $substr i32) (param $start i32) (result i32)
115 | (local $res i32)
116 | (set_local $start (call $-chars_to_bytes
117 | (call $-offset (get_local $string))
118 | (call $-i32_u (get_local $start))
119 | ))
120 | (set_local $res (call $binary_search
121 | (get_local $string)
122 | (get_local $substr)
123 | (call $-integer_u (get_local $start))
124 | ))
125 | (if (get_local $res)(then
126 | (set_local $res (call $-integer_u (call $-bytes_to_chars
127 | (call $-offset (get_local $string))
128 | (call $-i32_u (get_local $res))
129 | )))
130 | ))
131 | (get_local $res)
132 | )
133 | (func $string_lower (param $string i32) (result i32)
134 | (local $out i32)
135 | (local $len i32)
136 | (local $byte i32)
137 | (set_local $len (call $-len (get_local $string)))
138 | (set_local $out (call $-new_value (i32.const 3) (get_local $len)))
139 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
140 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
141 | (set_local $byte (call $-read8 (get_local $string) (get_local $len)))
142 | (if (i32.and
143 | (i32.gt_u
144 | (get_local $byte)
145 | (i32.const 0x40)
146 | )
147 | (i32.lt_u
148 | (get_local $byte)
149 | (i32.const 0x5B)
150 | )
151 | )(then
152 | (call $-write8
153 | (get_local $out)
154 | (get_local $len)
155 | (i32.add
156 | (get_local $byte)
157 | (i32.const 0x20)
158 | )
159 | )
160 | )(else
161 | (call $-write8
162 | (get_local $out)
163 | (get_local $len)
164 | (get_local $byte)
165 | )
166 | ))
167 | (br 0)))
168 | (get_local $out)
169 | )
170 | (func $string_upper (param $string i32) (result i32)
171 | (local $out i32)
172 | (local $len i32)
173 | (local $byte i32)
174 | (set_local $len (call $-len (get_local $string)))
175 | (set_local $out (call $-new_value (i32.const 3) (get_local $len)))
176 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
177 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
178 | (set_local $byte (call $-read8 (get_local $string) (get_local $len)))
179 | (if (i32.and
180 | (i32.gt_u
181 | (get_local $byte)
182 | (i32.const 0x60)
183 | )
184 | (i32.lt_u
185 | (get_local $byte)
186 | (i32.const 0x7B)
187 | )
188 | )(then
189 | (call $-write8
190 | (get_local $out)
191 | (get_local $len)
192 | (i32.sub
193 | (get_local $byte)
194 | (i32.const 0x20)
195 | )
196 | )
197 | )(else
198 | (call $-write8
199 | (get_local $out)
200 | (get_local $len)
201 | (get_local $byte)
202 | )
203 | ))
204 | (br 0)))
205 | (get_local $out)
206 | )
207 | (func $string_split (param $string i32) (param $seperator i32) (result i32)
208 | (local $parts i32)
209 | (local $sub i32)
210 | (local $start i32)
211 | (local $pos i32)
212 | (if (i32.lt_u (call $-len (get_local $string)) (call $-len (get_local $seperator))) (then
213 | (return (i32.const 0))
214 | ))
215 | (set_local $parts (call $-new_value (i32.const 4) (i32.const 0)))
216 | (set_local $sub (call $-new_value (call $-datatype (get_local $seperator)) (call $-len (get_local $seperator))))
217 | (block(loop
218 | (br_if 1 (i32.gt_u (get_local $pos) (i32.sub (call $-len (get_local $string)) (call $-len (get_local $seperator)))))
219 | (call $-memcopy
220 | (i32.add (call $-offset (get_local $string)) (get_local $pos))
221 | (call $-offset (get_local $sub))
222 | (call $-len (get_local $sub))
223 | )
224 | (if (i32.eqz (call $-compare (get_local $sub) (get_local $seperator))) (then
225 | (call $-write32
226 | (get_local $parts)
227 | (call $-len (get_local $parts))
228 | (call $-string
229 | (i32.add
230 | (call $-offset (get_local $string))
231 | (get_local $start)
232 | )
233 | (i32.sub
234 | (get_local $pos)
235 | (get_local $start)
236 | )
237 | )
238 | )
239 | (set_local $start (i32.add
240 | (get_local $pos)
241 | (call $-len (get_local $seperator))
242 | ))
243 | (set_local $pos (get_local $start))
244 | )(else
245 | (set_local $pos (i32.add (get_local $pos) (i32.const 1)))
246 | ))
247 | (br 0)
248 | ))
249 | (call $-write32
250 | (get_local $parts)
251 | (call $-len (get_local $parts))
252 | (call $-string
253 | (i32.add
254 | (call $-offset (get_local $string))
255 | (get_local $start)
256 | )
257 | (i32.sub
258 | (call $-len (get_local $string))
259 | (get_local $start)
260 | )
261 | )
262 | )
263 | (get_local $parts)
264 | )
265 | (func $char (param $code i32) (result i32)
266 | (set_local $code (call $-i32_u (get_local $code)))
267 | (call $-char (get_local $code))
268 | )
269 | (func $char_code (param $string i32) (param $pos i32) (result i32)
270 | (set_local $pos (i32.add
271 | (call $-offset (get_local $string))
272 | (call $-chars_to_bytes
273 | (call $-offset (get_local $string))
274 | (call $-i32_u (get_local $pos))
275 | )
276 | ))
277 | (call $-integer_u (call $-char_code (get_local $pos)))
278 | )
279 |
280 | ;; array functions
281 | (func $array_length (param $array i32) (result i32)
282 | (call $-integer_u (i32.div_u (call $-len (get_local $array)) (i32.const 4)))
283 | )
284 | (func $array_insert (param $array i32) (param $index i32) (param $value i32) (result i32)
285 | (local $rest i32)
286 | (set_local $index (i32.mul (call $-i32_u (get_local $index)) (i32.const 4)))
287 | (if (i32.lt_u (call $-len (get_local $array)) (get_local $index))(then
288 | (set_local $index (call $-len (get_local $array)))
289 | ))
290 | (set_local $rest (i32.sub (call $-len (get_local $array)) (get_local $index)))
291 | (call $-resize
292 | (get_local $array)
293 | (i32.add (i32.add (get_local $index) (get_local $rest)) (i32.const 4))
294 | )
295 | (call $-memcopy
296 | (i32.add (call $-offset (get_local $array)) (get_local $index))
297 | (i32.add (i32.add (call $-offset (get_local $array)) (get_local $index)) (i32.const 4))
298 | (get_local $rest)
299 | )
300 | (call $-write32 (get_local $array) (get_local $index) (get_local $value))
301 | (get_local $value)
302 | )
303 | (func $array_remove (param $array i32) (param $index i32) (result i32)
304 | (local $value i32)
305 | (local $rest i32)
306 | (set_local $index (i32.mul (call $-i32_u (get_local $index)) (i32.const 4)))
307 | (if (i32.le_u (call $-len (get_local $array)) (get_local $index))(then
308 | (return (i32.const 0))
309 | ))
310 | (set_local $rest (i32.sub (i32.sub (call $-len (get_local $array)) (get_local $index)) (i32.const 4)))
311 | (set_local $value (call $-read32 (get_local $array) (get_local $index)))
312 | (call $-memcopy
313 | (i32.add (i32.add (call $-offset (get_local $array)) (get_local $index)) (i32.const 4))
314 | (i32.add (call $-offset (get_local $array)) (get_local $index))
315 | (get_local $rest)
316 | )
317 | (call $-resize
318 | (get_local $array)
319 | (i32.add (get_local $index) (get_local $rest))
320 | )
321 | (get_local $value)
322 | )
323 | (func $array_push (param $array i32) (param $value i32) (result i32)
324 | (call $array_insert (get_local $array) (call $array_length (get_local $array)) (get_local $value))
325 | )
326 | (func $array_pop (param $array i32) (result i32)
327 | (call $array_remove
328 | (get_local $array)
329 | (call $-sub
330 | (call $array_length (get_local $array))
331 | (call $-integer_u (i32.const 1))
332 | )
333 | )
334 | )
335 | (func $array_unshift (param $array i32) (param $value i32) (result i32)
336 | (call $array_insert (get_local $array) (i32.const 2) (get_local $value))
337 | )
338 | (func $array_shift (param $array i32) (result i32)
339 | (call $array_remove
340 | (get_local $array)
341 | (i32.const 2)
342 | )
343 | )
344 | (func $array_search (param $array i32) (param $value i32) (param $start i32) (result i32)
345 | (local $index i32)
346 | (local $len i32)
347 | (local $pos i32)
348 | (set_local $start (i32.mul (call $-i32_u (get_local $start)) (i32.const 4)))
349 | (if (i32.lt_u (call $-len (get_local $array)) (get_local $start))(then
350 | (return (i32.const 0))
351 | ))
352 | (set_local $len (i32.sub (call $-len (get_local $array)) (get_local $start)))
353 | (set_local $pos (i32.add (call $-offset (get_local $array)) (get_local $start)))
354 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
355 | (if (call $-truthy (call $-equal (get_local $value) (i32.load (get_local $pos))))(then
356 | (set_local $index (call $-integer_u (i32.div_u
357 | (i32.sub
358 | (get_local $pos )
359 | (call $-offset
360 | (get_local $array )
361 | )
362 | )
363 | (i32.const 4 )
364 | )))
365 | (br 2)
366 | ))
367 | (set_local $pos (i32.add (get_local $pos) (i32.const 4)))
368 | (set_local $len (i32.sub (get_local $len) (i32.const 4)))
369 | (br 0)))
370 |
371 | (get_local $index)
372 | )
373 | (func $array_slice (param $array i32) (param $start i32) (param $len i32) (result i32)
374 | (local $out i32)
375 | (set_local $start (i32.mul (call $-i32_u (get_local $start)) (i32.const 4)))
376 | (set_local $len (i32.mul (call $-i32_u (get_local $len)) (i32.const 4)))
377 | (if (i32.lt_u (call $-len (get_local $array)) (get_local $start))(then
378 | (set_local $start (call $-len (get_local $array)))
379 | ))
380 | (if (i32.lt_u (i32.sub (call $-len (get_local $array)) (get_local $start)) (get_local $len))(then
381 | (set_local $len (i32.sub (call $-len (get_local $array)) (get_local $start)))
382 | ))
383 | (set_local $out (call $-new_value (i32.const 4) (call $-i32_u (get_local $len))))
384 | (call $-memcopy (i32.add (call $-offset (get_local $array)) (get_local $start)) (call $-offset (get_local $out)) (get_local $len))
385 | (get_local $out)
386 | )
387 | (func $array_splice (param $array i32) (param $start i32) (param $delete i32) (param $replace i32) (result i32)
388 | (local $rest i32)
389 | (set_local $start (i32.mul (call $-i32_u (get_local $start)) (i32.const 4)))
390 | (set_local $delete (i32.mul (call $-i32_u (get_local $delete)) (i32.const 4)))
391 | (if (i32.lt_u (call $-len (get_local $array)) (get_local $start))(then
392 | (set_local $start (call $-len (get_local $array)))
393 | ))
394 | (if (i32.lt_u (i32.sub (call $-len (get_local $array)) (get_local $start)) (get_local $delete))(then
395 | (set_local $delete (i32.sub (call $-len (get_local $array)) (get_local $start)))
396 | ))
397 | (set_local $rest (i32.sub (i32.sub (call $-len (get_local $array)) (get_local $start)) (get_local $delete)))
398 | (call $-memcopy
399 | (i32.add (i32.add (call $-offset (get_local $array)) (get_local $start)) (get_local $delete))
400 | (i32.add (call $-offset (get_local $array)) (get_local $start))
401 | (get_local $rest)
402 | )
403 | (call $-resize
404 | (get_local $array)
405 | (i32.add (i32.add (get_local $start) (get_local $rest)) (call $-len (get_local $replace)))
406 | )
407 | (call $-memcopy
408 | (i32.add (call $-offset (get_local $array)) (get_local $start))
409 | (i32.add (i32.add (call $-offset (get_local $array)) (get_local $start)) (call $-len (get_local $replace)))
410 | (get_local $rest)
411 | )
412 | (call $-memcopy
413 | (call $-offset (get_local $replace))
414 | (i32.add (call $-offset (get_local $array)) (get_local $start))
415 | (call $-len (get_local $replace))
416 | )
417 | (i32.const 0)
418 | )
419 | (func $array_sort (param $array i32) (result i32)
420 | (local $out i32)
421 | (local $len i32)
422 | (local $pos i32)
423 | (local $ins i32)
424 | (local $val i32)
425 | (set_local $out (call $-new_value (i32.const 4) (call $-len (get_local $array))))
426 | (set_local $len (i32.div_u (call $-len (get_local $array)) (i32.const 4)))
427 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
428 | (set_local $val
429 | (call $-read32
430 | (get_local $array)
431 | (i32.mul (get_local $pos) (i32.const 4))
432 | )
433 | )
434 | (set_local $ins (get_local $pos))
435 | (block(loop (br_if 1 (i32.eqz (get_local $ins)))
436 | (br_if 1 (call $-ge
437 | (get_local $val)
438 | (call $-read32
439 | (get_local $out)
440 | (i32.mul (i32.sub (get_local $ins) (i32.const 1)) (i32.const 4))
441 | )
442 | ))
443 | (call $-write32
444 | (get_local $out)
445 | (i32.mul (get_local $ins) (i32.const 4))
446 | (call $-read32
447 | (get_local $out)
448 | (i32.mul (i32.sub (get_local $ins) (i32.const 1)) (i32.const 4))
449 | )
450 | )
451 | (set_local $ins (i32.sub (get_local $ins) (i32.const 1)))
452 | (br 0)))
453 | (call $-write32
454 | (get_local $out)
455 | (i32.mul (get_local $ins) (i32.const 4))
456 | (get_local $val)
457 | )
458 | (set_local $pos (i32.add (get_local $pos) (i32.const 1)))
459 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
460 | (br 0)))
461 | (get_local $out)
462 | )
463 | (func $array_join (param $array i32) (param $glue i32) (result i32)
464 | (local $string i32)
465 | (local $strlen i32)
466 | (local $part i32)
467 | (local $pos i32)
468 | (local $len i32)
469 | (set_local $string (call $-new_value (i32.const 3) (get_local $strlen)))
470 | (set_local $len (call $-len (get_local $array)))
471 | (if (get_local $len)(then
472 | (set_local $part (call $-to_string (call $-read32 (get_local $array) (get_local $pos))))
473 | (call $-resize (get_local $string) (i32.add
474 | (get_local $strlen)
475 | (call $-len (get_local $part))
476 | ))
477 | (call $-memcopy
478 | (call $-offset (get_local $part))
479 | (i32.add
480 | (call $-offset (get_local $string))
481 | (get_local $strlen)
482 | )
483 | (call $-len (get_local $part))
484 | )
485 | (set_local $strlen (i32.add (get_local $strlen) (call $-len (get_local $part))))
486 | (set_local $pos (i32.add (get_local $pos) (i32.const 4)))
487 | (set_local $len (i32.sub (get_local $len) (i32.const 4)))
488 | ))
489 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
490 | (set_local $part (call $-to_string (call $-read32 (get_local $array) (get_local $pos))))
491 | (call $-resize (get_local $string) (i32.add
492 | (get_local $strlen)
493 | (i32.add
494 | (call $-len (get_local $glue))
495 | (call $-len (get_local $part))
496 | )
497 | ))
498 | (call $-memcopy
499 | (call $-offset (get_local $glue))
500 | (i32.add
501 | (call $-offset (get_local $string))
502 | (get_local $strlen)
503 | )
504 | (call $-len (get_local $glue))
505 | )
506 | (set_local $strlen (i32.add (get_local $strlen) (call $-len (get_local $glue))))
507 | (call $-memcopy
508 | (call $-offset (get_local $part))
509 | (i32.add
510 | (call $-offset (get_local $string))
511 | (get_local $strlen)
512 | )
513 | (call $-len (get_local $part))
514 | )
515 | (set_local $strlen (i32.add (get_local $strlen) (call $-len (get_local $part))))
516 | (set_local $pos (i32.add (get_local $pos) (i32.const 4)))
517 | (set_local $len (i32.sub (get_local $len) (i32.const 4)))
518 | (br 0)))
519 | (get_local $string)
520 | )
521 | (func $range (param $start i32) (param $end i32) (param $step i32) (result i32)
522 | (local $_start f64)
523 | (local $_end f64)
524 | (local $_step f64)
525 | (local $out i32)
526 | (local $offset i32)
527 | (local $len i32)
528 | (set_local $_start (call $-f64 (get_local $start)))
529 | (set_local $_end (call $-f64 (get_local $end)))
530 | (set_local $_step (call $-f64 (get_local $step)))
531 | (if (f64.eq (get_local $_step) (f64.const 0))(then
532 | (if (f64.gt (get_local $_start) (get_local $_end))(then
533 | (set_local $_step (f64.const -1))
534 | )(else
535 | (set_local $_step (f64.const 1))
536 | ))
537 | ))
538 | (set_local $out (call $-new_value (i32.const 4) (i32.trunc_u/f64
539 | (f64.mul
540 | (f64.floor (f64.div
541 | (f64.sub
542 | (get_local $_end)
543 | (get_local $_start)
544 | )
545 | (get_local $_step)
546 | ))
547 | (f64.const 4)
548 | )
549 | )))
550 | (set_local $offset (call $-offset (get_local $out)))
551 | (set_local $len (call $-len (get_local $out)))
552 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
553 | (i32.store (get_local $offset) (call $-number (get_local $_start)))
554 | (set_local $_start (f64.add (get_local $_start) (get_local $_step)))
555 | (set_local $offset (i32.add (get_local $offset) (i32.const 4)))
556 | (set_local $len (i32.sub (get_local $len) (i32.const 4)))
557 | (br 0)))
558 | (get_local $out)
559 | )
560 |
561 | ;; object functions
562 | (func $object_keys (param $object i32) (result i32)
563 | (local $out i32)
564 | (local $len i32)
565 | (set_local $out (call $-new_value (i32.const 4) (i32.div_u (call $-len (get_local $object)) (i32.const 2))))
566 | (set_local $len (i32.div_u (call $-len (get_local $out)) (i32.const 4)))
567 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
568 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
569 | (call $-write32
570 | (get_local $out)
571 | (i32.mul (get_local $len) (i32.const 4))
572 | (call $-read32
573 | (get_local $object)
574 | (i32.mul (get_local $len) (i32.const 8))
575 | )
576 | )
577 | (br 0)))
578 | (get_local $out)
579 | )
580 | (func $object_values (param $object i32) (result i32)
581 | (local $out i32)
582 | (local $len i32)
583 | (set_local $out (call $-new_value (i32.const 4) (i32.div_u (call $-len (get_local $object)) (i32.const 2))))
584 | (set_local $len (i32.div_u (call $-len (get_local $out)) (i32.const 4)))
585 | (block(loop (br_if 1 (i32.eqz (get_local $len)))
586 | (set_local $len (i32.sub (get_local $len) (i32.const 1)))
587 | (call $-write32
588 | (get_local $out)
589 | (i32.mul (get_local $len) (i32.const 4))
590 | (call $-read32
591 | (get_local $object)
592 | (i32.add (i32.mul (get_local $len) (i32.const 8)) (i32.const 4))
593 | )
594 | )
595 | (br 0)))
596 | (get_local $out)
597 | )
598 |
599 | ;; math functions
600 | (func $abs (param $number i32) (result i32)
601 | (call $-number (f64.abs (call $-f64 (get_local $number))))
602 | )
603 | (func $ceil (param $number i32) (result i32)
604 | (call $-number (f64.ceil (call $-f64 (get_local $number))))
605 | )
606 | (func $floor (param $number i32) (result i32)
607 | (call $-number (f64.floor (call $-f64 (get_local $number))))
608 | )
609 | (func $nearest (param $number i32) (result i32)
610 | (call $-number (f64.nearest (call $-f64 (get_local $number))))
611 | )
612 | (func $sqrt (param $number i32) (result i32)
613 | (call $-number (f64.sqrt (call $-f64 (get_local $number))))
614 | )
615 | (func $min (param $number1 i32) (param $number2 i32) (result i32)
616 | (call $-number (f64.min
617 | (call $-f64 (get_local $number1))
618 | (call $-f64 (get_local $number2))
619 | ))
620 | )
621 | (func $max (param $number1 i32) (param $number2 i32) (result i32)
622 | (call $-number (f64.max
623 | (call $-f64 (get_local $number1))
624 | (call $-f64 (get_local $number2))
625 | ))
626 | )
627 |
628 | ;; JSON
629 | (func $json_encode (param $value i32) (result i32)
630 | (local $datatype i32)
631 | (local $len i32)
632 | (local $json_string i32)
633 | (local $char i32)
634 | (local $done i32)
635 | (local $ipos i32)
636 | (local $opos i32)
637 | (set_local $datatype (call $-datatype (get_local $value)))
638 | (set_local $len (call $-len (get_local $value)))
639 | (if (i32.lt_u (get_local $datatype) (i32.const 3))(then
640 | (set_local $json_string (call $-to_string (get_local $value)))
641 | ))
642 | (if (i32.gt_u (get_local $datatype) (i32.const 5))(then
643 | (set_local $value (call $-to_string (get_local $value)))
644 | (set_local $datatype (i32.const 3))
645 | ))
646 | (if (i32.eq (get_local $datatype) (i32.const 3))(then ;; string
647 | (set_local $json_string (call $-new_value (i32.const 3) (call $-len (get_local $value))))
648 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x22)) ;; "
649 | (set_local $opos (i32.add (get_local $opos) (i32.const 1)))
650 | (block(loop (br_if 1 (i32.ge_u (get_local $ipos) (get_local $len)))
651 | (set_local $done (i32.const 0))
652 | (set_local $char (call $-read8 (get_local $value) (get_local $ipos)))
653 | (if (i32.eq (get_local $char) (i32.const 0x08))(then
654 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x625c)) ;; \b
655 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
656 | (set_local $done (i32.const 1))
657 | ))
658 | (if (i32.eq (get_local $char) (i32.const 0x09))(then
659 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x745c)) ;; \t
660 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
661 | (set_local $done (i32.const 1))
662 | ))
663 | (if (i32.eq (get_local $char) (i32.const 0x0a))(then
664 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x6e5c)) ;; \n
665 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
666 | (set_local $done (i32.const 1))
667 | ))
668 | (if (i32.eq (get_local $char) (i32.const 0x0c))(then
669 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x665c)) ;; \f
670 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
671 | (set_local $done (i32.const 1))
672 | ))
673 | (if (i32.eq (get_local $char) (i32.const 0x0d))(then
674 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x725c)) ;; \r
675 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
676 | (set_local $done (i32.const 1))
677 | ))
678 | (if (i32.eq (get_local $char) (i32.const 0x22))(then
679 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x225c)) ;; \"
680 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
681 | (set_local $done (i32.const 1))
682 | ))
683 | (if (i32.eq (get_local $char) (i32.const 0x5c))(then
684 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x5c5c)) ;; \\
685 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
686 | (set_local $done (i32.const 1))
687 | ))
688 | (if (i32.eq (get_local $char) (i32.const 0x7f))(then
689 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x755c)) ;; \u
690 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
691 | (call $-write32 (get_local $json_string) (get_local $opos) (i32.const 0x66373030)) ;; 007f
692 | (set_local $opos (i32.add (get_local $opos) (i32.const 4)))
693 | (set_local $done (i32.const 1))
694 | ))
695 | (if (i32.eqz (get_local $done))(then
696 | (if (i32.lt_u (get_local $char) (i32.const 0x20))(then
697 | (call $-write16 (get_local $json_string) (get_local $opos) (i32.const 0x755c)) ;; \u
698 | (set_local $opos (i32.add (get_local $opos) (i32.const 2)))
699 | (set_local $done (call $-to_hex (get_local $char) (i32.const 4)))
700 | (call $-write32 (get_local $json_string) (get_local $opos) (call $-read32 (get_local $done) (i32.const 0)))
701 | (set_local $opos (i32.add (get_local $opos) (i32.const 4)))
702 | )(else
703 | (call $-write8 (get_local $json_string) (get_local $opos) (get_local $char))
704 | (set_local $opos (i32.add (get_local $opos) (i32.const 1)))
705 | ))
706 | ))
707 | (set_local $ipos (i32.add (get_local $ipos) (i32.const 1)))
708 | (br 0)))
709 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x22)) ;; "
710 | ))
711 | (if (i32.eq (get_local $datatype) (i32.const 4))(then ;; array
712 | (set_local $json_string (call $-new_value (i32.const 3) (i32.const 0)))
713 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x5b)) ;; [
714 | (set_local $opos (i32.add (get_local $opos) (i32.const 1)))
715 | (block(loop (br_if 1 (i32.ge_u (get_local $ipos) (get_local $len)))
716 | (set_local $char (call $-read32 (get_local $value) (get_local $ipos)))
717 | (set_local $ipos (i32.add (get_local $ipos) (i32.const 4)))
718 | (set_local $opos (call $-len (get_local $json_string)))
719 | (call $-write_to (get_local $json_string) (get_local $opos) (call $json_encode (get_local $char)))
720 | (set_local $opos (call $-len (get_local $json_string)))
721 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x2c)) ;; ,
722 | (br 0)))
723 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x5d)) ;; ]
724 | ))
725 | (if (i32.eq (get_local $datatype) (i32.const 5))(then ;; object
726 | (set_local $json_string (call $-new_value (i32.const 3) (i32.const 0)))
727 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x7b)) ;; {
728 | (set_local $opos (i32.add (get_local $opos) (i32.const 1)))
729 | (block(loop (br_if 1 (i32.ge_u (get_local $ipos) (get_local $len)))
730 | (set_local $char (call $-read32 (get_local $value) (get_local $ipos)))
731 | (set_local $ipos (i32.add (get_local $ipos) (i32.const 4)))
732 | (set_local $opos (call $-len (get_local $json_string)))
733 | (call $-write_to (get_local $json_string) (get_local $opos) (call $json_encode (call $-to_string (get_local $char))))
734 | (set_local $opos (call $-len (get_local $json_string)))
735 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x3a)) ;; :
736 | (set_local $char (call $-read32 (get_local $value) (get_local $ipos)))
737 | (set_local $ipos (i32.add (get_local $ipos) (i32.const 4)))
738 | (set_local $opos (call $-len (get_local $json_string)))
739 | (call $-write_to (get_local $json_string) (get_local $opos) (call $json_encode (get_local $char)))
740 | (set_local $opos (call $-len (get_local $json_string)))
741 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x2c)) ;; ,
742 | (br 0)))
743 | (call $-write8 (get_local $json_string) (get_local $opos) (i32.const 0x7d)) ;; }
744 | ))
745 | (get_local $json_string)
746 | )
747 | (func $json_decode (param $json_string i32) (result i32)
748 | (local $datatype i32)
749 | (local $value i32)
750 | (set_local $datatype (call $-datatype (get_local $json_string)))
751 | (set_local $value (get_local $json_string))
752 | (set_global $~pos (call $-offset (get_local $json_string)))
753 | (if (i32.eq (get_local $datatype) (i32.const 3))(then
754 | (set_local $value (call $~json_decode))
755 | ))
756 | (if (i32.eq (get_local $datatype) (i32.const 6))(then
757 | (set_local $value (call $~json_decode))
758 | ))
759 | (get_local $value)
760 | )
761 | (global $~pos (mut i32) (i32.const 0))
762 | (func $~json_decode (result i32)
763 | (local $value i32)
764 | (local $err i32)
765 | (local $char i32)
766 | (local $pos i32)
767 | (local $hex i32)
768 | (local $num f64)
769 | (local $neg f64)
770 | (local $exp f64)
771 | (local $eneg f64)
772 | (set_local $err (i32.eqz (call $~skip_whitespace)))
773 | (set_local $char (i32.load8_u (get_global $~pos)))
774 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
775 | (if (i32.eq (get_local $char) (i32.const 0x6e))(then ;; n
776 | (set_global $~pos (i32.sub (get_global $~pos) (i32.const 1)))
777 | (set_local $char (i32.load (get_global $~pos)))
778 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 4)))
779 | (if (i32.eq (get_local $char) (i32.const 0x6c6c756e))(then ;; null
780 | (set_local $value (i32.const 0))
781 | )(else
782 | (set_local $char (i32.const 0))
783 | (set_local $err (i32.const 1))
784 | ))
785 | ))
786 | (if (i32.eq (get_local $char) (i32.const 0x66))(then ;; f
787 | (set_local $char (i32.load (get_global $~pos)))
788 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 4)))
789 | (if (i32.eq (get_local $char) (i32.const 0x65736c61))(then ;; alse
790 | (set_local $value (i32.const 1))
791 | )(else
792 | (set_local $char (i32.const 0))
793 | (set_local $err (i32.const 1))
794 | ))
795 | ))
796 | (if (i32.eq (get_local $char) (i32.const 0x74))(then ;; t
797 | (set_global $~pos (i32.sub (get_global $~pos) (i32.const 1)))
798 | (set_local $char (i32.load (get_global $~pos)))
799 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 4)))
800 | (if (i32.eq (get_local $char) (i32.const 0x65757274))(then ;; true
801 | (set_local $value (i32.const 5))
802 | )(else
803 | (set_local $char (i32.const 0))
804 | (set_local $err (i32.const 1))
805 | ))
806 | ))
807 | (if (i32.or
808 | (i32.eq (get_local $char) (i32.const 0x2d)) ;; -
809 | (i32.and
810 | (i32.ge_u (get_local $char) (i32.const 0x30)) ;; 0
811 | (i32.le_u (get_local $char) (i32.const 0x39)) ;; 9
812 | )) (then
813 | (set_global $~pos (i32.sub (get_global $~pos) (i32.const 1)))
814 | (set_local $value (call $-number (call $-parse_float (get_global $~pos) (i32.const 10))))
815 | (set_global $~pos (get_global $-parsing_offset))
816 | ))
817 | (if (i32.eq (get_local $char) (i32.const 0x22))(then ;; "
818 | (set_local $char (i32.load8_u (get_global $~pos)))
819 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
820 | (set_local $value (call $-new_value (i32.const 3) (i32.const 0)))
821 | (block(loop (br_if 1 (i32.eq (get_local $char) (i32.const 0x22))) ;; "
822 | (set_local $pos (call $-len (get_local $value)))
823 | (if (i32.eq (get_local $char) (i32.const 0x5c))(then ;; \
824 | (set_local $char (i32.load8_u (get_global $~pos)))
825 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
826 | (call $-write8 (get_local $value) (get_local $pos) (get_local $char))
827 | (if (i32.eq (get_local $char) (i32.const 0x62))(then ;; b
828 | (call $-write8 (get_local $value) (get_local $pos) (i32.const 0x08))
829 | ))
830 | (if (i32.eq (get_local $char) (i32.const 0x66))(then ;; f
831 | (call $-write8 (get_local $value) (get_local $pos) (i32.const 0x0c))
832 | ))
833 | (if (i32.eq (get_local $char) (i32.const 0x6e))(then ;; n
834 | (call $-write8 (get_local $value) (get_local $pos) (i32.const 0x0a))
835 | ))
836 | (if (i32.eq (get_local $char) (i32.const 0x72))(then ;; r
837 | (call $-write8 (get_local $value) (get_local $pos) (i32.const 0x0d))
838 | ))
839 | (if (i32.eq (get_local $char) (i32.const 0x74))(then ;; t
840 | (call $-write8 (get_local $value) (get_local $pos) (i32.const 0x09))
841 | ))
842 | (if (i32.eq (get_local $char) (i32.const 0x75))(then ;; u
843 | (if (i32.eqz (get_local $hex))(then
844 | (set_local $hex (call $-new_value (i32.const 3) (i32.const 4)))
845 | ))
846 | (set_local $char (i32.load (get_global $~pos)))
847 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 4)))
848 | (call $-write32 (get_local $hex) (i32.const 0) (get_local $char))
849 | (set_local $char (call $-from_hex (get_local $hex)))
850 | (if (i32.eq (i32.and (get_local $char) (i32.const 0xfc00)) (i32.const 0xd800))(then ;; surrogate pair
851 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 2)))
852 | (call $-write32 (get_local $hex) (i32.const 0) (i32.load (get_global $~pos)))
853 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 4)))
854 | (set_local $hex (call $-from_hex (get_local $hex)))
855 | (set_local $char (i32.mul (i32.sub (get_local $char) (i32.const 0xd800)) (i32.const 0x400)))
856 | (set_local $hex (i32.sub (get_local $hex) (i32.const 0xdc00)))
857 | (set_local $char (i32.add (i32.add (get_local $char) (get_local $hex)) (i32.const 0x10000)))
858 | (set_local $char (call $-char (get_local $char)))
859 | (set_local $hex (i32.const 0))
860 | )(else
861 | (set_local $char (call $-char (get_local $char)))
862 | ))
863 | (call $-write_to (get_local $value) (get_local $pos) (get_local $char))
864 | ))
865 | )(else
866 | (call $-write8 (get_local $value) (get_local $pos) (get_local $char))
867 | ))
868 |
869 | (set_local $char (i32.load8_u (get_global $~pos)))
870 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
871 | (br 0)))
872 | ))
873 | (if (i32.eq (get_local $char) (i32.const 0x5b))(then ;; [
874 | (set_local $value (call $-new_value (i32.const 4) (i32.const 0)))
875 | (set_local $char (call $~skip_whitespace))
876 | (set_local $err (i32.eqz (call $~skip_whitespace)))
877 | (block(loop (br_if 1 (i32.or (get_local $err) (i32.eq (get_local $char) (i32.const 0x5d)))) ;; ]
878 | (if (i32.eq (get_local $char) (i32.const 0x2c))(then ;; ,
879 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
880 | ))
881 | (call $-write32 (get_local $value) (call $-len (get_local $value)) (call $~json_decode))
882 | (set_local $char (call $~skip_whitespace))
883 | (set_local $err (i32.eqz (call $~skip_whitespace)))
884 | (br 0)))
885 | (if (i32.eq (get_local $char) (i32.const 0x5d))(then ;; ]
886 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
887 | ))
888 | ))
889 | (if (i32.eq (get_local $char) (i32.const 0x7b))(then ;; {
890 | (set_local $value (call $-new_value (i32.const 5) (i32.const 0)))
891 | (set_local $char (call $~skip_whitespace))
892 | (set_local $err (i32.eqz (call $~skip_whitespace)))
893 | (block(loop (br_if 1 (i32.or (get_local $err) (i32.eq (get_local $char) (i32.const 0x7d)))) ;; }
894 | (if (i32.eq (get_local $char) (i32.const 0x2c))(then ;; ,
895 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
896 | ))
897 | (call $-write32 (get_local $value) (call $-len (get_local $value)) (call $~json_decode))
898 | (set_local $char (call $~skip_whitespace))
899 | (set_local $err (i32.eqz (call $~skip_whitespace)))
900 | (if (i32.eq (get_local $char) (i32.const 0x3a))(then ;; :
901 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
902 | ))
903 | (call $-write32 (get_local $value) (call $-len (get_local $value)) (call $~json_decode))
904 | (set_local $char (call $~skip_whitespace))
905 | (set_local $err (i32.eqz (call $~skip_whitespace)))
906 | (br 0)))
907 | (if (i32.eq (get_local $char) (i32.const 0x7d))(then ;; }
908 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
909 | ))
910 | ))
911 | (get_local $value)
912 | )
913 | (func $~skip_whitespace (result i32)
914 | (local $char i32)
915 | (local $err i32)
916 | (set_local $char (i32.load8_u (get_global $~pos)))
917 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
918 | (block(loop (br_if 1 (i32.or (get_local $err) (i32.gt_u (get_local $char) (i32.const 0x20))))
919 | (if (i32.eqz (get_local $char)) (then
920 | (set_local $err (i32.const 1))
921 | )(else
922 | (set_local $char (i32.load8_u (get_global $~pos)))
923 | (set_global $~pos (i32.add (get_global $~pos) (i32.const 1)))
924 | ))
925 | (br 0)))
926 | (set_global $~pos (i32.sub (get_global $~pos) (i32.const 1)))
927 | (get_local $char)
928 | )
929 |
--------------------------------------------------------------------------------
/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Experiment
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | function read_bin(offset, len) {
2 | return wasm.memory.buffer.slice(offset, offset + len)
3 | }
4 | function read_string(offset, len) {
5 | let dec = new TextDecoder()
6 | let buf = read_bin(offset, len)
7 | return dec.decode(buf)
8 | }
9 |
10 | let importObject = {
11 | env: {
12 | logNumber: console.log,
13 | log: (offset, len) => {
14 | console.log(read_string(offset, len))
15 | }
16 | }
17 | }
18 |
19 | fetch('boot.wasm').then(response =>
20 | response.arrayBuffer()
21 | ).then(bytes =>
22 | WebAssembly.instantiate(bytes, importObject)
23 | ).then(obj => {
24 | window.wasm = obj.instance.exports
25 | console.groupCollapsed()
26 | wasm.init()
27 | console.groupEnd()
28 | console.groupCollapsed()
29 | wasm.init()
30 | console.groupEnd()
31 | console.group()
32 | wasm.init()
33 | console.groupEnd()
34 | }
35 | )
36 |
37 | var bits = 1
38 | document.write('')
39 | document.getElementsByTagName("button")[0].addEventListener("click", () => {
40 | console.log(++bits, max = Math.pow(2, bits))
41 | for (let i = -8; i < 8; i++) {
42 | let j = max + i
43 | console.log(j === wasm.echo(j))
44 | }
45 | })
46 |
47 | function memoryIndex() {
48 | let mem = new Int32Array(wasm.memory.buffer)
49 | let mindex = wasm.get_mindex()
50 | let mindexLen = mem[mindex / 4 - 1]
51 | let id = 8
52 | let index = []
53 | for (let i = mindex; i < mindex + mindexLen; i += 8) {
54 | let item = {}
55 | index.push(item)
56 | item.offset = mem[i / 4]
57 | item.len = mem[item.offset / 4 - 1]
58 | item.datatype = mem[i / 4 + 1] / Math.pow(2, 16)
59 | item.used = item.datatype > 255
60 | item.datatype %= 256
61 | try {
62 | item.value = getValue(id++)
63 | } catch (error) {
64 | item.value = undefined
65 | }
66 | }
67 | console.table(index)
68 | }
69 |
70 | function getValue(id) {
71 | if (id < 8) {
72 | return [null, false, 0, "", undefined, true][id]
73 | }
74 | let mem = new Int32Array(wasm.memory.buffer)
75 | let mindex = wasm.get_mindex()
76 | id -= 8
77 | let i = mindex + 8 * id
78 |
79 | let item = {}
80 | item.offset = mem[i / 4]
81 | item.len = mem[item.offset / 4 - 1]
82 | item.datatype = (mem[i / 4 + 1] / Math.pow(2, 16)) % 256
83 | switch (item.datatype) {
84 | case 0:
85 | return null
86 | case 1:
87 | return undefined
88 | case 2:
89 | return wasm.load_f64(item.offset)
90 | case 3:
91 | return read_string(item.offset, item.len)
92 | case 4:
93 | let ar = []
94 | for (let i = item.offset; i < item.offset + item.len; i += 4) {
95 | ar.push(getValue(mem[i / 4]))
96 | }
97 | return ar
98 | case 5:
99 | let obj = {}
100 | for (let i = item.offset; i < item.offset + item.len; i += 8) {
101 | obj[getValue(mem[i / 4])] = getValue(mem[i / 4 + 1])
102 | }
103 | return obj
104 | case 6:
105 | return read_bin(item.offset, item.len)
106 |
107 | default:
108 | return undefined
109 | }
110 | }
111 |
112 | function validateAlloc() {
113 | let mem = new Int32Array(wasm.memory.buffer)
114 | let allocs = []
115 | let offset = 0
116 | let space = mem[offset / 4]
117 | while (offset < mem.length - 1) {
118 | let alloc = {}
119 | allocs.push(alloc)
120 | alloc.free = space
121 | offset += space
122 | if (space !== mem[offset / 4]) console.error("memory error at", offset)
123 | offset += 4
124 | space = mem[offset / 4]
125 |
126 | alloc.offset = offset + 4
127 | alloc.used = space
128 | offset += space + 4
129 | offset = Math.floor(offset / 8) * 8 + 8
130 | space = mem[offset / 4]
131 | space = Math.floor(space / 8) * 8
132 | }
133 | console.table(allocs)
134 | }
--------------------------------------------------------------------------------