porffor 0.2.0-a6c01f5 → 0.2.0-a88bbe6

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.
package/compiler/opt.js CHANGED
@@ -172,14 +172,14 @@ export default (funcs, globals, pages, tags, exceptions) => {
172
172
  }
173
173
  }
174
174
 
175
- if (inst[inst.length - 1] === 'string_only' && !pages.hasAnyString) {
175
+ if (inst[inst.length - 1] === 'string_only' && !pages.hasAnyString && !Prefs.noRmUnusedTypes) {
176
176
  // remove this inst
177
177
  wasm.splice(i, 1);
178
178
  if (i > 0) i--;
179
179
  inst = wasm[i];
180
180
  }
181
181
 
182
- if (inst[inst.length - 1] === 'string_only|start' && !pages.hasAnyString) {
182
+ if (inst[inst.length - 1] === 'string_only|start' && !pages.hasAnyString&& !Prefs.noRmUnusedTypes) {
183
183
  let j = i;
184
184
  for (; j < wasm.length; j++) {
185
185
  const op = wasm[j];
@@ -193,7 +193,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
193
193
  inst = wasm[i];
194
194
  }
195
195
 
196
- if (inst[0] === Opcodes.if && typeof inst[2] === 'string') {
196
+ if (inst[0] === Opcodes.if && typeof inst[2] === 'string' && !Prefs.noRmUnusedTypes) {
197
197
  // remove unneeded typeswitch checks
198
198
 
199
199
  const type = inst[2].split('|')[1];
package/compiler/parse.js CHANGED
@@ -9,8 +9,10 @@ if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
9
9
  globalThis.process = { argv: ['', '', ...Deno.args], stdout: { write: str => Deno.writeAllSync(Deno.stdout, textEncoder.encode(str)) } };
10
10
  }
11
11
 
12
+ const file = process.argv.slice(2).find(x => x[0] !== '-');
13
+
12
14
  // should we try to support types (while parsing)
13
- const types = Prefs.parseTypes;
15
+ const types = Prefs.parseTypes || file?.endsWith('.ts');
14
16
  globalThis.typedInput = types && Prefs.optTypes;
15
17
 
16
18
  // todo: review which to use by default
@@ -23,7 +25,7 @@ globalThis.typedInput = types && Prefs.optTypes;
23
25
  globalThis.parser = '';
24
26
  let parse;
25
27
  const loadParser = async (fallbackParser = 'acorn', forceParser) => {
26
- parser = forceParser ?? process.argv.find(x => x.startsWith('-parser='))?.split('=')?.[1] ?? fallbackParser;
28
+ parser = forceParser ?? process.argv.find(x => x.startsWith('--parser='))?.split('=')?.[1] ?? fallbackParser;
27
29
  0, { parse } = (await import((globalThis.document || globalThis.Deno ? 'https://esm.sh/' : '') + parser));
28
30
  };
29
31
  globalThis._porf_loadParser = loadParser;
@@ -7,9 +7,6 @@ import { join } from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
8
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
9
9
 
10
- // import porfParse from './parse.js';
11
- // import porfCodegen from './codeGen.js';
12
-
13
10
  const argv = process.argv.slice();
14
11
 
15
12
  const compile = async (file, [ _funcs, _globals ]) => {
@@ -21,17 +18,12 @@ const compile = async (file, [ _funcs, _globals ]) => {
21
18
  first = source.slice(0, source.indexOf('\n'));
22
19
  }
23
20
 
24
- let args = ['-bytestring', '-todo-time=compile', '-no-aot-pointer-opt', '-no-treeshake-wasm-imports', '-scoped-page-names', '-parse-types', '-opt-types'];
21
+ let args = ['--bytestring', '--todo-time=compile', '--no-aot-pointer-opt', '--no-treeshake-wasm-imports', '--no-rm-unused-types', '--scoped-page-names', '--funsafe-no-unlikely-proto-checks', '--parse-types', '--opt-types'];
25
22
  if (first.startsWith('// @porf')) {
26
23
  args = args.concat(first.slice('// @porf '.length).split(' '));
27
24
  }
28
25
  process.argv = argv.concat(args);
29
26
 
30
- // const porfParse = (await import(`./parse.js?_=${Date.now()}`)).default;
31
- // const porfCodegen = (await import(`./codeGen.js?_=${Date.now()}`)).default;
32
-
33
- // let { funcs, globals, data } = porfCodegen(porfParse(source, ['module']));
34
-
35
27
  const porfCompile = (await import(`./index.js?_=${Date.now()}`)).default;
36
28
 
37
29
  let { funcs, globals, data, exceptions } = porfCompile(source, ['module']);
@@ -70,7 +62,7 @@ const compile = async (file, [ _funcs, _globals ]) => {
70
62
  if (y[0] === Opcodes.const && (n[0] === Opcodes.local_set || n[0] === Opcodes.local_tee)) {
71
63
  const l = locals[n[1]];
72
64
  if (!l) continue;
73
- if (![TYPES.string, TYPES._array, TYPES._bytestring].includes(l.metadata?.type)) continue;
65
+ if (![TYPES.string, TYPES.array, TYPES.bytestring].includes(l.metadata?.type)) continue;
74
66
  if (!x.pages) continue;
75
67
 
76
68
  const pageName = [...x.pages.keys()].find(z => z.endsWith(l.name));
@@ -78,7 +70,14 @@ const compile = async (file, [ _funcs, _globals ]) => {
78
70
  allocated.add(pageName);
79
71
 
80
72
  y.splice(0, 10, 'alloc', pageName, x.pages.get(pageName).type, valtypeBinary);
81
- // y.push(x.pages.get(pageName));
73
+ }
74
+
75
+ if (y[0] === Opcodes.i32_const && n[0] === Opcodes.throw) {
76
+ const id = y[1];
77
+ y.splice(0, 10, 'throw', exceptions[id].constructor, exceptions[id].message);
78
+
79
+ // remove throw inst
80
+ x.wasm.splice(i + 1, 1);
82
81
  }
83
82
  }
84
83
  }
@@ -93,31 +92,29 @@ const precompile = async () => {
93
92
  let funcs = [], globals = [];
94
93
  for (const file of fs.readdirSync(dir)) {
95
94
  if (file.endsWith('.d.ts')) continue;
95
+ console.log(file);
96
+
96
97
  await compile(join(dir, file), [ funcs, globals ]);
97
98
  }
98
99
 
99
- // ${x.pages && x.pages.size > 0 ? ` pages: ${JSON.stringify(Object.fromEntries(x.pages.entries()))},` : ''}
100
- // ${x.used && x.used.length > 0 ? ` used: ${JSON.stringify(x.used)},` : ''}
101
-
102
100
  return `// autogenerated by compiler/precompile.js
103
101
  import { number } from './embedding.js';
104
102
 
105
103
  export const BuiltinFuncs = function() {
106
- ${funcs.map(x => ` this.${x.name} = {
107
- wasm: (scope, { allocPage, builtin }) => ${JSON.stringify(x.wasm.filter(x => x.length && x[0] != null)).replace(/\["alloc","(.*?)","(.*?)",(.*?)\]/g, (_, reason, type, valtype) => `...number(allocPage(scope, '${reason}', '${type}') * pageSize, ${valtype})`).replace(/\[16,"(.*?)"]/g, (_, name) => `[16, builtin('${name}')]`)},
104
+ ${funcs.map(x => {
105
+ const wasm = JSON.stringify(x.wasm.filter(x => x.length && x[0] != null)).replace(/\["alloc","(.*?)","(.*?)",(.*?)\]/g, (_, reason, type, valtype) => `...number(allocPage(scope, '${reason}', '${type}') * pageSize, ${valtype})`).replace(/\[16,"(.*?)"]/g, (_, name) => `[16, builtin('${name}')]`).replace(/\["throw","(.*?)","(.*?)"\]/g, (_, constructor, message) => `...internalThrow(scope, '${constructor}', \`${message}\`)`);
106
+ return ` this.${x.name} = {
107
+ wasm: (scope, {${wasm.includes('allocPage(') ? 'allocPage,' : ''}${wasm.includes('builtin(') ? 'builtin,' : ''}${wasm.includes('internalThrow(') ? 'internalThrow,' : ''}}) => ${wasm},
108
108
  params: ${JSON.stringify(x.params)},
109
109
  typedParams: true,
110
110
  returns: ${JSON.stringify(x.returns)},
111
111
  ${x.returnType != null ? `returnType: ${JSON.stringify(x.returnType)}` : 'typedReturns: true'},
112
112
  locals: ${JSON.stringify(Object.values(x.locals).slice(x.params.length).map(x => x.type))},
113
113
  localNames: ${JSON.stringify(Object.keys(x.locals))},
114
- ${x.data && x.data.length > 0 ? ` data: ${JSON.stringify(x.data)},` : ''}
115
- ${x.exceptions && x.exceptions.length > 0 ? ` exceptions: ${JSON.stringify(x.exceptions)},` : ''}
116
- };`.replaceAll('\n\n', '\n').replaceAll('\n\n', '\n')).join('\n')}
114
+ ${x.data && x.data.length > 0 ? ` data: ${JSON.stringify(x.data)}` : ''}
115
+ };`.replaceAll('\n\n', '\n').replaceAll('\n\n', '\n')
116
+ }).join('\n')}
117
117
  };`;
118
118
  };
119
119
 
120
- const code = await precompile();
121
- // console.log(code);
122
-
123
- fs.writeFileSync(join(__dirname, 'generated_builtins.js'), code);
120
+ fs.writeFileSync(join(__dirname, 'generated_builtins.js'), await precompile());
package/compiler/prefs.js CHANGED
@@ -1,4 +1,4 @@
1
- const onByDefault = [ 'bytestring', 'aotPointerOpt', 'treeshakeWasmImports' ];
1
+ const onByDefault = [ 'bytestring', 'aotPointerOpt', 'treeshakeWasmImports', 'alwaysMemory' ];
2
2
 
3
3
  let cache = {};
4
4
  const obj = new Proxy({}, {
@@ -9,11 +9,12 @@ const obj = new Proxy({}, {
9
9
  return cache[p] = (() => {
10
10
  // fooBar -> foo-bar
11
11
  const name = p[0] === '_' ? p : p.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
12
- if (process.argv.includes('-' + name)) return true;
13
- if (process.argv.includes('-no-' + name)) return false;
12
+ const prefix = name.length === 1 ? '-' : '--';
13
+ if (process.argv.includes(prefix + name)) return true;
14
+ if (process.argv.includes(prefix + 'no-' + name)) return false;
14
15
 
15
- const valArg = process.argv.find(x => x.startsWith(`-${name}=`));
16
- if (valArg) return valArg.slice(name.length + 2);
16
+ const valArg = process.argv.find(x => x.startsWith(`${prefix}${name}=`));
17
+ if (valArg) return valArg.slice(name.length + 1 + prefix.length);
17
18
 
18
19
  if (onByDefault.includes(p)) return true;
19
20
  return undefined;
@@ -14,7 +14,7 @@ export const PrototypeFuncs = function() {
14
14
  if (Prefs.zeroChecks) zeroChecks = Prefs.zeroChecks.split('=')[1].split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
15
15
  else zeroChecks = {};
16
16
 
17
- this[TYPES._array] = {
17
+ this[TYPES.array] = {
18
18
  // lX = local accessor of X ({ get, set }), iX = local index of X, wX = wasm ops of X
19
19
  at: (pointer, length, wIndex, iTmp) => [
20
20
  ...wIndex,
@@ -253,10 +253,10 @@ export const PrototypeFuncs = function() {
253
253
  ]
254
254
  };
255
255
 
256
- this[TYPES._array].at.local = Valtype.i32;
257
- this[TYPES._array].push.noArgRetLength = true;
258
- this[TYPES._array].fill.local = valtypeBinary;
259
- this[TYPES._array].fill.returnType = TYPES._array;
256
+ this[TYPES.array].at.local = Valtype.i32;
257
+ this[TYPES.array].push.noArgRetLength = true;
258
+ this[TYPES.array].fill.local = valtypeBinary;
259
+ this[TYPES.array].fill.returnType = TYPES.array;
260
260
 
261
261
  this[TYPES.string] = {
262
262
  at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
@@ -476,7 +476,7 @@ export const PrototypeFuncs = function() {
476
476
  this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
477
477
 
478
478
  if (Prefs.bytestring) {
479
- this[TYPES._bytestring] = {
479
+ this[TYPES.bytestring] = {
480
480
  at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
481
481
  const [ newOut, newPointer ] = arrayShell(1, 'i8');
482
482
 
@@ -606,14 +606,14 @@ export const PrototypeFuncs = function() {
606
606
  }
607
607
  };
608
608
 
609
- this[TYPES._bytestring].at.local = Valtype.i32;
610
- this[TYPES._bytestring].at.returnType = TYPES._bytestring;
611
- this[TYPES._bytestring].charAt.returnType = TYPES._bytestring;
612
- this[TYPES._bytestring].charCodeAt.local = Valtype.i32;
613
- this[TYPES._bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
609
+ this[TYPES.bytestring].at.local = Valtype.i32;
610
+ this[TYPES.bytestring].at.returnType = TYPES.bytestring;
611
+ this[TYPES.bytestring].charAt.returnType = TYPES.bytestring;
612
+ this[TYPES.bytestring].charCodeAt.local = Valtype.i32;
613
+ this[TYPES.bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
614
614
 
615
- this[TYPES._bytestring].isWellFormed.local = Valtype.i32;
616
- this[TYPES._bytestring].isWellFormed.local2 = Valtype.i32;
617
- this[TYPES._bytestring].isWellFormed.returnType = TYPES.boolean;
615
+ this[TYPES.bytestring].isWellFormed.local = Valtype.i32;
616
+ this[TYPES.bytestring].isWellFormed.local2 = Valtype.i32;
617
+ this[TYPES.bytestring].isWellFormed.returnType = TYPES.boolean;
618
618
  }
619
619
  };
package/compiler/types.js CHANGED
@@ -24,7 +24,7 @@ export const INTERNAL_TYPE_BASE = 0x10;
24
24
  let internalTypeIndex = INTERNAL_TYPE_BASE;
25
25
  const registerInternalType = name => {
26
26
  const n = internalTypeIndex++;
27
- TYPES['_' + name.toLowerCase()] = n;
27
+ TYPES[name.toLowerCase()] = n;
28
28
  TYPE_NAMES[n] = name;
29
29
  };
30
30
 
@@ -34,4 +34,5 @@ const registerInternalType = name => {
34
34
  registerInternalType('Array');
35
35
  registerInternalType('RegExp');
36
36
  registerInternalType('ByteString');
37
- registerInternalType('Date');
37
+ registerInternalType('Date');
38
+ registerInternalType('Set');
package/compiler/wrap.js CHANGED
@@ -7,6 +7,70 @@ import { TYPES } from './types.js';
7
7
 
8
8
  const bold = x => `\u001b[1m${x}\u001b[0m`;
9
9
 
10
+ const porfToJSValue = (memory, funcs, value, type) => {
11
+ switch (type) {
12
+ case TYPES.boolean: return Boolean(value);
13
+ case TYPES.undefined: return undefined;
14
+ case TYPES.object: return value === 0 ? null : {};
15
+
16
+ case TYPES.function: {
17
+ // wasm func index, including all imports
18
+ const func = funcs.find(x => (x.originalIndex ?? x.index) === value);
19
+ // if (!func) return value;
20
+ if (!func) return function () {};
21
+
22
+ // make fake empty func for repl/etc
23
+ return {[func.name]() {}}[func.name];
24
+ }
25
+
26
+ case TYPES.string: {
27
+ const length = (new Int32Array(memory.buffer, value, 1))[0];
28
+ return Array.from(new Uint16Array(memory.buffer, value + 4, length)).map(x => String.fromCharCode(x)).join('');
29
+ }
30
+
31
+ case TYPES.bytestring: {
32
+ const length = (new Int32Array(memory.buffer, value, 1))[0];
33
+ return Array.from(new Uint8Array(memory.buffer, value + 4, length)).map(x => String.fromCharCode(x)).join('');
34
+ }
35
+
36
+ case TYPES.array: {
37
+ const length = (new Int32Array(memory.buffer, value, 1))[0];
38
+
39
+ // have to slice because of memory alignment (?)
40
+ const buf = memory.buffer.slice(value + 4, value + 4 + 8 * length);
41
+ return Array.from(new Float64Array(buf, 0, length));
42
+ }
43
+
44
+ case TYPES.date: {
45
+ const t = (new Float64Array(memory.buffer, value, 1))[0];
46
+ return new Date(t);
47
+ }
48
+
49
+ case TYPES.set: {
50
+ const size = (new Int32Array(memory.buffer, value, 1))[0];
51
+
52
+ const out = new Set();
53
+ for (let i = 0; i < size; i++) {
54
+ const offset = value + 4 + (i * 9);
55
+
56
+ // have to slice because of memory alignment (?)
57
+ const v = (new Float64Array(memory.buffer.slice(offset, offset + 8), 0, 1))[0];
58
+ const t = (new Uint8Array(memory.buffer, offset + 8, 1))[0];
59
+
60
+ // console.log(`reading value at index ${i}...`)
61
+ // console.log(' memory:', Array.from(new Uint8Array(memory.buffer, offset, 9)).map(x => x.toString(16).padStart(2, '0')).join(' '));
62
+ // console.log(' read:', { value: v, type: t }, '\n');
63
+
64
+ out.add(porfToJSValue(memory, funcs, v, t));
65
+ }
66
+
67
+ return out;
68
+ }
69
+
70
+ default: return value;
71
+ }
72
+ };
73
+
10
74
  export default async (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
11
75
  const times = [];
12
76
 
@@ -148,62 +212,11 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
148
212
 
149
213
  exports[func.name] = function() {
150
214
  try {
151
- const _ret = exp.apply(this, arguments);
152
-
153
- if (_ret == null) return undefined;
154
-
155
- const [ ret, type ] = _ret;
156
-
157
- // if (ret >= typeBase && ret <= typeBase + 8) return ret > (typeBase + 7) ? 'object' : TYPES[ret];
158
-
159
- switch (type) {
160
- case TYPES.boolean: return Boolean(ret);
161
- case TYPES.undefined: return undefined;
162
- case TYPES.object: return ret === 0 ? null : {};
163
-
164
- case TYPES.string: {
165
- const pointer = ret;
166
- const length = (new Int32Array(memory.buffer, pointer, 1))[0];
167
-
168
- return Array.from(new Uint16Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
169
- }
215
+ const ret = exp.apply(this, arguments);
170
216
 
171
- case TYPES.function: {
172
- // wasm func index, including all imports
173
- const func = funcs.find(x => (x.originalIndex ?? x.index) === ret);
174
- // if (!func) return ret;
175
- if (!func) return function () {};
217
+ if (ret == null) return undefined;
176
218
 
177
- // make fake empty func for repl/etc
178
- return {[func.name]() {}}[func.name];
179
- }
180
-
181
- case TYPES._array: {
182
- const pointer = ret;
183
- const length = (new Int32Array(memory.buffer, pointer, 1))[0];
184
-
185
- // have to slice because of memory alignment
186
- const buf = memory.buffer.slice(pointer + 4, pointer + 4 + 8 * length);
187
-
188
- return Array.from(new Float64Array(buf));
189
- }
190
-
191
- case TYPES._bytestring: {
192
- const pointer = ret;
193
- const length = (new Int32Array(memory.buffer, pointer, 1))[0];
194
-
195
- return Array.from(new Uint8Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
196
- }
197
-
198
- case TYPES._date: {
199
- const pointer = ret;
200
- const value = (new Float64Array(memory.buffer, pointer, 1))[0];
201
-
202
- return new Date(value);
203
- }
204
-
205
- default: return ret;
206
- }
219
+ return porfToJSValue(memory, funcs, ret[0], ret[1])
207
220
  } catch (e) {
208
221
  if (e.is && e.is(exceptTag)) {
209
222
  const exceptId = e.getArg(exceptTag, 0);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
4
- "version": "0.2.0-a6c01f5",
4
+ "version": "0.2.0-a88bbe6",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {
package/rhemyn/compile.js CHANGED
@@ -1,8 +1,8 @@
1
- import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from '../compiler/wasmSpec.js';
1
+ import { Blocktype, Opcodes, Valtype, ValtypeSize } from '../compiler/wasmSpec.js';
2
2
  import { number } from '../compiler/embedding.js';
3
- import { signedLEB128, unsignedLEB128 } from '../compiler/encoding.js';
4
3
  import parse from './parse.js';
5
4
  import Prefs from '../compiler/prefs.js';
5
+ import { TYPES } from '../compiler/types.js';
6
6
 
7
7
  // local indexes
8
8
  const BasePointer = 0; // base string pointer
@@ -14,7 +14,7 @@ const Length = 5;
14
14
  const Tmp = 6;
15
15
 
16
16
  let exprLastGet = false;
17
- const generate = (node, negated = false, get = true, func = 'test') => {
17
+ const generate = (node, negated = false, get = true, stringSize = 2, func = 'test') => {
18
18
  let out = [];
19
19
  switch (node.type) {
20
20
  case 'Expression':
@@ -42,7 +42,7 @@ const generate = (node, negated = false, get = true, func = 'test') => {
42
42
  // generate checks
43
43
  ...node.body.flatMap((x, i) => {
44
44
  exprLastGet = x.type !== 'Group' && i === (node.body.length - 1);
45
- return generate(x, negated);
45
+ return generate(x, negated, true, stringSize, func);
46
46
  }),
47
47
 
48
48
  // reached end without branching out, successful match
@@ -56,9 +56,9 @@ const generate = (node, negated = false, get = true, func = 'test') => {
56
56
 
57
57
  [ Opcodes.end ],
58
58
 
59
- // increment iter pointer by sizeof i16
59
+ // increment iter pointer by string size
60
60
  [ Opcodes.local_get, IterPointer ],
61
- ...number(ValtypeSize.i16, Valtype.i32),
61
+ ...number(stringSize, Valtype.i32),
62
62
  [ Opcodes.i32_add ],
63
63
  [ Opcodes.local_set, IterPointer ],
64
64
 
@@ -91,34 +91,34 @@ const generate = (node, negated = false, get = true, func = 'test') => {
91
91
  break;
92
92
 
93
93
  case 'Character':
94
- out = generateChar(node, node.negated ^ negated, get);
94
+ out = generateChar(node, node.negated ^ negated, get, stringSize);
95
95
  break;
96
96
 
97
97
  case 'Set':
98
- out = generateSet(node, node.negated, get);
98
+ out = generateSet(node, node.negated, get, stringSize);
99
99
  break;
100
100
 
101
101
  case 'Group':
102
- out = generateGroup(node, negated, get);
102
+ out = generateGroup(node, negated, get, stringSize);
103
103
  break;
104
104
 
105
105
  case 'Range':
106
- out = generateRange(node, negated, get);
106
+ out = generateRange(node, negated, get, stringSize);
107
107
  break;
108
108
  }
109
109
 
110
110
  return out;
111
111
  };
112
112
 
113
- const getNextChar = () => [
113
+ const getNextChar = (stringSize) => [
114
114
  // get char from pointer
115
115
  [ Opcodes.local_get, Pointer ],
116
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(0) ],
116
+ [ stringSize == 2 ? Opcodes.i32_load16_u : Opcodes.i32_load8_u, 0, 0 ],
117
117
 
118
118
  ...(exprLastGet ? [] : [
119
- // pointer += sizeof i16
119
+ // pointer += string size
120
120
  [ Opcodes.local_get, Pointer ],
121
- ...number(ValtypeSize.i16, Valtype.i32),
121
+ ...number(stringSize, Valtype.i32),
122
122
  [ Opcodes.i32_add ],
123
123
  [ Opcodes.local_set, Pointer ]
124
124
  ])
@@ -134,21 +134,21 @@ const checkFailure = () => [
134
134
  [ Opcodes.br_if, 0 ]
135
135
  ];
136
136
 
137
- const generateChar = (node, negated, get) => {
137
+ const generateChar = (node, negated, get, stringSize) => {
138
138
  return [
139
- ...(get ? getNextChar() : []),
139
+ ...(get ? getNextChar(stringSize) : []),
140
140
  ...number(node.char.charCodeAt(0), Valtype.i32),
141
141
  negated ? [ Opcodes.i32_eq ] : [ Opcodes.i32_ne ],
142
142
  ...(get ? checkFailure(): [])
143
143
  ];
144
144
  };
145
145
 
146
- const generateSet = (node, negated, get) => {
146
+ const generateSet = (node, negated, get, stringSize) => {
147
147
  // for a single char we do not need a tmp, it is like just
148
148
  const singleChar = node.body.length === 1 && node.body[0].type === 'Character';
149
149
 
150
150
  let out = [
151
- ...(get ? getNextChar() : []),
151
+ ...(get ? getNextChar(stringSize) : []),
152
152
  ...(singleChar ? [] : [ [ Opcodes.local_set, Tmp ] ]),
153
153
  ];
154
154
 
@@ -156,7 +156,7 @@ const generateSet = (node, negated, get) => {
156
156
  out = [
157
157
  ...out,
158
158
  ...(singleChar ? [] : [ [ Opcodes.local_get, Tmp ] ]),
159
- ...generate(x, negated, false)
159
+ ...generate(x, negated, false, stringSize)
160
160
  ];
161
161
  }
162
162
 
@@ -168,9 +168,9 @@ const generateSet = (node, negated, get) => {
168
168
  ];
169
169
  };
170
170
 
171
- const generateRange = (node, negated, get) => {
171
+ const generateRange = (node, negated, get, stringSize) => {
172
172
  return [
173
- ...(get ? getNextChar() : []),
173
+ ...(get ? getNextChar(stringSize) : []),
174
174
  ...(get ? [ [ Opcodes.local_tee, Tmp ] ] : []),
175
175
 
176
176
  ...number(node.from.charCodeAt(0), Valtype.i32),
@@ -192,8 +192,25 @@ const generateGroup = (node, negated, get) => {
192
192
  return [];
193
193
  };
194
194
 
195
- export const test = (regex, index = 0, name = 'regex_test_' + regex) => outputFunc(generate(parse(regex), false, true, 'test'), name, index);
196
- export const search = (regex, index = 0, name = 'regex_search_' + regex) => outputFunc(generate(parse(regex), false, true, 'search'), name, index);
195
+ const wrapFunc = (regex, func, name, index) => {
196
+ const parsed = parse(regex);
197
+
198
+ return outputFunc([
199
+ [ Opcodes.local_get, 1 ],
200
+ ...number(TYPES.string, Valtype.i32),
201
+ [ Opcodes.i32_eq ],
202
+ [ Opcodes.if, Valtype.i32 ],
203
+ // string
204
+ ...generate(parsed, false, true, 2, func),
205
+ [ Opcodes.else ],
206
+ // bytestring
207
+ ...generate(parsed, false, true, 1, func),
208
+ [ Opcodes.end ]
209
+ ], name, index);
210
+ };
211
+
212
+ export const test = (regex, index = 0, name = 'regex_test_' + regex) => wrapFunc(regex, 'test', name, index);
213
+ export const search = (regex, index = 0, name = 'regex_search_' + regex) => wrapFunc(regex, 'search', name, index);
197
214
 
198
215
  const outputFunc = (wasm, name, index) => ({
199
216
  name,
@@ -201,9 +218,9 @@ const outputFunc = (wasm, name, index) => ({
201
218
  wasm,
202
219
 
203
220
  export: true,
204
- params: [ Valtype.i32 ],
221
+ params: [ Valtype.i32, Valtype.i32 ],
205
222
  returns: [ Valtype.i32 ],
206
- returnType: 0xffffffffffff1, // boolean - todo: do not hardcode this
223
+ returnType: TYPES.boolean,
207
224
  locals: {
208
225
  basePointer: { idx: 0, type: Valtype.i32 },
209
226
  iterPointer: { idx: 1, type: Valtype.i32 },
package/rhemyn/parse.js CHANGED
@@ -11,7 +11,7 @@ const Quantifiers = {
11
11
  const QuantifierKeys = Object.keys(Quantifiers);
12
12
 
13
13
  const getArg = (name, def) => {
14
- const arg = (typeof process !== 'undefined' ? process.argv : Deno.args).find(x => x.startsWith(`-${name}=`));
14
+ const arg = (typeof process !== 'undefined' ? process.argv : Deno.args).find(x => x.startsWith(`--${name}=`));
15
15
  if (arg) return arg.split('=')[0];
16
16
 
17
17
  return def;
@@ -20,8 +20,7 @@ const getArg = (name, def) => {
20
20
  // full is spec-compliant but slower. not needed most of the time. (evil)
21
21
  const DotChars = () => ({
22
22
  full: [ '\n', '\r', '\u2028', '\u2029' ],
23
- simple: [ '\n', '\r' ],
24
- fast: [ '\n' ]
23
+ fast: [ '\n', '\r' ]
25
24
  })[getArg('regex-dot', 'fast')];
26
25
 
27
26
  const WordChars = () => ({
@@ -31,8 +30,8 @@ const WordChars = () => ({
31
30
 
32
31
  const WhitespaceChars = () => ({
33
32
  full: [ ' ', '\t', '\n', '\r', '\u2028', '\u2029' ],
34
- simple: [ ' ', '\t', '\n', '\r' ]
35
- })[getArg('regex-ws', 'simple')];
33
+ fast: [ ' ', '\t', '\n', '\r' ]
34
+ })[getArg('regex-ws', 'fast')];
36
35
 
37
36
  const _Metachars = () => ({
38
37
  unescaped: {
package/runner/index.js CHANGED
@@ -5,7 +5,7 @@ import fs from 'node:fs';
5
5
 
6
6
  const start = performance.now();
7
7
 
8
- if (process.argv.includes('-compile-hints')) {
8
+ if (process.argv.includes('--compile-hints')) {
9
9
  const v8 = await import('node:v8');
10
10
  v8.setFlagsFromString(`--experimental-wasm-compilation-hints`);
11
11
 
@@ -29,8 +29,8 @@ if (process.argv.includes('--help')) {
29
29
  for (const [ cmd, [ color, desc ] ] of Object.entries({
30
30
  run: [ 34, 'Run a JS file' ],
31
31
  wasm: [ 34, 'Compile a JS file to a Wasm binary\n' ],
32
- native: [ 31, 'Compile a JS file to a native binary' ],
33
- c: [ 31, 'Compile a JS file to C source code\n' ],
32
+ c: [ 31, 'Compile a JS file to C source code' ],
33
+ native: [ 31, 'Compile a JS file to a native binary\n' ],
34
34
  profile: [ 33, 'Profile a JS file' ],
35
35
  debug: [ 33, 'Debug a JS file' ],
36
36
  'debug-wasm': [ 33, 'Debug the compiled Wasm of a JS file' ]
@@ -38,6 +38,22 @@ if (process.argv.includes('--help')) {
38
38
  console.log(` \x1B[1m\x1B[${color}m${cmd}\x1B[0m${' '.repeat(20 - cmd.length - (desc.startsWith('🧪') ? 3 : 0))}${desc}`);
39
39
  }
40
40
 
41
+ // console.log();
42
+
43
+ // // options
44
+ // console.log(`\n\u001b[4mCommands\x1B[0m`);
45
+ // for (const [ cmd, [ color, desc ] ] of Object.entries({
46
+ // run: [ 34, 'Run a JS file' ],
47
+ // wasm: [ 34, 'Compile a JS file to a Wasm binary\n' ],
48
+ // c: [ 31, 'Compile a JS file to C source code' ],
49
+ // native: [ 31, 'Compile a JS file to a native binary\n' ],
50
+ // profile: [ 33, 'Profile a JS file' ],
51
+ // debug: [ 33, 'Debug a JS file' ],
52
+ // 'debug-wasm': [ 33, 'Debug the compiled Wasm of a JS file' ]
53
+ // })) {
54
+ // console.log(` \x1B[1m\x1B[${color}m${cmd}\x1B[0m${' '.repeat(20 - cmd.length - (desc.startsWith('🧪') ? 3 : 0))}${desc}`);
55
+ // }
56
+
41
57
  console.log();
42
58
  process.exit(0);
43
59
  }
@@ -51,11 +67,11 @@ if (['run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm'].includes(fi
51
67
  }
52
68
 
53
69
  if (['wasm', 'native', 'c'].includes(file)) {
54
- process.argv.push(`-target=${file}`);
70
+ process.argv.push(`--target=${file}`);
55
71
  }
56
72
 
57
73
  if (file === 'debug-wasm') {
58
- process.argv.push('-asur', '-wasm-debug');
74
+ process.argv.push('--asur', '--wasm-debug');
59
75
  }
60
76
 
61
77
  if (file === 'debug') {
@@ -102,7 +118,7 @@ try {
102
118
  if (process.argv.includes('-b')) {
103
119
  const { wasm, exports } = await compile(source, process.argv.includes('--module') ? [ 'module' ] : [], {}, print);
104
120
 
105
- if (!process.argv.includes('-no-run')) exports.main();
121
+ if (!process.argv.includes('--no-run')) exports.main();
106
122
 
107
123
  console.log(`\n\nwasm size: ${wasm.byteLength} bytes`);
108
124
  } else {
package/runner/repl.js CHANGED
@@ -21,7 +21,7 @@ try {
21
21
 
22
22
  globalThis.valtype = 'f64';
23
23
 
24
- const valtypeOpt = process.argv.find(x => x.startsWith('-valtype='));
24
+ const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
25
25
  if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
26
26
 
27
27
  let host = globalThis?.navigator?.userAgent;
@@ -116,7 +116,7 @@ replServer.defineCommand('asm', {
116
116
  this.clearBufferedCommand();
117
117
 
118
118
  try {
119
- process.argv.push('-opt-funcs');
119
+ process.argv.push('--opt-funcs');
120
120
  await run('', null, null, () => {}, false);
121
121
  process.argv.pop();
122
122
  } catch { }