[
  {
    "path": ".gitignore",
    "content": "*.*~\n*.log\n*.aux\n*.beam\n*.dump\n*.tag.gz\n*.tgz\n_build/\ntests/\nrebar3\n*_leex.erl\n*_yeec.erl\n*.sublime-*\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: erlang\ndist: trusty\n\nscript:\n   - make\n   - make test\n   - ./rebar3 coveralls send\n\notp_release:\n   - 21.2\n   - 20.3\n   - 19.3\n   - 18.3\n\n"
  },
  {
    "path": "Emakefile",
    "content": "{\"src/*\", [\n   report, \n   verbose, \n   {i, \"include\"}, \n   {outdir, \"_build/default/lib/datalog/ebin\"},\n   debug_info \n]}.\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "##\n## @doc\n##   an example Makefile to build and ship erlang software\n##\n##   APP - identity of the application\n##   ORG - identity of the organization \n##   URI - identity of the docker repository with last /  \n\nAPP = datalog \nORG = fogfish\nURI = \n\ninclude erlang.mk\n"
  },
  {
    "path": "README.md",
    "content": "# datalog\n\nDatalog is a query language based on the logic programming paradigm. The library is designed to formalize relation of n-ary streams. It implements an ad-hoc query engine using simplified version of general _logic programming_ paradigm. The library facilitates development of data integration, information exchange and semantic web applications.\n\n[![Build Status](https://secure.travis-ci.org/fogfish/datalog.svg?branch=master)](http://travis-ci.org/fogfish/datalog)\n[![Coverage Status](https://coveralls.io/repos/github/fogfish/datalog/badge.svg?branch=master)](https://coveralls.io/github/fogfish/datalog?branch=master)\n[![Hex.pm](https://img.shields.io/hexpm/v/datalog.svg)](https://hex.pm/packages/datalog) \n[![Hex Downloads](https://img.shields.io/hexpm/dt/datalog.svg)](https://hex.pm/packages/datalog)\n\n## Key features\n\n* Top-down, sub-query, breath-first evaluation algorithm of logical program\n* Erlang native interface to describe relation of streams\n* Formalizes streams relation using human readable language\n* Supports conjunctions, unions and recursion\n\n### Background\n\nThe logic program consists of finite set of rules and large volume of ground facts -- knowledge. The rules are used to deduce new facts from other facts (built new relations). The [Horn clauses](https://en.wikipedia.org/wiki/Horn_clause) formally defines rules (first-order formula)\n\n```\np₀(ẋ₀) :- p₁(ẋ₁) ^ ... ^ pₙ(ẋₙ).\n```\n\n`p₀` is a rule head, it is a producer of new relation (facts). The body is a conjunction of predicates. Each `pᵢ` is a predicate expression consist of predicate symbol and terms such as `p(t₁ , ... , tₙ)`, terms are either a literal constant or a variable. The predicate expression refers to relation of arbitrary arity - stream of tuples; terms range over this stream of tuples. Body predicates refers either to derived relations or ground facts. The predicates with common variables give rise to join. Ground facts are physically stored in external memory and accesses using streams abstractions.\n\nA head is a new derived relation, deducted through the _logical program_ (body of horn clause) and ground facts. It is not explicitly persisted anywhere and corresponds the relation view (projection). The materialization of these view is the main task of this library.\n\nA naive example, a new relation `about` is deducted from two relations `category` and `article`.\n```\nabout(title, subject) :- category(x, subject), article(title, x).\n```\n\n### σ function\n\nThe library uses a \"functional\" interpretation of predicates, any predicate is a function -- sigma expression. It associates some of its bound terms to the remaining ones, returning the lazy set of tuples corresponding to materialized predicate. For example if p is binary predicate, its σ function is denoted as\n\n```\nσ(S) -> { ẋ ∈ S ^ p(ẋ) }\n```\n\nThe library translate goals of rules into algebraic queries with an objective to access the minimum of ground facts needed in order to determine the answer. Rules are compiled to composition of σ functions (sub-queries). They are recursively expanded and the evaluation of the current sub-query is postponed until the new sub-query has been completely solved. \n\nThe defined sigma expression formalism translates purely declarative semantic into operational semantic, i.e. specify of query must be executed. The lazy set ensures simplicity of one-tuple-at-a-time evaluation strategy while preserving efficiency of set-oriented methods used by high-level query languages. \n\nThe sigma function is the formalism to relate logic program to ground facts persisted by external storage (most common query languages, access methodologies, i/o interfaces). The library uses sigma algebra to evaluate logic program but it requires developers to implement corresponding access protocols supported by external storage. This is an abstraction interface to retrieve ground facts _matching_ predicate. The library hides the concerns of logical program evaluation but provides hooks to implement access protocols.\n\n\n## Getting started\n\nThe latest version of the library is available at its `master` branch. All development, including new features and bug fixes, take place on the `master` branch using forking and pull requests as described in contribution guidelines.\n\n### Installation\n\nThe stable library release is available via hex packages, add the library as dependency to `rebar.config`\n\n```erlang\n{deps, [{datalog}]}.\n``` \n\n### Usage\n\nThe library requires implementation of streaming interface to fetch a ground facts from external storage. It provides a [reference implementation](src/datalog_lists.erl) to deal with lists.\n\nLet's consider usage example of library using [movies dataset](priv/imdb.config) and human readable [datalog](doc/syntax.md).\n\nBuild library and run the development console\n\n```bash\nmake && make run\n```\n\nThe typical usage scenario **parse**, **compile** and **evaluate**.\n\n```erlang\n%% parse query\nQ = datalog:p(\"?- h(_, _). f(x,y). h(x,y) :- f(x,y), y > 1.\").\n\n%% compile query\nE = datalog:c(datalog_list, Q).\n\n%% evaluate query\nS = datalog:q(E, [{a, 1}, {b, 2}, {c, 3}]).\n\n%% [ \n%%   [b,2], [c,3] \n%% ]\nstream:list(S).\n```\n\nLet's consider a complex scenarios with a reference dataset about movies.\n\n```erlang\n{ok, Imdb} = file:consult(\"./priv/imdb.config\").\n```\n\n#### Basic queries\n\nMatch a person from dataset using query goals\n\n```erlang\n%%\n%% define a query goal to match a person with `name` equal to `Ridley Scott`.\n%% An identity rule is used to produce stream of tuples \nQ = \"?- h(_, \\\"name\\\", \\\"Ridley Scott\\\"). h(s, p, o) :- f(s, p, o).\".\n\n%%\n%% parse and compile a query into executable function\nF = datalog:c(datalog_list, datalog:p(Q)).\n\n%%\n%% apply the function to dataset and materialize a stream of tuple, it returns\n%% [\n%%    [<<\"urn:person:137\">>,<<\"name\">>,<<\"Ridley Scott\">>]\n%% ]\nstream:list(F(Imdb)).\n```\n\n#### Data patterns\n\nMatch a person from dataset using patterns: literals and guards\n\n```erlang\nQ = \"\n   ?- h(_, _). \n\n   f(s, p, o). \n\n   h(s, o) :- \n      f(s, \\\"name\\\", o), o = \\\"Ridley Scott\\\".\n\".\n\n%%\n%% [\n%%    [<<\"urn:person:137\">>,<<\"Ridley Scott\">>]\n%% ]\nF = datalog:c(datalog_list, datalog:p(Q)).\nstream:list(F(Imdb)).\n```\n\nDiscover all movies produces in 1987\n\n```erlang\nQ = \"\n   ?- h(_, _). \n\n   f(s, p, o). \n\n   h(s, title) :- \n      f(s, \\\"year\\\", 1987), \n      f(s, \\\"title\\\", title).\n\".\n\n%%\n%% [\n%%    [<<\"urn:movie:202\">>,<<\"Predator\">>],\n%%    [<<\"urn:movie:203\">>,<<\"Lethal Weapon\">>],\n%%    [<<\"urn:movie:204\">>,<<\"RoboCop\">>]\n%% ]\nF = datalog:c(datalog_list, datalog:p(Q)).\nstream:list(F(Imdb)).\n```\n\nDiscover all actors of \"Lethal Weapon\" movie.\n\n```erlang\nQ = \"\n   ?- h(_). \n\n   f(s, p, o). \n\n   h(name) :- \n      f(m, \\\"title\\\", \\\"Lethal Weapon\\\"), \n      f(m, \\\"cast\\\", p), \n      f(p, \\\"name\\\", name).\n\".\n\n%%\n%% [\n%%    [<<\"Mel Gibson\">>],\n%%    [<<\"Danny Glover\">>],\n%%    [<<\"Gary Busey\">>]\n%% ]\nF = datalog:c(datalog_list, datalog:p(Q)).\nstream:list(F(Imdb)).\n```\n\n#### Predicates\n\nDiscover all movies produced before 1984\n\n```erlang\nQ = \"\n   ?- h(_, _). \n\n   f(s, p, o).\n\n   h(title, year) :- \n      f(s, \\\"year\\\", year), \n      f(s, \\\"title\\\", title), \n      year < 1984.\n\".\n\n%%\n%% [\n%%    [<<\"First Blood\">>,1982],\n%%    [<<\"Alien\">>,1979],\n%%    [<<\"Mad Max\">>,1979],\n%%    [<<\"Mad Max 2\">>,1981]\n%% ]\nF = datalog:c(datalog_list, datalog:p(Q)).\nstream:list(F(Imdb)).\n```\n\n\n### Design custom σ function\n\nσ function is a partial application takes terms and side-effect environment, it returns a stream on tuples matching the terms pattern.\n\nAs an example, the following sigma function takes two terms (2-arity) and returns corresponding stream of tuples. The library uses list `[_]` as data structure for tuples. It allows efficiently bind deducted values to term variable. Thus, each sigma function return stream (lazy list) of lists.\n\n```erlang\nf(_, _, [X, Y]) ->\n   fun(Env) ->\n      stream:build(...)\n   end.\n```\n\nEach term takes one of the following types `undefined | [filter()] | literal()`:\n* `undefined` terms position corresponds to free variable, streams output at this \nposition will be bound to corresponding variable at datalog expression.\n* `[filter()]` defines acceptable range of term values\n* `literal()` defines exact matching of term at stream\n\n\n## Reference\n\n1. [What You Always Wanted to Know About Datalog (And Never Dared to Ask)](https://pdfs.semanticscholar.org/9374/f0da312f3ba77fa840071d68935a28cba364.pdf)\n1. [Theory of Relational Databases](http://www.cs.nott.ac.uk/~psznza/G53RDB07/rdb14.pdf)\n1. [Foundation of Database](https://wiki.epfl.ch/provenance2011/documents/foundations%20of%20databases-abiteboul-1995.pdf)\n1. [Recursive Programming in Datalog](http://infolab.stanford.edu/~ullman/dscb/dl-old.pdf)\n1. [Datalog and Recursive Query Processing](http://blogs.evergreen.edu/sosw/files/2014/04/Green-Vol5-DBS-017.pdf)\n1. http://ion.uwinnipeg.ca/~ychen2/journalpapers/StratifiedDB.pdf\n1. http://www.cs.toronto.edu/~drosu/csc343-l7-handout6.pdf\n\n\n## License\n\nCopyright 2014 Dmitry Kolesnikov\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.\n\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n"
  },
  {
    "path": "doc/syntax.md",
    "content": "# datalog syntax\n\n> Datalog is a declarative logic programming language that syntactically is a subset of Prolog. It is often used as a query language for deductive databases... Datalog is not Turing complete, and is thus used as a domain-specific language. Unlike in Prolog, Datalog queries on finite sets are guaranteed to terminate.\n> https://en.wikipedia.org/wiki/Datalog\n\nThis document depicts a datalog syntax supported by the library and it extensions that implements enhancement for Semantic Web and bindings with Erlang runtime.\n\nThe datalog program consist of finite set of rules and references to ground facts, which are stored in external memory. The rules are used to deduce new facts from other facts. It is important to understand: \n* there are no functions symbols in datalog, each predicate symbol refers to relation of arbitrary arity.\n* datalog has a purely declarative semantics - the order of clauses is irrelevant.\n\n## Rules\n\nThe [Horn clauses](https://en.wikipedia.org/wiki/Horn_clause) formally defines datalog rules (first-order formula)\n\n```\np₀(ẋ₀) :- p₁(ẋ₁), ... , pₙ(ẋₙ).\n```\n\n`p₀` is a rule head, which represents a newly derived relation, deducted through horn clauses evaluation. The body is a conjunction of predicates `p₁ , ... , pₙ`. Each predicate refers to either derived or ground relation of arity equals to `|ẋ|`. The language support primitive predicates using infix notation, e.g. equality predicate `x = 1`. \n\n`ẋ₀ , ... , ẋₙ` are vector of variables and constants. Every variable of `ẋ₀` must occur in `ẋ₁ , ... , ẋₙ` so that rule is range restricted. The predicates with common variables give rise to join of relations. Vector `|ẋ|` facilitates predicate to map a relation from domain Dⁿ to boolean values so that program is able to holds in each relation that obeys rules.\n\nA datalog program is a finite set of rules.\n\nExample of rules\n\n```\nh(x, z) :- a(x, y), b(y, z).\n```\n\n## Constants\n\nConstants are predicate terms that do not change its value during the evaluation of program. Constants facilitate in pattern matching of ground relations while evaluating a programs. The library uses [semantic types](https://github.com/fogfish/semantic/blob/master/doc/datatype.md) to express constants. The usage of semantic types improves ambiguous translations of string literals to type system used at external memory. \n\nData type | Syntax | Example\n--- | --- | ---\nxsd:anyURI |  `<.+>` | `<http://example.com/a>`\n|| `[a-zA-Z_@]+:[a-zA-Z_@]+` | `example:a`\nxsd:string | `\".*\"` | `\"example text\"`\n|| `\".*\"@en` | `\"example text\"@en`\nxsd:integer | `-?\\d+` | `123`\n|| `\"-?\\d+\"^^xsd:integer` | `\"123\"^^xsd:integer`\nxsd:decimal | `-?\\d+.\\d+` | `12.3`\n|| `\"-?\\d+.\\d+\"^^xsd:decimal` | `\"12.3\"^^xsd:decimal`\nxsd:boolean | `true\\|false` | `true`\nxsd:datetime | ISO8601 | `2007-04-05T14:30:00Z`\nxsd:date | ISO8601 | `2007-04-05`\nxsd:time | ISO8601 | `14:30:00Z`\nxsd:yearmonth | ISO8601 | `2007-04`\nxsd:monthdate | ISO8601 | `--04-05`\n\nThe library also implements container data types (tuples, maps, lists) usable as constants\n\nData type | Syntax | Example\n--- | --- | ---\nrdf:seq |  `( ... )` | `(154, 7623, 23)`\nrdf:map |  `{ ... }` | `{type:\"Point\", coordinates:[21.3, 60.2]}`\nrdf:list|  `[ ... ]` | `[1, \"a\", 3.2]`\n\n\nExample of constants\n\n```\nh(x) :- a(\"example\", x), b(x, 10.0).\nh(x) :- a(<http://example.com/a>, x), b(x, y), x = example:a.\n```\n\n## Variables\n\nVariable consists of all finite alphanumeric characters and digits beginning with an upper case letter, says datalog syntax. The library relaxes an upper case requirement for variables due to internal AST representation where variable becomes an atom. Variable are used to lift positional values of relation to a new one, and so on. The library support JSON-LD flavored syntax for variable name e.g. `@id`, `@type`.\n\nSometimes, you need to skip or ignore value of relation, use a black symbol (\\_) to mark unused positions. \n\nExample of variables\n\n```\nh(z) :- a(_, y), b(y, z).\nh(@id,z) :- a(@id, @type), b(@type, z).\n```\n\n## Predicates\n\n> In a logic programming view, the term “predicate” is used as synonym for “relation (name)”.\n\nLet's take an example `p₁(x₁ , ... , xₙ)`. `p₁` the name of relation, which is either correspond to ground truths one maintained by external storage or logical one derived while evaluating a program. `x₁ , ... , xₙ` terms either variable or constants.\n\n```\nactors(id, name).\nmovies(id, title, year, cast).\n\ncasting(title, name) :- movies(_, title, year, cast), actors(cast, name), year < 1984.\n```\n\nGround truths relation `actors` consists of tuples `(id, name)`, another ground truth relation `movies` is `(id, title, year, cast)`. The derived relation `casting` joins `movies` and `actors` relations and restricts `movies` to instance where `year` less then 1984. Values of `title` and `name` is lifted to derived relation.\n\n**Ground-truths** predicate provides reference to external memory and mapping of external tuples.  \n\n```\np( ... ).\n```\n\n**Derived relation**\n\n```\np( ... ) :- ... .\n```\n\n**Semantic Web** predicates are compact IRIs, its just annotates relations as an instance of a class (rdf:type), nothing more the syntax sugar. \n\n```\nschema:thing( ... ) :- foaf:person( ... foaf:name ), foaf:name > \"A\", foaf:name < \"B\".\n```\n\n**Native** predicates refers to ground truths relations implemented by Erlang functions. The syntax uses dot (.) to separate references to native modules and functions. \n\n```\nmodule.function( ... ).\n.function( ... ).\n``` \n\n**Built-in** are native predicates where module definition is by passed, they are implemented by the evaluator. \n\n```\n.unique( ... ) // a predicate ensures unique term(s) within the stream\n.flat( ... )   // a predicate flatmap identity of term(s) over stream\n.eq( ... )     // a predicate is a boolean predicates over stream terms\n.ne( ... )\n.lt( ... )\n.gt( ... )\n.le( ... )\n.ge( ... )\n``` \n\n**Infix** predicates, also know as guards, restricts terms of other relations. They always takes left argument a variable and right argument as constant.\n\n```\nx = 10\nx > 10\nx < 10\nx >= 10\nx =< 10\nx != 10\nx in (10, 20, 30)\n``` \n\n## Union\n\ndatalog supports union `a(X,Y) ⋁ b(X,Y)` by\n\n```\nh(X,Y) :- a(X,Y)\nh(X,Y) :- b(X,Y)\n```\n\n## Recursion\n\nThe following example computes the transitive closure of a graph.\n\n```\nt(x,y) :- g(x,y) \nt(x,y) :- g(x,z), t(z,y).\n```\n\nConsider the graph\n\n```\ng : (1, 2), (2, 3), (3, 4), (4, 5). \n```\n\nThen we have\n\n```\n0 -> t : (1, 2), (2, 3), (3, 4), (4, 5)\n1 -> t : (1, 3), (2, 4), (3, 5)\n2 -> t : (1, 4), (2, 5)\n3 -> t : (1, 5)\n```\n\nAn other example\n\n```\ng : (1, 2), (2, 3), (3, 2).\n\n0 -> t : (1, 2), (2, 3), (3, 2)\n1 -> t : (1, 3), (2, 2), (3, 3)\n```\n\n## Aggregations\n\nMany applications require the computation of various kinds of summary information over the data. Formally, an aggregate function is a mapping `ƒ` from bags (multi-sets) of domain values to domain values. The library offloads implementation of aggregations to sigma functions (external storage) but it provides a syntax to declare aggregation intent at ground truth predicates:\n\n```\np(id, count \"links\", category 10 \"subject\").\n```\n\n## Goal\n\nGoal defines a first rule.\n\n```\n?- h(_, _).\n?- h(\"example\", _).\n?- h/2.\n```\n\n## Semantic Web compatibility\n\nSemantic Web heavily uses IRIs as identifiers. IRIs defines subjects, predicates and sometimes objects. This library implements datalog syntax enhancement that supports absolute and compact IRIs inside queries either as constants or variables.\n\nIRIs as constants uses traditional syntax `<absolute IRI>` or `prefix:suffix`\n\n```\nh(x) :- p(x, <http://example.com/1>).\nh(x) :- p(x, foaf:name).\n```\n\nOnly compact IRIs are allowed as variable, they have to be prefixed by `'` character\n\n```\nh('rdf:id, 'foaf:name) :- p('rdf:id, 'foaf:name).\n```\n"
  },
  {
    "path": "erlang.mk",
    "content": "##\n## Copyright (C) 2012 Dmitry Kolesnikov\n##\n## This Makefile may be modified and distributed under the terms\n## of the MIT license.  See the LICENSE file for details.\n## https://github.com/fogfish/makefile\n##\n## @doc\n##   This makefile is the wrapper of rebar to build and ship erlang software\n##\n## @version 1.0.12\n.PHONY: all compile test unit clean distclean run console mock-up mock-rm benchmark release dist\n\nAPP := $(strip $(APP))\nORG := $(strip $(ORG))\nURI := $(strip $(URI))\n\n##\n## config\nPREFIX ?= /usr/local\nAPP    ?= $(notdir $(CURDIR))\nARCH    = $(shell uname -m)\nPLAT   ?= $(shell uname -s)\nVSN    ?= $(shell test -z \"`git status --porcelain`\" && git describe --tags --long | sed -e 's/-g[0-9a-f]*//' | sed -e 's/-0//' || echo \"`git describe --abbrev=0 --tags`-dev\")\nLATEST ?= latest\nREL     = ${APP}-${VSN}\nPKG     = ${REL}+${ARCH}.${PLAT}\nTEST   ?= tests\nCOOKIE ?= nocookie\nDOCKER ?= fogfish/erlang-alpine\nIID     = ${URI}${ORG}/${APP}\n\n## required tools\n##  - rebar version (no spaces at end)\n##  - path to basho benchmark \nREBAR  ?= 3.9.0\nBB      = ../basho_bench\n\n\n## erlang runtime configration flags\nROOT   = $(shell pwd)\nADDR   = localhost.localdomain\nEFLAGS = \\\n\t-name ${APP}@${ADDR} \\\n\t-setcookie ${COOKIE} \\\n\t-pa ${ROOT}/_build/default/lib/*/ebin \\\n\t-pa ${ROOT}/_build/default/lib/*/priv \\\n\t-pa ${ROOT}/rel \\\n\t-kernel inet_dist_listen_min 32100 \\\n\t-kernel inet_dist_listen_max 32199 \\\n\t+P 1000000 \\\n\t+K true +A 160 -sbt ts\n\n\n## erlang common test bootstrap\nBOOT_CT = \\\n   -module(test). \\\n   -export([run/1]). \\\n   run(Spec) -> \\\n      {ok, Test} = file:consult(Spec), \\\n      case lists:keymember(node, 1, Test) of \\\n         false -> \\\n            erlang:halt(element(2, ct:run_test([{spec, Spec}]))); \\\n         true  -> \\\n            ct_master:run(Spec), \\\n            erlang:halt(0) \\\n      end.\n\n\n## \nBUILDER = FROM ${DOCKER}\\nARG VERSION=\\nRUN mkdir ${APP}\\nCOPY . ${APP}/\\nRUN cd ${APP} && make VSN=\\x24{VERSION} && make release VSN=\\x24{VERSION}\\n\nSPAWNER = FROM ${DOCKER}\\nENV VERSION=${VSN}\\nRUN mkdir ${APP}\\nCOPY . ${APP}/\\nRUN cd ${APP} && make VSN=\\x24{VERSION} && make release VSN=\\x24{VERSION}\\nCMD sh -c 'cd ${APP} && make console VSN=\\x24{VERSION} RELX_REPLACE_OS_VARS=true ERL_NODE=${APP}'\\n\n\n## self extracting bundle archive\nBUNDLE_INIT = PREFIX=${PREFIX}\\nREL=${PREFIX}/${REL}\\nAPP=${APP}\\nVSN=${VSN}\\nLINE=`grep -a -n \"BUNDLE:$$\" $$0`\\nmkdir -p $${REL}\\ntail -n +$$(( $${LINE%%%%:*} + 1)) $$0 | gzip -vdc - | tar -C $${REL} -xvf - > /dev/null\\n\nBUNDLE_FREE = exit\\nBUNDLE:\\n\n\n\n#####################################################################\n##\n## build\n##\n#####################################################################\nall: rebar3 compile test\n\ncompile: rebar3\n\t@./rebar3 compile\n\n\n##\n## execute common test and terminate node\ntest:\n\t@./rebar3 ct --config=test/${TEST}.config --cover --verbose\n\t@./rebar3 cover\n\n# test: _build/test.beam\n#\t@mkdir -p /tmp/test/${APP}\n#\t@erl ${EFLAGS} -noshell -pa _build/ -pa test/ -run test run test/${TEST}.config\n#\t@F=`ls /tmp/test/${APP}/ct_run*/all.coverdata | tail -n 1` ;\\\n#\tcp $$F /tmp/test/${APP}/ct.coverdata\n#\n# _build/test.beam: _build/test.erl\n#\t@erlc -o _build $<\n#\n# _build/test.erl:\n#\t@mkdir -p _build && echo \"${BOOT_CT}\" > $@\n#\n\ntestclean:\n\t@rm -f  _build/test.beam\n\t@rm -f  _build/test.erl\n\t@rm -f  test/*.beam\n\t@rm -rf test.*-temp-data\n\t@rm -rf tests\n\n##\n## execute unit test\nunit: all\n\t@./rebar3 skip_deps=true eunit\n\n##\n## clean \nclean: testclean dockerclean\n\t-@./rebar3 clean\n\t@rm -Rf _build/builder\n\t@rm -Rf _build/default/rel\n\t@rm -rf log\n\t@rm -f  relx.config\n\t@rm -f  *.tar.gz\n\t@rm -f  *.bundle\n\ndistclean: clean\n\t-@make mock-rm\n\t-@make dist-rm\n\t-@rm -Rf _build\n\t-@rm rebar3\n\n#####################################################################\n##\n## debug\n##\n#####################################################################\nrun: \n\t@erl ${EFLAGS}\n\nconsole: ${PKG}.tar.gz\n\t@_build/default/rel/${APP}/bin/${APP} foreground\n\nmock-up: test/mock/docker-compose.yml\n\t@docker-compose -f $< up\n\nmock-rm: test/mock/docker-compose.yml\n\t-@docker-compose -f $< down --rmi all -v --remove-orphans\n\ndist-up: docker-compose.yml _build/spawner\n\t@docker-compose build\n\t@docker-compose -f $< up\n\ndist-rm: docker-compose.yml\n\t-@rm -f _build/spawner\n\t-@docker-compose -f $< down --rmi all -v --remove-orphans\t\n\nbenchmark:\n\t@echo \"==> benchmark: ${TEST}\" ;\\\n\t$(BB)/basho_bench -N bb@127.0.0.1 -C nocookie priv/${TEST}.benchmark ;\\\n\t$(BB)/priv/summary.r -i tests/current ;\\\n\topen tests/current/summary.png\n\n#####################################################################\n##\n## release \n##\n#####################################################################\nrelease: ${PKG}.tar.gz\n\n## assemble VM release\nifeq (${PLAT},$(shell uname -s))\n${PKG}.tar.gz: relx.config\n\t@./rebar3 tar -n ${APP} -v ${VSN} ;\\\n\tmv _build/default/rel/${APP}/${APP}-${VSN}.tar.gz $@ ;\\\n\techo \"==> tarball: $@\"\n\nrelx.config: rel/relx.config.src\n\t@cat $< | sed \"s/release/release, {'${APP}', \\\"${VSN}\\\"}/\" > $@ \nelse\n${PKG}.tar.gz: _build/builder\n\t@docker build --file=$< --force-rm=true --build-arg=\"VERSION=${VSN}\" --tag=build/${APP}:latest . ;\\\n\tI=`docker create build/${APP}:latest` ;\\\n\tdocker cp $$I:/${APP}/$@ $@ ;\\\n\tdocker rm -f $$I ;\\\n\tdocker rmi build/${APP}:latest ;\\\n\ttest -f $@ && echo \"==> tarball: $@\"\n\n_build/builder:\n\t@mkdir -p _build && echo \"${BUILDER}\" > $@\nendif\n\n## build docker image\ndocker: Dockerfile\n\tgit status --porcelain\n\ttest -z \"`git status --porcelain`\" || exit -1\n\tdocker build \\\n\t\t--build-arg APP=${APP} \\\n\t\t--build-arg VSN=${VSN} \\\n\t\t-t ${IID}:${VSN} -f $< .\n\tdocker tag ${IID}:${VSN} ${IID}:${LATEST}\n\ndockerclean:\n\t-@docker rmi -f ${IID}:${LATEST}\n\t-@docker rmi -f ${IID}:${VSN}\n\n_build/spawner:\n\t@mkdir -p _build && echo \"${SPAWNER}\" > $@\n\n\ndist: ${PKG}.tar.gz ${PKG}.bundle\n\n\n${PKG}.bundle: rel/bootstrap.sh\n\t@printf '${BUNDLE_INIT}' > $@ ;\\\n\tcat $<  >> $@ ;\\\n\tprintf  '${BUNDLE_FREE}' >> $@ ;\\\n\tcat  ${PKG}.tar.gz >> $@ ;\\\n\tchmod ugo+x $@ ;\\\n\techo \"==> bundle: $@\"\n\n\n#####################################################################\n##\n## dependencies\n##\n#####################################################################\nrebar3:\n\t@echo \"==> install rebar (${REBAR})\" ;\\\n\tcurl -L -O -s https://github.com/erlang/rebar3/releases/download/${REBAR}/rebar3 ;\\\n\tchmod +x $@\n\n"
  },
  {
    "path": "priv/imdb.config",
    "content": "{<<\"urn:person:100\">>, <<\"name\">>, <<\"James Cameron\">>}.\n{<<\"urn:person:100\">>, <<\"born\">>, <<\"1954-08-16\">>}.\n\n{<<\"urn:person:101\">>, <<\"name\">>, <<\"Arnold Schwarzenegger\">>}.\n{<<\"urn:person:101\">>, <<\"born\">>, <<\"1947-07-30\">>}.\n\n{<<\"urn:person:102\">>, <<\"name\">>, <<\"Linda Hamilton\">>}.\n{<<\"urn:person:102\">>, <<\"born\">>, <<\"1956-09-26\">>}.\n\n{<<\"urn:person:103\">>, <<\"name\">>, <<\"Michael Biehn\">>}.\n{<<\"urn:person:103\">>, <<\"born\">>, <<\"1956-07-31\">>}.\n\n{<<\"urn:person:104\">>, <<\"name\">>, <<\"Ted Kotcheff\">>}.\n{<<\"urn:person:104\">>, <<\"born\">>, <<\"1931-04-07\">>}.\n\n{<<\"urn:person:105\">>, <<\"name\">>, <<\"Sylvester Stallone\">>}.\n{<<\"urn:person:105\">>, <<\"born\">>, <<\"1946-07-06\">>}.\n\n{<<\"urn:person:106\">>, <<\"name\">>, <<\"Richard Crenna\">>}.\n{<<\"urn:person:106\">>, <<\"born\">>, <<\"1926-11-30\">>}.\n{<<\"urn:person:106\">>, <<\"death\">>, <<\"2003-01-17\">>}.\n\n{<<\"urn:person:107\">>, <<\"name\">>, <<\"Brian Dennehy\">>}.\n{<<\"urn:person:107\">>, <<\"born\">>, <<\"1938-07-09\">>}.\n\n{<<\"urn:person:108\">>, <<\"name\">>, <<\"John McTiernan\">>}.\n{<<\"urn:person:108\">>, <<\"born\">>, <<\"1951-01-08\">>}.\n\n{<<\"urn:person:109\">>, <<\"name\">>, <<\"Elpidia Carrillo\">>}.\n{<<\"urn:person:109\">>, <<\"born\">>, <<\"1961-08-16\">>}.\n\n{<<\"urn:person:110\">>, <<\"name\">>, <<\"Carl Weathers\">>}.\n{<<\"urn:person:110\">>, <<\"born\">>, <<\"1948-01-14\">>}.\n\n{<<\"urn:person:111\">>, <<\"name\">>, <<\"Richard Donner\">>}.\n{<<\"urn:person:111\">>, <<\"born\">>, <<\"1930-04-24\">>}.\n\n{<<\"urn:person:112\">>, <<\"name\">>, <<\"Mel Gibson\">>}.\n{<<\"urn:person:112\">>, <<\"born\">>, <<\"1956-01-03\">>}.\n\n{<<\"urn:person:113\">>, <<\"name\">>, <<\"Danny Glover\">>}.\n{<<\"urn:person:113\">>, <<\"born\">>, <<\"1946-07-22\">>}.\n\n{<<\"urn:person:114\">>, <<\"name\">>, <<\"Gary Busey\">>}.\n{<<\"urn:person:114\">>, <<\"born\">>, <<\"1944-07-29\">>}.\n\n{<<\"urn:person:115\">>, <<\"name\">>, <<\"Paul Verhoeven\">>}.\n{<<\"urn:person:115\">>, <<\"born\">>, <<\"1938-07-18\">>}.\n\n{<<\"urn:person:116\">>, <<\"name\">>, <<\"Peter Weller\">>}.\n{<<\"urn:person:116\">>, <<\"born\">>, <<\"1947-06-24\">>}.\n\n{<<\"urn:person:117\">>, <<\"name\">>, <<\"Nancy Allen\">>}.\n{<<\"urn:person:117\">>, <<\"born\">>, <<\"1950-06-24\">>}.\n\n{<<\"urn:person:118\">>, <<\"name\">>, <<\"Ronny Cox\">>}.\n{<<\"urn:person:118\">>, <<\"born\">>, <<\"1938-07-23\">>}.\n\n{<<\"urn:person:119\">>, <<\"name\">>, <<\"Mark L. Lester\">>}.\n{<<\"urn:person:119\">>, <<\"born\">>, <<\"1946-11-26\">>}.\n\n{<<\"urn:person:120\">>, <<\"name\">>, <<\"Rae Dawn Chong\">>}.\n{<<\"urn:person:120\">>, <<\"born\">>, <<\"1961-02-28\">>}.\n\n{<<\"urn:person:121\">>, <<\"name\">>, <<\"Alyssa Milano\">>}.\n{<<\"urn:person:121\">>, <<\"born\">>, <<\"1972-12-19\">>}.\n\n{<<\"urn:person:122\">>, <<\"name\">>, <<\"Bruce Willis\">>}.\n{<<\"urn:person:122\">>, <<\"born\">>, <<\"1955-03-19\">>}.\n\n{<<\"urn:person:123\">>, <<\"name\">>, <<\"Alan Rickman\">>}.\n{<<\"urn:person:123\">>, <<\"born\">>, <<\"1946-02-21\">>}.\n\n{<<\"urn:person:124\">>, <<\"name\">>, <<\"Alexander Godunov\">>}.\n{<<\"urn:person:124\">>, <<\"born\">>, <<\"1949-11-28\">>}.\n{<<\"urn:person:124\">>, <<\"death\">>, <<\"1995-05-18\">>}.\n\n{<<\"urn:person:125\">>, <<\"name\">>, <<\"Robert Patrick\">>}.\n{<<\"urn:person:125\">>, <<\"born\">>, <<\"1958-11-05\">>}.\n\n{<<\"urn:person:126\">>, <<\"name\">>, <<\"Edward Furlong\">>}.\n{<<\"urn:person:126\">>, <<\"born\">>, <<\"1977-08-02\">>}.\n\n{<<\"urn:person:127\">>, <<\"name\">>, <<\"Jonathan Mostow\">>}.\n{<<\"urn:person:127\">>, <<\"born\">>, <<\"1961-11-28\">>}.\n\n{<<\"urn:person:128\">>, <<\"name\">>, <<\"Nick Stahl\">>}.\n{<<\"urn:person:128\">>, <<\"born\">>, <<\"1979-12-05\">>}.\n\n{<<\"urn:person:129\">>, <<\"name\">>, <<\"Claire Danes\">>}.\n{<<\"urn:person:129\">>, <<\"born\">>, <<\"1979-04-12\">>}.\n\n{<<\"urn:person:130\">>, <<\"name\">>, <<\"George P. Cosmatos\">>}.\n{<<\"urn:person:130\">>, <<\"born\">>, <<\"1941-01-04\">>}.\n{<<\"urn:person:130\">>, <<\"death\">>, <<\"2005-04-19\">>}.\n\n{<<\"urn:person:131\">>, <<\"name\">>, <<\"Charles Napier\">>}.\n{<<\"urn:person:131\">>, <<\"born\">>, <<\"1936-04-12\">>}.\n{<<\"urn:person:131\">>, <<\"death\">>, <<\"2011-10-05\">>}.\n\n{<<\"urn:person:132\">>, <<\"name\">>, <<\"Peter MacDonald\">>}.\n\n{<<\"urn:person:133\">>, <<\"name\">>, <<\"Marc de Jonge\">>}.\n{<<\"urn:person:133\">>, <<\"born\">>, <<\"1949-02-16\">>}.\n{<<\"urn:person:133\">>, <<\"death\">>, <<\"1996-06-06\">>}.\n\n{<<\"urn:person:134\">>, <<\"name\">>, <<\"Stephen Hopkins\">>}.\n\n{<<\"urn:person:135\">>, <<\"name\">>, <<\"Ruben Blades\">>}.\n{<<\"urn:person:135\">>, <<\"born\">>, <<\"1948-07-16\">>}.\n\n{<<\"urn:person:136\">>, <<\"name\">>, <<\"Joe Pesci\">>}.\n{<<\"urn:person:136\">>, <<\"born\">>, <<\"1943-02-09\">>}.\n\n{<<\"urn:person:137\">>, <<\"name\">>, <<\"Ridley Scott\">>}.\n{<<\"urn:person:137\">>, <<\"born\">>, <<\"1937-11-30\">>}.\n\n{<<\"urn:person:138\">>, <<\"name\">>, <<\"Tom Skerritt\">>}.\n{<<\"urn:person:138\">>, <<\"born\">>, <<\"1933-08-25\">>}.\n\n{<<\"urn:person:139\">>, <<\"name\">>, <<\"Sigourney Weaver\">>}.\n{<<\"urn:person:139\">>, <<\"born\">>, <<\"1949-10-08\">>}.\n\n{<<\"urn:person:140\">>, <<\"name\">>, <<\"Veronica Cartwright\">>}.\n{<<\"urn:person:140\">>, <<\"born\">>, <<\"1949-04-20\">>}.\n\n{<<\"urn:person:141\">>, <<\"name\">>, <<\"Carrie Henn\">>}.\n\n{<<\"urn:person:142\">>, <<\"name\">>, <<\"George Miller\">>}.\n{<<\"urn:person:142\">>, <<\"born\">>, <<\"1945-03-03\">>}.\n\n{<<\"urn:person:143\">>, <<\"name\">>, <<\"Steve Bisley\">>}.\n{<<\"urn:person:143\">>, <<\"born\">>, <<\"1951-12-26\">>}.\n\n{<<\"urn:person:144\">>, <<\"name\">>, <<\"Joanne Samuel\">>}.\n\n{<<\"urn:person:145\">>, <<\"name\">>, <<\"Michael Preston\">>}.\n{<<\"urn:person:145\">>, <<\"born\">>, <<\"1938-05-14\">>}.\n\n{<<\"urn:person:146\">>, <<\"name\">>, <<\"Bruce Spence\">>}.\n{<<\"urn:person:146\">>, <<\"born\">>, <<\"1945-09-17\">>}.\n\n{<<\"urn:person:147\">>, <<\"name\">>, <<\"George Ogilvie\">>}.\n{<<\"urn:person:147\">>, <<\"born\">>, <<\"1931-03-05\">>}.\n\n{<<\"urn:person:148\">>, <<\"name\">>, <<\"Tina Turner\">>}.\n{<<\"urn:person:148\">>, <<\"born\">>, <<\"1939-11-26\">>}.\n\n{<<\"urn:person:149\">>, <<\"name\">>, <<\"Sophie Marceau\">>}.\n{<<\"urn:person:149\">>, <<\"born\">>, <<\"1966-11-17\">>}.\n\n{<<\"urn:movie:200\">>, <<\"title\">>, <<\"The Terminator\">>}.\n{<<\"urn:movie:200\">>, <<\"year\">>, 1984}.\n{<<\"urn:movie:200\">>, <<\"director\">>,<<\"urn:person:100\">>}.\n{<<\"urn:movie:200\">>, <<\"cast\">>, <<\"urn:person:101\">>}.\n{<<\"urn:movie:200\">>, <<\"cast\">>, <<\"urn:person:102\">>}.\n{<<\"urn:movie:200\">>, <<\"cast\">>, <<\"urn:person:103\">>}.\n{<<\"urn:movie:200\">>, <<\"sequel\">>, <<\"urn:movie:207\">>}.\n\n{<<\"urn:movie:201\">>, <<\"title\">>, <<\"First Blood\">>}.\n{<<\"urn:movie:201\">>, <<\"year\">>, 1982}.\n{<<\"urn:movie:201\">>, <<\"director\">>, <<\"urn:person:104\">>}.\n{<<\"urn:movie:201\">>, <<\"cast\">>, <<\"urn:person:105\">>}.\n{<<\"urn:movie:201\">>, <<\"cast\">>, <<\"urn:person:106\">>}.\n{<<\"urn:movie:201\">>, <<\"cast\">>, <<\"urn:person:107\">>}.\n{<<\"urn:movie:201\">>, <<\"sequel\">>, <<\"urn:movie:209\">>}.\n\n{<<\"urn:movie:202\">>, <<\"title\">>, <<\"Predator\">>}.\n{<<\"urn:movie:202\">>, <<\"year\">>, 1987}.\n{<<\"urn:movie:202\">>, <<\"director\">>, <<\"urn:person:108\">>}.\n{<<\"urn:movie:202\">>, <<\"cast\">>, <<\"urn:person:101\">>}.\n{<<\"urn:movie:202\">>, <<\"cast\">>, <<\"urn:person:109\">>}.\n{<<\"urn:movie:202\">>, <<\"cast\">>, <<\"urn:person:110\">>}.\n{<<\"urn:movie:202\">>, <<\"sequel\">>, <<\"urn:movie:211\">>}.\n\n{<<\"urn:movie:203\">>, <<\"title\">>, <<\"Lethal Weapon\">>}.\n{<<\"urn:movie:203\">>, <<\"year\">>, 1987}.\n{<<\"urn:movie:203\">>, <<\"director\">>, <<\"urn:person:111\">>}.\n{<<\"urn:movie:203\">>, <<\"cast\">>, <<\"urn:person:112\">>}.\n{<<\"urn:movie:203\">>, <<\"cast\">>, <<\"urn:person:113\">>}.\n{<<\"urn:movie:203\">>, <<\"cast\">>, <<\"urn:person:114\">>}.\n{<<\"urn:movie:203\">>, <<\"sequel\">>, <<\"urn:movie:212\">>}.\n\n{<<\"urn:movie:204\">>, <<\"title\">>, <<\"RoboCop\">>}.\n{<<\"urn:movie:204\">>, <<\"year\">>, 1987}.\n{<<\"urn:movie:204\">>, <<\"director\">>, <<\"urn:person:115\">>}.\n{<<\"urn:movie:204\">>, <<\"cast\">>, <<\"urn:person:116\">>}.\n{<<\"urn:movie:204\">>, <<\"cast\">>, <<\"urn:person:117\">>}.\n{<<\"urn:movie:204\">>, <<\"cast\">>, <<\"urn:person:118\">>}.\n\n{<<\"urn:movie:205\">>, <<\"title\">>, <<\"Commando\">>}.\n{<<\"urn:movie:205\">>, <<\"year\">>, 1985}.\n{<<\"urn:movie:205\">>, <<\"director\">>, <<\"urn:person:119\">>}.\n{<<\"urn:movie:205\">>, <<\"cast\">>, <<\"urn:person:101\">>}.\n{<<\"urn:movie:205\">>, <<\"cast\">>, <<\"urn:person:120\">>}.\n{<<\"urn:movie:205\">>, <<\"cast\">>, <<\"urn:person:121\">>}.\n\n{<<\"urn:movie:206\">>, <<\"title\">>, <<\"Die Hard\">>}.\n{<<\"urn:movie:206\">>, <<\"year\">>, 1988}.\n{<<\"urn:movie:206\">>, <<\"director\">>, <<\"urn:person:108\">>}.\n{<<\"urn:movie:206\">>, <<\"cast\">>, <<\"urn:person:122\">>}.\n{<<\"urn:movie:206\">>, <<\"cast\">>, <<\"urn:person:123\">>}.\n{<<\"urn:movie:206\">>, <<\"cast\">>, <<\"urn:person:124\">>}.\n\n{<<\"urn:movie:207\">>, <<\"title\">>, <<\"Terminator 2: Judgment Day\">>}.\n{<<\"urn:movie:207\">>, <<\"year\">>, 1991}.\n{<<\"urn:movie:207\">>, <<\"director\">>, <<\"urn:person:100\">>}.\n{<<\"urn:movie:207\">>, <<\"cast\">>, <<\"urn:person:101\">>}.\n{<<\"urn:movie:207\">>, <<\"cast\">>, <<\"urn:person:102\">>}.\n{<<\"urn:movie:207\">>, <<\"cast\">>, <<\"urn:person:125\">>}.\n{<<\"urn:movie:207\">>, <<\"cast\">>, <<\"urn:person:126\">>}.\n{<<\"urn:movie:207\">>, <<\"sequel\">>, <<\"urn:movie:208\">>}.\n\n{<<\"urn:movie:208\">>, <<\"title\">>, <<\"Terminator 3: Rise of the Machines\">>}.\n{<<\"urn:movie:208\">>, <<\"year\">>, 2003}.\n{<<\"urn:movie:208\">>, <<\"director\">>, <<\"urn:person:127\">>}.\n{<<\"urn:movie:208\">>, <<\"cast\">>, <<\"urn:person:101\">>}.\n{<<\"urn:movie:208\">>, <<\"cast\">>, <<\"urn:person:128\">>}.\n{<<\"urn:movie:208\">>, <<\"cast\">>, <<\"urn:person:129\">>}.\n\n{<<\"urn:movie:209\">>, <<\"title\">>, <<\"Rambo: First Blood Part II\">>}.\n{<<\"urn:movie:209\">>, <<\"year\">>, 1985}.\n{<<\"urn:movie:209\">>, <<\"director\">>, <<\"urn:person:130\">>}.\n{<<\"urn:movie:209\">>, <<\"cast\">>, <<\"urn:person:105\">>}.\n{<<\"urn:movie:209\">>, <<\"cast\">>, <<\"urn:person:106\">>}.\n{<<\"urn:movie:209\">>, <<\"cast\">>, <<\"urn:person:131\">>}.\n{<<\"urn:movie:209\">>, <<\"sequel\">>, <<\"urn:movie:210\">>}.\n\n{<<\"urn:movie:210\">>, <<\"title\">>, <<\"Rambo III\">>}.\n{<<\"urn:movie:210\">>, <<\"year\">>, 1988}.\n{<<\"urn:movie:210\">>, <<\"director\">>, <<\"urn:person:132\">>}.\n{<<\"urn:movie:210\">>, <<\"cast\">>, <<\"urn:person:105\">>}.\n{<<\"urn:movie:210\">>, <<\"cast\">>, <<\"urn:person:106\">>}.\n{<<\"urn:movie:210\">>, <<\"cast\">>, <<\"urn:person:133\">>}.\n\n{<<\"urn:movie:211\">>, <<\"title\">>, <<\"Predator 2\">>}.\n{<<\"urn:movie:211\">>, <<\"year\">>, 1990}.\n{<<\"urn:movie:211\">>, <<\"director\">>, <<\"urn:person:134\">>}.\n{<<\"urn:movie:211\">>, <<\"cast\">>, <<\"urn:person:113\">>}.\n{<<\"urn:movie:211\">>, <<\"cast\">>, <<\"urn:person:114\">>}.\n{<<\"urn:movie:211\">>, <<\"cast\">>, <<\"urn:person:135\">>}.\n\n{<<\"urn:movie:212\">>, <<\"title\">>, <<\"Lethal Weapon 2\">>}.\n{<<\"urn:movie:212\">>, <<\"year\">>, 1989}.\n{<<\"urn:movie:212\">>, <<\"director\">>, <<\"urn:person:111\">>}.\n{<<\"urn:movie:212\">>, <<\"cast\">>, <<\"urn:person:112\">>}.\n{<<\"urn:movie:212\">>, <<\"cast\">>, <<\"urn:person:113\">>}.\n{<<\"urn:movie:212\">>, <<\"cast\">>, <<\"urn:person:136\">>}.\n{<<\"urn:movie:212\">>, <<\"sequel\">>, <<\"urn:movie:213\">>}.\n\n{<<\"urn:movie:213\">>, <<\"title\">>, <<\"Lethal Weapon 3\">>}.\n{<<\"urn:movie:213\">>, <<\"year\">>, 1992}.\n{<<\"urn:movie:213\">>, <<\"director\">>, <<\"urn:person:111\">>}.\n{<<\"urn:movie:213\">>, <<\"cast\">>, <<\"urn:person:112\">>}.\n{<<\"urn:movie:213\">>, <<\"cast\">>, <<\"urn:person:113\">>}.\n{<<\"urn:movie:213\">>, <<\"cast\">>, <<\"urn:person:136\">>}.\n\n{<<\"urn:movie:214\">>, <<\"title\">>, <<\"Alien\">>}.\n{<<\"urn:movie:214\">>, <<\"year\">>, 1979}.\n{<<\"urn:movie:214\">>, <<\"director\">>, <<\"urn:person:137\">>}.\n{<<\"urn:movie:214\">>, <<\"cast\">>, <<\"urn:person:138\">>}.\n{<<\"urn:movie:214\">>, <<\"cast\">>, <<\"urn:person:139\">>}.\n{<<\"urn:movie:214\">>, <<\"cast\">>, <<\"urn:person:140\">>}.\n{<<\"urn:movie:214\">>, <<\"sequel\">>, <<\"urn:movie:215\">>}.\n\n{<<\"urn:movie:215\">>, <<\"title\">>, <<\"Aliens\">>}.\n{<<\"urn:movie:215\">>, <<\"year\">>, 1986}.\n{<<\"urn:movie:215\">>, <<\"director\">>, <<\"urn:person:100\">>}.\n{<<\"urn:movie:215\">>, <<\"cast\">>, <<\"urn:person:139\">>}.\n{<<\"urn:movie:215\">>, <<\"cast\">>, <<\"urn:person:141\">>}.\n{<<\"urn:movie:215\">>, <<\"cast\">>, <<\"urn:person:103\">>}.\n\n{<<\"urn:movie:216\">>, <<\"title\">>, <<\"Mad Max\">>}.\n{<<\"urn:movie:216\">>, <<\"year\">>, 1979}.\n{<<\"urn:movie:216\">>, <<\"director\">>, <<\"urn:person:142\">>}.\n{<<\"urn:movie:216\">>, <<\"cast\">>, <<\"urn:person:112\">>}.\n{<<\"urn:movie:216\">>, <<\"cast\">>, <<\"urn:person:143\">>}.\n{<<\"urn:movie:216\">>, <<\"cast\">>, <<\"urn:person:144\">>}.\n{<<\"urn:movie:216\">>, <<\"sequel\">>, <<\"urn:movie:217\">>}.\n\n{<<\"urn:movie:217\">>, <<\"title\">>, <<\"Mad Max 2\">>}.\n{<<\"urn:movie:217\">>, <<\"year\">>, 1981}.\n{<<\"urn:movie:217\">>, <<\"director\">>, <<\"urn:person:142\">>}.\n{<<\"urn:movie:217\">>, <<\"cast\">>, <<\"urn:person:112\">>}.\n{<<\"urn:movie:217\">>, <<\"cast\">>, <<\"urn:person:145\">>}.\n{<<\"urn:movie:217\">>, <<\"cast\">>, <<\"urn:person:146\">>}.\n{<<\"urn:movie:217\">>, <<\"sequel\">>, <<\"urn:movie:218\">>}.\n\n{<<\"urn:movie:218\">>, <<\"title\">>, <<\"Mad Max Beyond Thunderdome\">>}.\n{<<\"urn:movie:218\">>, <<\"year\">>, 1985}.\n{<<\"urn:movie:218\">>, <<\"director\">>, <<\"urn:person:142\">>}.\n{<<\"urn:movie:218\">>, <<\"director\">>, <<\"urn:person:147\">>}.\n{<<\"urn:movie:218\">>, <<\"cast\">>, <<\"urn:person:112\">>}.\n{<<\"urn:movie:218\">>, <<\"cast\">>, <<\"urn:person:148\">>}.\n\n{<<\"urn:movie:219\">>, <<\"title\">>, <<\"Braveheart\">>}.\n{<<\"urn:movie:219\">>, <<\"year\">>, 1995}.\n{<<\"urn:movie:219\">>, <<\"director\">>, <<\"urn:person:112\">>}.\n{<<\"urn:movie:219\">>, <<\"cast\">>, <<\"urn:person:112\">>}.\n{<<\"urn:movie:219\">>, <<\"cast\">>, <<\"urn:person:149\">>}.\n"
  },
  {
    "path": "priv/imdb.nt",
    "content": "<http://example.org/person/100> <http://schema.org/name> \"James Cameron\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/100> <http://schema.org/born> \"1954-08-16\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/101> <http://schema.org/name> \"Arnold Schwarzenegger\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/101> <http://schema.org/born> \"1947-07-30\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/102> <http://schema.org/name> \"Linda Hamilton\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/102> <http://schema.org/born> \"1956-09-26\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/103> <http://schema.org/name> \"Michael Biehn\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/103> <http://schema.org/born> \"1956-07-31\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/104> <http://schema.org/name> \"Ted Kotcheff\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/104> <http://schema.org/born> \"1931-04-07\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/105> <http://schema.org/name> \"Sylvester Stallone\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/105> <http://schema.org/born> \"1946-07-06\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/106> <http://schema.org/name> \"Richard Crenna\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/106> <http://schema.org/born> \"1926-11-30\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/106> <http://schema.org/death> \"2003-01-17\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/107> <http://schema.org/name> \"Brian Dennehy\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/107> <http://schema.org/born> \"1938-07-09\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/108> <http://schema.org/name> \"John McTiernan\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/108> <http://schema.org/born> \"1951-01-08\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/109> <http://schema.org/name> \"Elpidia Carrillo\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/109> <http://schema.org/born> \"1961-08-16\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/110> <http://schema.org/name> \"Carl Weathers\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/110> <http://schema.org/born> \"1948-01-14\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/111> <http://schema.org/name> \"Richard Donner\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/111> <http://schema.org/born> \"1930-04-24\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/112> <http://schema.org/name> \"Mel Gibson\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/112> <http://schema.org/born> \"1956-01-03\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/113> <http://schema.org/name> \"Danny Glover\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/113> <http://schema.org/born> \"1946-07-22\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/114> <http://schema.org/name> \"Gary Busey\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/114> <http://schema.org/born> \"1944-07-29\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/115> <http://schema.org/name> \"Paul Verhoeven\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/115> <http://schema.org/born> \"1938-07-18\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/116> <http://schema.org/name> \"Peter Weller\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/116> <http://schema.org/born> \"1947-06-24\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/117> <http://schema.org/name> \"Nancy Allen\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/117> <http://schema.org/born> \"1950-06-24\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/118> <http://schema.org/name> \"Ronny Cox\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/118> <http://schema.org/born> \"1938-07-23\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/119> <http://schema.org/name> \"Mark L. Lester\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/119> <http://schema.org/born> \"1946-11-26\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/120> <http://schema.org/name> \"Rae Dawn Chong\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/120> <http://schema.org/born> \"1961-02-28\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/121> <http://schema.org/name> \"Alyssa Milano\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/121> <http://schema.org/born> \"1972-12-19\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/122> <http://schema.org/name> \"Bruce Willis\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/122> <http://schema.org/born> \"1955-03-19\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/123> <http://schema.org/name> \"Alan Rickman\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/123> <http://schema.org/born> \"1946-02-21\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/124> <http://schema.org/name> \"Alexander Godunov\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/124> <http://schema.org/born> \"1949-11-28\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/124> <http://schema.org/death> \"1995-05-18\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/125> <http://schema.org/name> \"Robert Patrick\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/125> <http://schema.org/born> \"1958-11-05\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/126> <http://schema.org/name> \"Edward Furlong\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/126> <http://schema.org/born> \"1977-08-02\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/127> <http://schema.org/name> \"Jonathan Mostow\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/127> <http://schema.org/born> \"1961-11-28\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/128> <http://schema.org/name> \"Nick Stahl\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/128> <http://schema.org/born> \"1979-12-05\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/129> <http://schema.org/name> \"Claire Danes\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/129> <http://schema.org/born> \"1979-04-12\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/130> <http://schema.org/name> \"George P. Cosmatos\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/130> <http://schema.org/born> \"1941-01-04\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/130> <http://schema.org/death> \"2005-04-19\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/131> <http://schema.org/name> \"Charles Napier\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/131> <http://schema.org/born> \"1936-04-12\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/131> <http://schema.org/death> \"2011-10-05\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/132> <http://schema.org/name> \"Peter MacDonald\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/133> <http://schema.org/name> \"Marc de Jonge\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/133> <http://schema.org/born> \"1949-02-16\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/133> <http://schema.org/death> \"1996-06-06\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/134> <http://schema.org/name> \"Stephen Hopkins\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/135> <http://schema.org/name> \"Ruben Blades\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/135> <http://schema.org/born> \"1948-07-16\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/136> <http://schema.org/name> \"Joe Pesci\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/136> <http://schema.org/born> \"1943-02-09\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/137> <http://schema.org/name> \"Ridley Scott\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/137> <http://schema.org/born> \"1937-11-30\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/138> <http://schema.org/name> \"Tom Skerritt\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/138> <http://schema.org/born> \"1933-08-25\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/139> <http://schema.org/name> \"Sigourney Weaver\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/139> <http://schema.org/born> \"1949-10-08\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/140> <http://schema.org/name> \"Veronica Cartwright\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/140> <http://schema.org/born> \"1949-04-20\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/141> <http://schema.org/name> \"Carrie Henn\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/142> <http://schema.org/name> \"George Miller\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/142> <http://schema.org/born> \"1945-03-03\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/143> <http://schema.org/name> \"Steve Bisley\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/143> <http://schema.org/born> \"1951-12-26\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/144> <http://schema.org/name> \"Joanne Samuel\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/145> <http://schema.org/name> \"Michael Preston\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/145> <http://schema.org/born> \"1938-05-14\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/146> <http://schema.org/name> \"Bruce Spence\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/146> <http://schema.org/born> \"1945-09-17\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/147> <http://schema.org/name> \"George Ogilvie\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/147> <http://schema.org/born> \"1931-03-05\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/148> <http://schema.org/name> \"Tina Turner\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/148> <http://schema.org/born> \"1939-11-26\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/person/149> <http://schema.org/name> \"Sophie Marceau\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/person/149> <http://schema.org/born> \"1966-11-17\"^^<http://www.w3.org/2001/XMLSchema#string> .\n\n<http://example.org/movie/200> <http://schema.org/title> \"The Terminator\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/200> <http://schema.org/year> \"1984\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/200> <http://schema.org/director> <http://example.org/person/100> .\n<http://example.org/movie/200> <http://schema.org/cast> <http://example.org/person/101> .\n<http://example.org/movie/200> <http://schema.org/cast> <http://example.org/person/102> .\n<http://example.org/movie/200> <http://schema.org/cast> <http://example.org/person/103> .\n<http://example.org/movie/200> <http://schema.org/sequel> <http://example.org/movie/207> .\n\n<http://example.org/movie/201> <http://schema.org/title> \"First Blood\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/201> <http://schema.org/year> \"1982\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/201> <http://schema.org/director> <http://example.org/person/104> .\n<http://example.org/movie/201> <http://schema.org/cast> <http://example.org/person/105> .\n<http://example.org/movie/201> <http://schema.org/cast> <http://example.org/person/106> .\n<http://example.org/movie/201> <http://schema.org/cast> <http://example.org/person/107> .\n<http://example.org/movie/201> <http://schema.org/sequel> <http://example.org/movie/209> .\n\n<http://example.org/movie/202> <http://schema.org/title> \"Predator\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/202> <http://schema.org/year> \"1987\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/202> <http://schema.org/director> <http://example.org/person/108> .\n<http://example.org/movie/202> <http://schema.org/cast> <http://example.org/person/101> .\n<http://example.org/movie/202> <http://schema.org/cast> <http://example.org/person/109> .\n<http://example.org/movie/202> <http://schema.org/cast> <http://example.org/person/110> .\n<http://example.org/movie/202> <http://schema.org/sequel> <http://example.org/movie/211> .\n\n<http://example.org/movie/203> <http://schema.org/title> \"Lethal Weapon\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/203> <http://schema.org/year> \"1987\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/203> <http://schema.org/director> <http://example.org/person/111> .\n<http://example.org/movie/203> <http://schema.org/cast> <http://example.org/person/112> .\n<http://example.org/movie/203> <http://schema.org/cast> <http://example.org/person/113> .\n<http://example.org/movie/203> <http://schema.org/cast> <http://example.org/person/114> .\n<http://example.org/movie/203> <http://schema.org/sequel> <http://example.org/movie/212> .\n\n<http://example.org/movie/204> <http://schema.org/title> \"RoboCop\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/204> <http://schema.org/year> \"1987\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/204> <http://schema.org/director> <http://example.org/person/115> .\n<http://example.org/movie/204> <http://schema.org/cast> <http://example.org/person/116> .\n<http://example.org/movie/204> <http://schema.org/cast> <http://example.org/person/117> .\n<http://example.org/movie/204> <http://schema.org/cast> <http://example.org/person/118> .\n\n<http://example.org/movie/205> <http://schema.org/title> \"Commando\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/205> <http://schema.org/year> \"1985\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/205> <http://schema.org/director> <http://example.org/person/119> .\n<http://example.org/movie/205> <http://schema.org/cast> <http://example.org/person/101> .\n<http://example.org/movie/205> <http://schema.org/cast> <http://example.org/person/120> .\n<http://example.org/movie/205> <http://schema.org/cast> <http://example.org/person/121> .\n\n<http://example.org/movie/206> <http://schema.org/title> \"Die Hard\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/206> <http://schema.org/year> \"1988\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/206> <http://schema.org/director> <http://example.org/person/108> .\n<http://example.org/movie/206> <http://schema.org/cast> <http://example.org/person/122> .\n<http://example.org/movie/206> <http://schema.org/cast> <http://example.org/person/123> .\n<http://example.org/movie/206> <http://schema.org/cast> <http://example.org/person/124> .\n\n<http://example.org/movie/207> <http://schema.org/title> \"Terminator 2: Judgment Day\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/207> <http://schema.org/year> \"1991\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/207> <http://schema.org/director> <http://example.org/person/100> .\n<http://example.org/movie/207> <http://schema.org/cast> <http://example.org/person/101> .\n<http://example.org/movie/207> <http://schema.org/cast> <http://example.org/person/102> .\n<http://example.org/movie/207> <http://schema.org/cast> <http://example.org/person/125> .\n<http://example.org/movie/207> <http://schema.org/cast> <http://example.org/person/126> .\n<http://example.org/movie/207> <http://schema.org/sequel> <http://example.org/movie/208> .\n\n<http://example.org/movie/208> <http://schema.org/title> \"Terminator 3: Rise of the Machines\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/208> <http://schema.org/year> \"2003\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/208> <http://schema.org/director> <http://example.org/person/127> .\n<http://example.org/movie/208> <http://schema.org/cast> <http://example.org/person/101> .\n<http://example.org/movie/208> <http://schema.org/cast> <http://example.org/person/128> .\n<http://example.org/movie/208> <http://schema.org/cast> <http://example.org/person/129> .\n\n<http://example.org/movie/209> <http://schema.org/title> \"Rambo: First Blood Part II\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/209> <http://schema.org/year> \"1985\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/209> <http://schema.org/director> <http://example.org/person/130> .\n<http://example.org/movie/209> <http://schema.org/cast> <http://example.org/person/105> .\n<http://example.org/movie/209> <http://schema.org/cast> <http://example.org/person/106> .\n<http://example.org/movie/209> <http://schema.org/cast> <http://example.org/person/131> .\n<http://example.org/movie/209> <http://schema.org/sequel> <http://example.org/movie/210> .\n\n<http://example.org/movie/210> <http://schema.org/title> \"Rambo III\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/210> <http://schema.org/year> \"1988\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/210> <http://schema.org/director> <http://example.org/person/132> .\n<http://example.org/movie/210> <http://schema.org/cast> <http://example.org/person/105> .\n<http://example.org/movie/210> <http://schema.org/cast> <http://example.org/person/106> .\n<http://example.org/movie/210> <http://schema.org/cast> <http://example.org/person/133> .\n\n<http://example.org/movie/211> <http://schema.org/title> \"Predator 2\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/211> <http://schema.org/year> \"1990\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/211> <http://schema.org/director> <http://example.org/person/134> .\n<http://example.org/movie/211> <http://schema.org/cast> <http://example.org/person/113> .\n<http://example.org/movie/211> <http://schema.org/cast> <http://example.org/person/114> .\n<http://example.org/movie/211> <http://schema.org/cast> <http://example.org/person/135> .\n\n<http://example.org/movie/212> <http://schema.org/title> \"Lethal Weapon 2\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/212> <http://schema.org/year> \"1989\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/212> <http://schema.org/director> <http://example.org/person/111> .\n<http://example.org/movie/212> <http://schema.org/cast> <http://example.org/person/112> .\n<http://example.org/movie/212> <http://schema.org/cast> <http://example.org/person/113> .\n<http://example.org/movie/212> <http://schema.org/cast> <http://example.org/person/136> .\n<http://example.org/movie/212> <http://schema.org/sequel> <http://example.org/movie/213> .\n\n<http://example.org/movie/213> <http://schema.org/title> \"Lethal Weapon 3\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/213> <http://schema.org/year> \"1992\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/213> <http://schema.org/director> <http://example.org/person/111> .\n<http://example.org/movie/213> <http://schema.org/cast> <http://example.org/person/112> .\n<http://example.org/movie/213> <http://schema.org/cast> <http://example.org/person/113> .\n<http://example.org/movie/213> <http://schema.org/cast> <http://example.org/person/136> .\n\n<http://example.org/movie/214> <http://schema.org/title> \"Alien\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/214> <http://schema.org/year> \"1979\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/214> <http://schema.org/director> <http://example.org/person/137> .\n<http://example.org/movie/214> <http://schema.org/cast> <http://example.org/person/138> .\n<http://example.org/movie/214> <http://schema.org/cast> <http://example.org/person/139> .\n<http://example.org/movie/214> <http://schema.org/cast> <http://example.org/person/140> .\n<http://example.org/movie/214> <http://schema.org/sequel> <http://example.org/movie/215> .\n\n<http://example.org/movie/215> <http://schema.org/title> \"Aliens\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/215> <http://schema.org/year> \"1986\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/215> <http://schema.org/director> <http://example.org/person/100> .\n<http://example.org/movie/215> <http://schema.org/cast> <http://example.org/person/139> .\n<http://example.org/movie/215> <http://schema.org/cast> <http://example.org/person/141> .\n<http://example.org/movie/215> <http://schema.org/cast> <http://example.org/person/103> .\n\n<http://example.org/movie/216> <http://schema.org/title> \"Mad Max\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/216> <http://schema.org/year> \"1979\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/216> <http://schema.org/director> <http://example.org/person/142> .\n<http://example.org/movie/216> <http://schema.org/cast> <http://example.org/person/112> .\n<http://example.org/movie/216> <http://schema.org/cast> <http://example.org/person/143> .\n<http://example.org/movie/216> <http://schema.org/cast> <http://example.org/person/144> .\n<http://example.org/movie/216> <http://schema.org/sequel> <http://example.org/movie/217> .\n\n<http://example.org/movie/217> <http://schema.org/title> \"Mad Max 2\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/217> <http://schema.org/year> \"1981\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/217> <http://schema.org/director> <http://example.org/person/142> .\n<http://example.org/movie/217> <http://schema.org/cast> <http://example.org/person/112> .\n<http://example.org/movie/217> <http://schema.org/cast> <http://example.org/person/145> .\n<http://example.org/movie/217> <http://schema.org/cast> <http://example.org/person/146> .\n<http://example.org/movie/217> <http://schema.org/sequel> <http://example.org/movie/218> .\n\n<http://example.org/movie/218> <http://schema.org/title> \"Mad Max Beyond Thunderdome\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/218> <http://schema.org/year> \"1985\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/218> <http://schema.org/director> <http://example.org/person/142> .\n<http://example.org/movie/218> <http://schema.org/director> <http://example.org/person/147> .\n<http://example.org/movie/218> <http://schema.org/cast> <http://example.org/person/112> .\n<http://example.org/movie/218> <http://schema.org/cast> <http://example.org/person/148> .\n\n<http://example.org/movie/219> <http://schema.org/title> \"Braveheart\"^^<http://www.w3.org/2001/XMLSchema#string> .\n<http://example.org/movie/219> <http://schema.org/year> \"1995\"^^<http://www.w3.org/2001/XMLSchema#integer> .\n<http://example.org/movie/219> <http://schema.org/director> <http://example.org/person/112> .\n<http://example.org/movie/219> <http://schema.org/cast> <http://example.org/person/112> .\n<http://example.org/movie/219> <http://schema.org/cast> <http://example.org/person/149> .\n"
  },
  {
    "path": "rebar.config",
    "content": "{erl_opts, [\n]}.\n\n{deps, [\n   datum\n]}.\n\n%%\n%%\n{plugins                , [coveralls]}.\n{cover_enabled          , true}.\n{cover_export_enabled   , true}.\n{coveralls_coverdata    , \"_build/test/cover/ct.coverdata\"}.\n{coveralls_service_name , \"travis-ci\"}."
  },
  {
    "path": "rebar.config.script",
    "content": "case os:getenv(\"TRAVIS\") of\n  \"true\" ->\n    JobId   = os:getenv(\"TRAVIS_JOB_ID\"),\n    lists:keystore(coveralls_service_job_id, 1, CONFIG, {coveralls_service_job_id, JobId});\n  _ ->\n    CONFIG\nend.\n\n"
  },
  {
    "path": "src/datalog.app.src",
    "content": "{application, datalog,\n   [\n      {description, \"datalog is a query language based on the logic programming paradigm\"},\n      {vsn,         \"git\"},\n      {modules,     []},\n      {registered,  []},\n      {applications,[\n         kernel\n        ,stdlib\n      ]},\n      {env, []},\n\n      {licenses, [\"Apache\"]},\n      {maintainers, [\"Dmitry Kolesnikov\"]},\n      {links, [\n         {\"GitHub\", \"https://github.com/fogfish/datalog\"}\n      ]}\n   ]\n}.  \n"
  },
  {
    "path": "src/datalog.erl",
    "content": "%%\n%%   Copyright 2014 - 2016 Dmitry Kolesnikov, All Rights Reserved\n%%\n%%   Licensed under the Apache License, Version 2.0 (the \"License\");\n%%   you may not use this file except in compliance with the License.\n%%   You may obtain a copy of the License at\n%%\n%%       http://www.apache.org/licenses/LICENSE-2.0\n%%\n%%   Unless required by applicable law or agreed to in writing, software\n%%   distributed under the License is distributed on an \"AS IS\" BASIS,\n%%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n%%   See the License for the specific language governing permissions and\n%%   limitations under the License.\n%%\n%% @doc\n%%   datalog evaluator\n-module(datalog).\n-include(\"datalog.hrl\").\n\n%%\n%% datalog interface\n-export([\n   t/0,\n   q/2,\n   p/1,\n   c/2,\n   c/3,\n   % schema/1,\n   filter/1,\n   takewhile/2\n]).\n\n-export_type([q/0, eval/0, heap/0, predicate/0]).\n\n%%%----------------------------------------------------------------------------\n%%%\n%%% data types\n%%%\n%%%----------------------------------------------------------------------------\n\n%% datalog query is a set of horn clauses\n-type q()         :: #{horn() => [head() | body()]}.\n% -type head()      :: [atom()].\n% -type body()      :: [predicate()].\n-type horn()      :: atom().\n\n%% pattern is unit of work to access ground facts persisted in external storage. \n%% sigma function uses pattern as abstract sub-query definition towards the storage \n-type predicate() :: #{'@' => name(), '_' => head(), _ => pattern()}.\n-type name()      :: f() | {module(), f()}.\n-type pattern()   :: _ | [filter()].\n-type filter()    :: {'>' | '<' | '>=' | '=<' | '=/=', _}.\n-type f()         :: atom().\n\n%% sigma function (@todo: define types)\n-type eval()    :: fun( (_) -> datum:stream() ).\n-type heap()    :: fun( (map()) -> eval() ).\n\n\n%%\n%% stream based recursion\nt() ->\n   stream:unfold(fun tt/1, [stream:build([1,2,3])]).\n\ntt([undefined]) ->\n   undefined;\n\ntt([undefined | Stack]) ->\n   tt(Stack);\n\ntt([H | T]) ->\n   spin(stream:head(H), [stream:tail(H) | T]).\n\nspin(X, Stack) when X < 100 ->\n   {X, [rec(X) | Stack]};\nspin(X, Stack) ->\n   {X, Stack}.\n\nrec(X) ->\n   stream:build([X * 10, X * 10, X * 10]).\n\n\n%%\n%% evaluate compiled datalog expression with environment\n-spec q(_, _) -> eval().\n\nq(Datalog, Env) ->\n   Datalog(Env).   \n\n%%%----------------------------------------------------------------------------\n%%%\n%%% sigma function helpers\n%%%\n%%%----------------------------------------------------------------------------\n\n%%\n%% in-line stream filter(s) using predicate term and pattern \n-spec filter(pattern()) -> fun( (_, datum:stream()) -> datum:stream() ).\n\nfilter(Pattern) -> \n   datalog_lang:filter(fun stream:filter/2, Pattern).\n\n%%\n%% in-line stream filter(s) using predicate term and pattern \n-spec takewhile(_, pattern()) -> fun( (_, datum:stream()) -> datum:stream() ).\n\ntakewhile(X, Pattern) -> \n   datalog_lang:filter(fun stream:takewhile/2, X, Pattern).\n\n\n%%%----------------------------------------------------------------------------\n%%%\n%%% compiler\n%%%\n%%%----------------------------------------------------------------------------\n\n%%\n%% parse datalog to native format\n-spec p(string()) -> datalog:q().\n\np(Datalog) ->\n   p(Datalog, fun datalog_q:native/1).\n\np(Datalog, PreProcessor) ->\n   try\n      {ok, Lex, _} = datalog_leex:string(Datalog), \n      {ok, Req}    = datalog_yeec:parse(Lex),\n      PreProcessor(Req)\n   catch\n   _:{badmatch, {error, {_, rds_parser, Reason}}} ->\n      {error, Reason}; \n   _:{badmatch, {error, {_, rds_lexer,  Reason},_}} ->\n      {error, Reason}; \n   _:{badmatch, Error} ->\n      Error\n   end. \n\n%%\n%% compile native datalog to evaluator function\nc(Source, Datalog) ->\n   c(Source, Datalog, []).\n\nc(Source, Datalog, Opts) ->\n   case lists:keyfind(return, 1, Opts) of\n      {_, maps} ->\n         c_map(Source, Datalog);\n      {_, tuples} ->\n         c_tuple(Source, Datalog);\n      _    ->\n         c_list(Source, Datalog)\n   end.\n\nc_list(Source, [#goal{id = Goal, head = Head} | Datalog]) ->\n   Lprogram = lists:foldl(fun(Horn, Acc) -> compile(Source, Horn, Acc) end, #{}, Datalog),\n   Fun = maps:get(Goal, Lprogram),\n   fun(Env) ->\n      (Fun(Env))( head_lits(Head) )\n   end.\n\nc_tuple(Source, [#goal{id = Goal, head = Head} | Datalog]) ->\n   Lprogram = lists:foldl(fun(Horn, Acc) -> compile(Source, Horn, Acc) end, #{}, Datalog),\n   Fun = maps:get(Goal, Lprogram),\n   fun(Env) ->\n      stream:map(\n         fun(Tuple) -> erlang:list_to_tuple(Tuple) end,\n         (Fun(Env))( head_lits(Head) )\n      )\n   end.\n\nc_map(Source, [#goal{id = Goal, head = Head} | Datalog]) ->\n   Lprogram = lists:foldl(fun(Horn, Acc) -> compile(Source, Horn, Acc) end, #{}, Datalog),\n   Vars = case lists:keyfind(Goal, 2, Datalog) of\n      {_, _, X, _} -> \n         X;\n      #source{} ->\n         Head\n   end,\n   Fun = maps:get(Goal, Lprogram),\n   fun(Env) ->\n      stream:map(\n         fun(Tuple) -> maps:from_list( lists:zip(Vars, Tuple) ) end,\n         (Fun(Env))( head_lits(Head) )\n      )\n   end.\n\ncompile(Source, #source{id = Id, head = Head}, Datalog) ->\n   Datalog#{Id => datalog_vm:stream(fun Source:stream/3, Id, Head)};\n\ncompile(_, #horn{id = Id} = Horn, Datalog) ->\n   Datalog#{Id => compile(Horn, Datalog)};\n\ncompile(_, #join{id = Id} = Join, Datalog) ->\n   Datalog#{Id => compile(Join, Datalog)};\n\ncompile(_, #recc{id = Id} = Recc, Datalog) ->\n   Datalog#{Id => compile(Recc, Datalog)}.\n\n\ncompile(#{'@' := {datalog, Fun}} = Sigma, _Datalog) ->\n   Sigma#{'@' => datalog_lang:Fun(Sigma), '.' => pipe};\n\ncompile(#{'@' := Gen} = Sigma, Datalog) ->\n   Sigma#{'@' => maps:get(Gen, Datalog, Gen)};\n\ncompile(#horn{head = Head, body = Body}, Datalog) ->\n   datalog_vm:horn(Head, [compile(Sigma, Datalog) || Sigma <- Body]);\n\ncompile(#join{horn = Body}, Datalog) ->\n   datalog_vm:union([compile(Sigma, Datalog) || Sigma <- Body]);\n\ncompile(#recc{horn = [I, #horn{body = Body} = Horn]}, Datalog) ->\n   datalog_vm:recursion(\n      compile(I, Datalog),\n      Horn#horn{body = [compile(Sigma, Datalog) || Sigma <- Body]}\n   ).\n\nhead_lits(Head) ->\n   lists:map(\n      fun(X) -> \n         case is_atom(X) of \n            true -> '_';\n            false -> X \n         end\n      end,\n      Head\n   ).\n"
  },
  {
    "path": "src/datalog.hrl",
    "content": "%% @doc\n%%   abstract syntax tree \n\n%%\n%% Erlang Native Format\n\n\n\n-type id()     :: atom() | {atom(), atom()} | {iri, binary(), binary()}.\n-type head()   :: [_].\n-type body()   :: [#{}].\n\n-record(goal, {\n   id   = undefined        :: id()\n,  head = undefined        :: head()\n}).\n\n-record(horn, {\n   id   = undefined        :: id()\n,  head = undefined        :: head()\n,  body = undefined        :: body()\n}).\n\n-record(join, {\n   id   = undefined        :: id()\n,  head = undefined        :: head()\n,  horn = undefined        :: [#horn{}]\n}).\n\n-record(recc, {\n   id   = undefined        :: id()\n,  head = undefined        :: head()\n,  horn = undefined        :: [#horn{}]\n}).\n\n-record(source, {\n   id   = undefined        :: id()\n,  head = undefined        :: head()\n})."
  },
  {
    "path": "src/datalog_lang.erl",
    "content": "%%\n%%   Copyright 2014 - 2016 Dmitry Kolesnikov, All Rights Reserved\n%%\n%%   Licensed under the Apache License, Version 2.0 (the \"License\");\n%%   you may not use this file except in compliance with the License.\n%%   You may obtain a copy of the License at\n%%\n%%       http://www.apache.org/licenses/LICENSE-2.0\n%%\n%%   Unless required by applicable law or agreed to in writing, software\n%%   distributed under the License is distributed on an \"AS IS\" BASIS,\n%%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n%%   See the License for the specific language governing permissions and\n%%   limitations under the License.\n%%\n%% @doc\n%%   build-in datalog primitives\n-module(datalog_lang).\n\n-include_lib(\"datum/include/datum.hrl\").\n\n-export([\n   filter/2,\n   unique/1,\n   flat/1,\n   eq/1, ne/1, lt/1, gt/1, le/1, ge/1\n]).\n\n%%\n%% scalable bloom filter definition\n-define(SBF, sbf:new(128, 0.0001)).\n\n%%\n%% in-line stream filter(s),\n%% helper function to apply predicate terms and patterns on stream of tuples \n-spec filter(_, datalog:pattern()) -> _.\n\nfilter(_With, '_') ->\n   fun(_Lens, Stream) -> Stream end;\n\nfilter(_With, undefined) ->\n   fun(_Lens, Stream) -> Stream end;\n\nfilter(With, Pattern)\n when is_list(Pattern) ->\n   % pattern is guard condition: p(..., X, ...), X > 5, X < 10\n   fun(Lens, Stream) ->\n      lists:foldl(fun(Filter, Acc) -> filter(With, Lens, Filter, Acc) end, Stream, Pattern)\n   end;\n\nfilter(With, Pattern) ->\n   filter(With, [{'=:=', Pattern}]).\n\nfilter(With, Lens, '_', Stream) ->\n   Stream;\nfilter(With, Lens, Filter, Stream) ->\n   With(fun(X) -> filter_check(Lens(X), Filter) end, Stream).\n\nfilter_check(B, {'>',   A}) -> B >  A;\nfilter_check(B, {'>=',  A}) -> B >= A;\nfilter_check(B, {'<',   A}) -> B  < A;\nfilter_check(B, {'=<',  A}) -> B =< A;\nfilter_check(B, {'=:=', A}) -> B =:= A;\nfilter_check(B, {'=/=', A}) -> B =/= A.\n\n\n%%\n%% a predicate ensures unique terms within the stream\n%% ```\n%% h(x,z) :- a(x,y), .unique(y), b(y,z) . \n%% ``` \n-spec unique(datalog:predicate()) -> _.\n\nunique(#{'_' := Head}) ->   \n   fun(_) ->\n      fun(Stream) ->\n         stream:unfold(fun uniq/1, {?SBF, Head, Stream})\n      end\n   end.\n\nuniq({_, _, ?stream()}) ->\n   stream:new();  \n\nuniq({Sbf0, Head, Stream}) ->\n   Item = maps:with(Head, stream:head(Stream)),\n   Sbf1 = sbf:add(Item, Sbf0),\n   Tail = stream:dropwhile(fun(X) -> sbf:has(maps:with(Head, X), Sbf1) end, Stream),\n   {stream:head(Stream), {Sbf1, Head, Tail}}.\n\n%%\n%% a predicate flatmap identity over stream \n%% ```\n%% h(x,z) :- a(x,y), .flat(y), b(y,z) . \n%% ``` \n-spec flat(datalog:predicate()) -> _.\n\nflat(#{'_' := [Term]}) ->\n   fun(_) ->\n      fun(Stream) ->\n         stream:unfold(fun flatten/1, {[], Term, Stream})\n      end\n   end.\n\nflatten({_, _, ?stream()}) ->\n   stream:new();\n\nflatten({[], Term, Stream}) ->\n   case stream:head(Stream) of\n      #{Term := X} when is_list(X) ->\n         flatten({X, Term, Stream});\n      Head ->\n         {Head, {[], Term, stream:tail(Stream)}}\n   end;\n\nflatten({[H], Term, Stream}) ->\n   Head = stream:head(Stream),\n   {Head#{Term => H}, {[], Term, stream:tail(Stream)}};\n\nflatten({[H|T], Term, Stream}) ->\n   Head = stream:head(Stream),\n   {Head#{Term => H}, {T, Term, Stream}}.\n\n%%\n%% comparison predicates\n%% ```\n%% h(x,z) :- a(x,y), b(y,z), .eq(x,z). \n%% ``` \n-spec eq(datalog:predicate()) -> _.\n\neq(#{'_' := [A, B]}) ->\n   fun(_) ->\n      fun(Stream) ->\n         stream:filter(fun(#{A := Ax, B := Bx}) -> Ax =:= Bx end, Stream)\n      end\n   end.\n\n-spec ne(datalog:predicate()) -> _.\n\nne(#{'_' := [A, B]}) ->\n   fun(_) ->\n      fun(Stream) ->\n         stream:filter(fun(#{A := Ax, B := Bx}) -> Ax =/= Bx end, Stream)\n      end\n   end.\n\n-spec lt(datalog:predicate()) -> _.\n\nlt(#{'_' := [A, B]}) ->\n   fun(_) ->\n      fun(Stream) ->\n         stream:filter(fun(#{A := Ax, B := Bx}) -> Ax < Bx end, Stream)\n      end\n   end.\n\n-spec gt(datalog:predicate()) -> _.\n\ngt(#{'_' := [A, B]}) ->\n   fun(_) ->\n      fun(Stream) ->\n         stream:filter(fun(#{A := Ax, B := Bx}) -> Ax > Bx end, Stream)\n      end\n   end.\n\n-spec le(datalog:predicate()) -> _.\n\nle(#{'_' := [A, B]}) ->\n   fun(_) ->\n      fun(Stream) ->\n         stream:filter(fun(#{A := Ax, B := Bx}) -> Ax =< Bx end, Stream)\n      end\n   end.\n\n-spec ge(datalog:predicate()) -> _.\n\nge(#{'_' := [A, B]}) ->\n   fun(_) ->\n      fun(Stream) ->\n         stream:filter(fun(#{A := Ax, B := Bx}) -> Ax >= Bx end, Stream)\n      end\n   end.\n\n\n\n\n"
  },
  {
    "path": "src/datalog_leex.xrl",
    "content": "%%\n%%   Copyright 2014 - 2015 Dmitry Kolesnikov, All Rights Reserved\n%%\n%%   Licensed under the Apache License, Version 2.0 (the \"License\");\n%%   you may not use this file except in compliance with the License.\n%%   You may obtain a copy of the License at\n%%\n%%       http://www.apache.org/licenses/LICENSE-2.0\n%%\n%%   Unless required by applicable law or agreed to in writing, software\n%%   distributed under the License is distributed on an \"AS IS\" BASIS,\n%%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n%%   See the License for the specific language governing permissions and\n%%   limitations under the License.\n%%\n%% @doc\n%%   datalog\nDefinitions.\n\nCHAR  = [a-zA-Z_@]\nDIGIT = [0-9]\nWS    = ([\\000-\\s]|%.*)\n\n%%\n%%\nRules.\n\n%%\n%% symbol\n%%\n{CHAR}+  :\n   {token, {symbol, TokenLine, TokenChars}}.\n\n'[a-zA-Z_:]* :\n   {token, {symbol, TokenLine, lists:sublist(TokenChars, 2, TokenLen - 1)}}.\n\n%%\n%% xsd:anyURI\n%%   <http://a/b> - absolute IRI\n%%   a:b - compact IRI\n%%\n<[^>]*> :\n   {token, {iri, TokenLine, strip(TokenChars,TokenLen)}}.\n\n%%\n%% xsd:string\n%%\n\\\"[^\\\"]*\\\" :\n   {token, {binary, TokenLine, strip(TokenChars,TokenLen)}}.\n\n%%\n%% xsd:integer\n%%\n{DIGIT}+ :\n   {token, {integer, TokenLine, TokenChars}}.\n\n%%\n%% xsd:decimal\n%%\n{DIGIT}+\\.{DIGIT}+ :\n   {token, {decimal, TokenLine, TokenChars}}.\n\n%%\n%% syntax\n%%\n\\?\\- :\n   {token,{list_to_atom(TokenChars),TokenLine}}.\n\n\\:\\- :\n   {token,{list_to_atom(TokenChars),TokenLine}}.\n\n[()\\[\\]{}_<=>!.,^\\-\\:@/] :\n   {token,{list_to_atom(TokenChars),TokenLine}}.\n\n{WS}+  : skip_token.\n\n%%\n%%\nErlang code.\n\nstrip(TokenChars,TokenLen) ->\n   lists:sublist(TokenChars, 2, TokenLen - 2).\n"
  },
  {
    "path": "src/datalog_list.erl",
    "content": "%%\n%%   Copyright 2014 - 2015 Dmitry Kolesnikov, All Rights Reserved\n%%\n%%   Licensed under the Apache License, Version 2.0 (the \"License\");\n%%   you may not use this file except in compliance with the License.\n%%   You may obtain a copy of the License at\n%%\n%%       http://www.apache.org/licenses/LICENSE-2.0\n%%\n%%   Unless required by applicable law or agreed to in writing, software\n%%   distributed under the License is distributed on an \"AS IS\" BASIS,\n%%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n%%   See the License for the specific language governing permissions and\n%%   limitations under the License.\n%%\n%% @doc\n%%   a reference implementation of stream generators\n-module(datalog_list).\n-compile({parse_transform, category}).\n\n-export([stream/3]).\n\n%%\n%% example of ground facts generator, it produces a stream of tuple from input list\n%%\n%% a(x,y).\nstream(_, _, [X1]) ->\n   fun(List) ->\n      [identity ||\n         stream:build(List),\n         nary(1, _),\n         filter(1, X1, _),\n         stream:map(fun erlang:tuple_to_list/1, _)\n      ]\n   end;\n\nstream(_, _, [X1, X2]) ->\n   fun(List) ->\n      [identity ||\n         stream:build(List),\n         nary(2, _),\n         filter(1, X1, _),\n         filter(2, X2, _),\n         stream:map(fun erlang:tuple_to_list/1, _)\n      ]\n   end;\n\nstream(_, H, [X1, X2, X3] = K) ->\n   io:format(\"==< ~p ~p~n\", [H, K]),\n   fun(List) ->\n      [identity ||\n         stream:build(List),\n         nary(3, _),\n         filter(1, X1, _),\n         filter(2, X2, _),\n         filter(3, X3, _),\n         stream:map(fun erlang:tuple_to_list/1, _)\n      ]\n   end;\n\nstream(_, _, [X1, X2, X3, X4]) ->\n   fun(List) ->\n      [identity ||\n         stream:build(List),\n         nary(4, _),\n         filter(1, X1, _),\n         filter(2, X2, _),\n         filter(3, X3, _),\n         filter(4, X4, _),\n         stream:map(fun erlang:tuple_to_list/1, _)\n      ]\n   end.\n\n%%\n%%\nnary(N, Stream) ->\n   stream:filter(fun(X) -> is_tuple(X) andalso size(X) =:= N end, Stream).\n\nfilter(I, Filter, Stream) ->\n   Fun  = datalog:filter(Filter),\n   Fun(fun(X) -> erlang:element(I, X) end, Stream).\n"
  },
  {
    "path": "src/datalog_q.erl",
    "content": "%%\n%%   Copyright 2014 - 2018 Dmitry Kolesnikov, All Rights Reserved\n%%\n%%   Licensed under the Apache License, Version 2.0 (the \"License\");\n%%   you may not use this file except in compliance with the License.\n%%   You may obtain a copy of the License at\n%%\n%%       http://www.apache.org/licenses/LICENSE-2.0\n%%\n%%   Unless required by applicable law or agreed to in writing, software\n%%   distributed under the License is distributed on an \"AS IS\" BASIS,\n%%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n%%   See the License for the specific language governing permissions and\n%%   limitations under the License.\n%%\n%% @doc\n%%   the library parser uses leex / yeec to convert query (datalog syntax) to \n%%   abstract syntax tree (set of horn classes). The abstract syntax is not optimal\n%%   for evaluation. It has to be adapted to `-type datalog:q()`.\n-module(datalog_q).\n\n-include(\"datalog.hrl\").\n\n-export([\n   native/1\n]).\n\n%%\n%%\n-spec native([{_, _, _}]) -> datalog:q().\n\nnative(Datalog) ->\n   join(lists:map(fun optimise/1, Datalog)).\n\n%%\noptimise(#horn{body = Body} = Horn) ->\n   % horn clause body consists of predicates and infix predicates.\n   % infix predicates are converted to stream range filters \n   {Pattern, Infix} = lists:partition(fun(X) -> size(X) =:= 2 end, Body),\n   Horn#horn{body = ast_to_body(Pattern, Infix)};\n\noptimise(Clause) ->\n   Clause.\n\n%%\njoin([#horn{id = Id, head = Head} | _] = Datalog) ->\n   case \n      lists:partition(fun(#horn{id = X}) -> X =:= Id; (_) -> false end, Datalog)\n   of\n      {[Horn], Other} ->\n         [Horn | join(Other)];\n      {Joints, Other}  ->\n         case is_recc(Id, Joints) of\n            false ->\n               [#join{id = Id, head = Head, horn = Joints} | join(Other)];\n            true  ->\n               [#recc{id = Id, head = Head, horn = Joints} | join(Other)]\n         end\n   end; \n\njoin([Head | Tail]) ->\n   [Head | join(Tail)];\n\njoin([]) ->\n   [].\n\n%%\nis_recc(_, []) ->\n   false;\nis_recc(Horn, [#horn{body = Body} | T]) ->\n   case lists:dropwhile(fun(#{'@' := X}) -> X /= Horn end, Body) of\n      [] ->\n         is_recc(Horn, T);\n      _  ->\n         true\n   end.\n\n%%\n%%\nast_to_body(Pattern, Infix) ->\n   [ast_to_pattern(X, Infix) || X <- Pattern].\n\n%%\n%%\nast_to_pattern({Id, Pattern}, Filter) ->\n   %% check each pattern variable for BIF constrains \n   lists:foldl(\n      fun(X, Acc) -> ast_to_filter(X, Filter, Acc) end, \n      #{'@' => Id, '_' => Pattern},\n      Pattern\n   ).\n   \n%%\n%% interleave pattern variable with filters\nast_to_filter(Variable, Filter, Pattern) ->\n   case \n      lists:filter(\n         fun(X) -> \n            erlang:element(2, X) =:= Variable\n         end, \n         Filter\n      )\n   of\n      %% no BIF constrain\n      [] -> \n         Pattern;\n\n      %% BIF constrain variable\n      Fs ->\n         case lists:keyfind('=:=', 1, Fs) of\n            false ->\n               maps:put(Variable, [{P, F} || {P, _, F} <- Fs], Pattern);\n            {'=:=', _, F} ->\n               maps:put(Variable, F, Pattern)\n         end\n   end.\n\n\n"
  },
  {
    "path": "src/datalog_vm.erl",
    "content": "%%\n%%   Copyright 2014 - 2018 Dmitry Kolesnikov, All Rights Reserved\n%%\n%%   Licensed under the Apache License, Version 2.0 (the \"License\");\n%%   you may not use this file except in compliance with the License.\n%%   You may obtain a copy of the License at\n%%\n%%       http://www.apache.org/licenses/LICENSE-2.0\n%%\n%%   Unless required by applicable law or agreed to in writing, software\n%%   distributed under the License is distributed on an \"AS IS\" BASIS,\n%%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n%%   See the License for the specific language governing permissions and\n%%   limitations under the License.\n%%\n%% @doc\n%%   evaluates a logical program\n-module(datalog_vm).\n\n-compile({parse_transform, partial}).\n-compile({parse_transform, category}).\n-include_lib(\"datum/include/datum.hrl\").\n-include(\"datalog.hrl\").\n\n-export([\n   union/1,\n   recursion/2,\n   horn/2,\n   stream/3\n]).\n\n%%\n%% \nunion(Horns) ->\n   fun(Env) ->\n      HHorns = [F(Env) || F <- Horns],\n      fun(SubQ) ->\n         stream:unfold(fun funion/1, {?stream(), SubQ, HHorns})\n      end\n   end.\n\nfunion({?stream(), _, []}) ->\n   ?stream();\nfunion({?stream(), SubQ, [HHorn | THorn]}) ->\n   funion({HHorn(SubQ), SubQ, THorn});\nfunion({Stream, SubQ, HHorns}) ->\n   {stream:head(Stream), {stream:tail(Stream), SubQ, HHorns}}.\n\n\n%%\n%%\nrecursion(I, #horn{head = Head, body = Body}) ->\n   fun(Env) ->\n      IEnv  = I(Env),\n      {Horns, [#{'_' := XHead}]} = lists:partition(fun(#{'@' := F}) -> is_function(F) end, Body),\n      THorns =  [Spec#{'@' => F(Env)} || #{'@' := F} = Spec <- Horns],\n      fun(SubQ) ->\n         stream:unfold(fun frecc/1, {[IEnv(SubQ)], XHead, THorns, Head, sbf:new(128, 0.0001)})\n      end\n   end.\n\nfrecc({[undefined], _, _, _, _}) ->\n   undefined;\n\nfrecc({[undefined | Stack], XHead, THorn, Head, Sbf}) ->\n   frecc({Stack, XHead, THorn, Head, Sbf});\n\nfrecc({[H | T], XHead, THorn, Head, Sbf}) ->\n   Tuple = stream:head(H),\n   case not sbf:has(Tuple, Sbf) of\n      true ->\n         spinoff(Tuple, {[stream:tail(H) | T], XHead, THorn, Head, sbf:add(Tuple, Sbf)});\n      false ->\n         frecc({[stream:tail(H) | T], XHead, THorn, Head, Sbf})\n   end.\n\nspinoff(Cell, {Stack, XHead, [HHorn | THorn] = Horns, Head, Sbf}) ->\n   Heap   = maps:from_list(lists:zip(XHead, Cell)),\n   Stream = join(eval(Heap, HHorn), THorn),\n   New = stream:map(\n      fun(X) ->\n         [maps:get(K, X) || K <- Head]\n      end,\n      Stream\n   ),\n   {Cell, {[New | Stack], XHead, Horns, Head, Sbf}}.\n\n%%\n%%\nhorn(Head, Horn) ->\n   fun(Env) ->\n      [HHorn | THorn] = [Spec#{'@' => F(Env)} || #{'@' := F} = Spec <- Horn, is_function(F)],\n      fun(SubQ) ->\n         Heap   = maps:from_list(lists:zip(Head, SubQ)),\n         Stream = join(eval(Heap, HHorn), THorn),\n         stream:map(\n            fun(X) ->\n               [maps:get(K, X) || K <- Head]\n            end,\n            Stream\n         )\n      end\n   end.\n\n\njoin(Stream, [#{'.' := pipe, '@' := Pipe} | THorn]) ->\n   join(Pipe(Stream), THorn);\n\njoin(Stream, [HHorn | THorn]) ->\n   join(\n      stream:flat(\n         stream:map(fun(Heap) -> eval(Heap, HHorn) end, Stream)\n      ),\n      THorn\n   );\n\njoin(Stream, []) ->\n   Stream.\n\neval(Heap, #{'_' := Head, '@' := Fun} = Spec) ->\n   SubQ = [term(T, Spec, Heap) || T <- Head],\n   stream:map(\n      fun(Tuple) ->\n         %% Note: we need to give a priority to existed heap values, unless '_'\n         %% maps:merge(Heap, maps:from_list( lists:zip(Head, Tuple) ))\n         Prev = maps:filter(fun(_, X) -> X /= '_' end, Heap),\n         This = maps:from_list( lists:zip(Head, Tuple) ),\n         maps:merge(Heap, maps:merge(This, Prev))\n      end,\n      Fun(SubQ)\n   ).\n\n%%\n%%\nterm(T, Spec, Heap)\n when is_atom(T) ->\n   case Spec of\n      #{T := [{Op, Var}]} when is_atom(Var) ->\n         [{Op, maps:get(Var, Heap)}];\n      _ ->\n         case term(T, Spec) of\n            '_' -> term(T, Heap);\n            Val -> Val\n         end\n   end;\nterm(T, _, _) ->\n   T.\n\nterm(T, Predicate) ->\n   case Predicate of\n      #{T := Value} -> Value;\n      _             -> '_'\n   end;\nterm(T, _) ->\n   T.\n\n%%\n%%\nstream(Gen, Id, Head) ->\n   fun(Env) ->\n      fun(SubQ) -> (Gen(Id, Head, SubQ))(Env) end\n   end.\n\n"
  },
  {
    "path": "src/datalog_yeec.yrl",
    "content": "%%\n%%   Copyright 2014 - 2015 Dmitry Kolesnikov, All Rights Reserved\n%%\n%%   Licensed under the Apache License, Version 2.0 (the \"License\");\n%%   you may not use this file except in compliance with the License.\n%%   You may obtain a copy of the License at\n%%\n%%       http://www.apache.org/licenses/LICENSE-2.0\n%%\n%%   Unless required by applicable law or agreed to in writing, software\n%%   distributed under the License is distributed on an \"AS IS\" BASIS,\n%%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n%%   See the License for the specific language governing permissions and\n%%   limitations under the License.\n%%\n%% @doc\n%%   datalog\n\nNonterminals   CLAUSES GOAL HORN BODY ITEM PREDICATE TERMS TERM PAIRS LIT INFIX.\nTerminals      '?-' ':-' '(' ')' '.' ',' '<' '=' '>' '!' '-' ':' '[' ']' '{' '}' '/' symbol iri binary integer decimal.\nRootsymbol     CLAUSES.\n\n%%\n%%\nCLAUSES -> GOAL CLAUSES :\n   ['$1' | '$2'].\nCLAUSES -> HORN CLAUSES :\n   ['$1' | '$2'].\nCLAUSES -> '$empty' :\n   [].\n\n%%\n%%\nGOAL -> '?-' PREDICATE '(' TERMS ')' '.' :\n   {goal, '$2', '$4'}.\n\nGOAL -> '?-' PREDICATE '/' integer '.' :\n   {goal, '$2', head('$4')}.\n\n%%\n%%\nHORN -> PREDICATE '(' TERMS ')' ':-' BODY '.' :\n   {horn, '$1', '$3', '$6'}.\n\nHORN -> PREDICATE '(' TERMS ')' '.' :\n   {source, '$1', '$3'}.\n\nHORN -> PREDICATE '(' ')' '.' :\n   {source, '$1', []}.\n\n%%\n%%\nBODY -> ITEM ',' BODY :\n   ['$1' | '$3'].\nBODY -> ITEM :\n   ['$1'].\n\n%%\n%%\nITEM -> PREDICATE '(' ')' :\n   {'$1', []}.\n\nITEM -> PREDICATE '(' TERMS ')' :\n   {'$1', '$3'}.\n\nITEM -> symbol INFIX TERM :\n   {'$2', atom('$1'), '$3'}.\n\nITEM -> symbol ':' symbol INFIX TERM :\n   {'$4', {iri, binary('$1'), binary('$3')}, '$5'}.\n\n\n%%\n%%\nPREDICATE -> symbol :\n   atom('$1').\n\nPREDICATE -> symbol ':' symbol :\n  {iri, binary('$1'), binary('$3')}.\n\nPREDICATE -> symbol '.' symbol :\n   {atom('$1'), atom('$3')}.\n\nPREDICATE -> '.' symbol :\n   {datalog, atom('$2')}.\n\n%%\n%%\nTERMS -> TERM ',' TERMS :\n   ['$1' | '$3'].\nTERMS -> TERM :\n   ['$1'].\n\n%%\n%%\nTERM -> '{' PAIRS '}' :\n   maps:from_list('$2').\n\nTERM -> '(' TERMS ')' :\n   erlang:list_to_tuple('$2').\n\nTERM -> '[' TERMS ']' :\n   '$2'.\n\nTERM -> symbol LIT :\n   {atom('$1'), '$2'}.\n\nTERM -> symbol LIT LIT :\n   {atom('$1'), '$2', '$3'}.\n\nTERM -> symbol LIT LIT LIT :\n   {atom('$1'), '$2', '$3', '$4'}.\n\nTERM -> LIT :\n   '$1'.\n\n%%\n%%\nPAIRS -> symbol ':' TERM ',' PAIRS :\n   [{binary('$1'), '$3'} | '$5'].\n\nPAIRS -> symbol ':' TERM :\n   [{binary('$1'), '$3'}].\n\n\n%%\n%% xsd:anyURI\nLIT -> iri :\n   {iri, binary('$1')}.\nLIT -> symbol ':' symbol :\n   {iri, binary('$1'), binary('$3')}.\n\n%%\n%% xsd:string\nLIT -> binary :\n   binary('$1').\n\nLIT -> binary symbol :\n   binary('$1').\n\n%%\n%% xsd:integer\nLIT -> integer :\n   integer('$1').\nLIT -> '-' integer :\n   -integer('$2').\n\n%%\n%% xsd:decimal\nLIT -> decimal :\n   decimal('$1').\n\nLIT -> '-' decimal :\n   -decimal('$2').\n\n%%\n%% xsd:dateTime\nLIT -> integer '-' integer '-' integer symbol integer ':' integer ':' integer symbol :\n   timestamp({{integer('$1'), integer('$3'), integer('$5')}, {integer('$7'), integer('$9'), integer('$11')}}).\n\nLIT -> integer '-' integer '-' integer :\n   {{integer('$1'), integer('$3'), integer('$5')}, {0, 0, 0}}.\n\nLIT -> integer '-' integer :\n   {{integer('$1'), integer('$3'), 0}, {0, 0, 0}}.\n\nLIT -> '-' '-' integer '-' integer :\n   {{0, integer('$3'), integer('$5')}, {0, 0, 0}}.\n\nLIT -> integer ':' integer ':' integer symbol :\n   {{0, 0, 0}, {integer('$1'), integer('$3'), integer('$5')}}.\n\n%%\n%% symbols\nLIT -> symbol :\n   atom('$1').\n\n%%\n%%\nINFIX    -> '=' :\n   '=:='.\nINFIX    -> '>' :\n   '>'.\nINFIX    -> '<' :\n   '<'.\nINFIX    -> '>' '=' :\n   '>='.\nINFIX    -> '=' '>' :\n   '>='.\nINFIX    -> '=' '<' :\n   '=<'.\nINFIX    -> '<' '=' :\n   '=<'.\nINFIX    -> '!' '=' :\n   '=/='.\nINFIX    -> symbol  :\n   atom('$1').\n\n%%\n%%\nErlang code.\n\nunwrap({_, _, X}) ->\n   X.\n\natom({_,_,X}) ->\n   erlang:list_to_atom(X).\n\nbinary({_,_,X}) ->\n   erlang:list_to_binary(X).\n\ninteger({_,_,X}) ->\n   erlang:list_to_integer(X).\n\ndecimal({_,_,X}) ->\n   erlang:list_to_float(X).\n\ntimestamp({{_, _, _}, {_, _, _}} = T) -> \n   Sec = calendar:datetime_to_gregorian_seconds(T) - 62167219200,\n   {Sec div 1000000, Sec rem 1000000, 0}.\n\nhead({_,_,X}) ->\n   ['_' || _ <- lists:seq(1, erlang:list_to_integer(X))].\n"
  },
  {
    "path": "test/datalog_SUITE.erl",
    "content": "-module(datalog_SUITE).\n-include_lib(\"common_test/include/ct.hrl\").\n-compile({parse_transform, category}).\n\n-export([all/0]).\n-export([\n   predicate_stream_arity_1/1\n,  predicate_stream_arity_2/1\n,  predicate_stream_arity_3/1\n,  predicate_single_horn_1/1\n,  predicate_single_horn_2/1\n,  predicate_single_horn_3/1\n,  predicate_horn_2/1\n,  predicate_horn_3/1\n,  cartesian_product/1\n,  infix_eq/1\n,  infix_lt/1\n,  infix_le/1\n,  infix_gt/1\n,  infix_ge/1\n,  infix_ne/1\n,  union_2/1\n,  union_3/1\n,  recursion_1/1\n,  recursion_2/1\n,  recursion_3/1\n,  source_semantic_web/1\n,  source_native/1\n,  lang_eq/1\n,  lang_ne/1\n,  lang_lt/1\n,  lang_gt/1\n,  lang_le/1\n,  lang_ge/1\n,  lang_unique/1\n,  lang_flat/1\n]).\n\nall() ->\n   [Test || {Test, NAry} <- ?MODULE:module_info(exports), \n      Test =/= module_info,\n      NAry =:= 1\n   ].\n\ndatalog(Datalog, Input, Expect) ->\n   Expect = [identity ||\n      datalog:p(Datalog),\n      datalog:c(datalog_list, _, [{return, tuples}]),\n      datalog:q(_, Input),\n      stream:list(_)\n   ].\n\n%%\n%%\npredicate_stream_arity_1(_) ->\n   datalog(\n      \"?- p(_). p(x).\",\n      [{1}, {2}, {3}],\n      [{1}, {2}, {3}]\n   ).\n\npredicate_stream_arity_2(_) ->\n   datalog(\n      \"?- p(_, _). p(x, y).\",\n      [{1, 2}, {2, 3}, {3, 4}],\n      [{1, 2}, {2, 3}, {3, 4}]\n   ).\n\npredicate_stream_arity_3(_) ->\n   datalog(\n      \"?- p(_, _, _). p(x, y, z).\",\n      [{1, 2, 3}, {2, 3, 4}, {3, 4, 5}],\n      [{1, 2, 3}, {2, 3, 4}, {3, 4, 5}]\n   ).\n\n%%\n%%\npredicate_single_horn_1(_) ->\n   datalog(\n      \"?- a(_, _). p(x, y). a(x, y) :- p(x, y).\",\n      [{1, 2}, {2, 3}, {3, 4}, {4, 5}],\n      [{1, 2}, {2, 3}, {3, 4}, {4, 5}]\n   ).\n\npredicate_single_horn_2(_) ->\n   datalog(\n      \"?- a(_, _). p(x, y). a(x, y) :- p(x, z), p(z, y).\",\n      [{1, 2}, {2, 3}, {3, 4}, {4, 5}],\n      [{1, 3}, {2, 4}, {3, 5}]\n   ).\n\npredicate_single_horn_3(_) ->\n   datalog(\n      \"?- a(_, _). p(x, y). a(x, y) :- p(x, z), p(z, f), p(f, y).\",\n      [{1, 2}, {2, 3}, {3, 4}, {4, 5}],\n      [{1, 4}, {2, 5}]\n   ).\n\n\npredicate_horn_2(_) ->\n   datalog(\n      \"?- b(_, _). p(x, y). a(x, y) :- p(x, y). b(x, y) :- a(x, z), p(z, y).\",\n      [{1, 2}, {2, 3}, {3, 4}, {4, 5}],\n      [{1, 3}, {2, 4}, {3, 5}]\n   ).\n\npredicate_horn_3(_) ->\n   datalog(\n      \"?- c(_, _). p(x, y). a(x, y) :- p(x, y). b(x, y) :- a(x, z), p(z, y). c(x, y) :- b(x, z), p(z, y).\",\n      [{1, 2}, {2, 3}, {3, 4}, {4, 5}],\n      [{1, 4}, {2, 5}]\n   ).\n\ncartesian_product(_) ->\n   datalog(\n      \"?- h(_,_). p(x). h(x,y) :- p(x), p(y).\",\n      [{1}, {2}, {3}],\n      [{1,1}, {1,2}, {1,3}, {2,1}, {2,2}, {2,3}, {3,1}, {3,2}, {3,3}]\n   ).\n\n%%\n%%\ninfix_eq(_) ->\n   datalog(\n      \"?- h(_). p(x). h(x) :- p(x), x = 2.\",\n      [{1}, {2}, {3}, {4}],\n      [{2}]\n   ).\n\ninfix_lt(_) ->\n   datalog(\n      \"?- h(_). p(x). h(x) :- p(x), x < 3.\",\n      [{1}, {2}, {3}, {4}],\n      [{1}, {2}]\n   ).\n\ninfix_le(_) ->\n   datalog(\n      \"?- h(_). p(x). h(x) :- p(x), x =< 2.\",\n      [{1}, {2}, {3}, {4}],\n      [{1}, {2}]\n   ).\n\ninfix_gt(_) ->\n   datalog(\n      \"?- h(_). p(x). h(x) :- p(x), x > 2.\",\n      [{1}, {2}, {3}, {4}],\n      [{3}, {4}]\n   ).\n\ninfix_ge(_) ->\n   datalog(\n      \"?- h(_). p(x). h(x) :- p(x), x >= 3.\",\n      [{1}, {2}, {3}, {4}],\n      [{3}, {4}]\n   ).\n\ninfix_ne(_) ->\n   datalog(\n      \"?- h(_). p(x). h(x) :- p(x), x != 2.\",\n      [{1}, {2}, {3}, {4}],\n      [{1}, {3}, {4}]\n   ).\n\n\n%%\n%%\nunion_2(_) ->\n   datalog(\n      \"?- a(_, _). p(x,y). a(x,y) :- p(x,y), x > 2. a(x,y) :- p(x,y).\",\n      [{1,2}, {2,3}, {3,4}, {4,5}],\n      [{3,4}, {4,5}, {1,2}, {2,3}, {3,4}, {4,5}]\n   ).\n\nunion_3(_) ->\n   datalog(\n      \"?- a(_, _). p(x,y). a(x,y) :- p(x,y), x > 2. a(x,y) :- p(x,y), x < 3. a(x,y) :- p(x,y).\",\n      [{1,2}, {2,3}, {3,4}, {4,5}],\n      [{3,4}, {4,5}, {1,2}, {2,3}, {1,2}, {2,3}, {3,4}, {4,5}]\n   ).\n\n%%\n%%\nrecursion_1(_) ->\n   datalog(\n      \"?- a(_, _). p(x,y). a(x, y) :- p(x, y). a(x, y) :- p(x, z), a(z, y).\",\n      [{1,2}, {2,3}, {3,2}],\n      [{1,2}, {2,3}, {1,3}, {3,3}, {3,2}, {2,2}]\n   ).\n\nrecursion_2(_) ->\n   datalog(\n      \"?- a(_, _). p(x,y). a(x, y) :- p(x, y). a(x, y) :- p(x, z), a(z, y).\",\n      [{1,2}, {2,3}, {3,4}, {4,5}],\n      [{1,2}, {2,3}, {1,3}, {3,4}, {2,4}, {1,4}, {4,5}, {3,5}, {2,5}, {1,5}]\n   ).\n\nrecursion_3(_) ->\n   datalog(\n      \"?- a(_, _). p(x,y). a(x, y) :- p(x, y). a(x, y) :- p(x, z), a(z, y).\",\n      [{1,2}, {2,3}, {2,5}, {3,4}, {4,2}, {5,4}],\n      [{1,2}, {2,3}, {1,3}, {4,3}, {3,3}, {5,3}, {2,5}, {1,5}, {4,5}, {3,5}, {5,5}, {3,4}, {2,4}, {1,4}, {4,4}, {5,4}, {4,2}, {3,2}, {2,2}, {5,2}]\n   ).\n\n%%\n%%\nsource_semantic_web(_) ->\n   datalog(\n      \"?- schema:person(_, _). foaf:person('rdf:id, 'foaf:name). schema:person('rdf:id, 'foaf:name) :- foaf:person('rdf:id, 'foaf:name).\",\n      [{1,2}, {2,3}, {3,4}],\n      [{1,2}, {2,3}, {3,4}]\n   ).\n\nsource_native(_) ->\n   datalog(\n      \"?- a(_, _). foo.p(x, y). bar.p(x, y). a(x, y) :- foo.p(x, z), bar.p(z, y).\",\n      [{1,2}, {2,3}, {3,4}, {4,5}],\n      [{1,3}, {2,4}, {3,5}]\n   ).\n\n%%\n%%\nlang_eq(_) ->\n   datalog(\n      \"?- a(_, _). p(x). a(x, y) :- p(x), p(y), .eq(x, y).\",\n      [{1}, {2}, {3}, {4}],\n      [{1,1}, {2,2}, {3,3}, {4,4}]\n   ).\n\nlang_ne(_) ->\n   datalog(\n      \"?- a(_, _). p(x). a(x, y) :- p(x), p(y), .ne(x, y).\",\n      [{1}, {2}],\n      [{1,2}, {2,1}]\n   ).\n\nlang_lt(_) ->\n   datalog(\n      \"?- a(_, _). p(x). a(x, y) :- p(x), p(y), .lt(x, y).\",\n      [{1}, {2}, {3}, {4}],\n      [{1,2}, {1,3}, {1,4}, {2,3}, {2,4}, {3,4}]\n   ).\n\nlang_gt(_) ->\n   datalog(\n      \"?- a(_, _). p(x). a(x, y) :- p(x), p(y), .gt(x, y).\",\n      [{1}, {2}, {3}, {4}],\n      [{2,1}, {3,1}, {3,2}, {4,1}, {4,2}, {4,3}]\n   ).\n\nlang_le(_) ->\n   datalog(\n      \"?- a(_, _). p(x). a(x, y) :- p(x), p(y), .le(x, y).\",\n      [{1}, {2}, {3}, {4}],\n      [{1,1}, {1,2}, {1,3}, {1,4}, {2,2}, {2,3}, {2,4}, {3,3}, {3,4}, {4,4}]\n   ).\n\nlang_ge(_) ->\n   datalog(\n      \"?- a(_, _). p(x). a(x, y) :- p(x), p(y), .ge(x, y).\",\n      [{1}, {2}, {3}, {4}],\n      [{1,1}, {2,1}, {2,2}, {3,1}, {3,2}, {3,3}, {4,1}, {4,2}, {4,3}, {4,4}]\n   ).\n\nlang_unique(_) ->\n   datalog(\n      \"?- a(_). p(x). a(x) :- p(x), .unique(x).\",\n      [{1}, {2}, {1}, {3}, {1}, {2}, {4}, {1}, {2}, {3}],\n      [{1}, {2}, {3}, {4}]\n   ).\n\nlang_flat(_) ->\n   datalog(\n      \"?- a(_). p(x). a(x) :- p(x), .flat(x).\",\n      [{[1, 2]}, {[2, 3]}, {[3, 4]}],\n      [{1}, {2}, {2}, {3}, {3}, {4}]\n   ).\n"
  },
  {
    "path": "test/datalog_parser_SUITE.erl",
    "content": "%%\n%%   Copyright 2014 - 2015 Dmitry Kolesnikov, All Rights Reserved\n%%\n%%   Licensed under the Apache License, Version 2.0 (the \"License\");\n%%   you may not use this file except in compliance with the License.\n%%   You may obtain a copy of the License at\n%%\n%%       http://www.apache.org/licenses/LICENSE-2.0\n%%\n%%   Unless required by applicable law or agreed to in writing, software\n%%   distributed under the License is distributed on an \"AS IS\" BASIS,\n%%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n%%   See the License for the specific language governing permissions and\n%%   limitations under the License.\n%%\n%% @doc\n%%   datalog parser test suite\n-module(datalog_parser_SUITE).\n-include_lib(\"common_test/include/ct.hrl\").\n\n%% common test\n-export([all/0]).\n-export([\n   goal/1,\n   stream/1,\n   stream_native/1,\n   stream_semantic/1,\n   horn_1/1, \n   horn_n/1,\n   horn_0/1,\n   inline_string/1, \n   inline_int/1, \n   inline_float/1,\n   anything/1,\n   guard_eq_string/1, \n   guard_eq_tuple_of_string/1,\n   guard_eq_int/1, \n   guard_eq_float/1,\n   guard_gt_string/1, \n   guard_gt_int/1, \n   guard_gt_float/1,         \n   guard_string/1, \n   guard_number/1,\n   bif_datalog/1, \n   bif_external/1,\n   semantic_web/1,\n   jsonld/1,\n   constant_xsd_absolute_uri/1,\n   constant_xsd_compact_uri/1,\n   constant_xsd_string/1,\n   constant_xsd_lang_string/1,\n   constant_xsd_integer/1,\n   constant_xsd_decimal/1,\n   constant_xsd_boolean/1,\n   constant_xsd_datetime/1,\n   constant_xsd_date/1,\n   constant_xsd_yearmonth/1,\n   constant_xsd_monthdate/1,\n   constant_xsd_time/1,\n   constant_xsd_seq/1,\n   constant_xsd_map/1,\n   constant_xsd_list/1,\n   aggregation/1\n]).\n\n%%%----------------------------------------------------------------------------   \n%%%\n%%% factory\n%%%\n%%%----------------------------------------------------------------------------   \n\nall() ->\n   [Test || {Test, NAry} <- ?MODULE:module_info(exports), \n      Test =/= module_info,\n      NAry =:= 1\n   ].\n\n%%%----------------------------------------------------------------------------   \n%%%\n%%% unit test\n%%%\n%%%----------------------------------------------------------------------------   \n\n%%\n%%\ngoal(_) ->\n   [\n      {goal, h, [x,y]}\n   ] = datalog:p(\"?- h(x, y).\").\n\n%%\n%%\nstream(_) ->\n   [\n      {source, p, [x, y]},\n      {source, p, []}\n   ] = datalog:p(\"p(x, y). p().\").\n\nstream_native(_) ->\n   [\n      {source, {datalog, a}, []},\n      {source, {mod, a}, [<<\"x\">>, <<\"y\">>]}\n   ] = datalog:p(\".a(). mod.a(\\\"x\\\", \\\"y\\\").\").\n\nstream_semantic(_) ->\n   [\n      {source, {iri, <<\"foaf\">>, <<\"person\">>}, [x, y]}\n   ] = datalog:p(\"foaf:person(x, y).\").\n\n%%\n%%\nhorn_1(_Config) ->\n   [\n      {horn, h, [x,y], [ \n         #{'@' := a, '_' := [x,y]}\n      ]}\n   ] = datalog:p(\"h(x,y) :- a(x, y).\").\n\nhorn_n(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z).\").\n\n\nhorn_0(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y]},\n         #{'@' := b, '_' := []}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b().\").\n\n%%\n%%\ninline_string(_Config) ->\n   [\n      {horn, h, [z], [ \n         #{'@' := a, '_' := [<<\"x\">>,y]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(z) :- a(\\\"x\\\", y), b(y, z).\").\n\ninline_int(_Config) ->\n   [\n      {horn, h, [z], [ \n         #{'@' := a, '_' := [100,y]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(z) :- a(100, y), b(y, z).\").\n\ninline_float(_Config) ->\n   [\n      {horn, h, [z], [ \n         #{'@' := a, '_' := [1.0,y]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(z) :- a(1.0, y), b(y, z).\").\n\n%%\n%%\nanything(_Config) ->\n   [\n      {horn, h, [z], [ \n         #{'@' := a, '_' := ['_',y]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(z) :- a(_, y), b(y, z).\").\n\n%%\n%%\nguard_eq_string(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := <<\"x\">>},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x = \\\"x\\\".\").\n\nguard_eq_tuple_of_string(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := {<<\"x\">>, <<\"y\">>, <<\"z\">>}},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x = (\\\"x\\\", \\\"y\\\", \\\"z\\\").\").\n\n\nguard_eq_int(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := 100},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x = 100.\").\n\nguard_eq_float(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := 1.0},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x = 1.0.\").\n\n%%\n%%\nguard_gt_string(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := [{'>', <<\"x\">>}]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x > \\\"x\\\".\").\n\nguard_gt_int(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := [{'>', 100}]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x > 100.\").\n\nguard_gt_float(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := [{'>', 1.0}]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x > 1.0.\").\n\n\n%%\n%%\nguard_string(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := [{'>=', <<\"x\">>}, {'=<', <<\"z\">>}]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x >= \\\"x\\\", x =< \\\"z\\\" .\").\n\nguard_number(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := a, '_' := [x,y], x := [{'>=', 1.0}, {'=<', 100}]},\n         #{'@' := b, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- a(x, y), b(y, z), x >= 1.0, x =< 100.\").\n\n\n%%\n%%\nbif_datalog(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := {datalog, a}, '_' := [x,y]},\n         #{'@' := {datalog, b}, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- .a(x, y), .b(y, z).\").\n\nbif_external(_Config) ->\n   [\n      {horn, h, [x,z], [ \n         #{'@' := {mod, a}, '_' := [x,y]},\n         #{'@' := {mod, b}, '_' := [y,z]}\n      ]}\n   ] = datalog:p(\"h(x,z) :- mod.a(x, y), mod.b(y, z).\").\n\n%%\n%%\nsemantic_web(_Config) ->\n   [\n      {horn, \n         {iri, <<\"foaf\">>, <<\"person\">>}, \n         [{iri, <<\"rdf\">>, <<\"id\">>}, {iri, <<\"foaf\">>, <<\"name\">>}],\n         [\n            #{\n               '@' := {iri, <<\"foaf\">>, <<\"person\">>},\n               '_' := [{iri, <<\"rdf\">>, <<\"id\">>}, {iri, <<\"foaf\">>, <<\"name\">>}], \n               {iri, <<\"foaf\">>, <<\"name\">>} := [{'>', <<\"A\">>}, {'<', <<\"B\">>}]\n            }\n         ]\n      }\n   ] = datalog:p(\"foaf:person(rdf:id, foaf:name) :- foaf:person(rdf:id, foaf:name), foaf:name > \\\"A\\\", foaf:name < \\\"B\\\".\").\n\n%%\n%%\njsonld(_Config) ->\n   [\n      {horn, h, ['@id',z], [ \n         #{'@' := a, '_' := ['@id', '@type']},\n         #{'@' := b, '_' := ['@type', z]}\n      ]}\n   ] = datalog:p(\"h(@id,z) :- a(@id, @type), b(@type, z).\").\n\n%%\n%%\nconstant_xsd_absolute_uri(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := {iri, <<\"http://example.com/a\">>}}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = <http://example.com/a>.\").\n\nconstant_xsd_compact_uri(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := {iri, <<\"example\">>, <<\"a\">>}}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = example:a.\").\n\nconstant_xsd_string(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := <<\"example\">>}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = \\\"example\\\".\").\n\nconstant_xsd_lang_string(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := <<\"example\">>}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = \\\"example\\\"@en.\").\n\nconstant_xsd_integer(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := 123}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = 123.\").\n\nconstant_xsd_decimal(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := 12.3}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = 12.3.\").\n\nconstant_xsd_boolean(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x, y], x := true, y := false}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x, y), x = true, y = false.\").\n\nconstant_xsd_datetime(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := {1175,783410,0}}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = 2007-04-05T14:30:10Z.\").\n\nconstant_xsd_date(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := {{2007,4,5},{0,0,0}}}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = 2007-04-05.\").\n\nconstant_xsd_yearmonth(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := {{2007,4,0},{0,0,0}}}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = 2007-04.\").\n\nconstant_xsd_monthdate(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := {{0,4,5},{0,0,0}}}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = --04-05.\").\n\nconstant_xsd_time(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := {{0,0,0},{14,30,10}}}\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = 14:30:10Z.\").\n\nconstant_xsd_seq(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := {154, 7623, 23} }\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = (154, 7623, 23).\").\n\nconstant_xsd_map(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := #{<<\"type\">> := <<\"Point\">>, <<\"coordinates\">> := [21.3, 60.2]} }\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = {type:\\\"Point\\\", coordinates:[21.3, 60.2]}.\").\n\nconstant_xsd_list(_) ->\n   [\n      {horn, h, [x], [\n         #{'@' := a, '_' := [x], x := [1, <<\"a\">>, 3.2] }\n      ]}\n   ] = datalog:p(\"h(x) :- a(x), x = [1, \\\"a\\\", 3.2].\").\n\n%%\n%%\naggregation(_) ->\n   [\n      {source, p, [\n         id,\n         {count, <<\"x\">>},\n         {stats, <<\"y\">>},\n         {category, 10, <<\"z\">>}\n      ]}\n   ] = datalog:p(\"p(id, count \\\"x\\\", stats \\\"y\\\", category 10 \\\"z\\\").\").\n\n"
  },
  {
    "path": "test/tests.config",
    "content": "%%\n%% suites\n{suites, \".\", all}.\n"
  }
]