zuzu-js 0.1.1 → 0.1.2

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/lib/cli.js CHANGED
@@ -254,7 +254,7 @@ function stripShebang( source ) {
254
254
  }
255
255
 
256
256
  function printVersion( runtime, verbose ) {
257
- process.stdout.write( 'zuzu-js version 0.1.1\n' );
257
+ process.stdout.write( 'zuzu-js version 0.1.2\n' );
258
258
  if ( verbose ) {
259
259
  process.stdout.write( '\nlib search paths:\n' );
260
260
  for ( const p of runtime.getModuleSearchRoots() ) {
package/lib/runtime.js CHANGED
@@ -1904,6 +1904,13 @@ function zuzuTypeMatches( value, typeName ) {
1904
1904
  if ( typeName === 'PairList' ) {
1905
1905
  return isPairListLike( value ) ? 1 : 0;
1906
1906
  }
1907
+ if ( typeName === 'Exception' ) {
1908
+ const globalType = globalThis.Exception;
1909
+ if ( globalType != null && zuzuInstanceof( value, globalType ) ) {
1910
+ return 1;
1911
+ }
1912
+ return value instanceof Error ? 1 : 0;
1913
+ }
1907
1914
  return zuzuTypeof( value ) === typeName ? 1 : 0;
1908
1915
  }
1909
1916
  if ( typeName === 'BinaryString' ) {
@@ -32,6 +32,7 @@ function emitProgram( ast, options = {} ) {
32
32
  ...options,
33
33
  asyncContext: needsAsyncWrapper && !syncEval,
34
34
  asyncNames: new Set( collectAsyncFunctionNames( ast.body ) ),
35
+ evalNames: new Set( [ 'eval', ...collectEvalImportNames( ast.body ) ] ),
35
36
  weakStorageNames: new Set( collectWeakDeclaredNames( ast.body ) ),
36
37
  scopeNames: new Set( [
37
38
  ...expressionDeclaredNames,
@@ -91,6 +92,7 @@ function marshalCaptureNames( node, options = currentEmitContext() ) {
91
92
  '__file__',
92
93
  '__global__',
93
94
  '__system__',
95
+ ...( options.evalNames || [] ),
94
96
  ].filter( Boolean ) );
95
97
  const localKinds = new Set( [
96
98
  'FunctionDeclaration',
@@ -124,6 +126,21 @@ function marshalCaptureNames( node, options = currentEmitContext() ) {
124
126
  }
125
127
  return;
126
128
  }
129
+ if ( value.type === 'TryStatement' ) {
130
+ visit( value.block, value );
131
+ for ( const handler of value.handlers || [] ) {
132
+ const paramName = handler.paramName;
133
+ const hadParam = paramName ? declared.has( paramName ) : false;
134
+ if ( paramName ) {
135
+ declared.add( paramName );
136
+ }
137
+ visit( handler.body, handler );
138
+ if ( paramName && !hadParam ) {
139
+ declared.delete( paramName );
140
+ }
141
+ }
142
+ return;
143
+ }
127
144
  if ( value.type === 'VariableUnpackDeclaration' ) {
128
145
  visit( value.init, value );
129
146
  for ( const entry of bindingEntriesForPattern( value.pattern ) ) {
@@ -204,6 +221,7 @@ function nestedFunctionOptions( options = {} ) {
204
221
  syncEval: options.syncEval,
205
222
  asyncContext: options.asyncContext,
206
223
  asyncNames: options.asyncNames,
224
+ evalNames: options.evalNames,
207
225
  weakStorageNames: options.weakStorageNames,
208
226
  scopeNames: options.scopeNames,
209
227
  bodylessFunctionNames: options.bodylessFunctionNames,
@@ -898,7 +916,6 @@ function emitImportDeclaration( node, options = {} ) {
898
916
  if (
899
917
  node.source === 'std/eval'
900
918
  && importedName === 'eval'
901
- && specifier.local === 'eval'
902
919
  ) {
903
920
  return '';
904
921
  }
@@ -1101,6 +1118,22 @@ function collectAsyncFunctionNames( statements = [] ) {
1101
1118
  return names;
1102
1119
  }
1103
1120
 
1121
+ function collectEvalImportNames( statements = [] ) {
1122
+ const names = [];
1123
+ for ( const stmt of statements ) {
1124
+ if ( stmt.type !== 'ImportDeclaration' || stmt.source !== 'std/eval' ) {
1125
+ continue;
1126
+ }
1127
+ for ( const specifier of stmt.specifiers || [] ) {
1128
+ const importedName = normalizeImportedName( stmt.source, specifier.imported );
1129
+ if ( importedName === 'eval' && specifier.local ) {
1130
+ names.push( specifier.local );
1131
+ }
1132
+ }
1133
+ }
1134
+ return names;
1135
+ }
1136
+
1104
1137
  function collectDeclaredNames( statements ) {
1105
1138
  const names = [];
1106
1139
  for ( const stmt of statements || [] ) {
@@ -1684,7 +1717,11 @@ function emitCallExpression( node, options = {} ) {
1684
1717
  const argArray = emitCallArgumentArray( node.arguments );
1685
1718
  source = `__zuzu_super_dispatch( __zuzu_super_static__, self, __zuzu_super_class__, __zuzu_super_method__, ${argArray} )`;
1686
1719
  }
1687
- else if ( node.callee.type === 'Identifier' && node.callee.name === 'eval' && node.arguments.length > 0 ) {
1720
+ else if (
1721
+ node.callee.type === 'Identifier'
1722
+ && ( options.evalNames || new Set( [ 'eval' ] ) ).has( node.callee.name )
1723
+ && node.arguments.length > 0
1724
+ ) {
1688
1725
  source = emitEvalCall( node.arguments );
1689
1726
  }
1690
1727
  else if (
@@ -1968,7 +2005,7 @@ function emitBinaryExpression( node ) {
1968
2005
  return `__zuzu_ne( ${left}, ${right} )`;
1969
2006
  case '!=':
1970
2007
  case '≠':
1971
- return `__zuzu_num_ne( ${left}, ${right} )`;
2008
+ return `__zuzu_ne( ${left}, ${right} )`;
1972
2009
  case '~':
1973
2010
  return `__zuzu_match( ${left}, ${right} )`;
1974
2011
  case '_':
package/modules/std/io.js CHANGED
@@ -389,6 +389,14 @@ class Path {
389
389
  slurp_utf8_async() {
390
390
  return new Task( async () => fs.promises.readFile( this.value, 'utf8' ) );
391
391
  }
392
+ append( value ) {
393
+ traceBlockingOperation( 'std/io Path.append' );
394
+ if ( !( value && value.bytes instanceof Uint8Array ) ) {
395
+ throw new Error( `TypeException: Path.append expects BinaryString, got ${typeName( value )}` );
396
+ }
397
+ fs.appendFileSync( this.value, Buffer.from( value.bytes ) );
398
+ return this;
399
+ }
392
400
  append_async( value ) {
393
401
  return new Task( async () => {
394
402
  if ( !( value && value.bytes instanceof Uint8Array ) ) {
@@ -398,6 +406,14 @@ class Path {
398
406
  return this;
399
407
  } );
400
408
  }
409
+ append_utf8( text ) {
410
+ traceBlockingOperation( 'std/io Path.append_utf8' );
411
+ if ( typeof text !== 'string' ) {
412
+ throw new Error( `TypeException: Path.append_utf8 expects String, got ${typeName( text )}` );
413
+ }
414
+ fs.appendFileSync( this.value, text, 'utf8' );
415
+ return this;
416
+ }
401
417
  append_utf8_async( text ) {
402
418
  return new Task( async () => {
403
419
  if ( typeof text !== 'string' ) {
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { spawn, spawnSync } = require( 'node:child_process' );
4
4
  const fs = require( 'node:fs' );
5
+ const os = require( 'node:os' );
5
6
  const path = require( 'node:path' );
6
7
  const { Task, traceBlockingOperation } = require( './task' );
7
8
 
@@ -134,12 +135,15 @@ function runCommand( cmd, options = {} ) {
134
135
  return cwdErrorResult( cmd, options, cwd.error );
135
136
  }
136
137
 
138
+ const stdinDir = fs.mkdtempSync( path.join( os.tmpdir(), 'zuzu-proc-stdin-' ) );
139
+ const stdinPath = path.join( stdinDir, 'stdin' );
140
+ fs.writeFileSync( stdinPath, stdin, 'utf8' );
141
+ const stdinFd = fs.openSync( stdinPath, 'r' );
137
142
  const spawnOptions = {
138
- input: stdin,
139
143
  encoding: 'utf8',
140
144
  maxBuffer: 10 * 1024 * 1024,
141
145
  stdio: [
142
- 'pipe',
146
+ stdinFd,
143
147
  captureStdout ? 'pipe' : 'ignore',
144
148
  mergeStderr ? 'pipe' : ( captureStderr ? 'pipe' : 'ignore' ),
145
149
  ],
@@ -166,7 +170,19 @@ function runCommand( cmd, options = {} ) {
166
170
  }
167
171
  }
168
172
 
169
- const spawned = spawnSync( cmd[0], cmd.slice( 1 ), spawnOptions );
173
+ let spawned;
174
+ try {
175
+ spawned = spawnSync( cmd[0], cmd.slice( 1 ), spawnOptions );
176
+ }
177
+ finally {
178
+ fs.closeSync( stdinFd );
179
+ try {
180
+ fs.unlinkSync( stdinPath );
181
+ fs.rmdirSync( stdinDir );
182
+ }
183
+ catch ( _err ) {
184
+ }
185
+ }
170
186
  const timedOut = spawned.error && spawned.error.code === 'ETIMEDOUT';
171
187
  const signal = timedOut
172
188
  ? 14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuzu-js",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "JavaScript runtime, compiler, and browser bundle for ZuzuScript.",
5
5
  "main": "lib/zuzu.js",
6
6
  "bin": {