You've already forked libart-query
This commit is contained in:
17
.editorconfig
Normal file
17
.editorconfig
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
indent_size = 4
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.yaml]
|
||||||
|
indent_size = 2
|
||||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* text=auto
|
||||||
31
.gitea/workflows/on-push.yaml
Normal file
31
.gitea/workflows/on-push.yaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: on-push
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags-ignore:
|
||||||
|
- '*'
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-test:
|
||||||
|
runs-on: linux
|
||||||
|
container: code.helloryan.se/art/infra/buildenv/x86_64-fedora_42-unified:latest
|
||||||
|
volumes:
|
||||||
|
- /build
|
||||||
|
steps:
|
||||||
|
- name: Configure repository access
|
||||||
|
run: |
|
||||||
|
git config --global http.$GITHUB_SERVER_URL/.extraheader "Authorization: token ${{ secrets.ACT_RUNNER_TOKEN }}"
|
||||||
|
- name: Configure build directory
|
||||||
|
run: |
|
||||||
|
bpkg create -d /build cc config.cxx=clang++ config.cc.coptions="-Wall -Werror -Wno-unknown-pragmas"
|
||||||
|
- name: Build package
|
||||||
|
run: |
|
||||||
|
cd /build
|
||||||
|
bpkg build --yes --trust-yes $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git##$GITHUB_SHA
|
||||||
|
- name: Test package
|
||||||
|
run: |
|
||||||
|
cd /build
|
||||||
|
b test
|
||||||
|
|
||||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
patreon: helloryan
|
||||||
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
.bdep/
|
||||||
|
|
||||||
|
# Local default options files.
|
||||||
|
#
|
||||||
|
.build2/local/
|
||||||
|
|
||||||
|
# Compiler/linker output.
|
||||||
|
#
|
||||||
|
*.d
|
||||||
|
*.t
|
||||||
|
*.i
|
||||||
|
*.i.*
|
||||||
|
*.ii
|
||||||
|
*.ii.*
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.gcm
|
||||||
|
*.pcm
|
||||||
|
*.ifc
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
*.exp
|
||||||
|
*.pdb
|
||||||
|
*.ilk
|
||||||
|
*.exe
|
||||||
|
*.exe.dlls/
|
||||||
|
*.exe.manifest
|
||||||
|
*.pc
|
||||||
31
LICENSE
Normal file
31
LICENSE
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
Copyright © 2024 Ryan. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. All advertising materials mentioning features or use of this software must
|
||||||
|
display the following acknowledgement:
|
||||||
|
|
||||||
|
This product includes software developed by Ryan, http://helloryan.se/.
|
||||||
|
|
||||||
|
4. Neither the name(s) of the copyright holder(s) nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||||
|
NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
10
README.md
Normal file
10
README.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# libart-query
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
libart-query implements a simple query language.
|
||||||
|
|
||||||
|
## Sponsorship
|
||||||
|
|
||||||
|
You can sponsor the development of this project via Patreon. Read more
|
||||||
|
over at https://patreon.com/helloryan.
|
||||||
9
art/query/.gitignore
vendored
Normal file
9
art/query/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Generated version header.
|
||||||
|
#
|
||||||
|
version.hxx
|
||||||
|
|
||||||
|
# Unit test executables and Testscript output directories
|
||||||
|
# (can be symlinks).
|
||||||
|
#
|
||||||
|
*.test
|
||||||
|
test-*.test
|
||||||
62
art/query/buildfile
Normal file
62
art/query/buildfile
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
intf_libs = # Interface dependencies.
|
||||||
|
impl_libs = # Implementation dependencies.
|
||||||
|
|
||||||
|
./: lib{art-query}: libul{art-query}
|
||||||
|
|
||||||
|
libul{art-query}: {hxx ixx txx cxx}{** -**.test... -version} \
|
||||||
|
{hxx }{ version}
|
||||||
|
|
||||||
|
libul{art-query}: $impl_libs $intf_libs
|
||||||
|
|
||||||
|
# Unit tests.
|
||||||
|
#
|
||||||
|
exe{*.test}:
|
||||||
|
{
|
||||||
|
test = true
|
||||||
|
install = false
|
||||||
|
}
|
||||||
|
|
||||||
|
for t: cxx{**.test...}
|
||||||
|
{
|
||||||
|
d = $directory($t)
|
||||||
|
n = $name($t)...
|
||||||
|
|
||||||
|
./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n}
|
||||||
|
$d/exe{$n}: libul{art-query}: bin.whole = false
|
||||||
|
}
|
||||||
|
|
||||||
|
hxx{version}: in{version} $src_root/manifest
|
||||||
|
{
|
||||||
|
dist = true
|
||||||
|
clean = ($src_root != $out_root)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build options.
|
||||||
|
#
|
||||||
|
cxx.poptions =+ "-I$out_root" "-I$src_root"
|
||||||
|
|
||||||
|
# Export options.
|
||||||
|
#
|
||||||
|
lib{art-query}:
|
||||||
|
{
|
||||||
|
cxx.export.poptions = "-I$out_root" "-I$src_root"
|
||||||
|
cxx.export.libs = $intf_libs
|
||||||
|
}
|
||||||
|
|
||||||
|
# For pre-releases use the complete version to make sure they cannot
|
||||||
|
# be used in place of another pre-release or the final version. See
|
||||||
|
# the version module for details on the version.* variable values.
|
||||||
|
#
|
||||||
|
if $version.pre_release
|
||||||
|
lib{art-query}: bin.lib.version = "-$version.project_id"
|
||||||
|
else
|
||||||
|
lib{art-query}: bin.lib.version = "-$version.major.$version.minor"
|
||||||
|
|
||||||
|
# Install into the art/query/ subdirectory of, say, /usr/include/
|
||||||
|
# recreating subdirectories.
|
||||||
|
#
|
||||||
|
{hxx ixx txx}{*}:
|
||||||
|
{
|
||||||
|
install = include/art/query/
|
||||||
|
install.subdirs = true
|
||||||
|
}
|
||||||
46
art/query/error.cxx
Normal file
46
art/query/error.cxx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include <art/query/error.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
warning_t::
|
||||||
|
warning_t(source_location_t origin, string description)
|
||||||
|
: origin_{std::move(origin)},
|
||||||
|
description_{std::move(description)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
warning_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return origin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string const&
|
||||||
|
warning_t::
|
||||||
|
description() const
|
||||||
|
{
|
||||||
|
return description_;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t::
|
||||||
|
error_t(source_location_t origin, string description)
|
||||||
|
: origin_{std::move(origin)},
|
||||||
|
description_{std::move(description)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
error_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return origin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string const&
|
||||||
|
error_t::
|
||||||
|
description() const
|
||||||
|
{
|
||||||
|
return description_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
46
art/query/error.hxx
Normal file
46
art/query/error.hxx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef art__query__error_hxx_
|
||||||
|
#define art__query__error_hxx_
|
||||||
|
|
||||||
|
#include <art/query/source-location.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class warning_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
warning_t(source_location_t, string);
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
string const&
|
||||||
|
description() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location_t origin_;
|
||||||
|
string description_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class error_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
error_t(source_location_t source, string);
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
string const&
|
||||||
|
description() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location_t origin_;
|
||||||
|
string description_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
25
art/query/expression.cxx
Normal file
25
art/query/expression.cxx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include <art/query/expression.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
expression_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return container_->origin_();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
accept(expression_t const& e, visitor_t& v)
|
||||||
|
{
|
||||||
|
e.container_->accept_(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(expression_t const& e)
|
||||||
|
{
|
||||||
|
return e.container_->to_string_();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
94
art/query/expression.hxx
Normal file
94
art/query/expression.hxx
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#ifndef art__query__expression_hxx_
|
||||||
|
#define art__query__expression_hxx_
|
||||||
|
|
||||||
|
#include <art/query/error.hxx>
|
||||||
|
#include <art/query/source-location.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
#include <art/query/visitor.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class expression_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename E>
|
||||||
|
expression_t(E e)
|
||||||
|
: container_{make_shared<container_t<E>>(std::move(e))}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
friend
|
||||||
|
void
|
||||||
|
accept(expression_t const&, visitor_t&);
|
||||||
|
|
||||||
|
friend
|
||||||
|
string
|
||||||
|
to_string(expression_t const&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct abstract_t
|
||||||
|
{
|
||||||
|
virtual
|
||||||
|
~abstract_t() noexcept = default;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
source_location_t const&
|
||||||
|
origin_() const = 0;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
accept_(visitor_t& v) const = 0;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
string
|
||||||
|
to_string_() const = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename E>
|
||||||
|
struct container_t
|
||||||
|
: abstract_t
|
||||||
|
{
|
||||||
|
explicit
|
||||||
|
container_t(E e)
|
||||||
|
: e{std::move(e)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
~container_t() noexcept override
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin_() const override
|
||||||
|
{
|
||||||
|
return e.origin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
accept_(visitor_t& v) const override
|
||||||
|
{
|
||||||
|
if (auto c = dynamic_cast<basic_visitor_t<E>*>(&v); c) {
|
||||||
|
c->visit(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
v.visit_default();
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string_() const override
|
||||||
|
{
|
||||||
|
return to_string(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
E e;
|
||||||
|
};
|
||||||
|
|
||||||
|
shared_ptr<abstract_t const> container_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
134
art/query/lexical-analyzer.cxx
Normal file
134
art/query/lexical-analyzer.cxx
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
#include <art/query/lexical-analyzer.hxx>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
lexical_analyzer_t::
|
||||||
|
~lexical_analyzer_t() noexcept = default;
|
||||||
|
|
||||||
|
token_t
|
||||||
|
lexical_analyzer_t::
|
||||||
|
peek()
|
||||||
|
{
|
||||||
|
if (!current_)
|
||||||
|
current_ = extract();
|
||||||
|
|
||||||
|
return *current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lexical_analyzer_t::
|
||||||
|
consume()
|
||||||
|
{
|
||||||
|
current_ = extract();
|
||||||
|
}
|
||||||
|
|
||||||
|
lexical_analyzer_t::
|
||||||
|
lexical_analyzer_t() = default;
|
||||||
|
|
||||||
|
token_t
|
||||||
|
lexical_analyzer_t::
|
||||||
|
extract()
|
||||||
|
{
|
||||||
|
char_type c = peek_char();
|
||||||
|
|
||||||
|
while (is_whitespace(c)) {
|
||||||
|
consume_char();
|
||||||
|
c = peek_char();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return token_t{token_type_t::end};
|
||||||
|
|
||||||
|
if (c == ':') {
|
||||||
|
consume_char();
|
||||||
|
return token_t{token_type_t::colon};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '(') {
|
||||||
|
consume_char();
|
||||||
|
return token_t{token_type_t::open_parens};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == ')') {
|
||||||
|
consume_char();
|
||||||
|
return token_t{token_type_t::close_parens};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '"') {
|
||||||
|
consume_char();
|
||||||
|
|
||||||
|
c = peek_char();
|
||||||
|
|
||||||
|
std::stringstream str;
|
||||||
|
|
||||||
|
while (c != 0 && c != '"') {
|
||||||
|
str << (char)c; // FIXME: UTF-8 encode.
|
||||||
|
consume_char();
|
||||||
|
c = peek_char();
|
||||||
|
}
|
||||||
|
|
||||||
|
consume_char();
|
||||||
|
|
||||||
|
return token_t{token_type_t::quoted_term, str.str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream str;
|
||||||
|
|
||||||
|
while (c != 0 && !is_whitespace(c) && c != '(' && c != ')' && c != ':') {
|
||||||
|
consume_char();
|
||||||
|
str << (char)c; // FIXME: UFT-8 encode.
|
||||||
|
c = peek_char();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto term = str.str();
|
||||||
|
|
||||||
|
auto lower = [](string str)
|
||||||
|
{
|
||||||
|
for (auto& j : str) {
|
||||||
|
j = std::tolower(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lower(term) == "and")
|
||||||
|
return token_t{token_type_t::logical_and};
|
||||||
|
|
||||||
|
if (lower(term) == "or")
|
||||||
|
return token_t{token_type_t::logical_or};
|
||||||
|
|
||||||
|
if (lower(term) == "not")
|
||||||
|
return token_t{token_type_t::logical_not};
|
||||||
|
|
||||||
|
return token_t{token_type_t::simple_term, std::move(term)};
|
||||||
|
}
|
||||||
|
|
||||||
|
lexical_analyzer_t::char_type
|
||||||
|
lexical_analyzer_t::
|
||||||
|
peek_char()
|
||||||
|
{
|
||||||
|
if (!next_char_)
|
||||||
|
next_char_ = extract_char();
|
||||||
|
|
||||||
|
return *next_char_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lexical_analyzer_t::
|
||||||
|
consume_char()
|
||||||
|
{
|
||||||
|
next_char_ = extract_char();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
lexical_analyzer_t::
|
||||||
|
is_whitespace(char_type c)
|
||||||
|
{
|
||||||
|
return c == ' ' || c == '\t' || c == '\v';
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
94
art/query/lexical-analyzer.hxx
Normal file
94
art/query/lexical-analyzer.hxx
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#ifndef art__query__lexical_analyzer_hxx_
|
||||||
|
#define art__query__lexical_analyzer_hxx_
|
||||||
|
|
||||||
|
#include <art/query/token.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class lexical_analyzer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using char_type = uint32_t;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
~lexical_analyzer_t() noexcept;
|
||||||
|
|
||||||
|
token_t
|
||||||
|
peek();
|
||||||
|
|
||||||
|
void
|
||||||
|
consume();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
lexical_analyzer_t();
|
||||||
|
|
||||||
|
lexical_analyzer_t(lexical_analyzer_t const&) = delete;
|
||||||
|
lexical_analyzer_t(lexical_analyzer_t&&) = delete;
|
||||||
|
|
||||||
|
token_t
|
||||||
|
extract();
|
||||||
|
|
||||||
|
char_type
|
||||||
|
peek_char();
|
||||||
|
|
||||||
|
void
|
||||||
|
consume_char();
|
||||||
|
|
||||||
|
virtual
|
||||||
|
char_type
|
||||||
|
extract_char() = 0;
|
||||||
|
|
||||||
|
lexical_analyzer_t& operator=(lexical_analyzer_t const&) = delete;
|
||||||
|
lexical_analyzer_t& operator=(lexical_analyzer_t&&) = delete;
|
||||||
|
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
is_whitespace(char_type);
|
||||||
|
|
||||||
|
private:
|
||||||
|
optional<char_type> next_char_;
|
||||||
|
optional<token_t> current_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Iterator, typename EndIterator = Iterator>
|
||||||
|
class basic_lexical_analyzer_t
|
||||||
|
: public lexical_analyzer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using iterator = Iterator;
|
||||||
|
using end_iterator = EndIterator;
|
||||||
|
|
||||||
|
basic_lexical_analyzer_t(iterator, end_iterator);
|
||||||
|
|
||||||
|
basic_lexical_analyzer_t(basic_lexical_analyzer_t const&);
|
||||||
|
|
||||||
|
basic_lexical_analyzer_t(basic_lexical_analyzer_t&&);
|
||||||
|
|
||||||
|
~basic_lexical_analyzer_t() noexcept override;
|
||||||
|
|
||||||
|
basic_lexical_analyzer_t&
|
||||||
|
operator=(basic_lexical_analyzer_t const&) = delete;
|
||||||
|
|
||||||
|
basic_lexical_analyzer_t&
|
||||||
|
operator=(basic_lexical_analyzer_t&&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
char_type
|
||||||
|
extract_char() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
iterator current_;
|
||||||
|
end_iterator end_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
using string_lexical_analyzer_t = basic_lexical_analyzer_t<string::const_iterator>;
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#include <art/query/lexical-analyzer.txx>
|
||||||
|
|
||||||
|
#endif
|
||||||
40
art/query/lexical-analyzer.txx
Normal file
40
art/query/lexical-analyzer.txx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename I, typename E>
|
||||||
|
basic_lexical_analyzer_t<I, E>::
|
||||||
|
basic_lexical_analyzer_t(iterator begin, end_iterator end)
|
||||||
|
: current_{std::move(begin)},
|
||||||
|
end_{std::move(end)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename I, typename E>
|
||||||
|
basic_lexical_analyzer_t<I, E>::
|
||||||
|
basic_lexical_analyzer_t(basic_lexical_analyzer_t const& other)
|
||||||
|
: current_{other.current_},
|
||||||
|
end_{other.end_}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename I, typename E>
|
||||||
|
basic_lexical_analyzer_t<I, E>::
|
||||||
|
basic_lexical_analyzer_t(basic_lexical_analyzer_t&& other)
|
||||||
|
: current_{std::move(other.current_)},
|
||||||
|
end_{std::move(other.end_)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename I, typename E>
|
||||||
|
basic_lexical_analyzer_t<I, E>::
|
||||||
|
~basic_lexical_analyzer_t() noexcept = default;
|
||||||
|
|
||||||
|
template<typename I, typename E>
|
||||||
|
basic_lexical_analyzer_t<I, E>::char_type
|
||||||
|
basic_lexical_analyzer_t<I, E>::
|
||||||
|
extract_char()
|
||||||
|
{
|
||||||
|
if (current_ == end_)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return *current_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
56
art/query/logical-and.cxx
Normal file
56
art/query/logical-and.cxx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include <art/query/logical-and.hxx>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
logical_and_t::
|
||||||
|
logical_and_t(expression_t left, expression_t right)
|
||||||
|
: left_{std::move(left)},
|
||||||
|
right_{std::move(right)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
logical_and_t::
|
||||||
|
logical_and_t(source_location_t origin,
|
||||||
|
expression_t left,
|
||||||
|
expression_t right)
|
||||||
|
: origin_{std::move(origin)},
|
||||||
|
left_{std::move(left)},
|
||||||
|
right_{std::move(right)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
logical_and_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return origin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
logical_and_t::
|
||||||
|
left() const
|
||||||
|
{
|
||||||
|
return left_;
|
||||||
|
}
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
logical_and_t::
|
||||||
|
right() const
|
||||||
|
{
|
||||||
|
return right_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(logical_and_t const& e)
|
||||||
|
{
|
||||||
|
std::stringstream str;
|
||||||
|
|
||||||
|
str << to_string(e.left());
|
||||||
|
str << " AND ";
|
||||||
|
str << to_string(e.right());
|
||||||
|
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
39
art/query/logical-and.hxx
Normal file
39
art/query/logical-and.hxx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef art__query__logical_and_hxx_
|
||||||
|
#define art__query__logical_and_hxx_
|
||||||
|
|
||||||
|
#include <art/query/expression.hxx>
|
||||||
|
#include <art/query/source-location.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class logical_and_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
logical_and_t(expression_t, expression_t);
|
||||||
|
|
||||||
|
logical_and_t(source_location_t, expression_t, expression_t);
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
left() const;
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
right() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location_t origin_;
|
||||||
|
expression_t left_;
|
||||||
|
expression_t right_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(logical_and_t const&);
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
43
art/query/logical-not.cxx
Normal file
43
art/query/logical-not.cxx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include <art/query/logical-not.hxx>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
logical_not_t::
|
||||||
|
logical_not_t(expression_t right)
|
||||||
|
: right_{std::move(right)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
logical_not_t::
|
||||||
|
logical_not_t(source_location_t origin, expression_t right)
|
||||||
|
: origin_{std::move(origin)},
|
||||||
|
right_{std::move(right)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
logical_not_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return origin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
logical_not_t::
|
||||||
|
right() const
|
||||||
|
{
|
||||||
|
return right_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(logical_not_t const& e)
|
||||||
|
{
|
||||||
|
std::stringstream str;
|
||||||
|
|
||||||
|
str << "NOT " << to_string(e.right());
|
||||||
|
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
34
art/query/logical-not.hxx
Normal file
34
art/query/logical-not.hxx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef art__query__logical_not_t_hxx_
|
||||||
|
#define art__query__logical_not_t_hxx_
|
||||||
|
|
||||||
|
#include <art/query/expression.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class logical_not_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit
|
||||||
|
logical_not_t(expression_t);
|
||||||
|
|
||||||
|
logical_not_t(source_location_t, expression_t);
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
right() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location_t origin_;
|
||||||
|
expression_t right_;
|
||||||
|
};
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(logical_not_t const& e);
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
56
art/query/logical-or.cxx
Normal file
56
art/query/logical-or.cxx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include <art/query/logical-or.hxx>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
logical_or_t::
|
||||||
|
logical_or_t(expression_t left, expression_t right)
|
||||||
|
: left_{std::move(left)},
|
||||||
|
right_{std::move(right)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
logical_or_t::
|
||||||
|
logical_or_t(source_location_t origin,
|
||||||
|
expression_t left,
|
||||||
|
expression_t right)
|
||||||
|
: origin_{std::move(origin)},
|
||||||
|
left_{std::move(left)},
|
||||||
|
right_{std::move(right)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
logical_or_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return origin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
logical_or_t::
|
||||||
|
left() const
|
||||||
|
{
|
||||||
|
return left_;
|
||||||
|
}
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
logical_or_t::
|
||||||
|
right() const
|
||||||
|
{
|
||||||
|
return right_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(logical_or_t const& e)
|
||||||
|
{
|
||||||
|
std::stringstream str;
|
||||||
|
|
||||||
|
str << to_string(e.left());
|
||||||
|
str << " or ";
|
||||||
|
str << to_string(e.right());
|
||||||
|
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
39
art/query/logical-or.hxx
Normal file
39
art/query/logical-or.hxx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef art__query__logical_or_hxx_
|
||||||
|
#define art__query__logical_or_hxx_
|
||||||
|
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
#include <art/query/expression.hxx>
|
||||||
|
#include <art/query/source-location.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class logical_or_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
logical_or_t(expression_t, expression_t);
|
||||||
|
|
||||||
|
logical_or_t(source_location_t, expression_t, expression_t);
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
left() const;
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
right() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location_t origin_;
|
||||||
|
expression_t left_;
|
||||||
|
expression_t right_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(logical_or_t const&);
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
88
art/query/match.cxx
Normal file
88
art/query/match.cxx
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#include <art/query/match.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
bool
|
||||||
|
match(query_t const& q, predicate_t const& p)
|
||||||
|
{
|
||||||
|
class matcher_t
|
||||||
|
: public visitor_t,
|
||||||
|
public basic_visitor_t<term_t>,
|
||||||
|
public basic_visitor_t<tag_t>,
|
||||||
|
public basic_visitor_t<logical_and_t>,
|
||||||
|
public basic_visitor_t<logical_not_t>,
|
||||||
|
public basic_visitor_t<logical_or_t>,
|
||||||
|
public basic_visitor_t<parenthesized_t>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
match(optional<expression_t> const& e, predicate_t const& p)
|
||||||
|
{
|
||||||
|
matcher_t m{p};
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
accept(*e, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit
|
||||||
|
matcher_t(predicate_t const& p)
|
||||||
|
: predicate_{p}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit_default() override
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(term_t const& e) override
|
||||||
|
{
|
||||||
|
result = predicate_(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(tag_t const& e) override
|
||||||
|
{
|
||||||
|
result = predicate_(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(logical_and_t const& e) override
|
||||||
|
{
|
||||||
|
result = match(e.left(), predicate_) && match(e.right(), predicate_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(logical_or_t const& e) override
|
||||||
|
{
|
||||||
|
result = match(e.left(), predicate_) || match(e.right(), predicate_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(logical_not_t const& e) override
|
||||||
|
{
|
||||||
|
result = !match(e.right(), predicate_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(parenthesized_t const& e) override
|
||||||
|
{
|
||||||
|
result = match(e.expr(), predicate_);
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate_t const& predicate_;
|
||||||
|
bool result{};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return matcher_t::match(q.expr(), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
112
art/query/match.hxx
Normal file
112
art/query/match.hxx
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#ifndef art__query__match_hxx_
|
||||||
|
#define art__query__match_hxx_
|
||||||
|
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
#include <art/query/logical-and.hxx>
|
||||||
|
#include <art/query/logical-not.hxx>
|
||||||
|
#include <art/query/logical-or.hxx>
|
||||||
|
#include <art/query/parenthesized.hxx>
|
||||||
|
#include <art/query/query.hxx>
|
||||||
|
#include <art/query/tag.hxx>
|
||||||
|
#include <art/query/term.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
using predicate_t = function<
|
||||||
|
bool(variant<term_t, tag_t> const&)
|
||||||
|
>;
|
||||||
|
|
||||||
|
bool
|
||||||
|
match(query_t const&, predicate_t const&);
|
||||||
|
|
||||||
|
template<typename Q, typename P>
|
||||||
|
Q
|
||||||
|
transform(optional<query_t> const& q, P const& predicate)
|
||||||
|
{
|
||||||
|
class matcher_t
|
||||||
|
: public visitor_t,
|
||||||
|
public basic_visitor_t<term_t>,
|
||||||
|
public basic_visitor_t<tag_t>,
|
||||||
|
public basic_visitor_t<logical_and_t>,
|
||||||
|
public basic_visitor_t<logical_not_t>,
|
||||||
|
public basic_visitor_t<logical_or_t>,
|
||||||
|
public basic_visitor_t<parenthesized_t>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
P const& predicate;
|
||||||
|
|
||||||
|
static
|
||||||
|
Q
|
||||||
|
transform(optional<expression_t> const& e, P const& predicate)
|
||||||
|
{
|
||||||
|
matcher_t m{predicate};
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
accept(*e, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit
|
||||||
|
matcher_t(P const& predicate)
|
||||||
|
: predicate{predicate}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit_default() override
|
||||||
|
{}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(term_t const& term) override
|
||||||
|
{
|
||||||
|
result = predicate(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(tag_t const& tag) override
|
||||||
|
{
|
||||||
|
result = predicate(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(logical_and_t const& logical_and) override
|
||||||
|
{
|
||||||
|
result = transform(logical_and.left(), predicate) && transform(logical_and.right(), predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(logical_or_t const& logical_or) override
|
||||||
|
{
|
||||||
|
result = transform(logical_or.left(), predicate) || transform(logical_or.right(), predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(logical_not_t const& logical_not) override
|
||||||
|
{
|
||||||
|
result = !transform(logical_not.right(), predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
visit(parenthesized_t const& parenthesized) override
|
||||||
|
{
|
||||||
|
result = transform(parenthesized.expr(), predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q result{};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (q) {
|
||||||
|
return matcher_t::transform(q->expr(), predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Q{};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
43
art/query/parenthesized.cxx
Normal file
43
art/query/parenthesized.cxx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include <art/query/parenthesized.hxx>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
parenthesized_t::
|
||||||
|
parenthesized_t(expression_t expr)
|
||||||
|
: expr_{std::move(expr)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
parenthesized_t::
|
||||||
|
parenthesized_t(source_location_t origin, expression_t expr)
|
||||||
|
: origin_{std::move(origin)},
|
||||||
|
expr_{std::move(expr)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
parenthesized_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return origin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
parenthesized_t::
|
||||||
|
expr() const
|
||||||
|
{
|
||||||
|
return expr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(parenthesized_t const& e)
|
||||||
|
{
|
||||||
|
std::stringstream str;
|
||||||
|
|
||||||
|
str << '(' << to_string(e.expr()) << ')';
|
||||||
|
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
35
art/query/parenthesized.hxx
Normal file
35
art/query/parenthesized.hxx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef art__query__parenthesized_hxx_
|
||||||
|
#define art__query__parenthesized_hxx_
|
||||||
|
|
||||||
|
#include <art/query/expression.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class parenthesized_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit
|
||||||
|
parenthesized_t(expression_t);
|
||||||
|
|
||||||
|
parenthesized_t(source_location_t, expression_t);
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
expression_t const&
|
||||||
|
expr() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location_t origin_;
|
||||||
|
expression_t expr_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(parenthesized_t const& e);
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
38
art/query/parse-context.cxx
Normal file
38
art/query/parse-context.cxx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include <art/query/parse-context.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
parse_context_t::
|
||||||
|
parse_context_t()
|
||||||
|
{}
|
||||||
|
|
||||||
|
vector<warning_t> const&
|
||||||
|
parse_context_t::
|
||||||
|
warnings() const
|
||||||
|
{
|
||||||
|
return warnings_;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<error_t> const&
|
||||||
|
parse_context_t::
|
||||||
|
errors() const
|
||||||
|
{
|
||||||
|
return errors_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parse_context_t::
|
||||||
|
report_warning(warning_t w)
|
||||||
|
{
|
||||||
|
warnings_.emplace_back(std::move(w));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parse_context_t::
|
||||||
|
report_error(error_t e)
|
||||||
|
{
|
||||||
|
errors_.emplace_back(std::move(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
36
art/query/parse-context.hxx
Normal file
36
art/query/parse-context.hxx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef art__query__parse_context_hxx_
|
||||||
|
#define art__query__parse_context_hxx_
|
||||||
|
|
||||||
|
#include <art/query/error.hxx>
|
||||||
|
#include <art/query/source-location.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class parse_context_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
parse_context_t();
|
||||||
|
|
||||||
|
vector<warning_t> const&
|
||||||
|
warnings() const;
|
||||||
|
|
||||||
|
vector<error_t> const&
|
||||||
|
errors() const;
|
||||||
|
|
||||||
|
void
|
||||||
|
report_warning(warning_t);
|
||||||
|
|
||||||
|
void
|
||||||
|
report_error(error_t);
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<warning_t> warnings_;
|
||||||
|
vector<error_t> errors_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
16
art/query/parse.cxx
Normal file
16
art/query/parse.cxx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <art/query/parse.hxx>
|
||||||
|
|
||||||
|
#include <art/query/lexical-analyzer.hxx>
|
||||||
|
#include <art/query/syntactical-analyzer.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
query_t
|
||||||
|
try_parse(string const& q, parse_context_t& context)
|
||||||
|
{
|
||||||
|
string_lexical_analyzer_t lexer{q.begin(), q.end()};
|
||||||
|
return syntactical_analyzer_t{lexer, context}.try_parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
16
art/query/parse.hxx
Normal file
16
art/query/parse.hxx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef art__query__parse_hxx_
|
||||||
|
#define art__query__parse_hxx_
|
||||||
|
|
||||||
|
#include <art/query/parse-context.hxx>
|
||||||
|
#include <art/query/query.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
query_t
|
||||||
|
try_parse(string const&, parse_context_t&);
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
54
art/query/query.cxx
Normal file
54
art/query/query.cxx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#include <art/query/query.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
query_t::
|
||||||
|
query_t(optional<expression_t> e,
|
||||||
|
vector<warning_t> warnings,
|
||||||
|
vector<error_t> errors)
|
||||||
|
: expr_{std::move(e)},
|
||||||
|
warnings_{std::move(warnings)},
|
||||||
|
errors_{std::move(errors)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
optional<expression_t> const&
|
||||||
|
query_t::
|
||||||
|
expr() const
|
||||||
|
{
|
||||||
|
return expr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<warning_t> const&
|
||||||
|
query_t::
|
||||||
|
warnings() const
|
||||||
|
{
|
||||||
|
return warnings_;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<error_t> const&
|
||||||
|
query_t::
|
||||||
|
errors() const
|
||||||
|
{
|
||||||
|
return errors_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
accept(query_t const& q, visitor_t& v)
|
||||||
|
{
|
||||||
|
if (q.expr()) {
|
||||||
|
accept(*q.expr(), v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(query_t const& q)
|
||||||
|
{
|
||||||
|
if (q.expr()) {
|
||||||
|
return to_string(*q.expr());
|
||||||
|
}
|
||||||
|
|
||||||
|
return string{};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
43
art/query/query.hxx
Normal file
43
art/query/query.hxx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef art__query__query_hxx_
|
||||||
|
#define art__query__query_hxx_
|
||||||
|
|
||||||
|
#include <art/query/error.hxx>
|
||||||
|
#include <art/query/expression.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
#include <art/query/visitor.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class query_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
query_t(optional<expression_t> e,
|
||||||
|
vector<warning_t> warnings,
|
||||||
|
vector<error_t> errors);
|
||||||
|
|
||||||
|
optional<expression_t> const&
|
||||||
|
expr() const;
|
||||||
|
|
||||||
|
vector<warning_t> const&
|
||||||
|
warnings() const;
|
||||||
|
|
||||||
|
vector<error_t> const&
|
||||||
|
errors() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
optional<expression_t> expr_;
|
||||||
|
vector<warning_t> warnings_;
|
||||||
|
vector<error_t> errors_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
accept(query_t const& q, visitor_t& v);
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(query_t const& q);
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
19
art/query/source-location.hxx
Normal file
19
art/query/source-location.hxx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef art__query__source_location_hxx_
|
||||||
|
#define art__query__source_location_hxx_
|
||||||
|
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
struct source_location_t
|
||||||
|
{
|
||||||
|
string name;
|
||||||
|
uint32_t row{};
|
||||||
|
uint32_t column{};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
283
art/query/syntactical-analyzer.cxx
Normal file
283
art/query/syntactical-analyzer.cxx
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
#include <art/query/logical-and.hxx>
|
||||||
|
#include <art/query/logical-not.hxx>
|
||||||
|
#include <art/query/logical-or.hxx>
|
||||||
|
#include <art/query/parenthesized.hxx>
|
||||||
|
#include <art/query/syntactical-analyzer.hxx>
|
||||||
|
#include <art/query/tag.hxx>
|
||||||
|
#include <art/query/term.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
syntactical_analyzer_t::
|
||||||
|
syntactical_analyzer_t(lexical_analyzer_t& lexer,
|
||||||
|
parse_context_t& context)
|
||||||
|
: lexer_{lexer},
|
||||||
|
context_{context}
|
||||||
|
{}
|
||||||
|
|
||||||
|
lexical_analyzer_t&
|
||||||
|
syntactical_analyzer_t::
|
||||||
|
lexer()
|
||||||
|
{
|
||||||
|
return lexer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_context_t&
|
||||||
|
syntactical_analyzer_t::
|
||||||
|
context()
|
||||||
|
{
|
||||||
|
return context_;
|
||||||
|
}
|
||||||
|
|
||||||
|
query_t
|
||||||
|
syntactical_analyzer_t::
|
||||||
|
try_parse()
|
||||||
|
{
|
||||||
|
auto expr = try_parse_expression();
|
||||||
|
|
||||||
|
if (expr) {
|
||||||
|
auto last = lexer().peek();
|
||||||
|
|
||||||
|
if (last.type() != token_type_t::end) {
|
||||||
|
context().report_warning({{}, "trailing token at end of query"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return query_t{
|
||||||
|
std::move(expr),
|
||||||
|
context().warnings(),
|
||||||
|
context().errors()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<expression_t>
|
||||||
|
syntactical_analyzer_t::
|
||||||
|
try_parse_primary_expression()
|
||||||
|
{
|
||||||
|
optional<expression_t> expr;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
auto t = lexer().peek();
|
||||||
|
|
||||||
|
if (t.type() == token_type_t::end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (t.type() == token_type_t::logical_not) {
|
||||||
|
lexer().consume();
|
||||||
|
|
||||||
|
auto rhs = try_parse_primary_expression();
|
||||||
|
|
||||||
|
if (!rhs) {
|
||||||
|
context().report_warning({{}, "expected expression after NOT"});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr) {
|
||||||
|
expr = logical_and_t{
|
||||||
|
{}, *expr, logical_not_t{{}, *rhs}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expr = logical_not_t{{}, *rhs};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (t.type() == token_type_t::simple_term) {
|
||||||
|
lexer().consume();
|
||||||
|
|
||||||
|
// If the next token is a ':' then this is a tag.
|
||||||
|
//
|
||||||
|
if (lexer().peek().type() == token_type_t::colon) {
|
||||||
|
lexer().consume();
|
||||||
|
|
||||||
|
// consume trailing colons as well.
|
||||||
|
//
|
||||||
|
while (lexer().peek().type() == token_type_t::colon) {
|
||||||
|
lexer().consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto identifier = *t.value();
|
||||||
|
|
||||||
|
// Next expect a term or quoted term.
|
||||||
|
//
|
||||||
|
t = lexer().peek();
|
||||||
|
|
||||||
|
if (t.type() != token_type_t::simple_term &&
|
||||||
|
t.type() != token_type_t::quoted_term) {
|
||||||
|
context().report_warning({{}, "expected simple-term or quoted-term after tag" });
|
||||||
|
lexer().consume();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer().consume();
|
||||||
|
|
||||||
|
// Construct the term
|
||||||
|
//
|
||||||
|
term_t term{
|
||||||
|
{},
|
||||||
|
t.type() == token_type_t::simple_term ? term_t::simple : term_t::quoted,
|
||||||
|
*t.value()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (expr) {
|
||||||
|
expr = logical_or_t{
|
||||||
|
{}, *expr, tag_t{{}, std::move(identifier), std::move(term)}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expr = tag_t{{}, std::move(identifier), std::move(term)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (expr) {
|
||||||
|
expr = logical_or_t{
|
||||||
|
{}, *expr, term_t{{}, term_t::simple, *t.value()}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expr = term_t{{}, term_t::simple, *t.value()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (t.type() == token_type_t::quoted_term) {
|
||||||
|
if (expr) {
|
||||||
|
expr = logical_or_t{
|
||||||
|
{}, *expr, term_t{{}, term_t::quoted, *t.value()}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expr = term_t{{}, term_t::quoted, *t.value()};
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer().consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (t.type() == token_type_t::open_parens) {
|
||||||
|
lexer().consume();
|
||||||
|
|
||||||
|
t = lexer().peek();
|
||||||
|
|
||||||
|
if (t.type() == token_type_t::close_parens) {
|
||||||
|
lexer().consume();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto next_expr = try_parse_expression();
|
||||||
|
|
||||||
|
if (!next_expr) {
|
||||||
|
context().report_warning({{}, "expected expression inside parenthesis"});
|
||||||
|
lexer().consume();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_expr = parenthesized_t{{}, *next_expr};
|
||||||
|
|
||||||
|
if (expr) {
|
||||||
|
expr = logical_or_t{{}, *expr, *next_expr};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expr = next_expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = lexer().peek();
|
||||||
|
if (t.type() != token_type_t::close_parens) {
|
||||||
|
context().report_warning({{}, "expected end parenthesis"});
|
||||||
|
lexer().consume();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer().consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<expression_t>
|
||||||
|
syntactical_analyzer_t::
|
||||||
|
try_parse_logical_and()
|
||||||
|
{
|
||||||
|
auto lhs = try_parse_primary_expression();
|
||||||
|
|
||||||
|
if (!lhs) {
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (lexer().peek().type() == token_type_t::logical_and) {
|
||||||
|
lexer().consume();
|
||||||
|
auto rhs = try_parse_primary_expression();
|
||||||
|
|
||||||
|
if (!rhs) {
|
||||||
|
context().report_warning({{}, "expected expression after AND"});
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = logical_and_t{{}, *lhs, *rhs};
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<expression_t>
|
||||||
|
syntactical_analyzer_t::
|
||||||
|
try_parse_logical_or()
|
||||||
|
{
|
||||||
|
auto lhs = try_parse_logical_and();
|
||||||
|
|
||||||
|
if (!lhs)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
while (lexer().peek().type() == token_type_t::logical_or) {
|
||||||
|
lexer().consume();
|
||||||
|
auto rhs = try_parse_logical_and();
|
||||||
|
|
||||||
|
if (!rhs)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
lhs = logical_or_t{{}, *lhs, *rhs};
|
||||||
|
}
|
||||||
|
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<expression_t>
|
||||||
|
syntactical_analyzer_t::
|
||||||
|
try_parse_expression()
|
||||||
|
{
|
||||||
|
auto invalid = [](token_t const& token)
|
||||||
|
{
|
||||||
|
if (token.type() == token_type_t::end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.type() == token_type_t::simple_term) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.type() == token_type_t::quoted_term) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.type() == token_type_t::open_parens) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// filter leading invalid tokens.
|
||||||
|
//
|
||||||
|
while (invalid(lexer().peek())) {
|
||||||
|
context().report_warning({{}, "invalid leading token"});
|
||||||
|
lexer().consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
return try_parse_logical_or();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
48
art/query/syntactical-analyzer.hxx
Normal file
48
art/query/syntactical-analyzer.hxx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef art__query__syntactical_analyzer_hxx_
|
||||||
|
#define art__query__syntactical_analyzer_hxx_
|
||||||
|
|
||||||
|
#include <art/query/expression.hxx>
|
||||||
|
#include <art/query/lexical-analyzer.hxx>
|
||||||
|
#include <art/query/parse-context.hxx>
|
||||||
|
#include <art/query/query.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class syntactical_analyzer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
syntactical_analyzer_t(lexical_analyzer_t&, parse_context_t&);
|
||||||
|
|
||||||
|
lexical_analyzer_t&
|
||||||
|
lexer();
|
||||||
|
|
||||||
|
parse_context_t&
|
||||||
|
context();
|
||||||
|
|
||||||
|
query_t
|
||||||
|
try_parse();
|
||||||
|
|
||||||
|
private:
|
||||||
|
optional<expression_t>
|
||||||
|
try_parse_primary_expression();
|
||||||
|
|
||||||
|
optional<expression_t>
|
||||||
|
try_parse_logical_and();
|
||||||
|
|
||||||
|
optional<expression_t>
|
||||||
|
try_parse_logical_or();
|
||||||
|
|
||||||
|
optional<expression_t>
|
||||||
|
try_parse_expression();
|
||||||
|
|
||||||
|
private:
|
||||||
|
lexical_analyzer_t& lexer_;
|
||||||
|
parse_context_t& context_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
48
art/query/tag.cxx
Normal file
48
art/query/tag.cxx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include <art/query/tag.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
tag_t::
|
||||||
|
tag_t(string identifier, term_t value)
|
||||||
|
: identifier_{std::move(identifier)},
|
||||||
|
value_{std::move(value)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
tag_t::
|
||||||
|
tag_t(source_location_t origin,
|
||||||
|
string identifier,
|
||||||
|
term_t value)
|
||||||
|
: origin_{std::move(origin)},
|
||||||
|
identifier_{std::move(identifier)},
|
||||||
|
value_{std::move(value)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
tag_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return origin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string const&
|
||||||
|
tag_t::
|
||||||
|
identifier() const
|
||||||
|
{
|
||||||
|
return identifier_;
|
||||||
|
}
|
||||||
|
|
||||||
|
term_t const&
|
||||||
|
tag_t::
|
||||||
|
value() const
|
||||||
|
{
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(tag_t const& e)
|
||||||
|
{
|
||||||
|
return e.identifier() + ":" + to_string(e.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
40
art/query/tag.hxx
Normal file
40
art/query/tag.hxx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef art__query__tag_hxx_
|
||||||
|
#define art__query__tag_hxx_
|
||||||
|
|
||||||
|
#include <art/query/expression.hxx>
|
||||||
|
#include <art/query/source-location.hxx>
|
||||||
|
#include <art/query/term.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class tag_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
tag_t(string, term_t);
|
||||||
|
|
||||||
|
tag_t(source_location_t, string, term_t);
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
string const&
|
||||||
|
identifier() const;
|
||||||
|
|
||||||
|
term_t const&
|
||||||
|
value() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location_t origin_;
|
||||||
|
|
||||||
|
string identifier_;
|
||||||
|
term_t value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(tag_t const& e);
|
||||||
|
|
||||||
|
} // namespace imperium::contract::query
|
||||||
|
|
||||||
|
#endif
|
||||||
53
art/query/term.cxx
Normal file
53
art/query/term.cxx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#include <art/query/term.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
term_t::
|
||||||
|
term_t(term_type_t type, string value)
|
||||||
|
: type_{type},
|
||||||
|
value_{std::move(value)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
term_t::
|
||||||
|
term_t(source_location_t origin,
|
||||||
|
term_type_t type,
|
||||||
|
string value)
|
||||||
|
: origin_{std::move(origin)},
|
||||||
|
type_{type},
|
||||||
|
value_{std::move(value)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
term_t::
|
||||||
|
origin() const
|
||||||
|
{
|
||||||
|
return origin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
term_t::term_type_t
|
||||||
|
term_t::
|
||||||
|
type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string const&
|
||||||
|
term_t::
|
||||||
|
value() const
|
||||||
|
{
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(term_t const& term)
|
||||||
|
{
|
||||||
|
if (term.type() == term_t::simple)
|
||||||
|
return term.value();
|
||||||
|
|
||||||
|
// fixme: escape term.value()?
|
||||||
|
//
|
||||||
|
return "\"" + term.value() + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
45
art/query/term.hxx
Normal file
45
art/query/term.hxx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef art__query__term_hxx_
|
||||||
|
#define art__query__term_hxx_
|
||||||
|
|
||||||
|
#include <art/query/expression.hxx>
|
||||||
|
#include <art/query/source-location.hxx>
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class term_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum term_type_t
|
||||||
|
{
|
||||||
|
simple,
|
||||||
|
quoted
|
||||||
|
};
|
||||||
|
|
||||||
|
term_t(term_type_t, string);
|
||||||
|
|
||||||
|
term_t(source_location_t, term_type_t, string);
|
||||||
|
|
||||||
|
source_location_t const&
|
||||||
|
origin() const;
|
||||||
|
|
||||||
|
term_type_t
|
||||||
|
type() const;
|
||||||
|
|
||||||
|
string const&
|
||||||
|
value() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location_t origin_;
|
||||||
|
|
||||||
|
term_type_t type_;
|
||||||
|
string value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
string
|
||||||
|
to_string(term_t const&);
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
78
art/query/token.cxx
Normal file
78
art/query/token.cxx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include <art/query/token.hxx>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
token_t::
|
||||||
|
token_t(token_type_t type, optional<string> value)
|
||||||
|
: type_{type},
|
||||||
|
value_{std::move(value)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
token_type_t
|
||||||
|
token_t::
|
||||||
|
type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<string> const&
|
||||||
|
token_t::
|
||||||
|
value() const
|
||||||
|
{
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& o, token_t const& token)
|
||||||
|
{
|
||||||
|
switch (token.type()) {
|
||||||
|
case token_type_t::end:
|
||||||
|
o << "end";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token_type_t::simple_term:
|
||||||
|
o << "simple-term";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token_type_t::quoted_term:
|
||||||
|
o << "quoted-term";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token_type_t::colon:
|
||||||
|
o << "colon";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token_type_t::logical_and:
|
||||||
|
o << "logical-and";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token_type_t::logical_not:
|
||||||
|
o << "logical-not";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token_type_t::logical_or:
|
||||||
|
o << "logical-or";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token_type_t::open_parens:
|
||||||
|
o << "open-parens";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case token_type_t::close_parens:
|
||||||
|
o << "close-parens";
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto v = token.value(); v) {
|
||||||
|
o << ": " << *v;
|
||||||
|
}
|
||||||
|
|
||||||
|
o << '\n';
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
52
art/query/token.hxx
Normal file
52
art/query/token.hxx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#ifndef art__query__token_hxx_
|
||||||
|
#define art__query__token_hxx_
|
||||||
|
|
||||||
|
#include <art/query/types.hxx>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class token_type_t
|
||||||
|
{
|
||||||
|
end,
|
||||||
|
|
||||||
|
simple_term,
|
||||||
|
quoted_term,
|
||||||
|
|
||||||
|
colon,
|
||||||
|
|
||||||
|
logical_and,
|
||||||
|
logical_not,
|
||||||
|
logical_or,
|
||||||
|
|
||||||
|
open_parens,
|
||||||
|
close_parens
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class token_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit
|
||||||
|
token_t(token_type_t, optional<string> = nullopt);
|
||||||
|
|
||||||
|
token_type_t
|
||||||
|
type() const;
|
||||||
|
|
||||||
|
optional<string> const&
|
||||||
|
value() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
token_type_t type_;
|
||||||
|
optional<string> value_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream&, token_t const&);
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
42
art/query/types.hxx
Normal file
42
art/query/types.hxx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef art__query__types_hxx_
|
||||||
|
#define art__query__types_hxx_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
using std::int8_t;
|
||||||
|
using std::int16_t;
|
||||||
|
using std::int32_t;
|
||||||
|
using std::int64_t;
|
||||||
|
using std::uint8_t;
|
||||||
|
using std::uint16_t;
|
||||||
|
using std::uint32_t;
|
||||||
|
using std::uint64_t;
|
||||||
|
|
||||||
|
using std::make_shared;
|
||||||
|
using std::shared_ptr;
|
||||||
|
using std::weak_ptr;
|
||||||
|
|
||||||
|
using std::optional;
|
||||||
|
using std::nullopt;
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
using std::variant;
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using strings = vector<string>;
|
||||||
|
|
||||||
|
using std::function;
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
37
art/query/version.hxx.in
Normal file
37
art/query/version.hxx.in
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef art__query__version_hxx_
|
||||||
|
#define art__query__version_hxx_
|
||||||
|
|
||||||
|
// The numeric version format is AAAAABBBBBCCCCCDDDE where:
|
||||||
|
//
|
||||||
|
// AAAAA - major version number
|
||||||
|
// BBBBB - minor version number
|
||||||
|
// CCCCC - bugfix version number
|
||||||
|
// DDD - code / beta (DDD + 500) version number
|
||||||
|
// E - final (0) / snapshot (1)
|
||||||
|
//
|
||||||
|
// When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example:
|
||||||
|
//
|
||||||
|
// Version AAAAABBBBBCCCCCDDDE
|
||||||
|
//
|
||||||
|
// 0.1.0 0000000001000000000
|
||||||
|
// 0.1.2 0000000001000020000
|
||||||
|
// 1.2.3 0000100002000030000
|
||||||
|
// 2.2.0-a.1 0000200001999990010
|
||||||
|
// 3.0.0-b.2 0000299999999995020
|
||||||
|
// 2.2.0-a.1.z 0000200001999990011
|
||||||
|
//
|
||||||
|
#define LIBART_QUERY_VERSION $libart_query.version.project_number$ULL
|
||||||
|
#define LIBART_QUERY_VERSION_STR "$libart_query.version.project$"
|
||||||
|
#define LIBART_QUERY_VERSION_ID "$libart_query.version.project_id$"
|
||||||
|
#define LIBART_QUERY_VERSION_FULL "$libart_query.version$"
|
||||||
|
|
||||||
|
#define LIBART_QUERY_VERSION_MAJOR $libart_query.version.major$
|
||||||
|
#define LIBART_QUERY_VERSION_MINOR $libart_query.version.minor$
|
||||||
|
#define LIBART_QUERY_VERSION_PATCH $libart_query.version.patch$
|
||||||
|
|
||||||
|
#define LIBART_QUERY_PRE_RELEASE $libart_query.version.pre_release$
|
||||||
|
|
||||||
|
#define LIBART_QUERY_SNAPSHOT_SN $libart_query.version.snapshot_sn$ULL
|
||||||
|
#define LIBART_QUERY_SNAPSHOT_ID "$libart_query.version.snapshot_id$"
|
||||||
|
|
||||||
|
#endif
|
||||||
39
art/query/visitor.hxx
Normal file
39
art/query/visitor.hxx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef art__query__visitor_hxx_
|
||||||
|
#define art__query__visitor_hxx_
|
||||||
|
|
||||||
|
namespace art::query
|
||||||
|
{
|
||||||
|
|
||||||
|
class visitor_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual
|
||||||
|
~visitor_t() noexcept = default;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
visit_default() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
visitor_t() = default;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename V>
|
||||||
|
class basic_visitor_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
visit(V const&) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
basic_visitor_t() = default;
|
||||||
|
|
||||||
|
~basic_visitor_t() noexcept = default;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace art::query
|
||||||
|
|
||||||
|
#endif
|
||||||
4
build/.gitignore
vendored
Normal file
4
build/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/config.build
|
||||||
|
/root/
|
||||||
|
/bootstrap/
|
||||||
|
build/
|
||||||
7
build/bootstrap.build
Normal file
7
build/bootstrap.build
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
project = libart-query
|
||||||
|
|
||||||
|
using version
|
||||||
|
using config
|
||||||
|
using test
|
||||||
|
using install
|
||||||
|
using dist
|
||||||
6
build/export.build
Normal file
6
build/export.build
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
$out_root/
|
||||||
|
{
|
||||||
|
include art/query/
|
||||||
|
}
|
||||||
|
|
||||||
|
export $out_root/art/query/$import.target
|
||||||
16
build/root.build
Normal file
16
build/root.build
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Uncomment to suppress warnings coming from external libraries.
|
||||||
|
#
|
||||||
|
#cxx.internal.scope = current
|
||||||
|
|
||||||
|
cxx.std = latest
|
||||||
|
|
||||||
|
using cxx
|
||||||
|
|
||||||
|
hxx{*}: extension = hxx
|
||||||
|
ixx{*}: extension = ixx
|
||||||
|
txx{*}: extension = txx
|
||||||
|
cxx{*}: extension = cxx
|
||||||
|
|
||||||
|
# The test target for cross-testing (running tests under Wine, etc).
|
||||||
|
#
|
||||||
|
test.target = $cxx.target
|
||||||
5
buildfile
Normal file
5
buildfile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
./: {art/ tests/} doc{README.md} legal{LICENSE} manifest
|
||||||
|
|
||||||
|
# Don't install tests.
|
||||||
|
#
|
||||||
|
tests/: install = false
|
||||||
11
manifest
Normal file
11
manifest
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
: 1
|
||||||
|
name: libart-query
|
||||||
|
version: 0.1.0-a.0.z
|
||||||
|
language: c++
|
||||||
|
summary: libart-query C++ library
|
||||||
|
license: BSD-4-Clause
|
||||||
|
description-file: README.md
|
||||||
|
url: https://art.helloryan.se/
|
||||||
|
email: art@helloryan.se
|
||||||
|
depends: * build2 >= 0.17.0
|
||||||
|
depends: * bpkg >= 0.17.0
|
||||||
2
repositories.manifest
Normal file
2
repositories.manifest
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
: 1
|
||||||
|
summary: libart-query project repository
|
||||||
8
tests/.gitignore
vendored
Normal file
8
tests/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Test executables.
|
||||||
|
#
|
||||||
|
driver
|
||||||
|
|
||||||
|
# Testscript output directories (can be symlinks).
|
||||||
|
#
|
||||||
|
test
|
||||||
|
test-*
|
||||||
4
tests/build/.gitignore
vendored
Normal file
4
tests/build/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/config.build
|
||||||
|
/root/
|
||||||
|
/bootstrap/
|
||||||
|
build/
|
||||||
5
tests/build/bootstrap.build
Normal file
5
tests/build/bootstrap.build
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
project = # Unnamed tests subproject.
|
||||||
|
|
||||||
|
using config
|
||||||
|
using test
|
||||||
|
using dist
|
||||||
16
tests/build/root.build
Normal file
16
tests/build/root.build
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
cxx.std = latest
|
||||||
|
|
||||||
|
using cxx
|
||||||
|
|
||||||
|
hxx{*}: extension = hxx
|
||||||
|
ixx{*}: extension = ixx
|
||||||
|
txx{*}: extension = txx
|
||||||
|
cxx{*}: extension = cxx
|
||||||
|
|
||||||
|
# Every exe{} in this subproject is by default a test.
|
||||||
|
#
|
||||||
|
exe{*}: test = true
|
||||||
|
|
||||||
|
# The test target for cross-testing (running tests under Wine, etc).
|
||||||
|
#
|
||||||
|
test.target = $cxx.target
|
||||||
1
tests/buildfile
Normal file
1
tests/buildfile
Normal file
@@ -0,0 +1 @@
|
|||||||
|
./: {*/ -build/}
|
||||||
Reference in New Issue
Block a user