xanascript 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,573 @@
1
+ const MAGIC = new Uint8Array([0x00, 0x61, 0x73, 0x6d]);
2
+ const VERSION = new Uint8Array([0x01, 0x00, 0x00, 0x00]);
3
+
4
+ const SECTION = {
5
+ TYPE: 1, IMPORT: 2, FUNC: 3, MEMORY: 5,
6
+ GLOBAL: 6, EXPORT: 7, CODE: 10, DATA: 11,
7
+ };
8
+
9
+ const TYPES = { i32: 0x7f, i64: 0x7e, f32: 0x7d, f64: 0x7c };
10
+
11
+ function leb128u(value) {
12
+ const bytes = [];
13
+ do {
14
+ let byte = value & 0x7f;
15
+ value >>>= 7;
16
+ if (value !== 0) byte |= 0x80;
17
+ bytes.push(byte);
18
+ } while (value !== 0);
19
+ return bytes;
20
+ }
21
+
22
+ function leb128s(value) {
23
+ const bytes = [];
24
+ let more = true;
25
+ while (more) {
26
+ let byte = value & 0x7f;
27
+ value >>= 7;
28
+ if ((value === 0 && (byte & 0x40) === 0) || (value === -1 && (byte & 0x40) !== 0)) {
29
+ more = false;
30
+ } else {
31
+ byte |= 0x80;
32
+ }
33
+ bytes.push(byte);
34
+ }
35
+ return bytes;
36
+ }
37
+
38
+ function encodeVector(items) {
39
+ const all = [];
40
+ all.push(...leb128u(items.length));
41
+ for (const item of items) {
42
+ all.push(...item);
43
+ }
44
+ return all;
45
+ }
46
+
47
+ class WasmBuilder {
48
+ constructor() {
49
+ this.types = [];
50
+ this.imports = [];
51
+ this.functions = [];
52
+ this.exports = [];
53
+ this.codes = [];
54
+ this.memories = [];
55
+ this.globals = [];
56
+ this.dataSegments = [];
57
+ this.strings = [];
58
+ this.varScopes = [];
59
+ this.funcVars = new Map();
60
+ this.funcMap = new Map();
61
+ this.funcIdx = 0;
62
+ this.importMap = new Map();
63
+ }
64
+
65
+ addFuncType(params, results) {
66
+ const bytes = [0x60];
67
+ bytes.push(...leb128u(params.length));
68
+ for (const p of params) bytes.push(TYPES[p] || TYPES.i32);
69
+ bytes.push(...leb128u(results.length));
70
+ for (const r of results) bytes.push(TYPES[r] || TYPES.i32);
71
+ const idx = this.types.length;
72
+ this.types.push(bytes);
73
+ return idx;
74
+ }
75
+
76
+ addImport(mod, name, kind, typeIdx) {
77
+ const modBytes = [...leb128u(mod.length), ...[...mod].map(c => c.charCodeAt(0))];
78
+ const nameBytes = [...leb128u(name.length), ...[...name].map(c => c.charCodeAt(0))];
79
+ const kindByte = kind;
80
+ this.imports.push([...modBytes, ...nameBytes, kindByte, ...leb128u(typeIdx)]);
81
+ const idx = this.importMap.size;
82
+ this.importMap.set(name, { idx, module: mod, kind });
83
+ return idx;
84
+ }
85
+
86
+ addExport(name, kind, idx) {
87
+ const nameBytes = [...leb128u(name.length), ...[...name].map(c => c.charCodeAt(0))];
88
+ this.exports.push([...nameBytes, kind, ...leb128u(idx)]);
89
+ }
90
+
91
+ pushFunc(name) {
92
+ const scope = { vars: new Map(), count: 0, name };
93
+ this.varScopes.push(scope);
94
+ this.funcVars.set(name, scope);
95
+ return scope;
96
+ }
97
+
98
+ popFunc() {
99
+ this.varScopes.pop();
100
+ }
101
+
102
+ get currentVars() {
103
+ return this.varScopes[this.varScopes.length - 1]?.vars;
104
+ }
105
+
106
+ get currentVarCount() {
107
+ return this.varScopes[this.varScopes.length - 1]?.count || 0;
108
+ }
109
+
110
+ addVar(name) {
111
+ const scope = this.varScopes[this.varScopes.length - 1];
112
+ if (!scope) return;
113
+ if (!scope.vars.has(name)) {
114
+ scope.vars.set(name, { index: scope.count++, type: "i32" });
115
+ }
116
+ return scope.vars.get(name);
117
+ }
118
+
119
+ getVar(name) {
120
+ for (let i = this.varScopes.length - 1; i >= 0; i--) {
121
+ const scope = this.varScopes[i];
122
+ if (scope.vars.has(name)) return scope.vars.get(name);
123
+ }
124
+ return null;
125
+ }
126
+
127
+ addCode(locals, body) {
128
+ const localsBytes = [];
129
+ localsBytes.push(...leb128u(locals.length));
130
+ for (const [count, type] of locals) {
131
+ localsBytes.push(...leb128u(count), TYPES[type] || TYPES.i32);
132
+ }
133
+ const codeBody = [...localsBytes, ...body];
134
+ const codeBytes = [...leb128u(codeBody.length), ...codeBody];
135
+ this.codes.push(codeBytes);
136
+ }
137
+
138
+ addMemory(min, max) {
139
+ if (max !== undefined && max !== min) {
140
+ this.memories = [0x01, ...leb128u(min), ...leb128u(max)];
141
+ } else {
142
+ this.memories = [0x00, ...leb128u(min)];
143
+ }
144
+ }
145
+
146
+ addDataSegment(offset, data) {
147
+ const dataBytes = [...data].map(c => c.charCodeAt(0));
148
+ const seg = [0x00, ...leb128u(offset), ...leb128u(dataBytes.length), ...dataBytes];
149
+ this.dataSegments.push(seg);
150
+ }
151
+
152
+ build() {
153
+ const sections = [];
154
+
155
+ if (this.types.length > 0) {
156
+ const content = encodeVector(this.types);
157
+ sections.push([SECTION.TYPE, ...leb128u(content.length), ...content]);
158
+ }
159
+
160
+ if (this.imports.length > 0) {
161
+ const content = encodeVector(this.imports);
162
+ sections.push([SECTION.IMPORT, ...leb128u(content.length), ...content]);
163
+ }
164
+
165
+ if (this.functions.length > 0) {
166
+ const content = encodeVector(this.functions.map(f => leb128u(f)));
167
+ sections.push([SECTION.FUNC, ...leb128u(content.length), ...content]);
168
+ }
169
+
170
+ if (this.memories.length > 0) {
171
+ const content = [...leb128u(1), ...this.memories];
172
+ sections.push([SECTION.MEMORY, ...leb128u(content.length), ...content]);
173
+ }
174
+
175
+ if (this.exports.length > 0) {
176
+ const content = encodeVector(this.exports);
177
+ sections.push([SECTION.EXPORT, ...leb128u(content.length), ...content]);
178
+ }
179
+
180
+ if (this.codes.length > 0) {
181
+ const content = encodeVector(this.codes);
182
+ sections.push([SECTION.CODE, ...leb128u(content.length), ...content]);
183
+ }
184
+
185
+ if (this.dataSegments.length > 0) {
186
+ const content = encodeVector(this.dataSegments);
187
+ sections.push([SECTION.DATA, ...leb128u(content.length), ...content]);
188
+ }
189
+
190
+ const all = [...MAGIC, ...VERSION];
191
+ for (const s of sections) all.push(...s);
192
+
193
+ return new Uint8Array(all);
194
+ }
195
+ }
196
+
197
+ const OP = {
198
+ UNREACHABLE: 0x00, NOP: 0x01, BLOCK: 0x02, LOOP: 0x03, IF: 0x04,
199
+ ELSE: 0x05, END: 0x0b, BR: 0x0c, BR_IF: 0x0d, BR_TABLE: 0x0e,
200
+ RETURN: 0x0f, CALL: 0x10, CALL_INDIRECT: 0x11,
201
+ DROP: 0x1a, SELECT: 0x1b,
202
+ LOCAL_GET: 0x20, LOCAL_SET: 0x21, LOCAL_TEE: 0x22,
203
+ GLOBAL_GET: 0x23, GLOBAL_SET: 0x24,
204
+ I32_LOAD: 0x28, I64_LOAD: 0x29, F32_LOAD: 0x2a, F64_LOAD: 0x2b,
205
+ I32_STORE: 0x36, I64_STORE: 0x37, F32_STORE: 0x38, F64_STORE: 0x39,
206
+ MEMORY_SIZE: 0x3f, MEMORY_GROW: 0x40,
207
+ I32_CONST: 0x41, I64_CONST: 0x42, F32_CONST: 0x43, F64_CONST: 0x44,
208
+ I32_EQZ: 0x45, I32_EQ: 0x46, I32_NE: 0x47,
209
+ I32_LT_S: 0x48, I32_LT_U: 0x49, I32_GT_S: 0x4a, I32_GT_U: 0x4b,
210
+ I32_LE_S: 0x4c, I32_LE_U: 0x4d, I32_GE_S: 0x4e, I32_GE_U: 0x4f,
211
+ I32_ADD: 0x6a, I32_SUB: 0x6b, I32_MUL: 0x6c, I32_DIV_S: 0x6d,
212
+ I32_DIV_U: 0x6e, I32_REM_S: 0x6f, I32_REM_U: 0x70,
213
+ I32_AND: 0x71, I32_OR: 0x72, I32_XOR: 0x73, I32_SHL: 0x74,
214
+ I32_SHR_S: 0x75, I32_SHR_U: 0x76, I32_ROTL: 0x77, I32_ROTR: 0x78,
215
+ I32_CLZ: 0x79, I32_CTZ: 0x7a, I32_POPCNT: 0x7b,
216
+ };
217
+
218
+ const EMPTY_BLOCK = [OP.BLOCK, 0x40, OP.END];
219
+ const EMPTY_LOOP = [OP.LOOP, 0x40, OP.END];
220
+
221
+ export function compileWasm(ast) {
222
+ const wasm = new WasmBuilder();
223
+
224
+ collectWasmDecls(ast, wasm);
225
+
226
+ wasm.addMemory(1, 1);
227
+
228
+ emitWasmFunctions(ast, wasm);
229
+
230
+ const mainInfo = wasm.funcMap.get("main");
231
+ if (!mainInfo) {
232
+
233
+ const tIdx = wasm.addFuncType([], ["i32"]);
234
+ wasm.functions.push(tIdx);
235
+ wasm.funcMap.set("main", { typeIdx: tIdx, funcIdx: wasm.funcIdx++, params: [] });
236
+ emitWasmFunc("main", [], "i32", ast, wasm);
237
+ }
238
+
239
+ const mainAbsIdx = wasm.importMap.size + wasm.funcMap.get("main").funcIdx;
240
+ wasm.addExport("main", 0, mainAbsIdx);
241
+
242
+ return wasm.build();
243
+ }
244
+
245
+ function collectWasmDecls(node, wasm) {
246
+ if (!node || typeof node !== "object") return;
247
+ if (Array.isArray(node)) { node.forEach(n => collectWasmDecls(n, wasm)); return; }
248
+
249
+ if (node.type === "VarDecl") {
250
+
251
+ }
252
+
253
+ if (node.type === "FunctionDecl") {
254
+ const typeIdx = wasm.addFuncType(
255
+ (node.params || []).map(() => "i32"),
256
+ ["i32"]
257
+ );
258
+ wasm.functions.push(typeIdx);
259
+ wasm.funcMap.set(node.name, {
260
+ typeIdx,
261
+ funcIdx: wasm.funcIdx++,
262
+ params: node.params || [],
263
+ });
264
+ }
265
+
266
+ if (node.type === "Call" && node.callee?.type === "Ident") {
267
+ const name = node.callee.name;
268
+ if (["SOLTA_O_GRITO", "FALA_BAIXO", "SORTEIA", "PARSEIA", "AGORA", "TAMANHO"].includes(name)) {
269
+ if (!wasm.importMap.has(name)) {
270
+ const fnType = name === "SORTEIA"
271
+ ? wasm.addFuncType(["i32", "i32"], ["i32"])
272
+ : name === "TAMANHO"
273
+ ? wasm.addFuncType(["i32"], ["i32"])
274
+ : wasm.addFuncType(["i32"], ["i32"]);
275
+ wasm.addImport("env", name, 0, fnType);
276
+ }
277
+ }
278
+ }
279
+
280
+ for (const k of Object.keys(node)) {
281
+ if (k === "type") continue;
282
+ collectWasmDecls(node[k], wasm);
283
+ }
284
+ }
285
+
286
+ function emitWasmFunctions(node, wasm) {
287
+ if (!node || typeof node !== "object") return;
288
+
289
+ if (node.type === "FunctionDecl") {
290
+ emitWasmFunc(node.name, node.params || [], "i32", node.body, wasm);
291
+ return;
292
+ }
293
+
294
+ if (node.type === "Program" || node.type === "Block") {
295
+ (node.body || []).forEach(n => emitWasmFunctions(n, wasm));
296
+ return;
297
+ }
298
+
299
+ for (const k of Object.keys(node)) {
300
+ if (k === "type" || k === "loc") continue;
301
+ const val = node[k];
302
+ if (Array.isArray(val)) {
303
+ val.forEach(v => emitWasmFunctions(v, wasm));
304
+ } else if (typeof val === "object" && val !== null) {
305
+ emitWasmFunctions(val, wasm);
306
+ }
307
+ }
308
+ }
309
+
310
+ function emitWasmFunc(name, params, resultType, body, wasm) {
311
+ const funcInfo = wasm.funcMap.get(name);
312
+ const funcIdx = funcInfo ? funcInfo.funcIdx : 0;
313
+
314
+ const scope = wasm.pushFunc(name);
315
+ for (const p of params) {
316
+ scope.vars.set(p, { index: scope.count++, type: "i32" });
317
+ }
318
+
319
+ const localVars = new Set();
320
+ countLocals(body, wasm, localVars);
321
+ for (const vname of localVars) {
322
+ wasm.addVar(vname);
323
+ }
324
+
325
+ const localCount = scope.count - params.length;
326
+ const locals = [];
327
+ if (params.length > 0) {
328
+ locals.push([params.length, "i32"]);
329
+ }
330
+ if (localCount > 0) {
331
+ locals.push([localCount, "i32"]);
332
+ }
333
+
334
+ const bodyBytes = [];
335
+ bodyBytes.push(OP.BLOCK, 0x40);
336
+ emitWasmStmt(body, bodyBytes, wasm, name);
337
+ bodyBytes.push(OP.END);
338
+ bodyBytes.push(OP.I32_CONST, 0);
339
+ bodyBytes.push(OP.END);
340
+
341
+ wasm.addCode(locals, bodyBytes);
342
+ wasm.popFunc();
343
+ }
344
+
345
+ function countLocals(node, wasm, vars) {
346
+ if (!node || typeof node !== "object") return;
347
+ if (Array.isArray(node)) { node.forEach(n => countLocals(n, wasm, vars)); return; }
348
+
349
+ if (node.type === "VarDecl") {
350
+ if (!wasm.getVar(node.id)) {
351
+ vars.add(node.id);
352
+ }
353
+ }
354
+
355
+ for (const k of Object.keys(node)) {
356
+ if (k === "type" || k === "loc") continue;
357
+ const val = node[k];
358
+ if (Array.isArray(val)) {
359
+ val.forEach(v => countLocals(v, wasm, vars));
360
+ } else if (typeof val === "object" && val !== null) {
361
+ countLocals(val, wasm, vars);
362
+ }
363
+ }
364
+ }
365
+
366
+ function emitWasmStmt(node, bytes, wasm, funcName) {
367
+ if (!node || typeof node !== "object") return;
368
+
369
+ switch (node.type) {
370
+ case "Program":
371
+ (node.body || []).forEach(n => emitWasmStmt(n, bytes, wasm, funcName));
372
+ break;
373
+
374
+ case "Block":
375
+ (node.body || []).forEach(n => emitWasmStmt(n, bytes, wasm, funcName));
376
+ break;
377
+
378
+ case "VarDecl": {
379
+ emitWasmExpr(node.init, bytes, wasm, funcName);
380
+ const v = wasm.getVar(node.id) || wasm.addVar(node.id);
381
+ if (v) {
382
+ bytes.push(OP.LOCAL_SET, v.index);
383
+ }
384
+ break;
385
+ }
386
+
387
+ case "Assign": {
388
+ if (node.left?.type === "Ident") {
389
+ emitWasmExpr(node.right, bytes, wasm, funcName);
390
+ const v = wasm.getVar(node.left.name);
391
+ if (v) {
392
+ bytes.push(OP.LOCAL_SET, v.index);
393
+ }
394
+ }
395
+ break;
396
+ }
397
+
398
+ case "ReturnStmt": {
399
+ if (node.arg) {
400
+ emitWasmExpr(node.arg, bytes, wasm, funcName);
401
+ } else {
402
+ bytes.push(OP.I32_CONST, 0);
403
+ }
404
+ bytes.push(OP.RETURN);
405
+ break;
406
+ }
407
+
408
+ case "IfStmt": {
409
+ emitWasmExpr(node.test, bytes, wasm, funcName);
410
+ bytes.push(OP.IF, 0x40);
411
+ emitWasmStmt(node.cons, bytes, wasm, funcName);
412
+ if (node.alt) {
413
+ bytes.push(OP.ELSE);
414
+ emitWasmStmt(node.alt, bytes, wasm, funcName);
415
+ }
416
+ bytes.push(OP.END);
417
+ break;
418
+ }
419
+
420
+ case "ForStmt": {
421
+ if (node.init) emitWasmStmt(node.init, bytes, wasm, funcName);
422
+
423
+ bytes.push(OP.BLOCK, 0x40);
424
+ bytes.push(OP.LOOP, 0x40);
425
+ emitWasmExpr(node.test, bytes, wasm, funcName);
426
+ bytes.push(OP.I32_EQZ);
427
+ bytes.push(OP.BR_IF, 1);
428
+ emitWasmStmt(node.body, bytes, wasm, funcName);
429
+ if (node.update) emitWasmStmt(node.update, bytes, wasm, funcName);
430
+ bytes.push(OP.BR, 0);
431
+ bytes.push(OP.END);
432
+ bytes.push(OP.END);
433
+ break;
434
+ }
435
+
436
+ case "WhileStmt": {
437
+ bytes.push(OP.BLOCK, 0x40);
438
+ bytes.push(OP.LOOP, 0x40);
439
+ emitWasmExpr(node.test, bytes, wasm, funcName);
440
+ bytes.push(OP.I32_EQZ);
441
+ bytes.push(OP.BR_IF, 0);
442
+ emitWasmStmt(node.body, bytes, wasm, funcName);
443
+ bytes.push(OP.BR, 1);
444
+ bytes.push(OP.END);
445
+ bytes.push(OP.END);
446
+ break;
447
+ }
448
+
449
+ case "BreakStmt":
450
+ bytes.push(OP.BR, 1);
451
+ break;
452
+
453
+ case "ContinueStmt":
454
+ bytes.push(OP.BR, 0);
455
+ break;
456
+
457
+ case "Call": {
458
+ if (node.callee?.type === "Ident") {
459
+ const name = node.callee.name;
460
+ const imp = wasm.importMap.get(name);
461
+ if (imp) {
462
+ for (const arg of node.args) emitWasmExpr(arg, bytes, wasm, funcName);
463
+ bytes.push(OP.CALL, ...leb128u(imp.idx));
464
+ } else {
465
+ const func = wasm.funcMap.get(name);
466
+ if (func) {
467
+ for (const arg of node.args) emitWasmExpr(arg, bytes, wasm, funcName);
468
+ bytes.push(OP.CALL, ...leb128u(func.funcIdx + wasm.importMap.size));
469
+ }
470
+ }
471
+ }
472
+ break;
473
+ }
474
+
475
+ case "ExpressionStmt": {
476
+ emitWasmExpr(node.expression, bytes, wasm, funcName);
477
+ bytes.push(OP.DROP);
478
+ break;
479
+ }
480
+ }
481
+ }
482
+
483
+ function emitWasmExpr(node, bytes, wasm, funcName) {
484
+ if (!node || typeof node !== "object") return;
485
+
486
+ switch (node.type) {
487
+ case "Num": {
488
+ const val = node.value | 0;
489
+ if (val >= 0 && val < 128) {
490
+ bytes.push(OP.I32_CONST, val);
491
+ } else {
492
+ bytes.push(OP.I32_CONST, ...leb128s(val));
493
+ }
494
+ break;
495
+ }
496
+
497
+ case "Bool":
498
+ bytes.push(OP.I32_CONST, node.value ? 1 : 0);
499
+ break;
500
+
501
+ case "Nil":
502
+ bytes.push(OP.I32_CONST, 0);
503
+ break;
504
+
505
+ case "Ident": {
506
+ const v = wasm.getVar(node.name);
507
+ if (v) {
508
+ bytes.push(OP.LOCAL_GET, v.index);
509
+ } else {
510
+ bytes.push(OP.I32_CONST, 0);
511
+ }
512
+ break;
513
+ }
514
+
515
+ case "Binary": {
516
+ const opMap = {
517
+ "+": OP.I32_ADD, "-": OP.I32_SUB, "*": OP.I32_MUL,
518
+ "/": OP.I32_DIV_S, "%": OP.I32_REM_S,
519
+ "==": OP.I32_EQ, "!=": OP.I32_NE,
520
+ ">": OP.I32_GT_S, "<": OP.I32_LT_S,
521
+ ">=": OP.I32_GE_S, "<=": OP.I32_LE_S,
522
+ "&&": OP.I32_AND, "||": OP.I32_OR,
523
+ };
524
+ emitWasmExpr(node.left, bytes, wasm, funcName);
525
+ emitWasmExpr(node.right, bytes, wasm, funcName);
526
+ if (opMap[node.op]) {
527
+ bytes.push(opMap[node.op]);
528
+ }
529
+ break;
530
+ }
531
+
532
+ case "Unary": {
533
+ emitWasmExpr(node.arg, bytes, wasm, funcName);
534
+ if (node.op === "-") {
535
+ bytes.push(OP.I32_CONST, 0, OP.I32_SUB);
536
+ }
537
+ if (node.op === "!") {
538
+ bytes.push(OP.I32_EQZ);
539
+ }
540
+ break;
541
+ }
542
+
543
+ case "Ternary": {
544
+ emitWasmExpr(node.test, bytes, wasm, funcName);
545
+ bytes.push(OP.IF, 0x7f);
546
+ emitWasmExpr(node.cons, bytes, wasm, funcName);
547
+ bytes.push(OP.ELSE);
548
+ emitWasmExpr(node.alt, bytes, wasm, funcName);
549
+ bytes.push(OP.END);
550
+ break;
551
+ }
552
+
553
+ case "Call": {
554
+ if (node.callee?.type === "Ident") {
555
+ const name = node.callee.name;
556
+ const imp = wasm.importMap.get(name);
557
+ if (imp) {
558
+ for (const arg of node.args) emitWasmExpr(arg, bytes, wasm, funcName);
559
+ bytes.push(OP.CALL, ...leb128u(imp.idx));
560
+ } else {
561
+ const func = wasm.funcMap.get(name);
562
+ if (func) {
563
+ for (const arg of node.args) emitWasmExpr(arg, bytes, wasm, funcName);
564
+ bytes.push(OP.CALL, ...leb128u(func.funcIdx + wasm.importMap.size));
565
+ }
566
+ }
567
+ }
568
+ break;
569
+ }
570
+ }
571
+ }
572
+
573
+ export { generateWasm, getWasmRuntime, getDefaultExports } from "./codegen_wasm.js";
package/std/math.xs ADDED
@@ -0,0 +1,60 @@
1
+ PARTIU()
2
+
3
+ CHAMA ESSE CARA soma(a, b) {
4
+ VOLTA a + b
5
+ }
6
+
7
+ CHAMA ESSE CARA sub(a, b) {
8
+ VOLTA a - b
9
+ }
10
+
11
+ CHAMA ESSE CARA mul(a, b) {
12
+ VOLTA a * b
13
+ }
14
+
15
+ CHAMA ESSE CARA div(a, b) {
16
+ VOLTA a / b
17
+ }
18
+
19
+ CHAMA ESSE CARA mod(a, b) {
20
+ VOLTA a % b
21
+ }
22
+
23
+ CHAMA ESSE CARA abs(n) {
24
+ SE LIGA SO (n < 0) {
25
+ VOLTA -n
26
+ }
27
+ VOLTA n
28
+ }
29
+
30
+ CHAMA ESSE CARA max(a, b) {
31
+ SE LIGA SO (a > b) {
32
+ VOLTA a
33
+ }
34
+ VOLTA b
35
+ }
36
+
37
+ CHAMA ESSE CARA min(a, b) {
38
+ SE LIGA SO (a < b) {
39
+ VOLTA a
40
+ }
41
+ VOLTA b
42
+ }
43
+
44
+ CHAMA ESSE CARA clamp(val, min, max) {
45
+ SE LIGA SO (val < min) { VOLTA min }
46
+ SE LIGA SO (val > max) { VOLTA max }
47
+ VOLTA val
48
+ }
49
+
50
+ EXPORTA soma
51
+ EXPORTA sub
52
+ EXPORTA mul
53
+ EXPORTA div
54
+ EXPORTA mod
55
+ EXPORTA abs
56
+ EXPORTA max
57
+ EXPORTA min
58
+ EXPORTA clamp
59
+
60
+ ACABOU()