Fork of https://github.com/oxigraph/oxigraph.git for the purpose of NextGraph project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
oxigraph/src/rio/turtle/turtle_grammar.rustpeg

277 lines
7.3 KiB

//See https://www.w3.org/TR/turtle/#sec-grammar
use std::char;
use model::vocab::rdf;
use model::vocab::xsd;
use std::iter;
use rio::utils::unescape_unicode_codepoints;
#![arguments(state: &mut ParserState, buffer: &mut Vec<Triple>)]
//[1]
pub turtleDoc -> () = _ (statement _)*
//[2]
statement -> () = directive / triples "."
//[3]
directive -> () = prefixID / base / sparqlPrefix / sparqlBase
//[4]
prefixID -> () = "@prefix" _ ns:PNAME_NS _ i:IRIREF _ "." {
state.namespaces.insert(ns.into(), i);
}
//[5]
base -> () = "@base" _ url:IRIREF _ "." {
state.base_uri = Some(url);
}
//[5s]
sparqlBase -> () = "BASE"i _ url:IRIREF {
state.base_uri = Some(url);
}
//[6s]
sparqlPrefix -> () = "PREFIX"i _ ns:PNAME_NS _ i:IRIREF {
state.namespaces.insert(ns.into(), i);
}
//[6]
triples -> () = subject_push _ predicateObjectList / triples_blankNodePropertyList_push _ predicateObjectList? {
state.cur_subject.pop();
}
subject_push -> () = s:subject {
state.cur_subject.push(s)
}
triples_blankNodePropertyList_push -> () = s: blankNodePropertyList {
state.cur_subject.push(s)
}
//[7]
predicateObjectList -> () = predicateObject (";" _ predicateObject?)*
predicateObject -> () = predicate_push _ objectList _ {
state.cur_predicate.pop();
}
predicate_push -> () = v:verb {
state.cur_predicate.push(v)
}
//[8]
objectList -> () = object _ ("," _ object _)*
//[9]
verb -> NamedNode = predicate /
"a" { rdf::TYPE.clone() }
// [10]
subject -> NamedOrBlankNode =
i:iri { i.into() } /
b:BlankNode { b.into() } /
c:collection { c }
//[11]
predicate -> NamedNode = iri
// [12]
object -> () = o:object_value {?
match state.cur_subject.last() {
Some(s) => match state.cur_predicate.last() {
Some(p) => {
buffer.push(Triple::new(s.clone(), p.clone(), o));
Ok(())
}
None => Err("Predicate not found")
},
None => Err("Subject not found")
}
}
object_value -> Term =
i:iri { i.into() } /
b:BlankNode { b.into() } /
c:collection { c.into() } /
b:blankNodePropertyList { b.into() } /
l:literal { l.into() }
//[13]
literal -> Literal = RDFLiteral / NumericLiteral / BooleanLiteral
//[14]
blankNodePropertyList -> NamedOrBlankNode = blankNodePropertyList_open _ predicateObjectList _ "]" {?
state.cur_subject.pop().ok_or("No subject found in the stack")
}
blankNodePropertyList_open -> () = "[" {
state.cur_subject.push(BlankNode::default().into())
}
//[15]
collection -> NamedOrBlankNode = '(' _ o:(collection_value*) ')' {
let mut current_list_node = NamedOrBlankNode::from(rdf::NIL.clone());
for obj in o.into_iter().rev() {
let new_blank_node = NamedOrBlankNode::from(BlankNode::default());
buffer.push(Triple::new(new_blank_node.clone(), rdf::FIRST.clone(), obj));
buffer.push(Triple::new(new_blank_node.clone(), rdf::REST.clone(), current_list_node));
current_list_node = new_blank_node;
}
current_list_node
}
collection_value -> Term = o:object_value _ { o }
//[16]
NumericLiteral -> Literal =
d:$(DOUBLE) { Literal::new_typed_literal(d, xsd::DOUBLE.clone()) } /
d:$(DECIMAL) { Literal::new_typed_literal(d, xsd::DECIMAL.clone()) } /
i:$(INTEGER) { Literal::new_typed_literal(i, xsd::INTEGER.clone()) }
//[128s]
RDFLiteral -> Literal =
v:String _ "^^" _ t:iri { Literal::new_typed_literal(v, t) } /
v:String _ l:LANGTAG { Literal::new_language_tagged_literal(v, l) } /
v:String { v.into() }
//[133s]
BooleanLiteral -> Literal =
"true" { true.into() } /
"false" { false.into() }
//[17]
String -> String = STRING_LITERAL_LONG_SINGLE_QUOTE / STRING_LITERAL_LONG_QUOTE / STRING_LITERAL_QUOTE / STRING_LITERAL_SINGLE_QUOTE
//[135s]
iri -> NamedNode = i:(IRIREF / PrefixedName) {
i.into()
}
//[136s]
PrefixedName -> Url = PNAME_LN /
ns:PNAME_NS {? state.namespaces.get(ns).cloned().ok_or("Prefix not found") }
//[137s]
BlankNode -> BlankNode =
b:BLANK_NODE_LABEL { state.bnodes_map.entry(b.to_string()).or_insert_with(BlankNode::default).clone() } /
ANON { BlankNode::default() }
//[18]
IRIREF -> Url = "<" i:$(([^\u{00}-\u{20}<>"{}|^\u{60}\u{5c}] / UCHAR)*) ">" {?
match state.url_parser().parse(&unescape_unicode_codepoints(i)) {
Ok(url) => Ok(url),
Err(error) => Err("IRI parsing failed")
}
}
//[139s]
PNAME_NS -> &'input str = ns:$(PN_PREFIX? ":") {
ns
}
//[140s]
PNAME_LN -> Url = ns:$(PNAME_NS) local:PN_LOCAL {?
match state.namespaces.get(ns) {
Some(ns) => match Url::parse(&(ns.to_string() + &local)) {
Ok(url) => Ok(url),
Err(error) => Err("IRI parsing failed")
},
None => Err("Prefix not found")
}
}
//[141s]
BLANK_NODE_LABEL -> &'input str = "_:" b:$(([0-9] / PN_CHARS_U) PN_CHARS* ("."+ PN_CHARS+)*) {
b
}
//[144s]
LANGTAG -> &'input str = "@" l:$([a-zA-Z]+ ("-" [a-zA-Z0-9]+)*) {
l
}
//[19]
INTEGER -> () = [+-]? [0-9]+
//[20]
DECIMAL -> () = [+-]? [0-9]* "." [0-9]+
//[21]
DOUBLE -> () = [+-]? ([0-9]+ "." [0-9]* / "."? [0-9]+) EXPONENT
//[154s]
EXPONENT -> () = [eE] [+-]? [0-9]+
//[22]
STRING_LITERAL_QUOTE -> String = "\"" l: $(([^"\u{005c}\u{000a}\u{000d}] / ECHAR / UCHAR)*) "\"" {
unescape_unicode_codepoints(&unescape_echars(l)).into_owned()
}
//[23]
STRING_LITERAL_SINGLE_QUOTE -> String = "'" l:$(([^'\u{005c}\u{000a}\u{000d}] / ECHAR / UCHAR)*) "'" {
unescape_unicode_codepoints(&unescape_echars(l)).into_owned()
}
//[24]
STRING_LITERAL_LONG_SINGLE_QUOTE -> String = "'''" l:$(STRING_LITERAL_LONG_SINGLE_QUOTE_inner*) "'''" {
unescape_unicode_codepoints(&unescape_echars(l)).into_owned()
}
STRING_LITERAL_LONG_SINGLE_QUOTE_inner -> () = ("''" / "'")? ([^'\u{005c}] / ECHAR / UCHAR)
//[25]
STRING_LITERAL_LONG_QUOTE -> String = "\"\"\"" l:$(STRING_LITERAL_LONG_QUOTE_inner*) "\"\"\"" {
unescape_unicode_codepoints(&unescape_echars(l)).into_owned()
}
STRING_LITERAL_LONG_QUOTE_inner -> () = ("\"\"" / "\"")? ([^"\u{005c}] / ECHAR / UCHAR)
//[26]
UCHAR -> () = "\\u" HEX HEX HEX HEX / "\\U" HEX HEX HEX HEX HEX HEX HEX HEX
//[159s]
ECHAR -> () = "\\" [tbnrf"'\\]
//[161s]
WS -> () = #quiet<[\u{20}\u{9}\u{D}\u{A}]>
//[162s]
ANON -> () = "[" WS* "]"
//[163s]
PN_CHARS_BASE -> () = [A-Za-z\u{00C0}-\u{00D6}\u{00D8}-\u{00F6}\u{00F8}-\u{02FF}\u{0370}-\u{037D}\u{037F}-\u{1FFF}\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFFD}]
//[164s]
PN_CHARS_U -> () = "_" / PN_CHARS_BASE
//[166s]
PN_CHARS -> () = [\-0-9\u{00B7}\u{0300}-\u{036F}\u{203F}-\u{2040}] / PN_CHARS_U
//[167s]
PN_PREFIX -> () = PN_CHARS_BASE PN_CHARS* ("."+ PN_CHARS+)*
//[168s]
PN_LOCAL -> String = f:PN_LOCAL_first c:(PN_LOCAL_next*) e:(PN_LOCAL_next_dot*) {
f.to_string() + &c.concat() + &e.concat()
}
PN_LOCAL_first -> String =
c:$(":" / [0-9] / PN_CHARS_U) { c.into() } /
s:PLX { s }
PN_LOCAL_next -> String =
c:$(":" / PN_CHARS) { c.into() } /
s:PLX { s }
PN_LOCAL_next_dot -> String = d:$("."+) f:PN_LOCAL_next { d.to_string() + &f}
//[169s]
PLX -> String =
p:$(PERCENT) { p.into() } /
e:PN_LOCAL_ESC { iter::once(e).collect() }
//[170s]
PERCENT -> () = "%" HEX HEX
//[171s]
HEX -> () = ([0-9A-Fa-f])
//[172s]
PN_LOCAL_ESC -> char = "\\" c:$([_~\.\-!$&'()*+,;=/?#@%]) { c.chars().next().unwrap() }
//space
_ = #quiet<([ \t\n\r] / comment)*>
//comment
comment = #quiet<"#" [^\r\n]*>