@@ -17,7 +17,7 @@ export interface ValidationState {
1717}
1818
1919export interface ValidationFailure {
20- ptElement : PT_Element ;
20+ ptElement : PT_Element | undefined ;
2121 loopCount : number ;
2222 violatedConstraints : ValidationConstraint [ ] ;
2323}
@@ -340,7 +340,7 @@ export class ValidationGraph {
340340 return valRes . acceptedState !== undefined ;
341341 }
342342
343- public validateParsingTreeAndExtractContext ( astNode : Abstract_PT_Node ) : { acceptedState : ValidationState | undefined ; allStates : ValidationState [ ] } {
343+ public validateParsingTreeAndExtractContext ( ptNode : Abstract_PT_Node ) : { acceptedState : ValidationState | undefined ; allStates : ValidationState [ ] } {
344344 this . state = [
345345 {
346346 active : true ,
@@ -353,120 +353,11 @@ export class ValidationGraph {
353353 ] ;
354354
355355 // TODO: make this +1 better
356- for ( let astIndex = 0 ; astIndex < astNode . children . length + 1 ; astIndex ++ ) {
357- const astChild = astNode . children [ astIndex ] ;
356+ for ( let ptIndex = 0 ; ptIndex < ptNode . children . length + 1 ; ptIndex ++ ) {
357+ const ptChild = ptNode . children [ ptIndex ] ;
358358
359- while ( this . hasUnfinishedStates ( this . state , astIndex ) ) {
360- const newStates : ValidationState [ ] = [ ] ;
361-
362- for ( const validationState of this . state ) {
363- if ( ! validationState . active || validationState . currentInputIndex === astIndex ) {
364- newStates . push ( validationState ) ;
365- continue ;
366- }
367-
368- const currentState = validationState . nodeStates [ validationState . nodeStates . length - 1 ] ;
369- const node = this . getNode ( currentState ) ;
370- if ( ! node ) {
371- throw new Error ( 'this parser sucks' ) ;
372- }
373-
374- const loopCount = validationState . nodeStates . filter ( x => x === node . index ) . length ;
375-
376- const violatedConstraints : ValidationConstraint [ ] = [ ] ;
377- let allTransitionsFailed = true ;
378-
379- for ( const transition of node . transitions ) {
380- const canTransition = transition . canTransition ( astChild , loopCount ) ;
381- // console.log(transition, canTransition, astChild);
382-
383- if ( canTransition ) {
384- const newContext : ValidationContext = cloneValidationContext ( validationState . context ) ;
385- const newContextStack : ( string | number ) [ ] = [ ...validationState . currentContextStack ] ;
386- let currentContext : ValidationContext = traverseObjectByPath ( newContextStack as string [ ] , newContext ) ;
387- // console.log(currentContext);
388-
389- // do the current key first
390- if ( transition . key !== undefined ) {
391- currentContext [ transition . key ] = { element : astChild , inputIndex : astIndex } ;
392- }
393-
394- // do context actions
395- for ( const contextAction of transition . contextActions ) {
396- if ( contextAction . type === ContextActionType . POP ) {
397- newContextStack . pop ( ) ;
398- newContextStack . pop ( ) ;
399- currentContext = traverseObjectByPath ( newContextStack as string [ ] , newContext ) ;
400- } else {
401- if ( currentContext [ contextAction . key ] === undefined ) {
402- currentContext [ contextAction . key ] = [ ] as ValidationContext [ ] ;
403- }
404-
405- const subContextArray : ValidationContext [ ] = currentContext [ contextAction . key ] as ValidationContext [ ] ;
406- const newSubContext : ValidationContext = { } ;
407-
408- subContextArray . push ( newSubContext ) ;
409- newContextStack . push ( contextAction . key ) ;
410- newContextStack . push ( subContextArray . length - 1 ) ;
411- currentContext = newSubContext ;
412- }
413- }
414-
415- newStates . push ( {
416- active : true ,
417- currentInputIndex : transition . constraint !== undefined ? astIndex : validationState . currentInputIndex ,
418- context : newContext ,
419- currentContextStack : newContextStack ,
420- failure : undefined ,
421- nodeStates : validationState . nodeStates . concat ( [ transition . to ] ) ,
422- } ) ;
423-
424- allTransitionsFailed = false ;
425- } else {
426- violatedConstraints . push ( {
427- transitionConstraint : transition . constraint ,
428- loopBound : transition . loopBound ,
429- } ) ;
430- }
431- }
432-
433- // console.log(currentState, node.transitions, violatedConstraints, newStates);
434-
435- if ( astChild === undefined && node . transitions . length === 0 ) {
436- newStates . push ( {
437- active : true ,
438- currentInputIndex : astIndex ,
439- context : validationState . context ,
440- currentContextStack : validationState . currentContextStack ,
441- failure : undefined ,
442- nodeStates : validationState . nodeStates ,
443- } ) ;
444-
445- allTransitionsFailed = false ;
446- }
447-
448- if ( allTransitionsFailed ) {
449- // console.log('all transitions failed', node.transitions, node, astIndex, validationState);
450-
451- // TODO: maybe modify the object instead of creating a new one.
452- newStates . push ( {
453- active : false ,
454- context : validationState . context ,
455- currentInputIndex : astIndex ,
456- currentContextStack : validationState . currentContextStack ,
457- failure : {
458- ptElement : astChild ,
459- loopCount : loopCount ,
460- violatedConstraints : violatedConstraints ,
461- } ,
462- nodeStates : validationState . nodeStates ,
463- } ) ;
464- }
465- }
466-
467- // console.log(newStates);
468-
469- this . state = newStates ;
359+ while ( this . hasUnfinishedStates ( this . state , ptIndex ) ) {
360+ this . validateParsingTreeChild ( ptChild , ptIndex ) ;
470361 }
471362 }
472363
@@ -499,6 +390,136 @@ export class ValidationGraph {
499390 }
500391 }
501392
393+ private validateParsingTreeChild ( ptChild : PT_Element | undefined , ptIndex : number ) : void {
394+ const newStates : ValidationState [ ] = [ ] ;
395+
396+ for ( const validationState of this . state ) {
397+ if ( ! validationState . active || validationState . currentInputIndex === ptIndex ) {
398+ newStates . push ( validationState ) ;
399+ continue ;
400+ }
401+
402+ const currentState = validationState . nodeStates [ validationState . nodeStates . length - 1 ] ;
403+ const node = this . getNode ( currentState ) ;
404+ if ( ! node ) {
405+ throw new Error ( 'this parser sucks' ) ;
406+ }
407+
408+ // count the occurrences of the node in the validation state
409+ let loopCount = 0 ;
410+ for ( const nodeState of validationState . nodeStates ) {
411+ if ( nodeState === node . index ) {
412+ loopCount += 1 ;
413+ }
414+ }
415+
416+ const violatedConstraints : ValidationConstraint [ ] = [ ] ;
417+ let allTransitionsFailed = true ;
418+
419+ for ( const transition of node . transitions ) {
420+ if ( transition . canTransition ( ptChild , loopCount ) ) {
421+ let contextEntry = undefined ;
422+ if ( ptChild !== undefined ) {
423+ contextEntry = {
424+ element : ptChild ,
425+ inputIndex : ptIndex ,
426+ } ;
427+ }
428+
429+ const newContext = this . updateContext ( validationState , transition , contextEntry ) ;
430+
431+ newStates . push ( {
432+ active : true ,
433+ currentInputIndex : transition . constraint !== undefined ? ptIndex : validationState . currentInputIndex ,
434+ context : newContext . context ,
435+ currentContextStack : newContext . contextStack ,
436+ failure : undefined ,
437+ nodeStates : validationState . nodeStates . concat ( [ transition . to ] ) ,
438+ } ) ;
439+
440+ allTransitionsFailed = false ;
441+ } else {
442+ violatedConstraints . push ( {
443+ transitionConstraint : transition . constraint ,
444+ loopBound : transition . loopBound ,
445+ } ) ;
446+ }
447+ }
448+
449+ if ( ptChild === undefined && node . transitions . length === 0 ) {
450+ newStates . push ( {
451+ active : true ,
452+ currentInputIndex : ptIndex ,
453+ context : validationState . context ,
454+ currentContextStack : validationState . currentContextStack ,
455+ failure : undefined ,
456+ nodeStates : validationState . nodeStates ,
457+ } ) ;
458+
459+ allTransitionsFailed = false ;
460+ }
461+
462+ if ( allTransitionsFailed ) {
463+ newStates . push ( {
464+ active : false ,
465+ context : validationState . context ,
466+ currentInputIndex : ptIndex ,
467+ currentContextStack : validationState . currentContextStack ,
468+ failure : {
469+ ptElement : ptChild ,
470+ loopCount : loopCount ,
471+ violatedConstraints : violatedConstraints ,
472+ } ,
473+ nodeStates : validationState . nodeStates ,
474+ } ) ;
475+ }
476+ }
477+
478+ this . state = newStates ;
479+ }
480+
481+ private updateContext (
482+ validationState : ValidationState ,
483+ transition : VG_Transition ,
484+ contextEntry : ValidationContextEntry < PT_Element > | undefined
485+ ) : { context : ValidationContext ; contextStack : ( string | number ) [ ] } {
486+ const newContext : ValidationContext = cloneValidationContext ( validationState . context ) ;
487+ const newContextStack : ( string | number ) [ ] = [ ...validationState . currentContextStack ] ;
488+
489+ let currentContext : ValidationContext = traverseObjectByPath ( newContextStack as string [ ] , newContext ) ;
490+
491+ // do the current key first
492+ if ( transition . key !== undefined && contextEntry !== undefined ) {
493+ currentContext [ transition . key ] = contextEntry ;
494+ }
495+
496+ // do context actions
497+ for ( const contextAction of transition . contextActions ) {
498+ if ( contextAction . type === ContextActionType . POP ) {
499+ newContextStack . pop ( ) ;
500+ newContextStack . pop ( ) ;
501+ currentContext = traverseObjectByPath ( newContextStack as string [ ] , newContext ) ;
502+ } else {
503+ if ( currentContext [ contextAction . key ] === undefined ) {
504+ currentContext [ contextAction . key ] = [ ] as ValidationContext [ ] ;
505+ }
506+
507+ const subContextArray : ValidationContext [ ] = currentContext [ contextAction . key ] as ValidationContext [ ] ;
508+ const newSubContext : ValidationContext = { } ;
509+
510+ subContextArray . push ( newSubContext ) ;
511+ newContextStack . push ( contextAction . key ) ;
512+ newContextStack . push ( subContextArray . length - 1 ) ;
513+ currentContext = newSubContext ;
514+ }
515+ }
516+
517+ return {
518+ context : newContext ,
519+ contextStack : newContextStack ,
520+ } ;
521+ }
522+
502523 private hasUnfinishedStates ( states : ValidationState [ ] , astIndex : number ) : boolean {
503524 for ( const state of states ) {
504525 if ( state . active && state . currentInputIndex !== astIndex ) {
0 commit comments