@@ -4,11 +4,11 @@ import {
44 AstBlock ,
55 AstNode ,
66 BinOpNode ,
7- BracketObjectAccessNode ,
7+ ChainingCallsNode ,
8+ ChainingObjectAccessNode ,
89 ConstNode ,
910 CreateArrayNode ,
1011 CreateObjectNode ,
11- DotObjectAccessNode ,
1212 ForNode ,
1313 FuncDefNode ,
1414 FunctionCallNode ,
@@ -369,104 +369,48 @@ export class Evaluator {
369369
370370 if ( assignNode . target . type === 'getSingleVar' ) {
371371 const node = assignNode . target as SetSingleVarNode ;
372- blockContext . blockScope . set ( node . name , this . evalNode ( assignNode . source , blockContext ) ) ;
373- } else if ( assignNode . target . type === 'dotObjectAccess' ) {
374- const targetNode = assignNode . target as DotObjectAccessNode ;
372+ blockContext . blockScope . set (
373+ node . name ,
374+ this . evalNode ( assignNode . source , blockContext )
375+ ) ;
376+ } else if ( assignNode . target . type === 'chainingCalls' ) {
377+ const targetNode = assignNode . target as ChainingCallsNode ;
375378
376379 // create a node for all but last property token
377380 // potentially it can go to parser
378- const targetObjectNode = new DotObjectAccessNode (
379- targetNode . nestedProps . slice ( 0 , targetNode . nestedProps . length - 1 ) ,
381+ const targetObjectNode = new ChainingCallsNode (
382+ targetNode . innerNodes . slice ( 0 , targetNode . innerNodes . length - 1 ) ,
380383 targetNode . loc
381384 ) ;
382- const targetObject = this . evalNode ( targetObjectNode , blockContext ) as Record <
385+ const targetObject = ( this . evalNode ( targetObjectNode , blockContext ) ) as Record <
383386 string ,
384387 unknown
385388 > ;
386389
387- // not sure nested properties should be GetSingleVarNode
388- // can be factored in the parser
389- const lastPropertyName = (
390- targetNode . nestedProps [ targetNode . nestedProps . length - 1 ] as GetSingleVarNode
391- ) . name ;
390+ const lastInnerNode = targetNode . innerNodes [ targetNode . innerNodes . length - 1 ] ;
391+
392+ let lastPropertyName = '' ;
393+ if ( lastInnerNode . type === 'getSingleVar' ) {
394+ lastPropertyName = ( lastInnerNode as GetSingleVarNode ) . name ;
395+ } else if ( lastInnerNode . type === 'chainingObjectAccess' ) {
396+ lastPropertyName = ( this . evalNode (
397+ ( lastInnerNode as ChainingObjectAccessNode ) . indexerBody ,
398+ blockContext
399+ ) ) as string ;
400+ } else {
401+ throw Error ( 'Not implemented Assign operation with chaining calls' ) ;
402+ }
392403
393404 targetObject [ lastPropertyName ] = this . evalNode ( assignNode . source , blockContext ) ;
394- } else if ( assignNode . target . type === 'bracketObjectAccess' ) {
395- const targetNode = assignNode . target as BracketObjectAccessNode ;
396- const keyValue = this . evalNode ( targetNode . bracketBody , blockContext ) as string | number ;
397- const targetObject = blockContext . blockScope . get (
398- targetNode . propertyName as string
399- ) as Record < string , unknown > ;
400-
401- targetObject [ keyValue ] = this . evalNode ( assignNode . source , blockContext ) ;
402- } else {
403- throw Error ( 'Not implemented Assign operation' ) ;
404- // get chaining calls
405405 }
406406
407407 return null ;
408408 }
409409
410- if ( node . type === 'bracketObjectAccess' ) {
411- const sbNode = node as BracketObjectAccessNode ;
412- const key = this . evalNode ( sbNode . bracketBody , blockContext ) as string ;
413- const obj = blockContext . blockScope . get ( sbNode . propertyName as string ) as Record <
414- string ,
415- unknown
416- > ;
417- return obj [ key ] === undefined ? null : obj [ key ] ;
410+ if ( node . type === 'chainingCalls' ) {
411+ return this . resolveChainingCallsNode ( node as ChainingCallsNode , blockContext ) ;
418412 }
419413
420- if ( node . type === 'dotObjectAccess' ) {
421- const dotObject = node as DotObjectAccessNode ;
422-
423- // eslint-disable-next-line @typescript-eslint/no-explicit-any
424- let startObject = this . evalNode ( dotObject . nestedProps [ 0 ] , blockContext ) as any ;
425- for ( let i = 1 ; i < dotObject . nestedProps . length ; i ++ ) {
426- const nestedProp = dotObject . nestedProps [ i ] ;
427-
428- // eslint-disable-next-line @typescript-eslint/no-explicit-any
429- if ( ( dotObject . nestedProps [ i - 1 ] as any ) . nullCoelsing && ! startObject ) {
430- startObject = { } ;
431- }
432-
433- if ( nestedProp . type === 'getSingleVar' ) {
434- startObject = startObject [ ( nestedProp as SetSingleVarNode ) . name ] as unknown ;
435- } else if ( nestedProp . type === 'bracketObjectAccess' ) {
436- const node = nestedProp as BracketObjectAccessNode ;
437- startObject = startObject [ node . propertyName ] as unknown ;
438- startObject = startObject [
439- this . evalNode ( node . bracketBody , blockContext ) as string
440- ] as unknown ;
441- } else if ( nestedProp . type === 'funcCall' ) {
442- const funcCallNode = nestedProp as FunctionCallNode ;
443- const func = startObject [ funcCallNode . name ] as ( ...args : unknown [ ] ) => unknown ;
444-
445- if (
446- ( func === undefined || func === null ) &&
447- ( dotObject . nestedProps [ i - 1 ] as unknown as IsNullCoelsing ) . nullCoelsing
448- ) {
449- startObject = null ;
450- continue ;
451- }
452-
453- if ( typeof func !== 'function' ) {
454- throw Error ( `'${ funcCallNode . name } ' is not a function or not defined.` ) ;
455- }
456- const pms = funcCallNode . paramNodes ?. map ( n => this . evalNode ( n , blockContext ) ) || [ ] ;
457- startObject = this . invokeFunction ( func . bind ( startObject ) , pms , {
458- moduleName : blockContext . moduleName ,
459- line : funcCallNode . loc [ 0 ] ,
460- column : funcCallNode . loc [ 1 ]
461- } ) ;
462- } else {
463- throw Error ( "Can't resolve dotObjectAccess node" ) ;
464- }
465- }
466-
467- // no undefined values, make it rather null
468- return startObject === undefined ? null : startObject ;
469- }
470414
471415 if ( node . type === 'createObject' ) {
472416 const createObjectNode = node as CreateObjectNode ;
@@ -490,4 +434,60 @@ export class Evaluator {
490434 return res ;
491435 }
492436 }
437+
438+ private resolveChainingCallsNode (
439+ chNode : ChainingCallsNode ,
440+ blockContext : BlockContext
441+ ) : unknown {
442+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
443+ let startObject = ( this . evalNode ( chNode . innerNodes [ 0 ] , blockContext ) ) as any ;
444+
445+ for ( let i = 1 ; i < chNode . innerNodes . length ; i ++ ) {
446+ const nestedProp = chNode . innerNodes [ i ] ;
447+
448+ if ( ( chNode . innerNodes [ i - 1 ] as unknown as IsNullCoelsing ) . nullCoelsing && ! startObject ) {
449+ startObject = { } ;
450+ }
451+
452+ if ( nestedProp . type === 'getSingleVar' ) {
453+ startObject = startObject [ ( nestedProp as SetSingleVarNode ) . name ] as unknown ;
454+ } else if ( nestedProp . type === 'chainingObjectAccess' ) {
455+ const node = nestedProp as ChainingObjectAccessNode ;
456+ // startObject = startObject[node.] as unknown;
457+ startObject = startObject [
458+ ( this . evalNode ( node . indexerBody , blockContext ) ) as string
459+ ] as unknown ;
460+ } else if ( nestedProp . type === 'funcCall' ) {
461+ const funcCallNode = nestedProp as FunctionCallNode ;
462+ const func = startObject [ funcCallNode . name ] as ( ...args : unknown [ ] ) => unknown ;
463+
464+ if (
465+ ( func === undefined || func === null ) &&
466+ ( chNode . innerNodes [ i - 1 ] as unknown as IsNullCoelsing ) . nullCoelsing
467+ ) {
468+ startObject = null ;
469+ continue ;
470+ }
471+
472+ if ( typeof func !== 'function' ) {
473+ throw Error ( `'${ funcCallNode . name } ' is not a function or not defined.` ) ;
474+ }
475+ const pms = [ ] ;
476+ for ( const p of funcCallNode . paramNodes || [ ] ) {
477+ pms . push ( this . evalNode ( p , blockContext ) ) ;
478+ }
479+
480+ startObject = this . invokeFunction ( func . bind ( startObject ) , pms , {
481+ moduleName : blockContext . moduleName ,
482+ line : funcCallNode . loc [ 0 ] ,
483+ column : funcCallNode . loc [ 0 ]
484+ } ) ;
485+ } else {
486+ throw Error ( "Can't resolve chainingCalls node" ) ;
487+ }
488+ }
489+
490+ return startObject === undefined ? null : startObject ;
491+ }
492+
493493}
0 commit comments