<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://wiki.noethoumy.fr/index.php?action=history&amp;feed=atom&amp;title=Module%3AWikidata%2FChemin%2Fparser</id>
	<title>Module:Wikidata/Chemin/parser - Historique des versions</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.noethoumy.fr/index.php?action=history&amp;feed=atom&amp;title=Module%3AWikidata%2FChemin%2Fparser"/>
	<link rel="alternate" type="text/html" href="https://wiki.noethoumy.fr/index.php?title=Module:Wikidata/Chemin/parser&amp;action=history"/>
	<updated>2026-04-27T17:00:14Z</updated>
	<subtitle>Historique des versions pour cette page sur le wiki</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://wiki.noethoumy.fr/index.php?title=Module:Wikidata/Chemin/parser&amp;diff=347&amp;oldid=prev</id>
		<title>Jaggerwock : Page créée avec « local tool = require(&quot;Module:Utilitaire&quot;) local path = require &quot;Module:Wikidata/Chemin/Path&quot; local parser = require &quot;Module:FParser&quot;  local pparser = {}  --[[  grammar :   letter                  ::= &quot;A&quot; | &quot;B&quot; | &quot;C&quot; | &quot;D&quot; | &quot;E&quot; | &quot;F&quot; | &quot;G&quot;                           | &quot;H&quot; | &quot;I&quot; | &quot;J&quot; | &quot;K&quot; | &quot;L&quot; | &quot;M&quot; | &quot;N&quot;                           | &quot;O&quot; | &quot;P&quot; | &quot;Q&quot; | &quot;R&quot; | &quot;S&quot; | &quot;T&quot; | &quot;U&quot;                           | &quot;V&quot; | &quot;W&quot; | &quot;X&quot; | &quot;Y&quot; | &quot;Z&quot; | &quot;a&quot; | &quot;b&quot;... »</title>
		<link rel="alternate" type="text/html" href="https://wiki.noethoumy.fr/index.php?title=Module:Wikidata/Chemin/parser&amp;diff=347&amp;oldid=prev"/>
		<updated>2024-09-20T14:24:23Z</updated>

		<summary type="html">&lt;p&gt;Page créée avec « local tool = require(&amp;quot;Module:Utilitaire&amp;quot;) local path = require &amp;quot;Module:Wikidata/Chemin/Path&amp;quot; local parser = require &amp;quot;Module:FParser&amp;quot;  local pparser = {}  --[[  grammar :   letter                  ::= &amp;quot;A&amp;quot; | &amp;quot;B&amp;quot; | &amp;quot;C&amp;quot; | &amp;quot;D&amp;quot; | &amp;quot;E&amp;quot; | &amp;quot;F&amp;quot; | &amp;quot;G&amp;quot;                           | &amp;quot;H&amp;quot; | &amp;quot;I&amp;quot; | &amp;quot;J&amp;quot; | &amp;quot;K&amp;quot; | &amp;quot;L&amp;quot; | &amp;quot;M&amp;quot; | &amp;quot;N&amp;quot;                           | &amp;quot;O&amp;quot; | &amp;quot;P&amp;quot; | &amp;quot;Q&amp;quot; | &amp;quot;R&amp;quot; | &amp;quot;S&amp;quot; | &amp;quot;T&amp;quot; | &amp;quot;U&amp;quot;                           | &amp;quot;V&amp;quot; | &amp;quot;W&amp;quot; | &amp;quot;X&amp;quot; | &amp;quot;Y&amp;quot; | &amp;quot;Z&amp;quot; | &amp;quot;a&amp;quot; | &amp;quot;b&amp;quot;... »&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nouvelle page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local tool = require(&amp;quot;Module:Utilitaire&amp;quot;)&lt;br /&gt;
local path = require &amp;quot;Module:Wikidata/Chemin/Path&amp;quot;&lt;br /&gt;
local parser = require &amp;quot;Module:FParser&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local pparser = {}&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
&lt;br /&gt;
grammar : &lt;br /&gt;
&lt;br /&gt;
letter                  ::= &amp;quot;A&amp;quot; | &amp;quot;B&amp;quot; | &amp;quot;C&amp;quot; | &amp;quot;D&amp;quot; | &amp;quot;E&amp;quot; | &amp;quot;F&amp;quot; | &amp;quot;G&amp;quot;&lt;br /&gt;
                          | &amp;quot;H&amp;quot; | &amp;quot;I&amp;quot; | &amp;quot;J&amp;quot; | &amp;quot;K&amp;quot; | &amp;quot;L&amp;quot; | &amp;quot;M&amp;quot; | &amp;quot;N&amp;quot;&lt;br /&gt;
                          | &amp;quot;O&amp;quot; | &amp;quot;P&amp;quot; | &amp;quot;Q&amp;quot; | &amp;quot;R&amp;quot; | &amp;quot;S&amp;quot; | &amp;quot;T&amp;quot; | &amp;quot;U&amp;quot;&lt;br /&gt;
                          | &amp;quot;V&amp;quot; | &amp;quot;W&amp;quot; | &amp;quot;X&amp;quot; | &amp;quot;Y&amp;quot; | &amp;quot;Z&amp;quot; | &amp;quot;a&amp;quot; | &amp;quot;b&amp;quot;&lt;br /&gt;
                          | &amp;quot;c&amp;quot; | &amp;quot;d&amp;quot; | &amp;quot;e&amp;quot; | &amp;quot;f&amp;quot; | &amp;quot;g&amp;quot; | &amp;quot;h&amp;quot; | &amp;quot;i&amp;quot;&lt;br /&gt;
                          | &amp;quot;j&amp;quot; | &amp;quot;k&amp;quot; | &amp;quot;l&amp;quot; | &amp;quot;m&amp;quot; | &amp;quot;n&amp;quot; | &amp;quot;o&amp;quot; | &amp;quot;p&amp;quot;&lt;br /&gt;
                          | &amp;quot;q&amp;quot; | &amp;quot;r&amp;quot; | &amp;quot;s&amp;quot; | &amp;quot;t&amp;quot; | &amp;quot;u&amp;quot; | &amp;quot;v&amp;quot; | &amp;quot;w&amp;quot;&lt;br /&gt;
                          | &amp;quot;x&amp;quot; | &amp;quot;y&amp;quot; | &amp;quot;z&amp;quot; ;&lt;br /&gt;
digit                   ::= &amp;quot;0&amp;quot; | &amp;quot;1&amp;quot; | &amp;quot;2&amp;quot; | &amp;quot;3&amp;quot; | &amp;quot;4&amp;quot; | &amp;quot;5&amp;quot; | &amp;quot;6&amp;quot; | &amp;quot;7&amp;quot; | &amp;quot;8&amp;quot; | &amp;quot;9&amp;quot; ;&lt;br /&gt;
space                   ::= &amp;quot; &amp;quot; ;&lt;br /&gt;
&lt;br /&gt;
Pid                     ::= &amp;quot;P&amp;quot; , digit, { digit } ;&lt;br /&gt;
Pname                   ::= letter, { letter | digit | space | &amp;quot;&amp;#039;&amp;quot; } ;&lt;br /&gt;
&lt;br /&gt;
PathFirstLevel          ::= pathFirstAlternative&lt;br /&gt;
&lt;br /&gt;
-- Rules specific to allow to start from a statement instead of an item on the highest level of a path, variant of PathAlternative and PathSequence&lt;br /&gt;
&lt;br /&gt;
pathFirstAlternative   ::= PathFirstSequence ( &amp;#039;|&amp;#039; PathFirstSequence )*&lt;br /&gt;
PathFirstSequence &lt;br /&gt;
                        ::= (&amp;#039;&amp;gt;&amp;#039; PathQualifier | PathEltOrInverse ) ( &amp;#039;/&amp;#039; PathEltOrInverse | &amp;#039;^&amp;#039; PathElt )*&lt;br /&gt;
&lt;br /&gt;
Path			::= PathAlternative&lt;br /&gt;
PathAlternative 	::= 	PathSequence ( &amp;#039;|&amp;#039; PathSequence )*&lt;br /&gt;
PathSequence		::= 	PathEltOrInverse ( &amp;#039;/&amp;#039; PathEltOrInverse | &amp;#039;^&amp;#039; PathElt )*&lt;br /&gt;
PathElt			::= 	PathPrimary PathMod?&lt;br /&gt;
PathEltOrInverse	::= 	PathElt | &amp;#039;^&amp;#039; PathElt&lt;br /&gt;
PathMod			::= 	( &amp;#039;*&amp;#039; | &amp;#039;?&amp;#039; | &amp;#039;+&amp;#039; | &amp;#039;{&amp;#039; ( Integer ( &amp;#039;,&amp;#039; ( &amp;#039;}&amp;#039; | Integer &amp;#039;}&amp;#039; ) | &amp;#039;}&amp;#039; ) ) )&lt;br /&gt;
PathPrimary		::= ( Prop | &amp;#039;a&amp;#039; | &amp;#039;(&amp;#039; Path &amp;#039;)&amp;#039; &lt;br /&gt;
                            | ( Prop | &amp;#039;!&amp;#039; PathNegatedPropertySet ) &amp;#039;&amp;gt;&amp;#039; PathQualifier&lt;br /&gt;
                            | &amp;#039;!&amp;#039; PathNegatedPropertySet )&lt;br /&gt;
PathQualifier           ::= ( Prop | &amp;#039;!&amp;#039; PathNegatedPropertySet | PathPropertySet )&lt;br /&gt;
                    &lt;br /&gt;
Prop                    ::= IRIref | Pid | Pname&lt;br /&gt;
&lt;br /&gt;
rules 95 and 96 in https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rPathNegatedPropertySet&lt;br /&gt;
&lt;br /&gt;
PathNegatedPropertySet  ::=  	PathOneInPropertySet | &amp;#039;(&amp;#039; ( PathOneInPropertySet ( &amp;#039;|&amp;#039; PathOneInPropertySet )* )? &amp;#039;)&amp;#039;&lt;br /&gt;
PathOneInPropertySet    ::=  	iri | &amp;#039;a&amp;#039; | &amp;#039;^&amp;#039; ( iri | &amp;#039;a&amp;#039; ) &lt;br /&gt;
&lt;br /&gt;
PathPropertySet         ::=   &amp;#039;(&amp;#039; Path ( &amp;#039;|&amp;#039; Path )+ &amp;#039;)&amp;#039;&lt;br /&gt;
&lt;br /&gt;
For information, SPARQL property path grammar :&lt;br /&gt;
&lt;br /&gt;
https://www.w3.org/TR/sparql11-property-paths/#path-syntax&lt;br /&gt;
&lt;br /&gt;
TriplesSameSubjectPath  ::=   	VarOrTerm PropertyListNotEmptyPath | TriplesNode PropertyListPath&lt;br /&gt;
PropertyListPath        ::= 	PropertyListNotEmpty?&lt;br /&gt;
PropertyListNotEmptyPath::= 	( VerbPath | VerbSimple ) ObjectList ( &amp;#039;;&amp;#039; ( ( VerbPath | VerbSimple ) ObjectList )? )*&lt;br /&gt;
VerbPath 	        ::= 	Path&lt;br /&gt;
VerbSimple 	        ::= 	Var&lt;br /&gt;
Path 	                ::= 	PathAlternative&lt;br /&gt;
PathAlternative         ::= 	PathSequence ( &amp;#039;|&amp;#039; PathSequence )*&lt;br /&gt;
PathSequence            ::=	PathEltOrInverse ( &amp;#039;/&amp;#039; PathEltOrInverse | &amp;#039;^&amp;#039; PathElt )*&lt;br /&gt;
PathElt                 ::= 	PathPrimary PathMod?&lt;br /&gt;
PathEltOrInverse        ::= 	PathElt | &amp;#039;^&amp;#039; PathElt&lt;br /&gt;
PathMod                 ::= 	( &amp;#039;*&amp;#039; | &amp;#039;?&amp;#039; | &amp;#039;+&amp;#039; | &amp;#039;{&amp;#039; ( Integer ( &amp;#039;,&amp;#039; ( &amp;#039;}&amp;#039; | Integer &amp;#039;}&amp;#039; ) | &amp;#039;}&amp;#039; ) ) )&lt;br /&gt;
PathPrimary             ::= 	( IRIref | &amp;#039;a&amp;#039; | &amp;#039;(&amp;#039; Path &amp;#039;)&amp;#039; ) &lt;br /&gt;
&lt;br /&gt;
--]] &lt;br /&gt;
&lt;br /&gt;
local lexer = parser.lexer&lt;br /&gt;
&lt;br /&gt;
local chain = parser.chain&lt;br /&gt;
local alternative = parser.alternative&lt;br /&gt;
local plus = parser.plus&lt;br /&gt;
local idop = parser.idop&lt;br /&gt;
local nary_op_parser = parser.nary_op_parser&lt;br /&gt;
local lex_char = lexer.lex_char&lt;br /&gt;
local parse_epsilon = lexer.lex_epsilon&lt;br /&gt;
local lex_integer = lexer.lex_integer&lt;br /&gt;
&lt;br /&gt;
----------------------------------------------------------------------&lt;br /&gt;
-- grammar base lexer functions&lt;br /&gt;
----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local lex_pid = function(state)&lt;br /&gt;
	local res = lexer.lex_regex(state, &amp;quot;P[0-9]+&amp;quot;)&lt;br /&gt;
	if res then res.type=&amp;quot;Pid&amp;quot; return res end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local lex_sparql_prefix = function(state)&lt;br /&gt;
	local res = lexer.lex_regex(state, &amp;quot;[a-z_]*&amp;quot;)&lt;br /&gt;
	if res then res.type=&amp;quot;prefix&amp;quot; return res end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local lex_property_name = function(state)&lt;br /&gt;
	local res = lexer.lex_regex(state, &amp;quot;[a-zA-Z][a-z A-Z&amp;#039;-]*&amp;quot;)&lt;br /&gt;
	if res then res.type=&amp;quot;Plabel&amp;quot; return res end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- PathElt 	 ::= 	PathPrimary PathMod?&lt;br /&gt;
-- PathMod 	 ::= 	( &amp;#039;*&amp;#039; | &amp;#039;?&amp;#039; | &amp;#039;+&amp;#039; | &amp;#039;{&amp;#039; ( Integer ( &amp;#039;,&amp;#039; ( &amp;#039;}&amp;#039; | Integer &amp;#039;}&amp;#039; ) | &amp;#039;}&amp;#039; ) ) )&lt;br /&gt;
&lt;br /&gt;
function pparser.pathElt(state)&lt;br /&gt;
	local node&lt;br /&gt;
	local prime_node&lt;br /&gt;
	&lt;br /&gt;
	local min_bound = nil&lt;br /&gt;
	local max_bound = nil&lt;br /&gt;
	&lt;br /&gt;
	local function create_node(type)&lt;br /&gt;
		return idop(&lt;br /&gt;
			function(state)&lt;br /&gt;
				node = type:create(prime_node, min_bound, max_bound)&lt;br /&gt;
			end&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local res = chain{&lt;br /&gt;
		pparser.pathPrimary,&lt;br /&gt;
		idop(function(state) prime_node = state.node end),&lt;br /&gt;
		alternative{&lt;br /&gt;
			chain{&lt;br /&gt;
				lex_char(&amp;quot;*&amp;quot;),&lt;br /&gt;
				create_node(path.StarNode)&lt;br /&gt;
			},&lt;br /&gt;
		    chain{&lt;br /&gt;
				lex_char(&amp;quot;+&amp;quot;),&lt;br /&gt;
				create_node(path.PlusNode)&lt;br /&gt;
			},&lt;br /&gt;
		    chain{&lt;br /&gt;
				lex_char(&amp;quot;?&amp;quot;),&lt;br /&gt;
				create_node(path.MaybeNode)&lt;br /&gt;
			},&lt;br /&gt;
		    chain{&lt;br /&gt;
				lex_char(&amp;quot;^&amp;quot;),&lt;br /&gt;
				create_node(path.InverseNode)&lt;br /&gt;
			},&lt;br /&gt;
		    chain{&lt;br /&gt;
				lex_char(&amp;quot;{&amp;quot;),&lt;br /&gt;
				lex_integer,&lt;br /&gt;
				idop(function(state) min_bound = tonumber(state.lexed) end),&lt;br /&gt;
				alternative{&lt;br /&gt;
					chain{&lt;br /&gt;
						lex_char(&amp;quot;,&amp;quot;), &lt;br /&gt;
						lex_integer,&lt;br /&gt;
						idop(function(state) max_bound = tonumber(state.lexed) end)&lt;br /&gt;
					},&lt;br /&gt;
					chain{&lt;br /&gt;
						parse_epsilon, &lt;br /&gt;
						idop(function(state) max_bound = nil end)&lt;br /&gt;
					}&lt;br /&gt;
				},&lt;br /&gt;
				create_node(path.BetweenNode, min_bound, max_bound),&lt;br /&gt;
				lex_char(&amp;quot;}&amp;quot;),&lt;br /&gt;
			},&lt;br /&gt;
			chain{&lt;br /&gt;
				parse_epsilon,&lt;br /&gt;
				idop(function(state) node = prime_node end)&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}(state)&lt;br /&gt;
&lt;br /&gt;
	if res then&lt;br /&gt;
		res.node = node&lt;br /&gt;
		return res&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- PathEltOrInverse 	 ::= 	PathElt | &amp;#039;^&amp;#039; PathElt&lt;br /&gt;
pparser.pathEltOrInverse = function(state)&lt;br /&gt;
	return alternative{&lt;br /&gt;
		pparser.pathElt,&lt;br /&gt;
		chain{&lt;br /&gt;
			lex_char(&amp;quot;^&amp;quot;),&lt;br /&gt;
			pparser.pathElt,&lt;br /&gt;
			function(state)&lt;br /&gt;
				state.node = path.InverseNode(state.node)&lt;br /&gt;
				return state&lt;br /&gt;
			end&lt;br /&gt;
		}&lt;br /&gt;
	}(state)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[ &lt;br /&gt;
&lt;br /&gt;
Tests :&lt;br /&gt;
&lt;br /&gt;
plop=p.parse(&amp;quot;P31&amp;quot;,p.pathElt) ; t = require &amp;quot;Module:Tools&amp;quot; ; t.dump_to_console(plop)&lt;br /&gt;
yes&lt;br /&gt;
property=&amp;gt;&lt;br /&gt;
   P31&lt;br /&gt;
&lt;br /&gt;
plop=p.parse(&amp;quot;P31&amp;gt;P279&amp;quot;, p.pathElt) ; t = require &amp;quot;Module:Tools&amp;quot; ; t.dump_to_console(plop) &lt;br /&gt;
yes&lt;br /&gt;
property=&amp;gt;&lt;br /&gt;
   P279&lt;br /&gt;
node=&amp;gt;&lt;br /&gt;
   P31&lt;br /&gt;
&lt;br /&gt;
plop=p.parse(&amp;quot;P31{1,6}&amp;quot;,p.pathElt) ; t = require &amp;quot;Module:Tools&amp;quot; ; t.dump_to_console(plop)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
plop=p.parse(&amp;quot;(P31|P17&amp;gt;P31)&amp;quot;,p.pathElt) ; t = require &amp;quot;Module:Tools&amp;quot; ; t.dump_to_console(plop) &lt;br /&gt;
yes&lt;br /&gt;
nodes=&amp;gt;&lt;br /&gt;
   1=&amp;gt;&lt;br /&gt;
      property=&amp;gt;&lt;br /&gt;
         P31&lt;br /&gt;
   2=&amp;gt;&lt;br /&gt;
      property=&amp;gt;&lt;br /&gt;
         P31&lt;br /&gt;
      node=&amp;gt;&lt;br /&gt;
         P17&lt;br /&gt;
&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pparser.pathSequence = nary_op_parser(&lt;br /&gt;
	pparser.pathEltOrInverse,&lt;br /&gt;
	alternative{&lt;br /&gt;
		chain{&lt;br /&gt;
			lexer.lex_char(&amp;quot;/&amp;quot;), &lt;br /&gt;
			pparser.pathEltOrInverse,&lt;br /&gt;
		},&lt;br /&gt;
		chain{&lt;br /&gt;
			lexer.lex_char(&amp;quot;\^&amp;quot;), &lt;br /&gt;
			pparser.pathElt,&lt;br /&gt;
			function(state) &lt;br /&gt;
				state.node = path.InverseNode:create(state.node) &lt;br /&gt;
				return state&lt;br /&gt;
			end&lt;br /&gt;
		}&lt;br /&gt;
	},&lt;br /&gt;
	function(acc) return path.SequenceNode:create(acc) end&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Tests:&lt;br /&gt;
&lt;br /&gt;
plop=p.parse(&amp;quot;P31/P31+&amp;quot;,p.pathSequence) ; t = require &amp;quot;Module:Tools&amp;quot; ; t.dump_to_console(plop) &lt;br /&gt;
yes&lt;br /&gt;
nodes=&amp;gt;&lt;br /&gt;
   1=&amp;gt;&lt;br /&gt;
      property=&amp;gt;&lt;br /&gt;
         P31&lt;br /&gt;
   2=&amp;gt;&lt;br /&gt;
      node=&amp;gt;&lt;br /&gt;
         property=&amp;gt;&lt;br /&gt;
            P31&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- PathAlternative 	 ::= 	PathSequence ( &amp;#039;|&amp;#039; PathSequence )*&lt;br /&gt;
&lt;br /&gt;
pparser.pathAlternative = nary_op_parser(&lt;br /&gt;
	pparser.pathSequence,&lt;br /&gt;
	chain{&lt;br /&gt;
		lex_char(&amp;quot;[|]&amp;quot;), &lt;br /&gt;
		pparser.pathSequence&lt;br /&gt;
	},&lt;br /&gt;
	function(acc) return path.AlternativeNode:create(acc) end&lt;br /&gt;
)&lt;br /&gt;
	&lt;br /&gt;
--[[&lt;br /&gt;
plop=p.parse(&amp;quot;P31|P17/P279+&amp;quot;,p.pathAlternative) ; t = require &amp;quot;Module:Tools&amp;quot; ; t.dump_to_console(plop) &lt;br /&gt;
yes&lt;br /&gt;
nodes=&amp;gt;&lt;br /&gt;
   1=&amp;gt;&lt;br /&gt;
      property=&amp;gt;&lt;br /&gt;
         P31&lt;br /&gt;
   2=&amp;gt;&lt;br /&gt;
      nodes=&amp;gt;&lt;br /&gt;
         1=&amp;gt;&lt;br /&gt;
            property=&amp;gt;&lt;br /&gt;
               P17&lt;br /&gt;
         2=&amp;gt;&lt;br /&gt;
            node=&amp;gt;&lt;br /&gt;
               property=&amp;gt;&lt;br /&gt;
                  P279&lt;br /&gt;
                  &lt;br /&gt;
plop=p.parse(&amp;quot;P31|P17&amp;gt;P31/P279+&amp;quot;,p.pathAlternative) ; t = require &amp;quot;Module:Tools&amp;quot; ; t.dump_to_console(plop) &lt;br /&gt;
yes&lt;br /&gt;
nodes=&amp;gt;&lt;br /&gt;
   1=&amp;gt;&lt;br /&gt;
      property=&amp;gt;&lt;br /&gt;
         P31&lt;br /&gt;
   2=&amp;gt;&lt;br /&gt;
      nodes=&amp;gt;&lt;br /&gt;
         1=&amp;gt;&lt;br /&gt;
            property=&amp;gt;&lt;br /&gt;
               P31&lt;br /&gt;
            node=&amp;gt;&lt;br /&gt;
               P17&lt;br /&gt;
         2=&amp;gt;&lt;br /&gt;
            node=&amp;gt;&lt;br /&gt;
               property=&amp;gt;&lt;br /&gt;
                  P279&lt;br /&gt;
&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- PathSequence 	 ::= 	PathEltOrInverse ( &amp;#039;/&amp;#039; PathEltOrInverse | &amp;#039;^&amp;#039; PathElt )* &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local instance = function()&lt;br /&gt;
	-- P31/P279*&lt;br /&gt;
	return path.SequenceNode:create(&lt;br /&gt;
		{&lt;br /&gt;
			path.PropertyNode:create(&amp;quot;P31&amp;quot;),&lt;br /&gt;
			path.StarNode:create(path.PropertyNode:create(&amp;quot;P279&amp;quot;))&lt;br /&gt;
		}&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- PathPrimary 	 ::= ( Prop | &amp;#039;!&amp;#039;  NegatedPropertySet ) ( &amp;#039;&amp;gt;&amp;#039; ( Prop | &amp;#039;!&amp;#039;  NegatedPropertySet ) ) ? | &amp;#039;a&amp;#039; | &amp;#039;(&amp;#039; Path &amp;#039;)&amp;#039; &lt;br /&gt;
&lt;br /&gt;
pparser.pathPrimary = function(state)&lt;br /&gt;
	local node&lt;br /&gt;
	&lt;br /&gt;
	local res = alternative{&lt;br /&gt;
		chain{&lt;br /&gt;
			lex_char(&amp;#039;a&amp;#039;), &lt;br /&gt;
			lex_char(&amp;#039; &amp;#039;),&lt;br /&gt;
			idop(function(state) node = instance() end)&lt;br /&gt;
		},&lt;br /&gt;
		chain{&lt;br /&gt;
			chain{&lt;br /&gt;
				alternative{&lt;br /&gt;
					pparser.prop, &lt;br /&gt;
					chain {lex_char(&amp;#039;!&amp;#039;), pparser.negatedPropertySet}&lt;br /&gt;
				},&lt;br /&gt;
				idop(function(state) node = state.node end)&lt;br /&gt;
			},&lt;br /&gt;
			alternative{&lt;br /&gt;
				chain{&lt;br /&gt;
					pparser.pathQualifier,&lt;br /&gt;
					idop(&lt;br /&gt;
						function(state) &lt;br /&gt;
							node = path.QualifiedStatementNode:create(&lt;br /&gt;
								node,&lt;br /&gt;
								state.node&lt;br /&gt;
							)&lt;br /&gt;
						end&lt;br /&gt;
					)&lt;br /&gt;
				},&lt;br /&gt;
				parse_epsilon&lt;br /&gt;
			}&lt;br /&gt;
		},&lt;br /&gt;
		chain{&lt;br /&gt;
			lexer.open_parenthesis, &lt;br /&gt;
			pparser.path,&lt;br /&gt;
			idop(&lt;br /&gt;
				function(state) &lt;br /&gt;
					node = state.node &lt;br /&gt;
				end&lt;br /&gt;
			),&lt;br /&gt;
			lexer.close_parenthesis&lt;br /&gt;
		},&lt;br /&gt;
		chain{&lt;br /&gt;
			lexer.lex_char(&amp;#039;!&amp;#039;),&lt;br /&gt;
			pparser.negatedPropertySet,&lt;br /&gt;
			idop(&lt;br /&gt;
				function(state) &lt;br /&gt;
					node = state.node &lt;br /&gt;
				end&lt;br /&gt;
			)&lt;br /&gt;
		}&lt;br /&gt;
	}(state)&lt;br /&gt;
	if res then&lt;br /&gt;
		res.node = node&lt;br /&gt;
		return res&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Tests :&lt;br /&gt;
&lt;br /&gt;
p.parse(&amp;quot;a &amp;quot;, p.pathPrimary) =&amp;gt; yes&lt;br /&gt;
p.parse(&amp;quot;!P31&amp;quot;, p.pathPrimary) =&amp;gt; yes&lt;br /&gt;
p.parse(&amp;quot;!(P31|instance of)&amp;quot;, p.pathPrimary) =&amp;gt; yes&lt;br /&gt;
&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
-- stupid function to be eliminated soon (hum)&lt;br /&gt;
local function parsePropAndWrap(wrapper)&lt;br /&gt;
	return 	chain{ &lt;br /&gt;
				pparser.prop,&lt;br /&gt;
				function (state) &lt;br /&gt;
					&lt;br /&gt;
					local node = state.node&lt;br /&gt;
					local nodes = {}&lt;br /&gt;
					nodes[1] = {}&lt;br /&gt;
					nodes[1].node = node -- TODO: understand why this is needed instead of just &amp;quot;nodes[1] = node&amp;quot;&lt;br /&gt;
					state.node = wrapper(nodes) &lt;br /&gt;
					return state&lt;br /&gt;
				end&lt;br /&gt;
			}&lt;br /&gt;
end&lt;br /&gt;
		&lt;br /&gt;
pparser.pathPropertySetParser = function(final_node_creator)&lt;br /&gt;
    return function(state)&lt;br /&gt;
    	return chain{&lt;br /&gt;
			lexer.open_parenthesis,&lt;br /&gt;
			alternative{&lt;br /&gt;
				nary_op_parser(&lt;br /&gt;
					pparser.pathOneInPropertySet,&lt;br /&gt;
					chain{&lt;br /&gt;
						lexer.lex_char(&amp;quot;|&amp;quot;),&lt;br /&gt;
						pparser.pathOneInPropertySet&lt;br /&gt;
					},&lt;br /&gt;
					final_node_creator,&lt;br /&gt;
					function (node) &lt;br /&gt;
						&lt;br /&gt;
						local singlenodes = {}&lt;br /&gt;
						singlenodes[1] = node -- mmm&lt;br /&gt;
						-- singlenodes[1].node = node&lt;br /&gt;
						&lt;br /&gt;
						return final_node_creator(singlenodes)&lt;br /&gt;
					end&lt;br /&gt;
				),&lt;br /&gt;
				-- parsePropAndWrap(final_node_creator), -- case for &amp;quot;!(P31)&amp;quot; like patterns, naryopparser or something needs to be fixed to better handle this&lt;br /&gt;
													 -- here the solution for negation is to create a negated set with only one property.&lt;br /&gt;
				chain{&lt;br /&gt;
					parse_epsilon, &lt;br /&gt;
					function(state) &lt;br /&gt;
						state.node = final_node_creator({}) &lt;br /&gt;
						return state &lt;br /&gt;
					end&lt;br /&gt;
				} -- allows emty set (to mimic any qualifer allowed, equiv of «*»)&lt;br /&gt;
			},&lt;br /&gt;
			lexer.close_parenthesis&lt;br /&gt;
    	}(state)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
pparser.propOrSetParser = function(creator)&lt;br /&gt;
	return function(state)&lt;br /&gt;
		return alternative{&lt;br /&gt;
			parsePropAndWrap(creator), -- case for the pattern !P31 , in case it’s negated this stills need to be wrapped on a negated set &lt;br /&gt;
			pparser.pathPropertySetParser(function(nodes) return creator(nodes) end),&lt;br /&gt;
		}(state)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- &amp;#039;&amp;gt;&amp;#039; ( Prop | &amp;#039;!&amp;#039;  NegatedPropertySet | PropertySet )&lt;br /&gt;
pparser.pathQualifier = chain{&lt;br /&gt;
	lex_char(&amp;quot;&amp;gt;&amp;quot;),&lt;br /&gt;
	alternative{&lt;br /&gt;
		chain{&lt;br /&gt;
			lex_char(&amp;quot;!&amp;quot;),&lt;br /&gt;
			pparser.propOrSetParser(function(nodes) return path.NegatedPropertySetNode:create(nodes) end)&lt;br /&gt;
		},&lt;br /&gt;
		pparser.propOrSetParser(function(nodes) return path.PropertySetNode:create(nodes) end)&lt;br /&gt;
	},&lt;br /&gt;
	function(state) &lt;br /&gt;
		state.node = path.QualifierSnakNode:create(state.node)&lt;br /&gt;
		return state&lt;br /&gt;
	end&lt;br /&gt;
}&lt;br /&gt;
--[[&lt;br /&gt;
=p.parse(&amp;quot;&amp;gt;!(P31|P31)&amp;quot;,p.pathQualifier)&lt;br /&gt;
=p.parse(&amp;quot;&amp;gt;(P31|P31)&amp;quot;,p.pathQualifier)&lt;br /&gt;
=p.parse(&amp;quot;&amp;gt;P31&amp;quot;,p.pathQualifier)&lt;br /&gt;
=p.parse(&amp;quot;&amp;gt;!P31&amp;quot;,p.pathQualifier)&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
-- PathNegatedPropertySet	  ::=  	PathOneInPropertySet | &amp;#039;(&amp;#039; ( PathOneInPropertySet ( &amp;#039;|&amp;#039; PathOneInPropertySet )* )? &amp;#039;)&amp;#039;&lt;br /&gt;
&lt;br /&gt;
pparser.negatedPropertySet = pparser.pathPropertySetParser(&lt;br /&gt;
	function(nodes) &lt;br /&gt;
		return path.NegatedPropertySetNode:create(nodes) &lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Tests :&lt;br /&gt;
&lt;br /&gt;
p.parse(&amp;quot;!P31&amp;quot;,p.negatedPropertySet)&lt;br /&gt;
p.parse(&amp;quot;(P31|P32)&amp;quot;,p.negatedPropertySet) =&amp;gt; yes&lt;br /&gt;
p.parse(&amp;quot;P31&amp;quot;,p.negatedPropertySet) =&amp;gt; yes&lt;br /&gt;
p.parse(&amp;quot;^P31&amp;quot;,p.negatedPropertySet) =&amp;gt; yes&lt;br /&gt;
p.parse(&amp;quot;^(P31)&amp;quot;,p.negatedPropertySet) =&amp;gt; nope&lt;br /&gt;
p.parse(&amp;quot;(P31)&amp;quot;,p.negatedPropertySet) =&amp;gt; yes&lt;br /&gt;
p.parse(&amp;quot;(^P31)&amp;quot;,p.negatedPropertySet) =&amp;gt; yes&lt;br /&gt;
p.parse(&amp;quot;(^P31|a|plop)&amp;quot;,p.negatedPropertySet) =&amp;gt; yes&lt;br /&gt;
&lt;br /&gt;
All good(?)&lt;br /&gt;
&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
-- PathOneInPropertySet	  ::=  	iri | &amp;#039;a&amp;#039; | &amp;#039;^&amp;#039; ( iri | &amp;#039;a&amp;#039; ) &lt;br /&gt;
&lt;br /&gt;
pparser.pathOneInPropertySet = function(state)&lt;br /&gt;
	local node = {}&lt;br /&gt;
	&lt;br /&gt;
	local pElement = alternative{&lt;br /&gt;
		chain{&lt;br /&gt;
			lexer.lex_char(&amp;#039;a&amp;#039;),&lt;br /&gt;
			idop(function(state) elem = instance() end)&lt;br /&gt;
		},&lt;br /&gt;
		chain{&lt;br /&gt;
			pparser.prop,&lt;br /&gt;
			idop(function(state) elem = state.node end)&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	local res = alternative{&lt;br /&gt;
		chain{&lt;br /&gt;
			lexer.lex_char(&amp;quot;^&amp;quot;),&lt;br /&gt;
			pElement,&lt;br /&gt;
			idop(function(state) node = state.node end)&lt;br /&gt;
		},&lt;br /&gt;
		chain{&lt;br /&gt;
			pElement,&lt;br /&gt;
			idop(function(state) node = path.InverseNode:create(state.node) end)&lt;br /&gt;
		}&lt;br /&gt;
	}(state)&lt;br /&gt;
&lt;br /&gt;
	if res then res.node = node end&lt;br /&gt;
	return res&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
			&lt;br /&gt;
&lt;br /&gt;
-- Prop ::= IRIref | Pid | Pname&lt;br /&gt;
pparser.prop = function(state)&lt;br /&gt;
	local res = alternative{&lt;br /&gt;
		chain{&lt;br /&gt;
			parser.questionmark(&lt;br /&gt;
				chain{&lt;br /&gt;
					lex_sparql_prefix,&lt;br /&gt;
					lex_char(&amp;quot;:&amp;quot;)&lt;br /&gt;
				}&lt;br /&gt;
			),&lt;br /&gt;
			lex_pid&lt;br /&gt;
		},&lt;br /&gt;
		lex_property_name&lt;br /&gt;
	}(state)&lt;br /&gt;
&lt;br /&gt;
	if res then&lt;br /&gt;
		res.node = path.PropertyNode:create(res.lexed)&lt;br /&gt;
		return res&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
--[[&lt;br /&gt;
&lt;br /&gt;
Tests :&lt;br /&gt;
&lt;br /&gt;
p.parse(&amp;quot;a &amp;quot;, p.primary) =&amp;gt; yes&lt;br /&gt;
p.parse(&amp;quot;P31@&amp;quot;, p.prop) =&amp;gt; nope&lt;br /&gt;
p.parse(&amp;quot;P31&amp;quot;, p.prop) =&amp;gt; nope&lt;br /&gt;
p.parse(&amp;quot;P31&amp;gt;P279&amp;quot;, p.prop) =&amp;gt; nope&lt;br /&gt;
&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- PathFirstSequence      ::= &amp;#039;&amp;gt;&amp;#039; PathQualifier ( &amp;#039;/&amp;#039; PathEltOrInverse | &amp;#039;^&amp;#039; PathElt )* &lt;br /&gt;
pparser.pathFirstSequence = nary_op_parser(&lt;br /&gt;
--	chain{&lt;br /&gt;
		pparser.pathQualifier,&lt;br /&gt;
--		function(state)&lt;br /&gt;
--			state.node = path.QualifierSnakNode:create(state.node)&lt;br /&gt;
--			return state&lt;br /&gt;
--		end&lt;br /&gt;
--	},&lt;br /&gt;
	chain{&lt;br /&gt;
		lex_char(&amp;quot;/&amp;quot;),&lt;br /&gt;
		pparser.pathEltOrInverse&lt;br /&gt;
	},&lt;br /&gt;
	function (acc) &lt;br /&gt;
		return path.SequenceNode:create(acc) &lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
pparser.path = function(state)&lt;br /&gt;
	return pparser.pathAlternative(state)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- PathFirstAlternative   ::= PathFirstSequence ( &amp;#039;|&amp;#039; PathFirstSequence )* | Path&lt;br /&gt;
pparser.pathFirstAlternative = alternative{&lt;br /&gt;
	pparser.path,&lt;br /&gt;
	nary_op_parser(&lt;br /&gt;
		pparser.pathFirstSequence, &lt;br /&gt;
		chain{&lt;br /&gt;
			lex_char(&amp;quot;|&amp;quot;),&lt;br /&gt;
			pparser.pathFirstSequence&lt;br /&gt;
		},&lt;br /&gt;
		function(acc) return path.AlternativeNode:create(acc) end&lt;br /&gt;
	),&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- plop = p.parse_path(&amp;quot;P31/P31/P31&amp;gt;P31/P31&amp;quot;) &lt;br /&gt;
&lt;br /&gt;
pparser.parse_path = function (property_path)&lt;br /&gt;
	local res = parser.parse(property_path, pparser.pathFirstAlternative)&lt;br /&gt;
	assert(res, &amp;quot;parsing returned a nil obj on path : «&amp;quot; .. property_path .. &amp;quot;»&amp;quot;)&lt;br /&gt;
	return res&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- to test in console&lt;br /&gt;
pparser.parse = parser.parse&lt;br /&gt;
&lt;br /&gt;
return pparser&lt;/div&gt;</summary>
		<author><name>Jaggerwock</name></author>
	</entry>
</feed>