# EBNF Notation3 Grammar based pm Antlr4.
# From https://github.com/w3c/N3/blob/master/grammar/n3.g4

[1]  n3Doc                              ::= (n3Statement '.' | sparqlDirective)*

[2]  n3Statement                        ::= n3Directive | triples

[3]  n3Directive                        ::= prefixID | base

[4]  sparqlDirective                    ::= sparqlBase | sparqlPrefix

[5]  sparqlBase                         ::= BASE IRIREF

[6]  sparqlPrefix                       ::= PREFIX PNAME_NS IRIREF

[7]  prefixID                           ::= '@prefix' PNAME_NS IRIREF

[8]  base                               ::= '@base' IRIREF

[9]  triples                            ::= subject predicateObjectList?

[10] predicateObjectList                ::= verb objectList (';' (verb objectList)?)*

[11] objectList                         ::= object (',' object)*

[12] verb                               ::= predicate
                                          | 'a'
                                          | 'has' expression
                                          | 'is' expression 'of'
                                          | '='
                                          | '<='
                                          | '=>'

[13] subject                            ::= expression

[14] predicate                          ::= (expression | '<-' expression)
                                            /* allow inverting first predicate in a path */

[15] object                             ::= expression

[16] expression                         ::= path

[17] path	                              ::= pathItem ('!' path | '^' path)?

[18] pathItem                           ::= iri
                                          | blankNode
                                          | quickVar
                                          | collection
                                          | blankNodePropertyList
                                          | iriPropertyList
                                          | literal
                                          | formula

[19] literal                            ::= rdfLiteral
                                          | numericLiteral
                                          | BOOLEAN_LITERAL

[20] blankNodePropertyList              ::= '[' predicateObjectList ']'

[21] iriPropertyList                    ::= IPLSTART iri predicateObjectList ']'

[22] collection                         ::= '(' object* ')'

[23] formula                            ::= '{' formulaContent? '}'

[24] formulaContent                     ::= n3Statement ('.' formulaContent?)?
                                          | sparqlDirective formulaContent?

[25] numericLiteral                     ::= DOUBLE | DECIMAL | INTEGER

[26] rdfLiteral                         ::= STRING (LANGTAG | '^^' iri)?

[27] iri                                ::= IRIREF | prefixedName

[28] prefixedName                       ::= PNAME_LN | PNAME_NS
                                            # PNAME_NS will be matched for ':' (i.e., "empty") prefixedNames
                                            # hence this cannot be a lexer rule; for s/p/o of only ':', PNAME_NS will be returned
                                            # instead of PrefixedName token

[29] blankNode                          ::=  BLANK_NODE_LABEL | ANON

[30] quickVar                           ::= QUICK_VAR_NAME
                                            # only made this a parser rule for consistency
                                            # (all other path-items are also parser rules)

@terminals

[31] BOOLEAN_LITERAL                    ::= 'true' | 'false'

[32] STRING                             ::= STRING_LITERAL_LONG_SINGLE_QUOTE
                                          | STRING_LITERAL_LONG_QUOTE
                                          | STRING_LITERAL_QUOTE
                                          | STRING_LITERAL_SINGLE_QUOTE

/* Note, this must be matched before '[' */
[33] IPLSTART                           ::= '[' WS* 'id'

/* borrowed from SPARQL spec, which excludes newlines and other nastiness */
[139s] IRIREF                           ::= '<' ([^<>"{}|^`\]-[#x00-#x20] | UCHAR)* '>'
[140s] PNAME_NS                         ::= PN_PREFIX? ':'
[141s] PNAME_LN                         ::= PNAME_NS PN_LOCAL
[142s] BLANK_NODE_LABEL                 ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
[145s] LANGTAG                          ::= "@" ([a-zA-Z]+ ( "-" [a-zA-Z0-9]+ )*)
[146s] INTEGER                          ::= [0-9]+
[147s] DECIMAL                          ::= [0-9]* '.' [0-9]+
[148s] DOUBLE                           ::= [0-9]+ '.' [0-9]* EXPONENT
                                          | '.' ([0-9])+ EXPONENT | ([0-9])+ EXPONENT
[155s] EXPONENT                         ::= [eE] [+-]? [0-9]+
[156s] STRING_LITERAL_QUOTE             ::= '"' ( [^#x22#x5C#xA#xD] | ECHAR | UCHAR )* '"'
[157s] STRING_LITERAL_SINGLE_QUOTE      ::= "'" ( [^#x27#x5C#xA#xD] | ECHAR | UCHAR )* "'"
[158s] STRING_LITERAL_LONG_SINGLE_QUOTE ::= "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR | UCHAR ) )* "'''"
[159s] STRING_LITERAL_LONG_QUOTE        ::= '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR | UCHAR ) )* '"""'
[35]  UCHAR                             ::=   ( "\u" HEX HEX HEX HEX ) | ( "\U" HEX HEX HEX HEX HEX HEX HEX HEX )
[160s] ECHAR                            ::= "\" [tbnrf\"']
[162s] WS                               ::= #x20 | #x9 | #xD | #xA
[163s] ANON                             ::= '[' WS* ']'
[36] QUICK_VAR_NAME                     ::= "?" PN_LOCAL
                                           /* Allows fuller character set */
[164s] PN_CHARS_BASE                    ::= [A-Z] | [a-z] | [#x00C0-#x00D6]
                                          | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D]
                                          | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F]
                                          | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF]
                                          | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
[165s] PN_CHARS_U                     ::= PN_CHARS_BASE | '_'
[167s] PN_CHARS                       ::= PN_CHARS_U | "-" | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
/* BASE and PREFIX must be case-insensitive, hence these monstrosities */
[37] BASE                             ::= ('B'|'b') ('A'|'a') ('S'|'s') ('E'|'e')
[38] PREFIX                           ::= ('P'|'p') ('R'|'r') ('E'|'e') ('F'|'f') ('I'|'i') ('X'|'x')
[168s] PN_PREFIX                      ::= PN_CHARS_BASE ( ( PN_CHARS | "." )* PN_CHARS )?
[169s] PN_LOCAL                       ::= ( PN_CHARS_U | ':' | [0-9] | PLX ) ( ( PN_CHARS | '.' | ':' | PLX )*  ( PN_CHARS | ':' | PLX ) ) ?
[170s] PLX                            ::= PERCENT | PN_LOCAL_ESC
[171s] PERCENT                        ::= '%' HEX HEX
[172s] HEX                            ::=   [0-9] | [A-F] | [a-f]
[173s] PN_LOCAL_ESC                   ::= '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '='
                                        | '/' | '?' | '#' | '@' | '%' )
[39] COMMENT   ::= ('#' - '#x') [^#xA#xC#xD]*

# Ignore all whitespace and comments between non-terminals
@pass           ( WS | COMMENT )*