
DOCUMENT START
TOKENS
<DEFAULT> SKIP : {
" "
| "\t"
| "\n"
| "\r"
| "\f"
}

<DEFAULT> SPECIAL : {
<SINGLE_LINE_COMMENT: "#" (~["\n","\r"])* ("\n" | "\r" | "\r\n")?>
}

<DEFAULT> TOKEN [IGNORE_CASE] : {
<BASE: "BASE">
| <IMPORTS: "IMPORTS">
| <PREFIX: "PREFIX">
| <SHAPE_CLASS: "shapeClass">
| <SHAPE: "shape">
| <TRUE: "true">
| <FALSE: "false">
}

<DEFAULT> TOKEN : {
<BOM: "\ufeff">
| <#HEX: ["0"-"9"] | ["A"-"F"] | ["a"-"f"]>
| <PLUS: "+">
| <MINUS: "-">
| <VBAR: "|">
| <AT: "@">
| <CARAT: "^">
| <DOT: ".">
| <BANG: "!">
| <QMARK: "?">
| <SLASH: "/">
| <STAR: "*">
| <EQUALS: "=">
| <LPAREN: "(">
| <RPAREN: ")">
| <LBRACE: "{">
| <RBRACE: "}">
| <LBRACKET: "[">
| <RBRACKET: "]">
| <IRIref: "<" (~[">","<","\"","{","}","^","\\","|","`","\u0000"-" "] | <UCHAR>)* ">">
| <PNAME_NS: (<PN_PREFIX>)? ":">
| <PNAME_LN: <PNAME_NS> <PN_LOCAL>>
| <ATPNAME_NS: "@" <PNAME_NS>>
| <ATPNAME_LN: "@" <PNAME_LN>>
| <#QUOTE_3D: "\"\"\"">
| <#QUOTE_3S: "\'\'\'">
| <#ECHAR: "\\" ("t" | "b" | "n" | "r" | "f" | "\\" | "\"" | "\'")>
| <#UCHAR: <UCHAR4> | <UCHAR8>>
| <#UCHAR4: "\\" "u" <HEX> <HEX> <HEX> <HEX>>
| <#UCHAR8: "\\" "U" <HEX> <HEX> <HEX> <HEX> <HEX> <HEX> <HEX> <HEX>>
| <STRING_LITERAL1: "\'" (~["\'","\\","\n","\r"] | <ECHAR> | <UCHAR>)* "\'">
| <STRING_LITERAL2: "\"" (~["\"","\\","\n","\r"] | <ECHAR> | <UCHAR>)* "\"">
| <STRING_LITERAL_LONG1: <QUOTE_3S> (("\'" | "\'\'")? (~["\'","\\"] | <ECHAR> | <UCHAR>))* <QUOTE_3S>>
| <STRING_LITERAL_LONG2: <QUOTE_3D> (("\"" | "\"\"")? (~["\"","\\"] | <ECHAR> | <UCHAR>))* <QUOTE_3D>>
| <#DIGITS: (["0"-"9"])+>
| <INTEGER: (<PLUS> | <MINUS>)? <DIGITS>>
| <DECIMAL: (<PLUS> | <MINUS>)? (<DIGITS>)? "." <DIGITS>>
| <DOUBLE: (<PLUS> | <MINUS>)? ((["0"-"9"])+ "." (["0"-"9"])* <EXPONENT> | "." (["0"-"9"])+ <EXPONENT> | (["0"-"9"])+ <EXPONENT>)>
| <#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+>
| <LANGTAG: <AT> (<A2Z>)+ ("-" (<A2ZN>)+)*>
| <#A2Z: ["a"-"z","A"-"Z"]>
| <#A2ZN: ["a"-"z","A"-"Z","0"-"9"]>
| <#SURROGATE_PAIR: ["\ud800"-"\udbff"] ["\udc00"-"\udfff"]>
| <#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"-"\ufffd"] | <SURROGATE_PAIR>>
| <#PN_CHARS_U: <PN_CHARS_BASE> | "_">
| <#PN_CHARS: <PN_CHARS_U> | "-" | ["0"-"9"] | "\u00b7" | ["\u0300"-"\u036f"] | ["\u203f"-"\u2040"]>
| <#PN_PREFIX: <PN_CHARS_BASE> ((<PN_CHARS> | ".")* <PN_CHARS>)?>
| <#PN_LOCAL: (<PN_CHARS_U> | ":" | ["0"-"9"] | <PLX>) ((<PN_CHARS> | "." | ":" | <PLX>)* (<PN_CHARS> | ":" | <PLX>))?>
| <#VARNAME: (<PN_CHARS_U> | ["0"-"9"]) (<PN_CHARS_U> | ["0"-"9"] | "\u00b7" | ["\u0300"-"\u036f"] | ["\u203f"-"\u2040"])*>
| <#PN_LOCAL_ESC: "\\" ("_" | "~" | "." | "-" | "!" | "$" | "&" | "\'" | "(" | ")" | "*" | "+" | "," | ";" | "=" | "/" | "?" | "#" | "@" | "%")>
| <#PLX: <PERCENT> | <PN_LOCAL_ESC>>
| <#PERCENT: "%" <HEX> <HEX>>
}

// Catch-all tokens.  Must be last.  
// Any non-whitespace.  Causes a parser exception, rather than a
// token manager error (which hides the line numbers).
<DEFAULT> TOKEN : {
<#UNKNOWN: (~[" ","\t","\n","\r","\f"])+>
}

NON-TERMINALS
	Unit	:=	ByteOrderMark shaclDoc <EOF>
	ByteOrderMark	:=	( <BOM> )?
	shaclDoc	:=	( directive )* ( nodeShape | shapeClass )*
	directive	:=	( baseDecl | prefixDecl | importDecl )
	baseDecl	:=	<BASE> IRIREF
	prefixDecl	:=	<PREFIX> <PNAME_NS> IRIREF
	importDecl	:=	<IMPORTS> iri
	nodeShape	:=	<SHAPE> iri ( targetClass )? nodeShapeBody
	shapeClass	:=	<SHAPE_CLASS> iri nodeShapeBody
	targetClass	:=	"->" ( iri )+
	nodeShapeBody	:=	<LBRACE> ( constraint )* <RBRACE>
	constraint	:=	( ( nodeOr )+ | propertyShape | shapeRef ) <DOT>
	nodeOr	:=	nodeNot ( <VBAR> nodeNot )*
	nodeNot	:=	( negation )? nodeValue
	negation	:=	<BANG>
	nodeValue	:=	nodeParam <EQUALS> ( iriOrLiteral | array )
	propertyShape	:=	path ( propertyCount | propertyOr )*
	propertyOr	:=	propertyNot ( <VBAR> propertyNot )*
	propertyNot	:=	( negation )? propertyAtom
	propertyAtom	:=	propertyType
		|	nodeKind
		|	shapeRef
		|	propertyValue
		|	( nodeShapeBody )
	propertyCount	:=	<LBRACKET> propertyMinCount ".." propertyMaxCount <RBRACKET>
	propertyMinCount	:=	<INTEGER>
	propertyMaxCount	:=	( <INTEGER> | <STAR> )
	propertyType	:=	iri
	nodeKind	:=	( "BlankNode" | "IRI" | "Literal" | "BlankNodeOrIRI" | "BlankNodeOrLiteral" | "IRIOrLiteral" )
	shapeRef	:=	( <ATPNAME_LN> | <ATPNAME_NS> | <AT> IRIREF )
	propertyValue	:=	propertyParam <EQUALS> ( iriOrLiteral | array )
// Assemble items to build with from hereon down.
// Return Java objects.
	nodeParam	:=	( "targetNode" | "targetObjectsOf" | "targetSubjectsOf" | "targetClass" | "deactivated" | "severity" | "message" | "class" | "datatype" | "nodeKind" | "minExclusive" | "minInclusive" | "maxExclusive" | "maxInclusive" | "minLength" | "maxLength" | "pattern" | "flags" | "languageIn" | "equals" | "disjoint" | "closed" | "ignoredProperties" | "hasValue" | "in" )
	propertyParam	:=	( "deactivated" | "severity" | "message" | "class" | "datatype" | "nodeKind" | "minExclusive" | "minInclusive" | "maxExclusive" | "maxInclusive" | "minLength" | "maxLength" | "pattern" | "flags" | "languageIn" | "uniqueLang" | "equals" | "disjoint" | "lessThan" | "lessThanOrEquals" | "qualifiedValueShape" | "qualifiedMinCount" | "qualifiedMaxCount" | "qualifiedValueShapesDisjoint" | "closed" | "ignoredProperties" | "hasValue" | "in" | "group" | "order" | "name" | "description" | "defaultValue" )
// Paths - subset of SPARQL Paths - no negation, no path property sets.
	PathUnit	:=	ByteOrderMark path <EOF>
// Weakest outermost
	path	:=	pathAlternative
	pathAlternative	:=	pathSequence ( <VBAR> pathSequence )*
	pathSequence	:=	pathEltOrInverse ( <SLASH> pathEltOrInverse )*
// Path unit element, no inverse
	pathElt	:=	pathPrimary ( pathMod )?
// Path unit element, including inverse.
	pathEltOrInverse	:=	( pathElt | <CARAT> pathElt )
	pathMod	:=	( <QMARK> | <STAR> | <PLUS> )
	pathPrimary	:=	( iri | <LPAREN> path <RPAREN> )
// To preserve types, use ( iriOrLiteral() | array() ) directly
// void iriOrLiteralOrArray() : {}
// {
//   (
//     { Node n = null; }
//     n = iriOrLiteral()
//     { iriOrLiteralOrArray(n); }
//   |
//     { List<Node> x = null; }
//     x = array()
//     { iriOrLiteralOrArray(x); }
//   )
// }
	array	:=	<LBRACKET> ( iriOrLiteral )* <RBRACKET>
// Term generation
	iriOrLiteral	:=	( iri | literal )
	literal	:=	( rdfLiteral | numericLiteral | booleanLiteral )
	booleanLiteral	:=	<TRUE>
		|	<FALSE>
	numericLiteral	:=	<INTEGER>
		|	<DECIMAL>
		|	<DOUBLE>
	rdfLiteral	:=	string ( ( <LANGTAG> ) | ( "^^" datatype ) )?
	datatype	:=	iri
	string	:=	( <STRING_LITERAL1> | <STRING_LITERAL2> | <STRING_LITERAL_LONG1> | <STRING_LITERAL_LONG2> )
	iri	:=	IRIREF
		|	PrefixedName
	PrefixedName	:=	( <PNAME_LN> | <PNAME_NS> )
	IRIREF	:=	<IRIref>

DOCUMENT END
