# This is a JSON Grammar (JSG) file for the ShEx Results format.
# The form "OBJNAME  { property:PROPTYPE ... }" matches an object of type OBJTYPE
# The form "RULENAME = NAME1 | NAME2 ..." matches any of NAMEn.
# the form "TERMNAME : "RegExp" matches any literal matching RegExp
# A PROPTYPE can be:
#   TERMINAL - a terminal, all caps in this example.
#   [PROPTYPE] - an array of PROPTYPE.
#   {TERMINAL->PROPTYPE} - a map from TERMINAL to PROPTYPE.
#   (PROPTYPE1|PROPTYPE2...) - any of PROPTYPEn.

.TYPE type - ObjectLiteral; # ObjectLiterals use type to specify lexical datatype

shapeExprTest    = ShapeOrResults | ShapeAndResults | ShapeNotResults | ShapeTest | NodeTest | SolutionList | Failure | FailureList | AbstractShapeFailure ;
ShapeOrResults   { solution:shapeExprTest }
ShapeAndResults  { solutions:[shapeExprTest+] }
ShapeNotResults  { solution:Failure }
Failure          { node:(IRI|BNODE) shape:(IRI|BNODE) errors:[error+] }
error            = MissingProperty | TypeMismatch | Failure;
MissingProperty  { property:IRI valueExpr:NodeConstraint? } # get rid of valueExpr?
TypeMismatch     { triple:TestedTriple constraint:TripleConstraint errors:[STRING]  }
NodeTest         { node:(IRI|BNODE|ObjectLiteral) shape:(IRI|BNODE) shapeExpr:shapeExpr }
ShapeTest        { node:(IRI|BNODE) shape:(IRI|BNODE|START) solution:tripleExprSolutions? startActs:[SemAct+]? annotations:[Annotation+]? }
SolutionList     { solutions:[shapeExprTest+] }
FailureList      { errors:[error+] }
tripleExprSolutions = EachOfSolutions | OneOfSolutions | TripleConstraintSolutions ;
EachOfSolutions  { solutions:[EachOfSolution+] min:INTEGER? max:INTEGER? annotations:[Annotation+]? semActs:[SemAct+]? }
EachOfSolution   { expressions:[tripleExprSolutions+] }
OneOfSolutions   { solutions:[OneOfSolution+] min:INTEGER? max:INTEGER? annotations:[Annotation+]? semActs:[SemAct+]? }
OneOfSolution    { expressions:[tripleExprSolutions+] }
TripleConstraintSolutions { predicate:IRI valueExpr:shapeExpr? min:INTEGER? max:INTEGER? solutions:[TestedTriple] annotations:[Annotation+]? semActs:[SemAct+]? }
TestedTriple     { subject:(IRI|BNODE) predicate:IRI object:(IRI|BNODE|ObjectLiteral) referenced:(shapeExprTest|Recursion)? }
Recursion        { node:(IRI|BNODE) shape:(IRI|BNODE) }
AbstractShapeFailure { shape:(IRI|BNODE) errors:[error] }

# Shape Expressions
shapeExpr        = ShapeOr | ShapeAnd | ShapeNot | NodeConstraint | Shape | ShapeRef | ShapeExternal;
ShapeOr          { shapeExprs:[shapeExpr{2,}] }
ShapeAnd         { shapeExprs:[shapeExpr{2,}] }
ShapeNot         { shapeExpr:shapeExpr }
NodeConstraint   { nodeKind:("iri"|"bnode"|"nonliteral"|"literal")? datatype:IRI? xsFacet* values:[valueSetValue+]? }
ShapeRef         { reference:IRI } # should be a TERM or some such
Shape            { virtual:BOOL? closed:BOOL? extra:[IRI+]? expression:tripleExpr? extends:[shapeExpr+]? semActs:[SemAct+]? annotations:[Annotation+]? }
ShapeExternal    {  }

# Triple Expressions
tripleExpr       = EachOf | OneOf | TripleConstraint | tripleExprLabel ;
EachOf           { id:tripleExprLabel? expressions:[tripleExpr{2,}] min:INTEGER? max:INTEGER? semActs:[SemAct+]? annotations:[Annotation+]? }
OneOf            { id:tripleExprLabel? expressions:[tripleExpr{2,}] min:INTEGER? max:INTEGER? semActs:[SemAct+]? annotations:[Annotation+]? }
TripleConstraint { id:tripleExprLabel? inverse:BOOL? negated:BOOL? predicate:IRI valueExpr:shapeExpr? min:INTEGER? max:INTEGER? semActs:[SemAct+]? annotations:[Annotation+]? }

# XML Schema facets
xsFacet          = stringFacet | numericFacet ;
stringFacet      = (length|minlength|maxlength):INTEGER | pattern:STRING flags:STRING? ;
numericFacet     = (mininclusive|minexclusive|maxinclusive|maxexclusive):numericLiteral
                 | (totaldigits|fractiondigits):INTEGER ;

# Value Sets
valueSetValue    = objectValue | IriStem | IriStemRange | LiteralStem | LiteralStemRange | Language | LanguageStem | LanguageStemRange ;
objectValue      = IRI|ObjectLiteral ;
IriStem          { stem:IRI }
IriStemRange     { stem:(IRI|Wildcard) exclusions:[IRI|IriStem +] }
LiteralStem      { stem:STRING }
LiteralStemRange { stem:(STRING|Wildcard) exclusions:[STRING|LiteralStem +] }
Language         { languageTag:STRING }
LanguageStem     { stem:LANGTAG }
LanguageStemRange{ stem:(LANGTAG|Wildcard) exclusions:[LANGTAG|LanguageStem +] }
Wildcard         {  }

SemAct           { name:IRI code:STRING? }
Annotation       { predicate:IRI object:objectValue }

shapeExprLabel   = IRI|BNODE ;
tripleExprLabel  = IRI|BNODE ;
numericLiteral   = INTEGER|DECIMAL|DOUBLE ;
ObjectLiteral    { value:STRING language:LANGTAG? type:IRI? }

# Terminals used in productions:
IRI              : (PN_CHARS | '.' | ':' | '/' | '\\' | '#' | '@' | '%' | '&' | UCHAR)* ; # <http://www.w3.org/TR/turtle/#grammar-production-IRIREF> - "<>"s
BNODE            : '_:' (PN_CHARS_U | [0-9]) ((PN_CHARS | '.')* PN_CHARS)? ; # <http://www.w3.org/TR/turtle/#grammar-production-BLANK_NODE_LABEL>
BOOL             : "true" | "false" ; # JSON boolean tokens
INTEGER          : [+-]? [0-9] + ; # <http://www.w3.org/TR/turtle/#grammar-production-INTEGER>
DECIMAL          : [+-]? [0-9]* '.' [0-9] + ; # <http://www.w3.org/TR/turtle/#grammar-production-DECIMAL>
DOUBLE           : [+-]? ([0-9] + '.' [0-9]* EXPONENT | '.' [0-9]+ EXPONENT | [0-9]+ EXPONENT) ; # <http://www.w3.org/TR/turtle/#grammar-production-DOUBLE>
LANGTAG          : ([a-zA-Z])+('-'([a-zA-Z0-9])+)* ;
STRING           : .* ;

# Terminals use only in other terminals:
PN_PREFIX        : PN_CHARS_BASE ((PN_CHARS | '.')* PN_CHARS)? ;
PN_CHARS_BASE    : [A-Z] | [a-z] | [\u00C0-\u00D6] | [\u00D8-\u00F6]
                 | [\u00F8-\u02FF] | [\u0370-\u037D] | [\u037F-\u1FFF]
                 | [\u200C-\u200D] | [\u2070-\u218F] | [\u2C00-\u2FEF]
                 | [\u3001-\uD7FF] | [\uF900-\uFDCF] | [\uFDF0-\uFFFD]
                 | [\u10000-\uEFFFF] ;
PN_CHARS         : PN_CHARS_U | '-' | [0-9] | '\u00B7' | [\u0300-\u036F] | [\u203F-\u2040] ;
PN_CHARS_U       : PN_CHARS_BASE | '_' ;
UCHAR            : '\\u' HEX HEX HEX HEX
                 | '\\U' HEX HEX HEX HEX HEX HEX HEX HEX ;
HEX              : [0-9] | [A-F] | [a-f] ;
EXPONENT 	 : [eE] [+-]? [0-9]+ ;
START            : '_: -start-' ;
