couchbase-lite-core icon indicating copy to clipboard operation
couchbase-lite-core copied to clipboard

Grammar railroad diagram

Open mingodad opened this issue 3 years ago • 2 comments

Using a modified peg/leg from here https://github.com/mingodad/peg to convert the LiteCore/Query/N1QL_Parser/n1ql.leg in an EBNF understood by https://www.bottlecaps.de/rr/ui to generate a nice railroad diagram (https://en.wikipedia.org/wiki/Syntax_diagram) to help show/understand the syntax.

Command to generate leg -e syntax.leg then some minor manual fixes are still needed.

Copy and paste the EBNF shown bellow at https://www.bottlecaps.de/rr/ui on the tab Edit Grammar then click on the tab View Diagram.

//To be viewd at https://www.bottlecaps.de/rr/ui

n1ql ::=
	 ( _ selectStatement _ _NOT_  . )
	| ( selectResults _NOT_  . )

_ ::=
	 [ \t\r\n]*

selectStatement ::=
	 SELECT _ ( ( DISTINCT ) | ALL )? selectResults _ ( from _ )? ( WHERE expression )? ( groupBy _ ( having )? )? ( orderBy _ )? ( ( LIMIT expression ( OFFSET expression )? ) | ( OFFSET expression ( LIMIT expression )? ) )? ( _ ';' )?

selectResults ::=
	 selectResult ( _ ',' _ selectResult )*

SELECT ::=
	 "SELECT" WB

DISTINCT ::=
	 "DISTINCT" WB

ALL ::=
	 "ALL" WB

from ::=
	 FROM dataSource ( _ join )*

WHERE ::=
	 "WHERE" WB

expression ::=
	 expr8

groupBy ::=
	 GROUP BY expression ( _ ',' _ expression )*

having ::=
	 HAVING expression

orderBy ::=
	 ORDER BY ordering ( _ ',' _ ordering )*

LIMIT ::=
	 "LIMIT" WB

OFFSET ::=
	 "OFFSET" WB

selectResult ::=
	 expression ( _ AS? columnAlias )?

AS ::=
	 "AS" WB

columnAlias ::=
	 IDENTIFIER

FROM ::=
	 "FROM" WB

dataSource ::=
	 collectionName ( AS? collectionAlias )?

join ::=
	 joinOperator _ dataSource _ ( ON expression )?

collectionName ::=
	 IDENTIFIER ( '.' IDENTIFIER )?

collectionAlias ::=
	 IDENTIFIER

IDENTIFIER ::=
	 ( [a-zA-Z_] [a-zA-Z0-9_$]* _ )
	| ( "`" ( [^`] | "``" )* "`" _ )

joinOperator ::=
	 ( ( LEFT OUTER? ) | INNER | CROSS )? JOIN

ON ::=
	 "ON" WB

LEFT ::=
	 "LEFT" WB

OUTER ::=
	 "OUTER" WB

INNER ::=
	 "INNER" WB

CROSS ::=
	 "CROSS" WB

JOIN ::=
	 "JOIN" WB

GROUP ::=
	 "GROUP" WB

BY ::=
	 "BY" WB

HAVING ::=
	 "HAVING" WB

ORDER ::=
	 "ORDER" WB

ordering ::=
	 expression ( _ order )?

order ::=
	 ( ASC | DESC )

ASC ::=
	 "ASC" WB

DESC ::=
	 "DESC" WB

indexName ::=
	 IDENTIFIER

expr8 ::=
	 expr7 ( _ OP_PREC_8 _ expr7 )*

caseExpression ::=
	 CASE ( _NOT_  WHEN expression )? ( WHEN expression THEN expression )+ ( ELSE expression )? END

CASE ::=
	 "CASE" WB

WHEN ::=
	 "WHEN" WB

THEN ::=
	 "THEN" WB

ELSE ::=
	 "ELSE" WB

END ::=
	 "END" WB

anyEveryExpression ::=
	 anyEvery _ variableName _ IN _ expression _ SATISFIES _ expression END

anyEvery ::=
	 ( anyOrSome AND EVERY )
	| ( anyOrSome )
	| ( EVERY )

variableName ::=
	 IDENTIFIER

IN ::=
	 "IN" WB

SATISFIES ::=
	 "SATISFIES" WB

anyOrSome ::=
	 ANY
	| SOME

AND ::=
	 "AND" WB

EVERY ::=
	 "EVERY" WB

ANY ::=
	 "ANY" WB

SOME ::=
	 "SOME" WB

expr7 ::=
	 expr6 ( _ OP_PREC_7 _ expr6 )*

OP_PREC_8 ::=
	 OR

expr6 ::=
	 ( expr5 NOT NULL )
	| ( expr5 IS ( ( NULL ) | ( MISSING ) | ( VALUED ) ) )
	| ( expr5 IS NOT ( ( NULL ) | ( MISSING ) | ( VALUED ) ) )
	| inExpression
	| likeExpression
	| betweenExpression
	| ( expr5 ( _ OP_PREC_6 _ expr5 )* )

OP_PREC_7 ::=
	 AND

expr5 ::=
	 expr4 ( _ OP_PREC_5 _ expr4 )*

NOT ::=
	 "NOT" WB

NULL ::=
	 "NULL" WB

IS ::=
	 "IS" WB

MISSING ::=
	 "MISSING" WB

VALUED ::=
	 "VALUED" WB

inExpression ::=
	 expr5 IN_OR_NOT ( ( selectExpr ) | ( parenExprs ) )

likeExpression ::=
	 expr5 _ NOT? LIKE expr5

betweenExpression ::=
	 expr5 NOT? BETWEEN expr5 AND expr5

OP_PREC_6 ::=
	 ( ( '==' | '=' ) )
	| ( ( '<>' | '!=' ) )
	| ( IS NOT )
	| ( IS )

expr4 ::=
	 expr3 ( _ OP_PREC_4 _ expr3 )*

OP_PREC_5 ::=
	 ( '<=' | '<' | '>=' | '>' )

expr3 ::=
	 expr2 ( _ OP_PREC_3 _ expr2 )*

OP_PREC_4 ::=
	 ( '<<' | '>>' | '&' | '|' )

expr2 ::=
	 expr1 ( _ OP_PREC_2 _ expr1 )*

OP_PREC_3 ::=
	 [-+]

expr1 ::=
	 expr0 ( _ OP_PREC_1 _ expr0 )*

OP_PREC_2 ::=
	 [*/%]

expr0 ::=
	 ( baseExpr '.' propertyPath )
	| ( baseExpr _ collateSuffix )
	| ( baseExpr )

OP_PREC_1 ::=
	 '||'

LIKE ::=
	 "LIKE" WB

BETWEEN ::=
	 "BETWEEN" WB

OR ::=
	 "OR" WB

IN_OR_NOT ::=
	 ( NOT IN )
	| ( IN )

selectExpr ::=
	 '(' selectStatement ')'

parenExprs ::=
	 _ '(' _ ( expression ( ',' _ expression )* )? ')'

baseExpr ::=
	 _baseExpr _

propertyPath ::=
	 propertyName ( ( '.' _ propertyName ) | ( '[' _ INT_LITERAL _ ']' _ ) )*

collateSuffix ::=
	 COLLATE ( ( collation _ _NOT_  collation ) | ( '(' _ ( collation _ )+ ')' _ ) )

COLLATE ::=
	 "COLLATE" WB

collation ::=
	 ( "NO"? ( "UNICODE" | "CASE" | "DIAC" ) WB )

WB ::=
	 _NOT_  [a-zA-Z0-9_] _

_baseExpr ::=
	 literal
	| arrayLiteral
	| dictLiteral
	| ( OP_PREFIX _ baseExpr )
	| ( EXISTS selectExpr )
	| caseExpression
	| anyEveryExpression
	| ( '$' IDENTIFIER )
	| function
	| property
	| ( '(' _ expression _ ')' )

literal ::=
	 FLOAT_LITERAL
	| INT_LITERAL
	| BOOLEAN_LITERAL
	| STRING_LITERAL
	| ( NULL )
	| ( MISSING )

arrayLiteral ::=
	 '[' _ ( expression ( _ ',' _ expression )* )? ']'

dictLiteral ::=
	 '{' _ ( STRING_LITERAL ':' _ expression ( _ ',' _ STRING_LITERAL ':' _ expression )* )? '}'

OP_PREFIX ::=
	 ( '-' | '+' | NOT )

EXISTS ::=
	 "EXISTS" WB

function ::=
	 ( "meta" _ '(' _ ( collectionName _ )? ')' _ )
	| ( "match" _ '(' _ indexName _ ',' _ expression _ ')' _ )
	| ( "rank" _ '(' _ indexName _ ')' _ )
	| ( functionName parenExprs )

property ::=
	 ( '*' )
	| ( collectionAlias '.' _ '*' )
	| ( propertyPath )

propertyName ::=
	 IDENTIFIER

INT_LITERAL ::=
	 '-'? DIGIT+ WB

functionName ::=
	 IDENTIFIER

FALSE ::=
	 "FALSE" WB

TRUE ::=
	 "TRUE" WB

STRING_LITERAL ::=
	 ( "'" ( [^'] | "''" )* "'" _ )
	| ( '"' ( [^"] | '""' )* '"' _ )

FLOAT_LITERAL ::=
	 '-'? ( ( '.' DIGIT+ ) | ( ( DIGIT+ ( '.' DIGIT* ) ( [Ee] [-+]? DIGIT+ )? ) | ( DIGIT+ ( [Ee] [-+]? DIGIT+ ) ) ) ) WB

BOOLEAN_LITERAL ::=
	 ( TRUE )
	| ( FALSE )

DIGIT ::=
	 [0-9]


//Added tokens for railroad generation
_NOT_ ::= '!'
_AND_ ::= '&'

mingodad avatar May 05 '22 15:05 mingodad

Very nice, I will show this to our docs team.

borrrden avatar May 06 '22 02:05 borrrden

Awesome!

snej avatar May 06 '22 20:05 snej