mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Compare commits
9 Commits
regorus-v0
...
regorus-v0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a0048cd64 | ||
|
|
4a2a724a80 | ||
|
|
46e28b36f8 | ||
|
|
ee898e112e | ||
|
|
e6f2ec825d | ||
|
|
45627aa64a | ||
|
|
df98c8d168 | ||
|
|
25902bab57 | ||
|
|
e62bfdf161 |
5
.github/workflows/test-c-cpp.yml
vendored
5
.github/workflows/test-c-cpp.yml
vendored
@@ -18,6 +18,11 @@ jobs:
|
||||
- name: Setup gcc, g++, cmake, ninja
|
||||
run: sudo apt update && sudo apt install -y gcc g++ cmake ninja-build
|
||||
|
||||
- name: Workaround to ensure that regorus.h is generated
|
||||
run: |
|
||||
cargo build -r
|
||||
working-directory: ./bindings/ffi
|
||||
|
||||
- name: Test c binding
|
||||
run: |
|
||||
mkdir bindings/c/build
|
||||
|
||||
2
.github/workflows/test-ffi.yml
vendored
2
.github/workflows/test-ffi.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: bindings/c-cpp
|
||||
name: bindings/ffi
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.2.1](https://github.com/microsoft/regorus/compare/regorus-v0.2.0...regorus-v0.2.1) - 2024-06-19
|
||||
|
||||
### Added
|
||||
- get_policies: Way to obtain policy files and content ([#267](https://github.com/microsoft/regorus/pull/267))
|
||||
|
||||
### Other
|
||||
- Fix c,cpp,no-std binding examples ([#272](https://github.com/microsoft/regorus/pull/272))
|
||||
- Update binding versions for next release ([#270](https://github.com/microsoft/regorus/pull/270))
|
||||
- rename method from 'Clone' to 'clone' in 'Engine' class to match the java naming convention and definiont in the of java.lang.Object. ([#268](https://github.com/microsoft/regorus/pull/268))
|
||||
- Suppress clippy unused warning ([#269](https://github.com/microsoft/regorus/pull/269))
|
||||
- Provide ability to get JSON representation of policy AST ([#266](https://github.com/microsoft/regorus/pull/266))
|
||||
- Update OPA tests to v0.65.0 ([#264](https://github.com/microsoft/regorus/pull/264))
|
||||
- Allow lexer to be used for other policy languages ([#262](https://github.com/microsoft/regorus/pull/262))
|
||||
|
||||
## [0.2.0](https://github.com/microsoft/regorus/compare/regorus-v0.1.5...regorus-v0.2.0) - 2024-05-30
|
||||
|
||||
### Other
|
||||
|
||||
@@ -12,7 +12,7 @@ members = [
|
||||
[package]
|
||||
name = "regorus"
|
||||
description = "A fast, lightweight Rego (OPA policy language) interpreter"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
license-file = "LICENSE"
|
||||
repository = "https://github.com/microsoft/regorus"
|
||||
@@ -27,6 +27,7 @@ doctest = false
|
||||
default = ["full-opa", "arc"]
|
||||
|
||||
arc = ["scientific/arc"]
|
||||
ast = []
|
||||
base64 = ["dep:data-encoding"]
|
||||
base64url = ["dep:data-encoding"]
|
||||
coverage = []
|
||||
|
||||
@@ -38,4 +38,4 @@ corrosion_import_crate(
|
||||
add_executable(regorus_test main.c)
|
||||
# Add path to <regorus-source-folder>/bindings/ffi
|
||||
target_include_directories(regorus_test PRIVATE "../ffi")
|
||||
target_link_libraries(regorus_test regorus-ffi)
|
||||
target_link_libraries(regorus_test regorus_ffi)
|
||||
|
||||
@@ -31,4 +31,4 @@ corrosion_import_crate(
|
||||
add_executable(regorus_test main.c)
|
||||
# Add path to <regorus-source-folder>/bindings/ffi
|
||||
target_include_directories(regorus_test PRIVATE "../ffi")
|
||||
target_link_libraries(regorus_test regorus-ffi)
|
||||
target_link_libraries(regorus_test regorus_ffi)
|
||||
|
||||
@@ -31,4 +31,4 @@ corrosion_import_crate(
|
||||
add_executable(regorus_test main.cpp)
|
||||
# Add path to <regorus-source-folder>/bindings/ffi
|
||||
target_include_directories(regorus_test PRIVATE "../ffi")
|
||||
target_link_libraries(regorus_test regorus-ffi)
|
||||
target_link_libraries(regorus_test regorus_ffi)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "regorus-ffi"
|
||||
version = "0.1.5"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -13,7 +13,8 @@ regorus = { path = "../..", default-features = false }
|
||||
serde_json = "1.0.113"
|
||||
|
||||
[features]
|
||||
default = ["std", "coverage", "regorus/arc", "regorus/full-opa"]
|
||||
default = ["ast", "std", "coverage", "regorus/arc", "regorus/full-opa"]
|
||||
ast = ["regorus/ast"]
|
||||
std = ["regorus/std"]
|
||||
coverage = ["regorus/coverage"]
|
||||
custom_allocator = []
|
||||
|
||||
@@ -189,7 +189,6 @@ pub extern "C" fn regorus_engine_add_data_json(
|
||||
/// Get list of loaded Rego packages as JSON.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
|
||||
/// * `data`: JSON encoded value to be used as policy data.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_get_packages(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
@@ -198,6 +197,16 @@ pub extern "C" fn regorus_engine_get_packages(engine: *mut RegorusEngine) -> Reg
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get list of policies as JSON.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_get_policies(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
to_ref(&engine)?.engine.get_policies_as_json()
|
||||
}())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_data_from_json_file(
|
||||
@@ -411,6 +420,23 @@ pub extern "C" fn regorus_engine_take_prints(engine: *mut RegorusEngine) -> Rego
|
||||
}
|
||||
}
|
||||
|
||||
/// Get AST of policies.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_ast_as_json
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "ast")]
|
||||
pub extern "C" fn regorus_engine_get_ast_as_json(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
let output = || -> Result<String> { to_ref(&engine)?.engine.get_ast_as_json() }();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "custom_allocator")]
|
||||
extern "C" {
|
||||
fn regorus_aligned_alloc(alignment: usize, size: usize) -> *mut u8;
|
||||
|
||||
@@ -82,6 +82,19 @@ func main() {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("%s\n", output)
|
||||
|
||||
// Print packages
|
||||
if output, err = engine1.GetPackages(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("%s\n", output)
|
||||
|
||||
// Print policies
|
||||
if output, err = engine1.GetPolicies(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("%s\n", output)
|
||||
}
|
||||
|
||||
@@ -55,6 +55,25 @@ func (e *Engine) AddPolicyFromFile(path string) (string, error) {
|
||||
return C.GoString(result.output), nil
|
||||
}
|
||||
|
||||
func (e *Engine) GetPackages() (string, error) {
|
||||
result := C.regorus_engine_get_packages(e.e)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return C.GoString(result.output), nil
|
||||
}
|
||||
|
||||
func (e *Engine) GetPolicies() (string, error) {
|
||||
result := C.regorus_engine_get_policies(e.e)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return C.GoString(result.output), nil
|
||||
}
|
||||
|
||||
|
||||
func (e *Engine) AddDataJson(data string) error {
|
||||
data_c := C.CString(data)
|
||||
defer C.free(unsafe.Pointer(data_c))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "regorus-java"
|
||||
version = "0.1.5"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/microsoft/regorus/bindings/java"
|
||||
description = "Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||
@@ -11,7 +11,9 @@ keywords = ["interpreter", "opa", "policy-as-code", "rego"]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[features]
|
||||
default = ["regorus/std", "regorus/full-opa"]
|
||||
default = ["ast", "coverage", "regorus/std", "regorus/full-opa"]
|
||||
coverage = ["regorus/coverage"]
|
||||
ast = ["regorus/ast"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
|
||||
@@ -31,6 +31,12 @@ public class Test {
|
||||
System.out.println(coverageJson);
|
||||
|
||||
System.out.println(engine.getCoverageReportPretty());
|
||||
|
||||
String packagesJson = engine.getPackages();
|
||||
System.out.println(packagesJson);
|
||||
|
||||
String policiesJson = engine.getPolicies();
|
||||
System.out.println(policiesJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,25 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPackages(
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetPolicies(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
engine_ptr: jlong,
|
||||
) -> jstring {
|
||||
let res = throw_err(env, |env| {
|
||||
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||
let policies = engine.get_policies_as_json()?;
|
||||
let policies_json = env.new_string(&policies)?;
|
||||
Ok(policies_json.into_raw())
|
||||
});
|
||||
|
||||
match res {
|
||||
Ok(val) => val,
|
||||
Err(_) => JObject::null().into_raw(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearData(
|
||||
env: JNIEnv,
|
||||
@@ -205,6 +224,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeEvalRule(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetEnableCoverage(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
@@ -219,6 +239,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetEnableCoverage
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReport(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
@@ -238,6 +259,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReport
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReportPretty(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
@@ -257,6 +279,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeGetCoverageReport
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearCoverageData(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
@@ -302,6 +325,26 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeTakePrints(
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "ast")]
|
||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_getAstAsJson(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
engine_ptr: jlong,
|
||||
) -> jstring {
|
||||
let res = throw_err(env, |env| {
|
||||
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
|
||||
let ast = engine.get_ast_as_json()?;
|
||||
let output = env.new_string(&ast)?;
|
||||
Ok(output.into_raw())
|
||||
});
|
||||
|
||||
match res {
|
||||
Ok(val) => val,
|
||||
Err(_) => JObject::null().into_raw(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeDestroyEngine(
|
||||
_env: JNIEnv,
|
||||
|
||||
@@ -26,6 +26,7 @@ public class Engine implements AutoCloseable, Cloneable {
|
||||
private static native String nativeAddPolicy(long enginePtr, String path, String rego);
|
||||
private static native String nativeAddPolicyFromFile(long enginePtr, String path);
|
||||
private static native String nativeGetPackages(long enginePtr);
|
||||
private static native String nativeGetPolicies(long enginePtr);
|
||||
private static native void nativeClearData(long enginePtr);
|
||||
private static native void nativeAddDataJson(long enginePtr, String data);
|
||||
private static native void nativeAddDataJsonFromFile(long enginePtr, String path);
|
||||
@@ -60,7 +61,7 @@ public class Engine implements AutoCloseable, Cloneable {
|
||||
/**
|
||||
* Efficiently clones an Engine.
|
||||
*/
|
||||
public Engine Clone() {
|
||||
public Engine clone() {
|
||||
return new Engine(nativeClone(enginePtr));
|
||||
}
|
||||
|
||||
@@ -96,6 +97,15 @@ public class Engine implements AutoCloseable, Cloneable {
|
||||
return nativeGetPackages(enginePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of loaded policies.
|
||||
*
|
||||
* @return List of Rego policies as a JSON array of sources.
|
||||
*/
|
||||
public String getPolicies() {
|
||||
return nativeGetPolicies(enginePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the data document.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "regoruspy"
|
||||
version = "0.1.5"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/microsoft/regorus/bindings/python"
|
||||
description = "Python bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||
@@ -12,7 +12,9 @@ keywords = ["interpreter", "opa", "policy-as-code", "rego"]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[features]
|
||||
default = ["regorus/std", "regorus/full-opa"]
|
||||
default = ["ast", "coverage", "regorus/std", "regorus/full-opa"]
|
||||
ast = ["regorus/ast"]
|
||||
coverage = ["regorus/coverage"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
|
||||
@@ -184,10 +184,18 @@ impl Engine {
|
||||
|
||||
/// Get the list of packages defined by loaded policies.
|
||||
///
|
||||
pub fn get_packages(&mut self) -> Result<Vec<String>> {
|
||||
pub fn get_packages(&self) -> Result<Vec<String>> {
|
||||
self.engine.get_packages()
|
||||
}
|
||||
|
||||
/// Get the list of policies.
|
||||
///
|
||||
pub fn get_policies(&self) -> Result<String> {
|
||||
Ok(serde_json::to_string_pretty(
|
||||
&self.engine.get_policies_as_json()?,
|
||||
)?)
|
||||
}
|
||||
|
||||
/// Add policy data.
|
||||
///
|
||||
/// * `data`: Rego value. A Rego value is a number, bool, string, None
|
||||
@@ -312,6 +320,7 @@ impl Engine {
|
||||
|
||||
/// Get coverage report as json.
|
||||
///
|
||||
#[cfg(feature = "coverage")]
|
||||
pub fn get_coverage_report_as_json(&self) -> Result<String> {
|
||||
let report = self.engine.get_coverage_report()?;
|
||||
serde_json::to_string_pretty(&report).map_err(|e| anyhow!("{e}"))
|
||||
@@ -319,12 +328,14 @@ impl Engine {
|
||||
|
||||
/// Get coverage report as pretty printable string.
|
||||
///
|
||||
#[cfg(feature = "coverage")]
|
||||
pub fn get_coverage_report_pretty(&self) -> Result<String> {
|
||||
self.engine.get_coverage_report()?.to_string_pretty()
|
||||
}
|
||||
|
||||
/// Clear coverage data.
|
||||
///
|
||||
#[cfg(feature = "coverage")]
|
||||
pub fn clear_coverage_data(&mut self) {
|
||||
self.engine.clear_coverage_data();
|
||||
}
|
||||
@@ -350,6 +361,13 @@ impl Engine {
|
||||
engine: self.engine.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get AST of policies.
|
||||
///
|
||||
#[cfg(feature = "ast")]
|
||||
pub fn get_ast_as_json(&self) -> Result<String> {
|
||||
self.engine.get_ast_as_json()
|
||||
}
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
regorusrb (0.1.5)
|
||||
regorusrb (0.2.1)
|
||||
rb_sys (~> 0.9.97)
|
||||
|
||||
GEM
|
||||
@@ -10,9 +10,9 @@ GEM
|
||||
ast (2.4.2)
|
||||
json (2.7.2)
|
||||
language_server-protocol (3.17.0.3)
|
||||
minitest (5.23.1)
|
||||
parallel (1.24.0)
|
||||
parser (3.3.1.0)
|
||||
minitest (5.24.0)
|
||||
parallel (1.25.1)
|
||||
parser (3.3.3.0)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
racc (1.8.0)
|
||||
@@ -20,12 +20,12 @@ GEM
|
||||
rake (13.2.1)
|
||||
rake-compiler (1.2.7)
|
||||
rake
|
||||
rake-compiler-dock (1.5.0)
|
||||
rake-compiler-dock (1.5.1)
|
||||
rb_sys (0.9.97)
|
||||
regexp_parser (2.9.2)
|
||||
rexml (3.2.8)
|
||||
strscan (>= 3.0.9)
|
||||
rubocop (1.64.0)
|
||||
rexml (3.3.0)
|
||||
strscan
|
||||
rubocop (1.64.1)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (>= 3.17.0)
|
||||
parallel (~> 1.10)
|
||||
@@ -62,4 +62,4 @@ DEPENDENCIES
|
||||
rubocop-rake
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.10
|
||||
2.5.13
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "regorusrb"
|
||||
version = "0.1.5"
|
||||
version = "0.12.0"
|
||||
edition = "2021"
|
||||
description = "Ruby bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||
publish = false
|
||||
@@ -10,10 +10,12 @@ crate-type = ["cdylib"]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = ["regorus/std", "regorus/full-opa"]
|
||||
default = ["ast", "coverage", "regorus/std", "regorus/full-opa"]
|
||||
ast = ["regorus/ast"]
|
||||
coverage = ["regorus/coverage"]
|
||||
|
||||
[dependencies]
|
||||
magnus = { version = "0.6.4" }
|
||||
regorus = { git = "https://github.com/microsoft/regorus", default-features = false, features = ["arc"] }
|
||||
regorus = { path = "../../../..", default-features = false, features = ["arc"] }
|
||||
serde_json = "1.0.117"
|
||||
serde_magnus = "0.8.1"
|
||||
|
||||
@@ -92,6 +92,20 @@ impl Engine {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_packages(&self) -> Result<Vec<String>, Error> {
|
||||
self.engine
|
||||
.borrow()
|
||||
.get_packages()
|
||||
.map_err(|e| Error::new(runtime_error(), format!("Failed to get packages: {e}")))
|
||||
}
|
||||
|
||||
fn get_policies(&self) -> Result<String, Error> {
|
||||
self.engine
|
||||
.borrow()
|
||||
.get_policies_as_json()
|
||||
.map_err(|e| Error::new(runtime_error(), format!("Failed to get policies: {e}")))
|
||||
}
|
||||
|
||||
fn set_input(&self, ruby_hash: magnus::RHash) -> Result<(), Error> {
|
||||
let input_value: regorus::Value = serde_magnus::deserialize(ruby_hash).map_err(|e| {
|
||||
Error::new(
|
||||
@@ -192,11 +206,13 @@ impl Engine {
|
||||
Ok(self.engine.borrow_mut().eval_deny_query(query, false))
|
||||
}
|
||||
|
||||
#[cfg(feature = "coverage")]
|
||||
fn set_enable_coverage(&self, enable: bool) -> Result<(), Error> {
|
||||
self.engine.borrow_mut().set_enable_coverage(enable);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "coverage")]
|
||||
fn get_coverage_report_as_json(&self) -> Result<String, Error> {
|
||||
let report = self
|
||||
.engine
|
||||
@@ -217,6 +233,7 @@ impl Engine {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "coverage")]
|
||||
fn get_coverage_report_pretty(&self) -> Result<String, Error> {
|
||||
let report = self
|
||||
.engine
|
||||
@@ -237,6 +254,7 @@ impl Engine {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "coverage")]
|
||||
fn clear_coverage_data(&self) -> Result<(), Error> {
|
||||
self.engine.borrow_mut().clear_coverage_data();
|
||||
Ok(())
|
||||
@@ -256,6 +274,14 @@ impl Engine {
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "ast")]
|
||||
fn get_ast_as_json(&self) -> Result<String, Error> {
|
||||
self.engine
|
||||
.borrow()
|
||||
.get_ast_as_json()
|
||||
.map_err(|e| Error::new(runtime_error(), format!("Failed to get ast: {e}")))
|
||||
}
|
||||
}
|
||||
|
||||
#[magnus::init]
|
||||
@@ -277,6 +303,8 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
|
||||
"add_policy_from_file",
|
||||
method!(Engine::add_policy_from_file, 1),
|
||||
)?;
|
||||
engine_class.define_method("get_packages", method!(Engine::get_packages, 0))?;
|
||||
engine_class.define_method("get_policies", method!(Engine::get_policies, 0))?;
|
||||
|
||||
// data operations
|
||||
engine_class.define_method("add_data", method!(Engine::add_data, 1))?;
|
||||
@@ -325,5 +353,7 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
|
||||
engine_class.define_method("set_gather_prints", method!(Engine::set_gather_prints, 1))?;
|
||||
engine_class.define_method("take_prints", method!(Engine::take_prints, 0))?;
|
||||
|
||||
// ast
|
||||
engine_class.define_method("get_ast_as_json", method!(Engine::get_ast_as_json, 0))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Regorus
|
||||
VERSION = "0.1.5"
|
||||
VERSION = "0.2.1"
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "regorusjs"
|
||||
version = "0.1.5"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/microsoft/regorus/bindings/wasm"
|
||||
description = "WASM bindings for Regorus - a fast, lightweight Rego interpreter written in Rust"
|
||||
@@ -11,7 +11,9 @@ keywords = ["interpreter", "opa", "policy-as-code", "rego"]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[features]
|
||||
default = ["regorus/std", "regorus/full-opa"]
|
||||
default = ["ast", "coverage", "regorus/std", "regorus/full-opa"]
|
||||
ast = ["regorus/ast"]
|
||||
coverage = ["regorus/coverage"]
|
||||
|
||||
[dependencies]
|
||||
regorus = { path = "../..", default-features = false, features = ["arc"] }
|
||||
|
||||
@@ -72,6 +72,13 @@ impl Engine {
|
||||
self.engine.get_packages().map_err(error_to_jsvalue)
|
||||
}
|
||||
|
||||
/// Get the list of policies.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
|
||||
pub fn getPolicies(&self) -> Result<String, JsValue> {
|
||||
self.engine.get_policies_as_json().map_err(error_to_jsvalue)
|
||||
}
|
||||
|
||||
/// Clear policy data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/0.1.0-alpha.2/regorus/struct.Engine.html#method.clear_data
|
||||
@@ -131,6 +138,7 @@ impl Engine {
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
|
||||
/// * `b`: Whether to enable gathering coverage or not.
|
||||
#[cfg(feature = "coverage")]
|
||||
pub fn setEnableCoverage(&mut self, enable: bool) {
|
||||
self.engine.set_enable_coverage(enable)
|
||||
}
|
||||
@@ -138,6 +146,7 @@ impl Engine {
|
||||
/// Get the coverage report as json.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
|
||||
#[cfg(feature = "coverage")]
|
||||
pub fn getCoverageReport(&self) -> Result<String, JsValue> {
|
||||
let report = self
|
||||
.engine
|
||||
@@ -149,6 +158,7 @@ impl Engine {
|
||||
/// Clear gathered coverage data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
|
||||
#[cfg(feature = "coverage")]
|
||||
pub fn clearCoverageData(&mut self) {
|
||||
self.engine.clear_coverage_data()
|
||||
}
|
||||
@@ -156,6 +166,7 @@ impl Engine {
|
||||
/// Get ANSI color coded coverage report.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
|
||||
#[cfg(feature = "coverage")]
|
||||
pub fn getCoverageReportPretty(&self) -> Result<String, JsValue> {
|
||||
let report = self
|
||||
.engine
|
||||
@@ -163,10 +174,19 @@ impl Engine {
|
||||
.map_err(error_to_jsvalue)?;
|
||||
report.to_string_pretty().map_err(error_to_jsvalue)
|
||||
}
|
||||
|
||||
/// Get AST of policies.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_ast_as_json
|
||||
#[cfg(feature = "ast")]
|
||||
pub fn getAstAsJson(&self) -> Result<String, JsValue> {
|
||||
self.engine.get_ast_as_json().map_err(error_to_jsvalue)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::error_to_jsvalue;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_test::wasm_bindgen_test;
|
||||
|
||||
@@ -204,7 +224,7 @@ mod tests {
|
||||
assert_eq!(pkg, "data.test");
|
||||
|
||||
let results = engine.evalQuery("data".to_string())?;
|
||||
let r = regorus::Value::from_json_str(&results).map_err(crate::error_to_jsvalue)?;
|
||||
let r = regorus::Value::from_json_str(&results).map_err(error_to_jsvalue)?;
|
||||
|
||||
let v = &r["result"][0]["expressions"][0]["value"];
|
||||
|
||||
@@ -216,7 +236,7 @@ mod tests {
|
||||
|
||||
// Use eval_rule to perform same query.
|
||||
let v = engine.evalRule("data.test.message".to_owned())?;
|
||||
let v = regorus::Value::from_json_str(&v).map_err(crate::error_to_jsvalue)?;
|
||||
let v = regorus::Value::from_json_str(&v).map_err(error_to_jsvalue)?;
|
||||
|
||||
// Ensure that input and policy were evaluated.
|
||||
assert_eq!(v, regorus::Value::from("Hello"));
|
||||
@@ -234,7 +254,7 @@ mod tests {
|
||||
|
||||
// Test code coverage.
|
||||
let report = engine1.getCoverageReport()?;
|
||||
let r = regorus::Value::from_json_str(&report).map_err(crate::error_to_jsvalue)?;
|
||||
let r = regorus::Value::from_json_str(&report).map_err(error_to_jsvalue)?;
|
||||
|
||||
assert_eq!(
|
||||
r["files"][0]["covered"]
|
||||
@@ -246,6 +266,13 @@ mod tests {
|
||||
println!("{}", engine1.getCoverageReportPretty()?);
|
||||
|
||||
engine1.clearCoverageData();
|
||||
|
||||
let policies = engine1.getPolicies()?;
|
||||
let v = regorus::Value::from_json_str(&policies).map_err(error_to_jsvalue)?;
|
||||
assert_eq!(
|
||||
v[0]["path"].as_string().map_err(error_to_jsvalue)?.as_ref(),
|
||||
"hello.rego"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,8 +170,40 @@ fn rego_parse(file: String) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn rego_ast(file: String) -> Result<()> {
|
||||
#[cfg(feature = "ast")]
|
||||
{
|
||||
// Create engine.
|
||||
let mut engine = regorus::Engine::new();
|
||||
|
||||
// Create source.
|
||||
#[cfg(feature = "std")]
|
||||
engine.add_policy_from_file(file)?;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
engine.add_policy(file.clone(), read_file(&file)?)?;
|
||||
|
||||
let ast = engine.get_ast_as_json()?;
|
||||
|
||||
println!("{ast}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ast"))]
|
||||
{
|
||||
bail!("`ast` feature must be enabled");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(clap::Subcommand)]
|
||||
enum RegorusCommand {
|
||||
/// Parse a Rego policy and dump AST.
|
||||
Ast {
|
||||
/// Rego policy file.
|
||||
file: String,
|
||||
},
|
||||
|
||||
/// Evaluate a Rego Query.
|
||||
Eval {
|
||||
/// Directories containing Rego files.
|
||||
@@ -254,5 +286,6 @@ fn main() -> Result<()> {
|
||||
),
|
||||
RegorusCommand::Lex { file, verbose } => rego_lex(file, verbose),
|
||||
RegorusCommand::Parse { file } => rego_parse(file),
|
||||
RegorusCommand::Ast { file } => rego_ast(file),
|
||||
}
|
||||
}
|
||||
|
||||
21
src/ast.rs
21
src/ast.rs
@@ -8,12 +8,14 @@ use crate::*;
|
||||
use core::{cmp, fmt, ops::Deref};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub enum BinOp {
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub enum ArithOp {
|
||||
Add,
|
||||
Sub,
|
||||
@@ -23,6 +25,7 @@ pub enum ArithOp {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub enum BoolOp {
|
||||
Lt,
|
||||
Le,
|
||||
@@ -33,12 +36,15 @@ pub enum BoolOp {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub enum AssignOp {
|
||||
Eq,
|
||||
ColEq,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct NodeRef<T> {
|
||||
#[cfg_attr(feature = "ast", serde(flatten))]
|
||||
r: Rc<T>,
|
||||
}
|
||||
|
||||
@@ -97,6 +103,7 @@ impl<T> NodeRef<T> {
|
||||
pub type Ref<T> = NodeRef<T>;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub enum Expr {
|
||||
// Simple items that only have a span as content.
|
||||
String((Span, Value)),
|
||||
@@ -230,6 +237,7 @@ impl Expr {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub enum Literal {
|
||||
SomeVars {
|
||||
span: Span,
|
||||
@@ -259,6 +267,7 @@ pub enum Literal {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct WithModifier {
|
||||
pub span: Span,
|
||||
pub refr: Ref<Expr>,
|
||||
@@ -266,19 +275,23 @@ pub struct WithModifier {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct LiteralStmt {
|
||||
pub span: Span,
|
||||
pub literal: Literal,
|
||||
#[cfg_attr(feature = "ast", serde(skip_serializing_if = "Vec::is_empty"))]
|
||||
pub with_mods: Vec<WithModifier>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct Query {
|
||||
pub span: Span,
|
||||
pub stmts: Vec<LiteralStmt>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct RuleAssign {
|
||||
pub span: Span,
|
||||
pub op: AssignOp,
|
||||
@@ -286,6 +299,7 @@ pub struct RuleAssign {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct RuleBody {
|
||||
pub span: Span,
|
||||
pub assign: Option<RuleAssign>,
|
||||
@@ -293,6 +307,7 @@ pub struct RuleBody {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub enum RuleHead {
|
||||
Compr {
|
||||
span: Span,
|
||||
@@ -313,6 +328,7 @@ pub enum RuleHead {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub enum Rule {
|
||||
Spec {
|
||||
span: Span,
|
||||
@@ -337,22 +353,27 @@ impl Rule {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct Package {
|
||||
pub span: Span,
|
||||
pub refr: Ref<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct Import {
|
||||
pub span: Span,
|
||||
pub refr: Ref<Expr>,
|
||||
#[cfg_attr(feature = "ast", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub r#as: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct Module {
|
||||
pub package: Package,
|
||||
pub imports: Vec<Import>,
|
||||
#[cfg_attr(feature = "ast", serde(rename(serialize = "rules")))]
|
||||
pub policy: Vec<Ref<Rule>>,
|
||||
pub rego_v1: bool,
|
||||
}
|
||||
|
||||
@@ -129,6 +129,66 @@ impl Engine {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get the list of policy files.
|
||||
/// ```
|
||||
/// # use regorus::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let mut engine = Engine::new();
|
||||
///
|
||||
/// let pkg = engine.add_policy("hello.rego".to_string(), "package test".to_string())?;
|
||||
/// assert_eq!(pkg, "data.test");
|
||||
///
|
||||
/// let policies = engine.get_policies()?;
|
||||
///
|
||||
/// assert_eq!(policies[0].get_path(), "hello.rego");
|
||||
/// assert_eq!(policies[0].get_contents(), "package test");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn get_policies(&self) -> Result<Vec<Source>> {
|
||||
Ok(self
|
||||
.modules
|
||||
.iter()
|
||||
.map(|m| m.package.refr.span().source.clone())
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Get the list of policy files as a JSON object.
|
||||
/// ```
|
||||
/// # use regorus::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let mut engine = Engine::new();
|
||||
///
|
||||
/// let pkg = engine.add_policy("hello.rego".to_string(), "package test".to_string())?;
|
||||
/// assert_eq!(pkg, "data.test");
|
||||
///
|
||||
/// let policies = engine.get_policies_as_json()?;
|
||||
///
|
||||
/// let v = Value::from_json_str(&policies)?;
|
||||
/// assert_eq!(v[0]["path"].as_string()?.as_ref(), "hello.rego");
|
||||
/// assert_eq!(v[0]["contents"].as_string()?.as_ref(), "package test");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn get_policies_as_json(&self) -> Result<String> {
|
||||
#[derive(Serialize)]
|
||||
struct Source<'a> {
|
||||
path: &'a String,
|
||||
contents: &'a String,
|
||||
}
|
||||
|
||||
let mut sources = vec![];
|
||||
for m in self.modules.iter() {
|
||||
let source = &m.package.refr.span().source;
|
||||
sources.push(Source {
|
||||
path: source.get_path(),
|
||||
contents: source.get_contents(),
|
||||
});
|
||||
}
|
||||
|
||||
serde_json::to_string_pretty(&sources).map_err(anyhow::Error::msg)
|
||||
}
|
||||
|
||||
/// Set the input document.
|
||||
///
|
||||
/// * `input`: Input documented. Typically this [Value] is constructed from JSON or YAML.
|
||||
@@ -743,4 +803,42 @@ impl Engine {
|
||||
pub fn take_prints(&mut self) -> Result<Vec<String>> {
|
||||
self.interpreter.take_prints()
|
||||
}
|
||||
|
||||
/// Get the policies and corresponding AST.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// # use regorus::*;
|
||||
/// # use anyhow::{bail, Result};
|
||||
/// # fn main() -> Result<()> {
|
||||
/// # let mut engine = Engine::new();
|
||||
/// engine.add_policy("test.rego".to_string(), "package test\n x := 1".to_string())?;
|
||||
///
|
||||
/// let ast = engine.get_ast_as_json()?;
|
||||
/// let value = Value::from_json_str(&ast)?;
|
||||
///
|
||||
/// assert_eq!(value[0]["ast"]["package"]["refr"]["Var"][1].as_string()?.as_ref(), "test");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature = "ast")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "ast")))]
|
||||
pub fn get_ast_as_json(&self) -> Result<String> {
|
||||
#[derive(Serialize)]
|
||||
struct Policy<'a> {
|
||||
source: &'a Source,
|
||||
version: u32,
|
||||
ast: &'a Module,
|
||||
}
|
||||
let mut ast = vec![];
|
||||
for m in &self.modules {
|
||||
ast.push(Policy {
|
||||
source: &m.package.span.source,
|
||||
version: 1,
|
||||
ast: m,
|
||||
});
|
||||
}
|
||||
|
||||
serde_json::to_string_pretty(&ast).map_err(anyhow::Error::msg)
|
||||
}
|
||||
}
|
||||
|
||||
86
src/lexer.rs
86
src/lexer.rs
@@ -12,17 +12,34 @@ use crate::Value;
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
struct SourceInternal {
|
||||
pub file: String,
|
||||
pub contents: String,
|
||||
#[cfg_attr(feature = "ast", serde(skip_serializing))]
|
||||
pub lines: Vec<(u32, u32)>,
|
||||
}
|
||||
|
||||
/// A policy file.
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct Source {
|
||||
#[cfg_attr(feature = "ast", serde(flatten))]
|
||||
src: Rc<SourceInternal>,
|
||||
}
|
||||
|
||||
impl Source {
|
||||
/// The path associated with the policy file.
|
||||
pub fn get_path(&self) -> &String {
|
||||
&self.src.file
|
||||
}
|
||||
|
||||
/// The contents of the policy file.
|
||||
pub fn get_contents(&self) -> &String {
|
||||
&self.src.contents
|
||||
}
|
||||
}
|
||||
|
||||
impl cmp::Ord for Source {
|
||||
fn cmp(&self, other: &Source) -> cmp::Ordering {
|
||||
Rc::as_ptr(&self.src).cmp(&Rc::as_ptr(&other.src))
|
||||
@@ -212,7 +229,9 @@ impl Source {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "ast", derive(serde::Serialize))]
|
||||
pub struct Span {
|
||||
#[cfg_attr(feature = "ast", serde(skip_serializing))]
|
||||
pub source: Source,
|
||||
pub line: u32,
|
||||
pub col: u32,
|
||||
@@ -274,6 +293,10 @@ pub struct Lexer<'source> {
|
||||
iter: Peekable<CharIndices<'source>>,
|
||||
line: u32,
|
||||
col: u32,
|
||||
unknown_char_is_symbol: bool,
|
||||
allow_slash_star_escape: bool,
|
||||
comment_starts_with_double_slash: bool,
|
||||
double_colon_token: bool,
|
||||
}
|
||||
|
||||
impl<'source> Lexer<'source> {
|
||||
@@ -283,9 +306,29 @@ impl<'source> Lexer<'source> {
|
||||
iter: source.contents().char_indices().peekable(),
|
||||
line: 1,
|
||||
col: 1,
|
||||
unknown_char_is_symbol: false,
|
||||
allow_slash_star_escape: false,
|
||||
comment_starts_with_double_slash: false,
|
||||
double_colon_token: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_unknown_char_is_symbol(&mut self, b: bool) {
|
||||
self.unknown_char_is_symbol = b;
|
||||
}
|
||||
|
||||
pub fn set_allow_slash_star_escape(&mut self, b: bool) {
|
||||
self.allow_slash_star_escape = b;
|
||||
}
|
||||
|
||||
pub fn set_comment_starts_with_double_slash(&mut self, b: bool) {
|
||||
self.comment_starts_with_double_slash = b;
|
||||
}
|
||||
|
||||
pub fn set_double_colon_token(&mut self, b: bool) {
|
||||
self.double_colon_token = b;
|
||||
}
|
||||
|
||||
fn peek(&mut self) -> (usize, char) {
|
||||
match self.iter.peek() {
|
||||
Some((index, chr)) => (*index, *chr),
|
||||
@@ -465,6 +508,7 @@ impl<'source> Lexer<'source> {
|
||||
match ch {
|
||||
// json escape sequence
|
||||
'"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't' => (),
|
||||
'*' if self.allow_slash_star_escape => (),
|
||||
'u' => {
|
||||
for _i in 0..4 {
|
||||
let (offset, ch) = self.peek();
|
||||
@@ -528,12 +572,24 @@ impl<'source> Lexer<'source> {
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn skip_past_newline(&mut self) -> Result<()> {
|
||||
self.iter.next();
|
||||
loop {
|
||||
match self.peek().1 {
|
||||
'\n' | '\x00' => break,
|
||||
_ => self.iter.next(),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn skip_ws(&mut self) -> Result<()> {
|
||||
// Only the 4 json whitespace characters are recognized.
|
||||
// https://www.crockford.com/mckeeman.html.
|
||||
// Additionally, comments are also skipped.
|
||||
// A tab is considered 4 space characters.
|
||||
'outer: loop {
|
||||
loop {
|
||||
match self.peek().1 {
|
||||
' ' => self.col += 1,
|
||||
'\t' => self.col += 4,
|
||||
@@ -550,14 +606,13 @@ impl<'source> Lexer<'source> {
|
||||
self.col = 1;
|
||||
self.line += 1;
|
||||
}
|
||||
'#' => {
|
||||
self.iter.next();
|
||||
loop {
|
||||
match self.peek().1 {
|
||||
'\n' | '\x00' => continue 'outer,
|
||||
_ => self.iter.next(),
|
||||
};
|
||||
}
|
||||
'#' if !self.comment_starts_with_double_slash => {
|
||||
self.skip_past_newline()?;
|
||||
continue;
|
||||
}
|
||||
'/' if self.comment_starts_with_double_slash && self.peekahead(1).1 == '/' => {
|
||||
self.skip_past_newline()?;
|
||||
continue;
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
@@ -601,7 +656,7 @@ impl<'source> Lexer<'source> {
|
||||
self.col += 1;
|
||||
self.iter.next();
|
||||
let mut end = start as u32 + 1;
|
||||
if self.peek().1 == '=' {
|
||||
if self.peek().1 == '=' || (self.peek().1 == ':' && self.double_colon_token) {
|
||||
self.col += 1;
|
||||
self.iter.next();
|
||||
end += 1;
|
||||
@@ -675,6 +730,17 @@ impl<'source> Lexer<'source> {
|
||||
}
|
||||
Ok(ident)
|
||||
}
|
||||
_ if self.unknown_char_is_symbol => {
|
||||
self.col += 1;
|
||||
self.iter.next();
|
||||
Ok(Token(TokenKind::Symbol, Span {
|
||||
source: self.source.clone(),
|
||||
line: self.line,
|
||||
col,
|
||||
start: start as u32,
|
||||
end: start as u32 + 1,
|
||||
}))
|
||||
}
|
||||
_ => Err(self.source.error(self.line, self.col, "invalid character"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ mod utils;
|
||||
mod value;
|
||||
|
||||
pub use engine::Engine;
|
||||
pub use lexer::Source;
|
||||
pub use value::Value;
|
||||
|
||||
#[cfg(feature = "arc")]
|
||||
|
||||
@@ -387,6 +387,7 @@ pub struct Analyzer {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Schedule {
|
||||
#[allow(unused)]
|
||||
pub scopes: BTreeMap<Ref<Query>, Scope>,
|
||||
pub order: BTreeMap<Ref<Query>, Vec<u16>>,
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
const OPA_REPO: &str = "https://github.com/open-policy-agent/opa";
|
||||
const OPA_BRANCH: &str = "v0.64.0";
|
||||
const OPA_BRANCH: &str = "v0.65.0";
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -325,9 +325,9 @@ fn run_opa_tests(opa_tests_dir: String, folders: &[String]) -> Result<()> {
|
||||
if npass == 0 && nfail == 0 {
|
||||
bail!("no matching tests found.");
|
||||
} else if nfail == 0 {
|
||||
println!("\x1b[32m {:42}: {npass:4} {nfail:4}\x1b[0m", "TOTAL");
|
||||
println!("\x1b[32m {:40}: {npass:4} {nfail:4}\x1b[0m", "TOTAL");
|
||||
} else {
|
||||
println!("\x1b[31m {:42}: {npass:4} {nfail:4}\x1b[0m", "TOTAL");
|
||||
println!("\x1b[31m {:40}: {npass:4} {nfail:4}\x1b[0m", "TOTAL");
|
||||
}
|
||||
|
||||
if !missing_functions.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user