             let iriStrings = chars.elements().map { String($0) }.joined(separator: "").components(separatedBy: " ")
             let iris = iriStrings.map { Term(value: $0, type: .iri) }
             return .path(nodes[0], .nps(iris), nodes[1])
+        } else if op == "path" {
+            let parser = NTriplesPatternParser(reader: "")
+            let view = AnyIterator(rest.unicodeScalars.makeIterator())
+            var chars = PeekableIterator(generator: view)
+            guard let nodes = parser.parseNodes(chars: &chars, count: 2) else { return nil }
+            guard nodes.count == 2 else { return nil }
+            let rest = chars.elements().map { String($0) }.joined(separator: "").components(separatedBy: " ")
+            guard let pp = try parsePropertyPath(rest) else { throw QueryError.parseError("Failed to parse property path") }
+            return .path(nodes[0], pp, nodes[1])
         } else if op == "agg" { // (SUM(?skey) AS ?sresult) (AVG(?akey) AS ?aresult) ... GROUP BY ?x ?y ?z --> "agg sum sresult ?skey , avg aresult ?akey ; ?x , ?y , ?z"
             let pair = parts.suffix(from: 1).split(separator: ";")
             guard pair.count >= 1 else { throw QueryError.parseError("Bad syntax for agg operation") }

        return nil
    }
    
    public func parse() throws -> Algebra? {
        let lines = self.reader.lines()
        for line in lines {

    case inv(PropertyPath)
    case nps([Term])
    case alt(PropertyPath, PropertyPath)
    case seq(PropertyPath, PropertyPath)
}

public indirect enum Algebra {
