import { ExpressionNode , isExpressionNode , isSelectorNode , isValueNode , Node } from "@rsql/ast" ; import { createErrorForEmptyInput , createErrorForUnclosedParenthesis , createErrorForUnexpectedToken } from "./Error" ; import lex from "./lexer/lex" ; import Token , { AnyToken , isCloseParenthesisToken , isComparisonOperatorToken , isEndToken , isAndOperatorToken , isOrOperatorToken , isOpenParenthesisToken , isQuotedToken , isUnquotedToken , } from "./lexer/Token" ; import ParserContext , { createParserContext , getParserContextHead , getParserContextState , getParserContextToken , } from "./ParserContext" ; import { accept , goto , GoToOperation , NodeOperation , noop , OperationType , pop , PopOperation , push , PushOperation , reduce , ReduceOperation , shift , ShiftOperation , TokenOperation , } from "./ParserOperation" ; import { comparisonExpressionProduction , groupExpressionProduction , logicalExpressionProduction , multiValueProduction , ParserProduction , selectorProduction , singleValueProduction , } from "./ParserProduction" ; const productions = [ selectorProduction , singleValueProduction , multiValueProduction , comparisonExpressionProduction , logicalExpressionProduction , groupExpressionProduction , ] ; const tokenMatchers = [ isOpenParenthesisToken , isCloseParenthesisToken , isUnquotedToken , isQuotedToken , isComparisonOperatorToken , isOrOperatorToken , isAndOperatorToken , isEndToken , ] ; const nodeMatchers = [ isSelectorNode , isValueNode , isExpressionNode , ] ; type ParserTable = [ TokenOperation [ ] , NodeOperation [ ] ] [ ] ; const table = [ [ [ push ( 0 ) , noop , shift ( 8 ) , noop , noop , noop , noop , noop ] , [ goto ( 3 ) , noop , goto ( 7 ) ] ] , [ [ push ( 0 ) , noop , shift ( 8 ) , noop , noop , noop , noop , noop ] , [ goto ( 3 ) , noop , goto ( 12 ) , ] ] , [ [ push ( 0 ) , noop , shift ( 8 ) , noop , noop , noop , noop , noop ] , [ goto ( 3 ) , noop , goto ( 13 ) , ] ] , [ [ noop , noop , noop , noop , shift ( 4 ) , noop , noop , noop ] , [ noop , noop , noop , ] ] , [ [ shift ( 5 ) , noop , shift ( 9 ) , shift ( 9 ) , noop , noop , noop , noop ] , [ noop , goto ( 11 ) , noop , ] ] , [ [ noop , noop , shift ( 6 ) , shift ( 6 ) , noop , noop , noop , noop ] , [ noop , noop , noop , ] ] , [ [ noop , shift ( 10 ) , noop , noop , noop , shift ( 5 ) , noop , noop ] , [ noop , noop , noop , ] ] , [ [ noop , shift ( 14 ) , noop , noop , noop , shift ( 1 ) , shift ( 2 ) , accept ( ) ] , [ noop , noop , noop , ] ] , [ [ noop , noop , noop , noop , reduce ( 0 ) , noop , noop , noop ] , [ noop , noop , noop , ] ] , [ [ noop , reduce ( 1 ) , noop , noop , noop , reduce ( 1 ) , reduce ( 1 ) , reduce ( 1 ) ] , [ noop , noop , noop , ] ] , [ [ noop , reduce ( 2 ) , noop , noop , noop , reduce ( 2 ) , reduce ( 2 ) , reduce ( 2 ) ] , [ noop , noop , noop , ] ] , [ [ noop , reduce ( 3 ) , noop , noop , noop , reduce ( 3 ) , reduce ( 3 ) , reduce ( 3 ) ] , [ noop , noop , noop , ] ] , [ [ noop , reduce ( 4 ) , noop , noop , noop , reduce ( 4 ) , shift ( 2 ) , reduce ( 4 ) ] , [ noop , noop , noop , ] ] , [ [ noop , reduce ( 4 ) , noop , noop , noop , reduce ( 4 ) , reduce ( 4 ) , reduce ( 4 ) ] , [ noop , noop , noop , ] ] , [ [ noop , pop ( 5 ) , noop , noop , noop , pop ( 5 ) , pop ( 5 ) , pop ( 5 ) ] , [ noop , noop , noop , ] ] , ] ; function getParserTokenOperation ( state , token ) { return table [ state ] [ 0 ] [ tokenMatchers . findIndex ( ( matcher ) => matcher ( token ) ) ] ; } function getParserNodeOperation ( state , node ) { return table [ state ] [ 1 ] [ nodeMatchers . findIndex ( ( matcher ) => matcher ( node ) ) ] ; } function getMostMeaningfulInvalidToken ( context ) { if ( context . position > 0 && isCloseParenthesisToken ( context . tokens [ context . position - 1 ] ) && context . parent === null ) { return context . tokens [ context . position - 1 ] ; } return context . tokens [ context . position ] ; } function handleShift ( context , shiftOperation ) { context . stack . push ( context . tokens [ context . position ] ) ; context . state . push ( shiftOperation . state ) ; context . position = context . position + 1 ; return context ; } function handlePush ( context , pushOperation ) { return { position : context . position + 1 , tokens : context . tokens , stack : [ context . tokens [ context . position ] ] , state : [ pushOperation . state ] , parent : context , } ; } function handleGoTo ( context , gotoOperation ) { context . state . push ( gotoOperation . state ) ; return context ; } function handleReduce ( context , reduceOperation , input ) { const { consumed , produced } = productions [ reduceOperation . production ] ( context . stack ) ; for ( let i = 0 ; i < consumed ; ++ i ) { context . stack . pop ( ) ; context . state . pop ( ) ; } context . stack . push ( produced ) ; const stateAfterReduce = getParserContextState ( context ) ; const nodeAfterReduce = getParserContextHead ( context ) as Node ; const gotoOperation = getParserNodeOperation ( stateAfterReduce , nodeAfterReduce ) ; if ( gotoOperation ) { context = handleGoTo ( context , gotoOperation ) ; } else { throw createErrorForUnexpectedToken ( getMostMeaningfulInvalidToken ( context ) , input ) ; } return context ; } function handlePop ( context , popOperation , input ) { if ( ! context . parent ) { throw createErrorForUnexpectedToken ( getMostMeaningfulInvalidToken ( context ) , input ) ; } const { produced } = productions [ popOperation . production ] ( context . stack ) ; context . parent . position = context . position ; context . parent . stack . push ( produced ) ; context = context . parent ; const stateAfterPop = getParserContextState ( context ) ; const nodeAfterPop = getParserContextHead ( context ) as Node ; const gotoOperation = getParserNodeOperation ( stateAfterPop , nodeAfterPop ) ; if ( gotoOperation ) { context = handleGoTo ( context , gotoOperation ) ; } else { throw createErrorForUnexpectedToken ( getMostMeaningfulInvalidToken ( context ) , input ) ; } return context ; } function handleAccept ( context , input ) { if ( context . parent !== null ) { throw createErrorForUnclosedParenthesis ( getMostMeaningfulInvalidToken ( context ) , input , context . parent . position ) ; } return getParserContextHead ( context ) as ExpressionNode ; } function parse ( source ) { if ( typeof source !== "string" ) { throw new TypeError ( `The argument passed to the "parse" function has to be a string, "${ source }" passed.` ) ; } const tokens = lex ( source ) ; if ( tokens . length === 1 && tokens [ 0 ] . type === "END" ) { throw createErrorForEmptyInput ( tokens [ 0 ] , source ) ; } let context = createParserContext ( tokens ) ; while ( context . position < context . tokens . length ) { const state = getParserContextState ( context ) ; const token = getParserContextToken ( context ) ; const operation = getParserTokenOperation ( state , token ) ; if ( ! operation ) { throw createErrorForUnexpectedToken ( getMostMeaningfulInvalidToken ( context ) , source ) ; } switch ( operation . type ) { case OperationType . SHIFT : context = handleShift ( context , operation ) ; break ; case OperationType . PUSH : context = handlePush ( context , operation ) ; break ; case OperationType . REDUCE : context = handleReduce ( context , operation , source ) ; break ; case OperationType . POP : context = handlePop ( context , operation , source ) ; break ; case OperationType . ACCEPT : return handleAccept ( context , source ) ; } } throw createErrorForUnexpectedToken ( getMostMeaningfulInvalidToken ( context ) , source ) ; } export { parse } ;