import { Token } from '../token/token' ; import { TokenHelper } from '../token/token.helper' ; import { ParserError } from '../error' ; import { TokenError } from '../token/token.error' ; import { AbstractSyntaxTreeNode } from './ast.node' ; export abstract class AbstractSyntaxTreeBase extends AbstractSyntaxTreeNode { public findRoot ( ) { if ( this . isRoot ( ) ) return this . value !== undefined || ! this . leftNode ? this : this . leftNode ; return this . _parent . findRoot ( ) ; } public isRoot ( ) { return ! this . _parent ; } public isValid ( ) { return this . value && ( ! this . leftNode && ! this . rightNode ) || ( ! ! this . leftNode && ! ! this . rightNode ) ; } public hasOpenBracket ( ) { if ( TokenHelper . isBracketOpen ( this . value ) ) return true ; const leftNodeHasOpenBracket = this . leftNode ? this . leftNode . hasOpenBracket ( ) : false ; const rightNodeHasOpenBracket = this . rightNode ? this . rightNode . hasOpenBracket ( ) : false ; return leftNodeHasOpenBracket || rightNodeHasOpenBracket ; } private findOpenedBracket ( ) { if ( this . isRoot ( ) ) return undefined ; if ( TokenHelper . isBracketOpen ( this . _value ) ) return this ; return this . _parent . findOpenedBracket ( ) ; } public removeRootBracket ( ) { const rootNode = this . findRoot ( ) ; if ( TokenHelper . isBracketOpen ( rootNode . value ) ) rootNode . leftNode . removeParent ( ) ; return this === rootNode ? rootNode . leftNode : this ; } public removeClosestBracket ( ) { const node = this . findOpenedBracket ( ) ; if ( ! node ) throw new ParserError ( TokenError . missingOpenBracket ) ; const targetNode = node . leftNode ; targetNode . subType = Token . SubType . Group ; if ( ! node . parent ) { targetNode . removeParent ( ) ; return targetNode ; } if ( node . parent . leftNode === node ) node . parent . leftNode = targetNode ; else node . parent . rightNode = targetNode ; return node . parent ; } private climbUp ( token ) { return this . isClimbTop ( token ) ? this : this . _parent . climbUp ( token ) ; } private isClimbTop ( token ) { return this . isTokenHighest ( token ) || ! this . parent || TokenHelper . isBracketOpen ( this . value ) ; } private isTokenHighest ( token ) { return TokenHelper . getPrecedenceDiff ( token , this . value ) > 0 && this . subType !== Token . SubType . Group ; } private createChildNode ( value ? ) { const node = new ( < any > this . constructor ) ( value ) ; node . parent = this ; return node ; } private createParentNode ( value ? ) { const node = new ( < any > this . constructor ) ( value ) ; this . parent = node ; return node ; } private insertOperatorNode ( value ) { const rootNode = this . climbUp ( value ) ; if ( TokenHelper . isBracketOpen ( rootNode . value ) ) return rootNode . insertJointNodeToLeft ( value ) ; if ( this . needJointRight ( rootNode , value ) ) return rootNode . insertJointNodeToRight ( value ) ; const newNode = rootNode . createParentNode ( value ) ; newNode . leftNode = rootNode ; return newNode ; } private needJointRight ( rootNode , value ) { return rootNode . isTokenHighest ( value ) && rootNode . parent || this === rootNode ; } public insertNode ( value ) { if ( TokenHelper . isSymbol ( value ) ) if ( ! this . value ) { this . value = value ; return this ; } if ( TokenHelper . isOperator ( value ) ) return this . insertOperatorNode ( value ) ; const valueNode = this . createChildNode ( value ) ; if ( ! this . leftNode ) this . leftNode = valueNode ; else this . rightNode = valueNode ; return valueNode ; } private insertJointNodeToLeft ( value ) { const jointNode = this . createChildNode ( value ) ; jointNode . leftNode = this . leftNode ; jointNode . rightNode = this . rightNode ; this . leftNode = jointNode ; return jointNode ; } public insertJointNodeToRight ( value ) { const jointNode = this . createChildNode ( value ) ; jointNode . leftNode = this . rightNode ; this . rightNode = jointNode ; return jointNode ; } public removeLeftNode ( ) { this . _leftNode . removeParent ( ) ; this . _leftNode = undefined ; } public removeRightNode ( ) { this . _rightNode . removeParent ( ) ; this . _rightNode = undefined ; } public removeParent ( ) { this . _parent = undefined ; } }