Skip to content

Commit 3f3ccf9

Browse files
authored
Initial release. (#11)
With the addition of unification and the `some` keyword, the implementation is now usable (for a limited but reasonable set of use cases). This commit changes almost everything, but in short: - `RulesEngine` has been replaced by `Unifier` and `Resolver` - Rule bodies, values, and queries are now resolved as interconnected unification problems - `some` keyword - the `=` operator can be used now for expressing unification - object and array assignment (i.e. `[1, a] := foo`) is now possible Signed-off-by: Matthew A Johnson <[email protected]>
1 parent e470924 commit 3f3ccf9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+4770
-1635
lines changed

.github/workflows/pr_gate.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
sudo apt-get install ninja-build
3232
3333
- name: CMake config
34-
run: cmake -B ${{github.workspace}}/build -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++
34+
run: cmake -B ${{github.workspace}}/build -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DREGOCPP_BUILD_TOOLS=1 -DREGOCPP_BUILD_TESTS=1
3535

3636
- name: CMake build
3737
working-directory: ${{github.workspace}}/build
@@ -50,7 +50,7 @@ jobs:
5050

5151
- name: CMake config
5252
run: |
53-
cmake -B ${{github.workspace}}/build
53+
cmake -B ${{github.workspace}}/build -DREGOCPP_BUILD_TOOLS=1 -DREGOCPP_BUILD_TESTS=1
5454
5555
- name: CMake build
5656
working-directory: ${{github.workspace}}/build

CHANGELOG

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Changelog
2+
3+
## [2023-06-21 - Version 0.2.0](https://github.com/microsoft/scenepic/releases/tag/v0.2.0)
4+
Initial Release.

CMakeLists.txt

+93-13
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,38 @@ cmake_minimum_required(VERSION 3.15)
55

66
include(FetchContent)
77

8-
set( REGO_CPP_VERSION 0.1.3 )
9-
message("Configure REGO_CPP_VERSION at ${REGO_CPP_VERSION}")
8+
file( STRINGS "VERSION" REGOCPP_VERSION_FILE )
109

11-
project(regocpp VERSION ${REGO_CPP_VERSION} LANGUAGES CXX)
10+
string( REPLACE "." ";" REGOCPP_VERSION_LIST ${REGOCPP_VERSION_FILE} )
11+
12+
list( GET REGOCPP_VERSION_LIST 0 REGOCPP_VERSION_MAJOR )
13+
14+
list( GET REGOCPP_VERSION_LIST 1 REGOCPP_VERSION_MINOR )
15+
16+
list( GET REGOCPP_VERSION_LIST 2 REGOCPP_VERSION_REVISION )
17+
18+
set( REGOCPP_VERSION ${REGOCPP_VERSION_MAJOR}.${REGOCPP_VERSION_MINOR}.${REGOCPP_VERSION_REVISION} )
19+
20+
message("Configure REGOCPP_VERSION at ${REGOCPP_VERSION}")
21+
22+
project( regocpp VERSION ${REGOCPP_VERSION} LANGUAGES CXX)
1223

1324
set(CMAKE_CXX_STANDARD 20)
1425
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
1526

27+
# -------------------- Find packages --------------------------
28+
1629
FetchContent_Declare(
1730
trieste
1831
GIT_REPOSITORY https://github.com/microsoft/trieste
19-
GIT_TAG 11f9f56979707d11d96a4e8a473c7dd2bd79e7da
32+
GIT_TAG f66149cb53a79816120bd8f8af9e085be1f84e29
33+
GIT_SHALLOW TRUE
2034
)
2135

22-
FetchContent_GetProperties(trieste)
23-
if(NOT trieste_POPULATED)
24-
set(TRIESTE_BUILD_SAMPLES OFF)
25-
FetchContent_Populate(trieste)
26-
add_subdirectory(${trieste_SOURCE_DIR} ${trieste_BINARY_DIR} EXCLUDE_FROM_ALL)
27-
endif()
36+
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
2837

38+
set(TRIESTE_BUILD_SAMPLES OFF)
39+
FetchContent_MakeAvailable(trieste)
2940

3041
find_program(CLANG_FORMAT NAMES clang-format-10 clang-format-14 )
3142

@@ -35,7 +46,10 @@ if(CLANG_FORMAT_NOT_FOUND)
3546
else()
3647
file(GLOB_RECURSE ALL_SOURCE_FILES CONFIGURE_DEPENDS
3748
src/*.cc
49+
src/passes/*.cc
3850
src/*.h
51+
include/rego/*.h
52+
tools/*.cc
3953
)
4054

4155
add_custom_target(regocpp_format
@@ -45,9 +59,75 @@ else()
4559
${ALL_SOURCE_FILES})
4660
endif()
4761

48-
enable_testing()
62+
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
63+
64+
# -------------------- Options --------------------------
65+
66+
option(REGOCPP_BUILD_TOOLS "Specifies whether to build the command line tools" OFF)
67+
option(REGOCPP_BUILD_TESTS "Specifies whether to build the tests" OFF)
68+
option(REGOCPP_LOGGING "Specifies whether to enable logging" OFF)
69+
70+
# -------------------- Walk the subdirectories --------------------
71+
72+
if(REGOCPP_BUILD_TESTS)
73+
enable_testing()
74+
endif()
4975

5076
add_subdirectory(src)
5177

52-
install(TARGETS rego_interpreter rego_trieste RUNTIME)
53-
install(DIRECTORY src/examples DESTINATION .)
78+
if(REGOCPP_BUILD_TOOLS)
79+
add_subdirectory(tools)
80+
endif()
81+
82+
# -------------------- Install ------------------------------------
83+
84+
set(INSTALL_CONFIGDIR cmake)
85+
set(INSTALL_LIBDIR lib)
86+
set(INSTALL_INCLUDEDIR include)
87+
88+
install(TARGETS rego
89+
EXPORT ${PROJECT_NAME}_Targets
90+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
91+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
92+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
93+
)
94+
95+
# Create a ConfigVersion.cmake file
96+
include(CMakePackageConfigHelpers)
97+
write_basic_package_version_file(
98+
${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
99+
VERSION ${PROJECT_VERSION}
100+
COMPATIBILITY AnyNewerVersion
101+
)
102+
103+
configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in
104+
${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
105+
INSTALL_DESTINATION
106+
${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake
107+
)
108+
109+
install(EXPORT ${PROJECT_NAME}_Targets
110+
FILE ${PROJECT_NAME}Targets.cmake
111+
NAMESPACE ${PROJECT_NAME}::
112+
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake)
113+
114+
install(FILES ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
115+
${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
116+
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake)
117+
118+
if (REGOCPP_BUILD_TOOLS)
119+
install(TARGETS rego_interpreter rego_trieste RUNTIME)
120+
install(DIRECTORY tools/examples DESTINATION .)
121+
endif()
122+
123+
export(EXPORT ${PROJECT_NAME}_Targets
124+
FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake
125+
NAMESPACE ${PROJECT_NAME}::)
126+
127+
export(PACKAGE ${PROJECT_NAME})
128+
129+
install(DIRECTORY include/ DESTINATION ${INSTALL_INCLUDEDIR})
130+
install(FILES
131+
${CMAKE_CURRENT_BINARY_DIR}/src/version.h
132+
DESTINATION ${INSTALL_INCLUDEDIR}/rego
133+
)

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Create a build directory and initialize the cmake project:
3131

3232
mkdir build
3333
cd build
34-
cmake .. -DCMAKE_INSTALL_PREFIX=dist
34+
cmake .. -DCMAKE_INSTALL_PREFIX=dist -DREGOCPP_BUILD_TOOLS=1
3535

3636
You can then build and run the tests using:
3737

VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.2.0

cmake/regocppConfig.cmake.in

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
get_filename_component(REGOCPP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
2+
include(FetchContent)
3+
4+
FetchContent_Declare(
5+
trieste
6+
GIT_REPOSITORY https://github.com/microsoft/trieste
7+
GIT_TAG c23669df20956a19c263ae1638e6fa976c31eec5
8+
)
9+
10+
FetchContent_GetProperties(trieste)
11+
if(NOT trieste_POPULATED)
12+
set(TRIESTE_BUILD_SAMPLES OFF)
13+
FetchContent_Populate(trieste)
14+
add_subdirectory(${trieste_SOURCE_DIR} ${trieste_BINARY_DIR} EXCLUDE_FROM_ALL)
15+
endif()
16+
17+
if(NOT TARGET regocpp::rego)
18+
include("${REGOCPP_CMAKE_DIR}/regocppTargets.cmake")
19+
endif()
20+
21+
set(REGOCPP_lIBRARIES regocpp::rego)

include/rego/args.h

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include "value.h"
4+
5+
namespace rego
6+
{
7+
class Args
8+
{
9+
public:
10+
Args();
11+
void push_back(const Values& values);
12+
void mark_invalid(const std::set<Value>& active) const;
13+
Values at(std::size_t index) const;
14+
std::size_t size() const;
15+
std::string str() const;
16+
friend std::ostream& operator<<(std::ostream& os, const Args& args);
17+
18+
private:
19+
std::vector<Values> m_values;
20+
std::vector<size_t> m_stride;
21+
std::size_t m_size;
22+
};
23+
}

include/rego/interpreter.h

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
#include "lang.h"
4+
5+
#include <string>
6+
7+
namespace rego
8+
{
9+
using namespace trieste;
10+
class Interpreter
11+
{
12+
public:
13+
Interpreter(bool disable_well_formed_checks = false);
14+
void add_module_file(const std::filesystem::path& path);
15+
void add_module(const std::string& name, const std::string& contents);
16+
void add_data_json_file(const std::filesystem::path& path);
17+
void add_data_json(const std::string& json);
18+
void add_input_json_file(const std::filesystem::path& path);
19+
void add_input_json(const std::string& json);
20+
std::string query(const std::string& query_expr) const;
21+
Interpreter& debug_path(const std::filesystem::path& prefix);
22+
const std::filesystem::path& debug_path() const;
23+
Interpreter& debug_enabled(bool enabled);
24+
bool debug_enabled() const;
25+
Interpreter& well_formed_checks_enabled(bool enabled);
26+
bool well_formed_checks_enabled() const;
27+
Interpreter& executable(const std::filesystem::path& path);
28+
const std::filesystem::path& executable() const;
29+
30+
private:
31+
void write_ast(
32+
std::size_t index, const std::string& pass, const Node& ast) const;
33+
Parse m_parser;
34+
wf::Wellformed m_wf_parser;
35+
std::vector<PassCheck> m_passes;
36+
Node m_module_seq;
37+
Node m_data_seq;
38+
Node m_input;
39+
std::filesystem::path m_debug_path;
40+
bool m_debug_enabled;
41+
bool m_well_formed_checks_enabled;
42+
};
43+
}

src/lang.h include/rego/lang.h

+28-9
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ namespace rego
1515
inline constexpr auto RuleHeadComp = TokenDef("rule-head-comp");
1616
inline constexpr auto RuleHeadFunc = TokenDef("rule-head-func");
1717
inline constexpr auto RuleArgs = TokenDef("rule-args");
18-
inline constexpr auto RuleBody = TokenDef("rule-body");
19-
inline constexpr auto Query = TokenDef("query");
18+
inline constexpr auto Query = TokenDef("query", flag::symtab);
2019
inline constexpr auto Literal = TokenDef("literal");
2120
inline constexpr auto Expr = TokenDef("expr");
2221
inline constexpr auto ExprInfix = TokenDef("expr-infix");
@@ -28,7 +27,6 @@ namespace rego
2827
inline constexpr auto ArithOperator = TokenDef("arith-operator");
2928
inline constexpr auto AssignOperator = TokenDef("assign-operator");
3029
inline constexpr auto Ref = TokenDef("ref");
31-
inline constexpr auto RefArg = TokenDef("ref-arg");
3230
inline constexpr auto RefArgBrack = TokenDef("ref-arg-brack");
3331
inline constexpr auto RefArgDot = TokenDef("ref-arg-dot");
3432
inline constexpr auto RefArgCall = TokenDef("ref-arg-call");
@@ -60,8 +58,11 @@ namespace rego
6058
inline constexpr auto Divide = TokenDef("/");
6159
inline constexpr auto Modulo = TokenDef("%");
6260
inline constexpr auto Assign = TokenDef(":=");
61+
inline constexpr auto Unify = TokenDef("=");
62+
inline constexpr auto SomeDecl = TokenDef("some-decl");
6363

6464
// intermediate tokens
65+
inline constexpr auto UnifyBody = TokenDef("unify-body");
6566
inline constexpr auto RuleBodySeq = TokenDef("rule-body-seq");
6667
inline constexpr auto RefHead = TokenDef("ref-head");
6768
inline constexpr auto RefArgSeq = TokenDef("ref-arg-seq");
@@ -79,15 +80,19 @@ namespace rego
7980
inline constexpr auto Data = TokenDef("data", flag::symtab | flag::lookup);
8081

8182
// fused
82-
inline constexpr auto RuleComp =
83-
TokenDef("rule-comp", flag::symtab | flag::lookup | flag::lookdown);
84-
inline constexpr auto RuleFunc =
85-
TokenDef("rule-func", flag::symtab | flag::lookup | flag::lookdown);
83+
inline constexpr auto RuleComp = TokenDef(
84+
"rule-comp",
85+
flag::symtab | flag::lookup | flag::lookdown | flag::defbeforeuse);
86+
inline constexpr auto RuleFunc = TokenDef(
87+
"rule-func",
88+
flag::symtab | flag::lookup | flag::lookdown | flag::defbeforeuse);
8689
inline constexpr auto DefaultRule =
8790
TokenDef("default-rule", flag::lookup | flag::lookdown);
88-
inline constexpr auto LocalRule = TokenDef("local-rule", flag::lookup);
91+
inline constexpr auto Local =
92+
TokenDef("local", flag::lookup | flag::shadowing);
8993
inline constexpr auto ArithInfix = TokenDef("arith-infix");
9094
inline constexpr auto BoolInfix = TokenDef("bool-infix");
95+
inline constexpr auto AssignInfix = TokenDef("assign-infix");
9196
inline constexpr auto ArgVar = TokenDef("arg-var", flag::lookup);
9297
inline constexpr auto ArgVal = TokenDef("arg-val");
9398

@@ -97,7 +102,10 @@ namespace rego
97102
inline constexpr auto Math = TokenDef("math");
98103
inline constexpr auto Op = TokenDef("op");
99104
inline constexpr auto Comparison = TokenDef("comparison");
100-
inline constexpr auto Value = TokenDef("value");
105+
inline constexpr auto Function = TokenDef("function");
106+
inline constexpr auto Arg = TokenDef("arg");
107+
inline constexpr auto ArgSeq = TokenDef("arg-seq");
108+
inline constexpr auto Val = TokenDef("value");
101109
inline constexpr auto Id = TokenDef("id");
102110
inline constexpr auto Head = TokenDef("head");
103111
inline constexpr auto Tail = TokenDef("tail");
@@ -107,7 +115,15 @@ namespace rego
107115
inline constexpr auto RefTerm = TokenDef("ref-term");
108116
inline constexpr auto NumTerm = TokenDef("num-term");
109117
inline constexpr auto ArithArg = TokenDef("arith-arg");
118+
inline constexpr auto BoolArg = TokenDef("bool-arg");
119+
inline constexpr auto AssignArg = TokenDef("assign-arg");
110120
inline constexpr auto RuleHeadType = TokenDef("rule-head-type");
121+
inline constexpr auto UnifyExpr = TokenDef("unify-expr");
122+
inline constexpr auto TermSet = TokenDef("term-set");
123+
inline constexpr auto Empty = TokenDef("empty");
124+
inline constexpr auto SimpleRef = TokenDef("simple-ref");
125+
inline constexpr auto Binding = TokenDef("binding");
126+
inline constexpr auto DefaultTerm = TokenDef("default-term");
111127

112128
// lists
113129
inline constexpr auto List = TokenDef("list");
@@ -120,6 +136,7 @@ namespace rego
120136
inline constexpr auto Paren = TokenDef("paren");
121137
inline constexpr auto Not = TokenDef("not");
122138
inline constexpr auto Default = TokenDef("default");
139+
inline constexpr auto Some = TokenDef("some");
123140

124141
inline auto err(NodeRange& r, const std::string& msg)
125142
{
@@ -141,4 +158,6 @@ namespace rego
141158
using PassCheck = std::tuple<std::string, Pass, const wf::Wellformed&>;
142159
std::vector<PassCheck> passes();
143160
std::string to_json(const Node& node);
161+
bool contains_local(const Node& node);
162+
bool is_in(const Node& node, const Token& token);
144163
}

0 commit comments

Comments
 (0)