zuzu-js 0.1.2 → 0.2.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.
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.2\n' );
257
+ process.stdout.write( 'zuzu-js version 0.2.0\n' );
258
258
  if ( verbose ) {
259
259
  process.stdout.write( '\nlib search paths:\n' );
260
260
  for ( const p of runtime.getModuleSearchRoots() ) {
@@ -251,6 +251,8 @@ function collectTopLevelDeclarations( source, stripPod ) {
251
251
  let inSingle = false;
252
252
  let inDouble = false;
253
253
  let inBacktick = false;
254
+ let inRegex = false;
255
+ let inRegexClass = false;
254
256
  let inLineComment = false;
255
257
  let inBlockComment = false;
256
258
  let escape = false;
@@ -280,6 +282,35 @@ function collectTopLevelDeclarations( source, stripPod ) {
280
282
  masked.push( ch === '\n' ? '\n' : ' ' );
281
283
  continue;
282
284
  }
285
+ if ( inRegex ) {
286
+ if ( escape ) {
287
+ escape = false;
288
+ masked.push( ' ' );
289
+ continue;
290
+ }
291
+ if ( ch === '\\' ) {
292
+ escape = true;
293
+ masked.push( ' ' );
294
+ continue;
295
+ }
296
+ if ( ch === '[' ) {
297
+ inRegexClass = true;
298
+ masked.push( ' ' );
299
+ continue;
300
+ }
301
+ if ( ch === ']' ) {
302
+ inRegexClass = false;
303
+ masked.push( ' ' );
304
+ continue;
305
+ }
306
+ if ( ch === '/' && !inRegexClass ) {
307
+ inRegex = false;
308
+ masked.push( ' ' );
309
+ continue;
310
+ }
311
+ masked.push( ch === '\n' ? '\n' : ' ' );
312
+ continue;
313
+ }
283
314
  if ( inSingle || inDouble || inBacktick ) {
284
315
  if ( escape ) {
285
316
  escape = false;
@@ -318,6 +349,12 @@ function collectTopLevelDeclarations( source, stripPod ) {
318
349
  masked.push( ' ' );
319
350
  continue;
320
351
  }
352
+ if ( ch === '/' && looksLikeRegexLiteralStart( stripped, i ) ) {
353
+ inRegex = true;
354
+ inRegexClass = false;
355
+ masked.push( ' ' );
356
+ continue;
357
+ }
321
358
  if ( ch === '\'' ) {
322
359
  inSingle = true;
323
360
  masked.push( ' ' );
@@ -391,6 +428,18 @@ function collectTopLevelDeclarations( source, stripPod ) {
391
428
  return [ ...names ];
392
429
  }
393
430
 
431
+ function looksLikeRegexLiteralStart( source, index ) {
432
+ let pos = index - 1;
433
+ while ( pos >= 0 && /\s/u.test( source[pos] ) ) {
434
+ pos--;
435
+ }
436
+ if ( pos < 0 ) {
437
+ return true;
438
+ }
439
+ const previous = source[pos];
440
+ return /[({[=,:;!~?&|+\-*%^<>]/u.test( previous );
441
+ }
442
+
394
443
  function collectTopLevelUnpackDeclarationNames( source, topLevelMask ) {
395
444
  const names = [];
396
445
  const rx = /(?:^|[;\n])\s*(?:export\s+)?(?:let|const)\b/gm;
@@ -729,7 +729,7 @@ function emitFunctionPreamble( params, signature = null ) {
729
729
  for ( const param of params ) {
730
730
  if ( param.type === 'SpecialParameter' ) {
731
731
  if ( param.special === 'lead_rest' ) {
732
- lines.push( `let ${param.leadName} = arguments[${argIndex}];` );
732
+ lines.push( `const ${param.leadName} = arguments[${argIndex}];` );
733
733
  argIndex++;
734
734
  lines.push( `const ${param.name} = Array.prototype.slice.call( arguments, ${argIndex} );` );
735
735
  continue;
@@ -757,13 +757,13 @@ function emitFunctionPreamble( params, signature = null ) {
757
757
  continue;
758
758
  }
759
759
  if ( param.defaultValue ) {
760
- lines.push( `let ${paramName} = __argc__ > ${argIndex} ? arguments[${argIndex}] : ${emitExpression( param.defaultValue )};` );
760
+ lines.push( `const ${paramName} = __argc__ > ${argIndex} ? arguments[${argIndex}] : ${emitExpression( param.defaultValue )};` );
761
761
  }
762
762
  else if ( param.optional ) {
763
- lines.push( `let ${paramName} = __argc__ > ${argIndex} ? arguments[${argIndex}] : null;` );
763
+ lines.push( `const ${paramName} = __argc__ > ${argIndex} ? arguments[${argIndex}] : null;` );
764
764
  }
765
765
  else {
766
- lines.push( `let ${paramName} = arguments[${argIndex}];` );
766
+ lines.push( `const ${paramName} = arguments[${argIndex}];` );
767
767
  }
768
768
  if ( param.typeName ) {
769
769
  lines.push(
@@ -780,62 +780,71 @@ function emitSpecialFunctionPreamble( signature ) {
780
780
  case 'pairlist_only':
781
781
  return [
782
782
  `const __zuzu_call_args = Array.prototype.slice.call( arguments );`,
783
- `let ${signature.namedName} = __zuzu_pairlist_literal( [] );`,
783
+ 'let __zuzu_named_args = __zuzu_pairlist_literal( [] );',
784
784
  'for ( const __a of __zuzu_call_args ) {',
785
- `if ( __zuzu_is_pairlist( __a ) ) { ${signature.namedName} = __a; } else { throw new Exception( "named PairList parameter only accepts named arguments" ); }`,
785
+ 'if ( __zuzu_is_pairlist( __a ) ) { __zuzu_named_args = __a; } else { throw new Exception( "named PairList parameter only accepts named arguments" ); }',
786
786
  '}',
787
+ `const ${signature.namedName} = __zuzu_named_args;`,
787
788
  ].join( '\n' );
788
789
  case 'pairlist_rest_array':
789
790
  case 'rest_array_pairlist':
790
791
  return [
791
792
  `const __zuzu_call_args = Array.prototype.slice.call( arguments );`,
792
- `let ${signature.namedName} = __zuzu_pairlist_literal( [] );`,
793
- `let ${signature.restName} = [];`,
793
+ 'let __zuzu_named_args = __zuzu_pairlist_literal( [] );',
794
+ 'const __zuzu_rest_args = [];',
794
795
  'for ( const __a of __zuzu_call_args ) {',
795
- `if ( __zuzu_is_pairlist( __a ) ) { ${signature.namedName} = __a; } else { ${signature.restName}.push( __a ); }`,
796
+ 'if ( __zuzu_is_pairlist( __a ) ) { __zuzu_named_args = __a; } else { __zuzu_rest_args.push( __a ); }',
796
797
  '}',
798
+ `const ${signature.namedName} = __zuzu_named_args;`,
799
+ `const ${signature.restName} = __zuzu_rest_args;`,
797
800
  ].join( '\n' );
798
801
  case 'lead_pairlist':
799
802
  return [
800
803
  'const __zuzu_call_args = Array.prototype.slice.call( arguments );',
801
- `let ${signature.headName} = __zuzu_call_args[0];`,
802
- `let ${signature.namedName} = __zuzu_pairlist_literal( [] );`,
803
- `let ${signature.restName} = [];`,
804
+ `const ${signature.headName} = __zuzu_call_args[0];`,
805
+ 'let __zuzu_named_args = __zuzu_pairlist_literal( [] );',
806
+ 'const __zuzu_rest_args = [];',
804
807
  'for ( let __i = 1; __i < __zuzu_call_args.length; __i++ ) {',
805
808
  'const __a = __zuzu_call_args[__i];',
806
- `if ( __zuzu_is_pairlist( __a ) ) { ${signature.namedName} = __a; } else { ${signature.restName}.push( __a ); }`,
809
+ 'if ( __zuzu_is_pairlist( __a ) ) { __zuzu_named_args = __a; } else { __zuzu_rest_args.push( __a ); }',
807
810
  '}',
811
+ `const ${signature.namedName} = __zuzu_named_args;`,
812
+ `const ${signature.restName} = __zuzu_rest_args;`,
808
813
  ].join( '\n' );
809
814
  case 'trail_pairlist':
810
815
  return [
811
816
  'const __zuzu_call_args = Array.prototype.slice.call( arguments );',
812
- `let ${signature.headName} = __zuzu_call_args[0];`,
813
- `let ${signature.restName} = [];`,
814
- `let ${signature.namedName} = __zuzu_pairlist_literal( [] );`,
817
+ `const ${signature.headName} = __zuzu_call_args[0];`,
818
+ 'const __zuzu_rest_args = [];',
819
+ 'let __zuzu_named_args = __zuzu_pairlist_literal( [] );',
815
820
  'for ( let __i = 1; __i < __zuzu_call_args.length; __i++ ) {',
816
821
  'const __a = __zuzu_call_args[__i];',
817
- `if ( __zuzu_is_pairlist( __a ) ) { ${signature.namedName} = __a; } else { ${signature.restName}.push( __a ); }`,
822
+ 'if ( __zuzu_is_pairlist( __a ) ) { __zuzu_named_args = __a; } else { __zuzu_rest_args.push( __a ); }',
818
823
  '}',
824
+ `const ${signature.restName} = __zuzu_rest_args;`,
825
+ `const ${signature.namedName} = __zuzu_named_args;`,
819
826
  ].join( '\n' );
820
827
  case 'scalar_pairlist':
821
828
  return [
822
829
  'const __zuzu_call_args = Array.prototype.slice.call( arguments );',
823
- `let ${signature.headName} = __zuzu_call_args[0];`,
824
- `let ${signature.namedName} = __zuzu_pairlist_literal( [] );`,
830
+ `const ${signature.headName} = __zuzu_call_args[0];`,
831
+ 'let __zuzu_named_args = __zuzu_pairlist_literal( [] );',
825
832
  'for ( let __i = 1; __i < __zuzu_call_args.length; __i++ ) {',
826
833
  'const __a = __zuzu_call_args[__i];',
827
- `if ( __zuzu_is_pairlist( __a ) ) { ${signature.namedName} = __a; } else { throw new Exception( "named arguments not allowed for this function" ); }`,
834
+ 'if ( __zuzu_is_pairlist( __a ) ) { __zuzu_named_args = __a; } else { throw new Exception( "named arguments not allowed for this function" ); }',
828
835
  '}',
836
+ `const ${signature.namedName} = __zuzu_named_args;`,
829
837
  ].join( '\n' );
830
838
  case 'variadic':
831
839
  return [
832
840
  'const __zuzu_call_args = Array.prototype.slice.call( arguments );',
833
- `let ${signature.headName} = __zuzu_call_args[0];`,
834
- `let ${signature.restName} = [];`,
841
+ `const ${signature.headName} = __zuzu_call_args[0];`,
842
+ 'const __zuzu_rest_args = [];',
835
843
  'for ( let __i = 1; __i < __zuzu_call_args.length; __i++ ) {',
836
844
  'const __a = __zuzu_call_args[__i];',
837
- `if ( __zuzu_is_pairlist( __a ) ) { throw new Exception( "named arguments not allowed for this function" ); } ${signature.restName}.push( __a );`,
845
+ 'if ( __zuzu_is_pairlist( __a ) ) { throw new Exception( "named arguments not allowed for this function" ); } __zuzu_rest_args.push( __a );',
838
846
  '}',
847
+ `const ${signature.restName} = __zuzu_rest_args;`,
839
848
  ].join( '\n' );
840
849
  default:
841
850
  return '';
@@ -55,26 +55,22 @@ function parse( tokens, options = {} ) {
55
55
  return tokens[index - 1];
56
56
  }
57
57
 
58
- function canTerminateStatement() {
58
+ function canTerminateSimpleStatement() {
59
59
  const token = current();
60
- const prev = previous();
61
- if ( !prev ) {
62
- return false;
63
- }
64
60
  if ( token.type === 'punctuation' && token.value === '}' ) {
65
61
  return true;
66
62
  }
67
63
  if ( token.type === 'eof' ) {
68
64
  return true;
69
65
  }
70
- return token.line > prev.endLine;
66
+ return false;
71
67
  }
72
68
 
73
69
  function consumeStatementTerminator(message) {
74
70
  if ( match( 'punctuation', ';' ) ) {
75
71
  return;
76
72
  }
77
- if ( canTerminateStatement() ) {
73
+ if ( canTerminateSimpleStatement() ) {
78
74
  return;
79
75
  }
80
76
  throw new TranspilerSyntaxError( message || 'Expected statement terminator', current() );
@@ -1313,7 +1309,7 @@ function parse( tokens, options = {} ) {
1313
1309
  prefix: true,
1314
1310
  }, keyword, endLocFromNode( test ) );
1315
1311
  }
1316
- expect( 'punctuation', ';', semicolonMessage );
1312
+ consumeStatementTerminator( semicolonMessage );
1317
1313
  const consequent = withLoc( {
1318
1314
  type: 'BlockStatement',
1319
1315
  body: [ stmt ],
@@ -1330,7 +1326,7 @@ function parse( tokens, options = {} ) {
1330
1326
  const keyword = current();
1331
1327
  index++;
1332
1328
  const iterable = parseExpression();
1333
- expect( 'punctuation', ';', semicolonMessage );
1329
+ consumeStatementTerminator( semicolonMessage );
1334
1330
  const body = withLoc( {
1335
1331
  type: 'BlockStatement',
1336
1332
  body: [ stmt ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuzu-js",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "JavaScript runtime, compiler, and browser bundle for ZuzuScript.",
5
5
  "main": "lib/zuzu.js",
6
6
  "bin": {
@@ -158,6 +158,7 @@ function parse_lines ( Array lines ) {
158
158
  let top_level := _new_counts();
159
159
  let assertions := _new_counts();
160
160
  let planned := null;
161
+ let plan_directive := "";
161
162
  let tests := [];
162
163
 
163
164
  for ( let line in lines ) {
@@ -170,8 +171,11 @@ function parse_lines ( Array lines ) {
170
171
 
171
172
  if ( body ~ /^\d+\.\.\d+\b/ ) {
172
173
  if ( is_top_level ) {
173
- let parts := split( body, "..", 2 );
174
- planned := parts.get( 1, "" ) + 0;
174
+ let plan_parts := split( body, "#", 2 );
175
+ let range_parts := split( trim( plan_parts[0] ), "..", 2 );
176
+ planned := trim( range_parts.get( 1, "" ) ) + 0;
177
+ plan_directive := trim( plan_parts.get( 1, "" ) )
178
+ if plan_parts.length() > 1;
175
179
  }
176
180
  next;
177
181
  }
@@ -186,10 +190,17 @@ function parse_lines ( Array lines ) {
186
190
  }
187
191
  }
188
192
 
193
+ let skip_all_plan := false;
194
+ if ( planned ≡ 0 and plan_directive ~ /^skip\b/i ) {
195
+ skip_all_plan := true;
196
+ }
197
+
189
198
  return {
190
199
  top_level: top_level,
191
200
  assertions: assertions,
192
201
  planned: planned,
202
+ plan_directive: plan_directive,
203
+ skip_all: skip_all_plan,
193
204
  tests: tests,
194
205
  };
195
206
  }