@@ -15,7 +15,7 @@ import { Translator } from './sb3-creator-python.js';
1515const JS_KEYWORDS = new Set ( [ 'function' , 'if' , 'else' , 'while' , 'for' , 'return' , 'let' ,
1616 'const' , 'var' , 'true' , 'false' , 'null' , 'undefined' , 'new' , 'typeof' , 'break' , 'continue' ] ) ;
1717
18- const JS_OPS = [ '===' , '!==' , '**' , '==' , '!=' , '<=' , '>=' , '&&' , '||' , '++' , '--' ,
18+ const JS_OPS = [ '===' , '!==' , '=>' , ' **', '==' , '!=' , '<=' , '>=' , '&&' , '||' , '++' , '--' ,
1919 '+=' , '-=' , '*=' , '/=' , '%=' , '(' , ')' , '{' , '}' , '[' , ']' , ';' , ',' , '.' ,
2020 '+' , '-' , '*' , '/' , '%' , '<' , '>' , '=' , '!' , '?' , ':' ] ;
2121
@@ -297,13 +297,36 @@ class JsParser {
297297 if ( t . type === 'false' ) { this . next ( ) ; return { type : 'Const' , value : false } ; }
298298 if ( t . type === 'null' || t . type === 'undefined' ) { this . next ( ) ; return { type : 'Const' , value : null } ; }
299299 if ( t . type === 'NAME' ) { this . next ( ) ; return { type : 'Name' , id : t . value } ; }
300- if ( this . at ( 'OP' , '(' ) ) { this . next ( ) ; const e = this . parseExpr ( ) ; this . eat ( 'OP' , ')' ) ; return e ; }
300+ if ( this . at ( 'OP' , '(' ) ) {
301+ // Distinguish a grouped expression from arrow-function params `(a, b) => …`.
302+ let j = this . p , depth = 0 ;
303+ for ( ; j < this . toks . length ; j ++ ) { const tk = this . toks [ j ] ; if ( tk . type === 'OP' && tk . value === '(' ) depth ++ ; else if ( tk . type === 'OP' && tk . value === ')' ) { depth -- ; if ( depth === 0 ) break ; } }
304+ const after = this . toks [ j + 1 ] ;
305+ if ( after && after . type === 'OP' && after . value === '=>' ) {
306+ this . p = j + 2 ; // consume `(...) =>`
307+ if ( this . at ( 'OP' , '{' ) ) this . skipBraces ( ) ; else this . parseExpr ( ) ; // arrow body (discarded)
308+ return { type : 'Const' , value : null } ;
309+ }
310+ this . next ( ) ; const e = this . parseExpr ( ) ; this . eat ( 'OP' , ')' ) ; return e ;
311+ }
301312 if ( this . at ( 'OP' , '[' ) ) {
302313 this . next ( ) ; const elts = [ ] ;
303314 while ( ! this . at ( 'OP' , ']' ) ) { elts . push ( this . parseExpr ( ) ) ; if ( this . at ( 'OP' , ',' ) ) this . next ( ) ; }
304315 this . eat ( 'OP' , ']' ) ;
305316 return { type : 'List' , elts } ;
306317 }
318+ // object literal (e.g. the generated `_arrays = {}` registry / driver shims) — not in
319+ // the subset; consume the balanced braces and return a placeholder so parsing survives.
320+ if ( this . at ( 'OP' , '{' ) ) { this . skipBraces ( ) ; return { type : 'Const' , value : null } ; }
321+ // inline function expression (e.g. `.reduce(function(s,x){...})`) — out of subset;
322+ // consume it raw so parsing survives (the enclosing op won't reverse-map anyway).
323+ if ( t . type === 'function' ) {
324+ this . next ( ) ;
325+ if ( this . at ( 'NAME' ) ) this . next ( ) ;
326+ if ( this . at ( 'OP' , '(' ) ) { let d = 0 ; do { if ( this . at ( 'OP' , '(' ) ) d ++ ; else if ( this . at ( 'OP' , ')' ) ) d -- ; this . next ( ) ; } while ( d > 0 && ! this . at ( 'EOF' ) ) ; }
327+ if ( this . at ( 'OP' , '{' ) ) this . skipBraces ( ) ;
328+ return { type : 'Const' , value : null } ;
329+ }
307330 this . err ( `unexpected ${ t . type } ${ t . value || '' } ` ) ;
308331 return null ;
309332 }
0 commit comments